Skip to content

Commit

Permalink
Adds nimsuggest idle timeout.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmgomez committed Sep 30, 2024
1 parent ed6cc74 commit a1a7105
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Note when in a nimble project, `nimble` will drive the entry points for `nimsugg
- `nim.inlayHints` - configure inlay hints.
- `nim.notificationVerbosity` - configure the verbosity of notifications. Can be set to `"none"`, `"error"`, `"warning"`, or `"info"`.
- `nim.formatOnSave` - format the file on save. Requires `nph` to be available in the PATH.
- `nim.nimsuggestIdleTimeout` - the timeout in ms after which an idle `nimsuggest` will be stopped. If not specified the default is 120 seconds.

## Features

Expand Down
21 changes: 21 additions & 0 deletions ls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type
inlayHints*: Option[NlsInlayHintsConfig]
notificationVerbosity*: Option[NlsNotificationVerbosity]
formatOnSave*: Option[bool]
nimsuggestIdleTimeout*: Option[int] #idle timeout in ms

NlsFileInfo* = ref object of RootObj
projectFile*: Future[string]
Expand Down Expand Up @@ -918,7 +919,27 @@ proc removeCompletedPendingRequests(
for id in toRemove:
ls.pendingRequests.del id

proc removeIdleNimsuggests*(ls: LanguageServer) {.async.} =
const DefaultNimsuggestIdleTimeout = 120000
let timeout = ls.getWorkspaceConfiguration().await().nimsuggestIdleTimeout.get(DefaultNimsuggestIdleTimeout)
var toStop = newSeq[Project]()
for project in ls.projectFiles.values:
if project.file in ls.entryPoints: #we only remove non entry point nimsuggests
continue
if project.lastCmdDate.isSome:
let passedTime = now() - project.lastCmdDate.get()
if passedTime.inMilliseconds > timeout:
toStop.add(project)

for project in toStop:
debug "Removing idle nimsuggest", project = project.file
project.errorCallback = none(ProjectCallback)
project.stop()
ls.projectFiles.del(project.file)
ls.showMessage(fmt"Nimsuggest for {project.file} was stopped because it was idle for too long",MessageType.Info)

proc tick*(ls: LanguageServer): Future[void] {.async.} =
# debug "Ticking at ", now = now(), prs = ls.pendingRequests.len
ls.removeCompletedPendingRequests()
await ls.removeIdleNimsuggests()
ls.sendStatusChanged
2 changes: 1 addition & 1 deletion routes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ proc extensionSuggest*(
return SuggestResult()
template restart(ls: LanguageServer, project: Project) =
ls.showMessage(fmt "Restarting nimsuggest {projectFile}", MessageType.Info)
project.errorCallback = nil
project.errorCallback = none(ProjectCallback)
project.stop()
ls.createOrRestartNimsuggest(projectFile, projectFile.pathToUri)
ls.sendStatusChanged()
Expand Down
14 changes: 8 additions & 6 deletions suggestapi.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ type
ideType
ideExpand

NimsuggestCallback = proc(self: Nimsuggest): void {.gcsafe, raises: [].}
ProjectCallback = proc(self: Project): void {.gcsafe, raises: [].}
NimsuggestCallback* = proc(self: Nimsuggest): void {.gcsafe, raises: [].}
ProjectCallback* = proc(self: Project): void {.gcsafe, raises: [].}

Suggest* = ref object
section*: IdeCmd
Expand Down Expand Up @@ -111,10 +111,11 @@ type
ns*: Future[NimSuggest]
file*: string
process*: AsyncProcessRef
errorCallback*: ProjectCallback
errorCallback*: Option[ProjectCallback]
errorMessage*: string
failed*: bool
lastCmd*: string
lastCmdDate*: Option[DateTime]

func canHandleUnknown*(ns: Nimsuggest): bool =
nsUnknownFile in ns.capabilities
Expand Down Expand Up @@ -262,8 +263,8 @@ proc name*(sug: Suggest): string =
proc markFailed(self: Project, errMessage: string) {.raises: [].} =
self.failed = true
self.errorMessage = errMessage
if self.errorCallback != nil:
self.errorCallback(self)
if self.errorCallback.isSome:
self.errorCallback.get()(self)

proc stop*(self: Project) =
debug "Stopping nimsuggest for ", root = self.file
Expand Down Expand Up @@ -348,7 +349,7 @@ proc createNimsuggest*(
): Future[Project] {.async, gcsafe.} =
result = Project(file: root)
result.ns = newFuture[NimSuggest]()
result.errorCallback = errorCallback
result.errorCallback = some errorCallback

let ns = Nimsuggest()
ns.requestQueue = Deque[SuggestCall]()
Expand Down Expand Up @@ -415,6 +416,7 @@ proc processQueue(self: Nimsuggest): Future[void] {.async.} =
while self.requestQueue.len != 0:
let req = self.requestQueue.popFirst
self.project.lastCmd = req.commandString
self.project.lastCmdDate = some(now())
logScope:
command = req.commandString
if req.future.finished:
Expand Down
9 changes: 6 additions & 3 deletions utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,12 @@ proc catchOrQuit*(error: Exception) =

proc writeStackTrace*(ex = getCurrentException()) =
try:
stderr.write "An exception occured \n"
stderr.write ex.msg & "\n"
stderr.write ex.getStackTrace()
if ex != nil:
stderr.write "An exception occured \n"
stderr.write ex.msg & "\n"
stderr.write ex.getStackTrace()
else:
stderr.write getStackTrace()
except IOError:
discard

Expand Down

0 comments on commit a1a7105

Please sign in to comment.