Skip to content

Commit 3cc0e19

Browse files
authored
Fixes an out of range error that makes the ls to crash (#290)
1 parent d4dbaa5 commit 3cc0e19

File tree

1 file changed

+60
-54
lines changed

1 file changed

+60
-54
lines changed

ls.nim

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ type
140140
onExit*: OnExitCallback
141141
projectFiles*: Table[string, Project]
142142
openFiles*: Table[string, NlsFileInfo]
143-
idleOpenFiles*: Table[string, NlsFileInfo] #We close the file when its inactive and store it here.
143+
idleOpenFiles*: Table[string, NlsFileInfo]
144+
#We close the file when its inactive and store it here.
144145
workspaceConfiguration*: Future[JsonNode]
145146
prevWorkspaceConfiguration*: Future[JsonNode]
146147
inlayHintsRefreshRequest*: Future[JsonNode]
@@ -306,7 +307,7 @@ proc getWorkspaceConfiguration*(
306307
proc getAndWaitForWorkspaceConfiguration*(
307308
ls: LanguageServer
308309
): Future[NlsConfig] {.async.} =
309-
try:
310+
try:
310311
let conf = await ls.workspaceConfiguration
311312
return parseWorkspaceConfiguration(conf)
312313
except CatchableError as ex:
@@ -384,11 +385,11 @@ proc getLspStatus*(ls: LanguageServer): NimLangServerStatus {.raises: [].} =
384385
result.projectErrors = ls.projectErrors
385386

386387
proc sendStatusChanged*(ls: LanguageServer) {.raises: [].} =
387-
let status = %*ls.getLspStatus()
388+
let status = %*ls.getLspStatus()
388389
if status != ls.lastStatusSent:
389390
ls.notify("extension/statusUpdate", status)
390391
ls.lastStatusSent = status
391-
392+
392393
proc addProjectFileToPendingRequest*(
393394
ls: LanguageServer, id: uint, uri: string
394395
) {.async.} =
@@ -606,7 +607,7 @@ proc toUtf16Pos*(suggest: Suggest, ls: LanguageServer): Suggest =
606607
result.column = pos.get()
607608

608609
proc toUtf16Pos*(
609-
suggest: SuggestInlayHint, ls: LanguageServer, uri: string
610+
suggest: SuggestInlayHint, ls: LanguageServer, uri: string
610611
): SuggestInlayHint =
611612
result = suggest
612613
let pos = toUtf16Pos(ls, uri, suggest.line - 1, suggest.column)
@@ -619,9 +620,10 @@ proc toUtf16Pos*(checkResult: CheckResult, ls: LanguageServer): CheckResult =
619620
let pos = toUtf16Pos(ls, uri, checkResult.line - 1, checkResult.column)
620621
if pos.isSome:
621622
result.column = pos.get()
622-
623-
for i in 0..<result.stacktrace.len:
624-
let stPos = toUtf16Pos(ls, uri, result.stacktrace[i].line - 1, result.stacktrace[i].column)
623+
624+
for i in 0 ..< result.stacktrace.len:
625+
let stPos =
626+
toUtf16Pos(ls, uri, result.stacktrace[i].line - 1, result.stacktrace[i].column)
625627
if stPos.isSome:
626628
result.stacktrace[i].column = stPos.get()
627629

@@ -642,7 +644,7 @@ proc toDiagnostic(suggest: Suggest): Diagnostic =
642644
textStart = doc.find('\'')
643645
textEnd = doc.rfind('\'')
644646
endColumn =
645-
if textStart >= 0 and textEnd >= 0:
647+
if textStart >= 0 and textEnd > textStart:
646648
column + utf16Len(doc[textStart + 1 ..< textEnd])
647649
else:
648650
column + 1
@@ -677,7 +679,12 @@ proc toDiagnostic(checkResult: CheckResult): Diagnostic =
677679
let node =
678680
%*{
679681
"uri": pathToUri(checkResult.file),
680-
"range": range(checkResult.line - 1, max(0, checkResult.column), checkResult.line - 1, max(0, endColumn)),
682+
"range": range(
683+
checkResult.line - 1,
684+
max(0, checkResult.column),
685+
checkResult.line - 1,
686+
max(0, endColumn),
687+
),
681688
"severity":
682689
case checkResult.severity
683690
of "Error": DiagnosticSeverity.Error.int
@@ -688,21 +695,24 @@ proc toDiagnostic(checkResult: CheckResult): Diagnostic =
688695
"message": checkResult.msg,
689696
"source": "nim",
690697
"code": "nim check",
691-
}
698+
}
692699
return node.to(Diagnostic)
693700

694-
proc sendDiagnostics*(ls: LanguageServer, diagnostics: seq[Suggest] | seq[CheckResult], path: string) =
701+
proc sendDiagnostics*(
702+
ls: LanguageServer, diagnostics: seq[Suggest] | seq[CheckResult], path: string
703+
) =
695704
trace "Sending diagnostics", count = diagnostics.len, path = path
696705
let params =
697-
PublishDiagnosticsParams %*
698-
{"uri": pathToUri(path), "diagnostics": diagnostics.map(x => x.toUtf16Pos(ls).toDiagnostic)}
706+
PublishDiagnosticsParams %* {
707+
"uri": pathToUri(path),
708+
"diagnostics": diagnostics.map(x => x.toUtf16Pos(ls).toDiagnostic),
709+
}
699710
ls.notify("textDocument/publishDiagnostics", %params)
700711
if diagnostics.len != 0:
701712
ls.filesWithDiags.incl path
702713
else:
703714
ls.filesWithDiags.excl path
704715

705-
706716
proc warnIfUnknown*(
707717
ls: LanguageServer, ns: Nimsuggest, uri: string, projectFile: string
708718
): Future[void] {.async, gcsafe.} =
@@ -728,35 +738,31 @@ proc getNimsuggestInner(ls: LanguageServer, uri: string): Future[Nimsuggest] {.a
728738
ls.createOrRestartNimsuggest(projectFile, uri)
729739
# Wait a bit to allow nimsuggest to start
730740
await sleepAsync(10)
731-
741+
732742
# Check multiple times with small delays
733743
var attempts = 0
734744
const maxAttempts = 10
735745
while attempts < maxAttempts:
736746
if projectFile in ls.projectFiles:
737747
ls.lastNimsuggest = ls.projectFiles[projectFile].ns
738748
return await ls.projectFiles[projectFile].ns
739-
749+
740750
inc attempts
741751
if attempts < maxAttempts:
742752
await sleepAsync(100)
743-
debug "Waiting for nimsuggest to initialize",
744-
uri = uri,
745-
projectFile = projectFile,
746-
attempt = attempts
747-
753+
debug "Waiting for nimsuggest to initialize",
754+
uri = uri, projectFile = projectFile, attempt = attempts
755+
748756
debug "Failed to get nimsuggest after waiting", uri = uri, projectFile = projectFile
749757
return nil
750758

751759
proc tryGetNimsuggest*(
752760
ls: LanguageServer, uri: string
753-
): Future[Option[Nimsuggest]] {.raises:[], gcsafe.}
761+
): Future[Option[Nimsuggest]] {.raises: [], gcsafe.}
754762

755-
proc checkFile*(ls: LanguageServer, uri: string): Future[void] {.raises:[], gcsafe.}
763+
proc checkFile*(ls: LanguageServer, uri: string): Future[void] {.raises: [], gcsafe.}
756764

757-
proc didCloseFile*(
758-
ls: LanguageServer, uri: string
759-
): Future[void] {.async, gcsafe.} =
765+
proc didCloseFile*(ls: LanguageServer, uri: string): Future[void] {.async, gcsafe.} =
760766
debug "Closed the following document:", uri = uri
761767

762768
if ls.openFiles[uri].changed:
@@ -774,7 +780,9 @@ proc makeIdleFile*(
774780
ls.idleOpenFiles[uri] = file
775781
ls.openFiles.del(uri)
776782

777-
proc getProjectFile*(fileUri: string, ls: LanguageServer): Future[string] {.raises:[], gcsafe.}
783+
proc getProjectFile*(
784+
fileUri: string, ls: LanguageServer
785+
): Future[string] {.raises: [], gcsafe.}
778786

779787
proc didOpenFile*(
780788
ls: LanguageServer, textDocument: TextDocumentItem
@@ -785,9 +793,13 @@ proc didOpenFile*(
785793
file = open(ls.uriStorageLocation(uri), fmWrite)
786794
projectFileFuture = getProjectFile(uriToPath(uri), ls)
787795

788-
ls.openFiles[uri] =
789-
NlsFileInfo(projectFile: projectFileFuture, changed: false, fingerTable: @[], textDocument: textDocument)
790-
796+
ls.openFiles[uri] = NlsFileInfo(
797+
projectFile: projectFileFuture,
798+
changed: false,
799+
fingerTable: @[],
800+
textDocument: textDocument,
801+
)
802+
791803
if uri in ls.idleOpenFiles:
792804
ls.idleOpenFiles.del(uri)
793805

@@ -817,29 +829,28 @@ proc didOpenFile*(
817829
ls.showMessage(fmt "Opening {uri}", MessageType.Info)
818830

819831
proc tryGetNimsuggest*(
820-
ls: LanguageServer, uri: string
832+
ls: LanguageServer, uri: string
821833
): Future[Option[Nimsuggest]] {.async.} =
822-
823834
if uri in ls.idleOpenFiles:
824835
let idleFile = ls.idleOpenFiles[uri]
825836
await didOpenFile(ls, idleFile.textDocument)
826837

827838
if uri notin ls.openFiles:
828839
return none(NimSuggest)
829-
840+
830841
var retryCount = 0
831842
const maxRetries = 3
832843
while retryCount < maxRetries:
833844
let ns = await getNimsuggestInner(ls, uri)
834845
if not ns.isNil:
835846
return some ns
836-
847+
837848
# If nimsuggest is nil, wait a bit and retry
838849
inc retryCount
839850
if retryCount < maxRetries:
840851
debug "Nimsuggest not ready, retrying...", uri = uri, attempt = retryCount
841-
await sleepAsync(10000 * retryCount) # Exponential backoff
842-
852+
await sleepAsync(10000 * retryCount) # Exponential backoff
853+
843854
debug "Nimsuggest not found after retries", uri = uri
844855
return none(NimSuggest)
845856

@@ -848,11 +859,12 @@ proc checkProject*(ls: LanguageServer, uri: string): Future[void] {.async, gcsaf
848859
return
849860
let conf = await ls.getAndWaitForWorkspaceConfiguration()
850861
let useNimCheck = conf.useNimCheck.get(USE_NIM_CHECK_BY_DEFAULT)
851-
862+
852863
let nimPath = getNimPath(conf)
853864

854865
if useNimCheck and nimPath.isSome:
855-
proc getFilePath(c: CheckResult): string = c.file
866+
proc getFilePath(c: CheckResult): string =
867+
c.file
856868

857869
let token = fmt "Checking {uri}"
858870
ls.workDoneProgressCreate(token)
@@ -863,13 +875,13 @@ proc checkProject*(ls: LanguageServer, uri: string): Future[void] {.async, gcsaf
863875
return
864876
let diagnostics = await nimCheck(uriToPath(uri), nimPath.get)
865877
let filesWithDiags = diagnostics.map(r => r.file).toHashSet
866-
878+
867879
ls.progress(token, "end")
868-
880+
869881
debug "Found diagnostics", file = filesWithDiags
870882
for (path, diags) in groupBy(diagnostics, getFilePath):
871883
ls.sendDiagnostics(diags, path)
872-
884+
873885
# clean files with no diags
874886
for path in ls.filesWithDiags:
875887
if not filesWithDiags.contains path:
@@ -927,8 +939,6 @@ proc checkProject*(ls: LanguageServer, uri: string): Future[void] {.async, gcsaf
927939
debug "Running delayed check project...", uri = uri
928940
traceAsyncErrors ls.checkProject(uri)
929941

930-
931-
932942
proc onErrorCallback(args: (LanguageServer, string), project: Project) =
933943
let
934944
ls = args[0]
@@ -977,7 +987,7 @@ proc createOrRestartNimsuggest*(
977987
ls.createOrRestartNimsuggest(projectFile, uri)
978988
ls.sendStatusChanged()
979989
errorCallback = partial(onErrorCallback, (ls, uri))
980-
990+
981991
debug "Creating new nimsuggest project", projectFile = projectFile
982992
let projectNext = waitFor createNimsuggest(
983993
projectFile,
@@ -990,12 +1000,12 @@ proc createOrRestartNimsuggest*(
9901000
configuration.logNimsuggest.get(false),
9911001
configuration.exceptionHintsEnabled,
9921002
)
993-
1003+
9941004
if projectFile in ls.projectFiles:
9951005
var project = ls.projectFiles[projectFile]
9961006
project.stop()
9971007
ls.projectFiles[projectFile] = projectNext
998-
1008+
9991009
projectNext.ns.addCallback do(fut: Future[Nimsuggest]):
10001010
if fut.failed:
10011011
let msg = fut.error.msg
@@ -1011,9 +1021,8 @@ proc createOrRestartNimsuggest*(
10111021
fut.read().openFiles.incl uri
10121022
ls.sendStatusChanged()
10131023
except CatchableError as ex:
1014-
error "Failed to create/restart nimsuggest",
1015-
projectFile = projectFile,
1016-
error = ex.msg
1024+
error "Failed to create/restart nimsuggest",
1025+
projectFile = projectFile, error = ex.msg
10171026

10181027
proc restartAllNimsuggestInstances(ls: LanguageServer) =
10191028
debug "Restarting all nimsuggest instances"
@@ -1130,8 +1139,6 @@ proc getProjectFile*(fileUri: string, ls: LanguageServer): Future[string] {.asyn
11301139

11311140
debug "getProjectFile ", project = result, fileUri = fileUri
11321141

1133-
1134-
11351142
proc checkFile*(ls: LanguageServer, uri: string): Future[void] {.async.} =
11361143
let conf = await ls.getAndWaitForWorkspaceConfiguration()
11371144
let useNimCheck = conf.useNimCheck.get(USE_NIM_CHECK_BY_DEFAULT)
@@ -1186,7 +1193,7 @@ proc removeIdleNimsuggests*(ls: LanguageServer) {.async.} =
11861193
for project in toStop:
11871194
debug "Removing idle nimsuggest", project = project.file
11881195
project.errorCallback = none(ProjectCallback)
1189-
1196+
11901197
let ns = await project.ns
11911198
for uri in ns.openFiles:
11921199
debug "Removing idle nimsuggest open file", uri = uri
@@ -1208,4 +1215,3 @@ proc tick*(ls: LanguageServer): Future[void] {.async.} =
12081215
except CatchableError as ex:
12091216
error "Error in tick", msg = ex.msg
12101217
writeStacktrace(ex)
1211-

0 commit comments

Comments
 (0)