Skip to content

Adds nimsuggest idle timeout. #251

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Oct 1, 2024
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

21 changes: 21 additions & 0 deletions ls.nim
Original file line number Diff line number Diff line change
@@ -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]
@@ -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
@@ -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()
14 changes: 8 additions & 6 deletions suggestapi.nim
Original file line number Diff line number Diff line change
@@ -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
@@ -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
@@ -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
@@ -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]()
@@ -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:
9 changes: 6 additions & 3 deletions utils.nim
Original file line number Diff line number Diff line change
@@ -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

Loading