function collectAttributeNameSuggestions()

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;
		}