language-tools
language-tools copied to clipboard
highlight loss and elment miss end tag
Vue - Official extension or vue-tsc version
v2.0.26
VSCode version
1.91.1
Vue version
3.4.31
TypeScript version
5.5.2
System Info
System:
OS: Windows 10 10.0.19044
CPU: (12) x64 AMD Ryzen 5 5600 6-Core Processor
Memory: 18.51 GB / 23.92 GB
Binaries:
Node: 20.15.0 - C:\Program Files\nodejs\node.EXE
npm: 10.7.0 - C:\Program Files\nodejs\npm.CMD
pnpm: 9.5.0 - ~\AppData\Roaming\npm\pnpm.CMD
Browsers:
Internet Explorer: 11.0.19041.1566
Steps to reproduce
1.创建项目: pnpm create vite --template vue-ts my-project
2.在App.vue中声明变量: const count = ref(0);
3.折叠style块,会出现行<HelloWorld msg="Vite + Vue" />高亮丢失
4.在<HelloWorld msg="Vite + Vue" />下面再写同样的声明(不复制),写完<HelloWorld />后,紧贴着/左边填写msg字母并根据提示回车后,会出现/丢失(不是百分百出现,建议多尝试,复现概率较高)
What is expected?
HelloWorld组件高亮显示,组件自闭合标签/不丢失
What is actually happening?
HelloWorld组件高亮丢失,组件自闭合标签/在属性补充时缺失
Link to minimal reproduction
No response
Any additional comments?
thanks for you job❤
#4295
The highlight lost problem is reproducible, and the completion problem is tracked in #4295.
The strange thing is that the highlight loss only happens when:
- There is code inside
<script>or<script setup>. And the code mustn't have certain TS error. (e.g.alertoralert+1can cause the problem whilealercannot) - There is a folded SFC-level block after the template block.
Also, the inspector shows that the color is correct:
I think this is related to #4464.
I find that using setTimeout to wrap the relevant code will increase the probability of completion problem.
server.connection.onCompletion(async (params, token) => {
const uri = vscode_uri_1.URI.parse(params.textDocument.uri);
return new Promise(resolve => {
setTimeout(() => { // -> using setTimout to wrap code
worker(uri, token, async (languageService) => {
lastCompleteUri = params.textDocument.uri;
lastCompleteLs = languageService;
const list = await languageService.getCompletionItems(uri, params.position, params.context, token);
for (const item of list.items) {
fixTextEdit(initializeParams, item);
}
return list;
}).then(result => resolve(result))
}, 1000)
})
});
I debugged the code and found that the complete problem seems to be related to the execution order of server.connection.onCompletion and server.connection.onDidOpenTextDocument. For example, the completion option is msg="", the steps when the problem occurs are as follows,
- type
m,server.connection.onDidOpenTextDocumentis executed. server.connection.onCompletionis triggered, but execution is delayed(setTimeout).
https://github.com/volarjs/volar.js/blob/3215b596837e439fb3b8d80bf7ea32c90d417948/packages/language-server/lib/features/languageFeatures.ts#L766-L782
3. type s, server.connection.onDidOpenTextDocument is executed again.
4. the callback of server.connection.onCompletion is executed.
It seems to be no problem if step 4 is before step 3.
- type
m,server.connection.onDidOpenTextDocumentis executed.
- type
s,server.connection.onDidOpenTextDocumentis executed again.
@nieyuyao what do type m, type s mean here?
@nieyuyao what do type
m, typesmean here?
what I mean is that when we entered msg, we actually received m first, and then we received s. onDidOpenTextDocument will be triggered in sequence.
@wlonghaha does the miss end tag problem still reproduce in the latest version?
@wlonghaha does the miss end tag problem still reproduce in the latest version?
版本2.1.8 出现概率极小了,typescript版本5.5之前出现概率大点,之后版本没有问题了,不排除ts server压力大可能会复现,这问题应该无伤大雅了
The issue still exists in the latest version, but it does not reproduce stably
I debugged the code. Here is an example of a style attribute that might help.
I noticed that when I quickly pressed the s and t. The server receives the didChange, completion and didChange messages.
Ideally, the server should process all three messages one by one. But the completion function is asynchronous, so both didChange have already executed when the completion item is actually generated. So the length of final edit range is 2.
Before
After
I don't know how VSCode works. It seems to apply completions to an older version of the document (the content of the document were <div class="virus-decrypt" s> after the first didChange), so > is overwritten.
Save the doc when server receives the completion message. Use this doc to generate completion items instead of latest. That seems to solve the problem. However, this solution is difficult to implement and may need modify lots of code.
I found that vscode-languageserver-protocol supports async message handler in the latest version. This allows the second didChange to be processed exactly after completion.
Highlight issue has been fixed by https://github.com/volarjs/volar.js/pull/271.
If you still have problems with completion overwriting subsequent characters in v3, please open a new issue with steps to reproduce.