Skip to content

Commit

Permalink
added super basic document symbols lsp support
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimaoth committed Aug 20, 2023
1 parent 0a1fb44 commit b0796aa
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 12 deletions.
56 changes: 54 additions & 2 deletions src/language/language_server_lsp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,8 @@ method getDefinition*(self: LanguageServerLSP, filename: string, location: Curso
log(lvlError, fmt"Error: {response.error}")
return Definition.none


let parsedResponse = response.result
# echo parsedResponse

if parsedResponse.asLocation().getSome(location):
return Definition(filename: location.uri.parseUri.path.myNormalizedPath, location: (line: location.`range`.start.line, column: location.`range`.start.character)).some

Expand All @@ -124,6 +123,59 @@ method getDefinition*(self: LanguageServerLSP, filename: string, location: Curso
log(lvlError, "No definition found")
return Definition.none

method getSymbols*(self: LanguageServerLSP, filename: string): Future[seq[Symbol]] {.async.} =
let response = await self.client.getSymbols(filename)
if response.isError:
log(lvlError, fmt"Error: {response.error}")
return @[]

let parsedResponse = response.result
var completions: seq[Symbol]

if parsedResponse.asDocumentSymbolSeq().getSome(symbols):
for s in symbols:
debug s

elif parsedResponse.asSymbolInformationSeq().getSome(symbols):
for r in symbols:
let symbolKind: SymbolType = case r.kind
# of File: 1
# of Module: 2
# of Namespace: 3
# of Package: 4
# of Class: 5
of Method: SymbolType.Procedure
# of Property: 7
# of Field: 8
# of Constructor: 9
# of Enum: 10
# of Interface: 11
of Function: Procedure
of Variable: MutableVariable
# of Constant: 14
# of String: 15
# of Number: 16
# of Boolean: 17
# of Array: 18
# of Object: 19
# of Key: 20
# of Null: 21
# of EnumMember: 22
# of Struct: 23
# of Event: 24
# of Operator: 25
# of TypeParameter: 26
else: Unknown

completions.add Symbol(
location: (line: r.location.range.start.line, column: r.location.range.start.character),
name: r.name,
symbolType: symbolKind,
filename: r.location.uri.parseUri.path.myNormalizedPath,
)

return completions


method getCompletions*(self: LanguageServerLSP, languageId: string, filename: string, location: Cursor): Future[seq[TextCompletion]] {.async.} =
let response = await self.client.getCompletions(filename, location.line, location.column)
Expand Down
13 changes: 13 additions & 0 deletions src/lsp_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ when not defined(js):
"declaration": %*{
"linkSupport": true,
},
"documentSymbol": %*{
},
},
"window": %*{
"showDocument": %*{
Expand Down Expand Up @@ -272,6 +274,17 @@ when not defined(js):

return (await client.sendRequest("textDocument/declaration", params)).to DeclarationResponse

proc getSymbols*(client: LSPClient, filename: string): Future[Response[DocumentSymbolResponse]] {.async.} =
# echo fmt"[getCompletions] {filename.absolutePath}:{line}:{column}"

client.cancelAllOf("textDocument/documentSymbol")

let params = DocumentSymbolParams(
textDocument: TextDocumentIdentifier(uri: $filename.toUri),
).toJson

return (await client.sendRequest("textDocument/documentSymbol", params)).to DocumentSymbolResponse

proc getCompletions*(client: LSPClient, filename: string, line: int, column: int): Future[Response[CompletionList]] {.async.} =
# echo fmt"[getCompletions] {filename.absolutePath}:{line}:{column}"

Expand Down
78 changes: 68 additions & 10 deletions src/lsp_types.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import json, strutils, tables, options, macros
import std/[json, strutils, tables, options, macros, genasts]
import myjsonutils

macro variant(name: untyped, types: varargs[untyped]): untyped =
Expand All @@ -20,20 +20,22 @@ macro variant(name: untyped, types: varargs[untyped]): untyped =
let isSeqLit = newLit(isSeq)

let procName = ident("as" & typeName.capitalizeAscii)
procs.add quote do:
proc `procName`*(arg: `name`): Option[`t`] =
let ast = genAst(procName, name, t, isSeqLit):
proc procName*(arg: name): Option[t] =
try:
when `isSeqLit`:
when isSeqLit:
if arg.node.kind != JArray:
return `t`.none
return arg.node.jsonTo(`t`, Joptions(allowMissingKeys: true, allowExtraKeys: false)).some
return t.none
return arg.node.jsonTo(t, Joptions(allowMissingKeys: true, allowExtraKeys: false)).some
except CatchableError:
return `t`.none
proc `procName`*(arg: Option[`name`]): Option[`t`] =
return t.none
proc procName*(arg: Option[name]): Option[t] =
if arg.isSome:
return `procName`(arg.get)
return procName(arg.get)
else:
return `t`.none
return t.none

procs.add ast

return quote do:
`variantType`
Expand Down Expand Up @@ -449,6 +451,55 @@ type
itemDefaults*: bool # todo
items*: seq[CompletionItem]

SymbolKind* = enum
File = 1
Module = 2
Namespace = 3
Package = 4
Class = 5
Method = 6
Property = 7
Field = 8
Constructor = 9
Enum = 10
Interface = 11
Function = 12
Variable = 13
Constant = 14
String = 15
Number = 16
Boolean = 17
Array = 18
Object = 19
Key = 20
Null = 21
EnumMember = 22
Struct = 23
Event = 24
Operator = 25
TypeParameter = 26

SymbolTag* = enum
Deprecated = 1

SymbolInformation* = object
name*: string
kind*: SymbolKind
tags*: seq[SymbolTag]
deprecated*: Option[bool]
location*: Location
containerName*: Option[string]

DocumentSymbol* = object
name*: string
detail*: Option[string]
kind*: SymbolKind
tags*: seq[SymbolTag]
deprecated*: Option[bool]
range*: Range
selectionRange*: Range
children*: seq[DocumentSymbol]

type
CompletionParams* = object
workDoneProgress*: bool
Expand All @@ -469,13 +520,20 @@ type
position*: Position
partialResultToken*: Option[ProgressToken]

DocumentSymbolParams* = object
workDoneProgress*: bool
textDocument*: TextDocumentIdentifier
partialResultToken*: Option[ProgressToken]

variant(CompletionResponseVariant, seq[CompletionItem], CompletionList)
variant(DefinitionResponseVariant, Location, seq[Location], seq[LocationLink])
variant(DeclarationResponseVariant, Location, seq[Location], seq[LocationLink])
variant(DocumentSymbolResponseVariant, seq[DocumentSymbol], seq[SymbolInformation])

type CompletionResponse* = CompletionResponseVariant
type DefinitionResponse* = DefinitionResponseVariant
type DeclarationResponse* = DeclarationResponseVariant
type DocumentSymbolResponse* = DocumentSymbolResponseVariant

variant(TextDocumentSyncVariant, TextDocumentSyncOptions, TextDocumentSyncKind)
variant(HoverProviderVariant, bool, HoverOptions)
Expand Down

0 comments on commit b0796aa

Please sign in to comment.