Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit158bfe6

Browse files
authored
Single File Management Refactor (dotnet#5845)
* Trying to fix dev16 with latest changes* Dev16 is partially working* Fixed several issues, should be working dev16* Using try..with on computing options* Deleting unused code* Minor refactor* Check command line option cps stamps for recompute as a backup* Using ProjectId for project options* Updating binoutputpath for legacy projects to workspace project* Removing cps stamp as we don't need it* Updated roslyn package. Using IWorkspaceProjectContext.Id.* Handling single files (script files) differently* Removing dead code* Removing dead code* Removing dead code* Removing dead code* Removing dead code* Removing ProjectSitesAndFiles.fs* Initializing early to capture solution/workspace events* Handling rename of script files* Delete Fsi.nuget.props* Update Extensions.fs* Create project per script file* Make sure to dispose in fallback* Don't need that
1 parent7118378 commit158bfe6

File tree

8 files changed

+236
-500
lines changed

8 files changed

+236
-500
lines changed

‎vsintegration/src/FSharp.Editor/Common/Constants.fs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ module internal FSharpConstants =
4343
/// "FSharp"
4444
letFSharpLanguageLongName="FSharp"
4545

46+
[<Literal>]
47+
/// "F# Miscellaneous Files"
48+
letFSharpMiscellaneousFilesName="F# Miscellaneous Files"
49+
4650
[<RequireQualifiedAccess>]
4751
moduleinternalFSharpProviderConstants=
4852

‎vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,12 @@ type internal FSharpDocumentDiagnosticAnalyzer() =
127127
let!parsingOptions,_,projectOptions= projectInfoManager.TryGetOptionsForDocumentOrProject(document)
128128
let!sourceText= document.GetTextAsync(cancellationToken)
129129
let!textVersion= document.GetTextVersionAsync(cancellationToken)
130-
return!
131-
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic)
132-
|> liftAsync
130+
if document.Project.Name<> FSharpConstants.FSharpMiscellaneousFilesName|| isScriptFile document.FilePaththen
131+
return!
132+
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic)
133+
|> liftAsync
134+
else
135+
return ImmutableArray<Diagnostic>.Empty
133136
}
134137
|> Async.map(Option.defaultValue ImmutableArray<Diagnostic>.Empty)
135138
|> RoslynHelpers.StartAsyncAsTask cancellationToken

‎vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
<CompileInclude="LanguageService\Symbols.fs" />
4949
<CompileInclude="LanguageService\FSharpCheckerExtensions.fs" />
5050
<CompileInclude="LanguageService\IProjectSite.fs" />
51-
<CompileInclude="LanguageService\ProjectSitesAndFiles.fs" />
5251
<CompileInclude="LanguageService\ProvideFSharpVersionRegistrationAttribute.fs" />
5352
<CompileInclude="LanguageService\FSharpCheckerProvider.fs" />
5453
<CompileInclude="LanguageService\FSharpProjectOptionsManager.fs" />
54+
<CompileInclude="LanguageService\SingleFileWorkspaceMap.fs" />
5555
<CompileInclude="LanguageService\LegacyProjectWorkspaceMap.fs" />
5656
<CompileInclude="LanguageService\LanguageService.fs" />
5757
<CompileInclude="LanguageService\AssemblyContentProvider.fs" />
@@ -153,6 +153,7 @@
153153
<PackageReferenceInclude="Microsoft.VisualStudio.Shell.Immutable.10.0"Version="$(MicrosoftVisualStudioShellImmutable100PackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
154154
<PackageReferenceInclude="Microsoft.VisualStudio.Shell.Immutable.11.0"Version="$(MicrosoftVisualStudioShellImmutable110PackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
155155
<PackageReferenceInclude="Microsoft.VisualStudio.Shell.Interop.11.0"Version="$(MicrosoftVisualStudioShellInterop110PackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
156+
<PackageReferenceInclude="Microsoft.VisualStudio.Shell.Interop.12.0"Version="$(MicrosoftVisualStudioShellInterop120PackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
156157
<PackageReferenceInclude="Microsoft.VisualStudio.Text.UI"Version="$(MicrosoftVisualStudioTextUIPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
157158
<PackageReferenceInclude="Microsoft.VisualStudio.Text.UI.Wpf"Version="$(MicrosoftVisualStudioTextUIWpfPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
158159
<PackageReferenceInclude="Microsoft.VisualStudio.TextManager.Interop"Version="$(MicrosoftVisualStudioTextManagerInteropPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />

‎vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs‎

Lines changed: 87 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ open Microsoft.FSharp.Compiler.CompileOps
1414
openMicrosoft.FSharp.Compiler.SourceCodeServices
1515
openMicrosoft.VisualStudio
1616
openMicrosoft.VisualStudio.FSharp.Editor
17-
openMicrosoft.VisualStudio.FSharp.Editor.SiteProvider
1817
openMicrosoft.VisualStudio.LanguageServices
1918
openMicrosoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
2019
openMicrosoft.VisualStudio.Shell
@@ -34,8 +33,6 @@ module private FSharpProjectOptionsHelpers =
3433
{
3534
new IProvideProjectSitewith
3635
memberx.GetProjectSite()=
37-
letfst(a,_,_)= a
38-
letsnd(_,b,_)= b
3936
let mutableerrorReporter=
4037
letreporter= ProjectExternalErrorReporter(project.Id,"FS", serviceProvider)
4138
Some(reporter:> IVsLanguageServiceBuildErrorReporter2)
@@ -83,8 +80,10 @@ module private FSharpProjectOptionsHelpers =
8380

8481
[<RequireQualifiedAccess>]
8582
typeprivateFSharpProjectOptionsMessage=
86-
| TryGetOptionsofProject*AsyncReplyChannel<(FSharpParsingOptions*FSharpProjectOptions)option>
83+
| TryGetOptionsByDocumentofDocument*AsyncReplyChannel<(FSharpParsingOptions*FSharpProjectOptions)option>
84+
| TryGetOptionsByProjectofProject*AsyncReplyChannel<(FSharpParsingOptions*FSharpProjectOptions)option>
8785
| ClearOptionsofProjectId
86+
| ClearSingleFileOptionsCacheofDocumentId
8887

8988
[<Sealed>]
9089
typeprivateFSharpProjectOptionsReactor(workspace: VisualStudioWorkspaceImpl,settings: EditorOptions,serviceProvider,checkerProvider: FSharpCheckerProvider)=
@@ -94,6 +93,49 @@ type private FSharpProjectOptionsReactor (workspace: VisualStudioWorkspaceImpl,
9493
letcpsCommandLineOptions=new ConcurrentDictionary<ProjectId, string[]* string[]>()
9594

9695
letcache= Dictionary<ProjectId, VersionStamp* FSharpParsingOptions* FSharpProjectOptions>()
96+
letsingleFileCache= Dictionary<DocumentId, VersionStamp* FSharpParsingOptions* FSharpProjectOptions>()
97+
98+
let rectryComputeOptionsByFile(document:Document)=
99+
async{
100+
let!text= document.GetTextAsync()|> Async.AwaitTask
101+
let!fileStamp= document.GetTextVersionAsync()|> Async.AwaitTask
102+
let!scriptProjectOptions,_= checkerProvider.Checker.GetProjectOptionsFromScript(document.FilePath, text.ToString(), DateTime.Now)
103+
match singleFileCache.TryGetValue(document.Id)with
104+
|false,_->
105+
letprojectOptions=
106+
if isScriptFile document.FilePaththen
107+
scriptProjectOptions
108+
else
109+
{
110+
ProjectFileName= document.FilePath
111+
ProjectId= None
112+
SourceFiles=[|document.FilePath|]
113+
OtherOptions=[||]
114+
ReferencedProjects=[||]
115+
IsIncompleteTypeCheckEnvironment=false
116+
UseScriptResolutionRules= SourceFile.MustBeSingleFileProject(Path.GetFileName(document.FilePath))
117+
LoadTime= DateTime.Now
118+
UnresolvedReferences= None
119+
OriginalLoadReferences=[]
120+
ExtraProjectInfo= None
121+
Stamp= Some(int64(fileStamp.GetHashCode()))
122+
}
123+
124+
checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen=true, userOpName="computeOptions")
125+
126+
letparsingOptions,_= checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)
127+
128+
singleFileCache.[document.Id]<-(fileStamp, parsingOptions, projectOptions)
129+
130+
return Some(parsingOptions, projectOptions)
131+
132+
|true,(fileStamp2, parsingOptions, projectOptions)->
133+
if fileStamp<> fileStamp2then
134+
singleFileCache.Remove(document.Id)|> ignore
135+
return! tryComputeOptionsByFile document
136+
else
137+
return Some(parsingOptions, projectOptions)
138+
}
97139

98140
let rectryComputeOptions(project:Project)=
99141
letprojectId= project.Id
@@ -200,24 +242,48 @@ type private FSharpProjectOptionsReactor (workspace: VisualStudioWorkspaceImpl,
200242
async{
201243
whiletruedo
202244
match! agent.Receive()with
203-
| FSharpProjectOptionsMessage.TryGetOptions(project, reply)->
245+
| FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply)->
246+
try
247+
// For now, disallow miscellaneous workspace since we are using the hacky F# miscellaneous files project.
248+
if document.Project.Solution.Workspace.Kind= WorkspaceKind.MiscellaneousFilesthen
249+
reply.Reply(None)
250+
elif document.Project.Name= FSharpConstants.FSharpMiscellaneousFilesNamethen
251+
let!options= tryComputeOptionsByFile document
252+
reply.Reply(options)
253+
else
254+
reply.Reply(tryComputeOptions document.Project)
255+
with
256+
|_->
257+
reply.Reply(None)
258+
| FSharpProjectOptionsMessage.TryGetOptionsByProject(project, reply)->
204259
try
205-
reply.Reply(tryComputeOptions project)
260+
if project.Solution.Workspace.Kind= WorkspaceKind.MiscellaneousFiles|| project.Name= FSharpConstants.FSharpMiscellaneousFilesNamethen
261+
reply.Reply(None)
262+
else
263+
reply.Reply(tryComputeOptions project)
206264
with
207265
|_->
208266
reply.Reply(None)
209267
| FSharpProjectOptionsMessage.ClearOptions(projectId)->
210268
cache.Remove(projectId)|> ignore
269+
| FSharpProjectOptionsMessage.ClearSingleFileOptionsCache(documentId)->
270+
singleFileCache.Remove(documentId)|> ignore
211271
}
212272

213273
letagent= MailboxProcessor.Start((fun agent-> loop agent), cancellationToken= cancellationTokenSource.Token)
214274

215275
member__.TryGetOptionsByProjectAsync(project)=
216-
agent.PostAndAsyncReply(fun reply-> FSharpProjectOptionsMessage.TryGetOptions(project, reply))
276+
agent.PostAndAsyncReply(fun reply-> FSharpProjectOptionsMessage.TryGetOptionsByProject(project, reply))
277+
278+
member__.TryGetOptionsByDocumentAsync(document)=
279+
agent.PostAndAsyncReply(fun reply-> FSharpProjectOptionsMessage.TryGetOptionsByDocument(document, reply))
217280

218281
member__.ClearOptionsByProjectId(projectId)=
219282
agent.Post(FSharpProjectOptionsMessage.ClearOptions(projectId))
220283

284+
member__.ClearSingleFileOptionsCache(documentId)=
285+
agent.Post(FSharpProjectOptionsMessage.ClearSingleFileOptionsCache(documentId))
286+
221287
member__.SetCpsCommandLineOptions(projectId,sourcePaths,options)=
222288
cpsCommandLineOptions.[projectId]<-(sourcePaths, options)
223289

@@ -247,11 +313,11 @@ type internal FSharpProjectOptionsManager
247313
settings: EditorOptions
248314
)=
249315

250-
letreactor=new FSharpProjectOptionsReactor(workspace, settings, serviceProvider, checkerProvider)
316+
letprojectDisplayNameOf projectFileName=
317+
if String.IsNullOrWhiteSpace projectFileNamethen projectFileName
318+
else Path.GetFileNameWithoutExtension projectFileName
251319

252-
// A table of information about single-file projects. Currently we only need the load time of each such file, plus
253-
// the original options for editing
254-
letsingleFileProjectTable= ConcurrentDictionary<ProjectId, DateTime* FSharpParsingOptions* FSharpProjectOptions>()
320+
letreactor=new FSharpProjectOptionsReactor(workspace, settings, serviceProvider, checkerProvider)
255321

256322
do
257323
// We need to listen to this event for lifecycle purposes.
@@ -265,35 +331,8 @@ type internal FSharpProjectOptionsManager
265331
memberthis.ClearInfoForProject(projectId:ProjectId)=
266332
reactor.ClearOptionsByProjectId(projectId)
267333

268-
/// Clear a project from the single file project table
269-
memberthis.ClearInfoForSingleFileProject(projectId)=
270-
singleFileProjectTable.TryRemove(projectId)|> ignore
271-
272-
/// Update a project in the single file project table
273-
memberthis.AddOrUpdateSingleFileProject(projectId,data)= singleFileProjectTable.[projectId]<- data
274-
275-
/// Get the exact options for a single-file script
276-
memberthis.ComputeSingleFileOptions(tryGetOrCreateProjectId,fileName,loadTime,fileContents,solution)=
277-
async{
278-
letextraProjectInfo= Some(box workspace)
279-
if SourceFile.MustBeSingleFileProject(fileName)then
280-
// NOTE: we don't use a unique stamp for single files, instead comparing options structurally.
281-
// This is because we repeatedly recompute the options.
282-
letoptionsStamp= None
283-
let!options,_diagnostics= checkerProvider.Checker.GetProjectOptionsFromScript(fileName, fileContents, loadTime,[||], ?extraProjectInfo=extraProjectInfo, ?optionsStamp=optionsStamp)
284-
// NOTE: we don't use FCS cross-project references from scripts to projects. THe projects must have been
285-
// compiled and #r will refer to files on disk
286-
letreferencedProjectFileNames=[||]
287-
letsite= ProjectSitesAndFiles.CreateProjectSiteForScript(fileName, referencedProjectFileNames, options)
288-
letdeps,projectOptions= ProjectSitesAndFiles.GetProjectOptionsForProjectSite(settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider,(tryGetOrCreateProjectId fileName), fileName, options.ExtraProjectInfo, solution, None)
289-
letparsingOptions,_= checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)
290-
return(deps, parsingOptions, projectOptions)
291-
else
292-
letsite= ProjectSitesAndFiles.ProjectSiteOfSingleFile(fileName)
293-
letdeps,projectOptions= ProjectSitesAndFiles.GetProjectOptionsForProjectSite(settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider,(tryGetOrCreateProjectId fileName), fileName, extraProjectInfo, solution, None)
294-
letparsingOptions,_= checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)
295-
return(deps, parsingOptions, projectOptions)
296-
}
334+
memberthis.ClearSingleFileOptionsCache(documentId)=
335+
reactor.ClearSingleFileOptionsCache(documentId)
297336

298337
/// Get compilation defines relevant for syntax processing.
299338
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project
@@ -311,45 +350,20 @@ type internal FSharpProjectOptionsManager
311350
/// Get the exact options for a document or project
312351
memberthis.TryGetOptionsForDocumentOrProject(document:Document)=
313352
async{
314-
letprojectId= document.Project.Id
315-
316-
// The options for a single-file script project are re-requested each time the file is analyzed. This is because the
317-
// single-file project may contain #load and #r references which are changing as the user edits, and we may need to re-analyze
318-
// to determine the latest settings. FCS keeps a cache to help ensure these are up-to-date.
319-
match singleFileProjectTable.TryGetValue(projectId)with
320-
|true,(loadTime,_,_)->
321-
try
322-
letfileName= document.FilePath
323-
let!cancellationToken= Async.CancellationToken
324-
let!sourceText= document.GetTextAsync(cancellationToken)|> Async.AwaitTask
325-
// NOTE: we don't use FCS cross-project references from scripts to projects. The projects must have been
326-
// compiled and #r will refer to files on disk.
327-
lettryGetOrCreateProjectId _= None
328-
let!_referencedProjectFileNames,parsingOptions,projectOptions= this.ComputeSingleFileOptions(tryGetOrCreateProjectId, fileName, loadTime, sourceText.ToString(), document.Project.Solution)
329-
this.AddOrUpdateSingleFileProject(projectId,(loadTime, parsingOptions, projectOptions))
330-
return Some(parsingOptions, None, projectOptions)
331-
with ex->
332-
Assert.Exception(ex)
333-
return None
353+
match! reactor.TryGetOptionsByDocumentAsync(document)with
354+
| Some(parsingOptions, projectOptions)->
355+
return Some(parsingOptions, None, projectOptions)
334356
|_->
335-
match! reactor.TryGetOptionsByProjectAsync(document.Project)with
336-
| Some(parsingOptions, projectOptions)->
337-
return Some(parsingOptions, None, projectOptions)
338-
|_->
339-
return None
357+
return None
340358
}
341359

342360
/// Get the options for a document or project relevant for syntax processing.
343361
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project options for a script.
344362
memberthis.TryGetOptionsForEditingDocumentOrProject(document:Document)=
345-
letprojectId= document.Project.Id
346-
match singleFileProjectTable.TryGetValue(projectId)with
347-
|true,(_loadTime, parsingOptions, originalOptions)->async{return Some(parsingOptions, originalOptions)}
348-
|_->
349-
async{
350-
let!result= this.TryGetOptionsForDocumentOrProject(document)
351-
return result|> Option.map(fun(parsingOptions,_,projectOptions)-> parsingOptions, projectOptions)
352-
}
363+
async{
364+
let!result= this.TryGetOptionsForDocumentOrProject(document)
365+
return result|> Option.map(fun(parsingOptions,_,projectOptions)-> parsingOptions, projectOptions)
366+
}
353367

354368
[<Export>]
355369
/// This handles commandline change notifications from the Dotnet Project-system

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp