From b32f6d8e6c8a4ae779b3e95c5ae742c5170ac8a5 Mon Sep 17 00:00:00 2001 From: Petr Spacek Date: Fri, 10 Dec 2021 11:16:20 +0100 Subject: [PATCH] fix: completion invoke in three different scenarios - with short nextLine - nested object - with a new line inside the object - on the first array item --- src/languageservice/parser/yaml-documents.ts | 15 ++- test/autoCompletionFix.test.ts | 100 +++++++++++++++++++ 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/src/languageservice/parser/yaml-documents.ts b/src/languageservice/parser/yaml-documents.ts index b07ee434..588d9054 100644 --- a/src/languageservice/parser/yaml-documents.ts +++ b/src/languageservice/parser/yaml-documents.ts @@ -5,7 +5,7 @@ import { TextDocument } from 'vscode-languageserver-textdocument'; import { JSONDocument } from './jsonParser07'; -import { Document, isPair, isScalar, LineCounter, visit, YAMLError } from 'yaml'; +import { Document, isNode, isPair, isScalar, LineCounter, visit, YAMLError } from 'yaml'; import { ASTNode } from '../jsonASTTypes'; import { defaultOptions, parse as parseYAML, ParserOptions } from './yamlParser07'; import { ErrorCode } from 'vscode-json-languageservice'; @@ -126,9 +126,9 @@ export class SingleYAMLDocument extends JSONDocument { if (!range) { return; } - const diff = Math.abs(range[2] - offset); - if (maxOffset <= range[0] && diff <= offsetDiff) { - offsetDiff = diff; + const diff = range[2] - offset; + if (maxOffset <= range[0] && diff <= 0 && Math.abs(diff) <= offsetDiff) { + offsetDiff = Math.abs(diff); maxOffset = range[0]; closestNode = node; } @@ -155,11 +155,16 @@ export class SingleYAMLDocument extends JSONDocument { } if (node.range) { const position = textBuffer.getPosition(node.range[0]); - if (position.character !== indentation && position.character > 0) { + if (position.character > indentation && position.character > 0) { const parent = this.getParent(node); if (parent) { return this.getProperParentByIndentation(indentation, parent, textBuffer); } + } else if (position.character < indentation) { + const parent = this.getParent(node); + if (isPair(parent) && isNode(parent.value)) { + return parent.value; + } } else { return node; } diff --git a/test/autoCompletionFix.test.ts b/test/autoCompletionFix.test.ts index c0905c9f..75f75038 100644 --- a/test/autoCompletionFix.test.ts +++ b/test/autoCompletionFix.test.ts @@ -156,4 +156,104 @@ objB: expect(completion.items).length(4); expect(completion.items.map((it) => it.label)).to.have.members(['NOT', 'attribute', 'operation', 'value']); }); + + it('Autocomplete with short nextLine - nested object', async () => { + languageService.addSchema(SCHEMA_ID, { + type: 'object', + properties: { + example: { + type: 'object', + properties: { + sample: { + type: 'object', + properties: { + detail: { + type: 'object', + }, + }, + }, + }, + }, + a: { + type: 'string', + description: 'short prop name because of distance to the cursor', + }, + }, + }); + const content = 'example:\n sample:\n '; + const completion = await parseSetup(content + '\na: test', 2, 4); + expect(completion.items.length).equal(1); + expect(completion.items[0]).to.be.deep.equal( + createExpectedCompletion('detail', 'detail:\n ', 2, 4, 2, 4, 10, 2, { + documentation: '', + }) + ); + }); + + it('Autocomplete with a new line inside the object', async () => { + languageService.addSchema(SCHEMA_ID, { + type: 'object', + properties: { + example: { + type: 'object', + properties: { + sample: { + type: 'object', + properties: { + prop1: { + type: 'string', + }, + prop2: { + type: 'string', + }, + }, + }, + }, + }, + }, + }); + const content = 'example:\n sample:\n \n prop2: value2'; + const completion = await parseSetup(content, 2, 4); + expect(completion.items.length).equal(1); + expect(completion.items[0]).to.be.deep.equal( + createExpectedCompletion('prop1', 'prop1: ', 2, 4, 2, 4, 10, 2, { + documentation: '', + }) + ); + }); + + it('Autocomplete on the first array item', async () => { + languageService.addSchema(SCHEMA_ID, { + type: 'object', + properties: { + examples: { + type: 'array', + items: { + type: 'object', + properties: { + sample: { + type: 'object', + properties: { + prop1: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }); + const content = 'examples:\n \n - sample:\n prop1: value1'; + const completion = await parseSetup(content, 1, 2); + expect(completion.items.length).equal(1); + expect(completion.items[0]).to.be.deep.equal( + createExpectedCompletion('- (array item)', '- ', 1, 2, 1, 2, 9, 2, { + documentation: { + kind: 'markdown', + value: 'Create an item of an array\n ```\n- \n```', + }, + }) + ); + }); });