├── .gitattributes
├── .gitignore
├── .paket
├── paket.bootstrapper.exe
└── paket.targets
├── ProtoWorkspace.Tests
├── AssemblyInfo.fs
├── Library1.fs
├── ProtoWorkspace.Tests.fsproj
├── Script.fsx
└── paket.references
├── ProtoWorkspace.sln
├── ProtoWorkspace
├── BufferTracker.fs
├── CodeService.fsx
├── Commands.fs
├── Constants.fs
├── ConvertProject.fsx
├── Converters.fs
├── Environment.fs
├── Extensions.fs
├── HostServices.fs
├── LanguageService.fs
├── Loaders.fs
├── MSBuildConfig.fs
├── MSBuildEval.fsx
├── MSBuildProjectSystem.fs
├── Prelude.fs
├── ProjectConfig.fs
├── ProjectFileInfo.fs
├── ProtoWorkspace.fsproj
├── Scripts
│ ├── load-project-debug.fsx
│ ├── load-project-release.fsx
│ ├── load-references-debug.fsx
│ └── load-references-release.fsx
├── Services
│ ├── BraceMatching.fs
│ ├── Highlighting.fs
│ ├── QuickInfo.fs
│ └── ServiceInterfaces.fs
├── SolutionFileInfo.fs
├── Text.fs
├── Workspace.fs
├── WorkspaceServices.fs
├── paket.references
└── slntest.fsx
├── README.md
├── data
├── TestSln.sln
├── module_001.fs
├── module_002.fs
├── projects
│ ├── Library1
│ │ ├── AssemblyInfo.fs
│ │ ├── Library1.fs
│ │ ├── Library1.fsproj
│ │ └── Script.fsx
│ └── Library2
│ │ ├── AssemblyInfo.fs
│ │ ├── Library1.fs
│ │ ├── Library2.fsproj
│ │ └── Script.fsx
├── script_001.fsx
├── script_002.fsx
├── sig_001.fsi
└── sig_002.fsi
├── paket.dependencies
├── paket.lock
└── reference.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Microsoft Azure ApplicationInsights config file
170 | ApplicationInsights.config
171 |
172 | # Windows Store app package directory
173 | AppPackages/
174 | BundleArtifacts/
175 |
176 | # Visual Studio cache files
177 | # files ending in .cache can be ignored
178 | *.[Cc]ache
179 | # but keep track of directories ending in .cache
180 | !*.[Cc]ache/
181 |
182 | # Others
183 | ClientBin/
184 | [Ss]tyle[Cc]op.*
185 | ~$*
186 | *~
187 | *.dbmdl
188 | *.dbproj.schemaview
189 | *.pfx
190 | *.publishsettings
191 | node_modules/
192 | orleans.codegen.cs
193 |
194 | # RIA/Silverlight projects
195 | Generated_Code/
196 |
197 | # Backup & report files from converting an old project file
198 | # to a newer Visual Studio version. Backup files are not needed,
199 | # because we have git ;-)
200 | _UpgradeReport_Files/
201 | Backup*/
202 | UpgradeLog*.XML
203 | UpgradeLog*.htm
204 |
205 | # SQL Server files
206 | *.mdf
207 | *.ldf
208 |
209 | # Business Intelligence projects
210 | *.rdl.data
211 | *.bim.layout
212 | *.bim_*.settings
213 |
214 | # Microsoft Fakes
215 | FakesAssemblies/
216 |
217 | # GhostDoc plugin setting file
218 | *.GhostDoc.xml
219 |
220 | # Node.js Tools for Visual Studio
221 | .ntvs_analysis.dat
222 |
223 | # Visual Studio 6 build log
224 | *.plg
225 |
226 | # Visual Studio 6 workspace options file
227 | *.opt
228 |
229 | # Visual Studio LightSwitch build output
230 | **/*.HTMLClient/GeneratedArtifacts
231 | **/*.DesktopClient/GeneratedArtifacts
232 | **/*.DesktopClient/ModelManifest.xml
233 | **/*.Server/GeneratedArtifacts
234 | **/*.Server/ModelManifest.xml
235 | _Pvt_Extensions
236 |
237 | # LightSwitch generated files
238 | GeneratedArtifacts/
239 | ModelManifest.xml
240 |
241 | # Paket dependency manager
242 | .paket/paket.exe
243 |
244 | # FAKE - F# Make
245 | .fake/
--------------------------------------------------------------------------------
/.paket/paket.bootstrapper.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fsharp-editing/ProtoWorkspace/4e2509a5da4789ccd673328dbb8ffec3b0801b8a/.paket/paket.bootstrapper.exe
--------------------------------------------------------------------------------
/.paket/paket.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | true
6 |
7 | true
8 | $(MSBuildThisFileDirectory)
9 | $(MSBuildThisFileDirectory)..\
10 | /Library/Frameworks/Mono.framework/Commands/mono
11 | mono
12 |
13 |
14 |
15 | $(PaketToolsPath)paket.exe
16 | $(PaketToolsPath)paket.bootstrapper.exe
17 | "$(PaketExePath)"
18 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
19 | "$(PaketBootStrapperExePath)" $(PaketBootStrapperCommandArgs)
20 | $(MonoPath) --runtime=v4.0.30319 $(PaketBootStrapperExePath) $(PaketBootStrapperCommandArgs)
21 |
22 | $(MSBuildProjectDirectory)\paket.references
23 | $(MSBuildStartupDirectory)\paket.references
24 | $(MSBuildProjectFullPath).paket.references
25 | $(PaketCommand) restore --references-files "$(PaketReferences)"
26 | $(PaketBootStrapperCommand)
27 |
28 | RestorePackages; $(BuildDependsOn);
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ProtoWorkspace.Tests/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace.Tests.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ProtoWorkspace.Tests/Library1.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace.Tests
2 |
3 | type Class1() =
4 | member this.X = "F#"
5 |
--------------------------------------------------------------------------------
/ProtoWorkspace.Tests/ProtoWorkspace.Tests.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 57e880fe-e9f7-409d-81c7-2f50a62967d4
9 | Library
10 | ProtoWorkspace.Tests
11 | ProtoWorkspace.Tests
12 | v4.6.1
13 | 4.4.0.0
14 | true
15 | ProtoWorkspace.Tests
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | 3
26 | bin\Debug\ProtoWorkspace.Tests.XML
27 |
28 |
29 | pdbonly
30 | true
31 | true
32 | bin\Release\
33 | TRACE
34 | 3
35 | bin\Release\ProtoWorkspace.Tests.XML
36 |
37 |
38 |
39 |
40 | True
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | ProtoWorkspace
54 | {31c9d72f-6b95-4280-9abf-b97e421ff49d}
55 | True
56 |
57 |
58 |
59 | 11
60 |
61 |
62 |
63 |
64 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
65 |
66 |
67 |
68 |
69 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
70 |
71 |
72 |
73 |
74 |
81 |
82 |
83 |
84 |
85 | ..\packages\FsCheck\lib\net45\FsCheck.dll
86 | True
87 | True
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | ..\packages\NUnit\lib\net45\nunit.framework.dll
97 | True
98 | True
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/ProtoWorkspace.Tests/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Library1.fs"
5 | open ProtoWorkspace.Tests
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ProtoWorkspace.Tests/paket.references:
--------------------------------------------------------------------------------
1 | NUnit
2 | FsCheck
--------------------------------------------------------------------------------
/ProtoWorkspace.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ProtoWorkspace", "ProtoWorkspace\ProtoWorkspace.fsproj", "{31C9D72F-6B95-4280-9ABF-B97E421FF49D}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2E286A42-DBB8-4C4C-A9F2-DCA7FA73C44A}"
9 | ProjectSection(SolutionItems) = preProject
10 | .gitignore = .gitignore
11 | paket.dependencies = paket.dependencies
12 | paket.lock = paket.lock
13 | README.md = README.md
14 | Reference.md = Reference.md
15 | EndProjectSection
16 | EndProject
17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Data", "Data", "{B8CADD49-9C2A-4983-A09A-6DC8F6704A44}"
18 | ProjectSection(SolutionItems) = preProject
19 | data\module_001.fs = data\module_001.fs
20 | data\module_002.fs = data\module_002.fs
21 | data\script_001.fsx = data\script_001.fsx
22 | data\script_002.fsx = data\script_002.fsx
23 | data\sig_001.fsi = data\sig_001.fsi
24 | data\sig_002.fsi = data\sig_002.fsi
25 | EndProjectSection
26 | EndProject
27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Projects", "Projects", "{C0D364E2-E301-48BF-AB78-83F99C39FF4A}"
28 | ProjectSection(SolutionItems) = preProject
29 | data\projects\Library1\Library1.fsproj = data\projects\Library1\Library1.fsproj
30 | data\projects\Library2\Library2.fsproj = data\projects\Library2\Library2.fsproj
31 | EndProjectSection
32 | EndProject
33 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ProtoWorkspace.Tests", "ProtoWorkspace.Tests\ProtoWorkspace.Tests.fsproj", "{57E880FE-E9F7-409D-81C7-2F50A62967D4}"
34 | EndProject
35 | Global
36 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
37 | Debug|Any CPU = Debug|Any CPU
38 | Release|Any CPU = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
41 | {31C9D72F-6B95-4280-9ABF-B97E421FF49D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {31C9D72F-6B95-4280-9ABF-B97E421FF49D}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {31C9D72F-6B95-4280-9ABF-B97E421FF49D}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {31C9D72F-6B95-4280-9ABF-B97E421FF49D}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {57E880FE-E9F7-409D-81C7-2F50A62967D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {57E880FE-E9F7-409D-81C7-2F50A62967D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {57E880FE-E9F7-409D-81C7-2F50A62967D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {57E880FE-E9F7-409D-81C7-2F50A62967D4}.Release|Any CPU.Build.0 = Release|Any CPU
49 | EndGlobalSection
50 | GlobalSection(SolutionProperties) = preSolution
51 | HideSolutionNode = FALSE
52 | EndGlobalSection
53 | GlobalSection(NestedProjects) = preSolution
54 | {C0D364E2-E301-48BF-AB78-83F99C39FF4A} = {B8CADD49-9C2A-4983-A09A-6DC8F6704A44}
55 | EndGlobalSection
56 | EndGlobal
57 |
--------------------------------------------------------------------------------
/ProtoWorkspace/BufferTracker.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace
2 |
3 | open System
4 | open System.Text
5 | open System.Collections.Generic
6 | open Microsoft.FSharp.Compiler
7 | open Microsoft.FSharp.Compiler.Range
8 |
9 | []
10 | type EditorBuffer =
11 | { Text : string
12 | Range : range
13 | IsDirty : bool
14 | Encoding : Encoding
15 | LastChangeTime : DateTime
16 | ViewCount : int }
17 | static member Create text range isDirty encoding lastChangeTime =
18 | { Text = text
19 | Range = range
20 | IsDirty = isDirty
21 | Encoding = encoding
22 | LastChangeTime = lastChangeTime
23 | ViewCount = 1 }
24 |
25 | type IBufferTracker =
26 | abstract MapEditorBuffers : (KeyValuePair -> 'a) -> seq<'a>
27 | abstract TryFindEditorBuffer : string -> EditorBuffer option
28 | abstract TryGetBufferText : string -> string option
29 | abstract BufferChanged : string IEvent
30 | abstract BufferClosed : string IEvent
31 |
--------------------------------------------------------------------------------
/ProtoWorkspace/CodeService.fsx:
--------------------------------------------------------------------------------
1 | System.IO.Directory.SetCurrentDirectory __SOURCE_DIRECTORY__
2 | #r "System.Threading.Tasks"
3 | #load "scripts/load-references-release.fsx"
4 | #r "bin/release/protoworkspace.dll"
5 |
6 | open System
7 | open System.IO
8 | open System.Collections.Generic
9 | open Microsoft.CodeAnalysis
10 | open Microsoft.FSharp.Compiler.SourceCodeServices
11 | open Microsoft.Build
12 | open Microsoft.Build.Framework
13 | open Microsoft.Build.Evaluation
14 | open Microsoft.Build.Execution
15 | open Microsoft.Build.Utilities
16 | open System.Xml
17 | open System.Xml.Linq
18 | open ProtoWorkspace
19 | open System.Threading
20 |
21 |
22 | let printsq sqs = sqs |> Seq.iter (printfn "%A")
23 |
24 |
25 | //let library1path = "../data/projects/Library1/Library1.fsproj" |> Path.GetFullPath
26 | let library1path = "ProtoWorkspace.fsproj" |> Path.GetFullPath
27 | let library2path = "../data/projects/Library2/Library2.fsproj" |> Path.GetFullPath
28 |
29 |
30 | let xdoc = (library1path |> File.ReadAllText |> XDocument.Parse).Root
31 |
32 | let fswork = new FSharpWorkspace()
33 |
34 |
35 | let lib1info = (ProjectFileInfo.create library1path) |> ProjectFileInfo.toProjectInfo fswork
36 |
37 | let lib1proj = fswork.AddProject lib1info
38 | ;;
39 | lib1proj.Documents
40 | |> Seq.iter (fun doc -> printfn "%s - %s" doc.Name doc.FilePath)
41 |
42 |
43 | lib1proj.Documents |> Seq.find(fun doc -> doc.Name = "Library1")
44 | |> fun doc ->
45 | printfn "%s" doc.Name
46 | let text = doc.GetTextAsync().Result
47 |
48 | text.ToString()
49 | ;;
50 |
51 | let checker = FSharpChecker.Create()
52 |
53 | let fsopts = lib1proj.ToFSharpProjectOptions fswork
54 | ;;
55 | let checkDoc (doc:Document) = async {
56 | let! version = doc.GetTextVersionAsync() |> Async.AwaitTask
57 | let! text = doc.GetTextAsync() |> Async.AwaitTask
58 | let! parseResults, checkAnswer = checker.ParseAndCheckFileInProject(doc.FilePath,0,text.ToString(),fsopts)
59 | return
60 | match checkAnswer with
61 | | FSharpCheckFileAnswer.Succeeded res -> Some res
62 | | res -> None
63 | }
64 |
65 |
66 | lib1proj.Documents |> Seq.find(fun doc -> doc.Name = "ProjectFileInfo")
67 | |> fun doc ->
68 | let results = checkDoc doc |> Async.RunSynchronously
69 | if results.IsSome then
70 | (results.Value.GetAllUsesOfAllSymbolsInFile() |> Async.RunSynchronously)
71 | |> Array.iter ^ fun sym -> printfn "%s" sym.Symbol.FullName
72 | else
73 | printfn "didn't get back symbol results"
74 |
75 |
76 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Commands.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace
2 |
3 | open System
4 | open System.IO
5 | open System.Composition
6 | open Microsoft.CodeAnalysis
7 | open Newtonsoft.Json
8 | open ProtoWorkspace.Text
9 |
10 | []
11 | /// Contains the literals for the strings representing Editing Command Endpoints
12 | module Command =
13 | let [] GotoDefinition = "/gotodefinition"
14 | let [] FindSymbols = "/findsymbols"
15 | let [] UpdateBuffer = "/updatebuffer"
16 | let [] ChangeBuffer = "/changebuffer"
17 | let [] CodeCheck = "/codecheck"
18 | let [] FilesChanged = "/filesChanged"
19 | let [] FormatAfterKeystroke = "/formatAfterKeystroke"
20 | let [] FormatRange = "/formatRange"
21 | let [] CodeFormat = "/codeformat"
22 | let [] Highlight = "/highlight"
23 | let [] AutoComplete = "/autocomplete"
24 | let [] FindImplementations = "/findimplementations"
25 | let [] FindUsages = "/findusages"
26 | let [] GotoFile = "/gotofile"
27 | let [] GotoRegion = "/gotoregion"
28 | let [] NavigateUp = "/navigateup"
29 | let [] NavigateDown = "/navigatedown"
30 | let [] TypeLookup = "/typelookup"
31 | let [] GetCodeAction = "/getcodeactions"
32 | let [] RunCodeAction = "/runcodeaction"
33 | let [] Rename = "/rename"
34 | let [] SignatureHelp = "/signatureHelp"
35 | let [] MembersTree = "/currentfilemembersastree"
36 | let [] MembersFlat = "/currentfilemembersasflat"
37 | let [] TestCommand = "/gettestcontext"
38 | let [] Metadata = "/metadata"
39 | let [] PackageSource = "/packagesource"
40 | let [] PackageSearch = "/packagesearch"
41 | let [] PackageVersion = "/packageversion"
42 | let [] WorkspaceInformation = "/projects"
43 | let [] ProjectInformation = "/project"
44 | let [] FixUsings = "/fixusings"
45 | let [] CheckAliveStatus = "/checkalivestatus"
46 | let [] CheckReadyStatus = "/checkreadystatus"
47 | let [] StopServer = "/stopserver"
48 | let [] Open = "/open"
49 | let [] Close = "/close"
50 | let [] Diagnostics = "/diagnostics"
51 |
52 |
53 | type IRequest = interface end
54 | type IRequestHandler = interface end
55 |
56 |
57 | []
58 | /// MEF Exports an IRequestHandler
59 | type CommandHandlerAttribute(commandName:string, language:string) =
60 | inherit ExportAttribute(typeof)
61 | member __.CommandName = commandName
62 | member __.Language = language
63 |
64 |
65 | type CommandDescriptor<'Request,'Response> (commandName:string) =
66 | member val RequestType = typeof<'Request> with get
67 | member val ResponseType = typeof<'Response> with get
68 | member val CommandName = commandName with get
69 |
70 |
71 | []
72 | /// MEF Exports an IRequest
73 | type EditorCommandAttribute (commandName:string, request:Type,response:Type) =
74 | inherit ExportAttribute(typeof)
75 | member val RequestType = request with get
76 | member val ResponseType = response with get
77 | member val CommandName = commandName with get
78 |
79 |
80 | type Request () =
81 | let mutable fileName = ""
82 |
83 | interface IRequest
84 |
85 | [)>]
86 | member val Line : int = 0 with get, set
87 |
88 | [)>]
89 | member val Column : int = 0 with get, set
90 | member val Buffer : string = "" with get, set
91 | member val Changes : LinePositionSpanTextChange seq = Seq.empty with get, set
92 |
93 | member __.FileName
94 | with get () =
95 | fileName.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
96 | and set v = if isNull v then fileName <- String.Empty else fileName <- v
97 |
98 |
99 | type RequestHandler<'Request,'Response> =
100 | inherit IRequestHandler
101 | abstract member Handle: request:'Request -> 'Response Async
102 |
103 |
104 | type IAggregateResponse =
105 | abstract member Merge : response: IAggregateResponse -> IAggregateResponse
106 |
107 |
108 | type QuickFixResponse () =
109 | member val QuickFixes : QuickFix seq = Seq.empty with get, set
110 |
111 | new (quickFixes:QuickFix seq) as self =
112 | QuickFixResponse() then
113 | self.QuickFixes <- quickFixes
114 |
115 | member self.Merge (response:QuickFixResponse) =
116 | Seq.append self.QuickFixes response.QuickFixes
117 | |> QuickFixResponse
118 |
119 | interface IAggregateResponse with
120 | member self.Merge response =
121 | self.Merge (response :?> QuickFixResponse)
122 | :> IAggregateResponse
123 |
124 |
125 |
126 | type ModifiedFileResponse (fileName:string) =
127 | member val FileName = fileName with get, set
128 | member val Buffer = "" with get, set
129 | member val Changes : LinePositionSpanTextChange seq = Seq.empty with get, set
130 | new () = ModifiedFileResponse String.Empty
131 |
132 |
133 | // File Open
134 |
135 | type FileOpenResponse () =
136 | interface IAggregateResponse with
137 | member __.Merge response = response
138 |
139 | [,typeof)>]
140 | type FileOpenRequest() =
141 | inherit Request()
142 |
143 | // File Close
144 |
145 | type FileCloseResponse () =
146 | interface IAggregateResponse with
147 | member __.Merge response = response
148 |
149 | [,typeof)>]
150 | type FileCloseRequest() =
151 | inherit Request()
152 |
153 |
154 | // Rename
155 |
156 | type RenameResponse () =
157 | member val Changes : ModifiedFileResponse seq = Seq.empty with get, set
158 | member val ErrorMessage = "" with get, set
159 |
160 | [,typeof)>]
161 | type RenameRequest () =
162 | inherit Request ()
163 | /// When true, return just the text changes.
164 | member val WantsTextChanges = false with get, set
165 | /// When true, apply changes immediately on the server.
166 | member val ApplyTextChanges = true with get, set
167 | member val RenameTo = "" with get, set
168 |
169 |
170 | // Buffer
171 |
172 | [,typeof)>]
173 | type UpdateBufferRequest () =
174 | inherit Request()
175 | /// Instead of updating the buffer from the editor,
176 | /// set this to allow updating from disk
177 | member val FromDisk = false with get, set
178 |
179 | [,typeof)>]
180 | type ChangeBufferRequest () =
181 | interface IRequest
182 |
183 | member val NewText : string = "" with get, set
184 | member val FileName : string = "" with get, set
185 | [)>]
186 | member val StartLine : int = 0 with get, set
187 | [)>]
188 | member val StartColumn : int = 0 with get, set
189 | [)>]
190 | member val EndLine : int = 0 with get, set
191 | [)>]
192 | member val EndColumn : int = 0 with get, set
193 |
194 |
195 | // Signature Help
196 |
197 | [,typeof)>]
198 | type SignatureHelpRequest () = inherit Request()
199 |
200 |
201 | // Fix Usings
202 |
203 | type FixUsingsResponse () =
204 | member val Buffer = "" with get, set
205 | member val AmbiguousResults : QuickFix seq = Seq.empty with get, set
206 | member val Changes : LinePositionSpanTextChange seq = Seq.empty with get, set
207 |
208 |
209 | [,typeof)>]
210 | type FixUsingsRequest () =
211 | inherit Request()
212 | member val WantsTextChanges = false with get, set
213 | member val ApplyTextChanges = true with get, set
214 |
215 |
216 |
217 | // AutoComplete
218 |
219 | type AutoCompleteResponse () =
220 | /// The text to be "completed", that is, the text that will be inserted in the
221 | member val CompletionText = "" with get, set
222 | member val Description = "" with get, set
223 | /// The text that should be displayed in the auto-complete UI.
224 | member val DisplayText = "" with get, set
225 | member val RequiredNamespaceImport = "" with get, set
226 | member val MethodHandler = "" with get, set
227 | member val ReturnType = "" with get, set
228 | member val Snippet = "" with get, set
229 | member val Kind = "" with get, set
230 |
231 | override self.Equals (other:obj) =
232 | if isNull other then false else
233 | match other with
234 | | :? AutoCompleteResponse as other ->
235 | self.DisplayText = other.DisplayText
236 | && self.Snippet = other.Snippet
237 | | _ -> false
238 |
239 | override self.GetHashCode() =
240 | 17 * hash self.DisplayText
241 | + (if isNotNull self.Snippet then 31 * hash self.Snippet else 0)
242 |
243 |
244 | [,typeof)>]
245 | type AutoCompleteRequest () =
246 | inherit Request()
247 | let mutable wordToComplete = ""
248 |
249 | member __.WordToComplete
250 | with get () = wordToComplete ?|? ""
251 | and set v = wordToComplete <- v
252 |
253 | /// Specifies whether to return the code documentation for
254 | /// each and every returned autocomplete result.
255 | member val WantDocumentationForEveryCompletionResult = false with get, set
256 |
257 | /// Specifies whether to return importable types. Defaults to
258 | /// false. Can be turned off to get a small speed boost.
259 | member val WantImportableTypes = false with get, set
260 |
261 | /// Returns a 'method header' for working with parameter templating.
262 | member val WantMethodHeader = false with get, set
263 |
264 | /// Returns a snippet that can be used by common snippet libraries
265 | /// to provide parameter and type parameter placeholders
266 | member val WantSnippet = false with get, set
267 |
268 | /// Returns the return type
269 | member val WantReturnType = false with get, set
270 |
271 | /// Returns the kind (i.e Method, Property, Field)
272 | member val WantKind = false with get, set
273 |
274 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Constants.fs:
--------------------------------------------------------------------------------
1 |
2 | namespace ProtoWorkspace
3 | open System
4 |
5 | module Constants =
6 | let [] FSharpProjectGuidStr = "F2A71F9B-5D33-465A-A702-920D77279786"
7 | let FSharpProjectGuid = Guid FSharpProjectGuidStr
8 | let [] SolutionFolderGuidStr = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
9 | let SolutionFolderGuid = Guid SolutionFolderGuidStr
10 | let [] FSharpLanguageName = "F#"
11 | let [] FSharpContentTypeName = "F#"
12 |
13 | // Common Constants
14 | let [] Name = "Name"
15 | let [] None = "None"
16 | let [] Reference = "Reference"
17 |
18 | // Platform Constants
19 | let [] X86 = "x86"
20 | let [] X64 = "x64"
21 | let [] AnyCPU = "AnyCPU"
22 |
23 | // BuildAction Constants
24 | let [] Compile = "Compile"
25 | let [] Content = "Content"
26 | let [] Resource = "Resource"
27 | let [] EmbeddedResource = "EmbeddedResource"
28 |
29 | // CopyToOutputDirectory Constants
30 | let [] Never = "Never"
31 | let [] Always = "Always"
32 | let [] PreserveNewest = "PreserveNewest"
33 |
34 | // DebugType Constants
35 | let [] PdbOnly = "PdbOnly"
36 | let [] Full = "Full"
37 |
38 | // OutputType Constants
39 | let [] Exe = "Exe"
40 | let [] Winexe = "Winexe"
41 | let [] Library = "Library"
42 | let [] Module = "Module"
43 |
44 | // XML Attribute Name Constants
45 | let [] DefaultTargets = "DefaultTargets"
46 | let [] ToolsVersion = "ToolsVersion"
47 | let [] Include = "Include"
48 | let [] Condition = "Condition"
49 |
50 | // MSBuild XML Element Constants
51 |
52 | let [] Project = "Project"
53 | let [] ItemGroup = "ItemGroup"
54 | let [] PropertyGroup = "PropertyGroup"
55 | let [] ProjectReference = "ProjectReference"
56 |
57 | // XML Property Constants (found in PropertyGroups)
58 | let [] AssemblyName = "AssemblyName"
59 | let [] RootNamespace = "RootNamespace"
60 | let [] Configuration = "Configuration"
61 | let [] Platform = "Platform"
62 | let [] SchemaVersion = "SchemaVersion"
63 | let [] ProjectGuid = "ProjectGuid"
64 | let [] ProjectType = "ProjectType"
65 | let [] OutputType = "OutputType"
66 | let [] TargetFrameworkVersion = "TargetFrameworkVersion"
67 | let [] TargetFrameworkProfile = "TargetFrameworkProfile"
68 | let [] AutoGenerateBindingRedirects = "AutoGenerateBindingRedirects"
69 | let [] TargetFSharpCoreVersion = "TargetFSharpCoreVersion"
70 | let [] DebugSymbols = "DebugSymbols"
71 | let [] DebugType = "DebugType"
72 | let [] Optimize = "Optimize"
73 | let [] Tailcalls = "Tailcalls"
74 | let [] OutputPath = "OutputPath"
75 | let [] CompilationConstants = "DefineConstants"
76 | let [] WarningLevel = "WarningLevel"
77 | let [] PlatformTarget = "PlatformTarget"
78 | let [] DocumentationFile = "DocumentationFile"
79 | let [] Prefer32Bit = "Prefer32Bit"
80 | let [] OtherFlags = "OtherFlags"
81 |
82 | // XML Elements
83 | let [] CopyToOutputDirectory = "CopyToOutputDirectory"
84 | let [] HintPath = "HintPath"
85 | let [] Private = "Private"
86 | let [] SpecificVersion = "SpecificVersion"
87 | let [] Link = "Link"
88 | let [] Paket = "Paket"
89 | let [] XmlDecl = @""
90 | let [] Xmlns = "http://schemas.microsoft.com/developer/msbuild/2003"
91 |
92 |
93 | []
94 | /// MSBuild Properties
95 | module Property =
96 | let [] AllowUnsafeBlocks = "AllowUnsafeBlocks"
97 | let [] AssemblyName = "AssemblyName"
98 | let [] AssemblyOriginatorKeyFile = "AssemblyOriginatorKeyFile"
99 | let [] BuildProjectReferences = "BuildProjectReferences"
100 | let [] DefineConstants = "DefineConstants"
101 | let [] DesignTimeBuild = "DesignTimeBuild"
102 | let [] DocumentationFile = "DocumentationFile"
103 | let [] LangVersion = "LangVersion"
104 | let [] OutputType = "OutputType"
105 | let [] MSBuildExtensionsPath = "MSBuildExtensionsPath"
106 | let [] ProjectGuid = "ProjectGuid"
107 | let [] ProjectName = "ProjectName"
108 | let [] ResolveReferenceDependencies = "ResolveReferenceDependencies"
109 | let [] SignAssembly = "SignAssembly"
110 | let [] SolutionDir = "SolutionDir"
111 | let [] TargetFrameworkMoniker = "TargetFrameworkMoniker"
112 | let [] TargetPath = "TargetPath"
113 | let [] VisualStudioVersion = "VisualStudioVersion"
114 |
115 |
116 | []
117 | /// MSBuild Project Target Names
118 | module TargetName =
119 |
120 | let [] ResolveReferences = "ResolveReferences"
121 |
122 |
123 | []
124 | /// MSBuild Project Item Names
125 | module ItemName =
126 | let [] Analyzer = "Analyzer"
127 | let [] Compile = "Compile"
128 | let [] None = "None"
129 | let [] ProjectReference = "ProjectReference"
130 | let [] ReferencePath = "ReferencePath"
131 |
132 | []
133 | /// MSBuild Project Metadata Names
134 | module MetadataName =
135 | let [] FullPath = "FullPath"
136 | let [] Project = "Project"
137 | let [] ReferenceSourceTarget = "ReferenceSourceTarget"
138 |
--------------------------------------------------------------------------------
/ProtoWorkspace/ConvertProject.fsx:
--------------------------------------------------------------------------------
1 | System.IO.Directory.SetCurrentDirectory __SOURCE_DIRECTORY__
2 |
3 | #r "System.Threading.Tasks"
4 | #load "scripts/load-references-release.fsx"
5 | #r "bin/release/protoworkspace.dll"
6 |
7 | open System
8 | open System.IO
9 | open System.Collections.Generic
10 | open Microsoft.FSharp.Compiler.SourceCodeServices
11 | open Microsoft.CodeAnalysis
12 | open System.Xml
13 | open System.Xml.Linq
14 | open ProtoWorkspace
15 | open ProtoWorkspace.ProjectFileInfo
16 | open System.Threading
17 |
18 | let internal toFSharpProjectOptions (workspace: 'a when 'a :> Workspace) (projInfo: ProjectInfo): FSharpProjectOptions =
19 | let projectStore = Dictionary()
20 |
21 | let rec generate (projInfo:ProjectInfo) : FSharpProjectOptions =
22 | let getProjectRefs (projInfo:ProjectInfo) : (string * FSharpProjectOptions) [] =
23 | projInfo.ProjectReferences
24 | |> Seq.choose ^ fun pref -> workspace.CurrentSolution.TryGetProject pref.ProjectId
25 | |> Seq.map ^ fun proj ->
26 | let proj = proj.ToProjectInfo()
27 | if projectStore.ContainsKey proj.Id then (proj.OutputFilePath, projectStore.[proj.Id])
28 | else
29 | let fsinfo = generate proj
30 | projectStore.Add (proj.Id, fsinfo)
31 | (proj.OutputFilePath, fsinfo)
32 | |> Array.ofSeq
33 | { ProjectFileName = projInfo.FilePath
34 | ProjectFileNames =
35 | projInfo.Documents
36 | |> Seq.map ^ fun doc -> doc.FilePath
37 | |> Array.ofSeq
38 | OtherOptions = [||]
39 | ReferencedProjects = getProjectRefs projInfo
40 | IsIncompleteTypeCheckEnvironment = false
41 | UseScriptResolutionRules = false
42 | LoadTime = System.DateTime.Now
43 | UnresolvedReferences = None
44 | }
45 | generate projInfo
46 |
47 | type ProjectInfo with
48 | member self.ToFSharpProjectOptions(workspace: 'a when 'a :> Workspace): FSharpProjectOptions =
49 | toFSharpProjectOptions workspace self
50 |
51 | type Project with
52 | member self.ToProjectInfo() =
53 | ProjectInfo.Create
54 | (self.Id, self.Version, self.Name, self.AssemblyName, self.Language, self.FilePath,
55 | outputFilePath = self.OutputFilePath,
56 | projectReferences = self.ProjectReferences,
57 | metadataReferences = self.MetadataReferences,
58 | analyzerReferences = self.AnalyzerReferences,
59 | documents = (self.Documents |> Seq.map ^ fun doc -> doc.ToDocumentInfo()),
60 | additionalDocuments = (self.AdditionalDocuments |> Seq.map ^ fun doc -> doc.ToDocumentInfo()),
61 | compilationOptions = self.CompilationOptions,
62 | parseOptions = self.ParseOptions,
63 | isSubmission = self.IsSubmission)
64 | member self.ToFSharpProjectOptions(workspace: 'a when 'a :> Workspace): FSharpProjectOptions =
65 | self.ToProjectInfo().ToFSharpProjectOptions workspace
66 |
67 |
68 | let fswork = new FSharpWorkspace()
69 |
70 | let protopath = "ProtoWorkspace.fsproj" |> Path.GetFullPath
71 |
72 | let protoinfo = (ProjectFileInfo.create protopath) |> ProjectFileInfo.toProjectInfo fswork
73 |
74 | let protoproj = fswork.AddProject protoinfo
75 | ;;
76 | let protoOpts = protoinfo.ToFSharpProjectOptions fswork
77 |
78 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Converters.fs:
--------------------------------------------------------------------------------
1 | []
2 | module ProtoWorkspace.Converters
3 |
4 | open System
5 | open System.Collections.Immutable
6 | open System.Threading.Tasks
7 | open Microsoft.CodeAnalysis
8 | open Microsoft.CodeAnalysis.Text
9 | open Microsoft.FSharp.Compiler
10 | open Microsoft.FSharp.Compiler.SourceCodeServices
11 | open Microsoft.FSharp.Compiler.Range
12 | open Newtonsoft.Json
13 |
14 |
15 | let fsharpRangeToTextSpan (sourceText:SourceText, range:range) =
16 | // Roslyn TextLineCollection is zero-based, F# range lines are one-based
17 | let startPosition = sourceText.Lines.[range.StartLine - 1].Start + range.StartColumn
18 | let endPosition = sourceText.Lines.[range.EndLine - 1].Start + range.EndColumn
19 | TextSpan (startPosition, endPosition - startPosition)
20 |
21 | let getTaskAction (computation:Async) =
22 | // Shortcut due to nonstandard way of converting Async to Task
23 | let action () =
24 | try
25 | computation |> Async.RunSynchronously
26 | with ex ->
27 | Assert.Exception ^ ex.GetBaseException()
28 | raise ^ ex.GetBaseException()
29 | Action action
30 |
31 | let getCompletedTaskResult (task:'Result Task)=
32 | if task.Status = TaskStatus.RanToCompletion then
33 | task.Result
34 | else
35 | Assert.Exception ^ task.Exception.GetBaseException()
36 | raise ^ task.Exception.GetBaseException()
37 |
38 | let supportedDiagnostics () =
39 | // We are constructing our own descriptors at run-time. Compiler service is already doing error formatting and localization.
40 | let dummyDescriptor = DiagnosticDescriptor("0", String.Empty, String.Empty, String.Empty, DiagnosticSeverity.Error, true, null, null)
41 | ImmutableArray.Create dummyDescriptor
42 |
43 | let convertError(error: FSharpErrorInfo, location: Location) =
44 | let id = "FS" + error.ErrorNumber.ToString "0000"
45 | let emptyString = LocalizableString.op_Implicit ""
46 | let description = LocalizableString.op_Implicit error.Message
47 | let severity = if error.Severity = FSharpErrorSeverity.Error then DiagnosticSeverity.Error else DiagnosticSeverity.Warning
48 | let descriptor = DiagnosticDescriptor(id, emptyString, description, error.Subcategory, severity, true, emptyString, String.Empty, null)
49 | Diagnostic.Create(descriptor, location)
50 |
51 |
52 |
53 | type ZeroBasedIndexConverter() =
54 | inherit JsonConverter()
55 |
56 | override __.CanConvert (objectType:Type) =
57 | objectType
58 | |>( (=) typeof
59 | |?| (=) typeof
60 | |?| (=) typeof
61 | |?| (=) typeof
62 | )
63 |
64 | override __.ReadJson (reader:JsonReader, objectType:Type, existingValue:obj, serializer:JsonSerializer) =
65 | if reader.TokenType = JsonToken.Null then null
66 | elif objectType = typeof then
67 | serializer.Deserialize reader :> obj
68 | elif objectType = typeof then
69 | serializer.Deserialize reader
70 | |> Seq.map ^ fun x -> x - 1
71 | :> obj
72 | elif objectType = typeof then
73 | let result = serializer.Deserialize reader
74 | if result.HasValue then
75 | result.Value :> obj
76 | else
77 | null
78 | else
79 | null
80 |
81 | (* Omnisharp has a configuration on whether to use zerobasedindices or not
82 | if (Configuration.ZeroBasedIndices)
83 | {
84 | return serializer.Deserialize(reader, objectType);
85 | }
86 | *)
87 |
88 |
89 | override __.WriteJson(writer:JsonWriter, value: obj, serializer:JsonSerializer) =
90 | if isNull value then
91 | serializer.Serialize(writer,null)
92 | else
93 | let objectType = value.GetType()
94 | let results =
95 | if objectType = typeof then
96 | let results = value :?> int[]
97 | for i=0 to results.Length-1 do
98 | results.[i] <- results.[i] + 1
99 | results :> obj
100 | elif objectType = typeof then
101 | let results = value :?> int seq
102 | results |> Seq.map ^ fun x -> x + 1
103 | :> obj
104 | elif objectType = typeof then
105 | let result = value :?> int Nullable
106 | if result.HasValue then
107 | result.Value + 1 :> obj
108 | else
109 | null
110 | else
111 | null
112 | serializer.Serialize(writer,results)
113 |
114 |
115 | (*
116 |
117 | let FSharpRangeToTextSpan(sourceText: SourceText, range: range) =
118 | // Roslyn TextLineCollection is zero-based, F# range lines are one-based
119 | let startPosition = sourceText.Lines.[range.StartLine - 1].Start + range.StartColumn
120 | let endPosition = sourceText.Lines.[range.EndLine - 1].Start + range.EndColumn
121 | TextSpan(startPosition, endPosition - startPosition)
122 |
123 |
124 |
125 |
126 |
127 | *)
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Environment.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace
2 |
3 | []
4 | module Environment =
5 | open System
6 |
7 | /// Are we running on the Mono platform?
8 | let runningOnMono =
9 | try
10 | System.Type.GetType "Mono.Runtime" <> null
11 | with _ -> false
12 |
13 | let ``namewith.to`` = ""
14 |
15 | /// Target framework (used to find the right version of F# binaries)
16 | type FSharpTargetFramework =
17 | | NET_2_0
18 | | NET_3_0
19 | | NET_3_5
20 | | NET_4_0
21 | | NET_4_5
22 | | NET_4_6
23 |
24 | type FSharpCompilerVersion =
25 | /// F# 2.0 - 4.0.0.0
26 | | FSharp_2_0
27 | /// F# 3.0 - 4.3.0.0
28 | | FSharp_3_0
29 | /// F# 3.1 - 4.3.1.0
30 | | FSharp_3_1
31 | /// F# 4.0 - 4.4.0.0
32 | | FSharp_4_0
33 | /// F# 4.1 - 4.4.1.0
34 | | FSharp_4_1
35 |
36 | override x.ToString() =
37 | match x with
38 | | FSharp_2_0 -> "4.0.0.0"
39 | | FSharp_3_0 -> "4.3.0.0"
40 | | FSharp_3_1 -> "4.3.1.0"
41 | | FSharp_4_0 -> "4.4.0.0"
42 | | FSharp_4_1 -> "4.4.1.0"
43 |
44 | /// The current requested language version can be overridden by the user using environment variable.
45 | static member LatestKnown =
46 | match System.Environment.GetEnvironmentVariable "FSHARP_PREFERRED_VERSION" with
47 | | "4.0.0.0" -> FSharp_2_0
48 | | "4.3.0.0" -> FSharp_3_0
49 | | "4.3.1.0" -> FSharp_3_1
50 | | "4.4.0.0" -> FSharp_4_0
51 | | "4.4.1.0" -> FSharp_4_1
52 | | null | _ -> FSharp_4_0
53 |
54 | let maxPath = 260
55 | let maxDataLength = System.Text.UTF32Encoding().GetMaxByteCount maxPath
56 | let KEY_WOW64_DEFAULT = 0x0000
57 | let KEY_WOW64_32KEY = 0x0200
58 | let HKEY_LOCAL_MACHINE = UIntPtr 0x80000002u
59 | let KEY_QUERY_VALUE = 0x1
60 | let REG_SZ = 1u
61 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Extensions.fs:
--------------------------------------------------------------------------------
1 | []
2 | module ProtoWorkspace.Extensions
3 | open System
4 | open System.IO
5 | open System.Threading.Tasks
6 | open System.Collections.Generic
7 | open Microsoft.Extensions.Logging
8 | open Microsoft.CodeAnalysis
9 | open Microsoft.CodeAnalysis.Text
10 | open Microsoft.FSharp.Compiler
11 | open Microsoft.FSharp.Compiler.SourceCodeServices
12 |
13 |
14 | type AsyncBuilder with
15 | member self.Bind (task: 'a Task, fn: 'a -> 'b Async) =
16 | self.Bind (Async.AwaitTask task, fn)
17 |
18 | member self.Bind (task: Task, fn: unit -> unit Async) =
19 | self.Bind (Async.AwaitTask task, fn)
20 |
21 |
22 | type ILogger with
23 | member self.LogInfofn msg = Printf.ksprintf (fun s -> self.LogInformation(s, [||])) msg
24 | member self.LogCriticalfn msg = Printf.ksprintf (fun s -> self.LogCritical(s, [||])) msg
25 | member self.LogDebugfn msg = Printf.ksprintf (fun s -> self.LogDebug(s, [||])) msg
26 | member self.LogTracefn msg = Printf.ksprintf (fun s -> self.LogTrace(s, [||])) msg
27 | member self.LogErrorfn msg = Printf.ksprintf (fun s -> self.LogError(s, [||])) msg
28 | member self.LogWarningfn msg = Printf.ksprintf (fun s -> self.LogWarning(s, [||])) msg
29 |
30 |
31 | (* CodeAnalysis Extensions *)
32 |
33 | type TextSpan with
34 | /// Compares two instances of Microsoft.CodeAnalysis.Text.TextSpan
35 | static member CompareTo (a:TextSpan,b:TextSpan) = a.CompareTo b
36 |
37 | type Document with
38 |
39 | member self.ToDocumentInfo () =
40 | DocumentInfo.Create
41 | ( id=self.Id
42 | , name=self.Name
43 | , folders=self.Folders
44 | , sourceCodeKind=self.SourceCodeKind
45 | , loader=FileTextLoader(self.FilePath,Text.Encoding.UTF8)
46 | , filePath=self.FilePath
47 | )
48 |
49 |
50 | type TextDocument with
51 |
52 | member self.ToDocumentInfo () =
53 | DocumentInfo.Create
54 | ( id=self.Id
55 | , name=self.Name
56 | , folders=self.Folders
57 | , loader=FileTextLoader(self.FilePath,Text.Encoding.UTF8)
58 | , filePath=self.FilePath
59 | )
60 |
61 |
62 | type Solution with
63 |
64 | /// Get a project inside the solution using the project's name
65 | member self.GetProject projectName =
66 | self.Projects |> Seq.find(fun proj -> proj.Name = projectName)
67 |
68 | /// Try to get a project inside the solution using the project's name
69 | member self.TryGetProject projectName =
70 | self.Projects |> Seq.tryFind(fun proj -> proj.Name = projectName)
71 |
72 | /// Try to get a project inside the solution using the project's id
73 | member self.TryGetProject (projId:ProjectId) =
74 | if self.ContainsProject projId then Some (self.GetProject projId) else None
75 |
76 | /// Sequence of DocumentInfo for all source files and addtional documents
77 | /// from all of the projects within the solution
78 | member self.AllDocuments =
79 | self.Projects |> Seq.collect ^ fun proj ->
80 | Seq.append
81 | (proj.Documents |> Seq.map ^ fun doc -> doc.ToDocumentInfo())
82 | (proj.AdditionalDocuments |> Seq.map ^ fun doc -> doc.ToDocumentInfo())
83 |
84 |
85 | member self.Directory = (FileInfo self.FilePath).Directory.FullName
86 |
87 |
88 | type Project with
89 |
90 | member self.GetDocument docName =
91 | self.Documents |> Seq.find (fun doc -> doc.Name = docName)
92 |
93 | member self.TryGetDocument docName =
94 | self.Documents |> Seq.tryFind (fun doc -> doc.Name = docName)
95 |
96 |
97 | member self.ToProjectInfo () =
98 | ProjectInfo.Create
99 | ( self.Id
100 | , self.Version
101 | , self.Name
102 | , self.AssemblyName
103 | , self.Language
104 | , self.FilePath
105 | , outputFilePath = self.OutputFilePath
106 | , projectReferences = self.ProjectReferences
107 | , metadataReferences = self.MetadataReferences
108 | , analyzerReferences = self.AnalyzerReferences
109 | , documents = (self.Documents |> Seq.map(fun doc -> doc.ToDocumentInfo()))
110 | , additionalDocuments = (self.AdditionalDocuments |> Seq.map(fun doc -> doc.ToDocumentInfo()))
111 | , compilationOptions = self.CompilationOptions
112 | , parseOptions = self.ParseOptions
113 | , isSubmission = self.IsSubmission
114 | )
115 |
116 |
117 | let internal toFSharpProjectOptions (workspace:'a :> Workspace) (projInfo:ProjectInfo): FSharpProjectOptions =
118 | let projectStore = Dictionary()
119 |
120 | let rec generate (projInfo:ProjectInfo) : FSharpProjectOptions =
121 | let getProjectRefs (projInfo:ProjectInfo): (string * FSharpProjectOptions)[] =
122 | projInfo.ProjectReferences
123 | |> Seq.choose (fun pref -> workspace.CurrentSolution.TryGetProject pref.ProjectId)
124 | |> Seq.map(fun proj ->
125 | let proj = proj.ToProjectInfo()
126 | if projectStore.ContainsKey(proj.Id) then
127 | (proj.OutputFilePath, projectStore.[proj.Id])
128 | else
129 | let fsinfo = generate proj
130 | projectStore.Add(proj.Id,fsinfo)
131 | (proj.OutputFilePath, fsinfo)
132 | )|> Array.ofSeq
133 |
134 | { ProjectFileName = projInfo.FilePath
135 | ProjectFileNames = projInfo.Documents |> Seq.map(fun doc -> doc.FilePath) |> Array.ofSeq
136 | OtherOptions = [||]
137 | ReferencedProjects = getProjectRefs projInfo
138 | IsIncompleteTypeCheckEnvironment = false
139 | UseScriptResolutionRules = false
140 | LoadTime = System.DateTime.Now
141 | UnresolvedReferences = None
142 | }
143 | let fsprojOptions = generate projInfo
144 | projectStore.Clear()
145 | fsprojOptions
146 |
147 |
148 |
149 | type ProjectInfo with
150 |
151 | member self.ToFSharpProjectOptions (workspace:'a :> Workspace) : FSharpProjectOptions =
152 | toFSharpProjectOptions workspace self
153 |
154 |
155 | type Project with
156 |
157 | member self.ToFSharpProjectOptions (workspace:'a :> Workspace) : FSharpProjectOptions =
158 | self.ToProjectInfo().ToFSharpProjectOptions workspace
159 |
160 |
161 |
162 |
163 |
164 | type Workspace with
165 |
166 | member self.ProjectDictionary() =
167 | let dict = Dictionary<_,_>()
168 | self.CurrentSolution.Projects
169 | |> Seq.iter ^ fun proj -> dict.Add(proj.FilePath,proj.Id)
170 | dict
171 |
172 |
173 | member self.ProjectPaths() =
174 | self.CurrentSolution.Projects |> Seq.map(fun proj -> proj.FilePath)
175 |
176 |
177 | member self.GetProjectIdFromPath path : ProjectId option =
178 | let dict = self.ProjectDictionary()
179 | Dict.tryFind path dict
180 |
181 |
182 | /// checks the workspace for projects located at the provided paths.
183 | /// returns a mapping of the projectId and path of projects inside the workspace
184 | /// and a list of the paths to projects the workspace doesn't include
185 | member self.GetProjectIdsFromPaths paths =
186 | let dict = self.ProjectDictionary()
187 | let pathsInside,pathsOutside = paths |> List.ofSeq |> List.partition ^ fun path -> dict.ContainsKey path
188 | let idmap = pathsInside |> Seq.map ^ fun path -> dict.[path]
189 | idmap, pathsOutside
190 |
191 |
192 | member self.GetProject projectName =
193 | self.CurrentSolution.GetProject
194 |
195 | (* MSBuild Extensions *)
196 |
197 | open Microsoft.Build
198 | open Microsoft.Build.Evaluation
199 | open Microsoft.Build.Execution
200 |
201 |
202 |
203 | type ProjectInstance with
204 |
205 | member self.TryGetPropertyValue propertyName =
206 | let value = self.GetPropertyValue propertyName
207 | if String.IsNullOrEmpty value then None else Some value
208 |
--------------------------------------------------------------------------------
/ProtoWorkspace/HostServices.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace.HostServices
2 |
3 | open ProtoWorkspace
4 | open System
5 | open System.Collections.Generic
6 | open System.Reflection
7 | open System.Composition
8 | open System.Composition.Hosting.Core
9 | open System.Collections.Immutable
10 | open Microsoft.CodeAnalysis
11 | open Microsoft.CodeAnalysis.Host
12 | open Microsoft.CodeAnalysis.Host.Mef
13 |
14 | // based on - https://gist.github.com/praeclarum/953629b2f80860e54747
15 |
16 | type FSharpHostLanguageService (workspace:Workspace) =
17 | inherit HostLanguageServices()
18 |
19 | override __.Language = Constants.FSharpLanguageName
20 | override __.WorkspaceServices with get () = workspace.Services
21 | override __.GetService<'a when 'a :> ILanguageService>() : 'a = Unchecked.defaultof<'a>
22 |
23 |
24 |
25 | type FSharpHostWorkspaceService (workspace:Workspace,baseServices:HostWorkspaceServices) =
26 | inherit HostWorkspaceServices()
27 |
28 | let languageService = FSharpHostLanguageService workspace
29 |
30 | override __.GetService<'a when 'a :> IWorkspaceService >() =
31 | baseServices.GetService<'a>()
32 |
33 | override __.HostServices with get() = workspace.Services.HostServices
34 |
35 | override __.Workspace = workspace
36 |
37 | override __.IsSupported languageName = languageName = Constants.FSharpLanguageName
38 |
39 | override __.SupportedLanguages = seq [Constants.FSharpLanguageName]
40 |
41 | override __.GetLanguageServices _ = languageService :> HostLanguageServices
42 |
43 | override __.FindLanguageServices filter = base.FindLanguageServices filter
44 |
45 |
46 | type FSharpHostService () =
47 | inherit HostServices()
48 | let baseWorkspace = new AdhocWorkspace()
49 |
50 | override __.CreateWorkspaceServices workspace =
51 | FSharpHostWorkspaceService(workspace,baseWorkspace.Services) :> HostWorkspaceServices
52 |
53 |
54 | type IHostServicesProvider =
55 | abstract Assemblies : Assembly ImmutableArray
56 |
57 | []
58 | type HostServicesAggregator [] ([] hostServicesProviders : seq) =
59 | let builder = ImmutableHashSet.CreateBuilder()
60 |
61 | do
62 | for asm in MefHostServices.DefaultAssemblies do
63 | builder.Add asm |> ignore
64 | for provider in hostServicesProviders do
65 | for asm in provider.Assemblies do
66 | builder.Add asm |> ignore
67 |
68 | let assemblies = builder.ToImmutableArray()
69 | member __.CreateHostServices() = MefHostServices.Create assemblies
70 |
71 |
72 | type MefValueProvider<'a> (item:'a) =
73 | inherit ExportDescriptorProvider()
74 |
75 | // override self.GetExportDescriptors (contract:CompositionContract, descriptorAcessor:DependencyAccessor) =
76 | // seq { if contract.ContractType = typeof<'a> then
77 | // yield ExportDescriptorPromise
78 | // ( contract, String.Empty, true,
79 | // (fun () -> Seq.empty : CompositionDependency seq),
80 | // (fun deps ->
81 | // ExportDescriptor.Create
82 | // ( CompositeActivator (fun context operation -> item :> obj)
83 | // , Dictionary())
84 | // )
85 | // )
86 | // else yield! Seq.empty
87 | // }
88 |
89 | override self.GetExportDescriptors (contract:CompositionContract, _ ) =
90 | seq { if contract.ContractType = typeof<'a> then
91 | yield ExportDescriptorPromise
92 | ( contract, String.Empty, true,
93 | (fun () -> Seq.empty : CompositionDependency seq),
94 | (fun _ -> ExportDescriptor.Create(CompositeActivator(fun _ _ -> item :> obj),Dictionary<_,_>()))
95 | )
96 | else yield! Seq.empty
97 | }
98 |
99 | type MefValueProvider =
100 | static member From<'a> (value:'a) = MefValueProvider<'a> value
--------------------------------------------------------------------------------
/ProtoWorkspace/LanguageService.fs:
--------------------------------------------------------------------------------
1 | module ProtoWorkspace.LanguageService
2 |
3 | open System
4 | open System.Collections.Generic
5 | open System.Runtime.InteropServices
6 | open System.Linq
7 | open System.IO
8 |
9 | open Microsoft.FSharp.Compiler
10 | open Microsoft.FSharp.Compiler.SourceCodeServices
11 | open Microsoft.CodeAnalysis
12 | open Microsoft.CodeAnalysis.Editing
13 |
14 |
15 |
16 | type internal FSharpLanguageService (workspace:FSharpWorkspace) =
17 |
18 | static let optionsCache = Dictionary()
19 | static member GetOptions(projectId: ProjectId) =
20 | if optionsCache.ContainsKey projectId then
21 | Some optionsCache.[projectId]
22 | else
23 | None
24 |
25 | // member this.SyncProject(project: AbstractProject, projectContext: IWorkspaceProjectContext, site: IProjectSite) =
26 | // let updatedFiles = site.SourceFilesOnDisk()
27 | // let workspaceFiles = project.GetCurrentDocuments() |> Seq.map(fun file -> file.FilePath)
28 | //
29 | // for file in updatedFiles do if not(workspaceFiles.Contains(file)) then projectContext.AddSourceFile(file)
30 | // for file in workspaceFiles do if not(updatedFiles.Contains(file)) then projectContext.RemoveSourceFile(file)
31 |
32 | member this.ContentTypeName = Constants.FSharpContentTypeName
33 | member this.LanguageName = Constants.FSharpLanguageName
34 | member this.RoslynLanguageName = Constants.FSharpLanguageName
35 |
36 | // member this.LanguageServiceId = new Guid(FSharpConstants.languageServiceGuidString)
37 | member this.DebuggerLanguageId = DebuggerEnvironment.GetLanguageID()
38 |
39 | member this.CreateContext(_,_,_,_,_) = raise ^ System.NotImplementedException()
40 |
41 | // member this.SetupNewTextView(textView) =
42 | //
43 | //// let workspace = this.Package.ComponentModel.GetService()
44 | //
45 | // // FSROSLYNTODO: Hide navigation bars for now. Enable after adding tests
46 | // workspace.Options <- workspace.Options.WithChangedOption(NavigationBarOptions.ShowNavigationBar, FSharpCommonConstants.FSharpLanguageName, false)
47 | //
48 | // match textView.GetBuffer() with
49 | // | (VSConstants.S_OK, textLines) ->
50 | // let filename = VsTextLines.GetFilename textLines
51 | // match VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) with
52 | // | Some (hier, _) ->
53 | // if IsScript(filename) then
54 | // let editorAdapterFactoryService = this.Package.ComponentModel.GetService()
55 | // let fileContents = VsTextLines.GetFileContents(textLines, editorAdapterFactoryService)
56 | // this.SetupStandAloneFile(filename, fileContents, workspace, hier)
57 | // else
58 | // match hier with
59 | // | :? IProvideProjectSite as siteProvider -> this.SetupProjectFile(siteProvider, workspace)
60 | // | _ -> ()
61 | // | _ -> ()
62 | // | _ -> ()
63 |
64 | // member this.SetupProjectFile(siteProvider: IProvideProjectSite, workspace: VisualStudioWorkspaceImpl) =
65 | // let site = siteProvider.GetProjectSite()
66 | // let projectGuid = Guid(site.ProjectGuid)
67 | // let projectFileName = site.ProjectFileName()
68 | // let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectFileName)
69 | //
70 | // let options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(site, site.ProjectFileName())
71 | // if not (optionsCache.ContainsKey(projectId)) then
72 | // optionsCache.Add(projectId, options)
73 | //
74 | // match workspace.ProjectTracker.GetProject(projectId) with
75 | // | null ->
76 | // let projectContextFactory = this.Package.ComponentModel.GetService();
77 | // let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider)
78 | //
79 | // let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, projectFileName, projectFileName, projectGuid, siteProvider, null, errorReporter)
80 | // let project = projectContext :?> AbstractProject
81 | //
82 | // this.SyncProject(project, projectContext, site)
83 | // site.AdviseProjectSiteChanges(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> this.SyncProject(project, projectContext, site)))
84 | // site.AdviseProjectSiteClosed(FSharpCommonConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> project.Disconnect()))
85 | // | _ -> ()
86 | //
87 | // member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) =
88 | // let options = FSharpChecker.Instance.GetProjectOptionsFromScript(fileName, fileContents, DateTime.Now, [| |]) |> Async.RunSynchronously
89 | // let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(options.ProjectFileName, options.ProjectFileName)
90 | //
91 | // if not(optionsCache.ContainsKey(projectId)) then
92 | // optionsCache.Add(projectId, options)
93 | //
94 | // if obj.ReferenceEquals(workspace.ProjectTracker.GetProject(projectId), null) then
95 | // let projectContextFactory = this.Package.ComponentModel.GetService();
96 | // let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider)
97 | //
98 | // let projectContext = projectContextFactory.CreateProjectContext(FSharpCommonConstants.FSharpLanguageName, options.ProjectFileName, options.ProjectFileName, projectId.Id, hier, null, errorReporter)
99 | // projectContext.AddSourceFile(fileName)
100 | //
101 | // let project = projectContext :?> AbstractProject
102 | // let document = project.GetCurrentDocumentFromPath(fileName)
103 | //
104 | // document.Closing.Add(fun _ -> project.Disconnect())
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Loaders.fs:
--------------------------------------------------------------------------------
1 | module ProtoWorkspace.Loaders
2 |
3 | open Microsoft.CodeAnalysis
4 | open System.Reflection
5 |
6 | type AnalyzerAssemblyLoader() as self =
7 |
8 | member __.AddDependencyLocation(fullPath: string): unit = ()
9 |
10 | member __.LoadFromPath(fullPath: string): System.Reflection.Assembly =
11 | Assembly.Load(AssemblyName.GetAssemblyName fullPath)
12 |
13 | interface IAnalyzerAssemblyLoader with
14 | member __.AddDependencyLocation fullPath = self.AddDependencyLocation fullPath
15 | member __.LoadFromPath fullPath = self.LoadFromPath fullPath
16 |
17 |
--------------------------------------------------------------------------------
/ProtoWorkspace/MSBuildConfig.fs:
--------------------------------------------------------------------------------
1 | module ProtoWorkspace.MSBuildInfo
2 |
3 | open ProtoWorkspace
4 | open System
5 | open System.Collections.Generic
6 | open Microsoft.Build.Framework
7 | open Microsoft.Extensions.Logging
8 | open FSharp.Control
9 |
10 | type MSBuildDiagnosticsMessage =
11 | { LogLevel : string
12 | FileName : string
13 | Text : string
14 | StartLine : int
15 | Endline : int
16 | StartColumn : int
17 | EndColumn : int }
18 |
19 | type MSBuildProjectDiagnostics =
20 | { FileName : string
21 | Warnings : MSBuildDiagnosticsMessage []
22 | Errors : MSBuildDiagnosticsMessage [] }
23 |
24 | type MSBuildLogForwarder(logger : ILogger, diagnostics : MSBuildDiagnosticsMessage ICollection) as self =
25 | let mutable disposables : ResizeArray = ResizeArray()
26 |
27 | let onError (args : // TODO - Add other/loose configuration properties?
28 | // Properties : string []
29 | BuildErrorEventArgs) =
30 | logger.LogError args.Message
31 | diagnostics.Add { LogLevel = "Error"
32 | FileName = args.File
33 | Text = args.Message
34 | StartLine = args.LineNumber
35 | Endline = args.ColumnNumber
36 | StartColumn = args.EndLineNumber
37 | EndColumn = args.EndColumnNumber }
38 |
39 | let onWarning (args : BuildWarningEventArgs) =
40 | logger.LogError args.Message
41 | diagnostics.Add { LogLevel = "Warning"
42 | FileName = args.File
43 | Text = args.Message
44 | StartLine = args.LineNumber
45 | Endline = args.ColumnNumber
46 | StartColumn = args.EndLineNumber
47 | EndColumn = args.EndColumnNumber }
48 |
49 | member val Parameters = "" with get, set
50 | member val Verbosity = LoggerVerbosity.Normal with get, set
51 |
52 | member __.Initialize(eventSource : IEventSource) =
53 | eventSource.ErrorRaised.Subscribe onError |> disposables.Add
54 | eventSource.WarningRaised.Subscribe onWarning |> disposables.Add
55 |
56 | member __.Shutdown() =
57 | disposables |> Seq.iter dispose
58 | disposables.Clear()
59 |
60 | interface Microsoft.Build.Framework.ILogger with
61 | member __.Initialize eventSource = self.Initialize eventSource
62 | member __.Shutdown() = self.Shutdown()
63 |
64 | member __.Parameters
65 | with get () = self.Parameters
66 | and set v = self.Parameters <- v
67 |
68 | member __.Verbosity
69 | with get () = self.Verbosity
70 | and set v = self.Verbosity <- v
71 |
72 | type MSBuildOptions =
73 | { ToolsVersion : string
74 | VisualStudioVersion : string
75 | WaitForDebugger : bool
76 | MSBuildExtensionsPath : string }
77 |
78 | type MSBuildProject =
79 | { ProjectGuid : Guid
80 | Path : string
81 | AssemblyName : string
82 | TargetPath : string
83 | TargetFramework : string
84 | SourceFiles : string IList }
85 |
--------------------------------------------------------------------------------
/ProtoWorkspace/MSBuildEval.fsx:
--------------------------------------------------------------------------------
1 | System.IO.Directory.SetCurrentDirectory __SOURCE_DIRECTORY__
2 | #load "scripts/load-references-release.fsx"
3 |
4 | open System.IO
5 | open Microsoft.Build
6 | open Microsoft.Build.Evaluation
7 | open Microsoft.Build.Execution
8 |
9 |
10 | let manager = BuildManager.DefaultBuildManager
11 |
12 | let buildParam = BuildParameters(DetailedSummary=true)
13 |
14 | let fsprojFile = Path.Combine(__SOURCE_DIRECTORY__, "ProtoWorkspace.fsproj")
15 |
16 | File.ReadAllLines fsprojFile
17 | ;;
18 | let project = ProjectInstance fsprojFile
19 | let requestReferences =
20 | BuildRequestData(project,
21 | [|
22 | "ResolveAssemblyReferences"
23 | "ResolveProjectReferences"
24 | |])
25 |
26 | let fromBuildRes targetName (result:BuildResult) =
27 | result.ResultsByTarget.[targetName].Items
28 | |> Seq.iter(fun r -> printfn "%s" r.ItemSpec)
29 |
30 | let exec() =
31 | let result = manager.Build(buildParam,requestReferences)
32 | fromBuildRes "ResolveProjectReferences" result
33 | fromBuildRes "ResolveAssemblyReferences" result
34 | ;;
35 | exec()
36 | ;;
37 | project.Properties|>Seq.iter(fun p -> printfn "%s -%s" p.Name p.EvaluatedValue)
38 |
39 |
40 | //project.Items|>Seq.iter(fun p -> p.ItemType p.EvaluatedInclude)
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ProtoWorkspace/MSBuildProjectSystem.fs:
--------------------------------------------------------------------------------
1 | module MSBuildProjectSystem
2 |
3 | open Microsoft.Extensions.Configuration
4 |
5 | type IProjectSystem =
6 | abstract Key : string
7 | abstract Language : string
8 | abstract Extensions : string seq
9 | abstract Initialize : Configuration:IConfiguration -> unit
10 |
11 |
12 |
13 | // NOTE - Maybe use the msbuildprojectloader for this?
14 |
--------------------------------------------------------------------------------
/ProtoWorkspace/Prelude.fs:
--------------------------------------------------------------------------------
1 | []
2 | module ProtoWorkspace.Prelude
3 |
4 | open System
5 | open System.IO
6 | open System.Diagnostics
7 |
8 | type FileName = string
9 | type FilePath = string
10 |
11 | let inline debugfn msg = Printf.kprintf Debug.WriteLine msg
12 | let inline failfn msg = Printf.kprintf Debug.Fail msg
13 |
14 | let inline isNull v =
15 | match v with
16 | | null -> true
17 | | _ -> false
18 |
19 | let inline isNotNull v = not (isNull v)
20 | let inline curry f a b = f(a,b)
21 |
22 | let inline dispose (disposable : #IDisposable) = disposable.Dispose()
23 | let inline Ok a = Choice1Of2 a
24 | let inline Fail a = Choice2Of2 a
25 | let inline (|Ok|Fail|) a = a
26 |
27 | /// String Equals Ordinal Ignore Case
28 | let (|EqualsIC|_|) (str : string) arg =
29 | if String.Compare(str, arg, StringComparison.OrdinalIgnoreCase) = 0 then Some()
30 | else None
31 |
32 |
33 | let (|LessThan|_|) a b = if a < b then Some() else None
34 |
35 | let tryCast<'T> (o: obj): 'T option =
36 | match o with
37 | | null -> None
38 | | :? 'T as a -> Some a
39 | | _ ->
40 | debugfn "Cannot cast %O to %O" (o.GetType()) typeof<'T>.Name
41 | None
42 |
43 | /// Null coalescing operator, return non null a, otherwise b
44 | let (?|?) a b = if isNull a then b else a
45 |
46 | let (^) = (<|)
47 |
48 | /// OR predicate combinator
49 | let inline (|?|) (pred1:'a->bool) (pred2:'a->bool) =
50 | fun a -> pred1 a || pred2 a
51 |
52 | /// AND predicate combinator
53 | let inline (|&|) (pred1:'a->bool) (pred2:'a->bool) =
54 | fun a -> pred1 a && pred2 a
55 |
56 | let (>) path1 path2 = Path.Combine (path1, path2)
57 |
58 |
59 | /// If arg is null raise an `ArgumentNullException` with the argname
60 | let inline checkNullArg arg argName =
61 | if isNull arg then nullArg argName
62 |
63 |
64 | /// Load times used to reset type checking properly on script/project load/unload. It just has to be unique for each project load/reload.
65 | /// Not yet sure if this works for scripts.
66 | let fakeDateTimeRepresentingTimeLoaded x = DateTime(abs (int64 (match x with null -> 0 | _ -> x.GetHashCode())) % 103231L)
67 |
68 | []
69 | []
70 | module Array =
71 | let inline private checkNonNull argName arg =
72 | match box arg with
73 | | null -> nullArg argName
74 | | _ -> ()
75 |
76 | /// Optimized arrays equality. ~100x faster than `array1 = array2` on strings.
77 | /// ~2x faster for floats
78 | /// ~0.8x slower for ints
79 | let inline areEqual (xs : 'T []) (ys : 'T []) =
80 | match xs, ys with
81 | | null, null -> true
82 | | [||], [||] -> true
83 | | null, _ | _, null -> false
84 | | _ when xs.Length <> ys.Length -> false
85 | | _ ->
86 | let mutable break' = false
87 | let mutable i = 0
88 | let mutable result = true
89 | while i < xs.Length && not break' do
90 | if xs.[i] <> ys.[i] then
91 | break' <- true
92 | result <- false
93 | i <- i + 1
94 | result
95 |
96 | /// check if subArray is found in the wholeArray starting
97 | /// at the provided index
98 | let inline isSubArray (subArray : 'T []) (wholeArray : 'T []) index =
99 | if isNull subArray || isNull wholeArray then false
100 | elif subArray.Length = 0 then true
101 | elif subArray.Length > wholeArray.Length then false
102 | elif subArray.Length = wholeArray.Length then areEqual subArray wholeArray
103 | else
104 | let rec loop subidx idx =
105 | if subidx = subArray.Length then true
106 | elif subArray.[subidx] = wholeArray.[idx] then loop (subidx + 1) (idx + 1)
107 | else false
108 | loop 0 index
109 |
110 | /// Returns true if one array has another as its subset from index 0.
111 | let startsWith (prefix : _ []) (whole : _ []) = isSubArray prefix whole 0
112 |
113 | /// Returns true if one array has trailing elements equal to another's.
114 | let endsWith (suffix : _ []) (whole : _ []) = isSubArray suffix whole (whole.Length - suffix.Length)
115 |
116 | /// Returns a new array with an element replaced with a given value.
117 | let replace index value (array : _ []) =
118 | checkNonNull "array" array
119 | if index >= array.Length then raise (IndexOutOfRangeException "index")
120 | let res = Array.copy array
121 | res.[index] <- value
122 | res
123 |
124 | /// Returns all heads of a given array.
125 | /// For [|1;2;3|] it returns [|[|1; 2; 3|]; [|1; 2|]; [|1|]|]
126 | let heads (array : 'T []) =
127 | checkNonNull "array" array
128 | let res = Array.zeroCreate<'T []> array.Length
129 | for i = array.Length - 1 downto 0 do
130 | res.[i] <- array.[0..i]
131 | res
132 |
133 | /// Fold over the array passing the index and element at that index to a folding function
134 | let foldi (folder : 'State -> int -> 'T -> 'State) (state : 'State) (array : 'T []) =
135 | checkNonNull "array" array
136 | if array.Length = 0 then state
137 | else
138 | let folder = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt folder
139 | let mutable state : 'State = state
140 | let len = array.Length
141 | for i = 0 to len - 1 do
142 | state <- folder.Invoke(state, i, array.[i])
143 | state
144 |
145 | /// pass an array byref to reverse it in place
146 | let revInPlace (array : 'T []) =
147 | checkNonNull "array" array
148 | if areEqual array [||] then ()
149 | else
150 | let arrlen, revlen = array.Length - 1, array.Length / 2 - 1
151 | for idx in 0..revlen do
152 | let t1 = array.[idx]
153 | let t2 = array.[arrlen - idx]
154 | array.[idx] <- t2
155 | array.[arrlen - idx] <- t1
156 |
157 | /// Map all elements of the array that satisfy the predicate
158 | let filterMap predicate mapfn (array : 'T []) =
159 | checkNonNull "array" array
160 | if array.Length = 0 then [||]
161 | else
162 | let result = Array.zeroCreate array.Length
163 | let mutable count = 0
164 | for elm in array do
165 | if predicate elm then
166 | result.[count] <- mapfn elm
167 | count <- count + 1
168 | if count = 0 then [||]
169 | else result.[0..count - 1]
170 |
171 | []
172 | module Seq =
173 | let sortWithDescending fn source =
174 | source |> Seq.sortWith (fun a b -> fn b a)
175 |
176 | []
177 | []
178 | module String =
179 | let inline toCharArray (str : string) = str.ToCharArray()
180 |
181 | let lowerCaseFirstChar (str : string) =
182 | if String.IsNullOrEmpty str || Char.IsLower(str, 0) then str
183 | else
184 | let strArr = toCharArray str
185 | match Array.tryHead strArr with
186 | | None -> str
187 | | Some c ->
188 | strArr.[0] <- Char.ToLower c
189 | String strArr
190 |
191 | let inline contains (target : string) (str : string) = str.Contains target
192 | let inline equalsIgnoreCase (str1 : string) (str2 : string) = str1.Equals(str2, StringComparison.OrdinalIgnoreCase)
193 |
194 | let extractTrailingIndex (str : string) =
195 | match str with
196 | | null -> null, None
197 | | _ ->
198 | let charr = str.ToCharArray()
199 | Array.revInPlace charr
200 | let digits = Array.takeWhile Char.IsDigit charr
201 | Array.revInPlace digits
202 | String digits |> function
203 | | "" -> str, None
204 | | index -> str.Substring(0, str.Length - index.Length), Some(int index)
205 |
206 | /// Remove all trailing and leading whitespace from the string
207 | /// return null if the string is null
208 | let trim (value : string) =
209 | if isNull value then null
210 | else value.Trim()
211 |
212 | /// Splits a string into substrings based on the strings in the array separators
213 | let split options (separator : string []) (value : string) =
214 | if isNull value then null
215 | else value.Split(separator, options)
216 |
217 | let (|StartsWith|_|) pattern value =
218 | if String.IsNullOrWhiteSpace value then None
219 | elif value.StartsWith pattern then Some()
220 | else None
221 |
222 | let (|Contains|_|) pattern value =
223 | if String.IsNullOrWhiteSpace value then None
224 | elif value.Contains pattern then Some()
225 | else None
226 |
227 | open System.IO
228 |
229 | let getLines (str : string) =
230 | use reader = new StringReader(str)
231 | [| let line = ref (reader.ReadLine())
232 | while isNotNull (!line) do
233 | yield !line
234 | line := reader.ReadLine()
235 | if str.EndsWith "\n" then
236 | // last trailing space not returned
237 | // http://stackoverflow.com/questions/19365404/stringreader-omits-trailing-linebreak
238 | yield String.Empty |]
239 |
240 | let getNonEmptyLines (str : string) =
241 | use reader = new StringReader(str)
242 | [| let line = ref (reader.ReadLine())
243 | while isNotNull (!line) do
244 | if (!line).Length > 0 then yield !line
245 | line := reader.ReadLine() |]
246 |
247 | /// match strings with ordinal ignore case
248 | let inline equalsIC (str1:string) (str2:string) = str1.Equals(str2,StringComparison.OrdinalIgnoreCase)
249 |
250 | /// Parse a string to find the first nonempty line
251 | /// Return null if the string was null or only contained empty lines
252 | let firstNonEmptyLine (str : string) =
253 | use reader = new StringReader(str)
254 |
255 | let rec loop (line : string) =
256 | if isNull line then None
257 | elif line.Length > 0 then Some line
258 | else loop (reader.ReadLine())
259 | loop (reader.ReadLine())
260 |
261 | open System.Text
262 |
263 | []
264 | module StringBuilder =
265 | /// Pipelining function for appending a string to a stringbuilder
266 | let inline append (str : string) (sb : StringBuilder) = sb.Append str
267 |
268 | /// Pipelining function for appending a string with a '\n' to a stringbuilder
269 | let inline appendLine (str : string) (sb : StringBuilder) = sb.AppendLine str
270 |
271 | /// SideEffecting function for appending a string to a stringbuilder
272 | let inline appendi (str : string) (sb : StringBuilder) = sb.Append str |> ignore
273 |
274 | /// SideEffecting function for appending a string with a '\n' to a stringbuilder
275 | let inline appendLinei (str : string) (sb : StringBuilder) = sb.AppendLine str |> ignore
276 |
277 | []
278 | module Dict =
279 | open System.Collections.Generic
280 |
281 | let add key value (dict : #IDictionary<_, _>) =
282 | dict.[key] <- value
283 | dict
284 |
285 | let remove (key : 'k) (dict : #IDictionary<'k, _>) =
286 | dict.Remove key |> ignore
287 | dict
288 |
289 | let tryFind key (dict : #IDictionary<'k, 'v>) =
290 | let mutable value = Unchecked.defaultof<_>
291 | if dict.TryGetValue(key, &value) then Some value
292 | else None
293 |
294 | let ofSeq (xs : ('k * 'v) seq) =
295 | let dict = Dictionary()
296 | for k, v in xs do
297 | dict.[k] <- v
298 | dict
299 |
300 | module PropertyConverter =
301 | // TODO - railway this
302 | let toGuid propertyValue =
303 | match Guid.TryParse propertyValue with
304 | | true, value -> Some value
305 | | _ -> None
306 |
307 | let toDefineConstants propertyValue =
308 | if String.IsNullOrWhiteSpace propertyValue then [||]
309 | else propertyValue.Split([| ';' |], StringSplitOptions.RemoveEmptyEntries)
310 |
311 | // TODO - railway this
312 | let toBoolean propertyValue =
313 | if propertyValue = String.Empty then false else
314 | match Boolean.TryParse propertyValue with
315 | | true, value -> value
316 | | _ -> failwithf "Couldn't parse '%s' into a Boolean" propertyValue
317 |
318 | let toBooleanOr propertyValue defaultArg =
319 | match Boolean.TryParse propertyValue with
320 | | true, value -> value
321 | | _ -> defaultArg
322 | (*
323 | Omnisharp does it like this
324 |
325 | public static bool? ToBoolean(string propertyValue)
326 | {
327 | if (string.IsNullOrWhiteSpace(propertyValue))
328 | {
329 | return null;
330 | }
331 |
332 | try
333 | {
334 | return Convert.ToBoolean(propertyValue);
335 | }
336 | catch (FormatException)
337 | {
338 | return null;
339 | }
340 | }
341 |
342 | public static bool ToBoolean(string propertyValue, bool defaultValue)
343 | {
344 | if (string.IsNullOrWhiteSpace(propertyValue))
345 | {
346 | return defaultValue;
347 | }
348 |
349 | try
350 | {
351 | return Convert.ToBoolean(propertyValue);
352 | }
353 | catch (FormatException)
354 | {
355 | return defaultValue;
356 | }
357 | }
358 | *)
359 |
360 |
361 |
362 |
363 | type internal Assert() =
364 | /// Display a good exception for this error message and then rethrow.
365 | static member Exception(e:Exception) =
366 | System.Diagnostics.Debug.Assert(false, "Unexpected exception seen in language service", e.ToString())
367 |
368 |
369 | []
370 | []
371 | module Option =
372 | let inline ofNull value =
373 | if obj.ReferenceEquals(value, null) then None else Some value
374 |
375 | let inline ofNullable (value: Nullable<'T>) =
376 | if value.HasValue then Some value.Value else None
377 |
378 | let inline toNullable (value: 'T option) =
379 | match value with
380 | | Some x -> Nullable<_> x
381 | | None -> Nullable<_> ()
382 |
383 | let inline attempt (f: unit -> 'T) = try Some <| f() with _ -> None
384 |
385 | /// Gets the value associated with the option or the supplied default value.
386 | let inline getOrElse v =
387 | function
388 | | Some x -> x
389 | | None -> v
390 |
391 | /// Gets the option if Some x, otherwise the supplied default value.
392 | let inline orElse v =
393 | function
394 | | Some x -> Some x
395 | | None -> v
396 |
397 | /// Gets the value if Some x, otherwise try to get another value by calling a function
398 | let inline getOrTry f =
399 | function
400 | | Some x -> x
401 | | None -> f()
402 |
403 | /// Gets the option if Some x, otherwise try to get another value
404 | let inline orTry f =
405 | function
406 | | Some x -> Some x
407 | | None -> f()
408 |
409 | /// Some(Some x) -> Some x | None -> None
410 | let inline flatten x =
411 | match x with
412 | | Some x -> x
413 | | None -> None
414 |
415 | let inline toList x =
416 | match x with
417 | | Some x -> [x]
418 | | None -> []
419 |
420 | let inline iterElse someAction noneAction opt =
421 | match opt with
422 | | Some x -> someAction x
423 | | None -> noneAction ()
424 |
425 | // Async helper functions copied from https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/ControlCollections.Async.fs
426 | []
427 | []
428 | module Async =
429 | /// Transforms an Async value using the specified function.
430 | []
431 | let map (mapping : 'T -> 'U) (value : Async<'T>) : Async<'U> =
432 | async {
433 | // Get the input value.
434 | let! x = value
435 | // Apply the mapping function and return the result.
436 | return mapping x
437 | }
438 |
439 | // Transforms an Async value using the specified Async function.
440 | []
441 | let bind (binding : 'T -> Async<'U>) (value : Async<'T>) : Async<'U> =
442 | async {
443 | // Get the input value.
444 | let! x = value
445 | // Apply the binding function and return the result.
446 | return! binding x
447 | }
448 |
449 | []
450 | module Array =
451 | /// Async implementation of Array.map.
452 | let map (mapping : 'T -> Async<'U>) (array : 'T[]) : Async<'U[]> =
453 | let len = Array.length array
454 | let result = Array.zeroCreate len
455 |
456 | async { // Apply the mapping function to each array element.
457 | for i in 0 .. len - 1 do
458 | let! mappedValue = mapping array.[i]
459 | result.[i] <- mappedValue
460 |
461 | // Return the completed results.
462 | return result
463 | }
464 |
465 | /// Async implementation of Array.mapi.
466 | let mapi (mapping : int -> 'T -> Async<'U>) (array : 'T[]) : Async<'U[]> =
467 | let len = Array.length array
468 | let result = Array.zeroCreate len
469 |
470 | async {
471 | // Apply the mapping function to each array element.
472 | for i in 0 .. len - 1 do
473 | let! mappedValue = mapping i array.[i]
474 | result.[i] <- mappedValue
475 |
476 | // Return the completed results.
477 | return result
478 | }
479 |
480 | /// Async implementation of Array.exists.
481 | let exists (predicate : 'T -> Async) (array : 'T[]) : Async =
482 | let len = Array.length array
483 | let rec loop i =
484 | async {
485 | if i >= len then
486 | return false
487 | else
488 | let! found = predicate array.[i]
489 | if found then
490 | return true
491 | else
492 | return! loop (i + 1)
493 | }
494 | loop 0
495 |
496 | []
497 | module List =
498 | let rec private mapImpl (mapping, mapped : 'U list, pending : 'T list) =
499 | async {
500 | match pending with
501 | | [] ->
502 | // Reverse the list of mapped values before returning it.
503 | return List.rev mapped
504 |
505 | | el :: pending ->
506 | // Apply the current list element to the mapping function.
507 | let! mappedEl = mapping el
508 |
509 | // Cons the result to the list of mapped values, then continue
510 | // mapping the rest of the pending list elements.
511 | return! mapImpl (mapping, mappedEl :: mapped, pending)
512 | }
513 |
514 | /// Async implementation of List.map.
515 | let map (mapping : 'T -> Async<'U>) (list : 'T list) : Async<'U list> =
516 | mapImpl (mapping, [], list)
517 |
518 |
519 |
520 | /// Maybe computation expression builder, copied from ExtCore library
521 | /// https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Control.fs
522 | []
523 | type MaybeBuilder () =
524 | // 'T -> M<'T>
525 | []
526 | member inline __.Return value: 'T option = Some value
527 |
528 | // M<'T> -> M<'T>
529 | []
530 | member inline __.ReturnFrom value: 'T option = value
531 |
532 | // unit -> M<'T>
533 | []
534 | member inline __.Zero (): unit option = Some () // TODO: Should this be None?
535 |
536 | // (unit -> M<'T>) -> M<'T>
537 | []
538 | member __.Delay (f: unit -> 'T option): 'T option = f ()
539 |
540 | // M<'T> -> M<'T> -> M<'T>
541 | // or
542 | // M -> M<'T> -> M<'T>
543 | []
544 | member inline __.Combine (r1, r2: 'T option): 'T option =
545 | match r1 with
546 | | None -> None
547 | | Some () -> r2
548 |
549 | // M<'T> * ('T -> M<'U>) -> M<'U>
550 | []
551 | member inline __.Bind (value, f: 'T -> 'U option): 'U option = Option.bind f value
552 |
553 | // 'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable
554 | []
555 | member __.Using (resource: ('T :> System.IDisposable), body: _ -> _ option): _ option =
556 | try body resource
557 | finally
558 | if not <| obj.ReferenceEquals (null, box resource) then
559 | resource.Dispose ()
560 |
561 | // (unit -> bool) * M<'T> -> M<'T>
562 | []
563 | member x.While (guard, body: _ option): _ option =
564 | if guard () then
565 | // OPTIMIZE: This could be simplified so we don't need to make calls to Bind and While.
566 | x.Bind (body, (fun () -> x.While (guard, body)))
567 | else
568 | x.Zero ()
569 |
570 | // seq<'T> * ('T -> M<'U>) -> M<'U>
571 | // or
572 | // seq<'T> * ('T -> M<'U>) -> seq>
573 | []
574 | member x.For (sequence: seq<_>, body: 'T -> unit option): _ option =
575 | // OPTIMIZE: This could be simplified so we don't need to make calls to Using, While, Delay.
576 | using (sequence.GetEnumerator()) (fun enum ->
577 | x.While (enum.MoveNext,
578 | x.Delay (fun () -> body enum.Current)))
579 |
580 |
581 |
582 | []
583 | type AsyncMaybeBuilder () =
584 | []
585 | member __.Return value : Async<'T option> = Some value |> async.Return
586 |
587 | []
588 | member __.ReturnFrom value : Async<'T option> = value
589 |
590 | []
591 | member __.ReturnFrom (value: 'T option) : Async<'T option> = async.Return value
592 |
593 | []
594 | member __.Zero () : Async = Some () |> async.Return
595 |
596 | []
597 | member __.Delay (f : unit -> Async<'T option>) : Async<'T option> = f ()
598 |
599 | []
600 | member __.Combine (r1, r2 : Async<'T option>) : Async<'T option> =
601 | async {
602 | let! r1' = r1
603 | match r1' with
604 | | None -> return None
605 | | Some () -> return! r2
606 | }
607 |
608 | []
609 | member __.Bind (value: Async<'T option>, f : 'T -> Async<'U option>) : Async<'U option> =
610 | async {
611 | let! value' = value
612 | match value' with
613 | | None -> return None
614 | | Some result -> return! f result
615 | }
616 |
617 | []
618 | member __.Bind (value: 'T option, f : 'T -> Async<'U option>) : Async<'U option> =
619 | async {
620 | match value with
621 | | None -> return None
622 | | Some result -> return! f result
623 | }
624 |
625 | []
626 | member __.Using (resource : ('T :> IDisposable), body : _ -> Async<_ option>) : Async<_ option> =
627 | try body resource
628 | finally
629 | if isNotNull resource then resource.Dispose ()
630 |
631 | []
632 | member x.While (guard, body : Async<_ option>) : Async<_ option> =
633 | if guard () then
634 | x.Bind (body, (fun () -> x.While (guard, body)))
635 | else
636 | x.Zero ()
637 |
638 | []
639 | member x.For (sequence : seq<_>, body : 'T -> Async) : Async<_ option> =
640 | x.Using (sequence.GetEnumerator (), fun enum ->
641 | x.While (enum.MoveNext, x.Delay (fun () -> body enum.Current)))
642 |
643 | []
644 | member inline __.TryWith (computation : Async<'T option>, catchHandler : exn -> Async<'T option>) : Async<'T option> =
645 | async.TryWith (computation, catchHandler)
646 |
647 | []
648 | member inline __.TryFinally (computation : Async<'T option>, compensation : unit -> unit) : Async<'T option> =
649 | async.TryFinally (computation, compensation)
650 |
651 | []
652 | module AsyncMaybe =
653 | let inline liftAsync (async : Async<'T>) : Async<_ option> =
654 | async |> Async.map Some
655 |
656 |
657 | let maybe = MaybeBuilder()
658 | let asyncMaybe = AsyncMaybeBuilder()
659 |
660 |
661 | []
662 | module Directory =
663 |
664 | let fromPath path = (FileInfo path).Directory.FullName
--------------------------------------------------------------------------------
/ProtoWorkspace/ProjectConfig.fs:
--------------------------------------------------------------------------------
1 | namespace ProtoWorkspace
2 |
3 | open System.IO
4 |
5 | type ProjectSettings =
6 | { IsForStandaloneScript : bool
7 | ProjectFile : FileName
8 | TargetFramework : FSharpTargetFramework
9 | CompilerVersion : FSharpCompilerVersion option
10 | CompilerOptions : string []
11 | SourceFiles : FileName []
12 | FullOutputFilePath : FileName option
13 | References : FileName []
14 | ProjectReferences : FileName [] }
15 |
16 | type ProjectConfig =
17 | | FsProject of ProjectSettings
18 | | FsxProject of ProjectSettings
19 | | SigProject of ProjectSettings
20 |
21 | [