Skip to content

Commit

Permalink
add option to specify the location to store workspace-specific state (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
baronfel authored Apr 8, 2022
1 parent d2cf362 commit 3351be7
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 29 deletions.
10 changes: 5 additions & 5 deletions src/FsAutoComplete.BackgroundServices/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,10 @@ type BackgroundServiceServer(state: State, client: FsacClient) =
return LspResult.success ()
}

member __.InitWorkspace() =
member __.InitWorkspace(workspaceStateDir) =
async {
do! client.Notify {Value = "Init workspace" }
SymbolCache.initCache workspaceStateDir
do! Async.Sleep 100
let knownProjects = state.FileCheckOptions.Values |> Seq.distinctBy (fun o -> o.ProjectFileName)
do! client.Notify {Value = sprintf "Init workspace - starting typechecking on %d projects" (knownProjects |> Seq.length) }
Expand All @@ -498,21 +499,20 @@ module Program =
|> Map.add "background/update" (requestHandling (fun s p -> s.UpdateTextFile(p) ))
|> Map.add "background/project" (requestHandling (fun s p -> s.UpdateProject(p) ))
|> Map.add "background/save" (requestHandling (fun s p -> s.FileSaved(p) ))
|> Map.add "background/init" (requestHandling (fun s p -> s.InitWorkspace() ))
|> Map.add "background/init" (requestHandling (fun s p -> s.InitWorkspace p))

Ionide.LanguageServerProtocol.Server.start requestsHandlings input output FsacClient (fun lspClient -> new BackgroundServiceServer(state, lspClient))

open FSharp.Compiler.IO



[<EntryPoint>]
let main argv =

let pid = Int32.Parse argv.[0]
let pid= Int32.Parse argv[0]
let originalFs = FileSystemAutoOpens.FileSystem
let fs = FsAutoComplete.FileSystem(originalFs, state.Files.TryFind) :> IFileSystem
FileSystemAutoOpens.FileSystem <- fs
ProcessWatcher.zombieCheckWithHostPID (fun () -> exit 0) pid
SymbolCache.initCache (Environment.CurrentDirectory)
let _ = startCore()
0
16 changes: 8 additions & 8 deletions src/FsAutoComplete.Core/BackgroundServices.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ type BackgroundService =
abstract UpdateFile : BackgroundFileCheckType * string * int -> unit
abstract UpdateProject : string * FSharpProjectOptions -> unit
abstract SaveFile : BackgroundFileCheckType -> unit
abstract InitWorkspace : unit -> unit
abstract InitWorkspace : workspaceStateDir: string -> unit
abstract MessageReceived : IEvent<MessageType>
abstract Start : workspaceDir: string -> unit
abstract Start : unit -> unit
abstract GetSymbols: string -> Async<option<SymbolCache.SymbolUseRange array>>
abstract GetImplementation: string -> Async<option<SymbolCache.SymbolUseRange array>>

Expand Down Expand Up @@ -99,9 +99,8 @@ type ActualBackgroundService() =
)

interface BackgroundService with
member x.Start (workspaceDir) =
member x.Start () =
logger.info (Log.setMessage "Starting background service")
SymbolCache.initCache workspaceDir
client.Start()

member x.UpdateFile(file, content, version) =
Expand All @@ -123,8 +122,9 @@ type ActualBackgroundService() =
let msg : FileParms = { File = file }
client.SendNotification "background/save" msg

member x.InitWorkspace () =
client.SendNotification "background/init" {Ready = true}
member x.InitWorkspace (workspaceStateDir) =
SymbolCache.initCache workspaceStateDir
client.SendNotification "background/init" workspaceStateDir

member x.MessageReceived = messageRecieved.Publish

Expand All @@ -138,15 +138,15 @@ type MockBackgroundService() =
let m = Event<_>()

interface BackgroundService with
member x.Start _ = ()
member x.Start () = ()

member x.UpdateFile(file, content, version) = ()

member x.UpdateProject(file, opts) = ()

member x.SaveFile(file) = ()

member x.InitWorkspace () = ()
member x.InitWorkspace workspaceStateDir = ()

member x.MessageReceived = m.Publish

Expand Down
2 changes: 1 addition & 1 deletion src/FsAutoComplete.Core/Commands.fs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ type Commands
commandsLogger.info (
Log.setMessage "Workspace ready - sending init request to background service"
)
backgroundService.InitWorkspace())
backgroundService.InitWorkspace(state.WorkspaceStateDirectory.FullName))


member __.Notify = notify.Publish
Expand Down
7 changes: 5 additions & 2 deletions src/FsAutoComplete.Core/State.fs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ type State =
ScriptProjectOptions: ConcurrentDictionary<string<LocalPath>, int * FSharpProjectOptions>

mutable ColorizationOutput: bool

WorkspaceStateDirectory: System.IO.DirectoryInfo
}
member x.DebugString = $"{x.Files.Count} Files, {x.ProjectController.ProjectOptions |> Seq.length} Projects"

static member Initial toolsPath workspaceLoaderFactory =
static member Initial toolsPath workspaceStateDir workspaceLoaderFactory =
{ Files = ConcurrentDictionary()
LastCheckedVersion = ConcurrentDictionary()
ProjectController = new ProjectController(toolsPath, workspaceLoaderFactory)
Expand All @@ -47,7 +49,8 @@ type State =
CancellationTokens = ConcurrentDictionary()
NavigationDeclarations = ConcurrentDictionary()
ScriptProjectOptions = ConcurrentDictionary()
ColorizationOutput = false }
ColorizationOutput = false
WorkspaceStateDirectory = workspaceStateDir }

member x.RefreshCheckerOptions(file: string<LocalPath>, text: NamedText) : FSharpProjectOptions option =
x.ProjectController.GetProjectOptions (UMX.untag file)
Expand Down
10 changes: 5 additions & 5 deletions src/FsAutoComplete/FsAutoComplete.Lsp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ type FSharpLspServer(backgroundServiceEnabled: bool, state: State, lspClient: FS

rootPath <- actualRootPath
commands.SetWorkspaceRoot actualRootPath
rootPath |> Option.iter backgroundService.Start
backgroundService.Start()

let c =
p.InitializationOptions
Expand Down Expand Up @@ -2722,7 +2722,7 @@ type FSharpLspServer(backgroundServiceEnabled: bool, state: State, lspClient: FS

override x.Dispose() = x.Shutdown() |> Async.Start

let startCore backgroundServiceEnabled toolsPath workspaceLoaderFactory =
let startCore backgroundServiceEnabled toolsPath stateStorageDir workspaceLoaderFactory =
use input = Console.OpenStandardInput()
use output = Console.OpenStandardOutput()

Expand Down Expand Up @@ -2758,7 +2758,7 @@ let startCore backgroundServiceEnabled toolsPath workspaceLoaderFactory =
|> Map.add "fsharp/inlayHints" (requestHandling (fun s p -> s.FSharpInlayHints(p)))

let state =
State.Initial toolsPath workspaceLoaderFactory
State.Initial toolsPath stateStorageDir workspaceLoaderFactory

let originalFs =
FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem
Expand All @@ -2768,12 +2768,12 @@ let startCore backgroundServiceEnabled toolsPath workspaceLoaderFactory =
Ionide.LanguageServerProtocol.Server.start requestsHandlings input output FSharpLspClient (fun lspClient ->
new FSharpLspServer(backgroundServiceEnabled, state, lspClient))

let start backgroundServiceEnabled toolsPath workspaceLoaderFactory =
let start backgroundServiceEnabled toolsPath stateStorageDir workspaceLoaderFactory =
let logger = LogProvider.getLoggerByName "Startup"

try
let result =
startCore backgroundServiceEnabled toolsPath workspaceLoaderFactory
startCore backgroundServiceEnabled toolsPath stateStorageDir workspaceLoaderFactory

logger.info (
Log.setMessage "Start - Ending LSP mode with {reason}"
Expand Down
14 changes: 10 additions & 4 deletions src/FsAutoComplete/Parser.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace FsAutoComplete

open System
open System.IO
open Serilog
open Serilog.Core
open Serilog.Events
Expand Down Expand Up @@ -66,7 +67,7 @@ module Parser =

let waitForDebuggerOption =
Option<bool>(
"--wait-for-debugger",
[|"--wait-for-debugger"; "--attachdebugger"|],
"Stop execution on startup until an external debugger to attach to this process"
)
|> zero
Expand All @@ -85,6 +86,9 @@ module Parser =
)
|> zero

let stateLocationOption =
Option<DirectoryInfo>("--state-directory", getDefaultValue = Func<_> (fun () -> DirectoryInfo("C:\\Users\\chusk")), description = "Set the directory to store the state of the server. This should be a per-workspace location, not a shared-workspace location.")

let rootCommand =
let rootCommand = RootCommand("An F# LSP server implementation")

Expand All @@ -96,18 +100,20 @@ module Parser =
rootCommand.AddOption backgroundServiceOption
rootCommand.AddOption projectGraphOption
rootCommand.AddOption logLevelOption
rootCommand.AddOption stateLocationOption

rootCommand.SetHandler(
Func<_,_,Task>(fun backgroundServiceEnabled projectGraphEnabled ->
Func<_,_,_,Task>(fun backgroundServiceEnabled projectGraphEnabled stateDirectory ->
let workspaceLoaderFactory =
if projectGraphEnabled then Ionide.ProjInfo.WorkspaceLoaderViaProjectGraph.Create
else Ionide.ProjInfo.WorkspaceLoader.Create

let toolsPath = Ionide.ProjInfo.Init.init (IO.DirectoryInfo Environment.CurrentDirectory) None
use _compilerEventListener = new Debug.FSharpCompilerEventLogger.Listener()
let result = Lsp.start backgroundServiceEnabled toolsPath workspaceLoaderFactory
let result = Lsp.start backgroundServiceEnabled toolsPath stateDirectory workspaceLoaderFactory

Task.FromResult result
), backgroundServiceOption, projectGraphOption)
), backgroundServiceOption, projectGraphOption, stateLocationOption)
rootCommand

let waitForDebugger =
Expand Down
1 change: 1 addition & 0 deletions test/FsAutoComplete.Tests.Lsp/CoreTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ let initTests state =
testCaseAsync
"InitTest"
(async {
let tempDir = Path.Combine(Path.GetTempPath(), "FsAutoComplete.Tests", Guid.NewGuid().ToString())
let (server, event) = createServer state

let p: InitializeParams =
Expand Down
9 changes: 5 additions & 4 deletions test/FsAutoComplete.Tests.Lsp/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ open FsAutoComplete.Tests.InteractiveDirectivesTests
open Ionide.ProjInfo
open System.Threading
open Serilog.Filters
open System.IO

let testTimeout =
Environment.GetEnvironmentVariable "TEST_TIMEOUT_MINUTES"
Expand Down Expand Up @@ -41,10 +42,10 @@ let lspTests =
[ for (name, workspaceLoaderFactory) in loaders do
testList
name
[
Templates.tests ()
[ Templates.tests ()
let testRunDir = Path.Combine(Path.GetTempPath(), "FsAutoComplete.Tests", Guid.NewGuid().ToString()) |> DirectoryInfo
let state () =
FsAutoComplete.State.Initial toolsPath workspaceLoaderFactory
FsAutoComplete.State.Initial toolsPath testRunDir workspaceLoaderFactory

initTests state

Expand Down Expand Up @@ -82,7 +83,7 @@ let lspTests =
InfoPanelTests.docFormattingTest state
DetectUnitTests.tests state
XmlDocumentationGeneration.tests state
InlayHintTests.tests state
InlayHintTests.tests state
]
]

Expand Down

0 comments on commit 3351be7

Please sign in to comment.