Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to fcs 39 #93

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ node_modules/
.idea/
build.vsix
Scratch.fsx
Scratch.ts
Scratch.ts
fsharp-language-server.sln.DotSettings.user
4 changes: 3 additions & 1 deletion client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ export function activate(context: ExtensionContext) {
transport: TransportKind.stdio
}
if (debugMode) {
const commandName = process.platform === 'win32' ? 'dotnet.exe' : 'dotnet';

serverOptions = {
command: findInPath('dotnet'),
command: findInPath(commandName),
args: ['run', '--project', 'src/FSharpLanguageServer'],
transport: TransportKind.stdio,
options: { cwd: context.extensionPath }
Expand Down
409 changes: 69 additions & 340 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@
"vscode-languageclient": "^4.2.1"
},
"devDependencies": {
"@types/node": "^10.17.59",
"vscode-test": "^1.5.2"
"@types/node": "^14.14.37",
"@types/vscode": "^1.24.0",
"typescript": "^4.2.4"
}
}
2 changes: 1 addition & 1 deletion sample/Net5Console/Net5Console.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand Down
169 changes: 84 additions & 85 deletions src/FSharpLanguageServer/Conversions.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module FSharpLanguageServer.Conversions
module FSharpLanguageServer.Conversions

open LSP.Log
open FSharp.Compiler
Expand All @@ -8,45 +8,44 @@ open System.IO
open LSP.Types
open FSharp.Data

module Ast = FSharp.Compiler.Ast

/// Convert an F# Compiler Services 'FSharpErrorInfo' to an LSP 'Range'
let private errorAsRange(err: FSharpErrorInfo): Range =
let private errorAsRange(err: FSharpDiagnostic): Range =
{
// Got error "The field, constructor or member 'StartLine' is not defined"
start = {line=err.StartLineAlternate-1; character=err.StartColumn}
``end`` = {line=err.EndLineAlternate-1; character=err.EndColumn}
}

/// Convert an F# `Range.pos` to an LSP `Position`
let private asPosition(p: Range.pos): Position =
let private asPosition(p: Text.pos): Position =
{
line=p.Line-1
character=p.Column
}

/// Convert an F# `Range.range` to an LSP `Range`
let asRange(r: Range.range): Range =
let asRange(r: Text.range): Range =
{
start=asPosition r.Start
``end``=asPosition r.End
}

/// Convert an F# `Range.range` to an LSP `Location`
let private asLocation(l: Range.range): Location =
{
let private asLocation(l: Text.range): Location =
{
uri=Uri("file://" + l.FileName)
range = asRange l
range = asRange l
}

/// Convert an F# Compiler Services 'FSharpErrorSeverity' to an LSP 'DiagnosticSeverity'
let private asDiagnosticSeverity(s: FSharpErrorSeverity): DiagnosticSeverity =
match s with
| FSharpErrorSeverity.Warning -> DiagnosticSeverity.Warning
| FSharpErrorSeverity.Error -> DiagnosticSeverity.Error
let private asDiagnosticSeverity(s: FSharpDiagnosticSeverity): DiagnosticSeverity =
match s with
| FSharpDiagnosticSeverity.Warning -> DiagnosticSeverity.Warning
| FSharpDiagnosticSeverity.Error -> DiagnosticSeverity.Error
| FSharpDiagnosticSeverity.Info -> DiagnosticSeverity.Information

/// Convert an F# Compiler Services 'FSharpErrorInfo' to an LSP 'Diagnostic'
let asDiagnostic(err: FSharpErrorInfo): Diagnostic =
let asDiagnostic(err: FSharpDiagnostic): Diagnostic =
{
range = errorAsRange(err)
severity = Some(asDiagnosticSeverity(err.Severity))
Expand All @@ -56,18 +55,18 @@ let asDiagnostic(err: FSharpErrorInfo): Diagnostic =
}

/// Create a Diagnostic
let diagnostic(message: string, range: Range.range, severity: DiagnosticSeverity): Diagnostic =
let diagnostic(message: string, range: Text.range, severity: DiagnosticSeverity): Diagnostic =
{
range = asRange(range)
severity = Some(severity)
code = None
source = None
code = None
source = None
message = message
}

/// Some compiler errors have no location in the file and should be displayed at the top of the file
let private hasNoLocation(err: FSharpErrorInfo): bool =
err.StartLineAlternate-1 = 0 &&
let private hasNoLocation(err: FSharpDiagnostic): bool =
err.StartLineAlternate-1 = 0 &&
err.StartColumn = 0 &&
err.EndLineAlternate-1 = 0 &&
err.EndColumn = 0
Expand All @@ -76,60 +75,60 @@ let private hasNoLocation(err: FSharpErrorInfo): bool =
let errorAtTop(message: string): Diagnostic =
{
range = { start = {line=0; character=0}; ``end`` = {line=0; character=1} }
severity = Some(DiagnosticSeverity.Error)
severity = Some(DiagnosticSeverity.Error)
code = None
source = None
source = None
message = message
}

/// Convert a list of F# Compiler Services 'FSharpErrorInfo' to LSP 'Diagnostic'
let asDiagnostics(errors: FSharpErrorInfo seq): Diagnostic list =
[
for err in errors do
if hasNoLocation(err) then
let asDiagnostics(errors: FSharpDiagnostic seq): Diagnostic list =
[
for err in errors do
if hasNoLocation(err) then
yield errorAtTop(sprintf "%s: %s" err.Subcategory err.Message)
else
yield asDiagnostic(err)
yield asDiagnostic(err)
]


/// Convert an F# `FSharpToolTipElement` to an LSP `Hover`
let asHover(FSharpToolTipText tips): Hover =
let elements =
let asHover(FSharpToolTipText tips): Hover =
let elements =
[ for t in tips do
match t with
match t with
| FSharpToolTipElement.CompositionError(e) -> dprintfn "Error rendering tooltip: %s" e
| FSharpToolTipElement.None -> ()
| FSharpToolTipElement.Group(elements) ->
| FSharpToolTipElement.None -> ()
| FSharpToolTipElement.Group(elements) ->
yield! elements ]
let contents =
match elements with
let contents =
match elements with
| [] -> []
| [one] ->
[ yield HighlightedString(one.MainDescription, "fsharp")
match TipFormatter.docComment(one.XmlDoc) with
| [one] ->
[ yield HighlightedString(one.MainDescription, "fsharp")
match TipFormatter.docComment(one.XmlDoc) with
| None -> ()
| Some(markdown) -> yield PlainString(markdown + "\n\n")
match one.Remarks with
| None | Some("") -> ()
| Some(remarks) ->
match one.Remarks with
| None | Some("") -> ()
| Some(remarks) ->
yield PlainString("*" + remarks + "*\n\n") ]
| many ->
| many ->
let last = List.last(many)
[ for e in many do
[ for e in many do
yield HighlightedString(e.MainDescription, "fsharp")
match TipFormatter.docSummaryOnly(last.XmlDoc) with
match TipFormatter.docSummaryOnly(last.XmlDoc) with
| None -> ()
| Some(markdown) -> yield PlainString(markdown)
match last.Remarks with
| None | Some("") -> ()
| Some(remarks) ->
match last.Remarks with
| None | Some("") -> ()
| Some(remarks) ->
yield PlainString("*" + remarks + "*\n\n") ]
{contents=contents; range=None}

/// Convert an F# `FSharpGlyph` to an LSP `CompletionItemKind`
let private asCompletionItemKind(k: FSharpGlyph): CompletionItemKind =
match k with
let private asCompletionItemKind(k: FSharpGlyph): CompletionItemKind =
match k with
| FSharpGlyph.Class -> CompletionItemKind.Class
| FSharpGlyph.Constant -> CompletionItemKind.Constant
| FSharpGlyph.Delegate -> CompletionItemKind.Property // ?
Expand All @@ -153,9 +152,9 @@ let private asCompletionItemKind(k: FSharpGlyph): CompletionItemKind =
| FSharpGlyph.Error -> CompletionItemKind.Class // ?

/// Convert an F# `FSharpDeclarationListItem` to an LSP `CompletionItem`
let private asCompletionItem(i: FSharpDeclarationListItem): CompletionItem =
{ defaultCompletionItem with
label = i.Name
let private asCompletionItem(i: FSharpDeclarationListItem): CompletionItem =
{ defaultCompletionItem with
label = i.Name
insertText = Some(i.NameInCode)
kind = Some(asCompletionItemKind(i.Glyph))
detail = Some(i.FullName)
Expand All @@ -165,50 +164,50 @@ let private asCompletionItem(i: FSharpDeclarationListItem): CompletionItem =

/// Convert an F# `FSharpDeclarationListInfo` to an LSP `CompletionList`
/// Used in rendering autocomplete lists
let asCompletionList(ds: FSharpDeclarationListInfo): CompletionList =
let asCompletionList(ds: FSharpDeclarationListInfo): CompletionList =
let items = [for i in ds.Items do yield asCompletionItem(i)]
{isIncomplete=List.isEmpty(items); items=items}

/// Convert an F# `FSharpMethodGroupItemParameter` to an LSP `ParameterInformation`
let private asParameterInformation(p: FSharpMethodGroupItemParameter): ParameterInformation =
let private asParameterInformation(p: FSharpMethodGroupItemParameter): ParameterInformation =
{
label = p.ParameterName
documentation = Some p.Display
}

/// Convert an F# method name + `FSharpMethodGroupItem` to an LSP `SignatureInformation`
/// Used in providing signature help after autocompleting
let asSignatureInformation(methodName: string, s: FSharpMethodGroupItem): SignatureInformation =
let doc = match s.Description with
| FSharpToolTipText [FSharpToolTipElement.Group [tip]] -> Some tip.MainDescription
| _ ->
dprintfn "Can't render documentation %A" s.Description
None
let asSignatureInformation(methodName: string, s: FSharpMethodGroupItem): SignatureInformation =
let doc = match s.Description with
| FSharpToolTipText [FSharpToolTipElement.Group [tip]] -> Some tip.MainDescription
| _ ->
dprintfn "Can't render documentation %A" s.Description
None
let parameterName(p: FSharpMethodGroupItemParameter) = p.ParameterName
let parameterNames = Array.map parameterName s.Parameters
{
label = sprintf "%s(%s)" methodName (String.concat ", " parameterNames)
documentation = doc
label = sprintf "%s(%s)" methodName (String.concat ", " parameterNames)
documentation = doc
parameters = Array.map asParameterInformation s.Parameters |> List.ofArray
}

/// Get the lcation where `s` was declared
let declarationLocation(s: FSharpSymbol): Location option =
match s.DeclarationLocation with
| None ->
dprintfn "Symbol %s has no declaration" s.FullName
None
let declarationLocation(s: FSharpSymbol): Location option =
match s.DeclarationLocation with
| None ->
dprintfn "Symbol %s has no declaration" s.FullName
None
| Some l ->
Some(asLocation(l))

/// Get the location where `s` was used
let useLocation(s: FSharpSymbolUse): Location =
let useLocation(s: FSharpSymbolUse): Location =
asLocation(s.RangeAlternate)

/// Convert an F# `FSharpNavigationDeclarationItemKind` to an LSP `SymbolKind`
/// `FSharpNavigationDeclarationItemKind` is the level of symbol-type information you get when parsing without typechecking
let private asSymbolKind(k: FSharpNavigationDeclarationItemKind): SymbolKind =
match k with
let private asSymbolKind(k: FSharpNavigationDeclarationItemKind): SymbolKind =
match k with
| NamespaceDecl -> SymbolKind.Namespace
| ModuleFileDecl -> SymbolKind.Module
| ExnDecl -> SymbolKind.Class
Expand All @@ -222,17 +221,17 @@ let private asSymbolKind(k: FSharpNavigationDeclarationItemKind): SymbolKind =
/// Convert an F# `NavigationDeclarationItem` to an LSP `SymbolInformation`
/// `NavigationDeclarationItem` is the parsed AST representation of a symbol without typechecking
/// `container` is present when `d` is part of a module or type
let asSymbolInformation(d: NavigationDeclarationItem, container: NavigationDeclarationItem option): SymbolInformation =
let declarationName(d: NavigationDeclarationItem) = d.Name
let asSymbolInformation(d: NavigationItem, container: NavigationItem option): SymbolInformation =
let declarationName(d: NavigationItem) = d.Name
{
name=d.Name
kind=asSymbolKind d.Kind
location=asLocation d.Range
name=d.Name
kind=asSymbolKind d.Kind
location=asLocation d.Range
containerName=Option.map declarationName container
}

/// Convert symbols declared in an .fsi file to a CodeLens that helps the user navigate to the definition
let asGoToImplementation(name: string list, file: FileInfo, range: Range.range): CodeLens =
let asGoToImplementation(name: string list, file: FileInfo, range: Text.range): CodeLens =
let jsonFile = JsonValue.String(file.FullName)
let jsonName = JsonValue.Array([|for i in name do yield JsonValue.String(i)|])
{
Expand All @@ -241,13 +240,13 @@ let asGoToImplementation(name: string list, file: FileInfo, range: Range.range):
data=JsonValue.Array([|jsonFile; jsonName|])
}

let goToImplementationData(goTo: CodeLens) =
match goTo.data with
| JsonValue.Array([|JsonValue.String(file); JsonValue.Array(jsonNames)|]) ->
let goToImplementationData(goTo: CodeLens) =
match goTo.data with
| JsonValue.Array([|JsonValue.String(file); JsonValue.Array(jsonNames)|]) ->
FileInfo(file), [for JsonValue.String(j) in jsonNames do yield j ]

let resolveGoToImplementation(unresolved: CodeLens, file: FileInfo, range: Range.range): CodeLens =
let command =
let resolveGoToImplementation(unresolved: CodeLens, file: FileInfo, range: Text.range): CodeLens =
let command =
{
title=sprintf "%s(%d)" file.Name range.StartLine
command="fsharp.command.goto"
Expand All @@ -261,8 +260,8 @@ let resolveGoToImplementation(unresolved: CodeLens, file: FileInfo, range: Range
}
{ unresolved with command = Some(command) }

let resolveMissingGoToImplementation(unresolved: CodeLens, file: FileInfo): CodeLens =
let command =
let resolveMissingGoToImplementation(unresolved: CodeLens, file: FileInfo): CodeLens =
let command =
{
title="Not Found"
command="fsharp.command.goto"
Expand All @@ -276,7 +275,7 @@ let resolveMissingGoToImplementation(unresolved: CodeLens, file: FileInfo): Code
}
{ unresolved with command = Some(command) }

let asRunTest(fsproj: FileInfo, fullyQualifiedName: string list, test: Ast.SynBinding): CodeLens =
let asRunTest(fsproj: FileInfo, fullyQualifiedName: string list, test: SyntaxTree.SynBinding): CodeLens =
{
range=asRange(test.RangeOfBindingSansRhs)
command=Some({ title="Run Test"
Expand All @@ -285,11 +284,11 @@ let asRunTest(fsproj: FileInfo, fullyQualifiedName: string list, test: Ast.SynBi
data=JsonValue.Null
}

let asDebugTest(fsproj: FileInfo, fullyQualifiedName: string list, test: Ast.SynBinding): CodeLens =
let asDebugTest(fsproj: FileInfo, fullyQualifiedName: string list, test: SyntaxTree.SynBinding): CodeLens =
{
range=asRange(test.RangeOfBindingSansRhs)
command=Some({ title="Debug Test"
command="fsharp.command.test.debug"
arguments=[JsonValue.String(fsproj.FullName); JsonValue.String(String.concat "." fullyQualifiedName)] })
data=JsonValue.Null
}
}
3 changes: 2 additions & 1 deletion src/FSharpLanguageServer/FSharpLanguageServer.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ItemGroup>
<Compile Include="ProgressBar.fs" />
<Compile Include="TipFormatter.fs" />
<Compile Include="SyntaxTreeOps.fs" />
<Compile Include="Navigation.fs" />
<Compile Include="Conversions.fs" />
<Compile Include="ProjectManager.fs" />
Expand All @@ -18,7 +19,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="FSharp.Compiler.Service" Version="34.1.1" />
<PackageReference Include="FSharp.Compiler.Service" Version="39.0.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.8.4" />
</ItemGroup>

Expand Down
Loading