Skip to content
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
80 changes: 61 additions & 19 deletions src/nimlsp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import std/[algorithm, asyncdispatch, asyncfile, hashes, os, osproc, sets,
streams, strformat, strutils, tables, uri]
import asynctools/asyncproc
import nimlsppkg/[baseprotocol, logger, suggestlib, utfmapping]
include nimlsppkg/[messages, messageenums]
include nimlsppkg/[messages, messageenums, capabilities]


const
Expand Down Expand Up @@ -125,6 +125,28 @@ proc parseId(node: JsonNode): int =
else:
raise newException(MalformedFrame, "Invalid id node: " & repr(node))

func newTokenRange(x: Suggest): Range =
## Creates a [Range] that spans the length of the token
result = Range.create(
Position.create(x.line - 1, x.column),
Position.create(x.line - 1, x.column + x.tokenLen)
)

func newDocumentSymbol(sug: Suggest, children: seq[Suggest]): DocumentSymbol =
## Creates a [DocumentSymbol] from a suggestion
let childSymbols = children.mapIt(newDocumentSymbol(it, @[]))
result = DocumentSymbol.create(
sug.name[],
none(string),
nimSymToLSPKind(sug.symKind).int,
none(seq[int]),
newTokenRange(sug),
# TODO: Make selectionRange use endCol/endLine.
# This requires support for v3
newTokenRange(sug),
if children.len > 0: some(childSymbols) else: none(seq[DocumentSymbol])
)

proc respond(outs: Stream | AsyncFile, request: RequestMessage, data: JsonNode) {.multisync.} =
let resp = create(ResponseMessage, "2.0", parseId(request["id"]), some(data), none(ResponseError)).JsonNode
await outs.sendJson resp
Expand Down Expand Up @@ -222,6 +244,7 @@ proc main(ins: Stream | AsyncFile, outs: Stream | AsyncFile) {.multisync.} =
await checkVersion(outs)
else:
checkVersion(outs)
var capabilities: ClientCapabilities
while true:
try:
debugLog "Trying to read frame"
Expand All @@ -242,6 +265,7 @@ proc main(ins: Stream | AsyncFile, outs: Stream | AsyncFile) {.multisync.} =
of "initialize":
debugLog "Got initialize request, answering"
initialized = true
capabilities = ClientCapabilities(message["params"].get()["capabilities"])
let resp = create(InitializeResult, create(ServerCapabilities,
textDocumentSync = some(create(TextDocumentSyncOptions,
openClose = some(true),
Expand Down Expand Up @@ -449,10 +473,11 @@ proc main(ins: Stream | AsyncFile, outs: Stream | AsyncFile) {.multisync.} =
await outs.respond(message, resp)
of "textDocument/documentSymbol":
message.textDocumentRequest(DocumentSymbolParams, symbolRequest):
debugLog "Running equivalent of: outline ", uriToPath(fileuri),
let filePath = uriToPath(fileuri)
debugLog "Running equivalent of: outline ", filePath,
";", filestash
let syms = getNimsuggest(fileuri).outline(
uriToPath(fileuri),
filePath,
dirtyfile = filestash
)
debugLog "Found outlines: ", syms[0..<min(syms.len, 10)],
Expand All @@ -461,24 +486,41 @@ proc main(ins: Stream | AsyncFile, outs: Stream | AsyncFile) {.multisync.} =
if syms.len == 0:
resp = newJNull()
else:
# Store suggestion along with children
# that should appear under it
var symbols: OrderedTable[string, (Suggest, seq[Suggest])]
resp = newJarray()
for sym in syms.sortedByIt((it.line,it.column,it.quality)):
if sym.qualifiedPath.len != 2:
continue
resp.add create(
SymbolInformation,
sym.name[],
nimSymToLSPKind(sym.symKind).int,
some(false),
create(Location,
"file://" & pathToUri(sym.filepath),
create(Range,
create(Position, sym.line-1, sym.column),
create(Position, sym.line-1, sym.column + sym.qualifiedPath[^1].len)
)
),
none(string)
).JsonNode
# DocumentSymbol only allows specifying symbols in current file.
# So skip past external symbols that might be included
if sym.filepath != filePath: continue

let key = sym.qualifiedPath[0..<2].join("")
if sym.qualifiedPath.len == 2:
# Parent add it
symbols[key] = (sym, @[])
else:
# Append child to parent.
# LHS of types are semmed first so shouldn't
# run into key access problems
symbols[key][1] &= sym

let useDocumentSymbol = capabilities.supportsHierarchicalSymbols()
for (sym, children) in symbols.values():
let kind = nimSymToLSPKind(sym.symKind).int
if useDocumentSymbol:
resp &= newDocumentSymbol(sym, children).JsonNode
else:
resp &= SymbolInformation.create(
sym.name[],
kind,
some(false),
create(Location,
"file://" & pathToUri(sym.filepath),
newTokenRange(sym)
),
none(string)
).JsonNode
await outs.respond(message, resp)
of "textDocument/signatureHelp":
message.textDocumentRequest(TextDocumentPositionParams, sigHelpRequest):
Expand Down
10 changes: 10 additions & 0 deletions src/nimlsppkg/capabilities.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Helper functions to check what the client supports

import std/json

using caps: ClientCapabilities

func supportsHierarchicalSymbols*(caps): bool =
## True if the client supports having heirarchal
## symbols in the document outline
JsonNode(caps){"textDocument", "documentSymbol", "hierarchicalDocumentSymbolSupport"} == %true
3 changes: 3 additions & 0 deletions src/nimlsppkg/messageenums.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ type
Operator = 25,
TypeParameter = 26

SymbolTag* = enum
Deprecated = 1

CompletionItemKind* {.pure.} = enum
Text = 1,
Method = 2,
Expand Down
10 changes: 10 additions & 0 deletions src/nimlsppkg/messages.nim
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ jsonSchema:
DocumentSymbolCapability:
dynamicRegistration ?: bool
symbolKind ?: SymbolKindCapability
hierarchicalDocumentSymbolSupport ?: bool

FormattingCapability:
dynamicRegistration ?: bool
Expand Down Expand Up @@ -513,6 +514,15 @@ jsonSchema:
location: Location
containerName ?: string

DocumentSymbol:
name: string
detail ?: string
kind: int # SymbolKind
tags ?: int[] # SymbolTag[]
"range": Range
selectionRange: Range
children ?: DocumentSymbol[]

CodeActionParams:
textDocument: TextDocumentIdentifier
"range": Range
Expand Down
1 change: 1 addition & 0 deletions src/nimlsppkg/suggestlib.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func nimSymToLSPKind*(suggest: byte): SymbolKind =
case TSymKind(suggest):
of skConst: SymbolKind.Constant
of skEnumField: SymbolKind.EnumMember
of skField: SymbolKind.Field
of skIterator: SymbolKind.Function
of skConverter: SymbolKind.Function
of skLet: SymbolKind.Variable
Expand Down