in language-service/src/services/yamlCompletion.ts [54:213]
public doComplete(document: TextDocument, position: Position, yamlDocument: YAMLDocument): Thenable<CompletionList> {
let result: CompletionList = {
items: [],
isIncomplete: false
};
const offset = document.offsetAt(position);
if (document.getText()[offset] === ":") {
return Promise.resolve(result);
}
const jsonDocument: SingleYAMLDocument = yamlDocument.documents.length > 0 ? yamlDocument.documents[0] : null;
if (jsonDocument === null) {
return Promise.resolve(result);
}
let node = jsonDocument.getNodeFromOffsetEndInclusive(offset);
if (this.isInComment(document, node ? node.start : 0, offset)) {
return Promise.resolve(result);
}
//console.log(JSON.pruned(node));
let currentWord = this.getCurrentWord(document, offset);
let overwriteRange: Range = null;
if (node && node.type === 'null') {
//console.log('type = null');
let nodeStartPos = document.positionAt(node.start);
nodeStartPos.character += 1;
let nodeEndPos = document.positionAt(node.end);
nodeEndPos.character += 1;
overwriteRange = Range.create(nodeStartPos, nodeEndPos);
} else if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean')) {
//console.log('type = string | nuber | boolean');
overwriteRange = this.getRangeForLiteralProperties(document, node);
} else {
//console.log('else');
let overwriteStart = offset - currentWord.length;
if (overwriteStart > 0 && document.getText()[overwriteStart - 1] === '"') {
overwriteStart--;
}
overwriteRange = Range.create(document.positionAt(overwriteStart), position);
}
//console.log('overwriteRange: ' + JSON.stringify(overwriteRange));
let proposed: { [key: string]: CompletionItem } = {};
let collector: CompletionsCollector = {
add: (suggestion: CompletionItem) => {
let existing = proposed[suggestion.label];
if (!existing) {
proposed[suggestion.label] = suggestion;
if (overwriteRange) {
suggestion.textEdit = TextEdit.replace(overwriteRange, suggestion.insertText);
}
result.items.push(suggestion);
} else if (!existing.documentation) {
existing.documentation = suggestion.documentation;
}
},
setAsIncomplete: () => {
result.isIncomplete = true;
},
error: (message: string) => {
console.error(message);
},
log: (message: string) => {
console.log(message);
},
getNumberOfProposals: () => {
return result.items.length;
}
};
//console.log('document.uri: ' + JSON.stringify(document.uri));
return this.schemaService.getSchemaForResource(document.uri).then((schema) => {
//console.log('start');
//console.log('schema: ' + JSON.stringify(schema));
if (!schema) {
return Promise.resolve(result);
}
let collectionPromises: Thenable<any>[] = [];
let addValue = true;
let currentProperty: Parser.PropertyASTNode = null;
if (node) {
if (node.type === 'string') {
let stringNode = <Parser.StringASTNode>node;
if (stringNode.isKey) {
addValue = !(node.parent && ((<Parser.PropertyASTNode>node.parent).value));
currentProperty = node.parent ? <Parser.PropertyASTNode>node.parent : null;
// currentKey = document.getText().substring(node.start + 1, node.end - 1);
if (node.parent) {
node = node.parent.parent;
}
}
}
}
// proposals for properties
//console.log('node and node object');
if (node && node.type === 'object') {
// don't suggest properties that are already present
const properties: Parser.PropertyASTNode[] = (<Parser.ObjectASTNode>node).properties;
properties.forEach(p => {
if (!currentProperty || currentProperty !== p) {
proposed[p.key.value] = CompletionItem.create('__');
}
});
let separatorAfter = '';
if (addValue) {
separatorAfter = this.evaluateSeparatorAfter(document, document.offsetAt(overwriteRange.end));
}
if (schema) {
// property proposals with schema
this.getPropertyCompletions(schema, jsonDocument, node, addValue, collector, separatorAfter);
}
let location = node.getPath();
this.contributions.forEach((contribution) => {
let collectPromise = contribution.collectPropertyCompletions(document.uri, location, currentWord, addValue, false, collector);
if (collectPromise) {
collectionPromises.push(collectPromise);
}
});
if ((!schema && currentWord.length > 0 && document.getText().charAt(offset - currentWord.length - 1) !== '"')) {
collector.add({
kind: CompletionItemKind.Property,
label: this.getLabelForValue(currentWord),
insertText: this.getInsertTextForProperty(currentWord, null, false, separatorAfter),
insertTextFormat: InsertTextFormat.Snippet,
documentation: ''
});
}
}
// proposals for values
let types: { [type: string]: boolean } = {};
//console.log('schema: ' + JSON.stringify(schema));
if (schema) {
this.getValueCompletions(schema, jsonDocument, node, offset, document, collector, types);
}
if (this.contributions.length > 0) {
this.getContributedValueCompletions(jsonDocument, node, offset, document, collector, collectionPromises);
}
if (this.customTags.length > 0) {
this.getCustomTagValueCompletions(collector);
}
return this.promise.all(collectionPromises).then(() => {
return result;
});
});
}