Vimの補完プラグインをインストール。その4

Vimの補完プラグインをインストール。その3で、ddc-tabnineが使えそうです、などと書いたのですが、早速やってみました。

まず、tabnineのバイナリを用意しないといけません。がどうにもTabNineのサイトがわかりにくいので、tabnine-nvimにあるダウンロードスクリプトを利用させてもらいます。
(あるいはこちらのdl-binaries.shを単独でダウンロードして実行しても良いかもしれません)

すると最新バージョンのtabnineがbinaries/4.194.0/x86_64-unknown-linux-musl以下に展開されます。

ddc-tabnineでもダウンロードの仕組みはあるのですが、ちゃんと動かないようです。また、あまりメンテもされていないっぽいです。が、ddcプラグイン自体は動きます。

ちなみzipファイルを展開して出てきたTabNineを実行すると、.config/TabNineというディレクトリが作成されて設定などはここに入るようです。

次にddc-tabnineをdein.vimでインストールします。

call dein#add('LumaKernel/ddc-tabnine')  

でもって、そのページにある設定もvimrcにコピーしておきます。

call ddc#custom#patch_global('sources', ['tabnine'])
call ddc#custom#patch_global('sourceOptions', {
    \ 'tabnine': {
    \   'mark': 'TN',
    \   'maxCandidates': 5,
    \   'isVolatile': v:true,
    \ }})

ここで注意。sourceOptionsのmaxCandidatesは、2022年2月22日にmaxItemsに変更されています。

2022.02.22
* Rename maxCandidates to maxItems.
* Rename ddc#map#insert_candidate() to ddc#map#insert_item().
* Deprecate gatherCandidates attribute.

ですので、そのように修正。

また、sourcesにtabnineを追加します。正直、aroundはいらないかなとも思いますが。

call ddc#custom#patch_global('sources', ['vim-lsp', 'tabnine', 'around'])

ここでVimを終了して再起動すると、TabNineが見つからないとかのエラーが出ます。なので、先程ダウンロードしたbinariesディレクトリをそのまま ~/.cache/ddc-tabnine/以下に移動します。

たぶんここまでくれば動くと思いますが、動かない場合(TabNineがまだ見つからないとか)は、

call ddc#custom#patch_global('sourceParams', {
            \ 'tabnine': {
            \   'maxNumResults': 10,
            \   'storageDir': expand('~/.cache/ddc-tabnine/binaries'),
            \ }})

が必要かもしれません。これはddc-tabnine.txtに書いてあります。

 ということでソースを編集してみると、


ちゃんとTabNineが動いているようです。右のほうに "TN" とありますし。

めでたしめでたし、なんですが、あとはRuffでのisortとか試さないと。

Vimの補完プラグインをインストール。その3

Vimの補完プラグインをインストール。その1でRuffは高速でBlackとFlake8とその他もろもろを置き換えできるという件を書きましたが、ちょっと気になったのでインストールしてみます。

Ruffの公式ブログでは、The Ruff Language Serverで、

Ruff can be used to replace Black, Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, and more, all while executing tens or hundreds of times faster than any individual tool.

isortやその他もろもろを置き換えて、さらに数十倍から数百倍も速い、とうたっています。 githubでは、python-lsp-ruffがありますが、0.4.5以降でRuffは "ruff server" でLSPサーバとして動作するとのことで、それなら直接vim-lspとお話できるはずです。

Ruffのドキュメントでは、もういきなりvim-lspから使用するためにvimrcに記載するコードが書かれていました。

if executable('ruff')
    au User lsp_setup call lsp#register_server({
        \ 'name': 'ruff',
        \ 'cmd': {server_info->['ruff', 'server']},
        \ 'allowlist': ['python'],
        \ 'workspace_config': {},
        \ })
endif

さらに、他のLSP(Pyrightなど)の特定の機能を使いたいために、Ruffと組み合わせて使う場合には、

function! s:on_lsp_buffer_enabled() abort
    " add your keybindings here (see https://github.com/prabirshrestha/vim-lsp?tab=readme-ov-file#registering-servers)

    let l:capabilities = lsp#get_server_capabilities('ruff')
    if !empty(l:capabilities)
      let l:capabilities.hoverProvider = v:false
    endif
endfunction

などとするとよい、という設定も書かれています。tabnineなども使えるのかな?

余談ですが、tabnine-vimはdeprecatedになって、tabnine-nvimに開発が移っているようですが、LSPはお話しないので残念ながらNeovimのみが対象のようです。が、LSP経由ではなくてddc.vim経由なら、ddc-tabnineが使えそうです。

閑話休題。

ArchLinuxではextra/ruffパッケージが用意されているので、pacman -S ruffでインストールできます。

次にvimrcからpylspの設定をコメントアウトして、ruffの設定を加えます。

if (executable('ruff'))
    augroup RuffServer
        autocmd!
        autocmd User lsp_setup call lsp#register_server({
            \ 'name': 'ruff',
            \ 'cmd': {server_info->['ruff', 'server']},
            \ 'allowlist': ['python'],
            \ 'languageId': {server_info->'python'}
            \ })
    augroup END
endif

languageIdはあってもなくても。

これでVimを再起動してtest.pyなどと開くと、ちゃんと使えています。

あと、Vimでの折りたたみをLSPにやらせる設定も変えました。

" folding
" LSPにfoldをやらせる
augroup lsp_folding
    autocmd!
    autocmd FileType * setlocal
        \ foldmethod=expr
        \ foldexpr=lsp#ui#vim#folding#foldexpr()
        \ foldtext=lsp#ui#vim#folding#foldexpr()
    autocmd FileType vim setlocal
        \ foldmethod=syntax
        \ foldlevel=0
augroup end

vimrcを編集するときにLSPに折りたたみをやらせるとなんかウザかったので、vimだけ別扱いにしています。というか、* じゃなくてpythonにしてもよかったかも。

ddc-tabnineはまたそのうち。

Vimの補完プラグインをインストール。その2

Vimでpython-language-serverが動くようになりましたが、もう一つの本題が、いまいじってるvimrcをサポートしてくれるvim-language-server。これがnpmモジュールなんですね、実は。だって自分はTypeScript使わないから、npmもインストールしたくないし。なので、すでにDenoをインストールしているので、このvim-language-server(長いからvimlsにします)をDenoで使えないか、というあたりを攻めてみます。

Dinoは1.25以降でnpmモジュールをサポートするようになったということで、ちょっとこちらの解説を見ても今ひとつピンとこないのですが、要するにimport文やrunコマンドでnpmモジュールを指定することで、npm install相当のことをやってくれて実行できる、ということのようです。

$ pacman -Qs deno
local/deno 1.46.2-1
    A secure runtime for JavaScript and TypeScript
$ deno run npm:vim-language-server --help
✅ Granted env access to "XDG_RUNTIME_DIR".
✅ Granted sys access to "cpus".
error: Uncaught Error: Connection input stream is not set. Use arguments of createConnection or set command line parameters: '--node-ipc', '--stdio' or '--socket={number}'
(スタックトレースは省略)
$ deno run npm:vim-language-server --stdio
✅ Granted env access to "XDG_RUNTIME_DIR".
✅ Granted sys access to "cpus".

実際にはvimlsの他にstreamモジュールも必要だったので、コマンドラインからインストールしています。

$ deno
Deno 1.46.3
exit using ctrl+d, ctrl+c, or close()
REPL is running with all permissions allowed.
To specify permissions, run `deno repl` with allow flags.
> import "npm:stream"
[Module: null prototype] {
  default: <ref *1> [Function: Stream] { Stream: [Circular *1] }
}
>

importするだけでインストールしてくれるので、楽ちん。もっとも、pacmanを使わないので、アップデートはどうするんだろうとかありますが。"npm:stream@0.0.3"とかするとバージョン指定できるので、それでやるのかな。ちなみにnpmモジュールは${XDG_CACHE_HOME}/deno/npm/registry.npmjs.org/の下にダウンロードされるようです。ついでに言えば、globalインストールする方法は調べてません。

それでは、vimlsをDenoで起動してみます。

$ deno run npm:vim-language-server
┏ ⚠️  Deno requests env access to "XDG_RUNTIME_DIR".
┠─ Learn more at: https://docs.deno.com/go/--allow-env
┠─ Run again with --allow-env to bypass this prompt.
┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions) >

なんか許可するかどうするか聞いてきました。

Denoはセキュリティ強化の観点で、環境変数やファイルへのアクセス許可、実行許可などなど、いろいろ聞いてきます。vimlsは裏で起動してくれないと困るので、プロンプトを出さないようにするためにはオプション指定が必要です。-A を指定すると、全部まとめて許可!とかやってくれるみたいですが、推奨は個別指定なので、以下のようにしました。

$ deno run --allow-sys --allow-env --allow-read --allow-run npm:vim-language-server --stdio

--allow-readと--allow-runはvim-lspから起動されるときに必要になります。またvimlsは通信方法を指定しなくてはいけないので、--stdioを指定しています。上記のコマンドで起動すると、標準入力からの入力待ちになります。ということで起動まではOK。

vimlsの起動方法がわかったので、vimrcに設定していきます。

その1ではPythonの設定をしたのでそこから始めますが、それに先立って Neovim のCheckHealthと同等のチェックをしてくれるvim-healthcheckをインストールしておきます。language serversの状態も表示してくれるので、動いているかどうかの確認は簡単にできます。

call dein#add('rhysd/vim-healthcheck')

次に、vim-lspからlsp#regster_serverに食わせるために起動コマンドを記述するのですが、どうもnpmでvimlsをインストールした場合には vim-language-server というシンボリックリンクを作成してそれを起動しているみたいです。今回はDenoから起動する必要があるので、~/binにvim-language-serverというシェルスクリプトを作成して、それを起動することにします。

$ cat ~/bin/vim-language-server
#!/bin/sh
deno run --allow-sys --allow-env --allow-read --allow-run npm:vim-language-server --stdio

当然PATHも通しておきます。

そしてvimrcはこんな感じ。

if (executable('vim-language-server'))
    augroup LspVim
        autocmd!
        autocmd User lsp_setup call lsp#register_server({
            \ 'name': 'vimls',
            \ 'cmd': {server_info->['vim-language-server']},
            \ 'allowlist': ['vim'],
            \ 'initialization_options': {
            \   'vimruntime': $VIMRUNTIME,
            \   'runtimepath': &rtp,
            \   'diagnostic': {'enable': v:true}
            \ }})
    augroup END
endif

最初は'cmd' に 'deno', 'run', ... などと試してましたが、シェルスクリプトを作成するのが一番シンプルだなと思いまして。

これでvimrcを開いて :CheckHealth すると、

lsp: health#lsp#check
=====================
## server status
  - WARNING: pylsp: not running
  - OK: vimls: running

## server configuration: pylsp
  - INFO:
    ### allowlist
    ['python']

## server configuration: vimls
  - INFO:
    ### allowlist
    ['vim']

と表示するようになりました。

そのうちRuffも入れてみようと思います。Ruffはpacmanからインストールできて、python-lsp-serverにプラグインとして組み込めるようなので、BlackやFlake8と同等の設定ができればいいなと考えています。

あと、Vimのmessages、cmdline、popupmenuを置き換えるNoiceというのもあるようで、これはおいおい試してみます。

Vimの補完プラグインをインストール。その1

 もちろんNeovimがいいんだけれど、NeovimとVimは設定を分けることができるし、ディストリビューションで標準でインストールされてるのはVimなことが多いので、Vimの環境づくり。

ちなみに現在のVimバージョンは9.1.707です。

さて、Vimの補完プラグインですが、Shougoさんが作成していたneocomplete.vimは終了し、deoplete.nvimを経て、現在はddc.vimが開発を続けられています。なので、補完フレームワークはddc.vimにして、そうするとLSPとかfileとかいろいろと補完ソースに指定することができるはず。

AURを見るとvim-ddc 0.17.0-1というパッケージソースがあるようなので、dpp.vimのようなプラグインマネージャを利用するか、pacman(自前パッケージ)を利用するか悩むところですが、AURからextraになることもないだろうし、そうするとアップデートも自分でチェックしてやることになって面倒が増えるだろうから、プラグインマネージャで行う方針にします。とりあえずはdpp.vimで考えてみることに。

ddc.vimもそうですが、dpp.vimもDenoを利用し、そのためにdenops.vimをインストールする必要があるので、まずはDenoをインストールします。こちらはpacmanでさっくり。

次にdenops.vimですが、こちらはvim-plugのようなプラグインマネージャでインストールして、と書いてあります。vimballが提供されていれば楽なんですが…。プラグインマネージャのdpp.vimをインストールするにはdenops.vimが必要で、denops.vimをインストールするにはプラグインマネージャが必要という鶏卵問題。

もうちょっとお手軽にいかないかな、と考えた結果、メンテナンスフェーズに移って開発は終了していますがdein.vimを使用することにしました。lazy.nvimに手を出してみたいけど、こちらはVimでは動かないようですし。

ということで、Dein-installer.vimの手順でインストールします。curlなら標準でインストールされているので、curlのほうで行います。さっくり。

すると$HOME/.vimrcに書くべき設定を表示してくれるので、これを.config/vim/vimrcにコピペします。ぺたぺた。

でもってdein#addのところにインストールしたいプラグインを記述します。

call dein#add('vim-denops/denops.vim')
call dein#add('vim-denops/denops-helloworld.vim')

vimrcをリロードしたら、:call dein#install() して、:DenopsHelloしてみると、ちゃんと挨拶を返してくれました。

次はddc.vimです。こちらはフレームワークなので、Vimの場合にはポップアップメニューを表示するための仕組みが必要になるので、pum.vimも必要です。それと、pumのUIを定義するためにddc-ui-pumも必要です…と言い切っちゃっていいのかどうかよくわかりませんが、一応インストールします。

call dein#add('Shougo/ddc.vim')
call dein#add('Shougo/pum.vim')
call dein#add('Shougo/ddc-ui-pum')

また、ddc.vimで入力補完を利用するにはソースプラグインとフィルタプラグインが必要です。ddc.vimはあくまでフレームワークなので。

call dein#add('Shougo/ddc-filter-sorter_rank')
call dein#add('Shougo/ddc-source-around')
call dein#add('Shougo/ddc-filter-matcher_head')

フィルタ用の設定も書き足します。

call ddc#custom#patch_global('sourceOptions', #{
      \   _: #{
      \     sorters: ['sorter_rank'],
      \   }
      \ })
call ddc#custom#patch_global('sourceOptions', #{
      \   around: #{ mark: 'A' },
      \ })
call ddc#custom#patch_global('sourceParams', #{
      \   around: #{ maxSize: 500 },
      \ })

ここまでは下準備で、次がようやく当初の目的のLSP(Language Service Protocol)のインストールです。

よく使うのはPythonなので、まずはPythonからいってみます。

PythonのLSPはMicrosoftのPyrightやPylanceなどもありますが、PyrightもPylanceはTypeScriptで記述されており、動作にはnode.jsが必要です。今回はnode.jsではなくDenoで行きたいので、これはなしの方向で。

ということで、Python LSP Serverことpylspを導入します。pylspはpipでもインストールできますが、pipだと前述したようにアップデートの管理が面倒なので、ArchLinuxのパッケージになっているpython-lsp-serverをインストールします。python-lsp-serverはSpyderプロジェクトにて開発されていたもので、Pythonで記述されているため、速度的には遅いもののnode.jsやnpmは不要です。

# sudo pacman -S python-lsp-server

また、Vim側でLSPをお話するLSPクライアントのプラグインであるvim-lspをインストールします。vim-lspはVimスクリプトで記述されていますが、重たい動作の部分をluaで実装しているため、Vimがluaをサポートしていないと利用できません。幸いArchLinuxのVimは+luaでコンパイルされているので問題なし。

call dein#add('prabirshrestha/vim-lsp')

vim-lspを使ったLSPの設定を用意にするために、vim-lsp-settingsを使ってもよいのですが、実はこれを使うとちょっとnode.jsがゴニョゴニョっぽいので自前で用意します。といっても、vim-lspのページのRegistering Serversの設定をコピペするだけ。なのでコードは省きます。これはpylsp用の設定なので、その他のLSPサーバを利用するときはそれ用の設定を加えないといけませんが、それはまたあとで。

ここまでやれば、あとはddc.vimに渡してやると動くようになります。

call ddc#custom#patch_global('sourceOptions', #{
      \   vim-lsp: #{
      \     matchers: ['matcher_head'],
      \     mark: 'lsp',
      \   },
      \ })

call ddc#custom#patch_global('sources', ['around', 'vim-lsp'])
call ddc#enable()

最後のddc#enable()をcallしないと動きませんが、結構忘れがち。これで .py のファイルを編集するときには自動でpylspが動きます。

とりあえずは動いたので、チューニングなどはおいおい :h vim-lsp などしてやっていきます。

ちなみにちなみに、Python用の高速なlinter/formatterのruffをpylspのプラグインとして利用するpython-lsp-ruffというのもあるようですが、これもまたあとで。これまで使っていたBlackとFlake8を置き換えられるかどうかの検討が必要かなと。Pythonの Ruff (linter) でコード整形もできるようになりましたでは

要約: Flake8 + Black + isort はもうすべて Ruff だけで置き換えられる。

などとあるのでちょっと気になってます。ちなみにruffはRustで書かれていますが、Rustってripgrepのアレだよねぇ、と高速っぽい印象バイアスかかってます。

それとは別に、python-lsp-blackというのもあり、こちらはBlackを使うプラグインです。どっちがいいんだろうか。それと静的型チェックを行うmypyのプラグインpylsp-mypyなんてのもあります。いずれにしてもまたあとで。

ArchLinux on WSLでどたばた。

Windows11のノートPCで、WSLでArchLinuxをインストールしようと思ってちょっと引っかかったところがあったのでメモ。

インストール自体はArchWSLのページの通りで進みましたが、pacman -Syu するとtrusted keyが云々でできませんでした。

そこで、/etc/pacman.d/gnupgをディレクトリごと削除し、また$HOMEにある .gnupg も削除してリブート、次に pacman-key --init してから、pacman-key --populate archlinux すると、archlinux.orgのarchlinux.gpgを追加してくれるので、以降は pacman -Syu できるようになりました。

  1. /etc/pacman.d/gnupgをディレクトリごと削除
  2. $HOMEにある .gnupg も削除
  3.  pacman-key --init
  4. pacman-key --populate archlinux
これ、しばらくぶりにアップデートしようとするとハマるんですよね。

MSYSTEMはどこで設定する?

MSYS2 を今まで pacman でアップデートしてきたんですが、ちょっと apcupsd の apctray.exe をいじりたくて、make したら make がないとか言われたんで調べてみたら、構成がいろいろ変わっていて、/ucrt64 とかいろいろできていて、path を通さないといけないっぽい。ので、ちょっと調べてみました。

MSYS2 にある複数環境、C++ アプリ開発で簡単にまとめられていました。が、さてじゃあどれを使うのがいいのかというと、「自分がやりたいことができる環境にしなさい」らしいのですが……。

本家のドキュメントを見ると、Environments に、

If you are unsure, go with UCRT64.

とあるので、UCRT64 にしてみます。すると、

For example, in the UCRT64 environment the $PATH variable starts with /ucrt64/bin:/usr/bin so you get all ucrt64 based tools as well as all msys tools.

とあるように、UCRT64 環境を選ぶと、$PATH が /ucrt64/bin:/usr/bin というふうに変更されて、パスが通るようになっているようです。デフォルトでは bash が呼ばれるので、まずは /etc/profile が読み込まれるはず。そちらを見ると、

unset MINGW_MOUNT_POINT
. '/etc/msystem'
case "${MSYSTEM}" in
MINGW*|CLANG*|UCRT*)
  MINGW_MOUNT_POINT="${MINGW_PREFIX}"
  PATH="${MINGW_MOUNT_POINT}/bin:${MSYS2_PATH}${ORIGINAL_PATH:+:${ORIGINAL_PATH}}"
  PKG_CONFIG_PATH="${MINGW_MOUNT_POINT}/lib/pkgconfig:${MINGW_MOUNT_POINT}/share/pkgconfig"
  PKG_CONFIG_SYSTEM_INCLUDE_PATH="${MINGW_MOUNT_POINT}/include"
  PKG_CONFIG_SYSTEM_LIBRARY_PATH="${MINGW_MOUNT_POINT}/lib"
  ACLOCAL_PATH="${MINGW_MOUNT_POINT}/share/aclocal:/usr/share/aclocal"
  MANPATH="${MINGW_MOUNT_POINT}/local/man:${MINGW_MOUNT_POINT}/share/man:${MANPATH}"
  INFOPATH="${MINGW_MOUNT_POINT}/local/info:${MINGW_MOUNT_POINT}/share/info:${INFOPATH}"
  ;;
*)
  PATH="${MSYS2_PATH}:/opt/bin${ORIGINAL_PATH:+:${ORIGINAL_PATH}}"
  PKG_CONFIG_PATH="/usr/lib/pkgconfig:/usr/share/pkgconfig:/lib/pkgconfig"
esac

となっていて、2行目(ファイル中では48行目)で /etc/msystem をソースしています。長い行の改行がおかしな感じになってますが。

/etc/msystem を見ると、冒頭に

export MSYSTEM="${MSYSTEM:-MSYS}"

とあって、$MSYSTEM が定義されてなければ "MSYS" を設定するようになっています。

ということは、/etc/msystem が読まれる前に MSYSTEM を設定すれば、あとはドミノ倒しでうまくいきそうです。……なのですが、Shells には、

The launchers set the MSYSTEM variable and open a terminal window (mintty) with a proper shell (bash). Bash in turn sources /etc/profile which sets the environment depending on the value of MSYSTEM.

Without the correct environment, various things may and will (sometimes silently) break. The exception is using mingw subsystems from pure Windows, which shouldn't require any special environment apart from an entry in PATH. Do not set MSYSTEM outside of the shells, because that will also break things.

とあり、最後の行でなんだかよくわからないことが書いてあります。たぶん、ここは「shellが読み込んだ後に MSYSTEM を変えるな」ということだと思うのですが…。

ランチャが MSYSTEM 変数をセットしてから mintty を開くということなので、ランチャを見てみます。msys2_shell.cmd がそれです。すると37行目から、

rem Shell types
if "x%~1" == "x-msys" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=MSYS& goto :checkparams
if "x%~1" == "x-msys2" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=MSYS& goto :checkparams
if "x%~1" == "x-mingw32" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=MINGW32& goto :checkparams
if "x%~1" == "x-mingw64" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=MINGW64& goto :checkparams
if "x%~1" == "x-ucrt64" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=UCRT64& goto :checkparams
if "x%~1" == "x-clang64" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=CLANG64& goto :checkparams
if "x%~1" == "x-clang32" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=CLANG32& goto :checkparams
if "x%~1" == "x-clangarm64" shift& set /a msys2_shiftCounter+=1& set MSYSTEM=CLANGARM64& goto :checkparams
if "x%~1" == "x-mingw" shift& set /a msys2_shiftCounter+=1& (if exist "%WD%..\..\mingw64" (set MSYSTEM=MINGW64) else (set MSYSTEM=MINGW32))& goto :checkparams

などとなっています。どうやら、msys2_shell.cmd に続いてハイフンとシェルタイプを指定すればよいようです。

うちの場合、Windows Terminal を使って MSYS2 を開くので、今までは

C:/Apps/msys64/msys2_shell.cmd -no-start -defterm -msys2 -here -shell zsh

としていましたが、UCRT64環境にしたければ -msys2 を -ucrt64 にすればよいようです。てっきり /etc 以下のどこかのファイルかと思ってしまいました。

AstroNvimでtelescope.nvimがエラーを吐いたとき。

Windowsの環境でAstroNvimをインストールして、Find Fileしたらtelescopeがエラーを吐いてきました。


メッセージは、
Failed to run `config` for telescope.nvim
...a/lazy/telescope.nvim/lua/telescope/extensions/init.lua:10: 'fzf' extension doesn't exist or isn't installed: ...nvim-data/lazy/

なんて感じになってます。 

~/.local/share/nvim-data/lazy/telescope-fsf-native.nvim を見ると、Makefileがあってsrcディレクトリがありますから、AstroNvimのインストール時にコンパイルしようとしてずっこけているようです。

Makefileを見てみると、libfzf.dllを作成して配置してやればよさそうなので、msys64のコンソールを起動してMakefileのあるディレクトリに移動し、make一発。buildディレクトリが作成されて、無事libfzf.dllができあがりました。ちなみに他のディレクトリにインストールする必要はなく、このbuildディレクトにあることが必要なようです。

Neovimを起動してみると上記のエラーは消えていました。めでたしめでたし。

WesternDigitalこわれた。

たぶん寿命を過ぎてるのでクレームとまではいかないのだけれど。

WesternDigitalのWD60EFRXが壊れました。モノは2014年11月に購入。ところが3年で壊れ、RMAにより2017年11月に交換したものです。BlackBlazeでも故障率がそれなりに高かったので、そういうもんなんだろうな、という感じですが。

ちなみに症状は、PCをリブートしたらいきなりWindowsの起動画面で画面中央下のマルがくるくると永遠に回り続ける状態で、最悪ブートドライブ交換の再インストールコースかと覚悟し、m.2 ssdとかいろいろ準備してから取り掛かったらWDがおかしくて止まってたというオチ。スピンドルは回ってるようだけどヘッドの動く音がしないので、叩けば治るかもですが。

ただ、中のデータはそんなに大事なものではなく、さらに大容量の東芝16TBを導入してコピーしていたはずなので、暇を見てコンコンしてみます。

TeXLive2024がインストールできない。

TeX Live 2024がリリースされていたので、インストールしてみました。

BitTorrentでISOをダウンロードして、ISOイメージをダブルクリックすると自動でマウントされるので、そのままinstall-tl-windows.batを実行。するとエラーになります。


こんな感じ。もしかしたらPythonのtcl/tkとかち合ってるのかもしれません。

ぐぐってみるとError in Installation Processにあるのが同じ状態でした。

結論として、コマンドプロンプトを開いて

i:\install-tl-windows.bat -texdir c:\texlive\2024 -gui text

とすれば、GUIなしでインストーラを起動でき、無事にインストールできました。

QNAPで/etc以下のファイルを置き換える。

うちのQNAP NASはちょっと古いTS-669Lです。

[    0.017724] CPU0: Intel(R) Atom(TM) CPU D2701   @ 2.13GHz stepping 01

dmesgではx86アーキテクチャのAtom D2701を使っていることがわかります。
アプリケーションのアップデートに合わせて、時たまQTSのアップデートもありますが、

[  522.957235] ====== 2024-05-04 09:16:06 TS-669L (4.3.4.2675-20240131) boot finished.

バージョンは4.3.4。2017年にリリースされたものです。最新バージョンはQTS 5.2です。なのですでにサポート対象外です。一応、最新の筐体をディスクレスで持ってきて、HDDを順番通りに載せ替えれば使えるらしいですが、でもちゃんと使えてますので。16TBx6ですけど、使えてますので。

ところでこのQNAP、App Centerで提供されているアプリ以外にも、Linuxで利用できる色々なソフトウェアが利用できるようになっています。メールサーバやWikiサーバにすることもできます。そのためには、Entware-stdをインストールして、QPKGを使えるようにする必要があります。

Entware-stdは、以前にあったEntware-ng-3xとEntware-ngが1本化されたものです。インストール方法は、こちらにあります。このページにあるリンクからqpkgをダウンロードして、App Centerの右上にある田の字っぽいアイコンから手動インストールを行います。

次に、ユーザのホームディレクトリ($HOME)に、.profileを作成します。Entware-stdは/opt/etcにprofileファイルを作成し、opkgでインストールされるディレクトリへのパスなどを設定するようになっています。なので、Entwareをインストールしたら、$HOMEに以下の内容を記述した.profileを作成して、/opt/etc/profileをソースします。

source /opt/etc/profile

Entware-stdはGUIアプリではないので、いろいろとインストールするにはsshログインする必要があります。が、sshログインするためのいろいろは割愛で。

Entwareはopkgコマンドで管理します。sshログインしてopkgとタイプすると、ずらーっとコマンドオプションが表示されます。リポジトリのパッケージリストを取得するには、
opkg update

します。ちなみにパッケージリストはここにあるものと同じ内容みたいです。が、ここでroot(あるいはadmin)権限がないと、パッケージリストのxmlファイルを保存できずにエラーになります。もちろんadminアカウントでログインすればいいんですが、個人的セキュリティポリシーとしては通常ユーザでログインして、suなりsudoなりしたいです。使い勝手ならsudoがベスト。でも、sudoするにはsudoersにユーザの記述をしないといけません。標準で入っているsudoは、/usr/etcからsudoersを読み込んでいます。ところがこのディレクトリは、リブートのたびにリフレッシュされます。つまり、起動後にこのsudoersを編集しても、リブートするともとに戻ってしまいます。

リフレッシュするにはオリジナルが必要ですが、そのオリジナルは /mnt/HDA_ROOT/.config にあります。が、そこにはsudoersがありません。どこにあるのか調べようと思っても、ディレクトリツリーもいろいろあっちゃこっちゃしていて、探すのめんどくさい。こんなときこそlocate!……入ってません。しかたないからfindで……Permission denied。

じゃあどこかにファイルを作っておいて、起動時に自動で上書きコピーするしかないか、ということでぐぐってみると、Running Your Own Application at Startupなるページを見つけました。起動時にautorun.shを実行してくれるようです。

autorun.shを使用するには、QNAPのコントロールパネルから、「システム」➔「ハードウェア」➔一般タブの「起動時にユーザー定義処理を実行」にチェックを入れて、autorun.shを実行してくれるように設定します。


起動時のどのタイミングで実行されるのかがわからないので、そのあたりは試してみるしかなさそうです。が、ここにあらかじめ用意しておいたファイルをコピーするような指示を入れれば、うまくいきそうです。もっとも、パーミッションとかセキュリティ的に考えることがありそうなので、/mnt/HDA_ROOT/.autorunなどのフォルダを作ってsudoersなどを置き、それをコピーするようにすればよさそう。

なのですが、もうちょっとクレバーなやり方はないかな、と探してみたら、create-autorunというのを見つけました。これは、上記の方法で作成されたautorun.shをお仕着せで作成してくれるツールです。このツールを使うと、

/share/CACHEDEV1_DATA/.system/autorun/autorun.sh

を自動で作成してくれます。さらに、

/share/CACHEDEV1_DATA/.system/autorun/scripts/

以下に、rc.dスクリプトのように数字付きでスクリプトを置くことで、順番に実行してくれるようです。

このツールはインストールする必要はなく、adminアカウントで

curl -skL https://git.io/create-autorun | sudo bash

などとすればよさそう。

実行すると以下のようにメッセージが出力されます。幅が足りなくて改行が変ですが。

[/mnt/HDA_ROOT] # curl -skL https://git.io/create-autorun | sudo bash
create-autorun.sh 230527
info: NAS model: TS-669L
info: QTS version: 4.3.4 #20240131
info: default volume: /share/CACHEDEV1_DATA
info: autorun partition should be: /dev/sdg6
done: mounted: ext2 device: /dev/sdg6 -> /tmp/create-autorun.fh0ERU
info: confirmed partition tag-file exists: uLinux.conf (we're in the right place)
done: created autorun script processor: /share/CACHEDEV1_DATA/.system/autorun/autorun.sh
done: created script store: /share/CACHEDEV1_DATA/.system/autorun/scripts
done: created symlink from partition to autorun.sh
skip: autorun.sh is already enabled in OS
done: unmounted ext2 autorun partition
info: please place your startup scripts into: /share/CACHEDEV1_DATA/.system/autorun/scripts
info: your autorun.sh file is located at: /share/CACHEDEV1_DATA/.system/autorun/autorun.sh 

インストールしたら、/share/CACHEDEV1_DATA/.system/autorun/scriptsに必要なスクリプトを記述すればいいので、まずsudoersをコピーしてきます。
mkdir etc
/share/CACHEDEV1_DATA/.system/autorun/etc
cp /usr/etc/sudoers .

そしてsudoersを修正したあと、00_sudoersとでもしてscripts以下にファイルを作成します。

#!/usr/bin/env bash
ETC_DIR=/share/CACHEDEV1_DATA/.system/autorun/etc
cp -v ${ETC_DIR}/sudoers /usr/etc

これでsudoが使えるようになりました。

さっそくzshをインストール。

[kats@QNAP ~]$ opkg list zsh
zsh - 5.9-2 - Zsh is a UNIX command interpreter (shell) usable as an interactive
 login shell and as a shell script command processor. Of the standard
 shells, zsh most closely resembles ksh but includes many enhancements.
 Zsh has command line editing, builtin spelling correction, programmable
 command completion, shell functions (with autoloading), a history
 mechanism, and a host of other features.
[kats@QNAP ~]$ sudo opkg install zsh
Installing zsh (5.9-2) to root...
Downloading http://bin.entware.net/x64-k3.2/zsh_5.9-2_x64-3.2.ipk
Installing libcap (2.69-1) to root...
Downloading http://bin.entware.net/x64-k3.2/libcap_2.69-1_x64-3.2.ipk
Installing libncursesw (6.4-2a) to root...
Downloading http://bin.entware.net/x64-k3.2/libncursesw_6.4-2a_x64-3.2.ipk
Installing libncurses (6.4-2a) to root...
Downloading http://bin.entware.net/x64-k3.2/libncurses_6.4-2a_x64-3.2.ipk
Configuring libcap.
Configuring libncursesw.
Configuring libncurses.
Configuring zsh.
[kats@QNAP ~]$ which zsh
/opt/bin/zsh

めでたしめでたし。

Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。

 busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv[0] を調べて、その名前によって動作を変える、ということをしたい、ということです。

まずは argtest.py というファイルを作ります。

import sys
import pathlib

f = pathlib.Path(sys.argv[0])
print(sys.argv)
print(f.name)
print(__file__)

これを実行すると、

C:\Users\kats\projects\argtest>argtest.py
['C:\\Users\\kats\\projects\\argtest\\argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>py argtest.py
['argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>python argtest.py
['argtest.py']
argtest.py

のようになります。py または python を指定して実行するとファイル名のみ、直接実行するとフルパス名が argv[0] に入っているようです。

次にショートカットを作成してみます。コマンドプロンプトから作るのは WSH を呼び出すスクリプトが必要なようなので、エクスプローラーから行います。

作成すると、 "argtest.py - ショートカット.lnk" というファイルが作成されます。サフィックスの ".lnk" は拡張子を表示する設定にしないと表示されませんが、ショートカットにつく拡張子です。余談ですが、".lnk" をリネームで削除してもショートカットとして使えるようです。

C:\Users\kats\projects\argtest>"argtest.py - ショートカット.lnk"
['C:\\Users\\kats\\projects\\argtest\\argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>py "argtest.py - ショートカット.lnk"
  File "C:\Users\kats\projects\argtest\argtest.py - ショートカット.lnk", line 1
    L
SyntaxError: source code cannot contain null bytes

C:\Users\kats\projects\argtest>python "argtest.py - ショートカット.lnk"
  File "C:\Users\kats\projects\argtest\argtest.py - ショートカット.lnk", line 1
    L
SyntaxError: source code cannot contain null bytes

実行するとショートカットをダイレクトに起動した場合以外はエラーになります。また、ダイレクトに起動した場合でも argv[0] には元ファイルのファイル名が入っているようです。これだと、呼び出しファイル名で動作を変えることができません。

ちなみに、エディタによっては、ショートカットファイルを編集すると、その元ファイルを開いてくれるものもあるようです。

ショートカットでは argv[0] に元ファイル名しか入っていないと、動作を変えることができません。UNIX系OSではシンボリックリンクを実行形式ファイルに張ると、ちゃんと argv[0] にシンボリックリンクの名前が入ってくるので、Windows上でシンボリックリンクが使えないか調べてみました。

Windowsには標準コマンドで mklink というのがあるようです。mklinkではハードリンクも作成できるようですが、同一のファイルシステム内にしか作成できないということで、ここではシンボリックリンクを試します。

ちなみにmklinkの実行は管理者権限が必要で、通常のコマンドプロンプトから実行すると怒られます。

C:\Users\kats\projects\argtest>mklink argtest2.py argtest.py
argtest2.py <<===>> argtest.py のシンボリック リンクが作成されました

シンボリックリンクを作成しました。早速実行してみると、

C:\Users\kats\projects\argtest>argtest2.py
['C:\\Users\\kats\\projects\\argtest\\argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>py argtest2.py
['argtest2.py']
argtest2.py
C:\Users\kats\projects\argtest\argtest2.py

C:\Users\kats\projects\argtest>python argtest2.py
['argtest2.py']
argtest2.py
C:\Users\kats\projects\argtest\argtest2.py

となります。今度は直接実行した場合に元ファイル名が出てきました。なかなかうまくいかないもんです。がっくし。

余談ですが、開発者モードというのを有効にしてやると、管理者モードのコマンドプロンプトでなくてもmklinkは実行できるようです。が、セキュリティ的によろしくないのでやめておきます。

ついでに、ものは試しでハードリンクもやってみます。

C:\Users\kats\projects\argtest>argtest3.py
['C:\\Users\\kats\\projects\\argtest\\argtest3.py']
argtest3.py
C:\Users\kats\projects\argtest\argtest3.py

C:\Users\kats\projects\argtest>py argtest3.py
['argtest3.py']
argtest3.py
C:\Users\kats\projects\argtest\argtest3.py

C:\Users\kats\projects\argtest>python argtest3.py
['argtest3.py']
argtest3.py
C:\Users\kats\projects\argtest\argtest3.py
これだとバッチリみたいですね。うーむ。

Vimの補完プラグインをインストール。その4

Vimの補完プラグインをインストール。その3 で、 ddc-tabnine が使えそうです、などと書いたのですが、早速やってみました。 まず、tabnineのバイナリを用意しないといけません。がどうにもTabNineのサイトがわかりにくいので、 tabnine-nvim にあるダ...