diff --git a/actions-languageservice/src/complete.expressions.test.ts b/actions-languageservice/src/complete.expressions.test.ts index a098a9d..6b5e41b 100644 --- a/actions-languageservice/src/complete.expressions.test.ts +++ b/actions-languageservice/src/complete.expressions.test.ts @@ -706,4 +706,20 @@ jobs: expect(github!.kind).toBe(CompletionItemKind.Variable); expect(github!.insertText).toBeUndefined(); }); + + it("function parentheses are not inserted when parentheses already exist", async () => { + const input = ` + on: push + + jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo \${{ toJS|(github.event) }} + `; + + const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig); + + expect(result.find(x => x.label === "toJson")!.insertText).toBe("toJson"); + }); }); diff --git a/actions-languageservice/src/complete.ts b/actions-languageservice/src/complete.ts index cecfb5b..0477b19 100644 --- a/actions-languageservice/src/complete.ts +++ b/actions-languageservice/src/complete.ts @@ -1,4 +1,5 @@ import {complete as completeExpression} from "@github/actions-expressions"; +import {CompletionItem as ExpressionCompletionItem} from "@github/actions-expressions/completion"; import {convertWorkflowTemplate, isSequence, isString, parseWorkflow} from "@github/actions-workflow-parser"; import {ErrorPolicy} from "@github/actions-workflow-parser/model/convert"; import {DefinitionType} from "@github/actions-workflow-parser/templates/schema/definition-type"; @@ -87,13 +88,9 @@ export async function complete( const allowedContext = token.definitionInfo?.allowedContext || []; const context = await getContext(allowedContext, contextProviderConfig, workflowContext, Mode.Completion); - return completeExpression(expressionInput, context, []).map(item => { - return { - label: item.label, - insertText: item.function ? item.label + "()" : undefined, - kind: item.function ? CompletionItemKind.Function : CompletionItemKind.Variable - }; - }); + return completeExpression(expressionInput, context, []).map(item => + mapExpressionCompletionItem(item, currentInput[relCharPos]) + ); } } @@ -198,3 +195,17 @@ function filterAndSortCompletionOptions(options: Value[], existingValues?: Set a.label.localeCompare(b.label)); return options; } + +function mapExpressionCompletionItem(item: ExpressionCompletionItem, charAfterPos: string): CompletionItem { + let insertText: string | undefined; + // Insert parentheses if the cursor is after a function + // and the function does not have any parantheses already + if (item.function) { + insertText = charAfterPos === "(" ? item.label : item.label + "()"; + } + return { + label: item.label, + insertText: insertText, + kind: item.function ? CompletionItemKind.Function : CompletionItemKind.Variable + }; +}