extensions/emmet/src/selectItemHTML.ts/getNextAttribute
function getNextAttribute(document: vscode.TextDocument, selectionStart: number, selectionEnd: number, node: HtmlNode): vscode.Selection | undefined {
	if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') {
		return;
	}

	for (const attr of node.attributes) {
		if (selectionEnd < attr.start) {
			// select full attr
			return offsetRangeToSelection(document, attr.start, attr.end);
		}

		if (!attr.value || attr.value.start === attr.value.end) {
			// No attr value to select
			continue;
		}

		if ((selectionStart === attr.start && selectionEnd === attr.end) ||
			selectionEnd < attr.value.start) {
			// cursor is in attr name,  so select full attr value
			return offsetRangeToSelection(document, attr.value.start, attr.value.end);
		}

		// Fetch the next word in the attr value
		if (attr.value.toString().indexOf(' ') === -1) {
			// attr value does not have space, so no next word to find
			continue;
		}

		let pos: number | undefined = undefined;
		if (selectionStart === attr.value.start && selectionEnd === attr.value.end) {
			pos = -1;
		}
		if (pos === undefined && selectionEnd < attr.end) {
			const selectionEndCharacter = document.positionAt(selectionEnd).character;
			const attrValueStartCharacter = document.positionAt(attr.value.start).character;
			pos = selectionEndCharacter - attrValueStartCharacter - 1;
		}

		if (pos !== undefined) {
			const [newSelectionStartOffset, newSelectionEndOffset] = findNextWord(attr.value.toString(), pos);
			if (newSelectionStartOffset === undefined || newSelectionEndOffset === undefined) {
				return;
			}
			if (newSelectionStartOffset >= 0 && newSelectionEndOffset >= 0) {
				const newSelectionStart = attr.value.start + newSelectionStartOffset;
				const newSelectionEnd = attr.value.start + newSelectionEndOffset;
				return offsetRangeToSelection(document, newSelectionStart, newSelectionEnd);
			}
		}

	}

	return;
}