diff --git a/src/languageservice/parser/yaml-documents.ts b/src/languageservice/parser/yaml-documents.ts index 24ca9e3b..c650f5b1 100644 --- a/src/languageservice/parser/yaml-documents.ts +++ b/src/languageservice/parser/yaml-documents.ts @@ -95,11 +95,15 @@ export class SingleYAMLDocument extends JSONDocument { return this.internalDocument.warnings.map(YAMLErrorToYamlDocDiagnostics); } - getNodeFromPosition(positionOffset: number, textBuffer: TextBuffer): [YamlNode | undefined, boolean] { + getNodeFromPosition( + positionOffset: number, + textBuffer: TextBuffer, + configuredIndentation?: number + ): [YamlNode | undefined, boolean] { const position = textBuffer.getPosition(positionOffset); const lineContent = textBuffer.getLineContent(position.line); if (lineContent.trim().length === 0) { - return [this.findClosestNode(positionOffset, textBuffer), true]; + return [this.findClosestNode(positionOffset, textBuffer, configuredIndentation), true]; } let closestNode: Node; @@ -122,7 +126,7 @@ export class SingleYAMLDocument extends JSONDocument { return [closestNode, false]; } - findClosestNode(offset: number, textBuffer: TextBuffer): YamlNode { + findClosestNode(offset: number, textBuffer: TextBuffer, configuredIndentation?: number): YamlNode { let offsetDiff = this.internalDocument.range[2]; let maxOffset = this.internalDocument.range[0]; let closestNode: YamlNode; @@ -151,34 +155,57 @@ export class SingleYAMLDocument extends JSONDocument { } if (indentation === position.character) { - closestNode = this.getProperParentByIndentation(indentation, closestNode, textBuffer); + closestNode = this.getProperParentByIndentation(indentation, closestNode, textBuffer, '', configuredIndentation); } return closestNode; } - private getProperParentByIndentation(indentation: number, node: YamlNode, textBuffer: TextBuffer): YamlNode { + private getProperParentByIndentation( + indentation: number, + node: YamlNode, + textBuffer: TextBuffer, + currentLine: string, + configuredIndentation: number, + rootParent?: YamlNode + ): YamlNode { if (!node) { return this.internalDocument.contents as Node; } + configuredIndentation = !configuredIndentation ? 2 : configuredIndentation; if (isNode(node) && node.range) { const position = textBuffer.getPosition(node.range[0]); + const lineContent = textBuffer.getLineContent(position.line); + currentLine = currentLine === '' ? lineContent.trim() : currentLine; + if (currentLine.startsWith('-') && indentation === configuredIndentation && currentLine === lineContent.trim()) { + position.character += indentation; + } if (position.character > indentation && position.character > 0) { const parent = this.getParent(node); if (parent) { - return this.getProperParentByIndentation(indentation, parent, textBuffer); + return this.getProperParentByIndentation( + indentation, + parent, + textBuffer, + currentLine, + configuredIndentation, + rootParent + ); } } else if (position.character < indentation) { const parent = this.getParent(node); if (isPair(parent) && isNode(parent.value)) { return parent.value; + } else if (isPair(rootParent) && isNode(rootParent.value)) { + return rootParent.value; } } else { return node; } } else if (isPair(node)) { + rootParent = node; const parent = this.getParent(node); - return this.getProperParentByIndentation(indentation, parent, textBuffer); + return this.getProperParentByIndentation(indentation, parent, textBuffer, currentLine, configuredIndentation, rootParent); } return node; } diff --git a/src/languageservice/services/yamlCompletion.ts b/src/languageservice/services/yamlCompletion.ts index 019825b4..a8f35a87 100644 --- a/src/languageservice/services/yamlCompletion.ts +++ b/src/languageservice/services/yamlCompletion.ts @@ -123,7 +123,7 @@ export class YamlCompletion { // as we modify AST for completion, we need to use copy of original document currentDoc = currentDoc.clone(); - let [node, foundByClosest] = currentDoc.getNodeFromPosition(offset, textBuffer); + let [node, foundByClosest] = currentDoc.getNodeFromPosition(offset, textBuffer, this.indentation.length); const currentWord = this.getCurrentWord(document, offset); diff --git a/test/autoCompletion.test.ts b/test/autoCompletion.test.ts index 4d0bd868..e06a4c9a 100644 --- a/test/autoCompletion.test.ts +++ b/test/autoCompletion.test.ts @@ -2066,6 +2066,40 @@ describe('Auto Completion Tests', () => { expect(completion.items[0].insertText).eq('fooBar:\n name: $1\n aaa:\n - $2'); }); + it('auto completion based on the list indentation', async () => { + languageService.addSchema(SCHEMA_ID, { + type: 'array', + items: { + type: 'object', + properties: { + prop1: { + type: 'string', + }, + prop2: { + type: 'string', + }, + Object: { + type: 'array', + items: { + type: 'object', + properties: { + env_prop1: { + type: 'string', + }, + }, + }, + }, + }, + }, + }); + + const content = '- prop1: value\n object:\n - env_prop1: value\n '; + const completion = await parseSetup(content, 49); + expect(completion.items).lengthOf(2); + expect(completion.items[0].label).eq('prop2'); + expect(completion.items[0].insertText).eq('prop2: '); + }); + it('should complete string which contains number in default value', async () => { languageService.addSchema(SCHEMA_ID, { type: 'object', diff --git a/test/yaml-documents.test.ts b/test/yaml-documents.test.ts index 9b1c3da7..31ebb9d4 100644 --- a/test/yaml-documents.test.ts +++ b/test/yaml-documents.test.ts @@ -232,7 +232,7 @@ objB: expect(result).is.not.undefined; expect(isMap(result)).is.true; - expect(((result as YAMLMap).items[0].key as Scalar).value).eqls('foo'); + expect(((result as YAMLMap).items[0].key as Scalar).value).eqls('bar'); }); }); });