diff --git a/actions-languageservice/src/complete.test.ts b/actions-languageservice/src/complete.test.ts index bf10a08..910da01 100644 --- a/actions-languageservice/src/complete.test.ts +++ b/actions-languageservice/src/complete.test.ts @@ -157,7 +157,7 @@ jobs: const result = await complete(...getPositionFromCursor(input)); expect(result).not.toBeUndefined(); - expect(result.length).toEqual(0); + expect(result.length).toEqual(17); }); it("custom value providers override defaults", async () => { @@ -202,4 +202,25 @@ jobs: expect(result).not.toBeUndefined(); expect(result.map(x => x.label).sort()).toEqual(["cancel-in-progress", "group"]); }); + + it("job key", async () => { + const input = `on: push +jobs: + build: + runs-|`; + const result = await complete(...getPositionFromCursor(input)); + expect(result).not.toBeUndefined(); + expect(result).toHaveLength(20); + }); + + it("job key with comment afterwards", async () => { + const input = `on: push +jobs: + build: + runs-| + #`; + const result = await complete(...getPositionFromCursor(input)); + expect(result).not.toBeUndefined(); + expect(result).toHaveLength(20); + }); }); diff --git a/actions-languageservice/src/utils/find-token.test.ts b/actions-languageservice/src/utils/find-token.test.ts index 20f0dec..1325fb4 100644 --- a/actions-languageservice/src/utils/find-token.test.ts +++ b/actions-languageservice/src/utils/find-token.test.ts @@ -95,4 +95,83 @@ jo|bs: token: [null, TokenType.String, "jobs"] }); }); + + it("value in job", () => { + expect( + testFindToken(`on: push +jobs: + build: + runs-on: ubu|`) + ).toEqual({ + parent: ["job-factory", TokenType.Mapping], + key: [null, TokenType.String, "runs-on"], + token: ["runs-on", TokenType.String, "ubu"] + }); + }); + + it("key in job", () => { + expect( + testFindToken(`on: push +jobs: + build: + run|s-on: ubu`) + ).toEqual({ + parent: ["job-factory", TokenType.Mapping], + key: null, + token: [null, TokenType.String, "runs-on"] + }); + }); + + it("pos after colon in empty mapping", () => { + expect( + testFindToken(`on: push +jobs: + build: + continue-on-error:|`) + ).toEqual({ + parent: ["job-factory", TokenType.Mapping], + key: [null, TokenType.String, "continue-on-error"], + token: ["boolean-strategy-context", TokenType.Null, ""] + }); + }); + + it("pos after colon in mapping", () => { + expect( + testFindToken(`on: push +jobs: + build: + continue-on-error:|foo`) + ).toEqual({ + parent: ["jobs", TokenType.Mapping], + key: ["job-id", TokenType.String, "build"], + token: ["job", TokenType.String, "continue-on-error:foo"] + }); + }); + + it("pos in mapping key without comment", () => { + expect( + testFindToken(`on: push +jobs: + build: + runs-|`) + ).toEqual({ + parent: ["jobs", TokenType.Mapping], + key: ["job-id", TokenType.String, "build"], + token: ["job", TokenType.String, "runs-"] + }); + }); + + it("pos in mapping key before comment", () => { + expect( + testFindToken(`on: push +jobs: + build: + runs-| + #`) + ).toEqual({ + parent: ["jobs", TokenType.Mapping], + key: ["job-id", TokenType.String, "build"], + token: ["job", TokenType.String, "runs-"] + }); + }); }); diff --git a/actions-languageservice/src/utils/find-token.ts b/actions-languageservice/src/utils/find-token.ts index 5e95694..2bdf54b 100644 --- a/actions-languageservice/src/utils/find-token.ts +++ b/actions-languageservice/src/utils/find-token.ts @@ -69,25 +69,25 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult { if (posInToken(pos, key)) { return { - token: key, + parent: mappingToken, keyToken: null, - parent: mappingToken + token: key }; } // Empty nodes positions won't always match the cursor, so check if we're on the same line if (emptyNode(value)) { return { - token: value, - keyToken: null, - parent: key + parent: mappingToken, + keyToken: key, + token: value }; } s.push({ - token: value, + parent: mappingToken, keyToken: key, - parent: mappingToken + token: value }); } continue; @@ -96,9 +96,9 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult { const sequenceToken = token as SequenceToken; for (let i = 0; i < sequenceToken.count; i++) { s.push({ - token: sequenceToken.get(i), + parent: sequenceToken, keyToken: null, - parent: sequenceToken + token: sequenceToken.get(i) }); } continue; diff --git a/actions-languageservice/src/utils/transform.test.ts b/actions-languageservice/src/utils/transform.test.ts index e9b2339..b4200bd 100644 --- a/actions-languageservice/src/utils/transform.test.ts +++ b/actions-languageservice/src/utils/transform.test.ts @@ -13,6 +13,18 @@ jobs: expect(newPos.character).toEqual(11); }); + it("adds : at end of line with trailing comment", () => { + const [doc, pos] = getPositionFromCursor("on: push\njobs:\n build:\n runs-on| \n#"); + const [newDoc, newPos] = transform(doc, pos); + + expect(newDoc.getText()).toEqual(`on: push +jobs: + build: + runs-on: +#`); + expect(newPos.character).toEqual(11); + }); + it("adds placeholder node in empty sequence", () => { const [doc, pos] = getPositionFromCursor(`on: push jobs: diff --git a/actions-languageservice/src/utils/transform.ts b/actions-languageservice/src/utils/transform.ts index 4f8591e..a6c831d 100644 --- a/actions-languageservice/src/utils/transform.ts +++ b/actions-languageservice/src/utils/transform.ts @@ -1,4 +1,5 @@ import {Position, TextDocument} from "vscode-languageserver-textdocument"; +import {Range} from "vscode-languageserver-types"; const DUMMY_KEY = "dummy"; @@ -6,10 +7,21 @@ const DUMMY_KEY = "dummy"; // Based on `_transform` in https://github.com/cschleiden/github-actions-parser/blob/main/src/lib/parser/complete.ts#L311 export function transform(doc: TextDocument, pos: Position): [TextDocument, Position] { let offset = doc.offsetAt(pos); - let line = doc.getText({ + + const lineRange: Range = { start: {line: pos.line, character: 0}, end: {line: pos.line, character: Number.MAX_SAFE_INTEGER} - }); + }; + + let line = doc.getText(lineRange); + + // If the line includes a new-line char, strip that out + const newLinePos = line.indexOf("\n"); + if (newLinePos >= 0) { + line = line.substring(0, newLinePos); + } + lineRange.end.character = line.length; + const linePos = pos.character; // Special case for Actions, if this line contains an expression marker, do _not_ transform. This is @@ -34,7 +46,7 @@ export function transform(doc: TextDocument, pos: Position): [TextDocument, Posi offset++; } else if (!trimmedLine.startsWith("-")) { // Add `:` to end of line - line = line + ":"; + line = line.trimEnd() + ":"; } } else { offset = offset - 1; @@ -47,7 +59,7 @@ export function transform(doc: TextDocument, pos: Position): [TextDocument, Posi newDoc, [ { - range: {start: {line: pos.line, character: 0}, end: {line: pos.line, character: Number.MAX_SAFE_INTEGER}}, + range: lineRange, text: line } ],