diff --git a/src/languageservice/services/yamlCompletion.ts b/src/languageservice/services/yamlCompletion.ts index 1a0a77d2..e3e66dc0 100644 --- a/src/languageservice/services/yamlCompletion.ts +++ b/src/languageservice/services/yamlCompletion.ts @@ -178,7 +178,7 @@ export class YAMLCompletion { if (newSchema) { // property proposals with schema - this.getPropertyCompletions(newSchema, currentDoc, node, addValue, collector, separatorAfter); + this.getPropertyCompletions(document, newSchema, currentDoc, node, addValue, collector, separatorAfter); } const location = node.getPath(); @@ -212,7 +212,7 @@ export class YAMLCompletion { }); } - private getPropertyCompletions(schema: SchemaService.ResolvedSchema, +private getPropertyCompletions(document: TextDocument, schema: SchemaService.ResolvedSchema, doc, node: Parser.ASTNode, addValue: boolean, @@ -227,10 +227,21 @@ export class YAMLCompletion { Object.keys(schemaProperties).forEach((key: string) => { const propertySchema = schemaProperties[key]; if (!propertySchema.deprecationMessage && !propertySchema['doNotSuggest']) { + let identCompensation = ''; + if (node.parent && node.parent.type === 'array') { + // because there is a slash '-' to prevent the properties generated to have the correct + // indent + const sourceText = document.getText(); + const indexOfSlash = sourceText.lastIndexOf('-', node.start - 1); + if (indexOfSlash > 0) { + // add one space to compensate the '-' + identCompensation = ' ' + sourceText.slice(indexOfSlash + 1, node.start); + } + } collector.add({ kind: CompletionItemKind.Property, label: key, - insertText: this.getInsertTextForProperty(key, propertySchema, addValue, separatorAfter), + insertText: this.getInsertTextForProperty(key, propertySchema, addValue, separatorAfter, identCompensation + '\t'), insertTextFormat: InsertTextFormat.Snippet, documentation: propertySchema.description || '' }); @@ -684,7 +695,8 @@ export class YAMLCompletion { return { insertText, insertIndex }; } - private getInsertTextForProperty(key: string, propertySchema: JSONSchema, addValue: boolean, separatorAfter: string): string { + private getInsertTextForProperty(key: string, propertySchema: JSONSchema, addValue: boolean, separatorAfter: string, + ident: string = '\t'): string { const propertyText = this.getInsertTextForValue(key, ''); // if (!addValue) { @@ -696,14 +708,11 @@ export class YAMLCompletion { if (propertySchema) { if (propertySchema.default !== undefined) { value = ` \${1:${propertySchema.default}}`; - } - else if (propertySchema.properties) { - return `${resultText}\n${this.getInsertTextForObject(propertySchema, separatorAfter).insertText}`; - } - else if (propertySchema.items) { - return `${resultText}\n\t- ${this.getInsertTextForArray(propertySchema.items, separatorAfter).insertText}`; - } - else { + } else if (propertySchema.properties) { + return `${resultText}\n${this.getInsertTextForObject(propertySchema, separatorAfter, ident).insertText}`; + } else if (propertySchema.items) { + return `${resultText}\n\t- ${this.getInsertTextForArray(propertySchema.items, separatorAfter, ident).insertText}`; + } else { const type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type; switch (type) { case 'boolean': diff --git a/test/autoCompletion5.test.ts b/test/autoCompletion5.test.ts new file mode 100644 index 00000000..6c86a6de --- /dev/null +++ b/test/autoCompletion5.test.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { TextDocument } from 'vscode-languageserver'; +import { getLanguageService } from '../src/languageservice/yamlLanguageService'; +import { toFsPath, schemaRequestService, workspaceContext } from './utils/testHelper'; +import assert = require('assert'); +import path = require('path'); + +const languageService = getLanguageService(schemaRequestService, workspaceContext, [], null); + +const languageSettings = { + schemas: [], + completion: true +}; + +const uri = toFsPath(path.join(__dirname, './fixtures/testArrayIndent.json')); +const fileMatch = ['*.yml', '*.yaml']; +languageSettings.schemas.push({ uri, fileMatch: fileMatch }); +languageService.configure(languageSettings); + +suite('Auto Completion Tests', () => { + + describe('yamlCompletion with array object', function () { + + describe('doComplete', function () { + + function setup(content: string) { + return TextDocument.create('file://~/Desktop/vscode-k8s/test.yaml', 'yaml', 0, content); + } + + function parseSetup(content: string, position) { + const testTextDocument = setup(content); + return languageService.doComplete(testTextDocument, testTextDocument.positionAt(position), false); + } + + it('Indent should be considered with position relative to slash', done => { + const content = 'install:\n - he'; + const completion = parseSetup(content, content.lastIndexOf('he') + 2); + completion.then(function (result) { + assert.equal('helm:\n \tname: $1', result.items[0].insertText); + }).then(done, done); + }); + + it('Large indent should be considered with position relative to slash', done => { + const content = 'install:\n - he'; + const completion = parseSetup(content, content.lastIndexOf('he') + 2); + completion.then(function (result) { + assert.equal('helm:\n \tname: $1', result.items[0].insertText); + }).then(done, done); + }); + + it('Tab indent should be considered with position relative to slash', done => { + const content = 'install:\n -\t he'; + const completion = parseSetup(content, content.lastIndexOf('he') + 2); + completion.then(function (result) { + assert.equal('helm:\n \t \tname: $1', result.items[0].insertText); + }).then(done, done); + }); + + }); + }); +}); diff --git a/test/fixtures/testArrayIndent.json b/test/fixtures/testArrayIndent.json new file mode 100644 index 00000000..88aa5edc --- /dev/null +++ b/test/fixtures/testArrayIndent.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "installStep": { + "properties": { + "helm": { + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + } + }, + "required": [ + "helm" + ], + "type": "object" + } + }, + "properties": { + "install": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/installStep" + } + ] + }, + "type": "array" + } + }, + "type": "object" +}