Skip to content

Commit bd99c28

Browse files
authored
fix: clamp completion range for unclosed string literals (#239)
When an attribute value has an unclosed quote, the replace range could extend past `<` characters after the cursor, causing completions to delete subsequent HTML tags. Clamp valueContentEnd to the cursor offset when the closing quote is missing. Fixes microsoft/vscode#273226
1 parent fd178cf commit bd99c28

2 files changed

Lines changed: 13 additions & 0 deletions

File tree

src/services/htmlCompletion.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ export class HTMLCompletion {
294294
// valueEnd points to the char after quote, which encloses the replace range
295295
if (valueEnd > valueStart && text[valueEnd - 1] === text[valueStart]) {
296296
valueContentEnd--;
297+
} else {
298+
// unclosed quote: clamp the end to the cursor position so that
299+
// the replace range does not extend into subsequent HTML content
300+
valueContentEnd = offset;
297301
}
298302

299303
const wsBefore = getWordStart(text, offset, valueContentStart);

src/test/completion.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ suite('HTML Completion', () => {
164164
testCompletionFor('<input src="c" type=color| ', {
165165
items: [{ label: 'color', resultText: '<input src="c" type="color" ' }]
166166
});
167+
168+
// unclosed string literals should not extend the replace range past the cursor
169+
testCompletionFor('<th><input type="che|</th>', {
170+
items: [{ label: 'checkbox', resultText: '<th><input type="checkbox</th>' }]
171+
});
172+
testCompletionFor('<th><input type="che|</th><td></td>', {
173+
items: [{ label: 'checkbox', resultText: '<th><input type="checkbox</th><td></td>' }]
174+
});
175+
167176
testCompletionFor('<div dir=|></div>', {
168177
items: [
169178
{ label: 'ltr', resultText: '<div dir="ltr"></div>' },

0 commit comments

Comments
 (0)