in Composer/packages/tools/language-servers/language-understanding/src/LUServer.ts [478:714]
protected async completion(params: TextDocumentPositionParams): Promise<CompletionList | null> {
const document = this.documents.get(params.textDocument.uri);
if (!document) {
return Promise.resolve(null);
}
const position = params.position;
const range = Range.create(position.line, 0, position.line, position.character);
const curLineContent = document.getText(range);
const luDoc = this.getLUDocument(document);
const text = (await luDoc?.index()).content || document.getText();
const lines = text.split('\n');
const curLineNumber = params.position.line;
//const textBeforeCurLine = lines.slice(0, curLineNumber).join('\n');
const textExceptCurLine = lines
.slice(0, curLineNumber)
.concat(lines.slice(curLineNumber + 1))
.join('\n');
const completionList: CompletionItem[] = [];
if (util.isEntityType(curLineContent)) {
const triggerChar = curLineContent[position.character - 1];
const extraWhiteSpace = triggerChar === '@' ? ' ' : '';
const entityTypes: string[] = EntityTypesObj.EntityType;
entityTypes.forEach((entity) => {
const item = {
label: entity,
kind: CompletionItemKind.Keyword,
insertText: `${extraWhiteSpace}${entity}`,
documentation: `Enitity type: ${entity}`,
};
completionList.push(item);
});
}
if (util.isPrebuiltEntity(curLineContent)) {
const prebuiltTypes: string[] = EntityTypesObj.Prebuilt;
const triggerChar = curLineContent[position.character - 1];
const extraWhiteSpace = triggerChar !== ' ' ? ' ' : '';
prebuiltTypes.forEach((entity) => {
const item = {
label: entity,
kind: CompletionItemKind.Keyword,
insertText: `${extraWhiteSpace}${entity}`,
documentation: `Prebuilt enitity: ${entity}`,
};
completionList.push(item);
});
}
if (util.isRegexEntity(curLineContent)) {
const item = {
label: 'RegExp Entity',
kind: CompletionItemKind.Keyword,
insertText: `//`,
documentation: `regex enitity`,
};
completionList.push(item);
}
if (util.isEntityName(curLineContent)) {
const item = {
label: 'hasRoles?',
kind: CompletionItemKind.Keyword,
insertText: `hasRoles`,
documentation: `Entity name hasRole?`,
};
completionList.push(item);
const item2 = {
label: 'usesFeature?',
kind: CompletionItemKind.Keyword,
insertText: `usesFeature`,
documentation: `Entity name usesFeature?`,
};
completionList.push(item2);
}
if (util.isPhraseListEntity(curLineContent)) {
const item = {
label: 'interchangeable synonyms?',
kind: CompletionItemKind.Keyword,
insertText: `interchangeable`,
documentation: `interchangeable synonyms as part of the entity definition`,
};
completionList.push(item);
}
// completion for entities and patterns, use the text without current line due to usually it will cause parser errors, the luisjson will be undefined
let luisJson = await this.extractLUISContent(text);
if (!luisJson) {
luisJson = await this.extractLUISContent(textExceptCurLine);
}
const suggestionEntityList = uniq(
util.getSuggestionEntities(luisJson, util.suggestionAllEntityTypes).concat(this._importedEntities)
);
const regexEntityList = util.getRegexEntities(luisJson);
//suggest a regex pattern for seperated line definition
if (util.isSeperatedEntityDef(curLineContent)) {
const seperatedEntityDef = /^\s*@\s*([\w._]+|"[\w._\s]+")+\s*=\s*$/; //lgtm [js/redos]
let entityName = '';
const matchGroup = curLineContent.match(seperatedEntityDef);
if (matchGroup && matchGroup.length >= 2) {
entityName = matchGroup[1].trim();
}
if (regexEntityList.includes(entityName)) {
const item = {
label: 'RegExp Entity',
kind: CompletionItemKind.Keyword,
insertText: `//`,
documentation: `regex enitity`,
};
completionList.push(item);
}
}
// auto suggest pattern
if (util.matchedEnterPattern(curLineContent)) {
suggestionEntityList.forEach((name) => {
const item = {
label: `Entity: ${name}`,
kind: CompletionItemKind.Property,
insertText: `${name}`,
documentation: `pattern suggestion for entity: ${name}`,
};
completionList.push(item);
});
}
// suggestions for entities in a seperated line
if (util.isEntityType(curLineContent)) {
suggestionEntityList.forEach((entity) => {
const item = {
label: entity,
kind: CompletionItemKind.Property,
insertText: `${entity}`,
documentation: `Enitity type: ${entity}`,
};
completionList.push(item);
});
}
if (util.isCompositeEntity(curLineContent)) {
util.getSuggestionEntities(luisJson, util.suggestionNoCompositeEntityTypes).forEach((entity) => {
const item = {
label: entity,
kind: CompletionItemKind.Property,
insertText: `${entity}`,
documentation: `Enitity type: ${entity}`,
};
completionList.push(item);
});
}
const suggestionRolesList = util.getSuggestionRoles(luisJson, util.suggestionAllEntityTypes);
// auto suggest roles
if (util.matchedRolesPattern(curLineContent)) {
suggestionRolesList.forEach((name) => {
const item = {
label: `Role: ${name}`,
kind: CompletionItemKind.Property,
insertText: `${name}`,
documentation: `roles suggestion for entity name: ${name}`,
};
completionList.push(item);
});
}
if (util.matchedEntityPattern(curLineContent)) {
suggestionEntityList.forEach((name) => {
const item = {
label: `Entity: ${name}`,
kind: CompletionItemKind.Property,
insertText: ` ${name}`,
documentation: `pattern suggestion for entity: ${name}`,
};
completionList.push(item);
});
}
if (util.matchedEntityCanUsesFeature(curLineContent, text, luisJson)) {
const enitityName = util.extractEntityNameInUseFeature(curLineContent);
const suggestionFeatureList = util.getSuggestionEntities(luisJson, util.suggestionNoPatternAnyEntityTypes);
suggestionFeatureList.forEach((name) => {
if (name !== enitityName) {
const item = {
label: `Entity: ${name}`,
kind: CompletionItemKind.Method,
insertText: `${name}`,
documentation: `Feature suggestion for current entity: ${name}`,
};
completionList.push(item);
}
});
}
if (util.matchIntentInEntityDef(curLineContent)) {
const item = {
label: 'usesFeature?',
kind: CompletionItemKind.Keyword,
insertText: `usesFeature`,
documentation: `Does this intent usesFeature?`,
};
completionList.push(item);
}
if (util.matchIntentUsesFeatures(curLineContent)) {
const suggestionFeatureList = util.getSuggestionEntities(luisJson, util.suggestionNoPatternAnyEntityTypes);
suggestionFeatureList.forEach((name) => {
const item = {
label: `Entity: ${name}`,
kind: CompletionItemKind.Method,
insertText: `${name}`,
documentation: `Feature suggestion for current entity: ${name}`,
};
completionList.push(item);
});
}
return Promise.resolve({ isIncomplete: false, items: completionList });
}