voltaを入れてNeovimでTypeScriptを開くとTSEchoMessageエラーが出る対応方法

筆者はエディタにNeovim(NVIM v0.4.4)を使っています。
https://github.com/neovim/neovim

PC初心者なのでなんにもしてないのに壊れてしまい [^1] 、なんとか動くようになったのでログを載せておきます。
なにせPC初心者なので、もっといいやり方をご存じの方は教えてほしいです！

[^1]: https://dic.nicovideo.jp/a/何もしてないのに壊れた


# 筆者のエディタ環境

- コード補完には[coc.nvim](https://github.com/neoclide/coc.nvim)を利用
- TypeScriptとRubyで補完を使っている
- Node.jsのバージョン管理には[volta](https://volta.sh/)を利用 ←ここが肝だったっぽい
- Rubyのバージョン管理には [rbenv](https://github.com/rbenv/rbenv)を利用 ←ここはおまけ

# TL; DR

これで直りました。

```diff:~/.config/nvim/init.vim
+ let g:node_host_prog = '~/.volta/tools/image/packages/neovim/lib/node_modules/neovim/bin/cli.js'
```

ついでに、一緒に出ていたRuby providerの警告はこれで直しました。

```sh
$ rbenv rehash
```

`rbenv rehash` はエラーが出ましたが、こちらを参考にしました。
https://qiita.com/ironsand/items/2f9f20e6e77ab1877160

# 最近何をしたか

Nodeバージョン管理ツールに [volta](https://volta.sh/) を入れた

# 何が起きたか

TypeScreiptファイル(*.ts)をneovimで開いたり、その後カーソル移動をすると、以下のようなエラーが延々と出続けてしまいまったくコーディングができなくなりました。いや、ちょっとはできるだけど1タイプごとにこのようなエラーが出る感じです。


```:ファイルを開いた時
Error detected while processing function remote#define#FunctionBootstrap[1]..remote#host#Require[10]..provider#node#Require:
line    2:
Cannot find the "neovim" node package. Try :checkhealth
Error detected while processing function remote#define#FunctionBootstrap:
line    9:
Host " node" for "TSOnBufLeave" function is not available
Error detected while processing BufUnload Autocommands for "*.ts":
E117: Unknown function: TSOnBufLeave
Error detected while processing function remote#define#FunctionBootstrap:
line    9:
Host " node" for "TSCloseWindow" function is not available
Error detected while processing BufUnload Autocommands for "*.ts":
E117: Unknown function: TSCloseWindow
Error detected while processing function remote#define#FunctionBootstrap:
line    9:
Host " node" for "TSOnBufEnter" function is not available
Error detected while processing BufEnter Autocommands for "*.ts":
E117: Unknown function: TSOnBufEnter
```

```:ファイルを開いてしばらく経った時
Error detected while processing function remote#define#FunctionBootstrap:
line    9:
Host " node" for "TSEchoMessage" function is not available
```

```:カーソル移動したとき
Error detected while processing CursorHold Autocommands for "*.ts":
Error detected while processing CursorMoved Autocommands for "*.ts":
E117: Unknown function: TSCloseWindow
```

# ヘルスチェック

`:checkhealth` すると、 `Ruby provider` `Node.js provider` に不備があるようです。
Neovimは言語プロバイダにpython, ruby, nodeなど外部のエコシステムを使うようなので、それらが壊れると各種言語ファイルを編集する際に不都合が起きてしまうのでしょう（雰囲気で語っている）

そしてTypeScriptに関係するのは `Node.js provider` のほうでしょうから、こちらを直していきたいと思います。
（最後におまけで `Ruby provider` も直します。）


```
...
health#provider#check
========================================================================
...
## Ruby provider (optional)
  - INFO: Ruby: ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-darwin19]
  - WARNING: `neovim-ruby-host` not found.
    - ADVICE:
      - Run `gem install neovim` to ensure the neovim RubyGem is installed.
      - Run `gem environment` to ensure the gem bin directory is in $PATH.
      - If you are using rvm/rbenv/chruby, try "rehashing".
      - See :help |g:ruby_host_prog| for non-standard gem installations.

## Node.js provider (optional)
  - INFO: Node.js: v14.15.3
  - WARNING: Missing "neovim" npm (or yarn) package.
    - ADVICE:
      - Run in shell: npm install -g neovim
      - Run in shell (if you use yarn): yarn global add neovim
```

## Node.js providerを直す

おそらく、これが壊れているからTypeScript的なほげほげができなくなっているのでしょう（雰囲気すら語れていない）。
アドバイスには、npmかyarnで `neovim` をグローバルインストールしてねと書いてありますね。

```
## Node.js provider (optional)
  - INFO: Node.js: v14.15.3
  - WARNING: Missing "neovim" npm (or yarn) package.
    - ADVICE:
      - Run in shell: npm install -g neovim
      - Run in shell (if you use yarn): yarn global add neovim
```

`:h g:node_host_prog` でヘルプを見てみると、 `npm root -g` の実行結果以下の `neovim-node-host` を探しに行くそうですね。でも、これはちょっと遅いので、定数で設定しちゃうといいよ、とも書いてあります。

```
NODEJS PROVIDER CONFIGURATION~
						*g:loaded_node_provider*
To disable Node.js support: >
    :let g:loaded_node_provider = 0
<
						*g:node_host_prog*
Command to start the Node.js host. Setting this makes startup faster.

By default, Nvim searches for "neovim-node-host" using "npm root -g", which
can be slow. To avoid this, set g:node_host_prog to the host path: >
    let g:node_host_prog = '/usr/local/bin/neovim-node-host'
```

インストールしてないワケはないのですが、念のため（？）もう一度インストール。しかし、探しても見つからない。なんで…？ :thinking: 

```sh
$ npm i -g neovim
$ find $(npm -g root) -name '*neovim*'
```

`neovim-node-host` という実行可能ファイルにパスが通っているはずなので、 `which` してみましょう。

```sh
$ ls -l $(which neovim-node-host)
lrwxr-xr-x  1 username  staff    41B Dec 14 20:36 /Users/username/.volta/bin/neovim-node-host -> /Users/username/.volta/bin/volta-shim
```

`~/.volta/bin` 以下の実行可能ファイルはすべて `~/.volta/bin/volta-shim` にリンクが貼られています。おそらく呼び出し時のシンボリックリンクの名前で実体にルーティングしているのでしょう。`~/.volta/bin/volta-shim`はバイナリで（Rust製なので）、何が行われているのかこれ以上は追えませんでした。いや、どこかで追えるのでしょうけど追いませんでした（めんどくさくて）

雰囲気で察するに、どうやらvoltaで管理されたnode/yarnでグローバルインストールされた実行可能コマンドは、 `$(node -g root)` 以下には配置されないようです。ちょっとこの辺の細かい仕組みはよくわかりませんがこのへんが関係していそうです。
https://docs.volta.sh/guide/#install-and-forget

じゃあしょうがない、voltaは便利だから使いたいので `g:node_host_prog` を設定してやろうじゃないか（そっちのほうが速いって言ってるし）

```diff:~/.config/nvim/init.vim
+ let g:node_host_prog = '~/.volta/bin/neovim-node-host'
```

それでも `:checkhealth` でエラー。でも、今度は内容が変わりました。

```
## Node.js provider (optional)
  - INFO: Node.js: v14.15.3
  - INFO: Neovim node.js host:  /Users/username/.volta/bin/neovim-node-host
  - ERROR: Command error (job=24, exit code 1): `node ' /Users/username/.volta/bin/neovim-node-host' --version` (in '/Users/username/develop/project-name')
    Output: internal/modules/cjs/loader.js:883  throw err;  ^Error: Cannot find module '/Users/username/develop/project-name/ /Users/username/.volta/bin/neovim-node-host'    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)    at Function.Module._load (internal/modules/cjs/loader.js:725:27)    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)    at internal/main/run_main_module.js:17:47 {  code: 'MODULE_NOT_FOUND',  requireStack: []}
    Stderr: internal/modules/cjs/loader.js:883  throw err;  ^Error: Cannot find module '/Users/username/develop/project-name/ /Users/username/.volta/bin/neovim-node-host'    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)    at Function.Module._load (internal/modules/cjs/loader.js:725:27)    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)    at internal/main/run_main_module.js:17:47 {  code: 'MODULE_NOT_FOUND',  requireStack: []}
  - ERROR: Failed to run: ['node', ' /Users/username/.volta/bin/neovim-node-host', '--version']
    - ADVICE:
      - Report this issue with the output of: 
      - ['node', ' /Users/username/.volta/bin/neovim-node-host', '--version']
```


「neovim-node-host SyntaxError」でググると、同じ内容でIssueが立っていました。node_host_progに設定するファイルそのものが違う・・・。うーん、ヘルプのADVICEに書いてある内容変えてもらったほうが良いのかな？しょうがないので `/path/to/neovim/bin/cli.js` を設定します。

> `neovim-node-host` is executable, but can't be invoked by `node {filename}.`
> So you should use `let g:node_host_prog=/path/to/neovim/bin/cli.js` in your `.vimrc`
https://github.com/neovim/node-client/issues/92

自力で `neovim/bin/cli.js` を見つけ出します。

```sh
$ find ~/.volta -name 'cli.js' | grep neovim
/Users/username/.volta/tools/image/packages/neovim/lib/node_modules/neovim/bin/cli.js
```

### 解決

```diff:~/.config/nvim/init.vim
+ let g:node_host_prog = '~/.volta/tools/image/packages/neovim/lib/node_modules/neovim/bin/cli.js'
```

`:checkhealth` もOK :ok_hand: 

```
## Node.js provider (optional)
  - INFO: Node.js: v14.15.3
  - INFO: Neovim node.js host: /Users/username/.volta/tools/image/packages/neovim/lib/node_modules/neovim/bin/cli.js
  - OK: Latest "neovim" npm/yarn package is installed: 4.9.0
```

## Ruby providerを直す（おまけ）

```
## Ruby provider (optional)
  - INFO: Ruby: ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-darwin19]
  - WARNING: `neovim-ruby-host` not found.
    - ADVICE:
      - Run `gem install neovim` to ensure the neovim RubyGem is installed.
      - Run `gem environment` to ensure the gem bin directory is in $PATH.
      - If you are using rvm/rbenv/chruby, try "rehashing".
      - See :help |g:ruby_host_prog| for non-standard gem installations.
```

警告内容を読んでみると `neovim-ruby-host` が見つからないので、 `gem install neovim` でインストールしてね、インストール先が `$PATH` に含まれてるようにしてね、rbenvを使ってるならrehashしてみてね、と書いてあります。普通のインストール方法じゃない場合は `:help g:ruby_host_prog` で設定方法を見てね、とも書かれてあります。

仕組みをなんとなく理解したところで、問題の警告が出るプロジェクトを確認します。

```:.ruby-version
2.5.7
```
```
/Users/username/.rbenv/versions/2.5.7/bin/neovim-ruby-host
```

ははぁ、Rubyバージョンには `neovim-ruby-host` は入ってるけど、 `rehash` しないと使えないんですね。
（rehashを理解していなかった）

### 解決

ということで、`rehash` してちゃんとパスが通ることを確認。

```sh
$ rbenv rehash
$ type neovim-ruby-host
neovim-ruby-host is /Users/username/.rbenv/shims/neovim-ruby-host
```

`:checkhelth` も無事Passしました。

新しいRubyバージョンを入れたら、 `gem install neovim` `rbenv rehash` を忘れずに。

```
## Ruby provider (optional)
  - INFO: Ruby: ruby 2.5.7p206 (2019-10-01 revision 67816) [x86_64-darwin17]
  - INFO: Host: /Users/username/.rbenv/shims/neovim-ruby-host
  - OK: Latest "neovim" gem is installed: 0.8.1
```

# あとがき

Vim(Neovim)のヘルプはとても親切ですが、慣れていないと知りたい情報にたどり着くのが難しいですね。
`help: help` をちゃんと学ぶいいきっかけにしたいと思います。