@@ -42,6 +42,7 @@ export function doComplete(
42
42
const scanner = createScanner ( text , node . start ) ;
43
43
let currentTag : string ;
44
44
let currentAttributeName = '' ;
45
+ let currentTagStartOffset : number ;
45
46
46
47
function getReplaceRange ( replaceStart : number , replaceEnd : number = offset ) : Range {
47
48
if ( replaceStart > offset ) {
@@ -147,7 +148,11 @@ export function doComplete(
147
148
return result ;
148
149
}
149
150
150
- function collectAttributeNameSuggestions ( nameStart : number , nameEnd : number = offset ) : CompletionList {
151
+ function collectAttributeNameSuggestions (
152
+ usedAttributes : string [ ] ,
153
+ nameStart : number ,
154
+ nameEnd : number = offset
155
+ ) : CompletionList {
151
156
const execArray = / ^ [: @ ] / . exec ( scanner . getTokenText ( ) ) ;
152
157
const filterPrefix = execArray ? execArray [ 0 ] : '' ;
153
158
const start = filterPrefix ? nameStart + 1 : nameStart ;
@@ -158,6 +163,16 @@ export function doComplete(
158
163
tagProviders . forEach ( provider => {
159
164
const priority = provider . priority ;
160
165
provider . collectAttributes ( currentTag , ( attribute , type , documentation ) => {
166
+ if (
167
+ usedAttributes . includes ( normalizeAttribute ( attribute ) ) &&
168
+ // can listen to same event by adding modifiers
169
+ type !== 'event' &&
170
+ // `class` and `:class`, `style` and `:style` can coexist
171
+ attribute !== 'class' &&
172
+ attribute !== 'style'
173
+ ) {
174
+ return ;
175
+ }
161
176
if ( ( type === 'event' && filterPrefix !== '@' ) || ( type !== 'event' && filterPrefix === '@' ) ) {
162
177
return ;
163
178
}
@@ -271,6 +286,23 @@ export function doComplete(
271
286
return offset ;
272
287
}
273
288
289
+ function collectUsedAttributes ( ) : string [ ] {
290
+ const attrScanner = createScanner ( text , currentTagStartOffset ) ;
291
+
292
+ let token = attrScanner . scan ( ) ;
293
+ let currentAttributeName ! : string ;
294
+ const attrs = [ ] ;
295
+ while ( token !== TokenType . EOS && token !== TokenType . StartTagClose ) {
296
+ if ( token === TokenType . AttributeName ) {
297
+ currentAttributeName = normalizeAttribute ( attrScanner . getTokenText ( ) ) ;
298
+ } else if ( token === TokenType . AttributeValue ) {
299
+ attrs . push ( currentAttributeName ) ;
300
+ }
301
+ token = attrScanner . scan ( ) ;
302
+ }
303
+ return attrs ;
304
+ }
305
+
274
306
let token = scanner . scan ( ) ;
275
307
276
308
while ( token !== TokenType . EOS && scanner . getTokenOffset ( ) <= offset ) {
@@ -280,6 +312,7 @@ export function doComplete(
280
312
const endPos = scanNextForEndPos ( TokenType . StartTag ) ;
281
313
return collectTagSuggestions ( offset , endPos ) ;
282
314
}
315
+ currentTagStartOffset = scanner . getTokenOffset ( ) ;
283
316
break ;
284
317
case TokenType . StartTag :
285
318
if ( scanner . getTokenOffset ( ) <= offset && offset <= scanner . getTokenEnd ( ) ) {
@@ -289,7 +322,8 @@ export function doComplete(
289
322
break ;
290
323
case TokenType . AttributeName :
291
324
if ( scanner . getTokenOffset ( ) <= offset && offset <= scanner . getTokenEnd ( ) ) {
292
- return collectAttributeNameSuggestions ( scanner . getTokenOffset ( ) , scanner . getTokenEnd ( ) ) ;
325
+ const usedAttrs = collectUsedAttributes ( ) ;
326
+ return collectAttributeNameSuggestions ( usedAttrs , scanner . getTokenOffset ( ) , scanner . getTokenEnd ( ) ) ;
293
327
}
294
328
currentAttributeName = scanner . getTokenText ( ) ;
295
329
break ;
@@ -321,7 +355,8 @@ export function doComplete(
321
355
return collectTagSuggestions ( startPos , endTagPos ) ;
322
356
case ScannerState . WithinTag :
323
357
case ScannerState . AfterAttributeName :
324
- return collectAttributeNameSuggestions ( scanner . getTokenEnd ( ) ) ;
358
+ const usedAttrs = collectUsedAttributes ( ) ;
359
+ return collectAttributeNameSuggestions ( usedAttrs , scanner . getTokenEnd ( ) ) ;
325
360
case ScannerState . BeforeAttributeValue :
326
361
return collectAttributeValueSuggestions ( currentAttributeName , scanner . getTokenEnd ( ) ) ;
327
362
case ScannerState . AfterOpeningEndTag :
@@ -392,3 +427,10 @@ function getWordEnd(s: string, offset: number, limit: number): number {
392
427
}
393
428
return offset ;
394
429
}
430
+
431
+ function normalizeAttribute ( attr : string ) : string {
432
+ // trim modifiers
433
+ attr = attr . replace ( / \. .+ $ / , '' ) ;
434
+
435
+ return attr . replace ( / ^ (?: v - b i n d : | : ) / , '' ) . replace ( / ^ v - o n : / , '@' ) ;
436
+ }
0 commit comments