Quantcast
Channel: Vimタグが付けられた新着記事 - Qiita
Viewing all 5720 articles
Browse latest View live

NeoVimでモダンなPython環境を構築するv2(LSPを添えて)

$
0
0

tl;dr

私は以前、NeovimでモダンなPython環境を構築するという記事を投稿しました。

上記記事の投稿から1年8ヶ月が経過し、LSPや新たなVimの機能などによりVimを取り巻く環境には次々と大きな変化が訪れていることを日々感じており、VimConf 2019に参加したことでその感覚はより強い確信へと変わりました。

以前から上記記事の内容は最新の状態に則しておらず、現状を踏まえた新しい記事を書く必要性は感じていました。
本記事を書くにあたり前記事に対して上書きすることも考えたのですが、あえて別記事にすることで、
この数年でVimの開発環境にどれほどの変化が起こったのか。
以前との対比を残すと面白いのではないか。
と思いv2として新しく本記事を書くことを決めました。

Language ServerによりPythonのインテリセンスを提供する

Vimに訪れた最も大きな環境の変化としてLanguage Server Protocol(LSP)の普及とそれに伴って発達したLanguage Server(LS)クライアントが挙げられることでしょう。
またLSから提供された情報を表示するための手段がより豊富になり、より直感的なUIが作れるようになったことも忘れてはなりません。
VimにおけるpopupやNeoVimに追加されたFloatingWindowやVirtualTextなどですね。

LSPによりコードの静的解析とによって得られる言語のインテリセンスは、劇的な変化を遂げました。
より高速により正確に提供されるインテリセンスによって、私達はさらに快適な開発環境を得られたのです。

Vimにおいては各機能ごと(自動補完や定義ジャンプ、静的解析ツール結果表示など)に分割されていたプラグイン郡は徐々にLSクライアントに集約されたり、インテリセンス提供部分をLSクライントに任せてインタフェースの表示のみを担当する別プラグインが生まれるなど、エコシステムに変化が見受けられます。

また後述する各プラグインのセットアップをすることでPythonの開発環境を整えれば、他の言語に対して同等のインテリセンスを持とうとしたとき、比較的楽にその設定を追加することができるようになりました。

vim-lsp + python-language-server(pyls)

Pythonのインテリセンスを得るためにはpylsが必要となります。pipでインストール可能です。

pip install python-language-server

以前まではPythonの静的解析サーバであるjediがあり、jedi解析結果を受け取ってVim上でインテリセンスを得るためのjedi-vimというプラグインを使用することがPythonのインテリセンスを得る手段として一般的であったと思います。
これらの役割は現在vim-lsp + python-language-server(pyls)で担うことができます。
READMEを見る限り、pylsは実態としてjediやその他ツールを統合し、LSP経由でアクセスできるようにしたもののようです。

以下にvim-lspを利用した場合の設定例を示します。

" vim-lspの各種オプション設定letg:lsp_signs_enabled=1letg:lsp_diagnostics_enabled=1letg:lsp_diagnostics_echo_cursor=1letg:lsp_virtual_text_enabled=1letg:lsp_signs_error={'text':'✗'}letg:lsp_signs_warning={'text':'‼'}letg:lsp_signs_information={'text':'i'}letg:lsp_signs_hint={'text':'?'}if(executable('pyls'))" pylsの起動定義
    augroup LspPython
        autocmd!
        autocmd User lsp_setup call lsp#register_server({            \'name':'pyls',            \'cmd':{ server_info ->['pyls']},            \'whitelist':['python'],            \})
    augroup END
endif" 定義ジャンプ(デフォルトのctagsによるジャンプを上書きしているのでこのあたりは好みが別れます)
nnoremap <C-]>:<C-u>LspDefinition<CR>" 定義情報のホバー表示
nnoremap K :<C-u>LspHover<CR>" 名前変更
nnoremap <LocalLeader>R :<C-u>LspRename<CR>" 参照検索
nnoremap <LocalLeader>n:<C-u>LspReferences<CR>" Lint結果をQuickFixで表示
nnoremap <LocalLeader>f:<C-u>LspDocumentDiagnostics<CR>" テキスト整形
nnoremap <LocalLeader>s :<C-u>LspDocumentFormat<CR>" オムニ補完を利用する場合、定義の追加set omnifunc=lsp#complete

上記に加えて、goplsなど他のLSを導入することで容易に対応言語を増やすことが出来ます。
嗚呼素晴らしきかなLSP。

フォーマッター

pylsは単体ではLSPのフォーマット(textDocument/formatting Method)には対応しておらず、
別途プラグインが必要となります。

こちらについてもpipでインストール可能です。

pip3 install pyls-isort
pip3 install pyls-black

blackなどはPyCon 2019でもいくつかのセッションで利用を推奨されるようなフォーマッタになっており、特別理由がないのであれば入れておいたほうが良いでしょう。
フォーマッタに準拠したコードを維持するのであれば以下のようなautocmdを追加することで、保存時にフックしてフォーマットをかけることができます。

augroup LspAutoFormatting
    autocmd!
    autocmd BufWritePre *.py LspDocumentFormatSync
augroup END

マニュアル実行をかけたいのであればキーバインドにLspDocumentFormatを登録してあげると良いでしょう。

Linterおよびその設定

pylsで注意が必要なのは、デフォルトであると少々過剰なチェックが実施されるという点です。
型チェックを実施しないのであればPythonのLintはflake8だけでだいたいは足ります。
しかしpylsでは以下のLinter郡がデフォルトで動作するようになっています。

  • pep8
  • pycodestyle
  • pylint
  • flake8

pylintはかなり厳し目のスタイルチェックが実行されるため、未設定で実行するとflake8だけでは出ないかなり多くのErrorやWarnが出ることが予想されます。
そのためpyls初期化時に不要な設定を無効化する。ないし以下のlint設定ファイルにて個別設定することをおすすめします。

LintConfig File
pep8$HOME/.config/pep8
pycodestyle$HOME/.config/pycodestyle
pylint$HOME/.config/pilintrc
flake8$HOME/.config/flake8

参考までに私の設定ファイルを以下に示しておきます。

これらの各LinterはLSクライアントの設定で以下のようにON/OFFが可能です。

" pylsの設定。LinterのON/OFFなどが可能lets:pyls_config={'pyls':{'plugins':{    \'pycodestyle':{'enabled':v:true},    \'pydocstyle':{'enabled':v:false},    \'pylint':{'enabled':v:false},    \'flake8':{'enabled':v:true},    \'jedi_definition':{    \'follow_imports':v:true,    \'follow_builtin_imports':v:true,    \},    \}}}" pylsの起動定義
augroup LspPython
    autocmd!
    autocmd User lsp_setup call lsp#register_server({        \'name':'pyls',        \'cmd':{ server_info ->['pyls']},        \'whitelist':['python'],        \'workspace_config':s:pyls_config        \})
augroup END

またTypeHintを利用するためのmypyについては外部提供のプラグイン(pyls-mypy)を追加することでLSに機能追加が可能です。

vim-lsp以外のLSクライアント

VimのLSクライアントにはいくつかの選択肢があります。自分の環境や好みに合わせてチョイスすると良いでしょう。
と言われてもどう選べばよいのだとおっしゃるかもしれませんね。そんな方のためにいくつか簡単な説明を添えます。

LSクライアントを選択する上で重要なのは今ご自分が利用されているVimがなにかに大きく左右されます。

素のVimであれば私はvim-lspをおすすめします。vim-lspはVim/Neovimの両対応を明言しており、両方のユーザがいるため、バグ報告や修正も活発に行われるからです。
他のcoc.nvimやLanguageClient-neovimは元々Neovimのリモートプラグインとして開発されているため、Vimのユーザが少なくVimに対するメンテが滞る可能性があると考えています。

NeoVimであれば選択肢はいろいろとありますが、大別して

  • IDEライクなインテリセンスを欲するならcoc.nvim
  • Vimのデフォルト機能を愛する人ならvim-lsp
  • 上記2つの中間ならLanguageClient-neovim

と認識しています。最近masterにマージされたNeovim標準搭載のLSクライアントを使うのも面白いかもしれません。
ただこれらは状況次第で変わる可能性があるため、継続的にプロジェクトの動向を追うことをおすすめします。

LSを用いて自動補完をする(deoplete.nvim with vim-lsp)

Vimの自動補完フレームワークとしてよく知られるdeoplete.nvimですが、LSに対してvim-lspを経由して補完候補のリクエストを行うためには、deoplete.nvimとは別途補完ソースが必要となります。手前味噌ですがdeoplete-vim-lspがそのためのソースとなります。

以下に私の設定を載せておきます。

letg:deoplete#enable_at_startup =1

inoremap <expr><C-h> deoplete#smart_close_popup()."<C-h>"
inoremap <expr><BS> deoplete#smart_close_popup()."<C-h>"call deoplete#custom#option({    \'auto_complete':v:true,    \'min_pattern_length':2,    \'auto_complete_delay':0,    \'auto_refresh_delay':20,    \'refresh_always':v:true,    \'smart_case':v:true,    \'camel_case':v:true,    \})lets:use_lsp_sources=['lsp','dictionary','file']call deoplete#custom#option('sources',{    \'go':s:use_lsp_sources,    \'python':s:use_lsp_sources,    \'vim':['vim','buffer','dictionary','file'],    \})

deoplete-vim-lspは、このLS過渡期におけるつなぎのような存在だと私は認識しています。
今後の動向次第では他のより良い選択肢がいつ出てきてもおかしくなく、そうなったときに儚く消えるかもしれません。

deoplete-vim-lsp以外のLS用補完ソース

deoplete.nvimの補完ソースの話が出たので、deoplete-vim-lsp以外の補完ソースについても言及しておきましょう。

現在主要なLSクライアントにはdeoplete用の補完ソースが存在しています。もしvim-lsp以外のLSクライアントにてdeopleteを用いた補完が行いたいのであれば、それぞれの補完ソースを導入する必要性があります。

deoplete.nvim以外の自動補完フレームワーク

asyncomplete.vim

deoplete.nvim以外にもvim-lsp経由の自動補完を行うための手段は存在します。
というかvim-lsp経由の自動補完を用いるのであればasyncomplete.vimのほうが一般的かもしれません。こちらはvim-lspを作成されているprabirshrestha氏が同じくメンテナをされています。

con.nvim

coc.nvimは現存するVimのLSクライアントの中でもひときわ大きなプロジェクトの一つになっています。
元々はcoc(Conquer Of Completion)の名の通り、自動補完用のフレームワークであったと思いますが、現在ではLSを通したインテリセンスをVim上で全て実現するための統合環境。VimにおけるIDE機能の実装とも呼ぶべきものになっており、自動補完はcoc.nvimにビルドインされています。

LSクライアントと補完フレームワークの組み合わせまとめ

さて、これまででLSクライアントと補完フレームワークがいろいろと出てきましたね。これらの組み合わせには種類があり、各LSクライアントと補完フレームワークは個別のポリシーを持って独自進化を遂げているような状況です。つまりディファクトスタンダードがあり、「コレを使えば間違いないさ!」というような状況ではないのです。
これまで紹介したLSクライアントと補完フレームワークの組み合わせを参考までに以下にまとめておきます。

LSクライアント補完フレームワーク
vim-lspasyncomplete.vim + asyncomplete-lsp.vim
vim-lspdeoplete.nvim + deoplete-vim-lsp
coc.nvimcoc.nvim
LanguageClient-neovimdeoplete.nvim + LanguageClient Source
NeovimビルトインLSクライアントdeoplete.nvim + deoplete-lsp

というわけでLSPがもたらしたVimのエコシステムへの変化は現状も続いています。
あるいはあなたがこれから作成するプラグインによってこのような状況に一石を投じるといったことも可能かもしれません。

アウトライン表示

エディタに欲しいIDE的機能の一つにアウトライン(関数やクラスなどシンボルの一覧)表示があります。
元々Vimにはctagsを用いてのシンボルジャンプや生成されたctagファイルを用いてアウトラインを表示するプラグイン(tagbarなど)があり、これまではアウトラインをVimで表示するならctagsを使うことが一般的でした。
一方LSPにはシンボル取得のためのメソッド(textDocument/documentSymbol Method)が定義されており、
LSクライアントを経由して取得したシンボルからアウトラインを表示するvista.vimがあります。

以下のように設定すれば、デフォルトでctagsで生成したアウトラインを、LSを起動する言語に関してはvim-lspを経由して取得したアウトラインを表示します。

letg:vista_sidebar_width=40letg:vista_echo_cursor=0" デフォルトの情報ソースをctagsにするletg:vista_default_executive='ctags'" 特定の言語の場合vim-lspを利用した情報ソースを利用するようにするletg:vista_executive_for={    \'go':'vim_lsp',    \'python':'vim_lsp',    \}" トグル(アウトラインを非表示の場合は表示、表示済みの場合は非表示に)
nnoremap <silent><Leader>o:<C-u>Vista!!<CR>

vista.vimはctagsとLSクライアントから取得したシンボルの表示どちらにも対応しています。
g:vista_executive_forにて言語と対応するLSクライアントを指定することで、言語別でctagsとLSの切り替えが可能になります。
ところが現状だとctagsを利用したほうが見やすかったりする部分があります。なので適宜状況を見ながら切り替えをしたほうが無難と考えています。
これはLSPやLSの拡張次第でどんどん状況が変わるると予測しています。

ctagsを用いるときはuniversal-ctagsのインストールをお忘れなく。

またlightline.vimで定義を追加することで、現在カーソルにあるシンボル名をvista.vimから取得してステータスラインにシンボル名を表示することが出来ます。

以下に私のlightline設定をおいておきます。

letg:lightline={    \'colorscheme':'iceberg',    \'active':{    \'left':[['mode','paste'],['readonly','myfilename','method','modified'],],    \'right':[['lineinfo'],['percent'],['char_code','fileformat','fileencoding','filetype'],],    \},    \'component_function':{    \'myfilename':'LightlineFilename',    \'method':'NearestMethodOrFunction',    \},    \'separator':{'left':"\ue0b0",'right':"\ue0b2"},    \'subseparator':{'left':"\ue0b1",'right':"\ue0b3"},    \}function! LightlineFilename()letl:p= expand('%:t')if''!=# l:preturnl:pendifreturn'[No Name]'endfunctionfunction! NearestMethodOrFunction() abort
    letl:func_name = get(b:,'vista_nearest_method_or_function','')ifl:func_name !=''return' '.l:func_name
    endifreturn''endfunction

augroup LightLineOnVista
    autocmd!
    autocmd VimEnter * call vista#RunForNearestMethodOrFunction()
augroup END

マイクロコードの実行

使用したことのない関数やライブラリなどの動作をチェックするために、マイクロコードを作成して実行することはよくあると思います。
その際、Vimから離れてCLIからpython main.pyなどして実行する方法がありますが、この方法であると以下のようにいくつかの手間がかかります。

  • Vimを離れる必要がある
  • エラー発生時に表示された行数とVimで表示しているコードの行数を脳内で一致させる必要がある

すばやくコードを書く上でほぼ必須の機能と言えるのですが、現状LSにはコード実行用の機能がありません。それっぽいメソッドがLSPにあるのですが、少なくともそれを実装しているLSを私は知らないので、誰か知っていたら教えてください。
なので別途プログラムランナーが必要になるのですが、私はvim-quickrunをおすすめします。

vim-quickrunがあればVimで記述したコードをVim上からすばやく実行することができます。これが最速です。
コード全てではなく、ヴィジュアルモードで選択した一部のコードのみでも実行することも可能です。便利ですね。

さてプログラムをVim上から実行するときに、実行中にVimの編集がブロックされるのは避けたいものです。つまりjobが必要になります。
vim-quickrunの作者であるthinca氏はVimのみを利用するユーザであるため、vim-quickrun本体にNeoVimのjobを実行する機能は含まれていません。
しかしご安心くださいlambdalisue氏が作成したvim-quickrun-neovim-jobを追加することでNeoVimのjobをvim-quickrunのrunnerとして追加することができるのです

letg:quickrun_config={    \'_':{        \'outputter':'error',        \'outputter/error/success':'buffer',        \'outputter/error/error':'quickfix',        \'outputter/buffer/split':':botright 8sp',    \}\}" VimとNeovimで利用するrunerを変更if has('nvim')letg:quickrun_config._.runner ='neovim_job'elseif exists('*ch_close_in')letg:quickrun_config._.runner ='job'endif

最小.vimrc(init.vim)

これまで紹介したVimプラグインが使える最小(と言う割には多い)vimrcをご用意しました。
参考にしていただければ幸いです。
なお普段のパッケージマネージャはdein.vimですが、deinのキャッシュを壊したくないので今回はvim-plugを使ったものをご用意しました。

このvimrcを~/.config/init.vimを貼るなり、適当なとこに配置してnvim -u {file}したあとに、以下のように実行すれば使えると思います。多分。

  • nvim起動後に:PlugInstall
  • 上記の後nvim再起動して:UpdateRemotePlugins
  • nvim再起動

なお、自分の趣味でg:python3_host_progにインストールされているpylsを利用するようにしています。ご注意を。
パス解決周りの話がわからなかったら以前書いた以下の記事を参照してみると良いでしょう。

まとめ

長文になりましたが、いかがだったでしょうか?
Vimは言語のインテリセンスが弱いのでちょっと。という方が本記事をみて、おぉVimもこんなことができるのかと知っていただければ幸いです。

それでは皆さんLanguage Serverを使ってより快適なプログラミングをお楽しみください!!


サークルでGoサーバ書いて成長した話

$
0
0

こんにちは TechTrain Advent Calender 2019 12日目です.

はじめに

部活のプロジェクトでTechTrainというSNSアプリをGoで書きました.
このプロジェクトでは技術好き学生向けのSNSアプリを開発しようということでモバイル班(Android,iOS),サーバ班,デザイン班に別れてチーム開発を行いました.
自分は編入組で4月後半に部活に入ったため途中からサーバ班に参加させていただきました.
自分が入った段階ではプロジェクトでどのようなものを作るか,サーバはGo言語を使用すると決まっていました.サーバ班全員Go言語メインで書いたことはなく勉強がてら触ってみようとなりメンターさんからもGoサインが出たので決定したらしいです.自分も昔少し触っただけでガッツリ書いたことがなく,新しい言語を触れるということでとても楽しみでした.新しい言語触るのって楽しいですよね.

プロジェクトの詳しい話に関しては他のプロジェクトメンバーの記事を見ると面白いと思います.
- TechTrainを利用してチームでアプリ開発をした話(Android編)
- 開発初心者が8か月間のチーム開発に参加して感じた反省
- TechTrain Advent Calender 2019 14日目
- TechTrain Advent Calender 2019 17日目
- TechTrain Advent Calender 2019 19日目
- TechTrain Advent Calender 2019 21日目

本編

ところでみなんさんプログラミングをするのに必要なものって何だとおもいますか?
そう テキストエディタですよね.ちなみにこの記事もNeovimで下書きを書いています.
新しい言語を触るということであればテキストエディタの設定をするのはこの世の理です.
昔Go言語を少し触ったときは今ほどLSPが主流ではなかったため今回Go言語を書くにあたってVimの設定を見直しました.
私のVimの設定ファイルのディレクトリ構成はこうなっています.

~/.config/nvim
├── after
│   └── ftplugin
│       ├── go.vim
│       ├── java.vim
│       ├── json.vim
│       ├── plaintex.vim
│       ├── prolog.vim
│       ├── python.vim
│       ├── rust.vim
│       └── tex.vim
├── autoload
│   └── aload.vim
├── dein.toml
├── dein_lazy.toml
├── ftdetect
│   └── pu.vim
├── init.vim
└── plugin
    ├── keymap.vim
    ├── lightline.vim
    └── syntastic.vim

では設定を一部抜粋し説明していきます.

まず起動時に読み込むプラグインです.

dein.toml
[[plugins]]
repo ='autozimu/LanguageClient-neovim'
rev ='next'
build ='bash install.sh'
hook_add ='''
  set hidden
  letg:LanguageClient_serverCommands={        \'cpp':['clangd'],        \'rust':['rustup','run','stable','rls'],        \'go':['gopls']        \}letg:LanguageClient_diagnosticsEnable=0letg:LanguageCliet_autoStart=1
  nnoremap <Space>lh:call LanguageClient#textDocument_hover()<CR>
  nnoremap <Space>ld:call LanguageClient#textDocument_definition()<CR>
  nnoremap <Space>lr:call LanguageClient#textDocument_rename()<CR>'''

[[plugins]]
repo ='vim-scripts/smartchr'
hook_add ='''
  inoremap <expr>= smartchr#loop(' = ',' == ','=','==')
  inoremap <expr>, smartchr#loop(', ',',')'''

[[plugins]]
repo ='w0rp/ale'
hook_add ='''
  setlocal signcolumn=yes
'''

今回の設定変更のメインとなるのがLSPの設定ですね.いままではdeoplete-goを使っていたのですが現在のエディタ界隈では補完はLSPに任せるのが主流になっているため私もLanguegeClient-neovimからGoのLSPであるgoplsを呼び出しています.

smartchrは特定のキー入力をしたときに別の入力を行うものです.例えば

  inoremap <expr>, smartchr#loop(', ',',')

このように書くと,をキー入力したときに,が挿入されます.もう一度押すとリストの次の要素である,に変化します.
上に記述した=に関してのリストは汎用的に使っているものなのでftpluginでまた定義し直します.

aleはシンタックスチェックを行ってくれるもので記述に間違いがあれば警告してくれます.

次にdeinの遅延読み込みの機能を使っているプラグインです.

after/dein_lazy.toml
[[plugins]]
repo ='Shougo/deoplete.nvim'
on_event ='insertCharPre'
hook_source ='''
  letg:deoplete#enable_at_startup =1letg:deoplete#auto_complete_delay =0letg:deoplete#augo_complete_start_length =1letg:deoplete#enable_camel_case =0letg:deoplete#enable_ignore_case =0letg:deoplete#enable_refresh_always =1letg:deoplete#smart_case =1letg:deoplete#file#enable_buffer_path =1letg:deoplete#max_list =10000letg:deoplete#max_list=1000
  imap <expr><tab> neosnippet#expandable_or_jumpable() ?
         \"\<Plug>(neosnippet_expand_or_jump)":"\<tab>"'''
on_i =1[[plugins]]
repo ='fatih/vim-go'
hook_add ='''
  letg:go_fmt_command="goimports"letg:go_def_mapping_enabled=0letg:go_doc_keywordprg_enabled=0'''
on_ft =['go'][[plugins]]
repo ='tyru/caw.vim'
on_path ='.*'

deopleteは補完フレームワークとして使っているものです.

vim-goはVimでGoを使うのであれば入れたいものですね.Vim編集中にビルドやクイックフィックスが行えたり自動importやフォーマット修正をしてくれます.

caw.vimはGo言語だけに使っているものではないですが現在のバッファのファイルタイプに応じたコメントアウト簡単にできるようになります.

最後にファイルタイプがGoだったときに読み込まれる設定です.

after/ftplugin/go.vim
inoremap <expr>= smartchr#loop(' := ',' == ',' != ',' = ','=','==')

Go言語では:=を使う機会が多いため=の入力で:=が挿入されるようにします.

おわり

Vim使っていると新しい言語に触れた際に自分の設定ファイルの成長を感じられてとてもよいですね!
皆さん良きVimライフを!

Vim で表示しているテキストを外部プログラムで編集する

$
0
0

この記事は Vim Advent Calendar 2019の 13 日目の記事です。

Vim は選択範囲であったり開いているテキスト全体であったりに対して、外部プログラムで編集することができます。
ここでは、 :{range}!{filter} [arg]を題材にして動きを確認していきます。

なお、詳細については :help complex-changeもしくは :help filterに記載があります。

tate コマンドで縦書きに変換する

tate コマンドは、テキストを縦書きに変換するプログラムです。

$ type sample.txt | iconv -f utf-8 -t cp932
Vim で表示している

テキストを

外部プログラムで

編集する

↑ のような sample.txt に対して、 tate コマンドを使うと縦書きになります。

$ type sample.txt | tate
編 外 テ V
集 部 キ i
す プ ス m
る ロ ト  
  グ を で
  ラ   表
  ム   示
  で   し
      て
      い
      る

この動作を Vim 上で直接再現するのが filter コマンドになります。
ここでは、 :%!tateというコマンドで、テキスト全体を tate コマンドで処理してみます。

tate.gif

大体想定通りだと思いますが、 range で指定した範囲のテキストを filter で指定したプログラムの標準入力に渡し、プログラムの標準出力で出力されたテキストで置き換えることができます。

ちなみに、 tate コマンドは以下になります。

tate
https://github.com/mattn/tate

filter として使いやすいプログラム

sed / awk / Perl あたりのワンライナーで書きやすいプログラムが使いやすいです。
自分は、 Perl を良く使っていますので、いくつか例を示します。

サンプル 1 : すべて大文字化

A filter is a program that accepts text at standard input, changes it in some
way, and sends it to standard output.  You can use the commands below to send
some text through a filter, so that it is replaced by the filter output.
Examples of filters are "sort", which sorts lines alphabetically, and
"indent", which formats C program files (you need a version of indent that
works like a filter; not all versions do).  The 'shell' option specifies the
shell Vim uses to execute the filter command (See also the 'shelltype'
option).  You can repeat filter commands with ".".  Vim does not recognize a
comment (starting with '"') after the `:!` command.

:%!perl -anE "print uc($_)"

A FILTER IS A PROGRAM THAT ACCEPTS TEXT AT STANDARD INPUT, CHANGES IT IN SOME
WAY, AND SENDS IT TO STANDARD OUTPUT.  YOU CAN USE THE COMMANDS BELOW TO SEND
SOME TEXT THROUGH A FILTER, SO THAT IT IS REPLACED BY THE FILTER OUTPUT.
EXAMPLES OF FILTERS ARE "SORT", WHICH SORTS LINES ALPHABETICALLY, AND
"INDENT", WHICH FORMATS C PROGRAM FILES (YOU NEED A VERSION OF INDENT THAT
WORKS LIKE A FILTER; NOT ALL VERSIONS DO).  THE 'SHELL' OPTION SPECIFIES THE
SHELL VIM USES TO EXECUTE THE FILTER COMMAND (SEE ALSO THE 'SHELLTYPE'
OPTION).  YOU CAN REPEAT FILTER COMMANDS WITH ".".  VIM DOES NOT RECOGNIZE A
COMMENT (STARTING WITH '"') AFTER THE `:!` COMMAND.

サンプル 2 : SREC の S0 レコードをデコード

443A5C446174615C5358313231325F4150495C4150495C4150495F636F64655Cが ASCII の 16 進数表記になっているので変換するという例。
Vim のコマンドラインモードでは、 %がファイル名に変換されてしまうので \%と書く必要があることに注意。

S02B0000443A5C446174615C5358313231325F4150495C4150495C4150495F636F64655C7475746F7269616C44

:%!perl -ape "s/^(S0......)((..)+)(..$)/sprintf qq'\%s\%s\%s', $1, pack('H*', $2), $3/e"

S02B0000D:\Data\SX1212_API\API\API_code\tutorial6C

サンプル 3 : 前の行のタイムスタンプとの差分を追加しつつ、 ID (3 カラム目) 毎の差分も出す

4.303006 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.413445 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.480696 1  2               Rx   d 8 00 57 00 00 00 00 00 00
4.482131 1  4               Rx   d 8 00 57 00 00 00 00 00 00
4.523533 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.634201 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.743692 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.780966 1  2               Rx   d 8 00 57 00 00 00 00 00 00
4.782392 1  4               Rx   d 8 00 57 00 00 00 00 00 00
4.853831 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.963971 1  1               Rx   d 8 00 00 00 00 00 00 00 00

:%!perl -ape "s/^/sprintf '\%.6f \%.6f ', $F[0]-$x{$F[2]}, $F[0]-$y/e; $x{$F[2]}=$F[0]; $y=$F[0]"

// 左から `ID 毎差分`、 `差分`、 `元のテキスト` を表示
4.303006   4.303006   4.303006 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.110439   0.110439   4.413445 1  1               Rx   d 8 00 00 00 00 00 00 00 00
4.480696   0.067251   4.480696 1  2               Rx   d 8 00 57 00 00 00 00 00 00
4.482131   0.001435   4.482131 1  4               Rx   d 8 00 57 00 00 00 00 00 00
0.110088   0.041402   4.523533 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.110668   0.110668   4.634201 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.109491   0.109491   4.743692 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.300270   0.037274   4.780966 1  2               Rx   d 8 00 57 00 00 00 00 00 00
0.300261   0.001426   4.782392 1  4               Rx   d 8 00 57 00 00 00 00 00 00
0.110139   0.071439   4.853831 1  1               Rx   d 8 00 00 00 00 00 00 00 00
0.110140   0.110140   4.963971 1  1               Rx   d 8 00 00 00 00 00 00 00 00

まとめ

以上のように、外部プログラムを使って簡単なテキスト編集ができました。
今回紹介したサンプルは Perl 中心ですが、他のプログラムでも同様の事が可能です。
使い慣れたプログラムでフィルタ処理をして、テキスト編集を快適にしていきましょう。

インフラよりvim環境

$
0
0

Vim2 Advent Calendar 2019 13th day

前置き

筆者が普段AWSにおいてdevopsするときに利用する環境とvimの使い方(plugin)を紹介する記事。
導入をメインとしているので詳細な設定項目やカスタマイズは個々のplugin公式サイトを参照してほしい。AWSの設定は言及しないがある程度の知識を前提としている。

開発環境とは?

文脈がないと限定しにくいがプログラマにとっての開発環境はIDEなら、インフラエンジニアにとっての開発環境とはなにか?

infrastructure as codeを行いやすい環境というのは最近なら想像に難くない。ただ具体的な定義はまだないと思われる。そのためのツール群が扱うファイル群の作成や編集を容易に行えて、オペレーションまで行えるものと個人的には考えている。

上記は経験による結果論で、普段はAmazon Linux 2のEC2を立ててそこにツール群などをインストールしている。

EC2を使う理由は主に以下となる

  • サーバ用途で提供されているディストリビューションなので通常使用するサーバと基本的近いもの
  • AWS環境のオペレーションを行うためのツール群が提供されメンテナンスされている
  • sshログインを行えるterminalがあれば手元のOSを選ばない(anywhere)
  • 環境のバックアップ、破棄、再構築が容易(AMIやAnsible)
  • セキュリティを高めることも容易(通信の遮断や証跡の方法が多い)

(いずれも手元のマシーンでも当然できるが、始端を固定化することが変更への対応のコストになると考えている)

vim環境の準備

以下は既にAmazon Linux 2のEC2を立てたあとsshによるログインを行った状態とする。

$ uname-r
4.14.152-127.182.amzn2.x86_64

デフォルトでは8.1が既にinstallされている

$ vim --version
VIM - Vi IMproved 8.1 (2018 May 18, compiled Jul 17 2019 17:46:26)
Included patches: 1-1602
Modified by Amazon Linux https://forums.aws.amazon.com/
Compiled by Amazon Linux https://forums.aws.amazon.com/

vimをinstallする

rpmのrebuildをするのは面倒なので、デフォルトを利用せずにソースからインストールする。

rpmからrebuildする場合(大体の手順)

提供されているvimのバージョンを確認

$ sudo yum --showduplicates list vim-common
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Installed Packages
vim-common.x86_64                         2:8.1.1602-1.amzn2                             installed
Available Packages
vim-common.x86_64                         2:7.4.160-2.amzn2                              amzn2-core
vim-common.x86_64                         2:7.4.160-4.amzn2.0.16                         amzn2-core
vim-common.x86_64                         2:8.0.1257-1.amzn2                             amzn2extra-vim
vim-common.x86_64                         2:8.0.1257-2.amzn2                             amzn2extra-vim
vim-common.x86_64                         2:8.1.1602-1.amzn2                             amzn2-core

8.1のsrc.rpmをダウンロードする

$ yumdownloader --source vim-common-2:8.1.1602-1.amzn2.x86_64
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Enabling amzn2extra-vim-source repository
Enabling amzn2extra-docker-source repository
Enabling amzn2-core-source repository
vim-8.1.1602-1.amzn2.src.rpm                                                    |  11 MB  00:00:00

展開

$ rpm -ivh vim-8.1.1602-1.amzn2.src.rpm

依存関係パッケージのチェックとインストール

$ sudo yum-builddep rpmbuild/SPECS/vim.spec

rpmbuildをインストールする

$ sudo yum install rpm-build

vim.specを編集してrebuildする

$ rpmbuild --rebuild rpmbuild/SPECS/vim.spec

インストールに必要なパッケージ

  • git
  • ncurses-devel
  • gcc
  • python3-devel(deopleteで利用)
  • ruby-devel(vim-terraform-completionで利用)
$ sudo yum install-y git python3-devel ruby-devel ncurses-devel gcc

デフォルトのvimを残したままユーザ環境(ec2-user)にインストールする場合は予めディレクトリを作成しておく

$ mkdir-p$HOME/.local/bin

ソースを取得

$ git clone https://github.com/vim/vim.git
$ cd vim

python3を有効にしてmake

$ ./configure \--enable-rubyinterp\--enable-python3interp\--prefix=$HOME/.local/vim
$ make

install

$ make install

pathを設定

$ echo'export PATH=$HOME/.local/vim/bin:$PATH'>> ~/.bashrc
$ source ~/.bashrc

versionをチェック

$ vim --version
VIM - Vi IMproved 8.1 (2018 May 18, compiled Dec 12 2019 08:50:33)
Included patches: 1-2424
Compiled by ec2-user@ip-172-31-18-199.us-east-2.compute.internal

+python3+rubyとなっている

vimのpluginについて

vimawesomeでは各pluginのインストール方法はVundleNeBundleVimPlugPathogenの4種のpluginマネージャのいずれかを利用してインストールすることになる。こだわりや差異を理解している場合でなければ大きくは変わらない。ここではVundleでの利用を紹介する。

Vundleをinstallする

$ git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

~/.vimrc

set nocompatible              " be iMproved, required
filetype off                  " required
set rtp+=~/.vim/bundle/Vundle.vimcall vundle#begin()

Plugin 'VundleVim/Vundle.vim'"--ここから"--ここまでの間にpluginの記述を行うcall vundle#end()            " required
filetype plugin indent on    " required

vimのcolorscheme

みんな大好きsolarized

vim-colors-solarizedをinstallする

$ mkdir-p ~/.vim/colors/
$ curl -LSs-o ~/.vim/colors/solarized.vim https://raw.githubusercontent.com/altercation/vim-colors-solarized/master/colors/solarized.vim

~/.vimrcに設定する

letg:solarized_termcolors=16letg:solarized_termtrans=1letg:solarized_degrade=0letg:solarized_bold=1letg:solarized_underline=1letg:solarized_italic=1letg:solarized_contrast='normal'letg:solarized_visibility='normal'

syntax enable
set background=darkcolorscheme solarized

vimのstatus情報

powerline系表示があると情報がわかりやすく効率アップにつながるので利用しよう。ここではvim-airlineを利用する。

vim-airlineをinstallする

~/.vimrcのVundleのPluginを記述すべきブロックの間に下記を追記

" airline
Plugin 'vim-airline/vim-airline'
Plugin 'vim-airline/vim-airline-themes'letg:airline#extensions#tabline#enabled =1letg:airline_theme='violet'letg:airline_powerline_fonts=1

vimrcを読み込む

:source %

pluginのinstallを行う

:PluginInstall

Done!が表示されれば正常にインストールが完了

いろんなテーマがあるので気に入ったものに変更できる。

コマンドラインから

:AirlineTheme solarized

もしくは~/.vimrcに記述する

letg:airline_solarized_bg='dark'

powerlineのフォントをinstallする

powerlineのフォントがないと一部表示が崩れるのでfontのinstallが必要となる。font自体はクライアントにインストールする。

macの場合

terminalからfontをインストール

$ git clone https://github.com/powerline/fonts.git
$ cd fonts
$ ./install.sh

Copying fonts...
Powerline fonts installed to /Users/YOURNAME/Library/Fonts

iTerm2を利用しているなら

Preferences -> Profiles -> Text(tab)

FontのプルダウンメニューからDejaVu Sans Mono for Powerlineを選択する

windowsの場合

https://github.com/powerline/fontsからzipでダウンロードして展開し、PowerShellからinstall.ps1を実行してfontをインストール

Puttyを利用しているなら

window -> Appearance -> Font settings

からDejaVu Sans Mono for Powerlineを選択する

formatについて

prettierを利用する。

vim-prettierをinstallする

node環境をまず用意する。

nvmをinstallする

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash

nvmを使えるように設定する

$ source ~/.bashrc

nodeをinstall

$ nvm install node
Downloading and installing node v13.3.0...
Downloading https://nodejs.org/dist/v13.3.0/node-v13.3.0-linux-x64.tar.xz...
################################################################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v13.3.0 (npm v6.13.1)
Creating default alias: default -> node (-> v13.3.0)

yarnをinstallする

$ npm i -g yarn

Vundleからprettierをinstallする

" prettier
Plugin 'prettier/vim-prettier'
:source %
:PluginInstall

言語のformatはmodule化しているのでvim-prettierのディレクトリ内で必要な言語をyarnでinstallする(例 typescript)

$ cd ~/.vim/bundle/vim-prettier/
$ yarn add typescript 

yarn add cssyarn add jsonなど、他にも利用言語がある場合は追加する

formatの細かい設定は公式を参照

行数表示

vim-numbertoggleを利用する。

カレント行以外の行番号は相対表示してくれるの上下の移動が便利になる。

vim-numbertoggleをinstallする

Vundleでinstallする

" vim-numbertoggle
Plugin 'jeffkreeftmeijer/vim-numbertoggle'setnumber relativenumber
:source %
:PluginInstall

解除する場合は

:se nu! rnu!

補完の強化

deopleteを利用する。

deopleteをinstallする

pynvimが必要のため先にpip3からinstallしておく

$ pip3 install--user pynvim

Vundleからinstallする

" deoplete
Plugin 'Shougo/deoplete.nvim'
Plugin 'roxma/nvim-yarp'
Plugin 'roxma/vim-hug-neovim-rpc'letg:deoplete#enable_at_startup =1
:source %
:PluginInstall

terraformのためのplugin

vim-terraformvim-terraform-completionがあると便利。

vim-terraform、vim-terraform-completionをinstallする

Vundleからinstall

" vim-terraform
Plugin 'hashivim/vim-terraform'letg:terraform_align=1letg:terraform_fmt_on_save=1" vim-terraform-completion 
Plugin 'juliosueiras/vim-terraform-completion'
:source %
:PluginInstall

詳細設定はそれぞれ参照

typescriptのためのplugin

tsuquyomiを利用する。

tsuquyomiをinstallする

nodeのtypescriptが必要なのでinstallする

$ npm i -g typescript

Vundleからinstallする

" tsuquyomi
Plugin 'Quramy/tsuquyomi'
:source %
:PluginInstall

golangのためのplugin

vim-goを利用する。

vim-goをinstallする

まずはgolangの環境を整える

amzn2-coreが提供するversionは1.9なので最新の1.13を利用する

$ sudo rpm --import https://mirror.go-repo.io/centos/RPM-GPG-KEY-GO-REPO
$ curl -s https://mirror.go-repo.io/centos/go-repo.repo | sudo tee /etc/yum.repos.d/go-repo.repo
$ sudo sed-e's/\$releasever/7/'-i /etc/yum.repos.d/go-repo.repo 
$ sudo yum install-y gcc
$ sudo yum install-y golang --disablerepo=amzn2-core,amzn2extra-golang*--enablerepo=go-repo
$ go version
go version go1.13.5 linux/amd64

pathを設定

export GOPATH=$(go env GOPATH)# "$HOME/go"export PATH="$PATH:${GOPATH//://bin:}/bin"

~/.bashrcに記述するなら

$ source ~/.bashrc

Vundleからinstallする

" vim-go
Plugin 'fatih/vim-go'letg:go_list_type="quickfix"letg:go_fmt_command="goimports"letg:go_highlight_functions=1letg:go_highlight_methods=1letg:go_highlight_structs=1letg:go_highlight_operators=1letg:go_highlight_fields=1letg:go_highlight_variable_declarations=1letg:go_highlight_variable_assignments=0letg:go_highlight_string_spellcheck=1letg:go_highlight_types=1letg:go_highlight_function_parameters=1letg:go_highlight_extra_types=1
:source %
:PluginInstall

GoInstallBinariesを実行する(vim-goが利用するツールをgo get)

:GoInstallBinaries

tagbarをinstallする

ctagsにgolangがないのgotagsを先にinstall

$ go get -u github.com/jstemmer/gotags

Vundleからinstallする

" tagbar
Plugin 'majutsushi/tagbar'
nmap <F8>:TagbarToggle<CR>letg:tagbar_type_go={        \'ctagstype':'go',        \'kinds':[                \'p:package',                \'i:imports:1',                \'c:constants',                \'v:variables',                \'t:types',                \'n:interfaces',                \'w:fields',                \'e:embedded',                \'m:methods',                \'r:constructor',                \'f:functions'        \],        \'sro':'.',        \'kind2scope':{                \'t':'ctype',                \'n':'ntype'        \},        \'scope2kind':{                \'ctype':'t',                \'ntype':'n'        \},        \'ctagsbin':'gotags',        \'ctagsargs':'-sort -silent'\}
:source %
:PluginInstall

F8もしくは:Tagbarで表示非表示を切り替える

ansibleのためのplugin

ansible-vimを利用する。

Vundleからinstallする

" ansible-vim
Plugin 'pearofducks/ansible-vim'letg:ansible_extra_keywords_highlight=1auBufRead,BufNewFile */playbooks/*.yml setfiletype=yaml.ansible
:source %
:PluginInstall

自動検知されない場合は:se ft=yaml.ansibleで指定する

まとめの前

pluginをたくさん紹介したがまだまだ便利なものはたくさんある。NERDTreefugitiveなどなど。ただしpluginをたくさん使用しようしているとそれだけ重くなっていく。不要なもの使わないものは読み込まないように注意する必要がある。

読み込まれているファイルの確認

:script

読み込む時間の確認

$ vim openfile --startuptime vimuptimelog
times in msec
 clock   self+sourced   self:  sourced script
 clock   elapsed:              other lines

000.006  000.006: --- VIM STARTING ---
000.140  000.134: Allocated generic buffers
000.218  000.078: locale set
000.222  000.004: window checked
000.624  000.402: inits 1
000.708  000.084: parsing arguments
000.711  000.003: expanding arguments
000.735  000.024: shell init
001.054  000.319: Termcap init
001.074  000.020: inits 2
001.199  000.125: init highlight
001.492  000.036  000.036: sourcing /home/ec2-user/.local/vim/share/vim/vim81/ftoff.vim
002.490  000.787  000.787: sourcing /home/ec2-user/.local/vim/share/vim/vim81/syntax/syncolor.vim
002.605  001.001  000.214: sourcing /home/ec2-user/.local/vim/share/vim/vim81/syntax/synload.vim
008.657  006.010  006.010: sourcing /home/ec2-user/.local/vim/share/vim/vim81/filetype.vim
008.696  007.147  000.136: sourcing /home/ec2-user/.local/vim/share/vim/vim81/syntax/syntax.vim
008.999  000.167  000.167: sourcing /home/ec2-user/.local/vim/share/vim/vim81/syntax/syncolor.vim
009.855  000.172  000.172: sourcing /home/ec2-user/.local/vim/share/vim/vim81/syntax/syncolor.vim
010.124  000.160  000.160: sourcing /home/ec2-user/.local/vim/share/vim/vim81/syntax/syncolor.vim
012.138  003.102  002.770: sourcing /home/ec2-user/.vim/colors/solarized.vim
012.756  000.212  000.212: sourcing /home/ec2-user/.vim/bundle/Vundle.vim/autoload/vundle.vim
012.997  000.152  000.152: sourcing /home/ec2-user/.vim/bundle/Vundle.vim/autoload/vundle/config.vim
015.858  000.015  000.015: sourcing /home/ec2-user/.local/vim/share/vim/vim81/filetype.vim
016.065  000.039  000.039: sourcing /home/ec2-user/.local/vim/share/vim/vim81/ftplugin.vim
016.260  000.034  000.034: sourcing /home/ec2-user/.local/vim/share/vim/vim81/indent.vim
016.340  015.011  004.107: sourcing $HOME/.vimrc
016.344  000.134: sourcing vimrc file(s)
・・・
・・・
406.016  028.532: first screen update
406.019  000.003: --- VIM STARTED ---

約400msかかっている

078.747  000.002: --- VIM STARTED ---

pluginを入れないデフォルトの状態だと78msしか必要としない

まとめ

インフラのdevopsで便利に利用できるvimのpluginはたくさんある。ただし軽さやシンプルさがあまり犠牲にならないように利用することをおすすめしたい。vimの真髄は操作系だと個人的に思っているので操作がサクサクできる状態を保つ方がcool。

Vim から conda を使って Python 環境を切り替えられる vim-conda が便利

$
0
0

空いていたので穴埋め。

はじめに

Python をお使いの皆さんならば、各アプリケーションを入れる際に conda を使って環境を綺麗に保っていると思います。

また Vim で Python スクリプトを実行する際には thinca さんの QuickRun を使ったりしてると思います。さらには Python Language Server を起動して入力補完を行ったりもするでしょう。そういった場合、いちいち Vim を終了して conda で activate して、とやるのは手間ですよね。

重い conda ら

そこで vim-conda です。

https://github.com/cjrh/vim-conda

vim-plug をお使いであれば以下を vimrc で指定して :PlugInstallでインストールできます。

Plug 'cjrh/vim-conda'

使い方

:CondaChangeEnvを実行すると選択可能な conda env が表示されます。

terminal7.gif

選択すれば内部的に activate され、それ以降に実行される python コマンドから有効になります。

おわりに

Vim を起動しっぱなしにしたい人には vim-conda は便利。

設定ファイルの語尾に付くrcの意味とは?

$
0
0

.bashrc, .vimrcなどよく使われているrcrun commandの略らしいです。使う機会がありましたら、アールシーではなく、ランコ マンド(ドヤ顔)と言ってみてはいかがでしょうか。

Vimに突如現れたKillersheepとは

$
0
0

アドベントカレンダー初参加です。

はじめに

先日Vim 8.2がリリースされましたね。
スクリーンショット 0001-12-14 午前0.31.53.png
早速ビルドしました。
Vim 8.2はポップアップウィンドウの実装とテキストプロパティこの二つが大きな新機能のようです。
www.vim.orgを見られた方なら気付いた方もいるかもしれませんが、KillersheepというVimプラグインがGitHubにアップロードされました。
開発はBram Moolenaar...つまりVimの開発者です。

Killersheepとは

Vim 8.2の新機能を使ったシューティングゲーム、と認識しています。
使われている新機能は以下の3つです。
詳細はヘルプを参照してください。
1. 音源再生機能 :h sound_playevent
2. ポップアップウィンドウ :h popup
3. テキストプロパティ :h textprop

インストール

Killersheepは普通のVim script製プラグインですので、プラグインマネージャ等にvim/killersheepを登録することでインストールは終わります。
README.mdによると動作の条件はVim 8.2とのことですが、一部の8.1系でも動作します。ソースコードを見ると8.1.1705以降で動作するようです。

プレイする

インストールが正常に終わっているならば、
:Killでプレイができます。
もし他のプラグインとコマンドが競合しているのなら:KillKillKillコマンドも使えます。コマンド名が物騒ですね
動作に必要な条件を記しておくと、
+textpropでコンパイルされていること。
ターミナルが45行以上あること。です。
ところで、音がなります。気をつけましょう。

プレイ中の画像

スクリーンショット 0001-12-13 午後11.47.56.png
操作

キー操作
xゲームの終了
sゲームの開始
h,l自機の移動
Space弾の発射

Dec-13-0001 11-58-16 PM.gif
プレイ中に流れる効果音は同僚さんの声らしいです。

ソースコードを読んで

羊から出ている何かは羊さんビームのような生易しいものではなく普通にpoopでした。
私はVim scriptの知識がほとんどないので申し訳ないのですが、中で出てくる羊ちゃんやウ●コ、自機や弾は皆ポップアップウィンドウのようです。色付けはテキストプロパティを用いているのでしょうか。
昔のvimゲームプラグインはバッファを直接書き換えているよう?なのですが、こちらはポップアップウィンドウを使っています。新しい手法が増えたのでしょうか。

終わりに

このようなことができるようになったのはたくさんの人の作業があったからなんだろうなと思いました。自分も何かしら貢献できるようにしたいです。

Vim用のDark themeカラースキーマ作りました

$
0
0

この記事はVim2 Advent Calendar 2019の14日目の記事です。

Motivation

Vimはそもそも黒い画面で構成されているものですし、「VimでDark theme...?」と思われる方も沢山いらっしゃると思います。

しかし、それでも現在アプリケーションで流行っている「Dark theme」のVimカラースキームを作ると面白いんじゃないかと個人的に思ったポイントがいくつかありました

  1. 裏を返せばもともと黒い画面で動いているVimとDark themeは相性が良さそう
  2. Dark themeの設計原則がGoogleより発表されていたので、試してみたい
  3. Vimをモダンなカラーリングに仕立て上げたい

Dark theme自体はアプリケーション用のスタイルガイドなので、CLIのエディタとは少し趣が違いますが、今回はアプリケーション用のスタイルガイドに沿ってVim用のDark themeを作ってみることにしました。

Principles (原理)

Googleより発表されているDark themeのデザインについてのスタイルガイドはこちらになります。

Dark theme
https://material.io/design/color/dark-theme.html

ざっとおさらいすると (Principlesの項目)

  • 要素の前後の表現はダークグレーの濃さによって表現される(奥側:暗い←→明るい:手前側)
  • 限られた色によるアクセント表現
  • 電池消費量が良くなる
  • コントラスト基準を守ってアクセシビリティも意識

といった感じです。

もともと黒い画面のVimなので、電池消費については置いておきましょう。

つまるところ背景色が黒なのでshadowのような表現は利用できず、濃淡で前後関係を表現し、また、利用できる色はコントラスト比を意識した限られた色になるようです。

早速適応していきましょう。

Color Parret

先程のDark themeのサイトに配色の例が載ってます。
今回はthe Dark themeを目指してみるので、似たような配色で進めていきます。

なお、Primary、Secondory色選定の方針ですが、

A dark theme should avoid using saturated colors

と、ある通り、彩度の高いものは目の疲れを起こさせる、テキストに対してのアクセシビリティの基準をクリアしていないということで、彩度が少し抑えられたものが採用されるようです。

また、文字色も3段階で細かくガイドが定められています。
ここで例として目立つ色は87%、中程度は60%、無効としての色は38%の透明度というように用途によってグレーの濃淡を使い分けます。

詳しくは先程のサイトを見ていただくとして…

要素の前後の表現のためのグレー色を多段階で用意し、ところどころこちらで少しアレンジが入っていますが下記のようにパレットを用意しました。
256色対応と16色進数が使えるGUIカラーの両方を対応しました。
palette.png

(Diff用の色を一部特別に追加していますが、普段はあまり表に出てきません。)

というわけで実際に適応してみる

こんな感じになりました。
https://vimcolors.com/960/darktheme/dark
(色足りなかったので、エラー色だった赤もちょっとしたアクセントで使ってます。)

スクリーンショット 2019-12-14 0.57.11.png

コードハイライトも色を揃えてしまいました。
ちょっと通常のコードの色付けと比較すると物足りない気がしますが、今回はThe Dark Themeを目指すゆえ、基本的に色を増やさない色の選定の方針かつ4,5色ほどあればいい感じに配色が分かれるだろうという感じです。
(普段、「これは青だから...関数だ!」みたいなハイライトの頼り方をしていなければたぶんそんなに困りません。たぶん...たぶん...)

Plugin

https://github.com/kamykn/dark-theme.vim
プラグインにしてみました。

例えばプラグインマネージャーにvim-plug使っている方は

.vimrc
Plug 'kamykn/dark-theme.vim'

などとしてプラグインを有効にしてから、

.vimrc
syntax enable
colorscheme darktheme

と追記をしてください。

まとめ

と、ここまで書いて実はこの記事は3,4ヶ月くらい放置この日が来るまで記事を温めていました。
やはり、ネタ臭がどうしても拭えずこのままお蔵入りにするのもなぁと思ってたら、そういえば丁度良くアドベントカレンダーというのがあるじゃないか...と!😆🍰🍗🍻🎅🏻🎄

tmuxのステータスラインも合わせて紫に揃えて使ってみると、意外と悪くはない...?🙌

スクリーンショット 2019-12-14 1.35.37.png

それでは皆さん、Happy Vimming!✌️🎉


Vim プラグインのヘルプのフォーマットについて調べた

$
0
0

はじめに

Vim プラグインを使う際、ヘルプを見ることがあると思いますが、フォーマットが整っていますよね。

その中で、自分でヘルプを書くときにはどのようにフォーマットに則ればいいのかがわからなかったので、調べてみました。

フォーマットサンプル

:help write-local-helpに、フォーマットサンプルが載っています。typecorr という
以下、引用します。こちらを参考に説明します。

  1     *typecorr.txt*  Plugin for correcting typing mistakes
  2
  3     If you make typing mistakes, this plugin will have them corrected
  4     automatically.
  5
  6     There are currently only a few corrections.  Add your own if you like.
  7
  8     Mappings:
  9     <Leader>a   or   <Plug>TypecorrAdd
 10             Add a correction for the word under the cursor.
 11
 12     Commands:
 13     :Correct {word}
 14             Add a correction for {word}.
 15
 16                                                     *typecorr-settings*
 17     This plugin doesn't have any settings.

ヘルプの書き方

:help help-writingに説明がありましたので、かいつまんで紹介します。

1行目にヘルプファイル名を記載する

1行目の行頭に、 *typecorr.txt*というヘルプファイル名へのリンクを記載します。
これで、:help typecorr.txtというふうに検索したら、準備したヘルプにジャンプしてくれます。

行末に Vim モードラインを書く

ファイルの見た目を制御するVim モードラインを定義することで、ヘルプファイルの体裁を整えます。
vim-go のドキュメントファイルには以下のように記載されていました。

vim: ft=help tw=78 et ts=2 sw=2 sts=2 norl

  • ft=help: filetypehelp
  • tw=78: textwidth、テキスト最大幅を 78 に
  • et: expandtab、タブを指定数の空白文字に
  • ts=2: tabstop、2文字分の空白文字をタブとして認識させる
  • sw=2: shiftwidth、インデント時に使用される空白文字の数を2文字に
  • sts=2: softtabstop、タブを押下したときに使用する空白の数
  • norl: norightleft: 画面表示の方向を左から右に

適切にヘルプタグを付ける

アスタリスク *を指定することで、ヘルプタグをつけることができます。プラグイン名から始めるのが理想的とのこと。<plugin-name>-hogehogeみたいな感じですね。
また既存のヘルプタグにリンクするときは|で囲みます。

適切にシンタックスハイライトを使う

よりヘルプを読みやすくするために、シンタックスハイライトを適用します。いくつか紹介します。

  • コマンドブロック:>をブロック直前に、<をブロック直後に
  • 列見出し:~を行末に
  • セクション区切り:=をテキスト最大幅まで使う

おわりに

今回調べたことでヘルプの書き方の概要はざっくりつかめました。あとは他の Vim プラグインのヘルプファイルを参考に書いていこうと思います。

参考

denite.nvimのfilterをかっこよくする

$
0
0

はじめに

Vim/Neovimにおける高機能なファジーファインダーShougo/denite.nvim
拡張性の高さが大きな特徴で、さまざまな記事で多彩なdenite.nvimの「使い方」が解説されています。
きっとみなさんも、.vimrcdein.tomlにゴリゴリと設定を書き込んで使っておられることでしょう。

参考:
【vim】denite.nvim v3のマイベスト設定 - Qiita

そこでこの記事では、denite.nvimの「見た目」、中でも最近新しく追加されたdenite-filterウィンドウをかっこよくした話をしようと思います。

denite.nvimのfilterについて

もともと非常に高い拡張性を誇っていたdenite.nvimですが、2019年にはプロンプトを排し、Vimのネイティブなバッファを使用するdenite v3へとアップデートされました。
現在のdenite.nvimでは一般的なファジーファインダーと異なり、このように絞り込みを「denite-filter」と呼ばれる別ウィンドウで行うようになっています。

参考:
【Vim】新しい Denite に爆速で対応する - Qiita

filterからできる操作が限定されてしまったので操作感は大きく変わりましたが、動作はより警戒に、キーマッピングはvimと共通したより自然な形で設定できるようになり、フィルタ中で補完が効くようになるなど、慣れればアドバンテージの方が多いかと思います。
しかし、気になる点がひとつ。
filter-2.png
filterがvimのウィンドウとして開くようになったゆえに、statuslineまでついてきてしまうのです。
filterは候補の絞り込みにのみ使われるバッファですので、このstatuslineを活用できる要素は (私には) 思いつきません。

もちろんstatuslineがあるからといってdenite.nvimの機能に悪影響があるわけではありません。
ありませんが、いかんせんフィルタウィンドウはdenite.nvimを使うならパカパカと何度も開くものなので、毎回付いてくる余計な1行が次第に気にかかるようになってきました。
denite.nvim v2のときは、Pythonで実装されたlambdalisue/neovim-promptによるいい感じのプロンプトで絞り込みを行っていたので、それと比較する部分もあります。

外観というのは実際重要なファクターです。
もし最新のdenite.nvimでもオシャレなプロンプトが使えるようになれば、テンションも上がり、進捗も鰻登りに違いありません。

floating windowの可能性

ところで、 Neovimにはfloating Windowと呼ばれる、バッファの上に仮想のウィンドウを重ねて開くこと機能があります。
追従するように本家vimにも似たような性質 (同一ではない) を持つPopup windowが取り入れられたことからも、Neovimにおけるキラーフィーチャーであることが分かります。
denite.nvimでもこの新機能を活用することが可能で、deniteのバッファをfloating windowで開くことができます。
おまけに、この設定を使うと、filterのstatuslineは表示されなくなり外観がサッパリしたいい感じになります。
float.png
しかし、バッファのステータルラインも表示されなくなるので、現在開いている候補の数やパスなどが見られなくなってしまいます。(実は表示できます。詳しくは後述。)
また、deniteウィンドウ内でパスを移動するときにウィンドウがフリックするのが個人的に気になるところで、deniteバッファは安定して動作するようにしたいという思いがあり、見た目のカッコよさを惜しみつつも通常のウィンドウを使っていました。

気付き

そんな感じでdenite.nvimを使っていたところ、突然、

filterだけfloating Windowで開けばいい感じになりそうでは?

とふっと思いつきました。突然。

それでソースコードを見てみたところ、ほんの少しコードを追加するだけで簡単に実現できることがわかりました。
まあもとからあったものを組み合せただけですので……。

そうして思いつきでIssueを立て、PRを送った結果がこれ。
image.png
(figのstatuslineはlightline.vimでカスタマイズしたものです。デフォルトではただのインアクティブなstatuslineが開くので注意)

私がこのPRで行ったのは、もともと存在したfilterの開く方向を指定する-filter-split-directionオプションに、=floatingの設定を追加したこと。
この設定を指定すると、denite-filter だけがfloating windowとしてstatuslineの一行下に開きます。
floating window機能を使っているので、Neovim限定、かつNeovimのバージョンが0.4.0+である必要があります。

ほとんど頑張っていない割には、かなりいい感じの見た目になったと自分でも思います。
もちろんvimのバッファであることには変わりないので、機能はまったく同様です。

しかし、少し問題点も。
Neovimのfloating Windowはコマンドラインを上書きできないようで、deniteのウィンドウが最下段にあるときはfilterウィンドウがstatuslineを上書きしてしまいます。
70452175-07938800-1aea-11ea-9048-2eceed622a5a.gif

filterを抜けた後は普通にstatuslineを表示してくれますが、これでは減っていく候補数を横目に見ながら絞り込んでいく……みたいなムーブができません。
そこで、denite.nvimの-statuslineオプションが設定してあり、かつNeovimがset=titleであれば、denite.nvimがfloating Windowを使用中はtitlestringにdeniteのステータスが表示されるようにしています。
便利ですね。
titlestring.gif
画像上部に注目。iTerm2のタイトルバーにdeniteのステータスが表示されています。

これは作者のShougo氏にIssueで言及されて初めて知りました。
便利なんですがあまり知られていない気がします (私の中で) 。

これでdenite-fileterがかっこよくなりましたね!
で終わらせてもいいのですが、denite.nvimはユーザー側でもとことんこだわって設定できるのが特徴。

せっかくなので、もうちょっと凝った設定を探してみることにしました。

winblendとlightline.vimでfilterをもっとかっこよくする

私は基本的にデフォルトの-direction=botrightでdeniteを使っているので、filterが開いている間はステータスラインが隠れてしまっています。
ここでfilterウィンドウをもう一度眺めてみると、右側に使われていない大きなスペースがありますね。
filterを開いている間もこのスペースにdeniteのステータスを表示させることができれば、もっといい感じになりそうな気がしませんか?
そこで、-direction=botrightでdeniteを開いた際、filterウィンドウがステータスラインを隠してしまうのを逆手に取ることにしました。

ところで、Neovimにはfloating windowの透過率を設定するウィンドウローカルなオプションwinblendがあります。
透過率といっても擬似的なものではあるのですが、floating windowの下にあるバッファをうっすら表示できるようにする機能です。
半透明ないい感じの見た目のfloating windowを作るためのオプションですね。
0から100の範囲で設定できるのですが、docには0から30の範囲で使うことが推奨されています。

そうです、このwinblend悪用活用します。
winblendはウィンドウの背景色を透過させますが、あくまで擬似的な透過なので、文字はそのまま表示されるのです。つまり、
filterがstatuslineに重なってしまうのならば、逆にfilterを透明にしてやれば、statuslineの情報をfilterと共に表示させることができるというわけです。

denite-filterにsetlocal winblend=100して完全に透過させたfigがこちら。
vim
autocmd WinEnter denite-filter setlocal winblend=100

winblend.gif
やや見辛いですが、denite-filterを開きつつも、後ろのステータスラインが見えるようになりました。
しかし、インプットした文字がファイル名にかぶってしまっていますね。

denite-filterと重なっているステータスラインは、deniteバッファを開いているウィンドウ非アクティブ時の表示です。
なのでそのウィンドウのステータスラインの表示を、左側のファイル名を消しつつ右側にdeniteの情報を表示するように設定すればよさそうです。

ここでは、そのようにステータスラインの表示をカスタマイズするためにitchyny/lightline.vimを使います。
というか私はlightlineしか使ったことがないので、vim-airlineなどの他のステータスライン改造プラグインでも実現できるのかは不明です。

デフォルトの状態から、denite.nvimのステータスを表示するまでの簡単な設定を並べていきます。
なお、lightline.vimの設定のしかたは作者のitchynyさんの解説を見るのが一番だと思います。

letg:lightline={}letg:lightline.inactive ={    \'left':[['filename']],    \'right':[['lineinfo'],    \['percent'],['denite']]}letg:lightline.component_function ={}letg:lightline.component_function['filename']='LLfilename'letg:lightline.component_function['denite']='LLDenite'

lightlineは、ひとつの大きな辞書型変数g:lightlineに書き込んでいくことで設定を行います。
ここでは非アクティブ時のステータスラインを設定したいので、g:lightilne.inactiveに書き足していきましょう。

ファイル名を表示しているコンポーネントが'filename'ですね。
この部分をfiletypedeniteの時にだけ表示させないようにしたいわけです。

通常filenameg:lightline.componentで記述されています。
この下に指定されるオプションはset=statuslineでのみ機能するフラグと同様のフラグが使えますが、場合分けをする場合は評価値を返すためこのフラグが使えません (と私は理解しています) 。
lightlineでステータスラインの表示内容を設定する際は、基本的に関数を作ってそこからcomponent_functionを介して返させるのがおすすめです。

function! LLfilename() abort
    if&filetype isnot# 'denite'" g:lightline.component['filename'] = '%t'  と同義return expand('%:t')elsereturn''endifendfunction

右側に表示する内容はg:lightline.inactive['right']に追加します。
deniteのステータス情報はdenite.nvimの関数denite#get_status()を使い引っ張ってきましょう。
pathの表示が長くて表示を圧迫するので、ちょっと手を加えて短めにしています。

" deniteを開いたときだけ表示するfunction! LLDenite() abort
     if&filetype isnot# 'denite'return''elsereturns:denite_statusline()endifendfunctionfunction!s:denite_statusline() abort
    letp=denite#get_status('path')" 飾りをはずすletp= substitute(p,'\(\[\|\]\)','','g')" パスをホームディレクトリからの相対パスに変換するletp= fnamemodify(p,':~')" パスが長い時は強引に切り詰めるif strlen(p)>40letp='.../'. fnamemodify(p,':h:h:t').'/'            \. fnamemodify(p,':h:t').'/'. fnamemodify(p,':t')endiflet path ='['.p.']'let buf ='buffer:'. denite#get_status('buffer_name')let source = denite#get_status('sources')return  buf .' '. source .' '. path
 endfunction

せっかくなのでアクティブなdeniteウィンドウにもステータス情報を表示させておきましょう。
filetypefileencodingfileformatを表示している部分をひとつの関数にまとめて、&ft='denite'のときはその関数をdeniteステータスに置換します。

letg:lightline.active ={    \'left':[['mode','paste'],    \['readonly','filename','modified']],    \'right':[['lineinfo'],    \['percent'],    \['filestatus','denite']]}letg:lightline.component_function['filestatus']='LLfilestatus'" function! LLfilestatus() abort
    if&filetype isnot# 'denite'let fenc =&fenc!=#""?&fenc:&enc
        let ft =&ft!=#""?&ft:"no ft"return&ff .' | '. ft .' | '. fenc
    elsereturn''endifendfunction

設定前はこんな感じ。
before.gif
設定後はこんな感じ。
after.gif
いい感じになりましたね。

おわりに

今回紹介したdenite.nvimとlightline.vimは、どちらも自分の気が済むまでとことん設定を書き込んでいける、とても使い甲斐のあるプラグインだと思います。
この記事に触発されて.vimrcに5万行書き足しちゃうような人が現れてくれれば幸いです。

記事を書いててPRに結構粗があることに気付いたので、また直してもらうかもしれません。
あとカラースキームがコロコロ変わって見辛い。

vimの環境がだいぶ煮詰まってきたので紹介する

$
0
0

vim2 advent calendar 2019 15日目です。

導入

vimと一口に言ってもその設定項目は多岐に渡ります。さらにプラグインも入れればプラグインそのものと設定を含めて、百人いれば百通りのvim環境が出来上がるでしょう。
なんだかんだでvimを使い続けて5年ほどになりますが、今まで煮詰めてきた自分のvim環境を百通りのうちの一つとして紹介するのがこの記事の趣旨です。

neovim

vimと言ってもいくつか種類がありますが、自分が使用しているのはneovimです。
非同期がサポートされたあたりで乗り換えています。現在はvimでも非同期をサポートしており、neovimでしか動かなかったようなプラグインもvimで動くようになっているようです。今回のアドベントカレンダーに合わせて、neovim専用になっていた設定ファイルをvimでも使えるようにしたかったのですが、手元で試してみた限りうまくいかなかったのでいくつかの部分がneovimでしか動かなくなっています。ご了承ください。一応本来の想定は記述しておきます。

フォルダ構成

dotfiles

vim含め、様々な設定ファイルをdotfilesで管理しています。
dotfilesのルートは以下の構成になっています。

% tree -a -L 1                                                                                                                                                                                                                                                 
.
├── .config
├── .ctags
├── .git
├── .gitignore
├── .tmux
├── .vimrc
├── .zplugrc
├── .zsh
├── .zshrc
├── bin
├── etc
├── nvim -> /Users/takumikawase/dotfiles/.config/nvim
└── tags

更に.configの中身は以下のようになっています。

% tree -a -L 1                                                                                                                                                                                                                                         
.
├── anyenv
├── coc
├── efm-langserver
├── nvim
└── xbuild

いくつかのファイルは省略しています。
vimの設定ファイルはデフォルトでは.vimrcですが、neovimの設定ファイルはデフォルトでは.config/nvim下にあるinit.vimとなっています。
vimとneovimで同じ設定ファイルを使い回すために.vimrcの中身は以下の二行のみです。
set runtimepath+=$XDG_CONFIG_HOME/nvim
source $XDG_CONFIG_HOME/nvim/init.vim
これでvimを起動すると同時にneovimの設定ファイルをそのまま読み込んでくれます。あとはneovimの設定ファイルでvimかneovimかによって処理を分岐させることでvim, neovim量対応の設定が可能です。
自分のdotfilesについては「CUI環境とdotfilesを紹介する」を参照してください。

nvim

nvimのフォルダ構成になります。

% tree -a -L 1                                                                                                                                                                                                                                             
.
├── autocmds.vim
├── autoload
├── coc-settings.json
├── coc.toml
├── color.vim
├── colors
├── commands.vim
├── dein.toml
├── dein.vim
├── dein_lang.toml
├── dein_lazy.toml
├── dein_lsp.toml
├── dein_plugin.toml
├── dein_vim.toml
├── func.vim
├── init.vim
├── keymappings.vim
├── linux.vim
├── mac.vim
├── tags
└── types.vim

元々は一つの.vimrcを使用していましたが、neovimへの移行に伴い段階的に機能ごとにファイル分けを行いました。
それぞれのファイルの役割は以下の通りです。

init.vim

起動時に最初に読み込まれるファイルです。このファイルを起点に他のファイルを読み込んでいきます。
更に、setコマンドで各種設定を行なっています。

init.vim
" settings for mac and unix
if has('mac')
    " settings for mac
    source$HOME/.config/nvim/mac.vim
    " settings for linux
else
    source $HOME/.config/nvim/linux.vim
endif


" load dein.vim
source$XDG_CONFIG_HOME/nvim/dein.vim


" color scheme
source $XDG_CONFIG_HOME/nvim/color.vim


" load other setting files
" key mappings
source $HOME/.config/nvim/keymappings.vim


" settings for each filetypes
source$HOME/.config/nvim/types.vim


" launch commands
"source$HOME/.config/nvim/commands.vim


" autocommands
source $HOME/.config/nvim/autocmds.vim


" functions
" source $HOME/.config/nvim/func.vim


set number
set title
set ambiwidth=double
set tabstop=4
set expandtab
set shiftwidth=4
set smartindent
set list
set listchars=tab:»-,trail:-,extends:»,precedes:«,nbsp:%
set nrformats-=octal
set hidden
set history=200
set virtualedit=block
set whichwrap=b,s,h,l,[,],<,>
set backspace=indent,eol,start
set wildmenu
set fenc=utf-8
set nobackup
set noswapfile
set autoread
set showcmd
set cursorline
set visualbell
set laststatus=2
set wrapscan
set modeline
set autowrite
set display=lastline
set matchpairs& matchpairs+=<:>
set matchtime=1
set showtabline=2
set wildmenu
set wildignore=*.o,*.obj,*.pyc,*.so,*.dll
set mouse=a
set updatetime=100


" search system
set showmatch
set smartcase
set ignorecase
set infercase
set hlsearch
set incsearch


" foldmethod
set foldmethod=marker
set foldlevel=0
set foldcolumn=1


" disable the preview window
set completeopt-=preview


if has('nvim')set pumblend=5
endif

最後のset pumblendはneovimのfloating windowを使うためのオプションです。

dein.vim

後述するvimのプラグインマネージャーであるdeinで、各種プラグインを読み込むためのファイルです。
ちなみにインストールするプラグインはtomlファイルで管理していますが、tomlファイルも用途ごとにファイルを分けています。

dein.vim
" dein Scripts-----------------------------
if &compatible
    set nocompatible               " Be iMproved
endif


" set cache and config dirs
let s:dein_cache_dir = $XDG_CACHE_HOME . '/dein'
let s:dein_config_dir = $XDG_CONFIG_HOME . '/nvim'


" Required:
set runtimepath+=$XDG_CACHE_HOME/dein/repos/github.com/Shougo/dein.vim


let s:dein_dir = s:dein_cache_dir .'/repos/github.com/Shougo/dein.vim'if!isdirectory(s:dein_dir)
    call system('git clone https://github.com/Shougo/dein.vim '. shellescape(s:dein_dir))
endif


" Required:
if dein#load_state(s:dein_cache_dir)
    call dein#begin(s:dein_cache_dir)


    let s:toml = s:dein_config_dir . '/dein.toml'
    let s:toml_lazy = s:dein_config_dir . '/dein_lazy.toml'
    let s:toml_coc = s:dein_config_dir . '/coc.toml'
    let s:toml_lang = s:dein_config_dir . '/dein_lang.toml'
    let s:toml_plugin = s:dein_config_dir . '/dein_plugin.toml'
    let s:toml_vim = s:dein_config_dir . '/dein_vim.toml'




    call dein#load_toml(s:toml, {'lazy': 0})
    call dein#load_toml(s:toml_lazy, {'lazy': 1})
    call dein#load_toml(s:toml_coc, {'lazy': 1})
    call dein#load_toml(s:toml_lang, {'lazy': 1})
    call dein#load_toml(s:toml_plugin, {'lazy': 0})
    if !has('nvim')
        call dein#load_toml(s:toml_vim, {'lazy': 0})
    endif


    call dein#end()
    call dein#save_state()


    " Let dein manage dein
    " Required:
    " call dein#add('/Users/kawasetakumi/.cache/dein/repos/github.com/Shougo/dein.vim')" Add or remove your plugins here:
    " call dein#add('Shougo/neosnippet.vim')" call dein#add('Shougo/neosnippet-snippets')


    " You can specify revision/branch/tag.
    " call dein#add('Shougo/vimshell', { 'rev': '3787e5' })


    " Required:
    " call dein#end()
    " call dein#save_state()
endif

" Required:
filetype plugin indent on


"if dein#check_install(['vimproc'])"     call dein#install(['vimproc'])
" endif


" If you want to install not installed plugins on startup.
if dein#check_install()
    call dein#install()
endif


" End dein Scripts-------------------------

autocmds.vim

autocmd類をこちらに定義しています。現在は各種Filetypeをトリガーに動くautocmdが全てを占めています。

autocmds.vim
"" push quickfix window always to the bottom
autocmd FileType qf wincmd J


" for go lang
augroup go
    autocmd!
    autocmd FileType go :highlight goErr cterm=bold ctermfg=214
    autocmd FileType go :match goErr /\<err\>/
augroup END


"for python
augroup python
    autocmd!
    autocmd FileType python :syn match pythonOperator "\(+\|=\|-\|\^\|\*\)"
    autocmd FileType python :syn match pythonDelimiter "\(,\|\.\|:\)"
    autocmd FileType python :syn keyword self self
    autocmd FileType python :hi link pythonOperator Statement
    autocmd FileType python :hi link pythonDelimiter Special
    autocmd FileType python :hi link self Type
    " autocmd FileType python :highlight self cterm=bold ctermfg=214
    " autocmd FileType python :match self /self/
    " autocmd FileType python :highlight colon cterm=bold ctermfg=214
    " autocmd FileType python :match colon /:/
augroup END


" for c++
augroup cpp
    autocmd!
    autocmd FileType cpp :highlight cppcoloncolon cterm=bold ctermfg=214
    autocmd FileType cpp :match cppcoloncolon /\:\:/
augroup END


augroup typescript
    autocmd!
    autocmd FileType typescript :syn match Operator "\(|\|+\|=\|-\|\^\|\*\)"
    autocmd FileType typescript :syn match Delimiter "\(\.\|:\)"
    autocmd FileType typescript :hi link Operator Statement
    autocmd FileType typescript :hi link Delimiter Special
augroup END


augroup typescriptreact
    autocmd!
    autocmd BufNewFile,BufRead *.tsx set filetype=typescript.tsx
    autocmd FileType typescript.tsx :syn match Operator "\(|\|+\|=\|-\|\^\|\*\)"
    autocmd FileType typescript.tsx :syn match Delimiter "\(\.\|:\)"
    autocmd FileType typescript.tsx  :hi link Operator Statement
    autocmd FileType typescript.tsx :hi link Delimiter Special
augroup END


augroup denite-windows
    autocmd!
    autocmd FileType denite set winblend=5
    autocmd FileType denite-filter set winblend=5
augroup END


" Define mappings
autocmd FileType denite call s:denite_my_settings()function! s:denite_my_settings() abort
    nnoremap <silent><buffer><expr><CR>
    \ denite#do_map('do_action')
    nnoremap <silent><buffer><expr> d
    \ denite#do_map('do_action', 'delete')
    nnoremap <silent><buffer><expr> p
    \ denite#do_map('do_action', 'preview')
    nnoremap <silent><buffer><expr> q
    \ denite#do_map('quit')
    nnoremap <silent><buffer><expr> i
    \ denite#do_map('open_filter_buffer')
    nnoremap <silent><buffer><expr><Space>
    \ denite#do_map('toggle_select').'j'
endfunction


autocmd FileType denite-filter call s:denite_filter_my_settings()function! s:denite_filter_my_settings() abort
    imap <silent><buffer> <C-o> <Plug>(denite_filter_quit)


endfunction


autocmd FileType defx call s:defx_my_settings()function! s:defx_my_settings() abort
    " Define mappings
    nnoremap <silent><buffer><expr> <CR>
    \ defx#do_action('drop')
    nnoremap <silent><buffer><expr> c
    \ defx#do_action('copy')
    nnoremap <silent><buffer><expr> m
    \ defx#do_action('move')
    nnoremap <silent><buffer><expr> p
    \ defx#do_action('paste')
    nnoremap <silent><buffer><expr> l
    \ defx#do_action('open')
    nnoremap <silent><buffer><expr> E
    \ defx#do_action('open', 'vsplit')
    nnoremap <silent><buffer><expr> P
    \ defx#do_action('open', 'pedit')
    nnoremap <silent><buffer><expr> o
    \ defx#do_action('open_or_close_tree')
    nnoremap <silent><buffer><expr> K
    \ defx#do_action('new_directory')
    nnoremap <silent><buffer><expr> N
    \ defx#do_action('new_file')
    nnoremap <silent><buffer><expr> M
    \ defx#do_action('new_multiple_files')
    nnoremap <silent><buffer><expr> C
    \ defx#do_action('toggle_columns',
    \                'mark:indent:icon:filename:type:size:time')
    nnoremap <silent><buffer><expr> S
    \ defx#do_action('toggle_sort', 'time')
    nnoremap <silent><buffer><expr> d
    \ defx#do_action('remove')
    nnoremap <silent><buffer><expr> r
    \ defx#do_action('rename')
    nnoremap <silent><buffer><expr> !
    \ defx#do_action('execute_command')
    nnoremap <silent><buffer><expr> x
    \ defx#do_action('execute_system')
    nnoremap <silent><buffer><expr> yy
    \ defx#do_action('yank_path')
    nnoremap <silent><buffer><expr> .
    \ defx#do_action('toggle_ignored_files')
    nnoremap <silent><buffer><expr> ;
    \ defx#do_action('repeat')
    nnoremap <silent><buffer><expr> h
    \ defx#do_action('cd', ['..'])
    nnoremap <silent><buffer><expr> ~
    \ defx#do_action('cd')
    nnoremap <silent><buffer><expr> q
    \ defx#do_action('quit')
    nnoremap <silent><buffer><expr> <Space>
    \ defx#do_action('toggle_select') . 'j'
    nnoremap <silent><buffer><expr> *
    \ defx#do_action('toggle_select_all')
    nnoremap <silent><buffer><expr> j
    \ line('.') == line('$') ? 'gg' : 'j'
    nnoremap <silent><buffer><expr> k
    \ line('.') == 1 ? 'G' : 'k'
    nnoremap <silent><buffer><expr> <C-l>
    \ defx#do_action('redraw')
    nnoremap <silent><buffer><expr> <C-g>
    \ defx#do_action('print')
    nnoremap <silent><buffer><expr> cd
    \ defx#do_action('change_vim_cwd')
endfunction

color.vim

カラースキームやハイライトの設定をここでまとめて行っています。

color.vim
set t_8f=^[[38;2;%lu;%lu;%lum
set t_8b=^[[48;2;%lu;%lu;%lum
colorscheme default
set bg=light


" syntax highlight
if has('syntax')
syntax enable
endif


" hi fold'
hi Folded ctermbg=0 ctermfg=2
hi FoldColumn ctermbg=8 ctermfg=2


" hi popup
hi Pmenu ctermfg=15 ctermbg=0
hi PmenuSel ctermfg=0 ctermbg=15
hi PMenuSbar ctermfg=15 ctermbg=0


" hilight color
hi Search ctermbg=lightyellow
hi Search ctermfg=black
hi CursorColumn ctermbg=lightyellow
hi CursorColumn ctermfg=black
hi SpellBad ctermfg=black
hi SpellRare ctermfg=black

keymappings.vim

ファイル名通りキーマッピングをここでまとめて定義しています。キーマッピングはプラグインで設定されるものが衝突しやすいので:nnoremapなどを使って確認しながら設定することをおすすめします。

keymappings.vim
" set <Leader> to <Space>
let mapleader = "\<Space>"


" mappings for plugins
nmap [denite] <Nop>
map <Space>u [denite]


" mappings for the quickfix window
nnoremap <Space>n :cn<CR>
nnoremap <Space>p :cp<CR>
nnoremap <Space>q :ccl<CR>
nnoremap <Space>w :botright cwindow<CR>


nnoremap <Space><Space> i<Space><Esc>


" mapping for ctags
nnoremap <C-]> g<C-]>


nnoremap j gj
nnoremap k gk
nnoremap <Down> gj
nnoremap <Up> gk
nnoremap gj j
nnoremap gk k


nnoremap <C-6> :b #" change the terminal mode to the normal mode.
tnoremap <silent> <ESC> <C-\><C-n>


autocmd FileType go nmap [vim-go] <Nop>
autocmd FileType go nmap <leader>g [vim-go]


autocmd FileType go nmap [vim-go]t <Plug>(go-test)


function! s:build_go_files()
let l:file = expand('%')
if l:file =~# '^\f\+_test\.go$'
call go#test#Test(0, 1)
elseif l:file =~# '^\f\+\.go$'
call go#cmd#Build(0)
endif
endfunction


autocmd FileType go nmap [vim-go]b :<C-u>call <SID>build_go_files()<CR>


autocmd FileType go nmap [vim-go]c <Plug>(go-coverage-toggle)

autoload

プラグインの設定は、関数としてautoload以下にまとめて置いておき、プラグインの読み込みの際にdeinの機能で関数を呼び出しています。

プラグイン

実際に使用しているプラグインについて紹介していきます。
先程から名前が出ている通りプラグインマネージにはdeinを使用しています。最初期はvim-plugを使用していましたが、deinが流行ってくるのにあわせて移行しました。
正直これについてはvim-plugでもdeinでもどちらでも良い気がします。

tomlファイル

使用したいプラグインと設定をtomlファイルに書き込みdeinでロードすることでプラグインが使用可能になります。
deinの関数で一つずつプラグインを追加することも可能なようですが、deinを使う場合はtomlファイルによるプラグインの管理をおすすめします。
更にtomlファイルを読み込む際、lazyオプションを追加することで遅延ロードが可能になります。vim起動時にたくさんのプラグインを読み込むのは起動が遅くなるので、起動時に必要かに応じてlazyオプションを付与するのが良いと思います。
現在使用しているtomlファイルは以下のとおりです。
% ls -1 | grep toml [~/.config/nvim]
dein_plugin.toml
dein.toml
coc.toml # lazy
dein_lang.toml # lazy
dein_vim.toml
dein_lazy.toml # lazy
# lazyと横に書いているものは遅延ロードされるtomlファイルです。遅延ロードを行う際は、tomlファイル内のプラグイン一つ一つに対して読み込む条件を設定します。

dein.toml

vimを起動する際に必ず実行するプラグイン群です。

[[plugins]]
repo ='Shougo/dein.vim'[[plugins]]
repo ='itchyny/lightline.vim'
depends ='gina.vim'
hook_add ='call config#init#lightline#hook_add()'[[plugins]]
repo ='soramugi/auto-ctags.vim'
hook_add ='''
    let g:auto_ctags = 1
'''[[plugins]]
repo ='tpope/vim-surround'[[plugins]]
repo ='t9md/vim-quickhl'
hook_add ='call config#init#vim_quickhl#hook_add()'[[plugins]]
repo ='w0rp/ale'
hook_add ='call config#init#ale#hook_add()'[[plugins]]
repo ='maximbaz/lightline-ale'[[plugins]]
repo ='junegunn/fzf'
build ='./install --all'[[plugins]]
repo ='junegunn/fzf.vim'[[plugins]]
repo ='airblade/vim-gitgutter'[[plugins]]
repo ='lambdalisue/gina.vim'[[plugins]]
repo ='ryanoasis/vim-devicons'[[plugins]]
repo ='luochen1990/rainbow'
hook_add ='''
    let g:rainbow_active = 1
'''

余談ですが、deinではhook_add, hook_sourceなどのフックを使用してプラグインを読むこむ際のどこかのタイミングに処理を挟むことができます。
基本的にはhook_addでプラグインの使用に必要な設定を行っていますが、設定が長い場合は関数として切り出してファイルをautoload/config/initフォルダ以下に置き、その関数をコールするようにしています。
また、場合によっては他のフックを使いますが、そちらも同じようなルールで運用しています。

itchyny/lightline.vim

vimの下部にステータスラインを追加するプラグインです。他のプラグインと連携して表示する情報を増やすことができます。
gina.vimを使用したブランチの表示、cocを使用した関す情報の表示を行っています。

lightline.vim
function! config#init#lightline#hook_add() abort
    let g:lightline ={\ 'colorscheme': 'wombat',
      \ 'active': {\ 'left': [['mode', 'paste'],
      \ ['gitbranch', 'readonly', 'filename', 'modified']],
      \ 'right': [['lineinfo'], ['percent'], ['fileformat', 'fileencoding', 'filetype'],
      \ ['cocstatus', 'currentfunction']]\ },
      \ 'component_function': {\ 'gitbranch': 'gina#component#repo#branch',
      \ 'mode': 'LightlineMode',
      \ 'cocstatus': 'coc#status',
      \ 'currentfunction': 'CocCurrentFunction'\ }\ }
endfunction


function! LightlineMode()return&ft =='denite' ? 'Denite' :
      \ &ft =='vimfiler' ? 'VimFiler' :
      \    winwidth(0)> 60 ? lightline#mode() : ''
endfunction


function! CocCurrentFunction()return get(b:, 'coc_current_function', '')
endfunction

lightlineの設定例です。このように設定が複数行に渡る場合は関数に切り出してファイルとしてautoload/config/init以下に置いておき、hookからコールするようにしています。

soramugi/auto-ctags.vim

vimにはctagsと連携して関数定義に移動する機能が備わっています。実はその機能はLSPを導入することでより便利に行うことが可能なのですが、後述のtagbarというプラグインのためにctagsを生成するようにしています。ただ、デフォルトではctagsは手動で実行する必要があるのでそれを自動化するプラグインです。g:auto_ctagsオプションをオンにすることで保存時に自動で生成してくれます。

tpope/vim-surround

ある文字列を囲んでいるHTMLタグやクォートなどを消したり変更したり追加するコマンドを追加するプラグインです。コマンドが覚えにくいのでなれないうちは都度調べる必要があるのが面倒ですが、ちょくちょく機能が欲しくなるプラグインです。

t9md/vim-quickhl

単語のハイライトを自動で行ったり、特定の文字列をハイライトできるプラグインです。いくらでもハイライトがつけられるのでコードリーディングの際などに便利です。

w0rp/ale

言語のlinterを使ってコードをチェックしてくれるプラグインです。デフォルトでも多くのlinterやその他ツールに対応しているので、とりあえずlinter等をインストールすればすぐ使えるのが強みです。最近はLSP機能も入ったようですが、自分は使用していません。

ale.vim
function! config#init#ale#hook_add() abort
    highlight clear ALEError
    highlight clear ALEWarning
    let g:ale_lint_on_enter = 0
    let g:ale_sign_column_always = 1
    let g:ale_set_loclist = 0
    let g:ale_set_quickfix = 1
    if has('mac')let s:header_path ='-I/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include'let g:ale_cpp_clang_options ='-std=c++14 -Wall '. s:header_path
        let g:ale_cpp_gcc_options ='-std=c++14 -Wall '. s:header_path
    endif
    let g:ale_linters ={\ 'c': ['clangd'],
                \ 'cpp' : ['clangd']\ }
endfunction

設定例です。c, cppのlinterについてはclangdを使用するように明示しています。

airblade/vim-gitgutter

gitの差分が発生した場合に、どこにどのような差分が発生しているかを行頭に表示してくれます。

lambdalisue/gina.vim

vim中でgitを扱うためにプラグインですが、自分は基本的にtmuxで開いている別ペインでgitを使用しています。
なのでlightlineでブランチを表示するためにプラグインになりかけてます...

luochen1990/rainbow

vimでも括弧の色分けができるようになります。素のvimでも対応する括弧にハイライトをつけたり、%コマンドで対応する括弧に移動ができますが、色による視認性の方が高いです。

dein_vim.toml

neovimではなくvimでneovim用に作られたプラグインを動かすための前提プラグイン用です。
dein.vimの方で、使用しているクライアントがnvimでない(=vim)のときに読み込みます。

[[plugins]]
repo ='roxma/vim-hug-neovim-rpc'[[plugins]]
repo ='roxma/nvim-yarp'

ただ、これで動くと思っていたのですが、どうもpythonがうまく呼べてないようで、エラーが出てうまくいっていません。(情報欲しいです!)

dein_lazy.toml

名前の通り遅延ロードしているプラグインです。比較的重そうなプラグインや、特定の状況下で動く必ずしも起動時に必要ではないプラグインは出来るだけ遅延ロードさせるようにしています。

[[plugins]]repo='Shougo/denite.nvim'on_cmd=['Denite']depends=['vim-devicons']hook_add='callconfig#init#denite#hook_add()'hook_post_source='callconfig#init#denite#hook_post_source()'[[plugins]]repo='Shougo/neomru.vim'on_cmd=['Denite']on_source=['denite.nvim'][[plugins]]repo='Shougo/neoyank.vim'on_cmd=['Denite']on_source=['denite.nvim'][[plugins]]repo='cespare/vim-toml'on_ft='toml'[[plugins]]repo='majutsushi/tagbar'on_cmd=['TagbarToggle']hook_add='callconfig#init#tagbar#hook_add()'hook_source='callconfig#init#tagbar#hook_source()'[[plugins]]repo='cohama/lexima.vim'on_event='InsertEnter'[[plugins]]repo='scrooloose/nerdtree'on_cmd=['NERDTreeToggle']depends=['vim-devicons','vim-nerdtree-syntax-highlight','nerdtree-git-plugin']hook_add='callconfig#init#nerdtree#hook_add()'hook_source='callconfig#init#nerdtree#hook_source()'[[plugins]]repo='Xuyuanp/nerdtree-git-plugin'[[plugins]]repo='tiagofumo/vim-nerdtree-syntax-highlight'[[plugins]]repo='ryanoasis/vim-devicons'

Shougo/denite.nvim

開いているバッファーやカレントディレクトリ以下のファイル、最近開いたファイルなどに素早くアクセスするためのインターフェースを提供するプラグインです。
ファイラーのように一覧表示されているのも便利ですが、名前のわかっているファイルへの移動についてはこちらのほうが高速です。こちらを導入する際にはripgrepなどの導入も合わせて行うと効果的です。遅延ロードの条件はdenite実行時にしています。

denite.vim
function! config#init#denite#hook_add() abort
    " defined in keymappings.vim
    " Prefix for denite
    " nmap [denite] <Nop>
    " map <Space>u [denite]


    " key mappings for Denite and sources
    nnoremap <silent> [denite]y :<C-u>Denite neoyank -split=floating<CR>
    nnoremap <silent> [denite]u :<C-u>Denite buffer file/rec -split=floating<CR>
    nnoremap <silent> [denite]f :<C-u>Denite file/rec -split=floating<CR>
    nnoremap <silent> [denite]b :<C-u>Denite buffer -split=floating<CR>
    nnoremap <silent> [denite]m :<C-u>Denite file_mru -split=floating<CR>
    nnoremap <silent> [denite]a :<C-u>Denite -resume -split=floating<CR>


    " settings for grep
    nnoremap <silent> [denite]g :<C-u>Denite grep-buffer-name=search-buffer-denite -split=floating<CR>
    nnoremap <silent> [denite]w :<C-u>DeniteCursorWord grep-buffer-name=search-buffer-denite -split=floating<CR>
    nnoremap <silent> [denite]r :<C-u>Denite -resume-buffer-name=search-buffer-denite -split=floating<CR>
    nnoremap <silent> [denite]n :<C-u>Denite -resume-buffer-name=search-buffer-denite -cursor-pos=+1 -immediately-split=floating<CR>
    nnoremap <silent> [denite]p :<C-u>Denite -resume-buffer-name=search-buffer-denite -cursor-pos=-1-immediately-split=floating<CR>
endfunction


function! config#init#denite#hook_post_source() abort
    " Change the prompt
    call denite#custom#option('default', 'prompt', '>')


    " Add action keybinds
    call denite#custom#map('insert', '<C-v>', '<denite:do_action:vsplit>')
    call denite#custom#map('insert', '<C-s>', '<denite:do_action:split>')
    call denite#custom#map('normal', '<C-v>', '<denite:do_action:vsplit>')
    call denite#custom#map('normal', '<C-s>', '<denite:do_action:split>')


    call denite#custom#map('insert', '<C-n>', '<denite:move_to_next_line>')
    call denite#custom#map('insert', '<C-p>', '<denite:move_to_previous_line>')
    call denite#custom#map('normal', '<C-n>', '<denite:move_to_next_line>')
    call denite#custom#map('normal', '<C-p>', '<denite:move_to_previous_line>')" Variables
    "grepでagを使用するように設定
    call denite#custom#var('grep', 'command', ['rg'])"カレントディレクトリ内の検索もagを使用する
    call denite#custom#var('file/rec', 'command', ['rg', '--files', '--glob', '!.git'])
    " call denite#custom#var('file/rec', 'command', ['ag', '--follow', '--nocolor', '--nogroup', '-g', ''])"その他のgrepの設定
    call denite#custom#var('grep', 'default_opts',['-i', '--vimgrep', '--no-heading'])
    call denite#custom#var('grep', 'recursive_opts', [])
    call denite#custom#var('grep', 'pattern_opt', ['--regexp'])
    call denite#custom#var('grep', 'separator', ['--'])
    call denite#custom#var('grep', 'final_opts', [])
endfunction

Shougo/neomru.vim

deniteのソースに"最近開いたバッファ"を追加します。deniteのインターフェースで検索を行う際に最近開いたバッファも検索対象として結果に出てくるようになります。

Shougo/neoyank.vim

上記同様に、yankしたものについてもdeniteのソースに追加できます。

cespare/vim-toml

vimでtomlファイルを編集する際に、シンタックスを追加してくれるプラグインです。deinなどでtomlファイルを編集する場合は入れておくと便利かもしれません。

majutsushi/tagbar

前述したctagsの中身を画面に表示するプラグインです。ctagsによる生成がうまく行っていれば、ファイル内の変数やクラス、関数などの一覧が表示されます。

tagbar.vim
function! config#init#tagbar#hook_add() abort
    let g:tagbar_width=40
    nmap <Space>z :TagbarToggle<CR>
endfunction


function! config#init#tagbar#hook_source() abort
    let g:tagbar_type_go ={\ 'ctagstype' : 'go',
    \ 'kinds'     : [\ 'p:package',
        \ 'i:imports:1',
        \ 'c:constants',
        \ 'v:variables',
        \ 't:types',
        \ 'n:interfaces',
        \ 'w:fields',
        \ 'e:embedded',
        \ 'm:methods',
        \ 'r:constructor',
        \ 'f:functions'\ ],
    \ 'sro' : '.',
    \ 'kind2scope' : {\ 't' : 'ctype',
        \ 'n' : 'ntype'\ },
    \ 'scope2kind' : {\ 'ctype' : 't',
        \ 'ntype' : 'n'\ },
    \ 'ctagsbin'  : 'gotags',
    \ 'ctagsargs' : '-sort -silent'\ }let g:tagbar_type_typescript ={\ 'ctagsbin' : 'ctags',                                                        
      \ 'kinds': [\ 'e:enums:0:1',                                                               
        \ 'f:function:0:1',                                                            
        \ 't:typealias:0:1',                                                           
        \ 'M:Module:0:1',                                                              
        \ 'I:import:0:1',                                                              
        \ 'i:interface:0:1',                                                           
        \ 'C:class:0:1',                                                               
        \ 'm:method:0:1',                                                              
        \ 'p:property:0:1',                                                            
        \ 'v:variable:0:1',                                                            
        \ 'c:const:0:1',                                                              
      \ ],                                                                            
      \ 'sort' : 0                                                                    
    \ }                   
endfunction

goとtypescriptについてはデフォルトでは物足りないので設定を追加しています。

cohama/lexima.vim

括弧やクォートを入力した際に対応する閉じ括弧を自動で付け足してくれるプラグインです。基本的には便利ですが、括弧を消したときや閉じ括弧を入力したときにうまく括弧の数が揃わない場合があるので注意が必要です。また、pythonの複数行コメントを入力したい場合など、クォートの数がイレギュラーな場合はうまく補完ができません。

scrooloose/nerdtree

vimのファイラーです。少し前までdefxを使用していましたが、ファイルのアイコンを表示した際にファイル名の表記が崩れるのでこちらに移行しました。
こちらでもファイル名の表記は多少崩れますが、defxに比べれば少ないので許容範囲内としています。vimにも実はファイラーは付属していますが、defxやnerdtreeのほうが操作が直感的でわかりやすいです。

nerdtree.vim
function! config#init#nerdtree#hook_add() abort
    nnoremap <silent> <Space>v :<C-u>NERDTreeToggle<CR>
endfunction


function! config#init#nerdtree#hook_source() abort
    let g:NERDTreeWinSize = 40
    let g:WebDevIconsUnicodeGlyphDoubleWidth = 0
    let g:WebDevIconsNerdTreeBeforeGlyphPadding =''let g:WebDevIconsNerdTreeAfterGlyphPadding ='  'let g:WebDevIconsUnicodeDecorateFolderNodes = 0
endfunction

Xuyuanp/nerdtree-git-plugin

nerdtree上で、gitのステータスを表示してくれるプラグインです。

tiagofumo/vim-nerdtree-syntax-highlight

nerdtree上で、シンタックスハイライトを追加してくれるプラグインです。純粋に視認性が上がるのでおすすめです。

ryanoasis/vim-devicons

vim内でdeviconを表示するためのプラグインです。deniteやnerdtreeでファイル名の頭にアイコンがつくようになってsyntax-highlightと同じく視認性が上がります。

dein_lang.toml

言語依存のプラグインをon_ftを使用して特定のファイルタイプのときに実行するようにしています。vimのデフォルトだと言語のサポート(syntax highlight)が不十分な場合に補ったり特定の言語のサポートツールをvimで使えるようにします。

[[plugins]]repo='rust-lang/rust.vim'on_ft='rust'hook_source='callconfig#init#rust#hook_source()'[[plugins]]repo='octol/vim-cpp-enhanced-highlight'on_ft=['c','cpp'][[plugins]]repo='fatih/vim-go'on_ft='go'hook_source='callconfig#init#vim_go#hook_source()'[[plugins]]repo='neovimhaskell/haskell-vim'on_ft='haskell'

rust-lang/rust.vim

vimでrustを書く際に、シンタックスハイライトを効かせたり、その他フォーマッターなどのサポートが導入できます。

octol/vim-cpp-enhanced-hightlight

より新しいバージョンのc, c++についてもシンタックスハイライトが効くようになるプラグインです。

fatih/vim-go

vimでgoを書くならば必須のプラグイン。goは周辺のツールが充実しており、それらをvimでうまく使えるようにしてくれます。

vim_go.vim
function! config#init#vim_go#hook_source() abort
    let g:go_highlight_array_whitespace_error = 1
    let g:go_highlight_chan_whitespace_error = 1
    let g:go_highlight_extra_types = 1
    let g:go_highlight_space_tab_error = 1
    let g:go_highlight_trailing_whitespace_error = 1
    let g:go_highlight_operators = 1
    let g:go_highlight_functions = 1
    let g:go_highlight_function_parameters = 1
    let g:go_highlight_function_calls = 1
    let g:go_highlight_types = 1
    let g:go_highlight_fields = 1
    let g:go_highlight_build_constraints = 1
    let g:go_highlight_generate_tags = 1
    let g:go_highlight_variable_declarations = 1
    let g:go_highlight_variable_assignments = 1
    let g:go_fmt_command ="goimports"let g:go_auto_type_info = 1
    let g:go_auto_sameids = 1
    let g:go_list_type ="quickfix"
endfunction

neovimhaskell/haskell-vim

同じくvimでhaskellを書きやすいようにシンタックスハイライトやインデントのルールなどを追加してくれるプラグインです。

coc.toml

lspクライアントであるcoc.nvimのためのtomlファイルです。もともとlsp関連プラグイン用のファイルとしてdein_lspがありましたが、coc.nvimを導入したことでlsp関連は全て間に合うのでこのようなファイル名になりました。

[[plugins]]
repo = 'neoclide/coc.nvim'
rev = 'release'
on_i = 1
merged = '0'
hook_source = 'call config#init#coc#hook_source()'

coc.vim
function! config#init#coc#hook_source() abort
    " if hidden is not set, TextEdit might fail.
    set hidden


    " Some servers have issues with backup files, see #649set nobackup
    set nowritebackup


    " Better display for messages
    "set cmdheight=2


    " You will have bad experience for diagnostic messages when it's default 4000.
    set updatetime=300


    " don't give |ins-completion-menu| messages.
    set shortmess+=c


    " always show signcolumns
    set signcolumn=yes


    " Use tab for trigger completion with characters ahead and navigate.
    " Use command ':verbose imap <tab>' to make sure tab is not mapped by other plugin.
    inoremap <silent><expr> <TAB>
          \ pumvisible() ? "\<C-n>" :
          \ <SID>check_back_space() ? "\<TAB>" :
          \ coc#refresh()
    inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"


    function! s:check_back_space() abort
      let col = col('.') - 1
      return !col || getline('.')[col - 1]  =~# '\s'
    endfunction


    " Use <c-space> to trigger completion.
    inoremap <silent><expr> <c-space> coc#refresh()


    " Use <cr> to confirm completion, `<C-g>u` means break undo chain at current position.
    " Coc only does snippet and additional edit on confirm.
    inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
    " Or use `complete_info` if your vim support it, like:
    " inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>"


    " Use `[g` and `]g` to navigate diagnostics
    nmap <silent> [g <Plug>(coc-diagnostic-prev)
    nmap <silent> ]g <Plug>(coc-diagnostic-next)


    " Remap keys for gotos
    nmap <silent> gd <Plug>(coc-definition)
    nmap <silent> gy <Plug>(coc-type-definition)
    nmap <silent> gi <Plug>(coc-implementation)
    nmap <silent> gr <Plug>(coc-references)


    " Use K to show documentation in preview window
    nnoremap <silent> K :call <SID>show_documentation()<CR>


    function! s:show_documentation()
      if (index(['vim','help'], &filetype) >= 0)
        execute 'h '.expand('<cword>')
      else
        call CocAction('doHover')
      endif
    endfunction


    " Highlight symbol under cursor on CursorHold
    " autocmd CursorHold * silent call CocActionAsync('highlight')


    " Remap for rename current word
    nmap <leader>rn <Plug>(coc-rename)


    " Remap for format selected region
    xmap <leader>f  <Plug>(coc-format-selected)
    nmap <leader>f  <Plug>(coc-format-selected)


    augroup mygroup
      autocmd!
      " Setup formatexpr specified filetype(s).
      autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
      " Update signature help on jump placeholder
      autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
    augroup end


    " Remap for do codeAction of selected region, ex: `<leader>aap` for current paragraph
    xmap <leader>a  <Plug>(coc-codeaction-selected)
    nmap <leader>a  <Plug>(coc-codeaction-selected)


    " Remap for do codeAction of current line
    nmap <leader>ac  <Plug>(coc-codeaction)
    " Fix autofix problem of current line
    nmap <leader>qf  <Plug>(coc-fix-current)


    " Create mappings for function text object, requires document symbols feature of languageserver.


    xmap if <Plug>(coc-funcobj-i)
    xmap af <Plug>(coc-funcobj-a)
    omap if <Plug>(coc-funcobj-i)
    omap af <Plug>(coc-funcobj-a)


    " Use <tab> for select selections ranges, needs server support, like: coc-tsserver, coc-python
    nmap <silent> <TAB> <Plug>(coc-range-select)
    xmap <silent> <TAB> <Plug>(coc-range-select)
    xmap <silent> <S-TAB> <Plug>(coc-range-select-backword)


    " Use `:Format` to format current buffer
    command! -nargs=0 Format :call CocAction('format')


    " Use `:Fold` to fold current buffer
    command! -nargs=? Fold :call     CocAction('fold', <f-args>)


    " use `:OR` for organize import of current buffer
    command! -nargs=0 OR   :call     CocAction('runCommand', 'editor.action.organizeImport')


    " Add status line support, for integration with other plugin, checkout `:h coc-status`
    " set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}


    " Using CocList
    " Show all diagnostics
    nnoremap <silent> <space>a  :<C-u>CocList diagnostics<cr>
    " Manage extensions
    nnoremap <silent> <space>e  :<C-u>CocList extensions<cr>
    " Show commands
    nnoremap <silent> <space>c  :<C-u>CocList commands<cr>
    " Find symbol of current document
    nnoremap <silent> <space>o  :<C-u>CocList outline<cr>
    " Search workspace symbols
    nnoremap <silent> <space>s  :<C-u>CocList -I symbols<cr>
    " Do default action for next item.
    nnoremap <silent> <space>j  :<C-u>CocNext<CR>
    " Do default action for previous item.
    nnoremap <silent> <space>k  :<C-u>CocPrev<CR>
    " Resume latest coc list
    nnoremap <silent> <space>r  :<C-u>CocListResume<CR>
endfunction

ほとんど公式からもってきたものそのままになっています。


coc.nvimについて詳しくはこちらに書いています。
coc.nvimを使ってvimをもっと強くする

終わり

以上が自分のvimの設定になっています。今まで多種多様な設定及びプラグインを導入しては削除を繰り返してきましたが、最近は以上のような構成で落ち着いています。
vimプラグインは開発が活発で様々なプラグインが存在しますが、プラグインの導入はだんだんとコストがかかるようになります。
vimの起動時間、キーマッピングの衝突、機能の使い方を覚えるetc...
たまにはインストールしているプラグインの一覧を見て、あまり使っていないようであれば消してしまってもいいと思います。また必要になったらインストールすればいいだけですし
それを繰り返していくことでだんだんと自分の理想の環境ができてくると思います。

vimの中からtmuxを操作する

$
0
0

この記事はdotfileアドベントカレンダーの15日目です!

はじめに

みなさんvim + tmux生活エンジョイしていますか?
エンジョイしている方、エンジョイしたい方にオススメの設定をお教えします。

ズバリ、vimの中からtmuxを操作するというものです。
基本的にはこちらを参考にし、コードをリファクタしました。
15年目のVim | POSTD

tmuxにはcommandでpaneに好きなコマンドを送ることができる、
tmux send-keysというコマンドがあります。

試しにお手元のtmuxで新しいセッションを開き、
3つほどpane分割をした後以下のコマンドを実行してみてください。

$ tmux send-keys -t$(tmux display-message -p"#S"):0.2 'echo hogefuga' c-j

おそらく別のpaneにてecho hogefugaというコマンドが実行されたかと思います。
(これで実行されない場合、おそらくtmuxのwindowやpaneの番号が1から始まるといった設定をしている
ことが考えられます)

-tオプションにて送信先のpaneを指定します。
フォーマットはsession名:window番号.pane番号となっております。
今回は$(tmux display-message -p "#S")にてsession名を取得し、柔軟に仕上げました。

こちらをvim内でsystem()を用いて実行してあげる、というものです。

apiのエンドポイントを開発しているときとかに別paneにcurlとjqを走らせておいて、

こいつを用いてvim内からそのcurlを走らせたりすると便利ですね
アイディア元のsample

Vimacs - VS Code で Vim と Emacs のいいとこどり

$
0
0

OPENLOGI Advent Calendar 2019の記事です。
昨年、完全に自分用に作ったプラグインですがなかなか便利なので紹介します。

理想のエディターを求めて

  • ベースの環境としては VS Code を使いたい!
  • カーソル操作は Vim キーバインドを使いたい!
  • 文字入力時は Emacs キーバインドを使いたい!

というわがままな人のために VSCode Extension です。

Vimacs for VSCode


https://marketplace.visualstudio.com/items?itemName=migrs.vimacs

できること

  • インサートモードで基本的な Emacs キーバインディングが使える
  • カーソル移動以外ではリージョン操作系にも対応
  • VS Code のコマンド入力やファイル選択のUIでも Ctrl+N, Ctrl+Pなどのカーソル移動に対応

詳しくは

自分のブログの方で紹介してますのでそちらを参照してください
https://m.igrs.jp/blog/2019/12/14/vimacs-for-vscode/

暫定対処

上記記事内にも書いてますが、期待通りに動かないキーバインドがあります。
現在私の方では以下の Emacs の切り取り(Ctrl+W)が動かないので keybindings.jsonで再度定義しています。

{"key":"ctrl+w","command":"emacs.action.clipboardCutAction","when":"editorTextFocus && editorHasSelection && !editorReadonly && vim.mode == 'Insert'"}

VSCode 拡張の開発について

久しぶりに触ってみたら忘れていた部分もあったので備忘録的に残しておきます。

VSCode の拡張開発には vsceというライブラリを利用します。

ビルドと検証と公開

ローカルパッケージの作成

vsce package

ローカルパッケージのインストール

code --install-extension vimacs-1.1.1.vsix

マーケットプレイスへの公開

vsce publish

基本的にはこれだけです。

アカウントの作成

ここらへん、以前と手順というか仕組みが異なった気がします。
基本的には Azure DevOps というところで、Organization と Project というものを用意して管理する必要があるようです。

https://dev.azure.com/[OrganizationID]

セキュリティートークンの場所もわかりにくくURL的には以下になります。
https://dev.azure.com/[OrganizationID]/_usersSettings/tokens

詳しくは公式のドキュメントをどうぞ
Publishing Extensions

Vim のオプション設定をバッファに挿入する

$
0
0

はじめに

Vim で試しにオプション設定を行い、それが良かったので vimrc に書こうとした際にその設定内容が手入力するには長かったり複雑だったりして困ったことはないでしょうか。
set {option}?の結果などをバッファに挿入できれば…と思って調べて回った結果その方法が見つかったので書きます。

使用する機能

以下の機能を使います。

  • レジスタの内容を挿入(i_CTRL-R)
  • Expression レジスタ
  • execute コマンド

詳細

レジスタの内容を挿入

インサートモードでレジスタの内容を挿入するには CTRL-Rを入力したあとにレジスタ名を入力します。

Expression レジスタ

レジスタには番号のレジスタ以外に特別なレジスタがあり、その一つが Expression レジスタです。
インサートモードで CTRL-Rを入力したあとに =を入力するとコマンド行に式を入力できるようになります。式を入力してEnterキーを入力すると式が評価されてその結果が挿入されます。

execute コマンド

Exコマンドを実行して出力を文字列として返すコマンドです。

オプション設定をバッファに挿入する

上記の機能を組み合わせることで Vim のオプション設定をバッファに挿入することができます。

  1. インサートモードに入る
  2. CTRL-Rを入力
  3. =execute("set {option}?")を入力
  4. Enter キーを入力

例えばインサートモードで CTRL-Rを入力した後、以下のように入力すると

=execute("set guifont?")

以下のような結果がバッファに挿入されます。

  guifont=Osaka-Mono:h14

実行してみればわかりますが、なぜか直前に空行が挿入されます。
これについては理由がわかっていません。(知っている方がいらっしゃったら教えて欲しいです…)

最後に

ちょっとした小ネタではありますが、これで vimrc の編集が少し楽になる場合があるんじゃないかなと思っています。

【超私見】VSCodeから始めるVim

$
0
0

はじめに

私がVSCode上でVimキーバインドを始め、3ヶ月目に「3ヶ月使って実感! 今すぐVSCodeにVimキーバインドを導入すべき3つの理由」 を書いてから、ちょうど1年が経過しました。

現在ではほとんど意識しなくてもさまざまな操作をナチュラルにできるようになり、この快適さをさらに多くの人に広めたいと思っています。

今回は、VSCodeでVimの入力方法を体得するために、本当に必要な設定やコマンドを厳選・抽出し、優先順位付けすることで、初心者の方でも速い段階で効果を感じることができるようにしたいと思います。

対象

  • VSCodeを使っている。
  • Vimは速いとか良いとか聞いているが、イマイチ良さがわからないし、入力のクセが強そうだし、設定もめんどくさそうだと思っている。

対象外の方

  • Vimを独学で学んで、自分用にカスタマイズしてバリバリコーディングしている、つよつよエンジニア。

お断わり

あらかじめお断わりしておきますが、この記事は大変私見にあふれております。

明らかな誤りについてはご指摘いただきたいのですが、思想的な面での差については、何卒暖かい目で見ていただきたく、よろしくお願いします。

なぜVSCodeからVimを?

ギャップを少なくして、色々な人に使ってほしい

「VimがいいならVim自体を使えばいいじゃないか、何故わざわざVSCodeでVimを使い始めるのか?」
と考える方もいらっしゃるかと思います。たしかにそうです。

しかし、初学者やVSCode等のエディタを使っている人に対してVimを勧めたとしても、ギャップが大きすぎて、多くの場合、良さを体感する前に止めてしまうことが想像されます。

今バリバリ Vim を使いこなしている人は、以下に当てはまると(勝手に)思っています。

  • エディタがviぐらいしかない環境で作業していて、覚えなくては生きていけなかった。
  • Vimを使える自分超エンジニア!カッコイイ!
  • 入力速度を高める過程で出会った。キーボード等のインターフェースも、もちろんこだわっています。
  • 周りに爆速でVimを使っている人がいて、羨しくてがんばった。

上記のようなモチベーションもっている人はいいのですが、そういったものが薄い人にも、Vimの良さを感じてもらいたいのです。

VSCodeが良いエディタだから

VSCodeはベテランにも初学者にも勧められる、良いエディタです。 高機能でありながら動作が軽く、カスタマイズ性もあり、本体・プラグインともに開発が活発です。

Vimのプラグイン開発者であるTim Pope氏)も以下のように呟いているほどです。

VSCodeの良い部分を享受しつつ、Vimの入力方法の便利な部分を感じ、体得してもらう。あとはVSCodeをそのまま使い続けるなり、Vimに移行するなり。

VSCodeで使うVimキーバインドは、Vimへの間口を開くものになると考えています。

必要な設定

VSCodeでVimの良さを感じるために必要な、最小限の設定をします。

インストール

まず、Vimプラグインをインストールします。

VSCodeの拡張機能(Extension)メニューを開き、検索ボックスにvimと入力すればトップに表示されるはずです。

image.png

Installボタンを押し、インストールします。

設定

VSCodeのsetting.jsonを開き、以下の内容を追記します。

setting.jsonの開き方
1. VSCodeを開き、Cmd+Shift+Pでコマンドパレットを開きます。
2. "setting json" と入力すると以下のような候補が表示されるので、Enterを押します。

image.png

  "vim.easymotion": true,
  "vim.handleKeys": {
    "<C-a>": false,
    "<C-f>": false
  },
  "vim.insertModeKeyBindings": [
    {
      "before": ["j", "k"],
      "after": ["<esc>"]
    },
  ],
  "vim.leader": "<space>",
  "vim.useCtrlKeys": true,
  "vim.useSystemClipboard": true,

学習の方針について

ギャップは少なくはじめる

学習のギャップを少なくするために、全てを一気にVimに寄せません。

元に戻す(Cmd+z)や全て選択(Cmd+a)など、VSCode以外のさまざまなソフトで共通しているショートカットもあります。そうした体に染み付いたクセと戦うのは、Vimの良さを感じてからでも遅くありません。

また、Vimのコマンド内でも同じ結果になる操作が複数ありますが、最も使いやすいものだけ抽出し、あとはバッサリ削っています。

VSCodeのショートカットをそのまま使うもの

「VSCodeのショートカットのほうが便利な場合は、そちら使う」ことにします。

特に、以下のようなCmdキーとのコンビネーション一回で終わるものはそちらを使います。

  • 検索 (Cmd + f)
  • 保存 (Cmd + s)
  • 元に戻す (Cmd + z)
  • 全て選択 (Cmd + a)
  • 他のアプリから貼り付ける (Cmd + v)

Vimのコマンドを使うもの

以下の操作については、絶対にVimのコマンドを使います。

  • 移動
  • 切り取り
  • 削除
  • コピー
  • 貼り付け

これらのコマンドについて、以下ステップのステップで体得していきます。

段階別 コマンド習熟ステップ

【レベル0】 モード切り替えと移動

レベル0では、ノーマルモードに常にいること、そしてマウスを使わずに必要な場所に移動する方法を体得します。

他のモードからノーマルモードに戻る

Vimにはいくつかのモードがありますが、主に使用するのは以下の4つです。

モード状態
ノーマルモードカーソル移動やテキストの削除、コピー、ペーストなどの簡単な指示を行う。
ビジュアルモードテキストを選択するだけのモード。
挿入モード実際にテキストを入力するモード。
コマンドラインモードファイルを開いたり、検索・置換などの様々な指示を行う。

このうち、移動やコピーなど、編集動作を行う状態がノーマルモードです。
Vimの操作において最もよく行うのが、 他のモードからノーマルモードに戻る操作です。

何らかの操作をしたら、とにかくすぐ ESCを押して下さい
とにもかくにも、なんかよく分からない状態になったらとにかくESCを押せばノーマルモードに戻れます。

操作が終わったら ESC
いやいや、操作してなくてもとりあえず ESC

このぐらいの感覚です。

一文字移動する

hjkl = ←↓↑→

カーソル移動です。

動かしたい方向を意識しなくても、指が動くようになるまで ↑↑↓↓←→←→BA、と練習しましょう。
hlは左右なので直感的ですが、jkのどちらが↑かは少し慣れが必要です。

画面内の特定の文字に移動する(vim-easymotion)

spacespaces移動したい文字記号

今移動したい場所に直感的かつ簡単に移動できます。

https___qiita-image-store.s3.amazonaws.com_0_319527_07a069dc-60c2-fae3-b769-a5025a6189b9.gif
↑GIFの説明はこちら

【レベル1】 文字を入力・消去

レベル0の内容が習得できれば、編集したい位置へキーボードだけで移動することができたでしょう。
あとはその場所で入力・削除できればとりあえずコーディングができます。

カーソルの位置に入力

i入力esc

カーソルの位置で入力を開始します。

ここで挿入モードに遷移しているのですが、意識する必要はありません。
入力が終わったらESCを押します。

行末に移動して文字を入力する

Shift + a入力esc

行末のカンマ挿入したりするのにめちゃくちゃ使うので覚えましょう。
入力が終わったらESCを押します。

一文字削除

x

カーソルの文字を削除します。

削除はできないと困るのでここで書きますが、DelBack Spaceで削除してもほとんど問題ないです。
実際のコードの編集上、一文字だけ消すということがあまりないのと、レベル2以降で紹介するコマンドのほうが便利なのでほとんど使わないからです。

【レベル2】 文字列を移動orコピーする

レベル1までで好きな場所に入力できるようになりましたが、ここまででは楽にはなっていません。
Vimの良いところはマウスやカーソルキーで範囲選択しなくて良いところなので、それを活かすコマンドを習得していきます。

単語を コピー/切り取り して貼り付け

操作コマンド
コピーyiw移動p
切り取りdiw移動p

単語までレベル0の方法で颯爽と移動してからyiwでコピー。
また移動してpを押せば作業完了。

ただ、pの貼り付け位置は最初違和感があると思います。
慣れの問題ですが、私は未だに意図と違う場所に貼り付けてしまったりします。

行単位に切り取って移動

操作コマンド
1行dd移動p
複数行shitf + vjとkで上下移動x移動p

複数行は5ddとかでもできるのですが、shitt-vのほうがどこまで切り取られるか直感的なのでこっちを使っています。

範囲の中を消してから入力

操作コマンド
単語ciw入力esc
( )の中ci(入力esc
" "の中ci"入力esc
タグの中cit入力esc

引数変えるとか、タグの中の文字丸ごと変える等の、よくやる操作です。

【レベル3】 任意の位置までの操作

今いる位置から特定の位置まで削除してから入力

ct消したい文字の一つ右の文字入力ESC
行内で特定の位置まで消して編集。
汎用性が高いので仕様頻度が多い。

【レベル4】 まれに使う便利コマンド

囲んでいる文字を変更

cs今囲んでいる文字囲みたい文字

cs'`とやれば ' 'で囲んでいる文字列を ` `で囲み直せる
JSだとたまに使う。

一文字入れ替え

r入れ変える文字

1文字だけtypoしたときなどにたまに使う。

最後に

レベル4までやれば、大抵の操作をVimコマンドだけでできるようになるはずです。

Vimコマンドだけでいろいろできるようになってくると、もっと便利なコマンドはないのかと探求したくなったり、Vimエディタ自体への興味も湧いてくるかもしれません。

コーディングをもっと楽しくして、沢山アウトプットしていきましょう〜。

それでは!

補記

あとでGIF動画追記します〜〜〜!!
(間に合いませんでした)


う し た ぷ に き あ く ん 笑 . v i m 

$
0
0

はじめに

この記事では、私が作成した(ネタ)プラグイン「ushitapunikiakun.vim」の紹介をします。

Q. 「う し た ぷ に き あ く ん 笑 っ て な ん で す か 笑 ? 」
A. 「知 り ま せ ん 笑 」

正直よくわかっていません。(は?) 競技プログラミング界隈でいつの間にか流行っていました。
詳しくはここを見てください。

どんなプラグイン?

皆さんは、以下のツイートのように文字列に1文字ずつ空白を入れた文章を作ったことはありますか?

ありますよね?? 特にTwitter廃人の方はあるかと思います。
しかし、全文字間に空白を入れるのは普通に面倒くさいです。特に、文字列内に漢字が入ったりアルファベットが入ったりすると余計に面倒くさいと思います。

このプラグインを使うと、Vimに書かれている文字列の間に全角空白を挟み込むことを容易にします。

プラグイン紹介

使用例

Ushitapunikiakun

:Ushitapunikiakunで、現在の行に全角空白を挿入します。

うしたぷにきあくん笑

↓ (:Ushitapunikiakun)

う し た ぷ に き あ く ん 笑

ちなみに現在の行が空だった場合、う し た ぷ に き あ く ん 笑が挿入されます笑。
この文字列は、設定することができます。

UshitapunikiakunAll

先のコマンドが現在の行だけだったのに対し、このコマンドはVimの文字すべてに空白を挿入します。

設定

挟み込む文字はデフォルトでは全角空白ですが、変更することもできます。変更する場合は.vimrcに以下のように記述します。

letg:ushitapunikiakun#insert_str ='🐮'

このように設定すると、Ushitapunikiakunコマンドの結果は以下のようになります。

う🐮し🐮た🐮ぷ🐮に🐮き🐮あ🐮く🐮ん🐮笑🐮

また、文字列が空だった場合に入力する文字は、ushitapunikiakun#empty_strの値で設定できます。

便利な利用例

藤原竜也っぽいセリフを生成する

letg:ushitapunikiakun#insert_str ='"'

とすると、藤原竜也っぽいセリフを生成できます。(お好みで'" 'などを設定すると良いです。)

demo

huziwaranikiakun..gif

firenvimと組み合わせる

https://github.com/glacambre/firenvim
こちらのfirenvimというプラグインを用いると、ブラウザのテキストボックスに自分のNeovimを展開することができます。
このプラグインを合わせると、とても簡単にうしたぷにきあくん構文をツイートすることができます。
これはTweetDeckでの利用イメージです。

demo

「う し た ぷ に き あ く ん 笑」や任意の文字列のうしたぷにきあくん笑構文をTweetdeck内で素早く作成しています。
 
tweetdeck.gif

Firenvimについては、いつか別記事で便利な設定例なども紹介したいなと思っています。
思っていましたが、Vim advent calendar 201914日目の記事にてすでに良い記事が公開されていました!

(ちなみにこの記事も、Neovim in Qiitaによって書いています)

実装について

とくに興味がなければ、最後にまでとんでください。

結論からいうとこのプラグインは

s/\(.\)/\=submatch(1).g:ushitapunikiakun#insert_char/g

というシンプルな文字列置換をしているだけにすぎません。ただ、この実装に行き着くまで時間がかかってしまいました。
この章ではVimscript初心者が、この実装に行き着いた経緯を書こうと思っています。

for文による実装

はじめ、このプラグインは「2重for文で行、文字を順に見て、g:insert_charを使って空白入り文字列を作り直す」という実装を考えていました。
具体的には、

letl:source_code_list = getline(0,'$')fors:lnumin range(len(l:source_code_list))letl:newline =''fors:cnumin range(strlen(l:source_code_list[s:lnum]))letl:newline =l:newline .l:source_code_list[s:lnum][s:cnum].g:insert_charendforcall setline(s:lnum+1,l:newline)endfor

という実装をしていました。
ちなみに、このコードを書いているときはスコープや名前空間の重要さなどをよくわからずに変数名を定義しています…。今もスコープについては理解しきれていないかもです……。
(当初と現在は変数名などが一部異なっています)

しかし、このコードを日本語に適用するとバグが発生することがわかりました。
以下のコードを試してみてください。

let japanese ="あいうえお"foriin range(strlen(japanese))echon japanese[i]endfor

(少なくとも私の環境では)結果はこうなります。

<e3><81><82><e3><81><84><e3><81><86><e3><81><88><e3><81><8a>

(おそらくUTF-8の文字コード?)

つまり、日本語にこの関数を適用しても<e3> <81> <82>...のように、想定していない文字列を生成してしまいます。
この問題を修正するために、実装を変更する必要がありました。

正規表現による実装

しばらく、「どのようにすれば日本語の文字単位でfor文を使えるようにできるか」考えていましたが、次第に「文字列置換なら正規表現で実現できるのでは?」と考えるようになりました。しかし、

%s/\(.\)/\1 /g

このコードなら全角空白を挿入することができますが、変数g:ushitapunikiakun#insert_charによるカスタムができなくなってしまいます。
色々調べたのですが、後方参照と変数の挿入を同時に実現する方法がどうしてもわからず、vim-jpのSlackにて質問をしてみたところ、解決することができました。

最終的な実装

最終的に、\=submatch()関数を使うことで解決しました。
\=は聞いたこともなかったのですが、helpによると「置換文字列が "\=" で始まるとき、それ以降の文字列は式として解釈される。」ようです。(詳しくは:h sub-replace-expression)
式として扱われるので、変数や関数の呼び出しができるようになる、というわけですね。

ということで、最終的に

s/\(.\)/\=submatch(1).g:ushitapunikiakun#insert_char/g

という実装になりました。
(実際にこのプラグインを使用してみて、全文にこの関数を適用したいと思うことがなかったので、現在の行に関数を適用するよう修正されました。)

最後に

質問に答えてくださったvim-jpの皆様、ありがとうございました。
Vim plugin作成経験やVimscript経験などまだまだ浅いので、何か間違っているところやより良い実装、改善案などがありましたら、この記事のコメントやIssues、PRにお願いします。:bow:

nosetestを実行してくれる簡単なvimプラグインを作ってみる

$
0
0

この記事はアラタナアドベントカレンダー2019の16日目の記事です。

ad.png

vim歴半年の新米がvimプラグインを作ってみる記事になります。
変な書き方しちゃってる箇所もあるかと思いますが、ご指摘いただけると嬉しいです。

せっかくなので普段使えるものを作ってみたいということでテストを実行してくれるプラグインを題材にしたいと思います。
筆者はせっかちなのでテストコードを書いたあと下記のように関数ひとつを指定してテストを実行します。

nosetests test_hoge.py:Hogeclass.test_func

これを簡単に実行するプラグインを目指します。

関数名の取得

現在のカーソルより前の位置で最初に検索に引っかかった箇所の関数名を取得します。

function! Get_func_name()
  ?\vdef\stest_[a-z]*
  return split(split(getline('.')," ")[1],"(")[0]endfunction

?\vdef\stest_[a-z]*

  • ?:前方向に検索
  • \v:正規表現を使用
  • \s:空白

def test_で始まる関数名を取得しています。

クラス名の取得

同様にクラス名も取得します。

function! Get_class_name()
  ?\vclass\s[a-zA-Z]*
  return split(split(getline('.')," ")[1],"(")[0]endfunction

テストコマンド作成

function! Create_test_command()let func_name = Get_func_name()let class_name = Get_class_name()let test_command ="nosetests"." ".expand("%:p").":".class_name.".".func_name." -v"return test_command
endfunction

下記の形をむりやり作ってます。

nosetests test_hoge.py:Hogeclass.test_func

テスト実行

テストを実行する関数の記述とコマンドモードで実行できる記述になります。
ExecTest

function! Exec_test()let test_command = Create_test_command()
  echo system(test_command)endfunction

command! ExecTest call Exec_test()

使ってみる

作成したvimscriptファイルを読み込みます

スクリーンショット 2019-12-15 22.58.58.png

ExecTestコマンドが使えるようになるので10行目にカーソルをあわせて使ってみます。

スクリーンショット 2019-12-15 22.57.13.png

test_secondが実行されていますね。カーソルを7行目にあわせて使ってみます。

スクリーンショット 2019-12-15 23.07.01.png

test_firstが実行されました。

まとめ

カーソル下ブロックのテストコードを実行するプラグインを作ってみました。
検索でヒットした箇所に移動する性質を利用したコードになっているのですが、逆に不便なところもあります。
できれば移動せずに実行したいので改善していきたいです。

VisualStudio + VsVim でタブ移動(gt、gT)を別のキーに割り当てる

$
0
0

やりたい設定

Visual Studio + VsVim でタブの移動を

Ctrl+l で 次のタブ(gt)
Ctrl+h で 前のタブ(gT)

で移動したい。

ショートカットキーの優先設定

VsVim と VisualStudio でショートカットキーが被っているので、どちらを優先するか設定する必要がある。
(VsVimインストール直後は全て Visual Studio 優先)

  1. Visual Studio のメニューから [ツール] - [オプション] - [VsVim] - [Keyboard] を開く。
  2. 割り当てたいキーを "Handled by VsVim" に変更して [OK] で閉じる。(今回は Ctrl+L と Ctrl+H) image.png

設定ファイル(_vsvimrc) の作成

_vsvimrc を作成するディレクトリを確認

コマンドプロンプトを起動して、下記のコマンドを実行する。

C:\> echo %userprofile%

実行するとディレクトリパスが表示される(YOUR_NAME部分は環境によって異なる)

C:\>echo %userprofile%
C:\Users\YOUR_NAME ←ここを確認

ファイルの作成

確認したディレクトリ直下に、_vsvimrc を下記の内容で作成する。

_vsvimrc
noremap <C-l> gt
noremap <C-h> gT

Visual Studio が起動している場合は、Visual Studio を再起動する。

以上で設定完了です。
Ctrl+l と Ctrl+h でタブが移動できるようになります。
その他にも VsVim の設定を変更したい場合は、_vsvimrc に追記していけばOK

設定ファイルが読み込まれない場合

  • Visual Studio を再起動してみる
  • _vsvimrc.txt になっている(意味が分からない場合は「windows 拡張子 表示」等で検索)

Vim script を GitHub Actions でテストする

$
0
0

Vim プラグインを作成するにあたって、Vim script のテストをCIツールで実行したいと思いました。

この記事では FizzBuzz プラグインをサンプルに、GitHub Actions でテストを実行する流れを掲載しています。

事前準備

GitHub にリポジトリを作成します。

今回は fizzbuzz.vimというリポジトリ名で作成しています。

FizzBuzz プラグインの追加

「引数として任意の数値を渡すと、FizzBuzz のルールに従い文字列を返す」という関数を定義するプラグインを追加します。

plugin/fizzbuzz.vim
function! fizzbuzz#to_fizzbuzz(number) abort
  lets:divisible_by_3=(a:number % 3==0)lets:divisible_by_5=(a:number % 5==0)ifs:divisible_by_3&& !s:divisible_by_5return'Fizz'elseif!s:divisible_by_3&& s:divisible_by_5return'Buzz'elseifs:divisible_by_3&& s:divisible_by_5return'FizzBuzz'endifreturn''endfunction

themis.vim を使ったテストの追加

Vim script 用テストフレームワークの themis.vimを利用して、テストを追加します。(テーミスやテミスと発音するようです)

FizzBuzz のルールに従った戻り値が返ってくることをテストしています。

test/fizzbuzz.vim
lets:suite= themis#suite('fizzbuzz')lets:assert= themis#helper('assert')function!s:suite.to_fizzbuzz_1()letl:number=1letl:response = fizzbuzz#to_fizzbuzz(l:number)calls:assert.equals(l:response,'')endfunctionfunction!s:suite.to_fizzbuzz_3()letl:number=3letl:response = fizzbuzz#to_fizzbuzz(l:number)calls:assert.equals(l:response,'Fizz')endfunctionfunction!s:suite.to_fizzbuzz_5()letl:number=5letl:response = fizzbuzz#to_fizzbuzz(l:number)calls:assert.equals(l:response,'Buzz')endfunctionfunction!s:suite.to_fizzbuzz_15()letl:number=15letl:response = fizzbuzz#to_fizzbuzz(l:number)calls:assert.equals(l:response,'FizzBuzz')endfunction

ターミナルでのテスト結果はこちら。

$ ~/.ghq/github.com/stackline/fizzbuzz.vim
$ themis
1..4
ok 1 - fizzbuzz to_fizzbuzz_1
ok 2 - fizzbuzz to_fizzbuzz_3
ok 3 - fizzbuzz to_fizzbuzz_5
ok 4 - fizzbuzz to_fizzbuzz_15

# tests 4# passes 4

GitHub Actions にワークフロー追加

Vim script のテスト環境構築と実行を行うワークフローを追加します。

GitHub Actions が提供する Simple workflowをベースに、async.vim の .travis.ymlを参考にしながら作成しました。(ローカルで Dockerfile を docker buildしながら動作確認しつつ、ある程度固まったタイミングで、ワークフローを作成)

.github/workflows/ci.yml
name:Teston:pushjobs:build:runs-on:ubuntu-lateststeps:-name:Initializerun:|sudo apt-get updatesudo apt-get install -y vimsudo apt-get install -y git-name:Clone repositoriesrun:|# Test frameworkgit clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis /tmp/vim-themis# Repository under testgit clone --depth 1 --branch master --single-branch https://github.com/stackline/fizzbuzz.vim /tmp/fizzbuzz.vim-name:Run testsrun:/tmp/vim-themis/bin/themisworking-directory:/tmp/fizzbuzz.vim

ワークフローをリモートリポジトリに push すると、次回から push イベントをトリガーにワークフローが実行されます。

GitHub Actions でテスト実行

例えば README.mdを追加するコミットを git pushします。

その後 GitHub で fizzbuzz.vimリポジトリにアクセスし、Actions タブをクリックすると、実行したワークフローの一覧が表示されます。

ワークフロー名をクリックすると、以下のようなログが閲覧でき、Vim script のテストが実行されていることを確認できます。

image.png

また、ワークフローのステータスを表すバッジも所定の URL で取得できます。

image.png

GitHub 内で CI/CD まで完結できるのは便利そうですね :)

vi[m] like file manager な vifm の紹介と vifmrc 設定例

$
0
0

本記事は Vim Advent Calendar 2019 - Qiitaの 17 日目の記事です。

この記事では vifmについてご紹介します。

capture_vifm_for_advent_calendar_2019.png

vifm とは

vifm とは ncurses ベースで vi[m] ライクな、ターミナル内で操作できるファイラ(ファイルマネージャ)の一つです。おそらく vi[m] (like) file manager の略で vifm なのだと思います。

ncurses は TUI (Text User Interface) を構築する際によく用いられるライブラリで、以前こちらで紹介した Tig など、多くのソフトウェアで使われています。

自分とファイラ

少しだけ自分の話をすると、昔から 2 画面ファイラと呼ばれるものを長年愛用していました。2 画面ファイラとは左右にファイル一覧が表示されるファイルマネージャで、コピーや移動などの操作を左のペインから右のペインに (あるいは右のペインから左のペインに) 向けて実行でき、高速なファイル操作が行えるのが特徴です。

以前 Windows 機をメインにしていた際は 2画面ファイラーKFだいなファイラーなどを愛用していました。

作業環境を Mac に変更してからは、Java で開発されている muCommanderを使用していました。その後メンテナンスが滞ったタイミングで、 GPL の muCommander のコードを fork して開発を継続している trolsoft の trolCommanderを使用していました。

trolCommander は概ね満足いくファイラでしたが 、GUI ソフトウェアなので自分の様に git 操作に Tig を使っていたり、普段からターミナルで作業することが多い人間は少し手間に感じていました。そのため、ターミナル内で実行できる 2 画面ファイラで、かつ操作性や拡張性がよいものを長年探していました。

そして数年前に vifm を使い始めてから、 trolCommander と同等以上に自分のニーズを満たしてくれることを確認できたので移行しました。今では手放せない存在になっています。

以下では、 vifm の初期設定での操作方法と、便利な設定について説明していきます。

ちなみに vim でのファイラは色々と有名なプラグインがあります(※)が、vifm 本体は vim を起動せずにスタンドアロンで起動します。それとは別に、プラグインで vim から呼び出す方法もあります (後述) 。起動は非常に速く、一瞬で立ち上がります。

※ 参考:mattn さんのファイラ記事

vifm のインストール方法

公式ページ (Vifm - Downloads) にバイナリがあります。また各種OSやディストリビューション向けにパッケージも用意されています。

Mac ユーザであれば

$ brew install vifm

で簡単にインストールできます。

基本的な操作方法

ここで紹介する内容はすべて公式マニュアルに書かれているので、詳細については本家ドキュメントをご確認ください。便利な Cheetsheet もあります。

終了方法

定番のコマンドですが、 vim と同じ操作で終了できます。

キー説明
:qvifm を終了する
ZZvifm を終了する
ZQエラーコードで vifm を終了する (後述)

(※ ただし毎回これを打つのは手間なので、自分は qに vifm 終了コマンドを割り当てています (後述))

カーソル移動

キー説明
jカーソルを下に移動
kカーソルを上に移動
hひとつ上のディレクトリに移動
lカーソル配下がディレクトリならそのディレクトリに移動する。ファイルならファイルをエディタで開く (デフォルトは vim )
ggカーソルを最上段に移動
Gカーソルを最下段に移動
[SPACE]反対側のペインに移動
[TAB]反対側のペインに移動
Ctrl-i反対側のペインに移動

その他のキーバインドは マニュアルの Basic Movementを参照してください。

ファイル操作

キー説明
yyファイルを vifm のクリップボードにコピー (yank) する
Yファイルを vifm のクリップボードにコピー (yank) する
Cファイルをクローンする (同じディレクトリに ファイル名(1).拡張子という名前で複製する)
pyank したファイルをコピーする。または ddで削除したファイルをコピーする
Pyank したファイルを移動する (元の場所からは消える)
ddファイルを vifm の trash ディレクトリに入れる (pで貼り付けられる)
DDファイルを完全に削除する
cwファイルをリネームする
cWファイルをリネームする (拡張子を除く)
alyank したファイルの symbolic link を絶対パスで作成する
rlyank したファイルの symbolic link を相対パスで作成する
tカーソル配下のファイル/ディレクトリを選択状態にする

trash ディレクトリについてはマニュアルの Trash directoryをご参照ください。筆者のデフォルトでは ~/.local/share/Trashでした。

カスタマイズ

上記のコマンドを覚えておけば最低限のファイル操作はできると思いますが、やはり手に馴染むようにカスタマイズしてこそのファイラなので、カスタマイズの方法をご紹介します。

設定ファイルのロード順についてはマニュアルの Startupに書かれています。最優先は ~/.vifm/vifmrcファイルですが、インストール直後にはこのファイルは存在しないので ~/.config/vifm/vifmrcファイルが読み込まれていると思います。このファイルは以下のいずれかがインストールされています。

まずはこのディレクトリをコピーしてカスタマイズを始めてみます。

$ cp -a ~/.config/vifm ~/.vifm

表示変更

デフォルトの画面だと情報量が少なすぎるので、だいたい以下のようにしています。それぞれの詳細については マニュアルの :set optionsをご確認ください。

~/.vifm/vifmrc
set timefmt=" %Y/%m/%d %H:%M:%S"
set statusline="  %t  [%T]%= %A %10u:%-7g %15s %20d [%a free]"
set viewcolumns=-45%{name}..,-{ext},10{size},12{perms},21{mtime}
set sizefmt=units:iec,precision:3

また、執筆当時最新の ver 0.10.1 を入れてみたところ、カラースキームが微妙になっていたので修正しています。カラースキームはデフォルトでは colorscheme Defaultが指定されているため ~/.vifm/colors/Default.vifmが読まれます(前述の ~/.config/vifmディレクトリをコピーしている場合)。

カラースキームは color_scheme.cで動的に作られているようですが、自分の場合 OtherWinの設定値が目立ちすぎていたのでコメントアウトしています。

~/.vifm/colors/Default.vifm
" highlight OtherWin cterm=bold,underline,reverse,standout ctermfg=default ctermbg=default

本記事の最初にも貼りましたが、上記を設定した際の筆者の iTerm2 (色調整した Solarized Dark テーマ) での vifm のスクリーンショットはこのような感じです。(右下のカレントパーティションの空き容量 [%a free]の値はうまくとれていないようですが)

capture_vifm_for_advent_calendar_2019.png

ちなみに vifm-colors というサブプロジェクトにも各種カラースキームが置かれています。

これらのカラースキームごとのサンプルは公式サイトに一覧があります。

エディタ/ビューア変更

lでファイルをチラ見するときに毎回 vim が開くと閉じるのが手間なので lessに変えています。

~/.vifm/vifmrc
set vicmd='less -N'

(-N--LINE-NUMBERSのことで行数表示のオプションです)

また、 hキーで lessを抜けられるように、 lesskey.confを以下のように書いて

lesskey.conf
h   quit
$ lesskey -o ~/.lesskey lesskey.conf

を実行することで lesshキーで抜けられるようになります。

コマンド定義

マニュアルの Commandsに書かれているコマンドを(ノーマルモードの)キーにバインドする場合は、 vim の .vimrcと同様に

~/.vifm/vifmrc
nnoremap C :copy

の様に書きます(デフォルトの Cキーを上書きしています)。 :copyは組み込みコマンドで、反対側のペインにコピーを行います。

前述した、 qで vifm を抜けるようにするには

~/.vifm/vifmrc
nnoremap q :quit<cr>

と書きます。(<cr>はコマンド行で確認せずに Enter します)

外部コマンド呼び出し

組み込みコマンド以外をシェル経由で実行するには、 !をつけます (%引数については後述します)

~/.vifm/vifmrc
nnoremap Z :!zip -r %D/%c:r.zip %f

また、コマンドを定義しておいて、内部コマンドの様に読み出すこともできます。

~/.vifm/vifmrc
command! zip -r %D/%c:r.zip %f
nnoremap Z :zip

コマンド引数

例えば unzip コマンドを Uに割り当てたい場合、

~/.vifm/vifmrc
nnoremap U :!unzip %f -d %D

と書くことでコマンド引数を展開することができます。ここで %fはカーソル配下のファイルパス、 %Dは反対側ペインのディレクトリを指します。このあたりの変数の詳細は マニュアルの Command macrosや、設定ファイル ~/.vifm/vifmrcに書かれています。

仮想ディレクトリ

一般にファイラは、 zip などのアーカイブも展開せずに中を開くことができるのが一般的です。vifm で zip ファイルを仮想ディレクトリとして開くには FUSEを利用します。

Mac OS の場合は、Home - FUSE for macOSからダウンロード&インストールするか、 Homebrew Cask が利用可能な場合は以下のコマンドでインストールできます。

$ brew cask install osxfuse

さらに zip ファイルを開くために fuse-zip を入れます。 公式サイトからダウンロード&インストールするか、Mac では Homebrew でインストールできるので、以下のコマンドでインストールしてください。

$ brew install fuse-zip

そして *.zipやその他の対応ファイルタイプに対して fuse-zip を割り当てます。

~/.vifm/vifmrc
filetype *.zip,*.jar,*.war,*.ear FUSE_MOUNT|fuse-zip %SOURCE_FILE %DESTINATION_DIR

と書いてみて気づきましたが、執筆当時最新の vifm v0.10.1 の初期設定ファイルには fuse-zip がある場合は自動で上記設定が有効になるようになってたので、現状では特に設定は不要となっているようです。

その他の FUSE Mount

その他、 sshfscurlftpfsなどの FUSE mount の記述が 初期設定にあります。

sshfs については、

$ brew install sshfs

のようにインストールしたのち、

hoge_server.ssh
username@hoge.example.com:/home/username

.sshと拡張子を持つファイルに sshfsに渡す接続情報を書いておけば、 lキーでそのファイルを開こうとすると透過的に ssh 先のサーバを手元の vifm で開くことができます。ローカルのコンテナの接続情報を書いていても便利だと思います。

vifm 起動ショートカット

ターミナルでは vifm か tig かエディタを開いて生活しているので、コマンド一つで vifm が開けると便利です。

zsh の場合は ~/.zshrcに以下の設定を入れておけば Alt-jで vifm をカレントディレクトリですぐに開けます。

~/.zshrc
bindkey -s'\ej''^a vifm . \n'

(history に残さないように、頭に空白を入れています。これを有効にするには setopt hist_ignore_space.zshrcに記載しておいてください)

起動シェルのカレントディレクトリ変更

vifm を抜けた際に、最後のディレクトリを呼び出したシェルのカレントディレクトリとして欲しいケースが多いと思います。
公式マニュアルにその設定が紹介されています。

以下は ~/.zshrcの例です。(公式マニュアルには .bashrcの設定が載っています)

~/.zshrc
function vicd(){local dst="$(command vifm $1$2--choose-dir -)"if[-z"$dst"];then
        echo'Directory picking cancelled/failed'return 1
    fi
    cd"$dst"}

これで vicdコマンドで実行された vifm が正常終了 (:q or ZZ) の場合は、 vifm の最後のディレクトリがカレントディレクトリに設定されます。

こちらを普段使うため、上記 Alt-jコマンドは vicd に書き換えています。

~/.zshrc
bindkey -s'\ej''^a vicd . \n'

また、 ZQで抜けた場合は起動時のディレクトリのままになります。

ちなみに自分の場合、qQをそれぞれに割り当て直しています。

~/.vifm/vifmrc
nnoremap q :quit<cr>
nnoremap Q :cquit<cr>

その他便利なコマンドのキー割り当て

以下は筆者が設定しているキー割り当ての一部です。これまでに説明していないもののうち、特に設定しておいたほうが便利だと思うものを挙げてみます。(キーバインドはお好みのものに変更してください)

~/.vifm/vifmrc
" ディレクトリを作成する
nnoremap K :mkdir<space>

" カレントファイルを関連付けられたデフォルトのアプリケーションで開く。フォルダの場合は Finder で開く (Mac)
nnoremap X :!open %f<cr>

" 反対側のペインをカレントペインと同期する
nnoremap , :sync!<cr>

" スペースキーを「カレントファイルを選択して、カーソルを1つ下に移動」にする
nnoremap <space> t<down>

(上記以外については筆者の vifmrcを参照してください)

その他

AFP (Mac のファイル共有プロトコル) でマウントしたサーバに対して :moveコマンドによるファイルの移動をすると更新日時が保持されないバグ(仕様?)があったので(現バージョンで解消されているかは未確認ですが)リモートサーバを操作する場合は事前に動作検証をしておくとよいと思います。

Vim 連携

ここまではスタンドアロンの vifm について説明してきましたが、 vim から vifm を呼び出すプラグインも存在しています。

Vundle の場合、 call vundle#begin() ~ call vundle#end()間に以下の指定をして :PluginInstallでインストールされます。

~/.vimrc
Plugin 'vifm/vifm.vim'

プラグインのドキュメントによると以下のコマンドが定義されています。(マニュアルの Pluginにも同様の説明があります)

Commands:

                                               *vifm-:EditVifm*
  :EditVifm   select a file or files to open in the current buffer.
                                               *vifm-:Vifm*
  :Vifm       alias for :EditVifm.
                                               *vifm-:SplitVifm*
  :SplitVifm  split buffer and select a file or files to open.
                                               *vifm-:VsplitVifm*
  :VsplitVifm vertically split buffer and select a file or files to open.
                                               *vifm-:DiffVifm*
  :DiffVifm   select a file or files to compare to the current file with
              :vert diffsplit.
                                               *vifm-:TabVifm*
  :TabVifm    select a file or files to open in tabs.

上記設定例で vicmd変数を lessにして lキーを lessで開くようにしていましたが、 vim plugin から呼び出すと、 lessではなく vim で開かれるようになります。

まとめ

本記事では、 Vim ベースのファイルマネージャ vifm をご紹介しました。皆様のターミナル生活の一助になれば幸いです。

最後までお読みいただきありがとうございました。

Viewing all 5720 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>