Auto completion for multi-line expressions

This commit is contained in:
Christopher Schleiden
2022-12-08 16:38:36 -08:00
parent 1af3f0b672
commit efe71dd684
3 changed files with 86 additions and 8 deletions
@@ -88,6 +88,64 @@ describe("expressions", () => {
]);
});
describe("multi-line strings", () => {
it("indented |", async () => {
const input = `on: push
jobs:
build:
steps:
- run: |
first line
test \${{ github.| }}
test2`;
const result = await complete(...getPositionFromCursor(input, 1), undefined, contextProviderConfig);
expect(result.map(x => x.label)).toEqual(["event"]);
});
it("indented |+", async () => {
const input = `on: push
jobs:
build:
steps:
- run: |+
first line
test \${{ github.| }}
test2`;
const result = await complete(...getPositionFromCursor(input, 1), undefined, contextProviderConfig);
expect(result.map(x => x.label)).toEqual(["event"]);
});
it("indented >", async () => {
const input = `on: push
jobs:
build:
steps:
- run: >
first line
test \${{ github.| }}
test2`;
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
expect(result.map(x => x.label)).toEqual(["event"]);
});
it("indented >+", async () => {
const input = `on: push
jobs:
build:
steps:
- run: >+
first line
test \${{ github.| }}
test2`;
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
expect(result.map(x => x.label)).toEqual(["event"]);
});
});
it("nested auto-complete", async () => {
const input = "run-name: ${{ github.| }}";
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
+11 -3
View File
@@ -9,7 +9,7 @@ import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/map
import {TokenType} from "@github/actions-workflow-parser/templates/tokens/types";
import {File} from "@github/actions-workflow-parser/workflows/file";
import {Position, TextDocument} from "vscode-languageserver-textdocument";
import {CompletionItem, TextEdit, Range} from "vscode-languageserver-types";
import {CompletionItem, Range, TextEdit} from "vscode-languageserver-types";
import {ContextProviderConfig} from "./context-providers/config";
import {getContext, Mode} from "./context-providers/default";
import {getWorkflowContext, WorkflowContext} from "./context/workflow-context";
@@ -77,10 +77,18 @@ export async function complete(
token.definition?.definitionType === DefinitionType.String && (token.definition as StringDefinition).isExpression;
const containsExpression = isString(token) && token.value.indexOf(OPEN_EXPRESSION) >= 0;
if (isString(token) && (isExpression || containsExpression)) {
const currentInput = token.value;
const currentInput = token.source || token.value;
// Transform the overall position into a node relative position
const relCharPos = newPos.character - token.range!.start[1];
let relCharPos: number = 0;
const lineDiff = newPos.line - token.range!.start[0];
if (token.range!.start[0] !== token.range!.end[0]) {
const lines = currentInput.split("\n");
const linesBeforeCusor = lines.slice(0, lineDiff);
relCharPos = linesBeforeCusor.join("\n").length + newPos.character;
} else {
relCharPos = newPos.character - token.range!.start[1];
}
const expressionInput = (getExpressionInput(currentInput, relCharPos) || "").trim();
@@ -1,18 +1,30 @@
import {Position, TextDocument} from "vscode-languageserver-textdocument";
import {createDocument} from "./document";
// Calculates the position of the cursor and the document without that cursor
// Cursor is represented by a `|` character
export function getPositionFromCursor(input: string): [TextDocument, Position] {
/**
* Calculates the position of the cursor and the document without that cursor
* Cursor is represented by a `|` character
* @param input Input string
* @param skip Instances of `|` to skip
*/
export function getPositionFromCursor(input: string, skip = 0): [TextDocument, Position] {
const doc = createDocument("test.yaml", input);
const cursorIndex = doc.getText().indexOf("|");
let cursorIndex = doc.getText().indexOf("|");
for (let i = 0; i < skip && cursorIndex !== -1; i++) {
cursorIndex = doc.getText().indexOf("|", cursorIndex + 1);
}
if (cursorIndex === -1) {
throw new Error("No cursor found in document");
}
// Replace only the last occurence of | in string
let newText = doc.getText();
newText = newText.substring(0, cursorIndex) + newText.substring(cursorIndex + 1);
const position = doc.positionAt(cursorIndex);
const newDoc = TextDocument.create(doc.uri, doc.languageId, doc.version, doc.getText().replace("|", ""));
const newDoc = TextDocument.create(doc.uri, doc.languageId, doc.version, newText);
return [newDoc, position];
}