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
6 changes: 4 additions & 2 deletions book/src/lsp.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Install [lsp-mode](https://github.com/emacs-lsp/lsp-mode) and `nim-mode` from ME
- Rename symbols
- Inlay hints
- Signature help
- Document formatting (requires `nph` on `PATH`)
- Document formatting (requires `nph` or `nimpretty` on `PATH`)
- Execute command
- Workspace symbols
- Document highlight
Expand All @@ -127,7 +127,9 @@ LSP configuration is supplied by the client/editor via `nim.*` settings.
| `nim.logNimsuggest` | Enable `nimsuggest` logging. |
| `nim.inlayHints` | Configure inlay hints. |
| `nim.notificationVerbosity` | Notification verbosity: `"none"`, `"error"`, `"warning"`, or `"info"`. |
| `nim.formatOnSave` | Format on save (requires `nph` on `PATH`). |
| `nim.formatOnSave` | Format on save (requires `nph` or `nimpretty` on `PATH`). |
| `nim.formatOnSave` | Format the file on save. Requires `nph` or `nimpretty` to be available in the PATH. |
| `nim.formatter` | The formatter to use. Can be `"nph"` (default) or `"nimpretty"`. |
| `nim.nimsuggestIdleTimeout` | Timeout in ms before an idle `nimsuggest` is stopped. Default: 120 seconds. |
| `nim.useNimCheck` | Use `nim check` instead of `nimsuggest` for linting. Default: `true`. |
| `nim.maxNimsuggestProcesses` | Maximum number of live `nimsuggest` processes. `0` means unlimited. Default: `0`. |
Expand Down
18 changes: 13 additions & 5 deletions ls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ type
nvWarning = "warning"
nvInfo = "info"

NlsFormatter* = enum
nfNph = "nph"
nfNimpretty = "nimpretty"

NlsConfig* = ref object of RootObj
projectMapping*: OptionalSeq[NlsNimsuggestConfig]
workingDirectoryMapping*: OptionalSeq[NlsWorkingDirectoryMaping]
Expand All @@ -90,6 +94,7 @@ type
inlayHints*: Option[NlsInlayHintsConfig]
notificationVerbosity*: Option[NlsNotificationVerbosity]
formatOnSave*: Option[bool]
formatter*: Option[NlsFormatter]
nimsuggestIdleTimeout*: Option[int] #idle timeout in ms
useNimCheck*: Option[bool]
nimExpandArc*: Option[bool]
Expand Down Expand Up @@ -278,7 +283,8 @@ proc getNimbleDumpInfo*(
try:
process = await startProcess(
"nimble",
arguments = @["dump", nimbleFile],
workingDir = nimbleFile.parentDir(),
arguments = @["dump"],
options = {UsePath},
stderrHandle = AsyncProcess.Pipe,
stdoutHandle = AsyncProcess.Pipe,
Expand Down Expand Up @@ -1091,7 +1097,7 @@ proc createOrRestartNimsuggest*(
project.stop()
ls.projectFiles[projectFile] = projectNext

projectNext.ns.addCallback do(fut: Future[Nimsuggest]):
projectNext.ns.addCallback do(fut: Future[Nimsuggest]) {.gcsafe.}:
if fut.failed:
let msg = fut.error.msg
error "Nimsuggest initialization failed", projectFile = projectFile, error = msg
Expand Down Expand Up @@ -1134,7 +1140,7 @@ proc maybeRegisterCapabilityDidChangeConfiguration*(ls: LanguageServer) =
gcsafe
.}:
debug "Got response for the didChangeConfiguration registration:",
res = res.read()
res = $res.read()

proc handleConfigurationChanges*(
ls: LanguageServer, oldConfiguration, newConfiguration: NlsConfig
Expand All @@ -1158,10 +1164,12 @@ proc maybeRequestConfigurationFromClient*(ls: LanguageServer) =
ls.prevWorkspaceConfiguration = ls.workspaceConfiguration

ls.workspaceConfiguration = ls.call("workspace/configuration", %configurationParams)
ls.workspaceConfiguration.addCallback do(futConfiguration: Future[JsonNode]):
ls.workspaceConfiguration.addCallback do(futConfiguration: Future[JsonNode]) {.
gcsafe
.}:
if futConfiguration.error.isNil:
debug "Received the following configuration",
configuration = futConfiguration.read()
configuration = $futConfiguration.read()
if not isNil(ls.prevWorkspaceConfiguration) and
ls.prevWorkspaceConfiguration.finished:
let
Expand Down
19 changes: 13 additions & 6 deletions lstransports.nim
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,9 @@ proc runRpc(ls: LanguageServer, req: RequestRx, rpc: RpcProc): Future[void] {.as
json["result"] = parseJson(res.string)
ls.writeOutput(json)
except CancelledError as ex:
debug "[RunRPC]Request cancelled", meth = req.meth
debug "[RunRPC]Request cancelled", meth = req.method.get("")
except CatchableError as ex:
error "[RunRPC] ", msg = ex.msg, req = req.`method`
error "[RunRPC] ", msg = ex.msg, req = req.method.get("")
writeStackTrace(ex = ex)

proc processMessage(ls: LanguageServer, message: string) {.raises: [].} =
Expand All @@ -220,9 +220,16 @@ proc processMessage(ls: LanguageServer, message: string) {.raises: [].} =
#OPT oportunity reuse the same JSON already parsed
let isReq = "method" in contentJson
if isReq:
debug "[Processing Message]", request = contentJson["method"]
debug "[Processing Message]", request = contentJson["method"].getStr()
var fut = Future[JsonString]()
var req = JrpcSys.decode(message, RequestRx)
# LSP allows null or absent params; json_rpc 0.6+ decoder requires array/object
if contentJson.getOrDefault("params").kind == JNull:
contentJson["params"] = newJObject()
# Notifications have no id; RequestRx.id is non-optional so inject null
# to avoid raiseIncompleteObject during decode.
if "id" notin contentJson:
contentJson["id"] = newJNull()
var req = JrpcSys.decode($contentJson, RequestRx)
if req.params.kind == rpNamed and req.id.kind == riNumber:
#Some requests have no id but for others we need to pass the id to the wrapRpc as the id information is lost in the rpc proc
req.params.named.add ParamDescNamed(
Expand All @@ -231,9 +238,9 @@ proc processMessage(ls: LanguageServer, message: string) {.raises: [].} =
req.params.named.add ParamDescNamed(
name: "method", value: JsonString($(contentJson["method"]))
)
let rpc = ls.srv.router.procs.getOrDefault(req.meth.get)
let rpc = ls.srv.router.procs.getOrDefault(req.method.get(""))
if rpc.isNil:
error "[Processing Message] rpc method not found: ", msg = req.meth.get
error "[Processing Message] rpc method not found: ", msg = req.method.get("")
return
asyncSpawn ls.runRpc(req, rpc)
else: #Response
Expand Down
2 changes: 1 addition & 1 deletion nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
--define:"async_backend=asyncdispatch"
--define:"chronicles_default_output_device=stderr"
--define:"chronicles_colors=None"
--define:"chronicles_disable_thread_id"
--define:"chronicles_thread_ids=no"
--define:"debugLogging"
#--define:"chronicles_log_level=TRACE"
--define:"chronicles_log_level=DEBUG"
Expand Down
Loading