Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ec16126
first working attempt
majocha Mar 6, 2023
0b9a331
try cwt
majocha Mar 7, 2023
66f3dc4
Merge branch 'main' into cache-parse-incremental
majocha Mar 7, 2023
d32e0fd
there is no source change?
majocha Mar 7, 2023
a4443d0
FSharpSources in state, with weakly attached parsed inputs
majocha Mar 7, 2023
92bec18
Merge branch 'main' into cache-parse-incremental
majocha Mar 7, 2023
afe51a0
invalidate correctly
majocha Mar 8, 2023
d1495c4
Merge branch 'main' into cache-parse-incremental
majocha Mar 8, 2023
93f76d7
some stupid debounce
majocha Mar 8, 2023
547768c
fix test
majocha Mar 8, 2023
6249d61
Merge branch 'cache-parse-incremental' of https://github.com/majocha/…
majocha Mar 8, 2023
aac93c5
fix wip
majocha Mar 8, 2023
057834d
fixit
majocha Mar 8, 2023
64315bb
revert to notifiedstamps, explicit invalidation
majocha Mar 8, 2023
f923d6d
some cleanup
majocha Mar 8, 2023
48fff10
Merge branch 'main' into cache-parse-incremental
majocha Mar 8, 2023
05e40cb
reduce diff a bit
majocha Mar 8, 2023
771d996
Merge branch 'cache-parse-incremental' of https://github.com/majocha/…
majocha Mar 8, 2023
efb258d
forgot that one
majocha Mar 8, 2023
f9bbe65
Merge branch 'main' into cache-parse-incremental
majocha Mar 8, 2023
02f51e6
add option
majocha Mar 9, 2023
2bd08a2
editor option
majocha Mar 9, 2023
48048cb
oops
majocha Mar 9, 2023
10c0a16
format
majocha Mar 9, 2023
2e7cbf5
update surface area
majocha Mar 9, 2023
a9ec7a8
Merge branch 'main' into cache-parse-incremental
majocha Mar 9, 2023
1f50158
add some tests and diagnostics
majocha Mar 9, 2023
eabdaf4
Merge branch 'cache-parse-incremental' of https://github.com/majocha/…
majocha Mar 9, 2023
f05e0e2
telemetry based tests
majocha Mar 10, 2023
ff204d4
add docs
majocha Mar 10, 2023
d0776dd
Merge branch 'main' into cache-parse-incremental
majocha Mar 10, 2023
8487db2
feedback, naming
majocha Mar 10, 2023
4c440d1
Merge branch 'main' into cache-parse-incremental
majocha Mar 10, 2023
8603a61
Merge branch 'cache-parse-incremental' of https://github.com/majocha/…
majocha Mar 10, 2023
4deea21
naming
majocha Mar 10, 2023
1ea1090
oops
majocha Mar 10, 2023
60e0dcf
feedback
majocha Mar 13, 2023
7da24c5
Merge branch 'main' into cache-parse-incremental
majocha Mar 13, 2023
47e748c
Merge branch 'main' into cache-parse-incremental
majocha Mar 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/builder-caches.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: IncrementalBuilder caches
category: Language Service Internals
categoryindex: 300
index: 1300
---
# IncrementalBuilder SyntaxTree cache

Incremental builder keeps in a cache at most one `ParsedInput` for each file it parses.
This behavior can be toggled with `useSyntaxTreeCache` parameter.

Memory impact of this feature can be in range of tens of MB for larger solutions. This can be inspected in memory profilng tools by searching for `ParsedInput` instances.
When partial checking is enabled, implementation files backed by signature will not be parsed or cached, as expected.
265 changes: 135 additions & 130 deletions src/Compiler/Service/IncrementalBuild.fs

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/Compiler/Service/IncrementalBuild.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ type internal IncrementalBuilder =
parallelReferenceResolution: ParallelReferenceResolution *
captureIdentifiersWhenParsing: bool *
getSource: (string -> ISourceText option) option *
useChangeNotifications: bool ->
useChangeNotifications: bool *
useSyntaxTreeCache: bool ->
NodeCode<IncrementalBuilder option * FSharpDiagnostic[]>

/// Generalized Incremental Builder. This is exposed only for unit testing purposes.
Expand Down
23 changes: 14 additions & 9 deletions src/Compiler/Service/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ type BackgroundCompiler
parallelReferenceResolution,
captureIdentifiersWhenParsing,
getSource: (string -> ISourceText option) option,
useChangeNotifications
useChangeNotifications,
useSyntaxTreeCache
) as self =

let beforeFileChecked = Event<string * FSharpProjectOptions>()
Expand Down Expand Up @@ -329,7 +330,8 @@ type BackgroundCompiler
parallelReferenceResolution,
captureIdentifiersWhenParsing,
getSource,
useChangeNotifications
useChangeNotifications,
useSyntaxTreeCache
)

match builderOpt with
Expand Down Expand Up @@ -636,9 +638,6 @@ type BackgroundCompiler
) =

node {
if useChangeNotifications then
do! builder.NotifyFileChanged(fileName, DateTime.UtcNow)

match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with
| Some (_, results) -> return FSharpCheckFileAnswer.Succeeded results
| _ ->
Expand Down Expand Up @@ -1263,7 +1262,8 @@ type FSharpChecker
parallelReferenceResolution,
captureIdentifiersWhenParsing,
getSource,
useChangeNotifications
useChangeNotifications,
useSyntaxTreeCache
) =

let backgroundCompiler =
Expand All @@ -1280,7 +1280,8 @@ type FSharpChecker
parallelReferenceResolution,
captureIdentifiersWhenParsing,
getSource,
useChangeNotifications
useChangeNotifications,
useSyntaxTreeCache
)

static let globalInstance = lazy FSharpChecker.Create()
Expand Down Expand Up @@ -1324,7 +1325,8 @@ type FSharpChecker
?enablePartialTypeChecking,
?parallelReferenceResolution: bool,
?captureIdentifiersWhenParsing: bool,
?documentSource: DocumentSource
?documentSource: DocumentSource,
?useSyntaxTreeCache: bool
) =

use _ = Activity.startNoTags "FSharpChecker.Create"
Expand Down Expand Up @@ -1352,6 +1354,8 @@ type FSharpChecker
| Some (DocumentSource.Custom _) -> true
| _ -> false

let useSyntaxTreeCache = defaultArg useSyntaxTreeCache true

if keepAssemblyContents && enablePartialTypeChecking then
invalidArg "enablePartialTypeChecking" "'keepAssemblyContents' and 'enablePartialTypeChecking' cannot be both enabled."

Expand All @@ -1372,7 +1376,8 @@ type FSharpChecker
(match documentSource with
| Some (DocumentSource.Custom f) -> Some f
| _ -> None),
useChangeNotifications
useChangeNotifications,
useSyntaxTreeCache
)

member _.ReferenceResolver = legacyReferenceResolver
Expand Down
5 changes: 3 additions & 2 deletions src/Compiler/Service/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type public FSharpChecker =
/// <param name="parallelReferenceResolution">Indicates whether to resolve references in parallel.</param>
/// <param name="captureIdentifiersWhenParsing">When set to true we create a set of all identifiers for each parsed file which can be used to speed up finding references.</param>
/// <param name="documentSource">Default: FileSystem. You can use Custom source to provide a function that will return the source for a given file path instead of reading it from the file system. Note that with this option the FSharpChecker will also not monitor the file system for file changes. It will expect to be notified of changes via the NotifyFileChanged method.</param>
/// <param name="useSyntaxTreeCache">Default: true. Indicates whether to keep parsing results in a cache.</param>
static member Create:
?projectCacheSize: int *
?keepAssemblyContents: bool *
Expand All @@ -53,7 +54,8 @@ type public FSharpChecker =
?enablePartialTypeChecking: bool *
?parallelReferenceResolution: bool *
?captureIdentifiersWhenParsing: bool *
[<Experimental "This parameter is experimental and likely to be removed in the future.">] ?documentSource: DocumentSource ->
[<Experimental "This parameter is experimental and likely to be removed in the future.">] ?documentSource: DocumentSource *
[<Experimental "This parameter is experimental and likely to be removed in the future.">] ?useSyntaxTreeCache: bool ->
FSharpChecker

/// <summary>
Expand Down Expand Up @@ -383,7 +385,6 @@ type public FSharpChecker =
member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients: unit -> unit

/// Notify the checker that given file has changed. This needs to be used when checker is created with documentSource = Custom.
/// Although it is not mandatory when the changed file is the next thing requested to be checked.
[<Experimental "This FCS API is experimental and likely to be removed in the future.">]
member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async<unit>

Expand Down
11 changes: 10 additions & 1 deletion src/Compiler/Utilities/Activity.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ open System.Text
[<RequireQualifiedAccess>]
module internal Activity =

let FscSourceName = "fsc"

module Tags =
let fileName = "fileName"
let project = "project"
Expand Down Expand Up @@ -40,7 +42,10 @@ module internal Activity =
outputDllFile
|]

let private activitySourceName = "fsc"
module Events =
let cacheHit = "cacheHit"

let private activitySourceName = FscSourceName
let private profiledSourceName = "fsc_with_env_stats"

type System.Diagnostics.Activity with
Expand Down Expand Up @@ -75,6 +80,10 @@ module internal Activity =

let startNoTags (name: string) : IDisposable = activitySource.StartActivity(name)

let addEvent name =
if Activity.Current <> null && Activity.Current.Source = activitySource then
Activity.Current.AddEvent(ActivityEvent(name)) |> ignore

module Profiling =

module Tags =
Expand Down
7 changes: 7 additions & 0 deletions src/Compiler/Utilities/Activity.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ open System
[<RequireQualifiedAccess>]
module internal Activity =

val FscSourceName: string

module Tags =
val fileName: string
val qualifiedNameOfFile: string
Expand All @@ -17,10 +19,15 @@ module internal Activity =
val length: string
val cache: string

module Events =
val cacheHit: string

val startNoTags: name: string -> IDisposable

val start: name: string -> tags: (string * string) seq -> IDisposable

val addEvent: name: string -> unit

module Profiling =
val startAndMeasureEnvironmentStats: name: string -> IDisposable
val addConsoleListener: unit -> IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

open System
open System.IO
open System.Diagnostics

open Xunit

Expand All @@ -10,6 +11,22 @@ open FSharp.Test.ProjectGeneration.Internal
open FSharp.Compiler.Text
open FSharp.Compiler.CodeAnalysis

module FcsDiagnostics = FSharp.Compiler.Diagnostics.Activity

let expectCacheHits n =
let events = ResizeArray()
let listener =
new ActivityListener(
ShouldListenTo = (fun s -> s.Name = FcsDiagnostics.FscSourceName),
Sample = (fun _ -> ActivitySamplingResult.AllData),
ActivityStopped = (fun a -> events.AddRange a.Events)
)
ActivitySource.AddActivityListener listener
{ new IDisposable with
member this.Dispose() =
listener.Dispose()
Assert.Equal(n, events |> Seq.filter (fun e -> e.Name = FcsDiagnostics.Events.cacheHit) |> Seq.length) }

let makeTestProject () =
SyntheticProject.Create(
sourceFile "First" [],
Expand Down Expand Up @@ -132,3 +149,62 @@ let ``Using getSource and notifications instead of filesystem`` () =
checkFile middle expectSignatureChanged
checkFile last expectSignatureChanged
}

[<Fact>]
let ``Using getSource and notifications instead of filesystem with parse caching`` () =

let size = 20

let project =
{ SyntheticProject.Create() with
SourceFiles = [
sourceFile $"File%03d{0}" []
for i in 1..size do
sourceFile $"File%03d{i}" [$"File%03d{i-1}"]
]
}

let first = "File001"
let middle = $"File%03d{size / 2}"
let last = $"File%03d{size}"

use _ = expectCacheHits 28
ProjectWorkflowBuilder(project, useGetSource = true, useChangeNotifications = true, useSyntaxTreeCache = true) {
updateFile first updatePublicSurface
checkFile first expectSignatureChanged
checkFile last expectSignatureChanged
updateFile middle updatePublicSurface
checkFile last expectSignatureChanged
addFileAbove middle (sourceFile "addedFile" [first])
updateFile middle (addDependency "addedFile")
checkFile middle expectSignatureChanged
checkFile last expectSignatureChanged
}

[<Fact>]
let ``Edit file, check it, then check dependent file with parse caching`` () =
use _ = expectCacheHits 1
ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = true) {
updateFile "First" breakDependentFiles
checkFile "First" expectSignatureChanged
saveFile "First"
checkFile "Second" expectErrors
}

[<Fact>]
let ``Edit file, don't check it, check dependent file with parse caching `` () =
use _ = expectCacheHits 1
ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = true) {
updateFile "First" breakDependentFiles
saveFile "First"
checkFile "Second" expectErrors
}

[<Fact>]
let ``Parse cache not used when not enabled`` () =
use _ = expectCacheHits 0
ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = false) {
updateFile "First" breakDependentFiles
saveFile "First"
checkFile "Second" expectErrors
}
Original file line number Diff line number Diff line change
Expand Up @@ -2031,7 +2031,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols.
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2031,7 +2031,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols.
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
Expand Down
6 changes: 4 additions & 2 deletions tests/FSharp.Test.Utilities/ProjectGeneration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,8 @@ type ProjectWorkflowBuilder
?initialContext,
?checker: FSharpChecker,
?useGetSource,
?useChangeNotifications
?useChangeNotifications,
?useSyntaxTreeCache
) =

let useGetSource = defaultArg useGetSource false
Expand Down Expand Up @@ -533,7 +534,8 @@ type ProjectWorkflowBuilder
enableBackgroundItemKeyStoreAndSemanticClassification = true,
enablePartialTypeChecking = true,
captureIdentifiersWhenParsing = true,
documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem)
documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem),
useSyntaxTreeCache = defaultArg useSyntaxTreeCache false
))

let mapProjectAsync f workflow =
Expand Down
2 changes: 1 addition & 1 deletion vsintegration/src/FSharp.Editor/FSharp.Editor.resx
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</value>
Enable fast find references &amp; rename (experimental);Cache parsing results (experimental)</value>
</data>
<data name="6012" xml:space="preserve">
<value>Advanced</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ type internal FSharpWorkspaceServiceFactory
let enableLiveBuffers =
getOption (fun options -> options.Advanced.IsLiveBuffersEnabled) false

let useSyntaxTreeCache =
getOption (fun options -> options.LanguageServicePerformance.UseSyntaxTreeCache) LanguageServicePerformanceOptions.Default.UseSyntaxTreeCache

let checker =
FSharpChecker.Create(
projectCacheSize = 5000, // We do not care how big the cache is. VS will actually tell FCS to clear caches, so this is fine.
Expand All @@ -133,7 +136,8 @@ type internal FSharpWorkspaceServiceFactory
enablePartialTypeChecking = true,
parallelReferenceResolution = enableParallelReferenceResolution,
captureIdentifiersWhenParsing = true,
documentSource = (if enableLiveBuffers then DocumentSource.Custom getSource else DocumentSource.FileSystem))
documentSource = (if enableLiveBuffers then DocumentSource.Custom getSource else DocumentSource.FileSystem),
useSyntaxTreeCache = useSyntaxTreeCache)

if enableLiveBuffers then
workspace.WorkspaceChanged.Add(fun args ->
Expand Down
Loading