A project's packages, and diagnostics at their column
A file in a project is checked against the packages bjo fetched for it: the server installs the project's .bjo/roots, .bjo/frameworks and .bjo/nuget/root before its first check, through the compiler's ProjectInputs, so imports from packages check and definition, hover and completion reach them. A server serves one project, the first file's; a warning on a file's first line says when it cannot serve one as bjo would: packages not fetched, the roots changed since it started, or another project. The server no longer has the old Microsoft.Extensions.DependencyInjection .Abstractions next to it. The compiler excludes it, the exclusion does not pass through a project reference, and with it there every ASP.NET type failed to load, so bjoweb did not check. A diagnostic marks the form at the line and column the compiler names now: an atom or a string whole, a bracketed form to its closing bracket, and one over several lines as far as its head. The build no longer asks git for Source Link, which fails on this repository's SHA-256 objects. 🤖 Generated with [ECA](https://eca.dev) (anthropic/claude-opus-5-5) Co-Authored-By: eca-agent <git@eca.dev>
This commit is contained in:
parent
77b8a92e03
commit
cc62a8a360
6 changed files with 362 additions and 15 deletions
|
|
@ -566,6 +566,91 @@ def expanding(server, tmp):
|
|||
server.diagnostics_after("textDocument/didClose", uri)
|
||||
|
||||
|
||||
GREET = """(import (std prelude))
|
||||
|
||||
(export greet)
|
||||
|
||||
;; Says hello.
|
||||
(: greet (-> string string))
|
||||
(defun (greet name) (string-append "hello, " name))
|
||||
"""
|
||||
|
||||
USES_GREET = """(import (std prelude))
|
||||
(import (mylib greet))
|
||||
|
||||
(: main (-> (Vec string) int))
|
||||
(defun (main args)
|
||||
(println (greet "you"))
|
||||
0)
|
||||
"""
|
||||
|
||||
|
||||
def packages():
|
||||
"""A project's packages, as `bjo` wrote them into its `.bjo/roots`. Each
|
||||
case has a server of its own, as one serves the project of the first file
|
||||
it is asked about."""
|
||||
|
||||
def started():
|
||||
server = Server()
|
||||
server.send("initialize", {"processId": None, "rootUri": None, "capabilities": {}}, request=True)
|
||||
server.send("initialized")
|
||||
return server
|
||||
|
||||
def stopped(server):
|
||||
server.send("shutdown", request=True)
|
||||
server.send("exit")
|
||||
server.proc.wait(timeout=10)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
lib = os.path.join(tmp, "mylib", "src")
|
||||
project = os.path.join(tmp, "app")
|
||||
os.makedirs(lib)
|
||||
os.makedirs(os.path.join(project, "src"))
|
||||
os.makedirs(os.path.join(project, ".bjo"))
|
||||
with open(os.path.join(lib, "greet.bjo"), "w") as f:
|
||||
f.write(GREET)
|
||||
with open(os.path.join(project, "manifest.bjodat"), "w") as f:
|
||||
f.write('(package (name (app)) (version "0.1.0"))\n')
|
||||
with open(os.path.join(project, ".bjo", "roots"), "w") as f:
|
||||
f.write(f'(roots (root (mylib) "{lib}"))\n')
|
||||
path = os.path.join(project, "src", "main.bjo")
|
||||
uri = "file://" + path
|
||||
with open(path, "w") as f:
|
||||
f.write(USES_GREET)
|
||||
|
||||
server = started()
|
||||
found = server.diagnostics_after("textDocument/didOpen", uri, USES_GREET)
|
||||
expect("packages: an import from the project's packages checks", found == [], json.dumps(found, indent=1))
|
||||
|
||||
at = position_of(USES_GREET, '(greet "you")')
|
||||
d = server.send(
|
||||
"textDocument/definition", {"textDocument": {"uri": uri}, "position": at}, request=True
|
||||
)["result"]
|
||||
expect(
|
||||
"packages: go to definition reaches the package",
|
||||
d and d["uri"] == "file://" + os.path.join(lib, "greet.bjo"),
|
||||
d,
|
||||
)
|
||||
items = server.send(
|
||||
"textDocument/completion",
|
||||
{"textDocument": {"uri": uri}, "position": position_of(USES_GREET, '(greet "you")', 0, 4)},
|
||||
request=True,
|
||||
)["result"]["items"]
|
||||
expect("packages: completion offers the package's names", any(i["label"] == "greet" for i in items))
|
||||
stopped(server)
|
||||
|
||||
# The same project before `bjo fetch`: the server says what to do.
|
||||
os.remove(os.path.join(project, ".bjo", "roots"))
|
||||
server = started()
|
||||
found = server.diagnostics_after("textDocument/didOpen", uri, USES_GREET)
|
||||
expect(
|
||||
"packages: unfetched, a warning says to run bjo fetch",
|
||||
any(d["severity"] == 2 and "bjo fetch" in d["message"] for d in found),
|
||||
json.dumps(found, indent=1),
|
||||
)
|
||||
stopped(server)
|
||||
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = os.path.join(tmp, "smoke.bjo")
|
||||
uri = "file://" + path
|
||||
|
|
@ -584,6 +669,17 @@ with tempfile.TemporaryDirectory() as tmp:
|
|||
any(d["range"]["start"]["line"] == 4 for d in found),
|
||||
json.dumps(found, indent=1),
|
||||
)
|
||||
# `(+ 1 "two")`: the compiler says the column of the `1`, and the form
|
||||
# there is what is marked.
|
||||
expect(
|
||||
"at its column, marking the form there",
|
||||
any(
|
||||
d["range"]["start"] == {"line": 4, "character": 5}
|
||||
and d["range"]["end"] == {"line": 4, "character": 6}
|
||||
for d in found
|
||||
),
|
||||
json.dumps(found, indent=1),
|
||||
)
|
||||
for d in found:
|
||||
print(" ", d["range"]["start"], d["message"].splitlines()[0])
|
||||
|
||||
|
|
@ -626,4 +722,6 @@ with tempfile.TemporaryDirectory() as tmp:
|
|||
server.send("exit")
|
||||
expect("exit ends the process with 0", server.proc.wait(timeout=10) == 0)
|
||||
|
||||
packages()
|
||||
|
||||
sys.exit(1 if failures else 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue