Skip to content

Commit aefb4ed

Browse files
authored
adds extension/tasks which returns all nimble tasks for the current project (#256)
* adds `extension/tasks` which returns all nimble tasks for the current project * remove comment * Better task parsing * better parsing
1 parent 5ccf289 commit aefb4ed

File tree

10 files changed

+134
-31
lines changed

10 files changed

+134
-31
lines changed

nimlangserver.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ proc registerRoutes(srv: RpcSocketServer, ls: LanguageServer) =
6464
srv.register("extension/status", wrapRpc(partial(status, ls)))
6565
srv.register("extension/capabilities", wrapRpc(partial(extensionCapabilities, ls)))
6666
srv.register("extension/suggest", wrapRpc(partial(extensionSuggest, ls)))
67+
srv.register("extension/tasks", wrapRpc(partial(tasks, ls)))
6768

6869
#Notifications
6970
srv.register("$/cancelRequest", wrapRpc(partial(cancelRequest, ls)))

protocol/types.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,3 +1030,7 @@ type
10301030

10311031
SuggestResult* = object
10321032
actionPerformed*: SuggestAction
1033+
1034+
NimbleTask* = object
1035+
name*: string
1036+
description*: string

routes.nim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,31 @@ proc exit*(
753753
result = newJNull()
754754
await p.onExit()
755755
756+
proc tasks*(
757+
ls: LanguageServer, conf: JsonNode
758+
): Future[seq[NimbleTask]] {.async, gcsafe.} =
759+
let rootPath: string = ls.initializeParams.getRootPath
760+
761+
debug "Received tasks ", rootPath = rootPath
762+
delEnv "NIMBLE_DIR"
763+
let process = await startProcess(
764+
"nimble",
765+
arguments = @["tasks"],
766+
options = {UsePath},
767+
workingDir = rootPath,
768+
stdoutHandle = AsyncProcess.Pipe,
769+
stderrHandle = AsyncProcess.Pipe,
770+
)
771+
let res =
772+
await process.waitForExit(InfiniteDuration) #TODO handle error (i.e. no nimble file)
773+
let output = await process.stdoutStream.readLine()
774+
var name, desc: string
775+
for line in output.splitLines:
776+
if scanf(line, "$+ $*", name, desc):
777+
#first run of nimble tasks can compile nim and output the result of the compilation
778+
if name.isWord:
779+
result.add NimbleTask(name: name.strip(), description: desc.strip())
780+
756781
#Notifications
757782
proc initialized*(ls: LanguageServer, _: JsonNode): Future[void] {.async.} =
758783
debug "Client initialized."

tests/projects/tasks/src/tasks.nim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# This is just an example to get you started. A typical hybrid package
2+
# uses this file as the main entry point of the application.
3+
4+
import tasks/submodule
5+
6+
when isMainModule:
7+
echo(getWelcomeMessage())
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# This is just an example to get you started. Users of your hybrid library will
2+
# import this file by writing ``import taskspkg/submodule``. Feel free to rename or
3+
# remove this file altogether. You may create additional modules alongside
4+
# this file as required.
5+
6+
proc getWelcomeMessage*(): string = "Hello, World!"

tests/projects/tasks/tasks.nimble

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Package
2+
3+
version = "0.1.0"
4+
author = "jmgomez"
5+
description = "A new awesome nimble package"
6+
license = "MIT"
7+
srcDir = "src"
8+
installExt = @["nim"]
9+
bin = @["tasks"]
10+
11+
12+
# Dependencies
13+
14+
requires "nim >= 2.1.99"
15+
16+
task helloWorld, "hello world":
17+
echo "helo world"
18+
19+
task anotherTask, "Another task":
20+
echo "another task"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
switch("path", "$projectDir/../src")

tests/projects/tasks/tests/test1.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This is just an example to get you started. You may wish to put all of your
2+
# tests into a single file, or separate them into multiple `test1`, `test2`
3+
# etc. files (better names are recommended, just make sure the name starts with
4+
# the letter 't').
5+
#
6+
# To run these tests, simply execute `nimble test`.
7+
8+
import unittest
9+
10+
import tasks/submodule
11+
test "correct welcome":
12+
check getWelcomeMessage() == "Hello, World!"

tests/textensions.nim

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,80 @@
1-
import ../[
2-
nimlangserver, ls, lstransports, utils
3-
]
1+
import ../[nimlangserver, ls, lstransports, utils]
42
import ../protocol/[enums, types]
5-
import std/[options, unittest, json, os, jsonutils, sequtils, strutils, sugar, strformat]
3+
import
4+
std/[options, unittest, json, os, jsonutils, sequtils, strutils, sugar, strformat]
65
import json_rpc/[rpcclient]
76
import chronicles
87
import lspsocketclient
98
import chronos/asyncproc
109

11-
1210
suite "Nimlangserver":
1311
let cmdParams = CommandLineParams(transport: some socket, port: getNextFreePort())
1412
let ls = main(cmdParams) #we could accesss to the ls here to test against its state
1513
let client = newLspSocketClient()
1614
waitFor client.connect("localhost", cmdParams.port)
1715
client.registerNotification(
18-
"window/showMessage",
19-
"window/workDoneProgress/create",
20-
"workspace/configuration",
21-
"extension/statusUpdate",
22-
"textDocument/publishDiagnostics",
23-
"$/progress"
24-
)
25-
16+
"window/showMessage", "window/workDoneProgress/create", "workspace/configuration",
17+
"extension/statusUpdate", "textDocument/publishDiagnostics", "$/progress",
18+
)
19+
2620
test "calling extension/suggest with restart in the project uri should restart nimsuggest":
27-
let initParams = InitializeParams %* {
21+
let initParams =
22+
InitializeParams %* {
2823
"processId": %getCurrentProcessId(),
2924
"rootUri": fixtureUri("projects/hw/"),
30-
"capabilities": {
31-
"window": {
32-
"workDoneProgress": true
33-
},
34-
"workspace": {"configuration": true}
35-
}
36-
}
25+
"capabilities":
26+
{"window": {"workDoneProgress": true}, "workspace": {"configuration": true}},
27+
}
3728
let initializeResult = waitFor client.initialize(initParams)
38-
29+
3930
check initializeResult.capabilities.textDocumentSync.isSome
4031

4132
let helloWorldUri = fixtureUri("projects/hw/hw.nim")
42-
let helloWorldFile = "projects/hw/hw.nim"
33+
let helloWorldFile = "projects/hw/hw.nim"
4334
let hwAbsFile = uriToPath(helloWorldFile.fixtureUri())
4435
client.notify("textDocument/didOpen", %createDidOpenParams(helloWorldFile))
4536

46-
let progressParam = %ProgressParams(token: fmt "Creating nimsuggest for {hwAbsFile}")
47-
check waitFor client.waitForNotification("$/progress", (json: JsonNode) => progressParam["token"] == json["token"])
48-
check waitFor client.waitForNotification("$/progress", (json: JsonNode) => json["value"]["kind"].getStr == "begin")
49-
check waitFor client.waitForNotification("$/progress", (json: JsonNode) => json["value"]["kind"].getStr == "end")
37+
let progressParam =
38+
%ProgressParams(token: fmt "Creating nimsuggest for {hwAbsFile}")
39+
check waitFor client.waitForNotification(
40+
"$/progress", (json: JsonNode) => progressParam["token"] == json["token"]
41+
)
42+
check waitFor client.waitForNotification(
43+
"$/progress", (json: JsonNode) => json["value"]["kind"].getStr == "begin"
44+
)
45+
check waitFor client.waitForNotification(
46+
"$/progress", (json: JsonNode) => json["value"]["kind"].getStr == "end"
47+
)
48+
49+
client.notify(
50+
"textDocument/didOpen", %createDidOpenParams("projects/hw/useRoot.nim")
51+
)
5052

51-
client.notify("textDocument/didOpen",
52-
%createDidOpenParams("projects/hw/useRoot.nim"))
53-
5453
let prevSuggestPid = ls.projectFiles[hwAbsFile].process.pid
5554
let suggestParams = SuggestParams(action: saRestart, projectFile: hwAbsFile)
5655
let suggestRes = client.call("extension/suggest", %suggestParams).waitFor
5756
let suggestPid = ls.projectFiles[hwAbsFile].process.pid
5857

5958
check prevSuggestPid != suggestPid
60-
59+
60+
test "calling extension/tasks should return all existing tasks":
61+
let initParams =
62+
InitializeParams %* {
63+
"processId": %getCurrentProcessId(),
64+
"rootUri": fixtureUri("projects/tasks/"),
65+
"capabilities":
66+
{"window": {"workDoneProgress": true}, "workspace": {"configuration": true}},
67+
}
68+
let initializeResult = waitFor client.initialize(initParams)
69+
70+
let tasksFile = "projects/tasks/src/tasks.nim"
71+
let taskAbsFile = uriToPath(tasksFile.fixtureUri())
72+
client.notify("textDocument/didOpen", %createDidOpenParams(tasksFile))
73+
74+
let tasks = client.call("extension/tasks", jsonutils.toJson(())).waitFor().jsonTo(
75+
seq[NimbleTask]
76+
)
77+
78+
check tasks.len == 2
79+
check tasks[0].name == "helloWorld"
80+
check tasks[0].description == "hello world"

utils.nim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,10 @@ proc getNextFreePort*(): Port =
300300
let (_, port) = s.getLocalAddr
301301
s.close()
302302
port
303+
304+
func isWord*(str: string): bool =
305+
var str = str.toLower()
306+
for c in str:
307+
if c.int notin 97 .. 122:
308+
return false
309+
return true

0 commit comments

Comments
 (0)