LoginSignup
2
1

More than 1 year has passed since last update.

そんなvimrcで大丈夫か?2022年のオレオレ環境構築メモ

Last updated at Posted at 2022-12-18

vimrcの話をしよう

あれは今から36万…いや、1万4千年前だったか。まぁいい。
私にとってvimrcを書いたのはつい昨日の出来事だが、
来年の私にとっては多分、明日の出来事だ。

vimrcには無数の書き方があるから、どう書けば良いのか…

そんなvimrcで大丈夫か?

2022年12月の僕のvimrcの特徴は下記の通り

  • LSPを使った非同期自動補完
  • Coc等は敢えて使わず、最良の未来を思い、自由に選択していけ
  • 20ms程度で起動するし起動後もヌルヌル
  • vimでもneovimでも動く
  • pythonのLSPに対する拡張
  • vimrc内部に目次をつけて管理する
  • インストールは一部を除いて自動でしてくれる

パクった設定は多いが…こんなリポジトリは誰も見ないから大丈夫だ、問題ない。多分。

Cocのサポートが心配なのかい?

いいんじゃないかな、Cocもよくやってくれるしね。

しかし、Cocはおま環に遭遇して私のvimrcは一度爆死したのだ…しかし、神は言っている、ここで死ぬ定めではないと。

後で知ったけれど、暗黒美無王はCocやYouCompleteMeによる弊害を下記の記事でこう指摘している。

そのプラグインの世界だけで完結する作業ならば極上の快適さが約束されますが、自由に設定し他のプラグインを組み合わせようとすると容易に破綻します。

つまり、僕のように半端に非公開のプラグインもどきを作ったりする素人にはむしろ難しいことがあるようだ。人が持つ唯一絶対の力、それは自らの意志で進むべき道を選択することだ。

一番いいプラグインを頼む

正直、一番いいプラグインなんて分かりません。代替は多分もっと沢山あります。
今回は下記を組み合わせる方法をとりましたが、最良の未来を思い、自由に選択していけ。

名前 機能 代替になるもの?
vim-lsp vimでLSPを使うためのプラグイン neovimの新しい機能?, Coc
vim-lsp-settings vim-lspの設定を簡単にする Coc
ddc 自動補完を行う asyncomplete?, Coc
ddc-vim-lsp ddcとvim-lspを組み合わせる ddc-nvim-lsp, Coc

プラグイン管理ソフトは速度性能を求めるためにdeinを導入します。
さらに、vimrcの運用をスムーズにするために、目次をつけます。
githubでdotfileとして使うとしても、プライベートリポジトリはサクッとワンライナーで落とせないです。サクッとしたいこともあるから公開設定は必要。内容が理解できなかったらいけないので、この記事も必要。詰めた設定は手元のクローンでブランチを作りたいです。それぞれの環境が違うこともあるので、基本のvimrcと追加のvimrcを分けたいです。
当然ですが、ファイル分けすぎると性能が落ちます。

vim本体

vimの種類でもそれなりに変わります。vimにはtiny, normal, huge, fullがありますので色々選べるのですが、Vim scriptをまともに動かすためにはnormal以上が必要です。
vimとneovimが有力というのは周知の事実ですが、このneovimでもappimage版はどこでも動く代わりに起動とかが遅いです。最良の未来を思い、自由に選択していけ。

考えたくないけれど、どちらかがお亡くなりになる可能性も微レ存です。だから、両方で動く事が必要です。

依存ソフト

まずは入れようと思っている自動補完プラグインのddc.vimがDeno依存なので、denoを入れます。界隈にはDeno依存のプラグインがそれなりにあるようです。どうせDenoをいれるならということで、自作スクリプトもDeno製に決定。

以下、公式サイトからの引用。

インストール

Unix

curl -fsSL https://deno.land/x/install/install.sh | sh

WindowsPowershell

irm https://deno.land/install.ps1 | iex

scoop

scoop install deno

chocolatey

choco install deno

homebrew

brew install deno

cargo

cargo install deno --locked

プラグイン管理ソフトDein

色々なプラグイン管理ソフトがありますが、最良の未来を思い、自由に選択していけ。
今回選んだのはスピードの速いDein。多機能で高性能なので、使い心地はやや玄人向け?な感じです。一度設定してしまえばQOLが上がります。
他にはvimplugとかもいいですよね。

ちなみに、下記に依存しているのでそれらも入れることになります。インストーラーが用意されているので、それほど意識することはありません。

  • roxma/nvim-yarp
  • roxma/vim-hug-neovim-rpc

以下、リポジトリからの引用。

インストール

wget

sh -c "$(wget -O- https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh)"

curl

sh -c "$(curl -fsSL https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh)"

powershell

Invoke-WebRequest https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.ps1 -OutFile installer.ps1
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
./installer.ps1 ~/.cache/dein

プラグインを入れる時の注意

プラグインを入れるにあたり、出来る限り遅延読み込みをします。遅延読み込みをすることにより、起動が速くなります。
例えばDeinであれば下記のようにします。

call dein#add('prabirshrestha/vim-lsp', {'lazy': 1, 'on_event': 'VimEnter'})

VimEnterはvimの起動処理が終わった後という意味です。細かいプラグインは後で読めばいいので、さっさと起動してコードを表示してもらいましょう。
このVimEnterとかは一覧があります。下記で見られます。

help event

自分のVim scriptがあるなら、下記で発火のタイミングを指定できます。

autocommand VimEnter * ほげほげコマンド

だいたいこんな感じ。このような設定を行うことにより、起動時の体感速度は圧倒的になります。
…と言っても、素のvim(vim -u NONE)に比べると10倍以上遅いですが。

LSP

Language server protocolの略です。外部のソフトがvimで書いている事について色々してくれるやつですね。

vimでやる場合、vim-lspがあるのですが、vim-lspはvimとLSPを繋ぐだけです。最良のLSPを思い、自由に選択していけ…と言いたいところですが、これの面倒臭さは異常です。
vim-lsp-settingsを使うと、コマンド一撃でインストールしてくれます。

具体的には、下記のコマンドを入力するとエディタで開いている言語のLSPがインストールされます。

LspInstallServer

さて、vim-lsp-settingsは楽ちんではあるのですが、pythonを使っていて困りました。Lsp自体にパッケージが入っていないので、補完が丁寧じゃないのです。そこで、下記のスクリプトを書きました。

function! s:lsp_python_pip(module)
  echo 'Installing '.a:module
  let loc = g:lsp_settings#global_settings_dir().'/servers/'
  let command = '/venv/bin/pip'
  let names = ['pyls-all', 'pyls', 'pylsp-all']
  for name in names
    let code = loc.name.command
    echo '> '.code
    echo system(code)
  endfor
  echo 'Ended'
endfunction

command! -nargs=1 LspPip call s:lsp_python_pip("<args>")

これで、下記のようにすると補完がより強力になります。

LspPip install pandas

もちろん、これは単に仮想環境のpipを呼んでいるだけなので、uninstallとかも出来ます。

自動補完

IDEっぽいのを目指すので自動補完を入れます。自動補完はバックグラウンドでLSPで動かすので、当然体感速度上がります。
今回は自動補完プラグインとしてddcを採用しました。ddcには関連するプラグインと設定が非常に多いです。最良の未来を思い、自由に選択していけ。
ただ、一応答えになる雛形でもないと僕のような素人には難しいんですよね。というわけで取り敢えず下記を使ってみます。

名前 機能 備考
tani/ddc-fuzzy ddcでfuzzyな並べ替えをするやつ
Shougo/ddc-converter_remove_overlap 補完の重複をなくすやつ
vim-denops/denops.vim ddcを動かす為にDenoを使うやつ 必須
Shougo/ddc-ui-native popupメニューをddcと組み合わせるやつ 必須
Shougo/ddc-around カーソル周囲の単語で補完するやつ
shun/ddc-vim-lsp ddcとLSPを組み合わせるやつ LSPには必須

今回はこうしたけど、下記もあります。

名前 機能
Shougo/ddc-sorter_rank 書きかけから補完結果を並べ替えるやつ
Shougo/ddc-matcher_head 補完結果を名前順に並べ替えるやつ
Shougo/pum.vim コマンドラインモードで補完をするやつ

確かに小さいのを組み合わせるという良さはあるのでしょうが、一寸多いですね。ここはファイルを分けたうえで目次を作って対策をします。
vimのq:で出てくるコマンドラインモードでも同じスタイルで補完して欲しければShougo/pum.vimを使うらしい。Shougo/ddc-ui-nativeはどうあっても必要らしい。

神は言っている、全てのvimrcを把握せよと

基本、Dotfilesになります。だから、Gitを使って管理すると幸せになれます。設定をふっとばしても元に戻せますしね。そして、複数のファイルに分散させて管理するのがよろしいかと。

だけど、それだけじゃなくて僕は目次が欲しかったんです。
vimrcはどんどん散らかります。そこで、僕はvimrcに目次をつけるスクリプトを書きました。vimはtagsというファイルを元にハイパーリンク的な挙動が出来ることは基本ですが…これを構築します。
どんなやり方でも良かったけれど、僕は「"# 」から始まる行を捉えるように書いてみました。まぁ、すごい適当です。見出しにアンダーバーを使わなきゃいけないという制約はあります。

"# Plugin_Dein

下記はdenoで書いたものです。

ハイパーリンク的な物を作るスクリプト

import { parse } from "https://deno.land/std@0.167.0/flags/mod.ts";
const args: object = parse(Deno.args)

const makeTag = async (fname: string, detectFunc: Function, writeFunc: Function) =>{
  const text: string = await Deno.readTextFile(fname);
  const lines = text.split('\n').filter(detectFunc)
  const codes = lines.map(writeFunc(fname))
  return codes
}

const isTypeofExt = (ext: string) => (fname: string) => fname.slice(fname.length - ext.length) === ext

const makeFnames = async (dirname: string, isFileOf: Function) => {
  let result: string[] = []
  for await (const dirEntry of Deno.readDir(dirname))
    if (dirEntry.isFile && isFileOf(dirEntry.name))
      result.push(dirname + dirEntry.name)
    else if(dirEntry.isDirectory)
      result = result.concat(await makeFnames(dirname + dirEntry.name + '/', isFileOf))
  return result
}

const makeTags = async (detector, writer) => {
  let result: string[] = []
  for (const fname of await makeFnames(args._[0], isTypeofExt('.vim')))
    for (const tag of await makeTag(fname, detector, writer))
      result.push(tag)
  return result.sort()
}


const detector = (text: string) => text.includes('"# ', 0)
const tocWriter = (fname: string) => (text: string) =>{
  const path = fname.split('/')
  const label = path[path.length - 1].split('.')[0].replace('-', '_')
  const capitalLabel = label[0].toUpperCase() + label.slice(1)
  return ('" ' + capitalLabel + '_' + text.slice(3) + ': in ' + fname)
}

const tagWriter = (fname: string) => (text: string) => {
  const path = fname.split('/')
  const label = path[path.length - 1].split('.')[0].replace('-', '_')
  const capitalLabel = label[0].toUpperCase() + label.slice(1)
  return capitalLabel + '_' + text.slice(3) + '\t' + fname + '\t/^' + text + '/'
}

if (args.tag === true){
  console.log('!_TAG_FILE_SORTED	1')
  let tags = await makeTags(detector, tagWriter)
  for (const tag of tags.sort()) console.log(tag)
}
else if (args.toc === true){
  console.log('"========================================')
  console.log('"# Table_of_contents')
  console.log('"========================================')
  for (const tag of await makeTags(detector, tocWriter))
    console.log(tag)
}


```</details>

<details><summary>これを呼ぶvimscript</summary>

```vim
function! MakeVimTOF()
  call system('deno run --allow-read '.g:vimrc_dir.'/make_tags.ts'.' '.g:vimrc_dir.'/ --toc' .' > '.g:vimrc_dir.'/tof.vim')
  call system('deno run --allow-read '.g:vimrc_dir.'/make_tags.ts'.' '.g:vimrc_dir.'/ --tag' .' > '.g:vimrc_dir.'/tags')
endfunction

これによって目次が出来ますが、この目次はvimrcとして読み込みませんので速度に影響はないはずです。vimrcにこんな風に書いておけばそこが目次へのリンクになります。

" Table_of_contents:

vimrcが冗長だと、色々ダルくなっていくので、なんとか工夫したい所です。

あぁ、やっぱり今回も駄目だったよ

下手くそが書いたvimrcは言うことを聞かないからな。

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1