Skip to content

Commit

Permalink
EXPERIMENT: Use FSharp.Data.Adaptive (#1007)
Browse files Browse the repository at this point in the history
Creates a new LSP server based on FSharp.Data.Adaptive, and factors out the core logic of LSP request processing to allow LSP server implementations to be chosen at process start.
  • Loading branch information
TheAngryByrd authored Oct 9, 2022
1 parent cfdee68 commit 4dea78f
Show file tree
Hide file tree
Showing 33 changed files with 8,718 additions and 4,215 deletions.
10 changes: 5 additions & 5 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ github TheAngryByrd/FsLibLog:f81cba440bf0476bb4e2262b57a067a0d6ab78a7 src/FsLibL

nuget Fantomas.Client
nuget FSharp.Compiler.Service
nuget Ionide.ProjInfo
nuget Ionide.ProjInfo.FCS
nuget Ionide.ProjInfo.ProjectSystem
nuget Ionide.ProjInfo.Sln
nuget Ionide.ProjInfo 0.60.2
nuget Ionide.ProjInfo.FCS 0.60.2
nuget Ionide.ProjInfo.ProjectSystem 0.60.2
nuget Ionide.ProjInfo.Sln 0.60.2
nuget Microsoft.Build copy_local:false
nuget Microsoft.Build.Framework copy_local:false
nuget Microsoft.Build.Utilities.Core copy_local:false
Expand All @@ -38,7 +38,7 @@ nuget FsToolkit.ErrorHandling
nuget FSharpx.Async
nuget CliWrap
nuget System.CommandLine prerelease

nuget FSharp.Data.Adaptive
nuget Microsoft.NET.Test.Sdk
nuget Dotnet.ReproducibleBuilds copy_local:true

Expand Down
27 changes: 15 additions & 12 deletions paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ NUGET
FSharp.Core (>= 4.7.2)
System.Reactive (>= 5.0 < 6.0)
FSharp.Core (6.0.5) - content: none
FSharp.Data.Adaptive (1.2.13)
FSharp.Core (>= 4.7)
System.Reflection.Emit.Lightweight (>= 4.6)
FSharp.Formatting (14.0.1)
FSharp.Compiler.Service (>= 40.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1))
FSharp.UMX (1.1)
Expand Down Expand Up @@ -101,25 +104,25 @@ NUGET
FSharp.Core (>= 6.0)
Newtonsoft.Json (>= 13.0.1)
StreamJsonRpc (>= 2.10.44)
Ionide.ProjInfo (0.60)
Ionide.ProjInfo (0.60.2)
FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.Sln (>= 0.60) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.Sln (>= 0.60.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Microsoft.Build (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
SemanticVersioning (>= 2.0.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.FCS (0.60)
Ionide.ProjInfo.FCS (0.60.2)
FSharp.Compiler.Service (>= 41.0.5 < 42.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo (>= 0.60) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.ProjectSystem (0.60)
Ionide.ProjInfo (>= 0.60.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.ProjectSystem (0.60.2)
FSharp.Compiler.Service (>= 41.0.5 < 42.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
FSharp.Control.Reactive (>= 5.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo (>= 0.60) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.FCS (>= 0.60) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.Sln (>= 0.60) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo (>= 0.60.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.FCS (>= 0.60.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.Sln (>= 0.60.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0))
Ionide.ProjInfo.Sln (0.60)
Ionide.ProjInfo.Sln (0.60.2)
McMaster.NETCore.Plugins (1.4) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0))
Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp2.1))
Microsoft.Extensions.DependencyModel (>= 5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp2.1))
Expand Down Expand Up @@ -179,9 +182,9 @@ NUGET
System.Runtime.CompilerServices.Unsafe (>= 6.0)
System.Text.Encodings.Web (>= 6.0)
System.Text.Json (>= 6.0)
Microsoft.NET.StringTools (1.0) - copy_local: false
System.Memory (>= 4.5.4)
System.Runtime.CompilerServices.Unsafe (>= 5.0)
Microsoft.NET.StringTools (17.3.1) - copy_local: false
System.Memory (>= 4.5.5)
System.Runtime.CompilerServices.Unsafe (>= 6.0)
Microsoft.NET.Test.Sdk (17.3)
Microsoft.CodeCoverage (>= 17.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net45)) (&& (== netstandard2.0) (>= netcoreapp1.0))
Microsoft.TestPlatform.TestHost (>= 17.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp1.0))
Expand Down
12 changes: 9 additions & 3 deletions src/FsAutoComplete.Core/AbstractClassStubGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ open FSharp.Compiler.Text
open FSharp.Compiler.Syntax
open FSharp.Compiler.Symbols
open FSharp.Compiler.Tokenization
open FsAutoComplete.Logging


type AbstractClassData =
| ObjExpr of baseTy: SynType * bindings: SynBinding list * overallRange: Range
Expand Down Expand Up @@ -78,7 +80,11 @@ let private tryFindAbstractClassExprInParsedInput

/// Walk the parse tree for the given document and look for the definition of any abstract classes in use at the given pos.
/// This looks for implementations of abstract types in object expressions, as well as inheriting of abstract types inside class type declarations.
let tryFindAbstractClassExprInBufferAtPos (codeGenService: CodeGenerationService) (pos: Position) (document: Document) =
let tryFindAbstractClassExprInBufferAtPos
(codeGenService: ICodeGenerationService)
(pos: Position)
(document: Document)
=
asyncMaybe {
let! parseResults = codeGenService.ParseFileInProject(document.FullName)
return! tryFindAbstractClassExprInParsedInput pos parseResults.ParseTree
Expand Down Expand Up @@ -108,7 +114,7 @@ let getMemberNameAndRanges (abstractClassData) =

/// Try to find the start column, so we know what the base indentation should be
let inferStartColumn
(codeGenServer: CodeGenerationService)
(codeGenServer: ICodeGenerationService)
(pos: Position)
(doc: Document)
(lines: ISourceText)
Expand Down Expand Up @@ -141,7 +147,7 @@ let inferStartColumn
/// If the destination type isn't an abstract class, or if there are no missing members to implement,
/// nothing is written. Otherwise, a list of missing members is generated and written
let writeAbstractClassStub
(codeGenServer: CodeGenerationService)
(codeGenServer: ICodeGenerationService)
(checkResultForFile: ParseAndCheckResults)
(doc: Document)
(lines: ISourceText)
Expand Down
95 changes: 53 additions & 42 deletions src/FsAutoComplete.Core/CodeGeneration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,69 @@ open FSharp.Compiler.Symbols
open FSharp.Compiler.Tokenization
open FSharp.Compiler.CodeAnalysis
open FsToolkit.ErrorHandling
open FSharp.UMX

[<Measure>]
type Line0

[<Measure>]
type Line1

type ICodeGenerationService =
abstract TokenizeLine: string<LocalPath> * int -> option<list<FSharpTokenInfo>>
abstract GetSymbolAtPosition: string<LocalPath> * Position -> option<LexerSymbol>

abstract GetSymbolAndUseAtPositionOfKind:
string<LocalPath> * Position * SymbolKind -> Async<option<LexerSymbol * option<FSharpSymbolUse>>>

abstract ParseFileInProject: string<LocalPath> -> option<FSharpParseFileResults>

type CodeGenerationService(checker: FSharpCompilerServiceChecker, state: State) =
member x.TokenizeLine(fileName, i) =
option {
let! text = state.TryGetFileSource fileName |> Option.ofResult

try
let! line = text.GetLine(Position.mkPos i 0)
return Lexer.tokenizeLine [||] line
with _ ->
return! None
}
interface ICodeGenerationService with
override x.TokenizeLine(fileName, i) =
option {
let! text = state.TryGetFileSource fileName |> Option.ofResult

try
let! line = text.GetLine(Position.mkPos i 0)
return Lexer.tokenizeLine [||] line
with _ ->
return! None
}

member x.GetSymbolAtPosition(fileName, pos: Position) =
match state.TryGetFileCheckerOptionsWithLinesAndLineStr(fileName, pos) with
| ResultOrString.Error _ -> None
| ResultOrString.Ok (opts, lines, line) ->
try
Lexer.getSymbol pos.Line pos.Column line SymbolLookupKind.Fuzzy [||]
with _ ->
None
override x.GetSymbolAtPosition(fileName, pos: Position) =
match state.TryGetFileCheckerOptionsWithLinesAndLineStr(fileName, pos) with
| ResultOrString.Error _ -> None
| ResultOrString.Ok (opts, lines, line) ->
try
Lexer.getSymbol pos.Line pos.Column line SymbolLookupKind.Fuzzy [||]
with _ ->
None

member x.GetSymbolAndUseAtPositionOfKind(fileName, pos: Position, kind) =
asyncMaybe {
let! symbol = x.GetSymbolAtPosition(fileName, pos)

if symbol.Kind = kind then
match state.TryGetFileCheckerOptionsWithLinesAndLineStr(fileName, pos) with
| ResultOrString.Error _ -> return! None
| ResultOrString.Ok (opts, text, line) ->
let! result = checker.TryGetRecentCheckResultsForFile(fileName, opts, text)
let symbolUse = result.TryGetSymbolUse pos line
return! Some(symbol, symbolUse)
else
return! None
}
override x.GetSymbolAndUseAtPositionOfKind(fileName, pos: Position, kind) =
asyncMaybe {
let! symbol = (x :> ICodeGenerationService).GetSymbolAtPosition(fileName, pos)

if symbol.Kind = kind then
match state.TryGetFileCheckerOptionsWithLinesAndLineStr(fileName, pos) with
| ResultOrString.Error _ -> return! None
| ResultOrString.Ok (opts, text, line) ->
let! result = checker.TryGetRecentCheckResultsForFile(fileName, opts, text)
let symbolUse = result.TryGetSymbolUse pos line
return! Some(symbol, symbolUse)
else
return! None
}

member x.ParseFileInProject(fileName) =
match state.TryGetFileCheckerOptionsWithLines fileName with
| ResultOrString.Error _ -> None
| ResultOrString.Ok (opts, text) ->
try
checker.TryGetRecentCheckResultsForFile(fileName, opts, text)
|> Option.map (fun n -> n.GetParseResults)
with _ ->
None
override x.ParseFileInProject(fileName) =
match state.TryGetFileCheckerOptionsWithLines fileName with
| ResultOrString.Error _ -> None
| ResultOrString.Ok (opts, text) ->
try
checker.TryGetRecentCheckResultsForFile(fileName, opts, text)
|> Option.map (fun n -> n.GetParseResults)
with _ ->
None

module CodeGenerationUtils =
open FSharp.Compiler.Syntax.PrettyNaming
Expand Down Expand Up @@ -105,7 +116,7 @@ module CodeGenerationUtils =
typ

let tryFindTokenLPosInRange
(codeGenService: CodeGenerationService)
(codeGenService: ICodeGenerationService)
(range: Range)
(document: Document)
(predicate: FSharpTokenInfo -> bool)
Expand Down
Loading

0 comments on commit 4dea78f

Please sign in to comment.