Skip to content

Commit 0154301

Browse files
authored
fix(language-service): skip document highlight from tsserver within element tags (#5584)
1 parent b6aad73 commit 0154301

File tree

5 files changed

+44
-27
lines changed

5 files changed

+44
-27
lines changed

packages/language-core/lib/codegen/codeFeatures.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ const raw = {
2424
navigation: {
2525
navigation: true,
2626
},
27-
navigationWithoutHighlight: {
28-
navigation: { shouldHighlight: () => false },
29-
},
3027
navigationWithoutRename: {
3128
navigation: { shouldRename: () => false },
3229
},

packages/language-core/lib/codegen/template/element.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import { camelize, capitalize } from '@vue/shared';
33
import type { Code, VueCodeInformation } from '../../types';
4-
import { getSlotsPropertyName, hyphenateTag } from '../../utils/shared';
4+
import { getElementTagOffsets, getSlotsPropertyName, hyphenateTag } from '../../utils/shared';
55
import { codeFeatures } from '../codeFeatures';
66
import { createVBindShorthandInlayHintInfo } from '../inlayHints';
77
import { endOfLine, identifierRegex, newLine, normalizeAttributeValue } from '../utils';
@@ -25,13 +25,7 @@ export function* generateComponent(
2525
ctx: TemplateCodegenContext,
2626
node: CompilerDOM.ElementNode,
2727
): Generator<Code> {
28-
const tagOffsets = [node.loc.start.offset + options.template.content.slice(node.loc.start.offset).indexOf(node.tag)];
29-
if (!node.isSelfClosing && options.template.lang === 'html') {
30-
const endTagOffset = node.loc.start.offset + node.loc.source.lastIndexOf(node.tag);
31-
if (endTagOffset > tagOffsets[0]) {
32-
tagOffsets.push(endTagOffset);
33-
}
34-
}
28+
const tagOffsets = getElementTagOffsets(node, options.template);
3529
const failedPropExps: FailedPropExpression[] = [];
3630
const possibleOriginalNames = getPossibleOriginalComponentNames(node.tag, true);
3731
const matchImportName = possibleOriginalNames.find(name => options.scriptSetupImportComponentNames.has(name));
@@ -294,25 +288,16 @@ export function* generateElement(
294288
ctx: TemplateCodegenContext,
295289
node: CompilerDOM.ElementNode,
296290
): Generator<Code> {
297-
const startTagOffset = node.loc.start.offset
298-
+ options.template.content.slice(node.loc.start.offset).indexOf(node.tag);
299-
const endTagOffset = !node.isSelfClosing && options.template.lang === 'html'
300-
? node.loc.start.offset + node.loc.source.lastIndexOf(node.tag)
301-
: undefined;
291+
const [startTagOffset, endTagOffset] = getElementTagOffsets(node, options.template);
302292
const failedPropExps: FailedPropExpression[] = [];
303293

304-
const features = {
305-
...codeFeatures.semanticWithoutHighlight,
306-
...codeFeatures.navigationWithoutHighlight,
307-
};
308-
309294
yield `__VLS_asFunctionalElement(__VLS_elements`;
310295
yield* generatePropertyAccess(
311296
options,
312297
ctx,
313298
node.tag,
314299
startTagOffset,
315-
features,
300+
codeFeatures.withoutHighlightAndCompletion,
316301
);
317302
if (endTagOffset !== undefined) {
318303
yield `, __VLS_elements`;
@@ -321,7 +306,7 @@ export function* generateElement(
321306
ctx,
322307
node.tag,
323308
endTagOffset,
324-
features,
309+
codeFeatures.withoutHighlightAndCompletion,
325310
);
326311
}
327312
yield `)(`;

packages/language-core/lib/codegen/template/slotOutlet.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import type { Code } from '../../types';
3+
import { getElementTagOffsets } from '../../utils/shared';
34
import { codeFeatures } from '../codeFeatures';
45
import { createVBindShorthandInlayHintInfo } from '../inlayHints';
56
import { endOfLine, newLine } from '../utils';
@@ -16,8 +17,7 @@ export function* generateSlotOutlet(
1617
ctx: TemplateCodegenContext,
1718
node: CompilerDOM.SlotOutletNode,
1819
): Generator<Code> {
19-
const startTagOffset = node.loc.start.offset
20-
+ options.template.content.slice(node.loc.start.offset).indexOf(node.tag);
20+
const [startTagOffset] = getElementTagOffsets(node, options.template);
2121
const startTagEndOffset = startTagOffset + node.tag.length;
2222
const propsVar = ctx.getInternalVariable();
2323
const nameProp = node.props.find(prop => {

packages/language-core/lib/utils/shared.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import type * as CompilerDOM from '@vue/compiler-dom';
12
import { hyphenate } from '@vue/shared';
23
import type * as ts from 'typescript';
3-
import type { TextRange } from '../types';
4+
import type { Sfc, TextRange } from '../types';
45

56
export { hyphenate as hyphenateTag } from '@vue/shared';
67

@@ -17,6 +18,22 @@ export function getSlotsPropertyName(vueVersion: number) {
1718
return vueVersion < 3 ? '$scopedSlots' : '$slots';
1819
}
1920

21+
export function getElementTagOffsets(
22+
node: CompilerDOM.ElementNode,
23+
template: NonNullable<Sfc['template']>,
24+
) {
25+
const tagOffsets = [
26+
template.content.indexOf(node.tag, node.loc.start.offset),
27+
];
28+
if (!node.isSelfClosing && template.lang === 'html') {
29+
const endTagOffset = node.loc.start.offset + node.loc.source.lastIndexOf(node.tag);
30+
if (endTagOffset > tagOffsets[0]) {
31+
tagOffsets.push(endTagOffset);
32+
}
33+
}
34+
return tagOffsets;
35+
}
36+
2037
export function getStartEnd(
2138
ts: typeof import('typescript'),
2239
node: ts.Node,

packages/language-service/lib/plugins/vue-document-highlights.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { DocumentHighlightKind, LanguageServicePlugin } from '@volar/language-service';
2+
import { forEachElementNode, getElementTagOffsets } from '@vue/language-core';
23
import { getEmbeddedInfo } from '../utils';
34

45
export function create(
@@ -18,7 +19,24 @@ export function create(
1819
}
1920
const { root } = info;
2021

21-
const result = await getDocumentHighlights(root.fileName, document.offsetAt(position));
22+
const { template } = root.sfc;
23+
const offset = document.offsetAt(position);
24+
25+
if (template?.ast && offset >= template.startTagEnd && offset <= template.endTagStart) {
26+
const pos = offset - template.startTagEnd;
27+
for (const node of forEachElementNode(template.ast)) {
28+
if (pos < node.loc.start.offset || pos > node.loc.end.offset) {
29+
continue;
30+
}
31+
for (const tagOffset of getElementTagOffsets(node, template)) {
32+
if (pos >= tagOffset && pos <= tagOffset + node.tag.length) {
33+
return;
34+
}
35+
}
36+
}
37+
}
38+
39+
const result = await getDocumentHighlights(root.fileName, offset);
2240

2341
return result
2442
?.filter(({ fileName }) => fileName === root.fileName)

0 commit comments

Comments
 (0)