Skip to content

Commit

Permalink
Trim instances on save to avoid race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
jmgomez committed Jun 24, 2024
1 parent fb725fe commit 85caa53
Showing 1 changed file with 54 additions and 42 deletions.
96 changes: 54 additions & 42 deletions nimlangserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type
storageDir*: string
cmdLineClientProcessId: Option[int]
nimDumpCache: Table[string, NimbleDumpInfo] #path to NimbleDumpInfo
entryPoints: seq[string]

Certainty = enum
None,
Expand Down Expand Up @@ -240,13 +241,30 @@ proc getRootPath(ip: InitializeParams): string =

proc createOrRestartNimsuggest(ls: LanguageServer, projectFile: string, uri = ""): void {.gcsafe.}

proc isKnownByAnyNimsuggest(ls: LanguageServer, filePath: string): Future[Option[string]] {.async.} =
for projectFile in ls.projectFiles.keys:
let ns = await ls.projectFiles[projectFile]
let isKnown = await ns.isKnown(filePath)
if isKnown:
return some projectFile
none(string)
proc showMessage(ls: LanguageServer, message: string, typ: MessageType) =
proc notify() =
ls.connection.notify(
"window/showMessage",
%* {
"type": typ.int,
"message": message
})
let verbosity =
ls
.getWorkspaceConfiguration
.waitFor
.notificationVerbosity.get(NlsNotificationVerbosity.nvInfo)
debug "ShowMessage ", message = message
case verbosity:
of nvInfo:
notify()
of nvWarning:
if typ.int <= MessageType.Warning.int :
notify()
of nvError:
if typ == MessageType.Error:
notify()
else: discard

proc getProjectFile(fileUri: string, ls: LanguageServer): Future[string] {.async.} =
let
Expand All @@ -269,47 +287,26 @@ proc getProjectFile(fileUri: string, ls: LanguageServer): Future[string] {.async
if nimbleFiles.len > 0:
let nimbleFile = nimbleFiles[0]
let nimbleDumpInfo = ls.getNimbleDumpInfo(nimbleFile)
let entryPoints = nimbleDumpInfo.getNimbleEntryPoints(ls.initializeParams.getRootPath)
for entryPoint in entryPoints:
ls.entryPoints = nimbleDumpInfo.getNimbleEntryPoints(ls.initializeParams.getRootPath)
# ls.showMessage(fmt "Found entry point {ls.entryPoints}?", MessageType.Info)
for entryPoint in ls.entryPoints:
debug "Starting nimsuggest for entry point ", entry = entryPoint
if not ls.projectFiles.hasKey(entryPoint):
ls.createOrRestartNimsuggest(entryPoint)
# let ns = await ls.projectFiles[entryPoint]

result = ls.getProjectFileAutoGuess(fileUri)
if result in ls.projectFiles:
let ns = await ls.projectFiles[result]
let isKnown = await ns.isKnown(fileUri)
if not isKnown:
debug "File is not known by nimsuggest", uri = fileUri, projectFile = result
result = fileUri

if result == "":
result = fileUri

let otherNsProject = await ls.isKnownByAnyNimsuggest(fileUri)
if otherNsProject.isSome:
debug "File is known by nimsuggest", uri = fileUri, projectFile = otherNsProject.get
result = otherNsProject.get
else:
result = ls.getProjectFileAutoGuess(fileUri)

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

proc showMessage(ls: LanguageServer, message: string, typ: MessageType) =
proc notify() =
ls.connection.notify(
"window/showMessage",
%* {
"type": typ.int,
"message": message
})
let verbosity =
ls
.getWorkspaceConfiguration
.waitFor
.notificationVerbosity.get(NlsNotificationVerbosity.nvInfo)
debug "ShowMessage ", message = message
case verbosity:
of nvInfo:
notify()
of nvWarning:
if typ.int <= MessageType.Warning.int :
notify()
of nvError:
if typ == MessageType.Error:
notify()
else: discard

# Fixes callback clobbering in core implementation
proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
var retFuture = newFuture[void]("asyncdispatch.`or`")
Expand Down Expand Up @@ -925,6 +922,21 @@ proc didSave(ls: LanguageServer, params: DidSaveTextDocumentParams):
if ls.getWorkspaceConfiguration().await().checkOnSave.get(true):
debug "Checking project", uri = uri
traceAsyncErrors ls.checkProject(uri)

var toStop = newTable[string, Nimsuggest]()
#We first get the project file for the current file so we can test if this file recently imported another project
let thisProjectFile = await getProjectFile(uri.uriToPath, ls)
let ns = await ls.projectFiles[thisProjectFile]
for projectFile in ls.projectFiles.keys:
if projectFile in ls.entryPoints: continue
let isKnown = await ns.isKnown(projectFile)
if isKnown:
toStop[projectFile] = await ls.projectFiles[projectFile]

for projectFile, ns in toStop:
ns.stop()
ls.projectFiles.del projectFile
ls.showMessage &"File {projectFile} is known by another nimsuggest instance, stopping the current one", MessageType.Warning

proc didClose(ls: LanguageServer, params: DidCloseTextDocumentParams):
Future[void] {.async, gcsafe.} =
Expand Down

0 comments on commit 85caa53

Please sign in to comment.