Skip to Content

category

Category: WebDev

In love with Nancy (F# and React too)

For some time I’m switching all my development from C# to F# (because of reasons…), and next on the list was Web development. Attempts at using ASP.NET MVC combined with F# were failures, mostly because I only switch language, not a general approach and still tried to use Razor, AutoMapper, Castle.Windsor and nHibernate, and as such I was bound to fail. Recently I came across Nancy and React, and decided to give them a try. For starters I recommend F# and Nancy – beyond Hello World by Michał Franc, I’ll add few notes to that.

Static content and folders

Though you may create folders for static content in your F# project in VS with F# power tools, it’s pain in the ass to work with them, manually sorting folders contents in *.fsproj file isn’t the most productive way to start work when reopening visual studio after some minor project structure changes. What I also noticed is VS slowing down.

VS Code and symbolic link

To avoid using folders I prefer to use VS code for non F# coding (CSS, JS, so on) and creating symlinks to static content in order to avoid manually coping files after change, or creating additional build scripts.

for bootstrapper and module looking like:

 
type Bootstrapper() as __ =
  inherit DefaultNancyBootstrapper()
  do 
    #if DEBUG
    Nancy.StaticConfiguration.DisableErrorTraces <- false
    #endif

  override __.ConfigureConventions nancyConventions =
    base.ConfigureConventions(nancyConventions)
    nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("/Scripts",null))
    nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("/Content",null))
    nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("/App",null))
 
 
type App() as this =
  inherit NancyModule()
  do
    this.Get.["/"] <- fun _ ->
      this.View.["Index.html"] :> obj
 

we’ll need following symlinks:

 
mklink Index.html "..\..\..\Static\Index.html"
mklink /D Content "..\..\..\Static\Content"
mklink /D App "..\..\..\Static\App"
mklink /D Scripts "..\..\..\Static\Scripts"
 

In order to create them, open Command Prompt as Administrator and use mklink command, supplying link name as first argument, and path to actual file/directory as second.

Note: I only create symlink to one view, Index.html, as in following posts I’ll be using React, and single view is sufficient.

Running our application

Self Hosted Nancy

Fastest way to run application is to install Nancy.Hosting.Self NuGet package and run in console

 
[<EntryPoint>]
let main _ = 
  let nancy = new Nancy.Hosting.Self.NancyHost(new Bootstrapper(), new Uri("http://localhost:8100"))
  nancy.Start()
 
  while Console.ReadLine() <> "x" do ()
  0 

Source code, for this and posts that will follow available at:


https://github.com/devanarch/in-love-with-nancy
0 forks.
1 stars.
0 open issues.
Recent commits:

Implementing language plugin for syntax highlighter evolved

In one of his posts  Maciej Anisierowicz recommended SyntaxHighlighter Evolved plugin, and indeed it’s a great one if you want to highlight one of popular languages syntax. In case of niche languages, like ones defined in IEC 61131-3, one has to implement his own language extension for SyntaxHighlighter.

IEC 61131-3 Structured Text

Due to #dajsiepoznac project there will appear Structured Text samples. Even though it resembles Pascal on which is based, included pascal syntax falls short.

(* Note samples based on ones available at http://infosys.beckhoff.com/ *)

TYPE TSimpleStruct :
STRUCT
	lrealVal: LREAL := 1.23;
	dintVal1: DINT := 120000;
END_STRUCT
END_TYPE

TYPE TComplexStruct :
STRUCT
	intVal : INT:=1200;
	dintArr: ARRAY[0..3] OF DINT:= 1,2,3,4;
	boolVal: BOOL := FALSE;
	byteVal: BYTE:=10;
	stringVal : STRING(5) := 'hallo';
	simpleStruct1: TSimpleStruct;
END_STRUCT
END_TYPE

PROGRAM MAIN
VAR

  REAL32_1 AT %MB0 : REAL;  (* 1 *)
  REAL32_2 AT %MB4 : REAL;  (* 2 *)
  REAL32_3 AT %MB8 : REAL;  (* 3 *)
  REAL32_4 AT %MB12: REAL;  (* 4 *)
  REAL32_5 AT %MB16: REAL;  (* 5 *)

  PLCVar : ARRAY [0..99] OF INT;
  Index: BYTE;
  text : STRING[30] := 'hello';
  Time1:TIME := T#21h33m23s231ms;
  Time2:TIME := T#21H;
  Time3:TIME := T#33M21MS;
  DateTime1:DT:=DT#1993-06-12-15:36:55.40;
  tod1:TOD:=TIME_OF_DAY#15:36:55.40;
  Date1:DATE:=DATE#1993-06-12;
  Bool1:BOOL := FALSE;
  int1:INT := 30000;
  dint1:DINT:=125000;
  usint1:USINT:=200;
  real1:REAL:= 1.2;
  lreal1:LREAL:=3.5;

  str1:STRING := 'this is a test string';
  str2:STRING(5) := 'hallo';

  complexStruct1 : TComplexStruct;

END_VAR

FOR Index := 0 TO 99 DO
  PLCVar[Index] := 3500 + INDEX;
END_FOR
(* Note samples based on ones available at http://infosys.beckhoff.com/ *)

TYPE TSimpleStruct :
STRUCT
	lrealVal: LREAL := 1.23;
	dintVal1: DINT := 120000;
END_STRUCT
END_TYPE

TYPE TComplexStruct :
STRUCT
	intVal : INT:=1200;
	dintArr: ARRAY[0..3] OF DINT:= 1,2,3,4;
	boolVal: BOOL := FALSE;
	byteVal: BYTE:=10;
	stringVal : STRING(5) := 'hallo';
	simpleStruct1: TSimpleStruct;
END_STRUCT
END_TYPE

PROGRAM MAIN
VAR

  REAL32_1 AT %MB0 : REAL;  (* 1 *)
  REAL32_2 AT %MB4 : REAL;  (* 2 *)
  REAL32_3 AT %MB8 : REAL;  (* 3 *)
  REAL32_4 AT %MB12: REAL;  (* 4 *)
  REAL32_5 AT %MB16: REAL;  (* 5 *)

  PLCVar : ARRAY [0..99] OF INT;
  Index: BYTE;
  text : STRING[30] := 'hello';
  Time1:TIME := T#21h33m23s231ms;
  Time2:TIME := T#21H;
  Time3:TIME := T#33M21MS;
  DateTime1:DT:=DT#1993-06-12-15:36:55.40;
  tod1:TOD:=TIME_OF_DAY#15:36:55.40;
  Date1:DATE:=DATE#1993-06-12;
  Bool1:BOOL := FALSE;
  int1:INT := 30000;
  dint1:DINT:=125000;
  usint1:USINT:=200;
  real1:REAL:= 1.2;
  lreal1:LREAL:=3.5;

  str1:STRING := 'this is a test string';
  str2:STRING(5) := 'hallo';

  complexStruct1 : TComplexStruct;

END_VAR

FOR Index := 0 TO 99 DO
  PLCVar[Index] := 3500 + INDEX;
END_FOR

Extending syntax highlighter

WP plugin SyntaxHighlighter Evolved is based on SyntaxHighlighter JavaScript package by Alex Gorbatchev, which is OSS available on GitHub. Thus we’ll be developing plugin for both. Best way to start is to find a supported language that most resembles yours.

JS extension

var BrushBase = require('brush-base');
var regexLib = require('syntaxhighlighter-regex').commonRegExp;

function Brush() {
  var keywords =  'ABS ACOS ACTION ADD AND ANDN ANY ANY_BIT ANY_DATE ANY_INT ANY_NUM ANY_REAL ARRAY ASIN AT ATAN ' +
                  'BOOL BY BYTE ' +
                  'CAL CALC CALCN CASE CD CDT CLK CONCAT CONFIGURATION CONSTANT COS CTD CTU CTUD CU CV ' +
                  'D DATE DATE_AND_TIME DELETE DINT DIV DO DS DT DWORD '+
                  'ELSE ELSIF END_ACTION END_CASE END_CONFIGURATION END_FOR END_FUNCTION END_FUNCTION_BLOCK END_IF END_PROGRAM END_REPEAT END_RESOURCE END_STEP END_STRUCT END_TRANSITION END_TYPE END_VAR END_WHILE EN ENO EQ ET EXIT EXP EXPT '+
                  'FALSE F_EDGE F_TRIG FIND FOR FROM FUNCTION FUNCTION_BLOCK '+
                  'GE GT'+
                  'IF IN INITIAL_STEP INSERT INT INTERVAL '+
                  'JMP JMPC JMPCN '+
                  'L LD LDN LE LEFT LEN LIMIT LINT LN LOG LREAL LT LWORD '+
                  'MAX MID MIN MOD MOVE MUL MUX '+
                  'N NE NEG NOT '+
                  'OF ON OR OEN '+
                  'P PRIORITY PROGRAM PT PV '+
                  'Q Q1 QU QD '+
                  'R R1 R_TRIG READ_ONLY READ_WRITE REAL RELEASE REPEAT REPLACE RESOURCE RET RETAIN RETC RTCN RETURN RIGHT ROL ROR RS RTC R_EDGE '+
                  'S S1 SD SEL SEMA SHL SHR SIN SINGLE SINT SL SQRT SR ST STEP STN STRING STRUCT SUB '+
                  'TAN TASK THEN TIME TIME_OF_DAY TO TOD TOF TON TP TRANSITION TRUE TYPE '+
                  'UDINT UINT ULINT UNTIL USINT '+
                  'VAR VAR_ACCESS VAR_EXTERNAL VAR_GLOBAL VAR_INPUT VAR_IN_OUT VAR_OUTPUT '+
                  'WHILE WITH WORD '+
                  'XOR XORN';

  this.regexList = [
    {
      //time literal
      regex: /(T|t|TIME|time)(?=.*([hms]|[HMS]))#(\d+(h|H))?(\d+(m|M))?(\d+(s|s))?(\d+(ms|MS))?/g,
      css: 'color2'
    },
    {
      // date and time literal
      regex: /(DT|dt|date_and_time|DATE_AND_TIME)#\d{4}-\d{2}-\d{2}-\d{2}:\d{2}:\d{2}\.\d{2}/g,
      css: 'color2'
    },
    {
      // time of day literal
      regex: /(TOD|tod|time_of_day|TIME_OF_DAY)#\d+:\d+(:\d+)?((\.\d+)|(\.?))/g,
      css: 'color2'
    },
    {
      //date literal
      regex: /(D|d|DATE|date)#\d{4}-\d{2}-\d{2}/g,
      css: 'color2'
    },
    {
      //direct memory adressing
      regex: /%[A-Z]{1,2}\d+(\.\d+)*/g,
      css: 'color2'
    },
    {
      //multiline comment (* *)
      regex: /\(\*[\s\S]*?\*\)/gm,
      css: 'comments'
    },
    {
      //string literal 'myvalue'
      regex: regexLib.singleQuotedString,
      css: 'string'
    },
    {
      //number integers, floating point with dot or exponential
      regex: /\b\d+([\.eE]\d+)?\b/g,
      css: 'value'
    },
    {
      //keywords
      regex: new RegExp(this.getKeywords(keywords), 'gmi'),
      css: 'keyword'
    }];
};

Brush.prototype = new BrushBase();
Brush.aliases = ['structuredtext', 'ST', 'IEC61131','st','iec61131'];
module.exports = Brush;

on lines 5-26 you may find keywords defined by IEC 61131-3 standard, later used to construct regex, in order to be highlighted, at line 76  which are later used at line. Beside using predefined single quoted string (line 61), we define regexes for language specific futures like TIME/DATE and direct memory addressing.

Make it work with WordPress

To use it at WordPress based site, we need to make it a plugin, extending SyntaxHighlighter Evolved. Separate plugin, as we don’t want to lose our changes on update of SH.

SyntaxHighlighter.brushes.IEC61131 = function()

  //keywords as specified by IEC 61131-3
  var keywords =  'ABS ACOS ACTION ADD AND ANDN ANY ANY_BIT ANY_DATE ANY_INT ANY_NUM ANY_REAL ARRAY ASIN AT ATAN ';
  /*rest of keywords*/
  this.regexList = [
    {
      //time literal
      regex: /(T|t|TIME|time)(?=.*([hms]|[HMS]))#(\d+(h|H))?(\d+(m|M))?(\d+(s|s))?(\d+(ms|MS))?/g,
      css: 'color2'
    },
    /* other custom regexes */
    {
      //string literal 'myvalue'
      regex: SyntaxHighlighter.regexLib.singleQuotedString,
      css: 'string'
    }
  ];
};
SyntaxHighlighter.brushes.IEC61131.prototype     = new SyntaxHighlighter.Highlighter();
SyntaxHighlighter.brushes.IEC61131.aliases = ['structuredtext', 'ST', 'IEC61131', 'iec61131', 'st'];

Highlighted are main differences, note that we’re not using Brush, as before but SyntaxHighlighter.brushes.IEC61131 instead.

<?php
/*put the usual WordPress plugin info here*/

//hook to init
add_action( 'init', 'syntaxhighlighter_IEC61131_regscript' );

// register brushe
function syntaxhighlighter_IEC61131_regscript() {
	wp_register_script( 'syntaxhighlighter-brush-iec61131', plugins_url( 'IEC61131-brush.js', __FILE__ ), array('syntaxhighlighter-core'), '1.2.3' );
}

// add filter for aliases
add_filter( 'syntaxhighlighter_brushes', 'syntaxhighlighter_IEC61131_brush' );

function syntaxhighlighter_IEC61131_brush($brushes) {
	$brushes['iec61131'] = 'iec61131';
   	$brushes['IEC61131'] = $brushes['iec61131'];
   	$brushes['structuredtext'] = $brushes['iec61131'];
   	$brushes['ST'] = $brushes['iec61131'];
   	$brushes['st'] = $brushes['iec61131'];
   
   return $brushes;
}
?>

Things we do in our litle plugin:

  • on line 5 we hook to WordPress init in order to
  • register our js script and it’s dependencies on line 9
  • on line 13 we register to SyntaxHighlighter Evolved filter for brushes in order to make it aware of our existance
  • finally we register our aliases (remember last line of our js plugin?) so that we could use them as shortcodes

And that’s pretty it when it comes to implement custom syntax plugin. It takes less time to create plugin than to write about it…

 

PS. I always wanted to release something under WTF PL 🙂