Skip to content

Commit

Permalink
plumb down tfm for scripts to the background checker as well
Browse files Browse the repository at this point in the history
  • Loading branch information
baronfel authored and Krzysztof-Cieslak committed Oct 6, 2019
1 parent b5d4425 commit 72a19d2
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 66 deletions.
120 changes: 78 additions & 42 deletions src/FsAutoComplete.BackgroundServices/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,18 @@ open FSharp.Compiler.SourceCodeServices
open System.Collections.Concurrent
open FsAutoComplete

type BackgroundFileCheckType =
| SourceFile of filePath: string
| ScriptFile of filePath: string * tfm: FSIRefs.TFM
with
member x.FilePath =
match x with
| SourceFile(path)
| ScriptFile(path, _) -> path


type UpdateFileParms = {
File: string
File: BackgroundFileCheckType
Content: string
Version: int
}
Expand All @@ -24,15 +34,16 @@ type ProjectParms = {
}

type FileParms = {
File: string
File: BackgroundFileCheckType
}

type Msg = {Value: string}

type State ={
type State = {
Files : ConcurrentDictionary<SourceFilePath, VolatileFile>
FileCheckOptions : ConcurrentDictionary<SourceFilePath, FSharpProjectOptions>
}

with
static member Initial =
{ Files = ConcurrentDictionary(); FileCheckOptions = ConcurrentDictionary() }
Expand Down Expand Up @@ -87,7 +98,7 @@ type FsacClient(sendServerRequest: ClientNotificationSender) =
member __.SendDiagnostics(p: PublishDiagnosticsParams) =
sendServerRequest "background/diagnostics" (box p) |> Async.Ignore

member __.Notifiy(o: Msg) =
member __.Notify(o: Msg) =
sendServerRequest "background/notify" o |> Async.Ignore

type BackgroundServiceServer(state: State, client: FsacClient) =
Expand All @@ -104,44 +115,67 @@ type BackgroundServiceServer(state: State, client: FsacClient) =
else
opts.SourceFiles

let getListOfFilesForProjectChecking file =
match state.FileCheckOptions.TryFind file with
| None ->
if file.EndsWith ".fsx" then
state.Files.TryFind file |> Option.map (fun st ->
async {
let! (opts, _errors) = checker.GetProjectOptionsFromScript(file, SourceText.ofString (st.Lines |> String.concat "\n"), assumeDotNetFramework = true, useSdkRefs = false)
let sf = getFilesFromOpts opts

return
sf
|> Array.skipWhile (fun n -> (Utils.normalizePath n) <> (Utils.normalizePath file))
|> Array.map (fun n -> (Utils.normalizePath n))
|> Array.toList
}
)
else
None
| Some opts ->
let sf = getFilesFromOpts opts
let getListOfFilesForProjectChecking (file: BackgroundFileCheckType) =
let replaceRefs (projOptions: FSharpProjectOptions) =
let okOtherOpts = projOptions.OtherOptions |> Array.filter (fun r -> not <| r.StartsWith("-r"))
let assemblyPaths =
match Environment.latest3xSdkVersion.Value, Environment.latest3xRuntimeVersion.Value with
| None, _
| _, None ->
[]
| Some sdkVersion, Some runtimeVersion ->
FSIRefs.netCoreRefs Environment.dotnetSDKRoot.Value (string sdkVersion) (string runtimeVersion) Environment.fsiTFMMoniker true
let refs = assemblyPaths |> List.map (fun r -> "-r:" + r)
let finalOpts = Array.append okOtherOpts (Array.ofList refs)
{ projOptions with OtherOptions = finalOpts }

let getScriptOptions file lines tfm =
match tfm with
| FSIRefs.NetFx ->
checker.GetProjectOptionsFromScript(file, SourceText.ofString lines, assumeDotNetFramework = true, useSdkRefs = false, useFsiAuxLib = true)
| FSIRefs.NetCore ->
async {
let! (opts, errors) = checker.GetProjectOptionsFromScript(file, SourceText.ofString lines, assumeDotNetFramework = false, useSdkRefs = true, useFsiAuxLib = true)
return replaceRefs opts, errors
}

sf
|> Array.skipWhile (fun n -> (Utils.normalizePath n) <> (Utils.normalizePath file))
|> Array.map (fun n -> (Utils.normalizePath n))
|> Array.toList
|> async.Return
|> Some
match file with
| ScriptFile(file, tfm) ->
state.Files.TryFind file |> Option.map (fun st ->
async {
let! (opts, _errors) = getScriptOptions file (st.Lines |> String.concat "\n") tfm
let sf = getFilesFromOpts opts

return
sf
|> Array.skipWhile (fun n -> (Utils.normalizePath n) <> (Utils.normalizePath file))
|> Array.map (fun n -> (Utils.normalizePath n))
|> Array.toList
}
)
| SourceFile file ->
match state.FileCheckOptions.TryFind file with
| None -> None
| Some opts ->
let sf = getFilesFromOpts opts

sf
|> Array.skipWhile (fun n -> (Utils.normalizePath n) <> (Utils.normalizePath file))
|> Array.map (fun n -> (Utils.normalizePath n))
|> Array.toList
|> async.Return
|> Some

let typecheckFile ignoredFile file =
async {
do! client.Notifiy {Value = sprintf "Typechecking %s" file }
do! client.Notify {Value = sprintf "Typechecking %s" file }
match state.Files.TryFind file, state.FileCheckOptions.TryFind file with
| Some vf, Some opts ->
let txt = vf.Lines |> String.concat "\n"
let! pr, cr = checker.ParseAndCheckFileInProject(file, defaultArg vf.Version 0, SourceText.ofString txt, opts)
match cr with
| FSharpCheckFileAnswer.Aborted ->
do! client.Notifiy {Value = sprintf "Typechecking aborted %s" file }
do! client.Notify {Value = sprintf "Typechecking aborted %s" file }
return ()
| FSharpCheckFileAnswer.Succeeded res ->
async {
Expand All @@ -162,7 +196,7 @@ type BackgroundServiceServer(state: State, client: FsacClient) =
let! pr, cr = checker.ParseAndCheckFileInProject(file, defaultArg vf.Version 0, SourceText.ofString txt, opts)
match cr with
| FSharpCheckFileAnswer.Aborted ->
do! client.Notifiy {Value = sprintf "Typechecking aborted %s" file }
do! client.Notify {Value = sprintf "Typechecking aborted %s" file }
return ()
| FSharpCheckFileAnswer.Succeeded res ->
async {
Expand All @@ -178,7 +212,7 @@ type BackgroundServiceServer(state: State, client: FsacClient) =
do! client.SendDiagnostics msg
return ()
| _ ->
do! client.Notifiy {Value = sprintf "Couldn't find state %s" file }
do! client.Notify {Value = sprintf "Couldn't find state %s" file }
return ()
}

Expand Down Expand Up @@ -260,12 +294,13 @@ type BackgroundServiceServer(state: State, client: FsacClient) =

member __.UpdateTextFile(p: UpdateFileParms) =
async {
do! client.Notifiy {Value = sprintf "File update %s" p.File }
let file = Utils.normalizePath p.File
do! client.Notify {Value = sprintf "File update %s" p.File.FilePath }
let file = Utils.normalizePath p.File.FilePath

let vf = {Lines = p.Content.Split( [|'\n' |] ); Touched = DateTime.Now; Version = Some p.Version }
state.Files.AddOrUpdate(file, (fun _ -> vf),( fun _ _ -> vf) ) |> ignore
let! filesToCheck = defaultArg (getListOfFilesForProjectChecking file) (async.Return [])
do! client.Notifiy {Value = sprintf "Files to check %A" filesToCheck }
let! filesToCheck = defaultArg (getListOfFilesForProjectChecking p.File) (async.Return [])
do! client.Notify { Value = sprintf "Files to check %A" filesToCheck }
bouncer.Bounce (false, file,filesToCheck)
return LspResult.success ()
}
Expand All @@ -282,18 +317,19 @@ type BackgroundServiceServer(state: State, client: FsacClient) =
state.FileCheckOptions.AddOrUpdate(file, (fun _ -> p.Options), (fun _ _ -> p.Options))
|> ignore
)
do! client.Notifiy {Value = sprintf "Project Updated %s" p.Options.ProjectFileName}
do! client.Notify {Value = sprintf "Project Updated %s" p.Options.ProjectFileName}
return LspResult.success ()
}

member __.FileSaved(p: FileParms) =
async {
let file = Utils.normalizePath p.File

do! client.Notifiy {Value = sprintf "File Saved %s " file }
let file = Utils.normalizePath p.File.FilePath

do! client.Notify {Value = sprintf "File Saved %s " file }

let projects = getDependingProjects file
let! filesToCheck = defaultArg (getListOfFilesForProjectChecking file) (async.Return [])
let! filesToCheck = defaultArg (getListOfFilesForProjectChecking p.File) (async.Return [])
let filesToCheck =
[
yield! filesToCheck
Expand Down
20 changes: 15 additions & 5 deletions src/FsAutoComplete.Core/BackgroundServices.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,18 @@ open FSharp.Compiler.SourceCodeServices

type Msg = {Value: string}

type BackgroundFileCheckType =
| SourceFile of filePath: string
| ScriptFile of filePath: string * tfm: FSIRefs.TFM
with
member x.FilePath =
match x with
| SourceFile(path)
| ScriptFile(path, _) -> path


type UpdateFileParms = {
File: string
File: BackgroundFileCheckType
Content: string
Version: int
}
Expand All @@ -19,7 +29,7 @@ type ProjectParms = {
}

type FileParms = {
File: string
File: BackgroundFileCheckType
}

let p =
Expand Down Expand Up @@ -60,13 +70,13 @@ let start () =
client.Start ()

let updateFile(file, content, version) =
let msg = {File = file; Content = content; Version = version}
let msg: UpdateFileParms = { File = file; Content = content; Version = version }
client.SendRequest "background/update" msg

let updateProject(file, opts) =
let msg = {File = file; Options = opts}
let msg = { File = file; Options = opts }
client.SendRequest "background/project" msg

let saveFile(file) =
let msg = {File = file}
let msg: FileParms = { File = file }
client.SendRequest "background/save" msg
31 changes: 20 additions & 11 deletions src/FsAutoComplete.Core/Commands.fs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
OtherOptions = opts.OtherOptions |> Array.map (fun n -> if FscArguments.isCompileFile(n) then Path.GetFullPath n else n)
}

let parseFilesInTheBackground files =
let parseFilesInTheBackground fsiScriptTFM files =
async {
files
|> List.toArray
Expand All @@ -178,8 +178,12 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
| Some f -> Some (f.Lines)
| None when File.Exists(file) ->
let ctn = File.ReadAllLines file
state.Files.[file] <- {Touched = DateTime.Now; Lines = ctn; Version = None }
if backgroundServiceEnabled then BackgroundServices.updateFile(file, ctn |> String.concat "\n", 0)
state.Files.[file] <- { Touched = DateTime.Now; Lines = ctn; Version = None }
let payload =
if Utils.isAScript file
then BackgroundServices.ScriptFile(file, fsiScriptTFM)
else BackgroundServices.SourceFile file
if backgroundServiceEnabled then BackgroundServices.updateFile(payload, ctn |> String.concat "\n", 0)
Some (ctn)
| None -> None
match sourceOpt with
Expand Down Expand Up @@ -225,13 +229,13 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
if insert.IsSome then state.CompletionNamespaceInsert.[n] <- insert.Value
} |> Async.Start

let onProjectLoaded projectFileName (response: ProjectCrackerCache) =
let onProjectLoaded projectFileName (response: ProjectCrackerCache) tfmForScripts =
for file in response.Items |> List.choose (function Dotnet.ProjInfo.Workspace.ProjectViewerItem.Compile(p, _) -> Some p) do
state.FileCheckOptions.[file] <- normalizeOptions response.Options

response.Items
|> List.choose (function Dotnet.ProjInfo.Workspace.ProjectViewerItem.Compile(p, _) -> Some p)
|> parseFilesInTheBackground
|> parseFilesInTheBackground tfmForScripts
|> Async.Start

let workspaceBinder () =
Expand All @@ -256,9 +260,14 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
member __.LastCheckResult
with get() = lastCheckResult

member __.SetFileContent(file: SourceFilePath, lines: LineStr[], version) =
member __.SetFileContent(file: SourceFilePath, lines: LineStr[], version, tfmIfScript) =
state.AddFileText(file, lines, version)
if backgroundServiceEnabled then BackgroundServices.updateFile(file, lines |> String.concat "\n", defaultArg version 0)
let payload =
if Utils.isAScript file
then BackgroundServices.ScriptFile(file, tfmIfScript)
else BackgroundServices.SourceFile file

if backgroundServiceEnabled then BackgroundServices.updateFile(payload, lines |> String.concat "\n", defaultArg version 0)

member private x.MapResultAsync (successToString: 'a -> Async<CoreResponse>, ?failureToString: string -> CoreResponse) =
Async.bind <| function
Expand Down Expand Up @@ -431,7 +440,7 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =

(opts.ProjectFileName, cached)

member x.Project projectFileName _verbose onChange = async {
member x.Project projectFileName _verbose onChange tfmForScripts = async {
let projectFileName = Path.GetFullPath projectFileName
let project =
match state.Projects.TryFind projectFileName with
Expand Down Expand Up @@ -463,7 +472,7 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
return
match projResponse with
| Result.Ok (projectFileName, response) ->
onProjectLoaded projectFileName response
onProjectLoaded projectFileName response tfmForScripts
let responseFiles =
response.Items
|> List.choose (function Dotnet.ProjInfo.Workspace.ProjectViewerItem.Compile(p, _) -> Some p)
Expand Down Expand Up @@ -898,7 +907,7 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
return [CoreResponse.WorkspacePeek d]
}

member x.WorkspaceLoad onChange (files: string list) (disableInMemoryProjectReferences: bool) = async {
member x.WorkspaceLoad onChange (files: string list) (disableInMemoryProjectReferences: bool) tfmForScripts = async {
checker.DisableInMemoryProjectReferences <- disableInMemoryProjectReferences
//TODO check full path
let projectFileNames = files |> List.map Path.GetFullPath
Expand Down Expand Up @@ -932,7 +941,7 @@ type Commands (serialize : Serializer, backgroundServiceEnabled) =
| WorkspaceProjectState.Loaded (opts, extraInfo, projectFiles, logMap) ->
let projectFileName, response = x.ToProjectCache(opts, extraInfo, projectFiles, logMap)
if backgroundServiceEnabled then BackgroundServices.updateProject(projectFileName, opts)
projectLoadedSuccessfully projectFileName response
projectLoadedSuccessfully projectFileName response tfmForScripts

let responseFiles =
response.Items
Expand Down
12 changes: 6 additions & 6 deletions src/FsAutoComplete/FsAutoComplete.Lsp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,15 @@ type FsharpLspServer(commands: Commands, lspClient: FSharpLspClient) =
match peeks with
| [] -> ()
| [CommandResponse.WorkspacePeekFound.Directory projs] ->
commands.WorkspaceLoad ignore projs.Fsprojs false
commands.WorkspaceLoad ignore projs.Fsprojs false config.ScriptTFM
|> Async.Ignore
|> Async.Start
| CommandResponse.WorkspacePeekFound.Solution sln::_ ->
let projs =
sln.Items
|> List.collect Workspace.foldFsproj
|> List.map fst
commands.WorkspaceLoad ignore projs false
commands.WorkspaceLoad ignore projs false config.ScriptTFM
|> Async.Ignore
|> Async.Start
| _ ->
Expand Down Expand Up @@ -385,7 +385,7 @@ type FsharpLspServer(commands: Commands, lspClient: FSharpLspClient) =
let content = doc.Text.Split('\n')
let tfmConfig = config.UseSdkScripts

commands.SetFileContent(filePath, content, Some doc.Version)
commands.SetFileContent(filePath, content, Some doc.Version, config.ScriptTFM)


if not commands.IsWorkspaceReady then
Expand All @@ -409,7 +409,7 @@ type FsharpLspServer(commands: Commands, lspClient: FSharpLspClient) =
| Some contentChange, Some version ->
if contentChange.Range.IsNone && contentChange.RangeLength.IsNone then
let content = contentChange.Text.Split('\n')
commands.SetFileContent(filePath, content, Some version)
commands.SetFileContent(filePath, content, Some version, config.ScriptTFM)
else ()
| _ -> ()

Expand Down Expand Up @@ -1586,7 +1586,7 @@ type FsharpLspServer(commands: Commands, lspClient: FSharpLspClient) =
member __.FSharpWorkspaceLoad(p) = async {
Debug.print "[LSP call] FSharpWorkspaceLoad"
let fns = p.TextDocuments |> Array.map (fun fn -> fn.GetFilePath() ) |> Array.toList
let! res = commands.WorkspaceLoad ignore fns config.DisableInMemoryProjectReferences
let! res = commands.WorkspaceLoad ignore fns config.DisableInMemoryProjectReferences config.ScriptTFM
let res =
match res.[0] with
| CoreResponse.InfoRes msg | CoreResponse.ErrorRes msg ->
Expand Down Expand Up @@ -1619,7 +1619,7 @@ type FsharpLspServer(commands: Commands, lspClient: FSharpLspClient) =
member __.FSharpProject(p) = async {
Debug.print "[LSP call] FSharpProject"
let fn = p.Project.GetFilePath()
let! res = commands.Project fn false ignore
let! res = commands.Project fn false ignore config.ScriptTFM
let res =
match res.[0] with
| CoreResponse.InfoRes msg | CoreResponse.ErrorRes msg ->
Expand Down
Loading

0 comments on commit 72a19d2

Please sign in to comment.