vsintegration/src/FSharp.Editor/Common/Pervasive.fs (163 lines of code) (raw):

[<AutoOpen>] module Microsoft.VisualStudio.FSharp.Editor.Pervasive open System open System.IO open System.Threading.Tasks open System.Diagnostics /// Checks if the filePath ends with ".fsi" let isSignatureFile (filePath:string) = String.Equals (Path.GetExtension filePath, ".fsi", StringComparison.OrdinalIgnoreCase) /// Checks if the file paht ends with '.fsx' or '.fsscript' let isScriptFile (filePath:string) = let ext = Path.GetExtension filePath String.Equals (ext, ".fsx", StringComparison.OrdinalIgnoreCase) || String.Equals (ext, ".fsscript", StringComparison.OrdinalIgnoreCase) /// Path combination operator let (</>) path1 path2 = Path.Combine (path1, path2) type internal ISetThemeColors = abstract member SetColors: unit -> unit [<Sealed>] type MaybeBuilder () = // 'T -> M<'T> [<DebuggerStepThrough>] member inline __.Return value: 'T option = Some value // M<'T> -> M<'T> [<DebuggerStepThrough>] member inline __.ReturnFrom value: 'T option = value // unit -> M<'T> [<DebuggerStepThrough>] member inline __.Zero (): unit option = Some () // TODO: Should this be None? // (unit -> M<'T>) -> M<'T> [<DebuggerStepThrough>] member __.Delay (f: unit -> 'T option): 'T option = f () // M<'T> -> M<'T> -> M<'T> // or // M<unit> -> M<'T> -> M<'T> [<DebuggerStepThrough>] member inline __.Combine (r1, r2: 'T option): 'T option = match r1 with | None -> None | Some () -> r2 // M<'T> * ('T -> M<'U>) -> M<'U> [<DebuggerStepThrough>] member inline __.Bind (value, f: 'T -> 'U option): 'U option = Option.bind f value // 'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable [<DebuggerStepThrough>] member __.Using (resource: ('T :> System.IDisposable), body: _ -> _ option): _ option = try body resource finally if not <| obj.ReferenceEquals (null, box resource) then resource.Dispose () // (unit -> bool) * M<'T> -> M<'T> [<DebuggerStepThrough>] member x.While (guard, body: _ option): _ option = if guard () then // OPTIMIZE: This could be simplified so we don't need to make calls to Bind and While. x.Bind (body, (fun () -> x.While (guard, body))) else x.Zero () // seq<'T> * ('T -> M<'U>) -> M<'U> // or // seq<'T> * ('T -> M<'U>) -> seq<M<'U>> [<DebuggerStepThrough>] member x.For (sequence: seq<_>, body: 'T -> unit option): _ option = // OPTIMIZE: This could be simplified so we don't need to make calls to Using, While, Delay. x.Using (sequence.GetEnumerator (), fun enum -> x.While ( enum.MoveNext, x.Delay (fun () -> body enum.Current))) let maybe = MaybeBuilder() [<Sealed>] type AsyncMaybeBuilder () = [<DebuggerStepThrough>] member __.Return value : Async<'T option> = Some value |> async.Return [<DebuggerStepThrough>] member __.ReturnFrom value : Async<'T option> = value [<DebuggerStepThrough>] member __.ReturnFrom (value: 'T option) : Async<'T option> = async.Return value [<DebuggerStepThrough>] member __.Zero () : Async<unit option> = Some () |> async.Return [<DebuggerStepThrough>] member __.Delay (f : unit -> Async<'T option>) : Async<'T option> = async.Delay f [<DebuggerStepThrough>] member __.Combine (r1, r2 : Async<'T option>) : Async<'T option> = async { let! r1' = r1 match r1' with | None -> return None | Some () -> return! r2 } [<DebuggerStepThrough>] member __.Bind (value: Async<'T option>, f : 'T -> Async<'U option>) : Async<'U option> = async { let! value' = value match value' with | None -> return None | Some result -> return! f result } [<DebuggerStepThrough>] member __.Bind (value: System.Threading.Tasks.Task<'T>, f : 'T -> Async<'U option>) : Async<'U option> = async { let! value' = Async.AwaitTask value return! f value' } [<DebuggerStepThrough>] member __.Bind (value: 'T option, f : 'T -> Async<'U option>) : Async<'U option> = async { match value with | None -> return None | Some result -> return! f result } [<DebuggerStepThrough>] member __.Using (resource : ('T :> IDisposable), body : _ -> Async<_ option>) : Async<_ option> = try body resource finally if not (isNull resource) then resource.Dispose () [<DebuggerStepThrough>] member x.While (guard, body : Async<_ option>) : Async<_ option> = if guard () then x.Bind (body, (fun () -> x.While (guard, body))) else x.Zero () [<DebuggerStepThrough>] member x.For (sequence : seq<_>, body : 'T -> Async<unit option>) : Async<_ option> = x.Using (sequence.GetEnumerator (), fun enum -> x.While (enum.MoveNext, x.Delay (fun () -> body enum.Current))) [<DebuggerStepThrough>] member inline __.TryWith (computation : Async<'T option>, catchHandler : exn -> Async<'T option>) : Async<'T option> = async.TryWith (computation, catchHandler) [<DebuggerStepThrough>] member inline __.TryFinally (computation : Async<'T option>, compensation : unit -> unit) : Async<'T option> = async.TryFinally (computation, compensation) let asyncMaybe = AsyncMaybeBuilder() let inline liftAsync (computation : Async<'T>) : Async<'T option> = async { let! a = computation return Some a } let liftTaskAsync task = task |> Async.AwaitTask |> liftAsync module Async = let map (f: 'T -> 'U) (a: Async<'T>) : Async<'U> = async { let! a = a return f a } /// Creates an asynchronous workflow that runs the asynchronous workflow given as an argument at most once. /// When the returned workflow is started for the second time, it reuses the result of the previous execution. let cache (input : Async<'T>) = let agent = MailboxProcessor<AsyncReplyChannel<_>>.Start <| fun agent -> async { let! replyCh = agent.Receive () let! res = input replyCh.Reply res while true do let! replyCh = agent.Receive () replyCh.Reply res } async { return! agent.PostAndAsyncReply id }