Skip to content
Draft
Show file tree
Hide file tree
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
26 changes: 26 additions & 0 deletions lang/src/arr/compiler/query.arr
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,32 @@ fun jump-to-def(cache-manager, uri :: String, line :: Number, col :: Number) ->
end
end

# this is a lot like jump-to-def
type HoverResult = { name :: String, docstring :: String, ann :: A.Ann }

fun hover(cache-manager, uri :: String, line :: Number, col :: Number) -> E.Either<String, HoverResult>:
cases(Option) cache-manager.get-surface-ast(uri):
| none => E.left("AST not available")
| some(ast) =>
cases(Option) cache-manager.get-named-result(uri):
| none => E.left("Resolved AST not available")
| some(named-result) =>
cases(Option) find-name-at(ast, line, col):
| none => E.left("Did not select a name")
| some(name) =>
cases(Option) find-name-key-by-srcloc(named-result.ast, name.l):
| none => E.left("Post-resolution name not found")
| some(key) =>
cases(Option) named-result.env.bindings.get-now(key):
| none => E.left("No value identifier binding found")
| some(vb) => E.right({ name: name.toname(), docstring: vb.doc, ann: vb.ann })
end
end
end
end
end
end

fun document-symbols(cache-manager, uri :: String)
-> E.Either<String, List<{String; String; S.Srcloc}>>:
cases(Option) cache-manager.get-named-result(uri):
Expand Down
25 changes: 25 additions & 0 deletions lang/src/arr/compiler/server.arr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import js-file("server") as S
import file("./cli-module-loader.arr") as CLI
import file("./compile-structs.arr") as CS
import file("./compile-lib.arr") as CL
import ast as A
import file("./query.arr") as Q
import file("locators/builtin.arr") as B

Expand Down Expand Up @@ -166,6 +167,10 @@ fun on-query(pyret-dir, cache-manager, query, compile-opts, query-opts, send-mes
line = query-opts.get-value("line")
col = query-opts.get-value("col")
Q.jump-to-def(cache-manager, base-uri, line, col)
| query == "hover" then:
line = query-opts.get-value("line")
col = query-opts.get-value("col")
Q.hover(cache-manager, base-uri, line, col)
| query == "document-symbols" then:
Q.document-symbols(cache-manager, base-uri)
| query == "check" then:
Expand Down Expand Up @@ -218,6 +223,26 @@ fun on-query(pyret-dir, cache-manager, query, compile-opts, query-opts, send-mes
]
send-message(J.j-obj(d).serialize())
end
| query == "hover" then:
cases(E.Either) info-result block:
| left(error-str) =>
err("hover: no result (errors: " + error-str + ")\n")
d = [SD.string-dict: "type", J.j-str("hover-failure")]
send-message(J.j-obj(d).serialize())
| right(hover-info) =>
ann-json = if A.is-a-blank(hover-info.ann):
J.j-null
else:
J.j-str(hover-info.ann.tosource().pretty(40).join-str("\n"))
end
d = [SD.string-dict:
"type", J.j-str("hover-success"),
"name", J.j-str(hover-info.name),
"ann", ann-json,
"doc", J.j-str(hover-info.docstring),
]
send-message(J.j-obj(d).serialize())
end
| query == "document-symbols" then:
cases(E.Either) info-result block:
| left(error-str) =>
Expand Down
1 change: 1 addition & 0 deletions lang/src/arr/trove/ast.arr
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,7 @@ data Expr:
method tosource(self): PP.str("!") + self.id.tosource() end
| s-id-letrec(l :: Loc, id :: Name, safe :: Boolean) with:
method label(self): "s-id-letrec" end,
# This is not actually to-source! There is a difference between tosource and pretty-print
method tosource(self): PP.str("~") + self.id.tosource() end
| s-id-var-modref(l :: Loc, id :: Name, uri :: String, name :: String) with:
method label(self): "s-id-var-modref" end,
Expand Down
63 changes: 63 additions & 0 deletions lsp/src/server-node-tmp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ connection.onInitialize(async (_params) => {
const capabilities: ServerCapabilities = {
textDocumentSync: TextDocumentSyncKind.Incremental,
definitionProvider: true,
hoverProvider: true,
documentSymbolProvider: true,
diagnosticProvider: {
interFileDependencies: false,
Expand Down Expand Up @@ -312,6 +313,8 @@ function sendCheckRequest(
}

// #region LSP request handlers
// TODO: there is a lot of redundancy here, we should probably develop better
// abstractions here! especially for the off-by-one location issues (hacked in rn)

connection.onDocumentSymbol(async (params) => {
const portFile = getSocketPath();
Expand Down Expand Up @@ -365,6 +368,7 @@ connection.onDefinition(async (params) => {
}

// LSP positions are 0-indexed; Pyret srclocs are 1-indexed
// TODO: fix these awful off-by-one errors!
const line = params.position.line + 1;
const col = params.position.character + 1;
const filePath = uriToFilePath(params.textDocument.uri);
Expand All @@ -386,6 +390,65 @@ connection.onDefinition(async (params) => {
}
});

interface HoverResult {
name: string;
ann: string;
doc: string;
}

function parseHover(msg: any): HoverResult | null {
if (msg.type === "hover-success") {
return { name: msg.name, ann: msg.ann, doc: msg.doc };
}
return null;
}

connection.onHover(async (params) => {
const portFile = getSocketPath();
if (!fs.existsSync(portFile)) {
connection.console.error("Pyret server not running, cannot get hover info");
return null;
}

const line = params.position.line + 1;
const col = params.position.character + 1;
const filePath = uriToFilePath(params.textDocument.uri);

try {
const result = await sendQueryRequest(
portFile,
"hover",
filePath,
{ line, col },
parseHover,
);
if (!result) return null;

const parts: string[] = [];
if (result.ann) {
parts.push(`\`\`\`pyret\n${result.name} :: ${result.ann}\n\`\`\``);
}
if (result.doc) {
if (result.ann) {
parts.push(result.doc);
} else {
parts.push(`${result.name}: ${result.doc}`);
}
}
if (parts.length === 0) return null;

return {
contents: {
kind: "markdown",
value: parts.join("\n\n"),
},
};
} catch (err) {
connection.console.error(`hover error: ${err}`);
return null;
}
});

const documents = new TextDocuments(TextDocument);

// Track the document version at last save per URI. VS Code triggers
Expand Down
7 changes: 7 additions & 0 deletions vscode/sampleFiles/lsp/hover.arr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ end

not-zero

fun doc-no-ann(asd):
doc: "hi mom"
asd
end

doc-no-ann

div-refine :: Number, Number%(not-zero) -> Number
fun div-refine(num, den):
doc: "divides the things"
Expand Down