in src/services/htmlCompletion.ts [200:254]
function collectAttributeNameSuggestions(nameStart: number, nameEnd: number = offset): CompletionList {
let replaceEnd = offset;
while (replaceEnd < nameEnd && text[replaceEnd] !== '<') { // < is a valid attribute name character, but we rather assume the attribute name ends. See #23236.
replaceEnd++;
}
const currentAttribute = text.substring(nameStart, nameEnd);
const range = getReplaceRange(nameStart, replaceEnd);
let value = '';
if (!isFollowedBy(text, nameEnd, ScannerState.AfterAttributeName, TokenType.DelimiterAssign)) {
const defaultValue = settings?.attributeDefaultValue ?? 'doublequotes';
if (defaultValue === 'empty') {
value = '=$1';
} else if (defaultValue === 'singlequotes') {
value = '=\'$1\'';
} else {
value = '="$1"';
}
}
const seenAttributes = getExistingAttributes();
// include current typing attribute
seenAttributes[currentAttribute] = false;
dataProviders.forEach(provider => {
provider.provideAttributes(currentTag).forEach(attr => {
if (seenAttributes[attr.name]) {
return;
}
seenAttributes[attr.name] = true;
let codeSnippet = attr.name;
let command;
if (attr.valueSet !== 'v' && value.length) {
codeSnippet = codeSnippet + value;
if (attr.valueSet || attr.name === 'style') {
command = {
title: 'Suggest',
command: 'editor.action.triggerSuggest'
};
}
}
result.items.push({
label: attr.name,
kind: attr.valueSet === 'handler' ? CompletionItemKind.Function : CompletionItemKind.Value,
documentation: generateDocumentation(attr, undefined, doesSupportMarkdown),
textEdit: TextEdit.replace(range, codeSnippet),
insertTextFormat: InsertTextFormat.Snippet,
command
});
});
});
collectDataAttributesSuggestions(range, seenAttributes);
return result;
}