Looking under the cover (How does it work?)
The source code of the project is available in the F# Community Samples project at CodePlex (under the MS-PL license). In this section, I'll write little information about the implementation of the tool. This may be interesting if you want to implement something similar yourself (anything to do with F# color highlighting or IntelliSense) or if you want to contribute to the tool - it is open-source and you are more than welcome to make it even better!
The implementation is easier than you
would expect, because the information about types as well as the tokenizer (used for colorization)
is available as a service of the F# compiler (more specifically, the FSharp.Compiler.dll
assembly). The only problem is that the functionality is not quite documented (there are some comments
in the source code distributed with the F# CTP) and that the functionality is marked as internal
(with several InternalsVisibleTo
attributes that expose it to F# integration for Visual
Studio).
Internal F# language service API
To call the internal
API, I'm using a couple of wrapper types that provide a typed
access to the F# compiler API. Under the cover, the wrappers use .NET Reflection to call the
F# compiler services. To implement the wrappers, I first create my implementation of the dynamic
invoke operator (<expr>?<ident>
) that calls a method or reads a property
of any .NET object using Reflection.
The implementation of the dynamic invoke operator is quite interesting, but it would require a
whole separate blog post, so we won't discuss it here (although I may write the blog post about it
sooner or later and you can find it in the source code). Instead, we'll look at a part of the wrapper
for the most important type. The InteractiveChecker
type represents an F# compiler
service running in the background that can be called to parse a source code (Visual Studio does that
when the source changes) and to get information about a parsed F# file. There are two kinds of information
that we can get from the background service:
- Untyped parse results (the
UntypedParseInfo
type) - this type represents information that the F# compiler obtains after running initial parsing of the source code (but before the type-checking has started). It can be used to get the names of identifiers in the file (e.g. to display in navigation bars in Visual Studio) etc. In F# Web Snippets we don't need anything from this type directly. However, we still need to get it before we can call a method to get the second kind of information... - Typed parse results (the
TypeCheckAnswer
type) - this type is returned as a result of type-checking (and so it may take some time before we get it back). It can be used to get information about types of various identifiers and expressions in the source code and also to implement auto-completion. Note that we don't get a full AST of the source code, but simply an object that can be used for getting some specific IntelliSense information.
The following snippet shows a part of the wrapper for the InteractiveChecker
type.
It shows a method used for creating it and two methods that are used to get the untyped and
typed information about F# source file. Finally, there is also a method that tries to get both of
the information from a cache (which can be used by IDE to get information quickly). As you can see,
the dynamic access operator makes the implementation quite easy:
1: type InteractiveChecker(wrapped:obj) = 2: /// Crate a new instance of a wrapped InteractiveChecker object 3: static member Create (dirty:FileTypeCheckStateIsDirty) = 4: InteractiveChecker(FSharpCompiler.InteractiveChecker?Create(dirty)) 5: 6: /// Parse a source code file, returning a handle that can be used for obtaining navigation 7: /// bar information; to get the full information, call 'TypeCheckSource' method on the result 8: member x.UntypedParse(filename:string, source:string, options:CheckOptions) : UntypedParseInfo = 9: UntypedParseInfo(wrapped?UntypedParse(filename, source, options.Wrapped)) 10: 11: /// Typecheck a source code file, returning a handle to the results of the parse including 12: /// the reconstructed types in the file. Returns 'None' if the background builder is not yet 13: /// done preparing the type check results for the antecedent to the file. 14: member x.TypeCheckSource 15: ( parsed:UntypedParseInfo, filename:string, fileversion:int, 16: source:string, options:CheckOptions, (IsResultObsolete f)) = (...) 17: 18: /// Try to get recent type check results for a file. This may arbitrarily refuse to 19: /// return any results if the 'InteractiveChecker' would like a chance to recheck the 20: /// file, in which case 'UntypedParse' and 'TypeCheckSource' should be called. If the 21: /// source of the file has changed the results returned by this function may be out 22: /// of date, though may still be usable for generating intellsense menus and information. 23: member x.TryGetRecentTypeCheckResultsForFile(filename:string, options:CheckOptions) = 24: let res = wrapped?TryGetRecentTypeCheckResultsForFile(filename, options.Wrapped) : obj 25: if res = null then None else 26: let tuple = res?Value 27: Some(UntypedParseInfo(tuple?Item1), TypeCheckResults(tuple?Item2), int tuple?Item3)F# Web Snippets
The ?
operator can be used in various ways. In the Create
method,
we use it to call a static method of a type (the InteractiveChecker
property of the
FSharpCompiler
type returns a value of type System.Type
that represents
the type whose static method we want to call). In the UntypedParse
method,
we call an instance method of the wrapped object. In both of the cases, the parameters
are written as a tuple and the dynamic invoke operator extracts elements of the tuple and
passes it to the method using Reflection. Note that we have to provide type annotations (for
both parameters and return type), because the compiler doesn't have any hints about the
types. Without type annotations, everything would be of type obj
, but we want
to define a typed wrapper. We also wrap the result of method call into other wrapper types
(e.g. UntypedParseInfo
) that are implemented similarly to InteractiveChecker
.
Finally, the TryGetRecentTypeCheckResultsForFile
method shows one complication
of this approach. When a method returns an F# option type (or a tuple or list), we don't know
the exact type of the result (because the actual type argument is some internal type).
As a result, we cannot use the option type (or a tuple) in an untyped manner. For option type,
we simply check if the value is null
, because this is how None
is represented and otherwise use the Value
property to get the actual value.
The situation with tuples is quite similar - we need to dynamically access the properties
Item1
, Item2
, etc. to get the values of the tuple.
Obtaining typed information
Once we have the wrapper, we can use it to parse F# source code and get typed information
for IntelliSense. The following code shows a part of a type declaration that implements the
source file processing. It starts by creating an instance of InteractiveChecker
and constructing object that represents F# compiler options. Then we parse the source code
to get an untyped information. This is relatively fast operation that doesn't fail. Getting
typed information may fail (the checker needs to process all referenced files first), so
we use asynchronous workflow to invoke the operation repeatedly:
1: type SourceFile(file, source, lines:string[], ?options, ?defines) = 2: (construction of interactive checker and compiler options omitted) 3: 4: // Run first parsing phase - parse source into AST without type information 5: let untypedInfo = checker.UntypedParse(file, source, opts) 6: 7: /// Type-checking takes some time and doesn't return information on the 8: /// first call, so this function creates workflow that tries repeatedly 9: let rec getTypeCheckInfo() = async { 10: let obs = IsResultObsolete(fun () -> false) 11: let info = checker.TypeCheckSource(untypedInfo, file, 0, source, opts, obs) 12: match info with 13: | TypeCheckSucceeded(res) when res.TypeCheckInfo.IsSome -> 14: let errs = (copying of errors omitted) 15: return res.TypeCheckInfo.Value, errs 16: | _ -> 17: do! Async.Sleep(500) 18: return! getTypeCheckInfo() } 19: 20: /// Runs type checking and allows specifying a timeout 21: member x.RunTypeCheck(?timeout) = 22: Async.RunSynchronously(getTypeCheckInfo(), ?timeout = timeout)F# Web Snippets
The asynchronous workflow implements a simple loop that calls TypeCheckSource
.
When the result of the call is a value representing successful parsing and it contains a
value with the actual result then we return the value (together with a list of errors reported
by F# compiler). If the operation fails, we simply wait 500ms and then try again. The workflow
can be started from the RunTypeCheck
method which allows specification of a timeout
and blocks until the operation completes (the application doesn't hang, because the whole
processing is done in background).
As you can see from the tool tips in the snippet above, the object that we get as the result
has a type TypeCheckInfo
. This type exposes various methods that can be used to
get information that might be used to implement IntelliSense for F#. In the next section, we'll see
how to use it to get tool tip for a specified location in the source.
Processing of source code lines
Once the compiler successfully parses and type-checks our F# source code, we process the entire
source code, colorize keywords and literals and generate tool tips for identifiers. The processing
is implemented using SourceTokenizer
type, which is relatively easy to use. It gives
us a list of tokens for each line. We will not look at working with this type (you can find
it in the source code) and instead we'll look at post processing of lines that calculates color
of tokens and finds tool tips using the TypeCheckInfo
object:
1: let rec processLine island tokens = seq { 2: match tokens with 3: | [] -> () 4: | (str, (tok:TokenInformation))::rest -> 5: (updating of long identifier information omitted) 6: let tip = 7: // If we're processing an identfier, see if it has any tool tip 8: if (tok.TokenName = "IDENT") then 9: let island = island |> List.rev 10: let pos = (line, tok.LeftColumn + 1) 11: let tip = checkInfo.GetDataTipText(pos, lines.[line], island, identToken) 12: match ToolTip.TryCreate(tip) with 13: | Some(_) as res -> res 14: | _ when island.Length > 1 -> (alternative attempt omitted) 15: | _ -> None 16: elif tok.TokenName.StartsWith("OMIT") then (...) 17: else None 18: 19: // Find color for the current token 20: let color = 21: if tok.TokenName.StartsWith("OMIT") then Some("omitted") 22: else Colors.colorMap.TryFind(tok.ColorClass) 23: // Return all information about token and continue 24: yield { Token = tok; Text = str; Color = color; Tip = tip } 25: yield! processLine island rest }F# Web Snippets
The snippet shows a function processLine
that recursively processes a list of tokens
(tokens
) on a single line. It also maintains a state with the current long name
(named island
), which is needed for getting tool tip information. An example of a long
name is Collections.List.map
- when a mouse pointer is over List
, we want
to show information about the module, but when the pointer moves to map
, we want to
show type signature of a function. When getting the IntelliSense information, the F# language service
wants a current identifier as an input (so that it doesn't show outdated information based just on
the location when the source code changes).
In the recursive processing, we get a TokenInformation
value. When the name of the
token is IDENT
, we want to see if there is any tool tip information for the token, so
we use the GetDataTipText
method to query the F# language service. Alternatively, the
token name may be OMIT
- this is a special name generated by our pre-processing that
deals with (*[omit:...]*)
comments. In this case, we return a tool tip with the
collapsed text.
Finally, once we determine the tool tip information, we also want to get a color of the current
token. This is quite easy, because the color is reported from the tokenizer (the property name is
ColorClass
). We first handle our special OMIT
token and for all other
(standard) tokens, we use a simple lookup into a table that returns a CSS class name. You can find
the possible CSS class names in a sample CSS file template (see downloads below).
Summary
In this article, I presented a tool for generating nice HTML snippets from F# source code called F# Web Snippets. The most interesting thing about the tool is that it also generates tool tips with type information for F# identifiers. This way, the readers of your blog get almost the same user experience as when reading F# code in Visual Studio. The additional information makes the code much easier to follow. You can see some examples of formatted F# code in this article and also in my three recent articles on parallel programming. To use the tool, you can either try a (somewhat limited and slow) web based version or download a standalone WinForms application (see links below). If you want to use the tool on your blog, you'll need to add a simple JavaScript and CSS snippets to your blog template (you can get those below too).
The second part of the article also talked briefly about the implementation - the tool invokes F# compiler service under the cover. This is done using Reflection, because the services are internal, but it provides a reasonably comfortable way of implementing colorization or IntelliSense tools for F#. I demonstrated how to initialize the service and how to use it to get tool tip information - hopefully, you can use this information to build some interesting F# tools yourself!
References & source code
- Download the source code from F# Community Samples project at CodePlex (go to Samples/WebSnippets).
- For a more detailed user guide, see the documentation
- Try web based version or download WinForms based version
- Download JavaScript and CSS templates for your blog or web
from Microsoft.FSharp.Control
Full name: Untitled.downloadUrl
Asynchronously download the content of a web page
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
type: WebRequest
implements: Runtime.Serialization.ISerializable
inherits: MarshalByRefObject
class
inherit System.Net.WebRequest
member Abort : unit -> unit
member Accept : string with get, set
member AddRange : int -> unit
member AddRange : int * int -> unit
member AddRange : string * int -> unit
member AddRange : string * int * int -> unit
member Address : System.Uri
member AllowAutoRedirect : bool with get, set
member AllowWriteStreamBuffering : bool with get, set
member AutomaticDecompression : System.Net.DecompressionMethods with get, set
member BeginGetRequestStream : System.AsyncCallback * obj -> System.IAsyncResult
member BeginGetResponse : System.AsyncCallback * obj -> System.IAsyncResult
member ClientCertificates : System.Security.Cryptography.X509Certificates.X509CertificateCollection with get, set
member Connection : string with get, set
member ConnectionGroupName : string with get, set
member ContentLength : int64 with get, set
member ContentType : string with get, set
member ContinueDelegate : System.Net.HttpContinueDelegate with get, set
member CookieContainer : System.Net.CookieContainer with get, set
member Credentials : System.Net.ICredentials with get, set
member EndGetRequestStream : System.IAsyncResult -> System.IO.Stream
member EndGetRequestStream : System.IAsyncResult * System.Net.TransportContext -> System.IO.Stream
member EndGetResponse : System.IAsyncResult -> System.Net.WebResponse
member Expect : string with get, set
member GetRequestStream : unit -> System.IO.Stream
member GetRequestStream : System.Net.TransportContext -> System.IO.Stream
member GetResponse : unit -> System.Net.WebResponse
member HaveResponse : bool
member Headers : System.Net.WebHeaderCollection with get, set
member IfModifiedSince : System.DateTime with get, set
member KeepAlive : bool with get, set
member MaximumAutomaticRedirections : int with get, set
member MaximumResponseHeadersLength : int with get, set
member MediaType : string with get, set
member Method : string with get, set
member Pipelined : bool with get, set
member PreAuthenticate : bool with get, set
member ProtocolVersion : System.Version with get, set
member Proxy : System.Net.IWebProxy with get, set
member ReadWriteTimeout : int with get, set
member Referer : string with get, set
member RequestUri : System.Uri
member SendChunked : bool with get, set
member ServicePoint : System.Net.ServicePoint
member Timeout : int with get, set
member TransferEncoding : string with get, set
member UnsafeAuthenticatedConnectionSharing : bool with get, set
member UseDefaultCredentials : bool with get, set
member UserAgent : string with get, set
static member DefaultCachePolicy : System.Net.Cache.RequestCachePolicy with get, set
static member DefaultMaximumErrorResponseLength : int with get, set
static member DefaultMaximumResponseHeadersLength : int with get, set
end
Full name: System.Net.HttpWebRequest
type: HttpWebRequest
implements: Runtime.Serialization.ISerializable
inherits: WebRequest
inherits: MarshalByRefObject
WebRequest.Create(requestUri: Uri) : WebRequest
WebRequest.Create(requestUriString: string) : WebRequest
class
new : string -> System.Uri
new : string * bool -> System.Uri
new : string * System.UriKind -> System.Uri
new : System.Uri * string -> System.Uri
new : System.Uri * string * bool -> System.Uri
new : System.Uri * System.Uri -> System.Uri
member AbsolutePath : string
member AbsoluteUri : string
member Authority : string
member DnsSafeHost : string
member Equals : obj -> bool
member Fragment : string
member GetComponents : System.UriComponents * System.UriFormat -> string
member GetHashCode : unit -> int
member GetLeftPart : System.UriPartial -> string
member Host : string
member HostNameType : System.UriHostNameType
member IsAbsoluteUri : bool
member IsBaseOf : System.Uri -> bool
member IsDefaultPort : bool
member IsFile : bool
member IsLoopback : bool
member IsUnc : bool
member IsWellFormedOriginalString : unit -> bool
member LocalPath : string
member MakeRelative : System.Uri -> string
member MakeRelativeUri : System.Uri -> System.Uri
member OriginalString : string
member PathAndQuery : string
member Port : int
member Query : string
member Scheme : string
member Segments : string []
member ToString : unit -> string
member UserEscaped : bool
member UserInfo : string
static val UriSchemeFile : string
static val UriSchemeFtp : string
static val UriSchemeGopher : string
static val UriSchemeHttp : string
static val UriSchemeHttps : string
static val UriSchemeMailto : string
static val UriSchemeNews : string
static val UriSchemeNntp : string
static val UriSchemeNetTcp : string
static val UriSchemeNetPipe : string
static val SchemeDelimiter : string
static member CheckHostName : string -> System.UriHostNameType
static member CheckSchemeName : string -> bool
static member Compare : System.Uri * System.Uri * System.UriComponents * System.UriFormat * System.StringComparison -> int
static member EscapeDataString : string -> string
static member EscapeUriString : string -> string
static member FromHex : char -> int
static member HexEscape : char -> string
static member HexUnescape : string * int -> char
static member IsHexDigit : char -> bool
static member IsHexEncoding : string * int -> bool
static member IsWellFormedUriString : string * System.UriKind -> bool
static member TryCreate : string * System.UriKind * System.Uri -> bool
static member TryCreate : System.Uri * string * System.Uri -> bool
static member TryCreate : System.Uri * System.Uri * System.Uri -> bool
static member UnescapeDataString : string -> string
end
Full name: System.Uri
type: Uri
implements: Runtime.Serialization.ISerializable
type: WebResponse
implements: Runtime.Serialization.ISerializable
implements: IDisposable
inherits: MarshalByRefObject
type: Stream
implements: IDisposable
inherits: MarshalByRefObject
type: StreamReader
implements: IDisposable
inherits: TextReader
inherits: MarshalByRefObject
class
inherit System.IO.TextReader
new : System.IO.Stream -> System.IO.StreamReader
new : System.IO.Stream * bool -> System.IO.StreamReader
new : System.IO.Stream * System.Text.Encoding -> System.IO.StreamReader
new : System.IO.Stream * System.Text.Encoding * bool -> System.IO.StreamReader
new : System.IO.Stream * System.Text.Encoding * bool * int -> System.IO.StreamReader
new : string -> System.IO.StreamReader
new : string * bool -> System.IO.StreamReader
new : string * System.Text.Encoding -> System.IO.StreamReader
new : string * System.Text.Encoding * bool -> System.IO.StreamReader
new : string * System.Text.Encoding * bool * int -> System.IO.StreamReader
member BaseStream : System.IO.Stream
member Close : unit -> unit
member CurrentEncoding : System.Text.Encoding
member DiscardBufferedData : unit -> unit
member EndOfStream : bool
member Peek : unit -> int
member Read : unit -> int
member Read : char [] * int * int -> int
member ReadLine : unit -> string
member ReadToEnd : unit -> string
static val Null : System.IO.StreamReader
end
Full name: System.IO.StreamReader
type: StreamReader
implements: IDisposable
inherits: TextReader
inherits: MarshalByRefObject
Full name: Untitled.getTotalLength
Download specified pages and add their lengths
type: string list
implements: Collections.IStructuralEquatable
implements: IComparable<List<string>>
implements: IComparable
implements: Collections.IStructuralComparable
implements: Collections.Generic.IEnumerable<string>
implements: Collections.IEnumerable
type: string []
implements: ICloneable
implements: Collections.IList
implements: Collections.ICollection
implements: Collections.Generic.IList<string>
implements: Collections.Generic.ICollection<string>
implements: seq<string>
implements: Collections.IEnumerable
inherits: Array
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of 'T * 'T list
with
interface Collections.IEnumerable
interface 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: Collections.IStructuralEquatable
implements: IComparable<List<'T>>
implements: IComparable
implements: Collections.IStructuralComparable
implements: Collections.Generic.IEnumerable<'T>
implements: Collections.IEnumerable
Full name: Microsoft.FSharp.Collections.List.map
type Async<'T>
Full name: Microsoft.FSharp.Control.Async<_>
--------------------
type Async
with
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitWaitHandle : waitHandle:Threading.WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:Threading.CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:Threading.CancellationToken -> unit
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:Threading.CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:Threading.CancellationToken -> unit
static member SwitchToContext : syncContext:Threading.SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<Threading.CancellationToken>
static member DefaultCancellationToken : Threading.CancellationToken
end
Full name: Microsoft.FSharp.Control.Async
from Microsoft.FSharp.Collections
Full name: Microsoft.FSharp.Collections.Seq.sumBy
class
new : char -> string
new : char * int * int -> string
new : System.SByte -> string
new : System.SByte * int * int -> string
new : System.SByte * int * int * System.Text.Encoding -> string
new : char [] * int * int -> string
new : char [] -> string
new : char * int -> string
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : obj -> int
member CompareTo : string -> int
member Contains : string -> bool
member CopyTo : int * char [] * int * int -> unit
member EndsWith : string -> bool
member EndsWith : string * System.StringComparison -> bool
member EndsWith : string * bool * System.Globalization.CultureInfo -> bool
member Equals : obj -> bool
member Equals : string -> bool
member Equals : string * System.StringComparison -> bool
member GetEnumerator : unit -> System.CharEnumerator
member GetHashCode : unit -> int
member GetTypeCode : unit -> System.TypeCode
member IndexOf : char -> int
member IndexOf : string -> int
member IndexOf : char * int -> int
member IndexOf : string * int -> int
member IndexOf : string * System.StringComparison -> int
member IndexOf : char * int * int -> int
member IndexOf : string * int * int -> int
member IndexOf : string * int * System.StringComparison -> int
member IndexOf : string * int * int * System.StringComparison -> int
member IndexOfAny : char [] -> int
member IndexOfAny : char [] * int -> int
member IndexOfAny : char [] * int * int -> int
member Insert : int * string -> string
member IsNormalized : unit -> bool
member IsNormalized : System.Text.NormalizationForm -> bool
member LastIndexOf : char -> int
member LastIndexOf : string -> int
member LastIndexOf : char * int -> int
member LastIndexOf : string * int -> int
member LastIndexOf : string * System.StringComparison -> int
member LastIndexOf : char * int * int -> int
member LastIndexOf : string * int * int -> int
member LastIndexOf : string * int * System.StringComparison -> int
member LastIndexOf : string * int * int * System.StringComparison -> int
member LastIndexOfAny : char [] -> int
member LastIndexOfAny : char [] * int -> int
member LastIndexOfAny : char [] * int * int -> int
member Length : int
member Normalize : unit -> string
member Normalize : System.Text.NormalizationForm -> string
member PadLeft : int -> string
member PadLeft : int * char -> string
member PadRight : int -> string
member PadRight : int * char -> string
member Remove : int -> string
member Remove : int * int -> string
member Replace : char * char -> string
member Replace : string * string -> string
member Split : char [] -> string []
member Split : char [] * int -> string []
member Split : char [] * System.StringSplitOptions -> string []
member Split : string [] * System.StringSplitOptions -> string []
member Split : char [] * int * System.StringSplitOptions -> string []
member Split : string [] * int * System.StringSplitOptions -> string []
member StartsWith : string -> bool
member StartsWith : string * System.StringComparison -> bool
member StartsWith : string * bool * System.Globalization.CultureInfo -> bool
member Substring : int -> string
member Substring : int * int -> string
member ToCharArray : unit -> char []
member ToCharArray : int * int -> char []
member ToLower : unit -> string
member ToLower : System.Globalization.CultureInfo -> string
member ToLowerInvariant : unit -> string
member ToString : unit -> string
member ToString : System.IFormatProvider -> string
member ToUpper : unit -> string
member ToUpper : System.Globalization.CultureInfo -> string
member ToUpperInvariant : unit -> string
member Trim : unit -> string
member Trim : char [] -> string
member TrimEnd : char [] -> string
member TrimStart : char [] -> string
static val Empty : string
static member Compare : string * string -> int
static member Compare : string * string * bool -> int
static member Compare : string * string * System.StringComparison -> int
static member Compare : string * string * System.Globalization.CultureInfo * System.Globalization.CompareOptions -> int
static member Compare : string * string * bool * System.Globalization.CultureInfo -> int
static member Compare : string * int * string * int * int -> int
static member Compare : string * int * string * int * int * bool -> int
static member Compare : string * int * string * int * int * System.StringComparison -> int
static member Compare : string * int * string * int * int * System.Globalization.CultureInfo * System.Globalization.CompareOptions -> int
static member Compare : string * int * string * int * int * bool * System.Globalization.CultureInfo -> int
static member CompareOrdinal : string * string -> int
static member CompareOrdinal : string * int * string * int * int -> int
static member Concat : obj -> string
static member Concat : obj [] -> string
static member Concat : string [] -> string
static member Concat : obj * obj -> string
static member Concat : string * string -> string
static member Concat : obj * obj * obj -> string
static member Concat : string * string * string -> string
static member Concat : obj * obj * obj * obj -> string
static member Concat : string * string * string * string -> string
static member Copy : string -> string
static member Equals : string * string -> bool
static member Equals : string * string * System.StringComparison -> bool
static member Format : string * obj -> string
static member Format : string * obj [] -> string
static member Format : string * obj * obj -> string
static member Format : System.IFormatProvider * string * obj [] -> string
static member Format : string * obj * obj * obj -> string
static member Intern : string -> string
static member IsInterned : string -> string
static member IsNullOrEmpty : string -> bool
static member Join : string * string [] -> string
static member Join : string * string [] * int * int -> string
end
Full name: System.String
type: String
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
Full name: Microsoft.FSharp.Core.String.length
let req = HttpWebRequest.Create(Uri(url))
let! resp = req.AsyncGetResponse()
let stream = resp.GetResponseStream()
let reader = new StreamReader(stream)
return! reader.AsyncReadToEnd() }
class
new : wrapped:obj -> InteractiveChecker
member GetCheckOptionsFromScriptRoot : filename:string * source:string -> CheckOptions
member StartBackgroundCompile : options:CheckOptions -> 'a
member TryGetRecentTypeCheckResultsForFile : filename:string * options:CheckOptions -> (UntypedParseInfo * TypeCheckResults * int) option
member TypeCheckSource : parsed:UntypedParseInfo * filename:string * fileversion:int * source:string * options:CheckOptions * IsResultObsolete -> TypeCheckAnswer
member UntypedParse : filename:string * source:string * options:CheckOptions -> UntypedParseInfo
static member Create : dirty:FileTypeCheckStateIsDirty -> InteractiveChecker
end
Full name: Untitled.SourceCodeServices.InteractiveChecker
Full name: Microsoft.FSharp.Core.obj
Full name: Untitled.SourceCodeServices.InteractiveChecker.Create
Crate a new instance of a wrapped InteractiveChecker object
Full name: Untitled.SourceCodeServices.FileTypeCheckStateIsDirty
class
private new : unit -> FSharpCompiler
static member CheckOptions : Type
static member InteractiveChecker : Type
static member IsResultObsolete : Type
static member SourceTokenizer : Type
static member TokenInformation : Type
end
Full name: Untitled.Reflection.FSharpCompiler
Wrapper type for the 'FSharp.Compiler.dll' assembly - expose types we use
Full name: Untitled.SourceCodeServices.InteractiveChecker.UntypedParse
Parse a source code file, returning a handle that can be used for obtaining navigation
bar information; to get the full information, call 'TypeCheckSource' method on the result
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
val string : 'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
class
new : wrapped:obj -> CheckOptions
member WithProjectOptions : options:string [] -> CheckOptions
member IsIncompleteTypeCheckEnvironment : bool
member ProjectFileName : string
member ProjectFileNames : string array
member ProjectOptions : string array
member UseScriptResolutionRules : bool
member Wrapped : obj
static member Create : fileName:string * fileNames:string [] * options:string [] * incomplete:bool * scriptRes:bool -> CheckOptions
end
Full name: Untitled.SourceCodeServices.CheckOptions
class
new : wrapped:obj -> UntypedParseInfo
member Wrapped : obj
end
Full name: Untitled.SourceCodeServices.UntypedParseInfo
Full name: Untitled.SourceCodeServices.InteractiveChecker.TypeCheckSource
Typecheck a source code file, returning a handle to the results of the parse including
the reconstructed types in the file. Returns 'None' if the background builder is not yet
done preparing the type check results for the antecedent to the file.
type: int
implements: IComparable
implements: IFormattable
implements: IConvertible
implements: IComparable<int>
implements: IEquatable<int>
inherits: ValueType
val int : 'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
type: int<'Measure>
implements: IComparable
implements: IConvertible
implements: IFormattable
implements: IComparable<int<'Measure>>
implements: IEquatable<int<'Measure>>
inherits: ValueType
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
type: int
implements: IComparable
implements: IFormattable
implements: IConvertible
implements: IComparable<int>
implements: IEquatable<int>
inherits: ValueType
union case IsResultObsolete.IsResultObsolete: (unit -> bool) -> IsResultObsolete
--------------------
type IsResultObsolete = | IsResultObsolete of (unit -> bool)
Full name: Untitled.SourceCodeServices.IsResultObsolete
Callback that indicates whether a requested result has become obsolete.
( wrapped?TypeCheckSource
( parsed.Wrapped, filename, fileversion, source, options.Wrapped,
FSharpCompiler.IsResultObsolete?NewIsResultObsolete(f) ) : obj)
Full name: Untitled.SourceCodeServices.InteractiveChecker.TryGetRecentTypeCheckResultsForFile
Try to get recent type check results for a file. This may arbitrarily refuse to
return any results if the 'InteractiveChecker' would like a chance to recheck the
file, in which case 'UntypedParse' and 'TypeCheckSource' should be called. If the
source of the file has changed the results returned by this function may be out
of date, though may still be usable for generating intellsense menus and information.
class
new : wrapped:obj -> TypeCheckResults
member Errors : ErrorInfo array
member TypeCheckInfo : TypeCheckInfo option
end
Full name: Untitled.SourceCodeServices.TypeCheckResults
A handle to the results of TypeCheckSource
class
new : file:string * source:string * lines:string [] * ?options:string * ?defines:string -> SourceFile
member ProcessSourceTokens : checkInfo:TypeCheckInfo * source:(int * (string * TokenInformation) list) list -> SnippetInfo list
member RunTypeCheck : ?timeout:int -> TypeCheckInfo * seq<ErrorInfo>
member TokenizeSource : unit -> (int * (string * TokenInformation) list) list
end
Full name: Untitled.SourceFile
Parses the specified file using F# compiler (by calling 'TokenizeSource'),
performs type checking (using 'RunTypeCheck') and then creates information
for the formatter (using 'ProcessSourceTokens')
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
type: string []
implements: ICloneable
implements: Collections.IList
implements: Collections.ICollection
implements: IList<string>
implements: ICollection<string>
implements: seq<string>
implements: Collections.IEnumerable
inherits: Array
val string : 'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
type: string option
implements: Collections.IStructuralEquatable
implements: IComparable<Option<string>>
implements: IComparable
implements: Collections.IStructuralComparable
type: string option
implements: Collections.IStructuralEquatable
implements: IComparable<Option<string>>
implements: IComparable
implements: Collections.IStructuralComparable
// Create an instance of an InteractiveChecker (which does background analysis
// in a typical IntelliSense editor integration for F#)
let checker = InteractiveChecker.Create(ignore)
// Get options for a standalone script file (this adds some
// default references and doesn't require full project information)
let opts = checker.GetCheckOptionsFromScriptRoot(file, source)
// Print additional information for debugging
let trace = false
// Parse command line options - split string by space, but if there is something
// enclosed in double quotes "..." then ignore spaces in the quoted text
let rec parseOptions (str:string) i opts current =
let opts =
if i < str.Length && str.[i] <> ' ' then opts
else (String(current |> List.rev |> Array.ofSeq))::opts
if i = str.Length then opts
elif str.[i] = ' ' then parseOptions str (i+1) opts []
elif str.[i] = '"' then
let endp = str.IndexOf('"', i+1)
let chars = str.Substring(i+1, endp - i - 1) |> List.ofSeq |> List.rev
parseOptions str (endp + 1) opts (chars @@ current)
else parseOptions str (i + 1) opts (str.[i] :: current)
// Override default options if the user specified something
let opts =
match options with
| Some(str:string) when not(String.IsNullOrEmpty(str)) ->
opts.WithProjectOptions(parseOptions str 0 [] [] |> Array.ofSeq)
| _ -> opts
// Creates an empty "Identifier" token (we need it when getting ToolTip)
let identToken = 176
Parse a source code file, returning a handle that can be used for obtaining navigation bar information
To get the full information, call 'TypeCheckSource' method on the result
Type-checking takes some time and doesn't return information on the
first call, so this function creates workflow that tries repeatedly
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
union case IsResultObsolete.IsResultObsolete: (unit -> bool) -> IsResultObsolete
--------------------
type IsResultObsolete = | IsResultObsolete of (unit -> bool)
Full name: Microsoft.FSharp.Compiler.SourceCodeServices.IsResultObsolete
Callback that indicates whether a requested result has become obsolete.
Typecheck a source code file, returning a handle to the results of the parse including
the reconstructed types in the file.
Return None if the background builder is not yet done prepring the type check results for the antecedent to the
file.
val TypeCheckSucceeded : TypeCheckResults -> TypeCheckAnswer
Full name: Microsoft.FSharp.Compiler.SourceCodeServices.TypeCheckSucceeded
--------------------
active recognizer TypeCheckSucceeded: TypeCheckAnswer -> Choice<unit,unit,TypeCheckResults>
Full name: Microsoft.FSharp.Compiler.SourceCodeServices.( |NoAntecedant|Aborted|TypeCheckSucceeded| )
A handle to type information gleaned from typechecking the file.
type: seq<ErrorInfo>
inherits: Collections.IEnumerable
{ StartColumn = e.StartColumn; StartLine = e.StartLine
Message = e.Message; IsError = e.Severity = Error } }
type Async<'T>
Full name: Microsoft.FSharp.Control.Async<_>
--------------------
type Async
with
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitWaitHandle : waitHandle:Threading.WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:Threading.CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:Threading.CancellationToken -> unit
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:Threading.CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:Threading.CancellationToken -> unit
static member SwitchToContext : syncContext:Threading.SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<Threading.CancellationToken>
static member DefaultCancellationToken : Threading.CancellationToken
end
Full name: Microsoft.FSharp.Control.Async
Full name: Untitled.SourceFile.RunTypeCheck
Runs type checking and allows specifying a timeout
type: int option
implements: Collections.IStructuralEquatable
implements: IComparable<Option<int>>
implements: IComparable
implements: Collections.IStructuralComparable
type: string list
implements: Collections.IStructuralEquatable
implements: IComparable<List<string>>
implements: IComparable
implements: Collections.IStructuralComparable
implements: IEnumerable<string>
implements: Collections.IEnumerable
type: (string * TokenInformation) list
implements: Collections.IStructuralEquatable
implements: IComparable<List<string * TokenInformation>>
implements: IComparable
implements: Collections.IStructuralComparable
implements: IEnumerable<string * TokenInformation>
implements: Collections.IEnumerable
val seq : seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
type: seq<'T>
inherits: Collections.IEnumerable
type: string
implements: IComparable
implements: ICloneable
implements: IConvertible
implements: IComparable<string>
implements: seq<char>
implements: Collections.IEnumerable
implements: IEquatable<string>
class
new : wrapped:obj -> TokenInformation
member WithRightColumn : rightColumn:int -> TokenInformation
member WithTokenName : tokenName:string -> TokenInformation
member CharClass : TokenCharKind
member ColorClass : TokenColorKind
member LeftColumn : int
member RightColumn : int
member Tag : int
member TokenName : string
member TriggerClass : TriggerClass
end
Full name: Microsoft.FSharp.Compiler.SourceCodeServices.TokenInformation
type: (string * TokenInformation) list
implements: Collections.IStructuralEquatable
implements: IComparable<List<string * TokenInformation>>
implements: IComparable
implements: Collections.IStructuralComparable
implements: IEnumerable<string * TokenInformation>
implements: Collections.IEnumerable
// (long identifier e.g. Collections.List.map)
let island =
match tok.TokenName with
| "DOT" -> island // keep what we have found so far
| "IDENT" -> str::island // add current identifier
| _ -> [] // drop everything - not in island
type: ToolTip option
implements: Collections.IStructuralEquatable
implements: IComparable<Option<ToolTip>>
implements: IComparable
implements: Collections.IStructuralComparable
class
new : unit -> System.Collections.Generic.List<'T>
new : int -> System.Collections.Generic.List<'T>
new : System.Collections.Generic.IEnumerable<'T> -> System.Collections.Generic.List<'T>
member Add : 'T -> unit
member AddRange : System.Collections.Generic.IEnumerable<'T> -> unit
member AsReadOnly : unit -> System.Collections.ObjectModel.ReadOnlyCollection<'T>
member BinarySearch : 'T -> int
member BinarySearch : 'T * System.Collections.Generic.IComparer<'T> -> int
member BinarySearch : int * int * 'T * System.Collections.Generic.IComparer<'T> -> int
member Capacity : int with get, set
member Clear : unit -> unit
member Contains : 'T -> bool
member ConvertAll<'TOutput> : System.Converter<'T,'TOutput> -> System.Collections.Generic.List<'TOutput>
member CopyTo : 'T [] -> unit
member CopyTo : 'T [] * int -> unit
member CopyTo : int * 'T [] * int * int -> unit
member Count : int
member Exists : System.Predicate<'T> -> bool
member Find : System.Predicate<'T> -> 'T
member FindAll : System.Predicate<'T> -> System.Collections.Generic.List<'T>
member FindIndex : System.Predicate<'T> -> int
member FindIndex : int * System.Predicate<'T> -> int
member FindIndex : int * int * System.Predicate<'T> -> int
member FindLast : System.Predicate<'T> -> 'T
member FindLastIndex : System.Predicate<'T> -> int
member FindLastIndex : int * System.Predicate<'T> -> int
member FindLastIndex : int * int * System.Predicate<'T> -> int
member ForEach : System.Action<'T> -> unit
member GetEnumerator : unit -> Enumerator<'T>
member GetRange : int * int -> System.Collections.Generic.List<'T>
member IndexOf : 'T -> int
member IndexOf : 'T * int -> int
member IndexOf : 'T * int * int -> int
member Insert : int * 'T -> unit
member InsertRange : int * System.Collections.Generic.IEnumerable<'T> -> unit
member Item : int -> 'T with get, set
member LastIndexOf : 'T -> int
member LastIndexOf : 'T * int -> int
member LastIndexOf : 'T * int * int -> int
member Remove : 'T -> bool
member RemoveAll : System.Predicate<'T> -> int
member RemoveAt : int -> unit
member RemoveRange : int * int -> unit
member Reverse : unit -> unit
member Reverse : int * int -> unit
member Sort : unit -> unit
member Sort : System.Collections.Generic.IComparer<'T> -> unit
member Sort : System.Comparison<'T> -> unit
member Sort : int * int * System.Collections.Generic.IComparer<'T> -> unit
member ToArray : unit -> 'T []
member TrimExcess : unit -> unit
member TrueForAll : System.Predicate<'T> -> bool
type Enumerator =
struct
member Current : 'T
member Dispose : unit -> unit
member MoveNext : unit -> bool
end
end
Full name: System.Collections.Generic.List<_>
type: List<'T>
implements: IList<'T>
implements: ICollection<'T>
implements: seq<'T>
implements: Collections.IList
implements: Collections.ICollection
implements: Collections.IEnumerable
Full name: Microsoft.FSharp.Collections.List.rev
type: int
implements: IComparable
implements: IFormattable
implements: IConvertible
implements: IComparable<int>
implements: IEquatable<int>
inherits: ValueType
Resolve the names at the given location to give a data tip
type: int
implements: IComparable
implements: IFormattable
implements: IConvertible
implements: IComparable<int>
implements: IEquatable<int>
inherits: ValueType
class
private new : str:string -> ToolTip
member ToolTipHtml : string
static member FromString : str:string -> ToolTip
static member TryCreate : tip:DataTipText -> ToolTip option
end
Full name: Untitled.ToolTip
Stores information about tool tip for an identifier
Creates a tool tip - returns 'None' if it contains no data
type: ToolTip option
implements: Collections.IStructuralEquatable
implements: IComparable<Option<ToolTip>>
implements: IComparable
implements: Collections.IStructuralComparable
let pos = (line, tok.LeftColumn + 2)
let tip = checkInfo.GetDataTipText(pos, lines.[line], [ str ], identToken)
ToolTip.TryCreate(tip)
String.StartsWith(value: string) : bool
String.StartsWith(value: string, comparisonType: StringComparison) : bool
String.StartsWith(value: string, ignoreCase: bool, culture: Globalization.CultureInfo) : bool
Some(ToolTip.FromString(tok.TokenName.Substring(4)))
type: string option
implements: Collections.IStructuralEquatable
implements: IComparable<Option<string>>
implements: IComparable
implements: Collections.IStructuralComparable
from Untitled
A mapping from kinds of tokens to CSS classes used by the formatter
Full name: Untitled.Colors.colorMap
type: Map<TokenColorKind,string>
implements: IComparable
implements: IDictionary<TokenColorKind,string>
implements: ICollection<KeyValuePair<TokenColorKind,string>>
implements: seq<KeyValuePair<TokenColorKind,string>>
implements: Collections.IEnumerable
Published: Monday, 18 October 2010, 1:42 AM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: functional, f#