## 事象 ```html <template> <div <header> <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> ``` カーソルは `<div` のあとにあり補完候補が出ている状態で決定すると以下のようになる。 ```html <template> <divr> <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> ``` 期待結果は ```html <template> <div> <header> <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> ``` ### 再現手順 ```console bun create vue@latest vue-sandbox ``` `TypeScript` だけ有効にする。 ```console cd vue-sandbox bun i bun dev ``` `./src/App.vue` を開いて事象のように入力する。 #### 補足 - [[VSCode]]では再現しない - [[HTML]]では再現しない ### 環境 ``` + @tsconfig/[email protected] + @types/[email protected] + @vitejs/[email protected] + @vue/[email protected] + [email protected] + [email protected] + [email protected] + [email protected] + [email protected] + [email protected] ``` | 対象 | バージョン | | --------------------------------- | ----------- | | [[Ubuntu]] | 24.04.1 LTS | | [[Neovim]] | 0.11.0 | | [[blink.cmp (Neovim)\|blink.cmp]] | cb5e346 | | [[nvim-lspconfig]] | b70b900 | | [[vue-language-server]] | 2.2.8 | ### LspInfo ``` ============================================================================== vim.lsp: require("vim.lsp.health").check() - LSP log level : WARN - Log path: /home/tadashi-aikawa/.local/state/nvim/lsp.log - Log size: 0 KB vim.lsp: Active Clients ~ - volar (id: 1) - Version: ? (no serverInfo.version response) - Root directory: ~/tmp/vue-sandbox - Command: { "/home/tadashi-aikawa/.local/share/mise/installs/npm-vue-language-server/2.2.8/bin/vue-language-server", "--stdio" } - Settings: vim.empty_dict() - Attached buffers: 12 - copilot (id: 2) - Version: 1.304.0 - Root directory: ~/tmp/vue-sandbox - Command: { "node", "/home/tadashi-aikawa/.local/share/nvim/lazy/copilot.lua/copilot/js/language-server.js", "--stdio" } - Settings: { telemetry = { telemetryLevel = "all" } } - Attached buffers: 12 vim.lsp: Enabled Configurations ~ vim.lsp: File Watcher ~ - file watching "(workspace/didChangeWatchedFiles)" disabled on all clients vim.lsp: Position Encodings ~ - No buffers contain mixed position encodings ``` ## 原因 不明 ## 解決方法 [[Volar]]の再インストール。 ``` mise rm npm:@vue/language-server mise use -g npm:@vue/language-server ``` ## 調査記録 ### blink.cmpのバージョンを変更する `cb5e346` は v1.1.1 なので #2025/04/04 時点のもの。これをmasterにしてみる。 だが変わらず。以前からこうだったのかは自信がない。[[blink.cmp (Neovim)|blink.cmp]]に変更したのは #2025/04/05 であり、それ以降はWebの開発をあまりやっていないので、[[nvim-cmp]]から移行した影響の可能性もある。たが、それにしては[[Vue]]だけというのも...。 ### [[Vue]]のバージョンについて 3.5.13が #2024/11/15 とかなり前であり、その頃はWeb開発バリバリやっていたのでそれが原因とは考えにくい。 ### [[nvim-lspconfig]]のバージョンを変更する #2025/04/05 時点の `2aacdb48` まで下げてみる。 変わらず。 ### blink.cmpの `completion.list.selection` 設定を変更する `preselect` と `auto_insert` を共にfalseにしたが効果はない。 ```lua completion = { list = { selection = { preselect = false, auto_insert = false, }, }, ``` ### 他のプラグインを無効化してみる 怪しそうなものを一通り。 - [[conform.nvim]] - [[copilot.lua]] - [[Lspsaga]] - [[ns-textobject.nvim]] - [[nvim-autopairs]] - [[nvim-surround]] - [[nvim-ts-autotag]] - [[obsidian.nvim]] - [[timber.nvim]] - [[tiny-inline-diagnostic.nvim (Neovim)|tiny-inline-diagnostic.nvim]] 変わらず。。まじか。。 ### [[nvim-lspconfig]]で[[Volar]]の[[Hybrid Mode]]を有効にする ```lua lspconfig.volar.setup({ capabilities = capabilities, filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" }, init_options = { vue = { -- デフォルト有効だけど明示的にfalseからtrueへ hybridMode = true, }, ``` 変わらず。 ### LSPのログを確認する 以下のようなログが出力されたので、[[LSP]]の結果がそもそもおかしい気がする。少なくとも、この補完で `line` が複数行にまたがることはあり得ないので。 ```lua textEdit = { newText = "div", range = { start = { character = 3, line = 6 }, ["end"] = { character = 5, line = 7 } } } ``` となるとこちらで対応するのは厳しそう。 ### nvim-cmpに戻してみる 問題が改善した... というよりは[[HTML]]タグ周りの補完が出なくなったので、結果的にそれを踏むことがなくなっただけな気がしている。 ### Issueの作成 必要な情報を記載してIssueを出してみる。 <div class="link-card-v2"> <div class="link-card-v2-site"> <img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" /> <span class="link-card-v2-site-name">GitHub</span> </div> <div class="link-card-v2-title"> When completing HTML tags within a template tag in Neovim, text gets overwritten in unexpected areas. · Issue #5331 · vuejs/language-tools </div> <div class="link-card-v2-content"> Vue - Official extension or vue-tsc version 2.2.8 VSCode version 1.99.3 Vue version 3.5.13 TypeScript version 5. ... </div> <img class="link-card-v2-image" src="https://opengraph.githubassets.com/228fa0535ab4814cb2dd1a84e443cf22d6266b3c17f53e0f39d9bf51810f4044/vuejs/language-tools/issues/5331" /> <a href="https://github.com/vuejs/language-tools/issues/5331"></a> </div> #### blink.cmp x nvim-lspconfig の再現構成 再現しないので最小構成が欲しいと回答をもらった。 `repro.lua` ```lua local root = vim.fn.fnamemodify("./.repro", ":p") for _, name in ipairs({ "config", "data", "state", "cache" }) do vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name end local lazypath = root .. "/plugins/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath }) end vim.opt.runtimepath:prepend(lazypath) local function get_typescript_server_path(root_dir) local project_root = vim.fs.dirname(vim.fs.find("node_modules", { path = root_dir, upward = true })[1]) return project_root and vim.fs.joinpath(project_root, "node_modules", "typescript", "lib") or "" end ---@type vim.lsp.Config vim.lsp.config.volar = { cmd = { "vue-language-server", "--stdio" }, filetypes = { "vue" }, root_markers = { "package.json" }, init_options = { typescript = { tsdk = "" } }, before_init = function(_, config) if config.init_options and config.init_options.typescript and config.init_options.typescript.tsdk == "" then config.init_options.typescript.tsdk = get_typescript_server_path(config.root_dir) end end, } vim.lsp.enable({ "volar" }) local plugins = { { "saghen/blink.cmp", version = "*", opts = { completion = { documentation = { auto_show = true }, }, }, }, } require("lazy").setup(plugins, { root = root .. "/plugins", }) ``` この設定にして編集すると再現する。 ```console nvim -u repro.lua src/App.vue ``` #### blink.cmp のみの再現構成 [[nvim-lspconfig]] `volar` 設定を直接書いただけ。 ```lua local root = vim.fn.fnamemodify("./.repro", ":p") for _, name in ipairs({ "config", "data", "state", "cache" }) do vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name end local lazypath = root .. "/plugins/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath }) end vim.opt.runtimepath:prepend(lazypath) local function get_typescript_server_path(root_dir) local project_root = vim.fs.dirname(vim.fs.find("node_modules", { path = root_dir, upward = true })[1]) return project_root and vim.fs.joinpath(project_root, "node_modules", "typescript", "lib") or "" end ---@type vim.lsp.Config vim.lsp.config.volar = { cmd = { "vue-language-server", "--stdio" }, filetypes = { "vue" }, root_markers = { "package.json" }, init_options = { typescript = { tsdk = "" } }, before_init = function(_, config) if config.init_options and config.init_options.typescript and config.init_options.typescript.tsdk == "" then config.init_options.typescript.tsdk = get_typescript_server_path(config.root_dir) end end, } vim.lsp.enable({ "volar" }) local plugins = { { "saghen/blink.cmp", version = "*", opts = {}, }, } require("lazy").setup(plugins, { root = root .. "/plugins", }) ``` #### 職場環境だと再現しない ```console - ts_ls (id: 1) - Version: ? (no serverInfo.version response) - Root directory: ~/work/vue-sandbox - Command: { "/home/tadashi-aikawa/.local/share/mise/installs/npm-typescript-language-server/4.3.3/bin/typescript-language-server", "--stdio" } - Settings: vim.empty_dict() - Attached buffers: 10 - volar (id: 2) - Version: ? (no serverInfo.version response) - Root directory: ~/work/vue-sandbox - Command: { "/home/tadashi-aikawa/.local/share/mise/installs/npm-vue-language-server/2.1.10/bin/vue-language-server", "--stdio" } - Settings: vim.empty_dict() - Attached buffers: 10 ``` ```console npm:@vue/language-server 2.2.10 ~/.config/mise/config.toml latest npm:@vue/typescript-plugin 2.2.10 ~/.config/mise/config.toml latest npm-typescript 5.6.2 npm-typescript-language-server 4.3.3 ``` 2.2.10 -> 2.2.8 にあわせても再現しない。 #### 家の環境ふたたび ```console npm:@vue/language-server 2.2.8 ~/.config/mise/config.toml latest npm:@vue/typescript-plugin 2.2.8 ~/.config/mise/config.toml latest npm:typescript 5.8.2 ~/.config/mise/config.toml latest npm:typescript-language-server 4.3.4 ~/.config/mise/config.toml latest ``` [[TypeScript]]バージョンは利用されていないのでさておき、[[TypeScript Language Server]]のマイナーバージョン違うのは気になる。。。ただ、変更内容的には関係なさそうに見える。 <div class="link-card-v2"> <div class="link-card-v2-site"> <img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" /> <span class="link-card-v2-site-name">GitHub</span> </div> <div class="link-card-v2-title"> Release v4.3.4 · typescript-language-server/typescript-language-server </div> <div class="link-card-v2-content"> 4.3.4 (2025-02-26)Bug Fixespreviewer: mark @example and @default code blocks as TS (#918) (184c60d) </div> <img class="link-card-v2-image" src="https://opengraph.githubassets.com/72baa6c986f33c44bbd4a29ca772dd9e5f757a19a823b2ccefc22ac4e8416254/typescript-language-server/typescript-language-server/releases/tag/v4.3.4" /> <a href="https://github.com/typescript-language-server/typescript-language-server/releases/tag/v4.3.4"></a> </div> ##### [[TypeScript Language Server]]バージョンを下げてみる ```console mise use -g npm:[email protected] ``` 関係なかった。 ##### [[TypeScript]]バージョンを下げてみる ```console $ mise use -g npm:[email protected] Reshimming mise 22.8.0... mise npm:[email protected] ✓ installed mise ~/.config/mise/config.toml tools: npm:[email protected] ``` 関係なかった。5.6.2や5.8.3も試したけどダメ。 ##### [[Volar]]を再インストールしてみる ``` mise rm npm:@vue/language-server ``` ```console $ mise use -g npm:@vue/language-server mise use -g npm:@vue/language-server Reshimming mise 22.8.0... mise npm:@vue/[email protected] ✓ installed mise ~/.config/mise/config.toml tools: npm:@vue/[email protected] ``` 2.2.10とバージョンは上がっているが、職場ではどちらも再現しなかったので問題ないはず。**なおった!** #### 解消した旨を連絡 <div class="link-card-v2"> <div class="link-card-v2-site"> <img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" /> <span class="link-card-v2-site-name">GitHub</span> </div> <div class="link-card-v2-title"> When completing HTML tags within a template tag in Neovim, text gets overwritten in unexpected areas. · Issue #5331 · vuejs/language-tools </div> <div class="link-card-v2-content"> Vue - Official extension or vue-tsc version 2.2.8 VSCode version 1.99.3 Vue version 3.5.13 TypeScript version 5. ... </div> <img class="link-card-v2-image" src="https://opengraph.githubassets.com/61ecab88cf3c5e46b5cfaf87fd3ba01f8092578f9d81b5afc69c7e502389ccb1/vuejs/language-tools/issues/5331" /> <a href="https://github.com/vuejs/language-tools/issues/5331#issuecomment-2824109773"></a> </div>