F# Web Snippets
F# Web Snippets is a tool for formatting your F# source code for web pages or blogs. It does colorization of the code and, more interestingly, adds tool tips with types and other information. This is especially important for languages like F# where types are not written explicitly in the source code. When reading F# code in Visual Studio, you can use tool tips to get information about the type, which is very useful when understanding code. However, if you post a code snippet to a web, the information about types is gone! F# Web Snippets generates snippets that include tool tips for identifiers in the same way as Visual Studio.
The following two code snippets were generated from a single script file. When you place the cursor over
an identifier (such as Hello, Console or name), you should see
a tool tip with additional information:
1: /// Says hello to the specified person/entity 2: type Hello(name) = 3: /// Display 'Hello <name>' message in console 4: member x.SayHello() = 5: Console.WriteLine("Hello " + name)F# Web Snippets
Note that the two snippets were generated from a single file, so we can see full information
about the Hello type (declared in the first snippet) in the second snippet, including
its members and documentation extracted from the /// comment:
1: let hello = new Hello("World") 2: hello.SayHello()F# Web Snippets
Get F# Web Snippets
There is a WinForms version and web based version of the tool. The WinForms based version has some additional features, runs faster so it is a better choice if you plan to use it seriously. The web based version is mainly for a demonstration (processing a simple script takes about 50% CPU time for a while, so please be nice to my server!)
- Go straight to the web based F# Web Snippets to try it out!
- Download a stand-alone Windows Forms based F# Web Snippets application.
- Read more about the tool in a blog post (and get the source code too)
- Download JavaScript and CSS templates for your blog or web
Using F# Web Snippets
The tool uses F# compiler service to do the formatting and to get tool tip texts. This
means that you'll see exactly the same information as in Visual Studio. In order to use it,
you need to have an F# script file (.fsx file) that the compiler can type-check
(so that it can generate correct tool tips). Obviously, the tool needs a complete and correct
script file and it cannot process a snippet without the full script context.
Marking snippets
To make it easier to generate snippets from the script file, the tool uses meta-comments to mark parts of code that you want to process. For example, the following script file generates snippet that is displayed in the screenshot on the right.
1: let isEven n = n%2 = 0 2: let formatInt n = (string n) + "N" 3: 4: // [snippet:Filtering and projection] 5: let res = 6: [ 1 .. 10 ] 7: |> List.filter isEven 8: |> List.map formatInt 9: // [/snippet]
The meta-comment syntax is quite simple - you can enclose any block of code between [snippet:<Title>]
and [/snippet] tags. As the screenshot demonstrates, F# Web Snippets tool will generate HTML
only for snippets marked using meta-comments. It also picks the title of a snippet from the comment
so that you can easily see which snippet is which. However, because we provided a complete script
file, the tool can generate tool tips even for items that are not declared in the snippets (e.g.
formatInt function in the screenshot).
Omitting blocks of code
When presenting a code snippet, it is often useful to hide some part of the code. For example when we have a type declaration and want to demonstrate just the structure of the type without looking at the actual implementation. When using F# Web Snippets, we can use another form of meta-comments to hide a block of code:
1: /// Mutable counter that can be incremented and decremented 2: type Counter(init) = 3: (private fields omitted) 4: member x.Increment = (...) 5: member x.Decrement = (...)F# Web Snippets
When hiding a block of code, we can provide a replacement text that will be displayed in the gray box (the look can be, of course, changed by modifying a CSS style). When you place a mouse pointer over the box, you'll see the original code (without unnecessary indentation and line breaks). The following snippet shows the code that we need to write to produce the above snippet:
1: /// Mutable counter that can be incremented and decremented 2: type Counter(init) = 3: (*[omit:(private fields omitted)]*) 4: let mutable n = init(*[/omit]*) 5: member x.Increment = (*[omit:(...)]*) 6: n <- n + 1 7: n(*[/omit]*) 8: member x.Decrement = (*[omit:(...)]*) 9: n <- n - 1 10: n(*[/omit]*)F# Web Snippets
The syntax of the meta-comments is again quite simple. One notable difference is that snippets are
marked using a // comment that needs to be a single thing on the whole line. When specifying
omission, we may want to specify a region that starts in the middle of a line and spans over a part of a line
or over several lines and then ends somewhere in the middle of another line. To enable this, we need to
use inline comments, which are written as (* ... *). In the starting tag, we
specify the replacement text, so we can write [omit:<Replacement>]. Note that the
replacement text doesn't have to be wrapped in parentheses (this is just a convention that I used in
the previous example). The ending tag is simply written as [/omit].
Tool configuration
The tool internally calls F# compiler and it will work correctly only when the script file type-checks without errors. This means that you may need to provide some information about the context. This can be done using a few options in the Windows Forms based version of the tool (the web based version supports only default .NET 2.0 script context). The ways to configure the tool are:
- File name - This is not used as the source for the parser - if you
modify the content in the text box, it will use the modified version. A file name is needed
because F# may need to resolve files referenced using
#loadand#rcommands (these are available only when the file name ends with.fsx) - #r and #load - You can use the standard
#loadand#rcommands in the source code to load other F# source files and reference additional .NET libraries. This is usually the easiest option to make the script type check. - Defined symbols - Here you can provide pre-processor symbols that
are defined (so that the colorizer can properly recognize inactive code marked with
#if) - Command line - The "ultimate" option that allows you to provide any
command line parameters to the compiler. You'll need this if you want to reference some
non-standard
mscorliblibrary (e.g. Silverlight or XNA), which requires the--noframeworkflag. The format should be the same as for compiler options (if a path contains space, it can be wrapped in double quotes, e.g.-r:"C:\Program Files\a.dll") - Standard - Contains some common command line options for the tool. Since
the tool is compiled using .NET 2.0, you need to use the drop down if you want to type-check
against .NET 4.0 runtime. The other options are experimental. You can customize the
settings here by editing the
standard.xmlfile in the application directory.
There are also a couple of settings that configure the HTML generator, so if you want to change the look of the formatted snippet, here is what you can do:
- CSS and JavaScript - The generated code uses CSS classes (such as
cfor comments,kfor keywords etc.), so colors can be configured by editing the defaultstyle.cssfile (or by adding styles to your blog). The JavaScript code for showing tool tips can be modified intips.js(and you also need to reference it from your blog). - Add line numbers - If the option is checked, the tool will add line numbers to the generated snippet (which makes the snippet nicer, but more difficult to copy & paste).
- Prefix - Here you can set a unique prefix that will be used for
idattributes in the generated HTML (you need to change this if you want to include snippets from multiple script files in a single page - to avoid name clashes in the generated HTML).
Full name: Untitled.isEven
type: int
implements: System.IComparable
implements: System.IFormattable
implements: System.IConvertible
implements: System.IComparable<int>
implements: System.IEquatable<int>
inherits: System.ValueType
Full name: Untitled.formatInt
val string : 'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
Full name: Untitled.res
type: string list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<string>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<string>
implements: System.Collections.IEnumerable
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of 'T * 'T list
with
interface System.Collections.IEnumerable
interface System.Collections.Generic.IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
end
Full name: Microsoft.FSharp.Collections.List<_>
type: List<'T>
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<'T>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<'T>
implements: System.Collections.IEnumerable
Full name: Microsoft.FSharp.Collections.List.filter
Full name: Microsoft.FSharp.Collections.List.map
class
new : name:string -> Hello
member SayHello : unit -> unit
end
Full name: Untitled.Hello
Says hello to the specified person/entity
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
Full name: Untitled.Hello.SayHello
Display 'Hello <name>' message in console
class
static member BackgroundColor : System.ConsoleColor with get, set
static member Beep : unit -> unit
static member Beep : int * int -> unit
static member BufferHeight : int with get, set
static member BufferWidth : int with get, set
static member CapsLock : bool
static member Clear : unit -> unit
static member CursorLeft : int with get, set
static member CursorSize : int with get, set
static member CursorTop : int with get, set
static member CursorVisible : bool with get, set
static member Error : System.IO.TextWriter
static member ForegroundColor : System.ConsoleColor with get, set
static member In : System.IO.TextReader
static member InputEncoding : System.Text.Encoding with get, set
static member KeyAvailable : bool
static member LargestWindowHeight : int
static member LargestWindowWidth : int
static member MoveBufferArea : int * int * int * int * int * int -> unit
static member MoveBufferArea : int * int * int * int * int * int * char * System.ConsoleColor * System.ConsoleColor -> unit
static member NumberLock : bool
static member OpenStandardError : unit -> System.IO.Stream
static member OpenStandardError : int -> System.IO.Stream
static member OpenStandardInput : unit -> System.IO.Stream
static member OpenStandardInput : int -> System.IO.Stream
static member OpenStandardOutput : unit -> System.IO.Stream
static member OpenStandardOutput : int -> System.IO.Stream
static member Out : System.IO.TextWriter
static member OutputEncoding : System.Text.Encoding with get, set
static member Read : unit -> int
static member ReadKey : unit -> System.ConsoleKeyInfo
static member ReadKey : bool -> System.ConsoleKeyInfo
static member ReadLine : unit -> string
static member ResetColor : unit -> unit
static member SetBufferSize : int * int -> unit
static member SetCursorPosition : int * int -> unit
static member SetError : System.IO.TextWriter -> unit
static member SetIn : System.IO.TextReader -> unit
static member SetOut : System.IO.TextWriter -> unit
static member SetWindowPosition : int * int -> unit
static member SetWindowSize : int * int -> unit
static member Title : string with get, set
static member TreatControlCAsInput : bool with get, set
static member WindowHeight : int with get, set
static member WindowLeft : int with get, set
static member WindowTop : int with get, set
static member WindowWidth : int with get, set
static member Write : bool -> unit
static member Write : char -> unit
static member Write : char [] -> unit
static member Write : float -> unit
static member Write : decimal -> unit
static member Write : float32 -> unit
static member Write : int -> unit
static member Write : uint32 -> unit
static member Write : int64 -> unit
static member Write : uint64 -> unit
static member Write : obj -> unit
static member Write : string -> unit
static member Write : string * obj -> unit
static member Write : string * obj [] -> unit
static member Write : string * obj * obj -> unit
static member Write : char [] * int * int -> unit
static member Write : string * obj * obj * obj -> unit
static member Write : string * obj * obj * obj * obj -> unit
static member WriteLine : unit -> unit
static member WriteLine : bool -> unit
static member WriteLine : char -> unit
static member WriteLine : char [] -> unit
static member WriteLine : decimal -> unit
static member WriteLine : float -> unit
static member WriteLine : float32 -> unit
static member WriteLine : int -> unit
static member WriteLine : uint32 -> unit
static member WriteLine : int64 -> unit
static member WriteLine : uint64 -> unit
static member WriteLine : obj -> unit
static member WriteLine : string -> unit
static member WriteLine : string * obj -> unit
static member WriteLine : string * obj [] -> unit
static member WriteLine : char [] * int * int -> unit
static member WriteLine : string * obj * obj -> unit
static member WriteLine : string * obj * obj * obj -> unit
static member WriteLine : string * obj * obj * obj * obj -> unit
end
Full name: System.Console
Console.WriteLine() : unit
Console.WriteLine(value: string) : unit
Console.WriteLine(value: obj) : unit
Console.WriteLine(value: uint64) : unit
Console.WriteLine(value: int64) : unit
Console.WriteLine(value: uint32) : unit
Console.WriteLine(value: int) : unit
Console.WriteLine(value: float32) : unit
Console.WriteLine(value: float) : unit
Console.WriteLine(value: decimal) : unit
(+9 other overloads)
Display 'Hello <name>' message in console
class
new : init:int -> Counter
member Decrement : int
member Increment : int
end
Full name: Untitled.Counter
Mutable counter that can be incremented and decremented
type: int
implements: System.IComparable
implements: System.IFormattable
implements: System.IConvertible
implements: System.IComparable<int>
implements: System.IEquatable<int>
inherits: System.ValueType
Full name: Untitled.Counter.Increment
n
Full name: Untitled.Counter.Decrement
n
type: int
implements: System.IComparable
implements: System.IFormattable
implements: System.IConvertible
implements: System.IComparable<int>
implements: System.IEquatable<int>
inherits: System.ValueType
Published: September 28, 2010 03:20








