Skip to content

Commit

Permalink
Add utility function for lsp macro completion
Browse files Browse the repository at this point in the history
  • Loading branch information
siefkenj committed Nov 30, 2023
1 parent 0bbcbe3 commit cbb9836
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 5 deletions.
7 changes: 7 additions & 0 deletions packages/lsp-tools/src/auto-completer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { doenetSchema } from "@doenet/static-assets";
import { DastAttribute, DastElement } from "@doenet/parser";
import { getCompletionItems } from "./methods/get-completion-items";
import { getSchemaViolations } from "./methods/get-schema-violations";
import { getCompletionContext } from "./methods/get-completion-context";

type ElementSchema = {
name: string;
Expand Down Expand Up @@ -99,6 +100,12 @@ export class AutoCompleter {
*/
getSchemaViolations = getSchemaViolations;

/**
* Get context about the current cursor position to determine whether completions should be offered or not,
* and what type of completions should be offered.
*/
getCompletionContext = getCompletionContext;

/**
* Get the children allowed inside an `elementName` named element.
* The search is case insensitive.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { RowCol } from "../../doenet-source-object";
import { DastMacro, showCursor } from "@doenet/parser";
import { AutoCompleter } from "..";

export type CompletionContext =
| { cursorPos: "body" }
| { cursorPos: "element"; complete: boolean; }
| { cursorPos: "macro"; complete: boolean;node: DastMacro | null };

/**
* Get context about the current cursor position to determine whether completions should be offered or not,
* and what type of completions should be offered.
*/
export function getCompletionContext(
this: AutoCompleter,
offset: number | RowCol,
): CompletionContext {
if (typeof offset !== "number") {
offset = this.sourceObj.rowColToOffset(offset);
}

const prevChar = this.sourceObj.source.charAt(offset - 1);
const prevPrevChar = this.sourceObj.source.charAt(offset - 2);
const nextChar = this.sourceObj.source.charAt(offset + 1);
let prevNonWhitespaceCharOffset = offset - 1;
while (
this.sourceObj.source
.charAt(prevNonWhitespaceCharOffset)
.match(/(\s|\n)/)
) {
prevNonWhitespaceCharOffset--;
}
const prevNonWhitespaceChar = this.sourceObj.source.charAt(
prevNonWhitespaceCharOffset,
);

const leftNode = this.sourceObj.nodeAtOffset(offset, {side:"left"});

// Check for status inside a macro
let macro = this.sourceObj.nodeAtOffset(offset, {
type: "macro",
side: "left",
});
if (!macro && (prevChar === "." || prevChar === "[") && prevPrevChar !== ")") {
macro = this.sourceObj.nodeAtOffset(offset - 1, {
type: "macro",
side: "left",
});
}
if (macro) {
// Since macros are terminal, if the node to our immediate left is a macro,
// the macro is complete.
const complete = leftNode?.type === "macro";
return { cursorPos: "macro", complete, node: macro };
}

return { cursorPos: "body" };
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ export function getCompletionItems(

const { tagComplete, closed } = this.sourceObj.isCompleteElement(element);

console.log({ tagComplete, closed, element: element.name });

if (
cursorPosition === "body" &&
containingElement.node &&
Expand Down
4 changes: 2 additions & 2 deletions packages/lsp-tools/src/dev-site.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ function App() {
console.log(
{ currentPos },
sourceObj.elementAtOffsetWithContext(currentPos),
"elm2 left", sourceObj.elementAtOffset(currentPos, {side: "left"})?.name || null,
"elm2 right", sourceObj.elementAtOffset(currentPos, {side: "right"})?.name || null,
"elm2 left", sourceObj.nodeAtOffset(currentPos, {side: "left"})?.type || null,
"elm2 right", sourceObj.nodeAtOffset(currentPos, {side: "right"})?.type || null,
sourceObj.attributeAtOffset(currentPos),
completionObj.getCompletionItems(currentPos),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
export function nodeAtOffset<const T extends DastNodes["type"]>(
this: DoenetSourceObject,
offset: number | RowCol,
options?: { type: T; side?: "left" | "right" },
options?: { type?: T; side?: "left" | "right" },
): Extract<DastNodes, { type: T }> | null {
let { type, side = "right" } = options || {};
if (typeof offset !== "number") {
Expand Down
29 changes: 29 additions & 0 deletions packages/lsp-tools/test/doenet-auto-complete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,33 @@ describe("AutoCompleter", () => {
`);
}
});
it("Can get completion context", () => {
let source: string;
let autoCompleter: AutoCompleter;

source = ` $foo.bar. `;
autoCompleter = new AutoCompleter(source, schema.elements);
{
let offset = 0;
let elm = autoCompleter.getCompletionContext(offset);
expect(elm).toEqual({
cursorPos: "body",
});

offset = source.indexOf("$foo") + 4;
elm = autoCompleter.getCompletionContext(offset);
expect(elm).toMatchObject({
complete: true,
cursorPos: "macro",
});

// Matching at the . following the macro.
offset = source.indexOf("bar") + 4;
elm = autoCompleter.getCompletionContext(offset);
expect(elm).toMatchObject({
complete: false,
cursorPos: "macro",
});
}
});
});

0 comments on commit cbb9836

Please sign in to comment.