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

Vim一年生による、Vimプラグイン作成指南

$
0
0

ad_banner4.gif
このエントリーは、aratana Adventカレンダー20日目のエントリーです。

こんにちは!
Qiita aratana organizationsの投稿タイプにVimをねじ込もうと企んでいる田村です。

前日は、@seiyaanさんの「仮想通貨取引所(bitbank.cc)の公式APIを使って仮想通貨の取引をする方法」というエントリーでした。
仮想通貨と聞いて手を出しづらいイメージがありますが、うまくいけばガッポリいけるんですかね?

今回は、簡単なVimプラグインを作成しながら、プラグイン作成の理解度を深めていきましょう回です。
この記事読めば、Vimプラグインを作成できるようになります。

作るプラグイン

Vimに、現在のソースが、スペースなのかタブなのか判定する変数が無かったような気がするので、
スペースとタブ判定のプラグイン作ろうと思います。(既に何個かあるっぽいですけど)
入門プラグイン作成としては、ちょうどよい感じでしょう。

ちなみに、、、
タブよりスペースを使う方が高年収という謎結果が出ております(参考サイト

私自身、昔はタブ派だったのですが、最近では、スペース派になりました。

Vimプラグイン基礎

Vimプラグインを作成するにあたり、基礎知識を確認していきましょう。
詳細は、:h write-plugin

  • プラグイン名を決める
  • ファイル構造の雛形を作り実装していく
  • プラグイン作成で必要なこと
  • プラグイン作成の注意点まとめ

プラグイン名を決める

プラグイン名は、とても大事なので慎重に決めていきましょう。
プラグインの名は(正確にいうとプラグインのファイル名かな?)、古いWindowsで問題起きないように、
できれば8文字以内が良いらしいです。(なぜ8文字以内?は、こちら
今の時代、8文字以内は守る必要はなさそうですね。
シンプルにプラグインを表すことを、重要とした方が良いと思います。

私の場合、スペースとタブを検知する動作なので、space tabをもじって、vim-spatabと意味分からん感じにします。(スパタブしてる?)
※ 既に同じプラグイン名が無いかググって決めましょう。被ると正常に読み込まれません。

ファイル構造の雛形作る

Vimプラグインを作るにあたり、ファイル構造を確認します。

pluginディレクトリ

まずは、pluginディレクトリを作成します。
このディレクトリは、Vimが立ち上がった時に、読み込まれるファイルです。
基本的にここには、マッピングやコマンド定義ぐらいしか書きません。
つまり、必要最小限のことを記述します。

autoloadディレクトリ

次に、autoloadディレクトリを作成します。
autoloadとは、簡単に説明すると、必要になったら読み込んでくれる環境に優しいやつです。
詳しくはこちらでモテる男になってください。モテる男のVim Script短期集中講座

プラグインファイル構造

上記を考慮したファイル構造は以下のとおりです。

vim-spatab
├── LICENSE
├── README.md
├── autoload
│   └── spatab.vim
└── plugin
    └── spatab.vim

こちらのファイルに、処理を書いていきます。

プラグイン作成で必要なこと

プラグイン作成でこれを守ってねルールがあります。
みんな幸せになる、お決まりみたいなやつです。
必要だと思われることだけ書いていきます。

行継続がある場合

行継続(line-continuation)がある場合、
Vi互換を保つために、cpoptions保護しておきましょう。
つまり、行継続使ってなかったら、cpoptions保護不要ってことですね(ですよね?)。

例:

let s:save_cpo =&cpoptionssetcpoptions&vimnnoremap<Plug>(test)
  \ :call Test<CR>let&cpoptions= s:save_cpo
unlet s:save_cpo

普通、行継続を表す\は、行末尾に書きますが、
なぜ、Vim scriptの行継続を表す\が、行の先頭にあるのでしょうか。
:h line-continuousに書いてある例だと、
:map xx asdf\
バックスラッシュもコマンドの一部として認識してしまうので、
先頭にバックスラッシュってことなんでしょう。

再度読込防止

再度設定ファイルが読み込まれた場合に、無駄な処理やエラー表示されないように、
一回のみ読込されるようにしましょう。

if exists('g:loaded_spatab')finishendifletg:loaded_spatab =1

キーマッピング

利用者になにかしらキーマッピングを提供する場合のお決まりです。

" 例noremap<Plug>(test_da) :<C-u>call testda()

マッピングの仕方は、<Plug>TestDaだったり、<Plug>(test-da)だったりと、
人によって異なりますが、私は、スネークケース派です。

<C-u>は、実行する前に数字など入力されていたときに予期せぬ動作をさせないため。
例えば、

nnoremap<Space>ec :echo 'test dayo!'<CR>

を設定したあと、1<Space>ecとか、コマンド入力前に、数字を入れてしまうと、

E481: 範囲指定は許可されていませんと表示されてしまいます。
これを防ぐために、先程の<C-u>を追加します。

nnoremap<Space>ec :<C-u>echo 'test dayo!'<CR>

とすることで、範囲指定部分が取り除かれ、問題なく動作します。

注意点まとめ

  • プラグイン名に気をつける(被らないように。シンプルに。)
  • Vi互換性のことを考える
  • 再度設定ファイルが読み込まれることを想定して作る
  • マッピングの際のお決まりを守る

以上を守れば、Vimプラグイン作成なんて怖くないです。

spatabプラグイン作成

これからプラグインを作成していきます。

軽く設計

このプラグインにどのような機能をもたせるか考えます。

  • 数行取得して先頭がスペースかタブかで判定(簡単に行きましょう)
  • スペースだったらspace、タブならtabも文字列を返してくれる
  • それぞれの判定で実行されるフックポイント的なのを用意しておく

以上の実装だけで十分そうですね。
では、作成していきましょう。

必要そうな変数宣言

先に必要そうな、変数たちを宣言しておきます。

vim-spatab/autoload/spatab.vim
" 何行まで判定に利用するかlet s:max_line_num = get(g:,'spatab_max_line_num',300)" スペース判定の場合に返す文字列let s:space_name = get(g:,'spatab_space_name','space')" タブ判定の場合に返す文字列let s:tab_name = get(g:,'spatab_tab_name','tab')" スペース判定の場合に実行される関数名let s:space_func_name = get(g:,'spatab_space_func_name','')" タブ判定の場合に実行される関数名let s:tab_func_name = get(g:,'spatab_tab_func_name','')" 判定時に、自動的にexpandtabを切り替えるかのフラグlet s:auto_expandtab  = get(g:,'spatab_auto_expandtab',1)

get関数

getというのは、

  • 第一引数に、辞書を。(この場合、グローバル変数のリストを指定)
  • 第二引数に、キーを。
  • 第三引数に、デフォルト値を。
  • 返り値、見つからなかったらデフォルト値を、見つかったらその値を。

つまり、指定の変数がなかったら、デフォルト値が返ってくるが、
指定の変数があったらその値を取得する便利なやつ。

スペースとタブを判定

現在開いているファイルが、スペースかタブか判定して、
それぞれの文字列を返す関数を作ります。

vim-spatab/autoload/spatab.vim
function! spatab#GetDetectName() abortlet detect_name = get(b:,'spatab_detect_name','')  " 既にチェック済みか確認。済みなら飛ばす。if detect_name ==# ''    " 現在ファイルの指定行数分の文字列を配列として取得let buflines  = getbufline(bufname('%'),1, s:max_line_num)    " 各行の先頭がタブかどうか調べ、個数を調べるlet len_tab   = len( filter(copy(buflines),"v:val =~# '^\\t'"))    " 各行の先頭がスペースかどうか調べ、個数を調べるlet len_space = len( filter(copy(buflines),"v:val =~# '^ '"))    " スペース数とタブ数を比較して、適切な文字列代入if len_space > len_tab      " spacelet detect_name = s:space_nameelseif len_space < len_tab      " tablet detect_name = s:tab_nameendif    " 結果をバッファ変数に保持し、チャック済みとするletb:spatab_detect_name = detect_nameendif  " 結果を返すreturn detect_nameendfunction

#の意味

#区切りは、なんやってなりますが、
例えば、autoload/spatab/get.vimに記述する場合は、
spatab#get#GetDetectNameという風に記述します。
つまり、階層区切りってことですね。

判定した後、それぞれの処理を実行

タブだった場合の処理、スペースだった場合の処理が、
必要になる人がいるかもしれないので、作成。

vim-spatab/autoload/spatab.vim
function! spatab#Execute() abortletres= spatab#GetDetectName()ifres==# s:space_name    " スペース判定の場合if s:auto_expandtab |setlocalexpandtab|endifif s:space_func_name !=# ''|call {s:space_func_name}()|endifelseifres==# s:tab_name    " タブ判定の場合if s:auto_expandtab |setlocalnoexpandtab|endifif s:tab_func_name !=# ''|call {s:tab_func_name}()|endifendifendfunction

pluginの設定

pluginディレクトリに記述していきます。

vim-spatab/plugin/spatab.vim
if exists('g:loaded_spatab')finishendifletg:loaded_spatab =1

command!-nargs=0 STDetect call spatab#Execute()
command!-nargs=0 STEcho   echo spatab#GetDetectName()noremap<unique><Plug>(spatab_echo_detect_name) :<C-u>echo spatab#GetDetectName()<CR>

利用しましょ!

dein.vimなどのプラグインマネージャーを利用して、利用できるようにしましょう。
まずは、ローカルに作成したプラグインディレクトリを読み込みましょう。

dein.toml
[[plugins]]
repo = '~/vim-spatab'

動作問題なければ、GithubへプッシュしてVimプラグイン公開完了です!!
vim-spatab

このQiita記事では、Vimプラグイン作成指南用に、シンプル?に書いているので、
Githubソースとは差異があります。

実際に利用してみます。

.vimrc
  augroup spatab
    autocmd!
    autocmd BufWinEnter * STDetect
  augroup ENDletg:spatab_space_func_name ='SpaceMode'function! SpaceMode()echomsg'space mode!!'endfunction

ファイルがウィンドウに表示された後、STDetectが発動して、スペースだった場合、
space mode!!と表示されます。
他には、lightlineなどで、spatab#GetDetectNameの関数を利用したりして、
ステータスバーに表示させることができるようになりました。

space.png

まとめ

これで、どのようにプラグイン作成するか分かったと思います。
docやtestのことも、書きたいです。
他にも、スペースとタブ判定時に実行される、いい感じにフックさせる方法とかないですかね?

明日(21日目)のaratana Advent Calendar 2017のエントリーは、
色々テクってる@mokamoto12さんのエントリーです!お楽しみに!


windowsでの、dein.vimからpackageへの移行手順

$
0
0

概要

Vim Advent Calendar 2017 の20日目の記事を見て、移行してみました。

環境

  • windows10
  • GVIM 8.0.596

使用しているリポジトリの取得

deinでは、~/.cache/dein/repoににクローンしたGitがあるので、そこから一覧を作成します。

cd ~\.cache\dein\repos\github.comdir /b/s/a .git > a.txtfor/f%i in (a.txt) do git --git-dir=%i remote -v >> repo.txt

後はrepo.txtgit clone {repo}できるように修正し、clone.batを作成します。

git clone https://github.com/cespare/vim-toml.git
git clone https://github.com/vim-scripts/Align.git
git clone https://github.com/Shougo/denite.nvim.git
git clone https://github.com/mattn/emmet-vim.git
git clone https://github.com/lambdalisue/gina.vim.git
git clone https://github.com/cocopon/iceberg.vim.git
git clone https://github.com/Shougo/neomru.vim.git
git clone https://github.com/Shougo/neosnippet-snippets.git
git clone https://github.com/Shougo/neosnippet.vim.git
git clone https://github.com/fuenor/qfixgrep.git
git clone https://github.com/cocopon/vaffle.vim.git
git clone https://github.com/tpope/vim-fugitive.git
git clone https://github.com/nathanaelkane/vim-indent-guides.git
git clone https://github.com/thinca/vim-qfreplace.git
git clone https://github.com/thinca/vim-quickrun.git
git clone https://github.com/cespare/vim-toml.git

リポジトリのClone

windowsでは、vimfilespackpathになります。変更する場合は、パスを追加します。

set packpath+=~/.cache/plugin/vimwork2.vim/vimfiles

vimfiles/pack/plugin/startに、作成したclone.batを配置し実行します。

設定ファイルのコピー

dein.vimでは、tomlで作成していましたのでそのまま流用します。

  1. tomlからコビーし、plugin.vimを作成する。
  2. hook_add以外の部分をコメントアウトする。

設定ファイルの読み込み

packageは、vimrcの後に設定されるので遅延させないとエラーが発生します。denite#custom#varでエラーが出て気が付きました。

autocmd VimEnter * source ~/.cache/plugin/vimwork2.vim/plugin.vim

更新処理

git pullするバッチを作成します。vimfiles/pack/plugin/startに、pull.batを配置して実行します。せっかくなので、forを使った方法を書いておきます。

for /d %%i in(*)do git --git-dir=%%i\.git pull

参考

http://tyru.hatenablog.com/entry/2017/12/20/035142
https://qiita.com/thinca/items/cdc0169e3bcc5a55a5ba
http://h-miyako.hatenablog.com/entry/2016/02/29/211534

vim-Tips集

$
0
0

目次

  1. 編集中のファイルの名前を確認する
  2. 文字列を置換する

(随時追加予定)

1.編集中のファイルの名前を確認する

編集中のファイルの名前を確認するには、<Ctrl>+gを押します。
それだけです。

2.文字列を置換する

コマンドモードで:%s/<置換対象文字列>/<置換後文字列>

ファイル中の全ての対象文字列を置換するには、コマンドの最後に/gをつけます。
:%s/<置換対象文字列>/<置換後文字列>/g

VimでC++のコードリーディング

$
0
0

この記事は 初心者C++er Advent Calendar 2017、20日目の記事です。

VimでC++のコードリーディング

私はC++の開発にVimを使用しています。
IDEにはさすがに負けるかもしれませんが、Vimでも結構快適にコードを読むことができます。

以下にVimを使用してC++のコードリーディングを行う際のTipsについて記載していきたいと思いますー。

環境

Windows 7

VIM - Vi IMproved 8.0 (2016 Sep 12, compiled May 2 2017 12:56:41)
MS-Windows 64 ビット GUI 版
適用済パッチ: 1-596

デフォルトで使用できるキーマップ

多用するのは以下です。

map説明
[#カーソルが#if-#endif内ならば#if or #elseにジャンプ
]#カーソルが#if-#endif内ならば#else of #endifにジャンプ
gd変数の定義位置にジャンプ(大抵うまくジャンプできるらしい)
gD変数(global)の定義位置にジャンプ(大抵うまくジャンプできるらしい)
[[一桁目が{の行(大抵関数の開始位置(?))にジャンプ
]]一桁目が}の行(大抵関数の終了位置(?))にジャンプ
[* or [/C コメントの始まり(/*)に移動します。
]* or ]/C コメントの終わり(*/)に移動します。
gfカーソル下のファイルを開く(環境によってpathの設定が必要です)
<C-^> or <C-6>直前に開いたファイルを開く(厳密には違います。詳細は:h CTRL-6)

このあたりのマップは実はC++用ではなくC言語用のマップかもしれません。
ただ、C++でも問題なく使用できます。

定義位置ジャンプ、参照元ジャンプ

ctagscscopeを使用します
Windowsの場合にctagsはここから、cscopeはここからバイナリをダウンロードできます。
ダウンロード後はパスが通っている場所に配置すればよいだけ。
あとは以下のような設定をvimrc内に記載して、少し便利にします。
(一部vim-submodeというプラグインを使用して、<C-t>と逆方向への移動を楽にしてます。)

" cscope show/killをマッピングnnoremap<Leader>zs :<C-u>cscope show<CR>nnoremap<Leader>zk :<C-u>cscope kill -1<CR>" :cscope find c <関数名> " 指定した関数を呼び出している関数を検索" :cscope find f <ファイル名> " ファイルを検索" :cscope find s <Cのシンボル> " シンボルを検索" 最後に指定する文字を大文字にするとクリップボード内の文字列を使用して:cscope findを実行します。" NOTE: @+ についてはclipboardの設定により、適宜変更してくださいnnoremap<Leader>zfc :<C-u>cscope find c<C-r>=expand('<cword>')<CR><CR>nnoremap<Leader>zfC :<C-u>cscope find c<C-r>=@+<CR><CR>nnoremap<Leader>zfs :<C-u>cscope find s <C-r>=expand('<cword>')<CR><CR>nnoremap<Leader>zfS :<C-u>cscope find s <C-r>=@+<CR><CR>nnoremap<Leader>zff :<C-u>cscope find f<C-r>=expand('<cfile>')<CR><CR>nnoremap<Leader>zfF :<C-u>cscope find f<C-r>=@+<CR><CR>" 定義位置へのジャンプ時に複数候補表示" クリップボード内の文字列使って:tjumpnnoremap<C-]>g<C-]>nnoremapg<C-]> :<C-u>tjump<C-r>=@+<CR><CR>" <C-t>と逆方向への移動をg<C-t>tttt..とできるよう設定" NOTE: <C-t>は定義への移動前にいた場所にジャンプ。" NOTE: vimデフォルトだと<C-t>の逆方向への移動用マップはない(<C-o>で逆移動っぽい動作はするが、少し違う)ので、定義call submode#enter_with('tag','n','','g<C-t>',':<C-u>tag<CR>')call submode#map('tag','n','','t',':<C-u>tag<CR>')

私の場合にはSVNの各ブランチのルートディレクトリ(.svn or .gitディレクトリがある場所)でctags, cscopeを実行したかったので、
以下のような設定も追加しています。

" 特定のファイルを開いた場合にはカレントディレクトリをルートディレクトリに変更function! s:root_dir() abortlet search_dir_names = ['.svn','.git']for dir_name in search_dir_nameslet ret_dir = finddir(dir_name, expand('%:p:h') . ';')if ret_dir !=''return substitute(fnamemodify(ret_dir,':p:h'), dir_name . '$','','g')endifendforreturn''endfunction
augroup cd_project_root
  autocmd!
  autocmd BufEnter *.cpp,*.h,*.c,silent execute 'lcd' s:root_dir()
augroup END" do ctagsfunction! s:do_ctags() abortif isdirectory('.svn')|| isdirectory('.git')if input('now: ' . getcwd() . "\nrun ctags? (y)es or (n)o : ")=~'^y$\|^yes$'silent!start ctags -Rendifelse
    echohl ErrorMsg | echo 'check current dir!'| echohl noneendifendfunction" cscope build/addfunction! s:cscope_build() abortif isdirectory('.svn')|| isdirectory('.git')if input('now: ' . getcwd() . "\nrun cscope -Rb? (y)es or (n)o : ")=~'^y$\|^yes$'silent!startcscope-Rbendifelse
    echohl ErrorMsg | echo 'check current dir!'| echohl noneendifendfunctionfunction! s:cscope_add() abortif(isdirectory('.svn')|| isdirectory('.git'))&& filereadable('cscope.out')cscope add cscope.out
    echo "cscope add cscope.out!"else
    echohl ErrorMsg | echo 'check current dir!'| echohl noneendifendfunction" ctags, cscope build/add用のマップ
nmap <Leader>ct :<C-u>call<SID>do_ctags()<CR>
nmap <Leader>zb :<C-u>call<SID>cscope_build()<CR>
nmap <Leader>za :<C-u>call<SID>cscope_add()<CR>

cscopeについて

記事を書いていく中で知ったのですが、cscopeはC言語用のパーサとして作られているようですね。。
c++でも大抵動くらしいですが、以下のような記載もあり油断は禁物らしいです。

The fuzzy parser supports C, but is flexible enough to be useful for C++ and Java, and for use as a generalized 'grep database'

現状はrtagsというのが流行っているそうですね。
どなたかWindowsでrtagsを使う方法をまとめてください(切実)

まとめ

いかがだったでしょうか?
Vimをつかえば設定しなくとも快適にコードを読めますし、設定すれば更に快適にコードを読むことができます!
他のIDEの使い方がわからないだけとは言えない

また、ここでは紹介しませんが、Vimのプラグインであるunite.vimのmru, bookmark, file機能をつかえば
ファイルを開くまでの時間を短縮できますし、unite-outlineを使用すれば
ファイル内の定義の一覧を常に表示でき、VimをIDEっぽくすることもできます。

皆様もいろいろ試してみて、Vimで快適なコードリーディングを行ってみましょー!
Happy C++ Life!

割と突き詰めてやったvim->vscode移行

$
0
0

導入、動機

今まではvimをメンテナンスして開発してきました。
vscodeの話をされてもそんなのvimmerには関係ないと思っていました。
まぁそれでもこれだけvscodeが盛り上がっているのに食わず嫌いはよくないと思い使って見たところ、、、

VSCODE最高!

って感じになりました。

vimのkeybindは?どこまで移行できる?

あとは割と重要なことなのですがvimのkeybindをどこまで反映できるかというところが重要です。
今までruby mineだったり、atomも使って見たことはあるのですが
納得のいくほどvimのkeyを移行することができなかったので
結局vimを使うことになってました。がしかし、vscodeはかなり痒いところに手が届く気がします。

installするvim拡張

vscodevim

vimへ移行する前にこれだけはやっておきたいvscodeの設定

{
    //fontsizeを小さく
    "editor.fontSize":9,
    "terminal.integrated.fontSize": 9,

    //wrap
    "editor.wordWrap": "on",
    "files.trimTrailingWhitespace": true,

    //ミニマップをfalse
    "editor.minimap.enabled": false,

    //bookmarkをsidebarに表示する
    "bookmarks.treeview.visible": true,

    //twigとvueでも有効にします
    "emmet.includeLanguages": {"twig": "html", "vue-html": "html"},

}

vscodevimの設定

{
    //システムのclipboardにコピー
    "vim.useSystemClipboard":true,

    //検索に:を入れる
    "vim.cmdLineInitialColon": true,

    "vim.hlsearch": true,

    //言わずもがなeasymotion
    "vim.easymotion": true,

    //カーソル常にあるワードを"*"で検索
    "vim.visualstar": true,

    //諸々のctrlキーを使った操作が有効になる
    "vim.useCtrlKeys": true,
}

vim拡張でやらない設定

    "vim.otherModesKeyBindings":

これで設定するとvscodeの中でうまく動かないときがある。
例えば下記のことをやろうとする

vscodeのなかのshellをトグルさせて表示させたい場合など
例えばvimであれば

nnoremap <Leader>t   :ToggleTerminal<CR>

これでshellをトグルさせることができる。
(*誰かの作ったライブラリか関数でToggleTerimnalを作っていたら)

vscodeの場合shellに一度入ってしまうと
以下のようにshellにキーバインドを取られないような設定を書かなければいけません。

 "terminal.integrated.commandsToSkipShell": [
        "editor.action.toggleTabFocusMode",
        "workbench.action.debug.continue",
        "workbench.action.debug.pause",
        "workbench.action.debug.restart",
        "workbench.action.debug.run",
        "workbench.action.debug.start",
        "workbench.action.debug.stop",
        "workbench.action.focusActiveEditorGroup",
        "workbench.action.focusFirstEditorGroup",
        "workbench.action.focusSecondEditorGroup",
        "workbench.action.focusThirdEditorGroup",
        "workbench.action.navigateDown",
        "workbench.action.navigateLeft",
        "workbench.action.navigateRight",
        "workbench.action.navigateUp",
        "workbench.action.openNextRecentlyUsedEditorInGroup",
        "workbench.action.openPreviousRecentlyUsedEditorInGroup",
        "workbench.action.quickOpen",
        "workbench.action.quickOpenPreviousEditor",
        "workbench.action.quickOpenView",
        "workbench.action.showCommands",
        "workbench.action.tasks.build",
        "workbench.action.tasks.restartTask",
        "workbench.action.tasks.runTask",
        "workbench.action.tasks.showLog",
        "workbench.action.tasks.showTasks",
        "workbench.action.tasks.terminate",
        "workbench.action.tasks.test",
        "workbench.action.terminal.clear",
        "workbench.action.terminal.copySelection",
        "workbench.action.terminal.deleteWordLeft",
        "workbench.action.terminal.deleteWordRight",
        "workbench.action.terminal.findWidget.history.showNext",
        "workbench.action.terminal.findWidget.history.showPrevious",
        "workbench.action.terminal.focus",
        "workbench.action.terminal.focusAtIndex1",
        "workbench.action.terminal.focusAtIndex2",
        "workbench.action.terminal.focusAtIndex3",
        "workbench.action.terminal.focusAtIndex4",
        "workbench.action.terminal.focusAtIndex5",
        "workbench.action.terminal.focusAtIndex6",
        "workbench.action.terminal.focusAtIndex7",
        "workbench.action.terminal.focusAtIndex8",
        "workbench.action.terminal.focusAtIndex9",
        "workbench.action.terminal.focusFindWidget",
        "workbench.action.terminal.focusNext",
        "workbench.action.terminal.focusPrevious",
        "workbench.action.terminal.hideFindWidget",
        "workbench.action.terminal.kill",
        "workbench.action.terminal.new",
        "workbench.action.terminal.paste",
        "workbench.action.terminal.runActiveFile",
        "workbench.action.terminal.runSelectedText",
        "workbench.action.terminal.scrollDown",
        "workbench.action.terminal.scrollDownPage",
        "workbench.action.terminal.scrollToBottom",
        "workbench.action.terminal.scrollToTop",
        "workbench.action.terminal.scrollUp",
        "workbench.action.terminal.scrollUpPage",
        "workbench.action.terminal.selectAll",
        "workbench.action.terminal.toggleTerminal",
        "workbench.action.togglePanel"
    ],

例えばvscodeのユーザー設定に

        { "before": ["leader", "t"],
            "after": [],
            "commands": [
                {
                    "command": "workbench.action.terminal.toggleTerminal",
                    "args": []
                }
            ]
        },

と書いたならシェルのトグルができそうな気がしますがこれだとうまく動きません。
おそらくはvimのコマンドでラップされているためだと思います。

    "vim.otherModesKeyBindings":

現状、僕はkeymap.jsonに直接書いて対応しています。良い方法があったら教えていただけるとありがたいです。

vimのkeymapをどこまで持ってこれるか

keymapを持ってくる前にprefixを決めます。
僕の中では

ctrl + u //検索系もしくは開発系のコマンドのprefixです
ctrl + o //割とメタっぽい動作をしますコマンドパレットだったりdebugの実行だったり
leader // "\" にマッピングして使用してwindow操作系が多いです。

妥協したところ、まだ完成していないところがありますが
上記を踏まえた上でこんな感じになっています。

機能vimvscode
プロジェクトルートからファイル検索ctrl+u ctrl+uctrl+u ctrl+u
検索したファイルの移動(下)ctrl+nctrl+n
検索したファイルの移動(上)ctrl+pctrl+p
実装している箇所に移動するctrl+u ctrl+ictrl+u ctrl+i
宣言している箇所に移動するctrl+u ctrl+dctrl+u ctrl+d
プロジェクトからgrep検索ctrl+u ctrl+gctrl+u ctrl+g
grep検索したファイルの移動(下)ctrl+nctrl+n
grep検索したファイルの移動(上)ctrl+pctrl+p
buffer(editor)間の移動(右) (vscodeだとeditor group関係なく移動します)ctrl+w lctrl+w ctrl+l
buffer(editor)間の移動(左) (vscodeだとeditor group関係なく移動します)ctrl+w hctrl+w ctrl+h
エクスプローラーのviewLetへの移動ctrl+w h
insertモードへ入っているときにカーソルを右へ移動ctrl+lctrl+l
insertモードへ入っているときにカーソルを左へ移動ctrl+hctrl+h
ソースtreeのトグル\ v\ v
shellのトグル\ t\ t
コマンドラインパレットの表示ctrl+o ctrl+o
git addg ag a
git statusg s t
git commitg c og c
ファイルの1行目に移動g gg g
viewを洗濯して移動ctrl+qctrl+q

あとは実際に僕の設定を載せるのですがたぶんケース漏れがあって不具合があると思います。参考までにどうぞ。
特にvscodevimを使用されている方だと

//vimのmodeを取得するために
vim.mode == 'SearchInProgressMode'
vim.mode == 'Normal'
//もしくは否定形
vim.mode != 'SearchInProgressMode'
vim.mode != 'Normal'

が以外と重宝されると思います。

    {
        "key": "ctrl+u ctrl+i",
        "command": "editor.action.goToImplementation",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+u ctrl+d",
        "command": "editor.action.goToDeclaration",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+u ctrl+g",
        "command": "workbench.action.findInFiles",
        "when": "!searchInputBoxFocus"
    },
    {
        "key": "ctrl+n",
        "command": "workbench.action.interactivePlayground.arrowDown",
        "when": "interactivePlaygroundFocus && !editorTextFocus"
    },
    {
        "key": "ctrl+w ctrl+h",
        "command": "workbench.action.focusPreviousGroup",
        "when": "editorFocus"
    },
    //エディターからサイドバーへの移動
    {
        "key": "ctrl+w h",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+w ctrl+l",
        "command": "workbench.action.navigateEditorGroups",
        "when": "!editorFocus"
    },
    {
        "key": "ctrl+w ctrl+l",
        "command": "workbench.action.focusFirstEditorGroup",
        "when": "!editorFocus"
    },
    {
        "key": "ctrl+w ctrl+l",
        "command": "workbench.action.nextEditor",
        "when": "editorFocus && vim.mode == 'Normal'"
    },
    //エディターfile検索以下のコマンドはfile mruと同等の機能が表示される
    {
        "key": "ctrl+u ctrl+u",
        "command": "workbench.action.quickOpen"
    },
    //エディターのテキストにフォーカスしている時のコマンドinsert modeでctrl + lを押すとカーソルが移動
    {
        "key": "ctrl+l",
        "command": "cursorRight",
        "when": "editorTextFocus && !editorReadOnly"
    },

    //候補系のkeybinding
    {
        "key": "ctrl+k",
        "command": "acceptSelectedSuggestion"
    },
    {
        "key": "ctrl+n",
        "command": "selectNextSuggestion",
        "when": "editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible"
    },
    {
        "key": "ctrl+p",
        "command": "selectPrevSuggestion",
        "when": "editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible"
    },
    {
        "key": "ctrl+n",
        "command": "settings.action.focusSettingsFile",
        "when": "inSettingsSearch"
    },
    {
        "key": "ctrl+n",
        "command": "showNextParameterHint",
        "when": "editorTextFocus && parameterHintsMultipleSignatures && parameterHintsVisible"
    },
    {
        "key": "ctrl+n",
        "command": "keybindings.editor.focusKeybindings",
        "when": "inKeybindings && inKeybindingsSearch"
    },
    {
        "key": "ctrl+n",
        "command": "list.focusDown",
        "when": "listFocus"
    },
    {
        "key": "ctrl+n",
        "command": "search.focus.nextInputBox",
        "when": "inputBoxFocus && searchViewletVisible"
    },
    {
        "key": "ctrl+[",
        "command": "settings.action.clearSearchResults",
        "when": "inSettingsSearch"
    },
    {
        "key": "ctrl+[",
        "command": "keybindings.editor.clearSearchResults",
        "when": "inKeybindings && inKeybindingsSearch"
    },
    {
        "key": "ctrl+[",
        "command": "search.action.cancel",
        "when": "listFocus && searchViewletVisible"
    },
    //スニペットのエクスパンド
    {
        "key": "ctrl+k",
        "command": "insertSnippet",
        "when": "editorTextFocus && hasSnippetCompletions && !editorTabMovesFocus && !inSnippetMode"
    },
    {
        "key": "ctrl+k",
        "command": "jumpToNextSnippetPlaceholder",
        "when": "editorTextFocus && hasNextTabstop && inSnippetMode"
    },
    {
        "key": "ctrl+h",
        "command": "jumpToPrevSnippetPlaceholder",
        "when": "editorTextFocus && hasPrevTabstop && inSnippetMode"
    },
    {
        "key": "ctrl+[",
        "command": "workbench.action.closeQuickOpen",
        "when": "inQuickOpen"
    },
    {
        "key": "ctrl+[",
        "command": "workbench.action.closeQuickOpen",
        "when": "inQuickOpen"
    },
    //サイドバーでソースツリーを開いている時のコマンド
    {
        "key": "l",
        "command": "explorer.openToSide",
        "when": "explorerViewletFocus && explorerViewletVisible"
    },
    {
        "key": "ctrl+r",
        "command": "renameFile",
        "when": "explorerViewletVisible && filesExplorerFocus"
    },
    {
        "key": "Enter",
        "command": "explorer.openToSide",
        "when": "explorerViewletVisible && filesExplorerFocus"
    },
    //どこにフォーカスしていても使いたいコマンド。
    {
        "key": "ctrl+o ctrl+d",
        "command": "workbench.view.debug"
    },
    {
        "key": "ctrl+o d",
        "command": "workbench.view.debug"
    },
    {
        "key": "ctrl+o ctrl+g",
        "command": "workbench.view.scm"
    },
    {
        "key": "ctrl+o g",
        "command": "workbench.view.scm"
    },
    //サイドバーの表示切り替え
    {
        "key": "[IntlYen] v",
        "command": "workbench.view.explorer",
        "when": "!explorerViewletVisible && vim.mode != 'SearchInProgressMode'"
    },

    {
        "key": "[IntlYen] v",
        "command": "workbench.action.toggleSidebarVisibility",
        "when": "explorerViewletVisible && !searchViewletVisible && !inDebugMode && vim.mode != 'SearchInProgressMode'"

    },
    //コマンドパレットオープン
    {
        "key": "ctrl+o ctrl+o",
        "command": "workbench.action.showCommands"
    },
    {
        "key": "ctrl+o o",
        "command": "workbench.action.showCommands"
    },
    //エディター以外のビューから抜けてくるときに
    {
        "key": "ctrl+w ctrl+w",
        "command": "workbench.action.focusActiveEditorGroup"
    },
    {
        "key": "tab",
        "command": "editor.emmet.action.expandAbbreviation",
        "when": "config.emmet.triggerExpansionOnTab && editorTextFocus && !editorReadonly && !editorTabMovesFocus"
    },
    {
    //パネルの表示切り替え
    {
        "key": "[IntlYen] t",
        "command": "workbench.action.terminal.toggleTerminal",
        "when": "!terminalFocus && vim.mode != 'SearchInProgressMode'"
    },
    {
        "key": "[IntlYen] t",
        "command": "workbench.action.terminal.toggleTerminal",
        "when": "terminalFocus && vim.mode != 'SearchInProgressMode'"
    },
    //git fugitiveの真似
    {
        "key": "g c",
        "command": "git.commit",
        "when": "editorTextFocus && vim.mode == 'Normal'"
    },
    {
        "key": "g a",
        "command": "git.stage",
        "when": "editorTextFocus && vim.mode == 'Normal'"
    },
    {
        "key": "g g",
        "command": "cursorTop",
        "when": "editorTextFocus && vim.mode == 'Normal'"
    },
    {
        "key": "ctrl+w h",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    }

そのほかにはphp-fixerをかける設定などや
Docker + php + xdebug + vscodeみたいな構成も割と簡単にできて満足しています!
VSCode最高ですね!
今のところは自分のvimとほとんど同じ挙動なので満足ですがバグはあるかもしれません!
次回Docker + php + xdebug + vscodeも共有したいと思います。

Vimの非同期文法チェッカALEにプロジェクト固有の情報を教える

$
0
0

はじめに

Vimの非同期文法チェックエンジン、ALE (Asynchronous Lint Engine)に、プロジェクト固有の情報を教えたいことがある。典型的なのがC/C++のヘッダのインクルードパスで、makefileで-Iで場所を教えていたりすると、ALEから呼ばれたgccclangがそのパスを探せずにエラーを報告してしまう。これを解決するには以下のようにすれば良い。

  1. .vimrcを修正して、カレントディレクトリに.vimrc.localがあったら読むようにする
  2. ALEに追加情報が必要な場合はそこに.vimrc.localを作って、その中に情報を書く
  3. 例えばC/C++のインクルードパスを教えるにはg:ale_cpp_clang_optionsg:ale_cpp_gcc_optionsに"-std=c++14 -Wall -Ipath/to/header"を指定する

状況

あるプログラムが参照するヘッダのインクルードパスが、コンパイル時に-Iオプションで指定されているものとする。

例えばこんな状況を考える。

project
├── includes/
│   └── hoge.hpp
└── src/
    └── test.cpp

test.cppの中身はこんな感じ。

test.cpp
#include<hoge.hpp>

もちろん、makefileには-Iで適切にヘッダファイルの場所を教えているから、問題なくコンパイルできる。

しかし、このsrc/test.cppをALEを有効にした状態のVimで編集すると、「hoge.hppが見つからないよ」と怒られてしまう。

image.png

これはALEから呼び出されるclang++g++には-Iオプションが渡されていないのでヘッダが探せないため。

解決法

直接解決するには、g:ale_cpp_clang_optionsg:ale_cpp_gcc_optionsにヘッダの場所を教えてやれば良い。デフォルト値は-std=c++14 -Wallになっているので、今回の場合は

letg:ale_cpp_clang_options ="-std=c++14 -Wall -I../includes"letg:ale_cpp_gcc_options ="-std=c++14 -Wall -I../includes"

とやってやれば、この警告は消える。しかし、毎回Vimを起動する度に上記の設定をするのは面倒。なのでVimでプロジェクト固有の設定を適用するを参考に、まず.vimrc

~/.vimrc
augroup vimrc-local
  autocmd!
  autocmd BufNewFile,BufReadPost * call s:vimrc_local(expand('<afile>:p:h'))
augroup ENDfunction! s:vimrc_local(loc)letfiles= findfile('.vimrc.local', escape(a:loc,' ') . ';',-1)foriin reverse(filter(files,'filereadable(v:val)'))
    source `=i`endforendfunction

と書いて、もしカレントディレクトリに.vimrc.localがあったら読み込むようにする。

その上で、先程のtest.cppと同じディレクトリに

.vimrc.local
letg:ale_cpp_clang_options ="-std=c++14 -Wall -I../includes"letg:ale_cpp_gcc_options ="-std=c++14 -Wall -I../includes"

というファイルを作ってやればよい。ファイル構成はこんな感じになる。

project
├── includes/
│   └── hoge.hpp
└── src/
    ├── .vimrc.local
    └── test.cpp

この状況でtest.cppをVimで開いても、「ヘッダが見つからない」とは怒られない。

まとめ

ALEにプロジェクト固有の情報を伝える方法をまとめた。「C/C++のヘッダは面倒だよね」という話はALEのissueにもなってて、作者も「100%の解決策はないよね〜」みたいなことを書いている。また、冒頭に書いたように本家のFAQに「vimrc-localを使え」と書いてあるんだけれど、僕のようなVim初心者にはそれだけの情報ではきつかった。

参考

ctag, gtagsで超捗るコードリーディング

$
0
0

vimmerのみなさん初めまして。
vimアドベントカレンダー20日目です。

今回はvimでコードリーディングするのに必須であろうツール、ctagsとgtagsについて設定例も交えながら紹介しようと思います。
色々と導入に手こずった結果、今の自分の環境に沿う形になります。

お詫び

macとlinuxの両方でインストールできるようにしたかったのですが、メインマシンのlinux(debian)の方で再現しようとして再インストールしたらgtagsが動かなくなりました...orz助けて(調査します)
仮想環境でのdebianでの再インストール、および新規のubuntuでのインストールはうまくいった。

ctags

ctagsについてはvimについての記事をいくつか読んでいる方なら、既に導入している方も多いと思います。
記事自体はたくさんあるのでサクッと
これがあるとvimのノーマルモードで<C-]>を押すと、関数やメソッドの定義先に飛ぶことができます。
導入についてはbrewやaptなどで

$ brew install ctags
$ apt install exuberant-ctags

とすれば普通に導入できると思います。
実際はapt install ctagsでもexuberant-ctagsを入れてくれます。

これでctagsの導入は完了です。
あとはctagsを使いたいファイルがあるディレクトリで

$ ctags -R

と打てばtag情報の入ったファイルが作られるので、あとは実際のファイル上で
定義元の関数、メソッドに飛びたいときに、カーソルを上に置いて<C-]>を押せば定義元に飛ぶと思います。
ただしこの時、複数の定義があった場合ctagsの方ではどれが正しい関数かは判断できないので、とりあえず一番最初に見つけた定義元に飛んでしまいます。
これ自体は仕方ないのですが、対策としてg<C-]>とすると定義元が一覧として表示されるのでこちらを使うと良いでしょう。

以上がctagsとなります。これだけでもだいぶコードリーディングが捗ると思います。

gtags

ctagsだけでもだいぶコードリーディングが捗るとは思うのですが、今一歩物足りない...
というかvscodeをライバル視しているので、ここは是非とも定義元だけでなく参照先にもジャンプしたいところ。
そこで使うのがこちらgtags(gnu globalが正式名称?)

まず導入について

for mac

homebrewを使った方法

下準備

ctagsに加えpygmentsをインストールする必要があります。

ctagsのインストール
既にインストールしていれば飛ばして大丈夫です。

$ brew install ctags
もしくは
$ apt install exuberant-ctags

pygmentsのインストール
pygmentsはpythonを使ってパースするツールです。
こちらに依存しているので、まずインストールします。
python2.7の方のpygmentsを使うのでpyenvかなんかを使っている人はpython2.7も動くようにしてください。

pip install pygments
インストール後
pygmentize
コマンドが動くはずです。

上記二つインストールが完了したらgtagsをインストールします。
パッケージ名はglobalなので

gnu global

$ brew install global
もしくは
$ apt install global

注意点としてgnu globalのバージョンは6以上を想定しているので、バージョン5などがインストールされてしまう場合は、自分でビルドしてみてください。
参考https://qiita.com/akegashi/items/042c659c856d2092c443
環境を汚したくない場合は、別途ホームディレクトリなどにoptフォルダなどを作り、パスを作ってそこにインストールすることをおすすめします。

これで、globalコマンド及びgtagsコマンドが動くようになります。
これらはターミナル上でも使えます。
ただし、gnu globalはそのままだとpythonやrubyなどに対応していない、すなわちpygmentsを呼び出さないため、明示的にコマンドで指定するか、.globalrcというファイルをホームに配置する必要があります。

.globalrcはインストールしたgtagsのフォルダ、もしくはビルドに使ったgnu globalのフォルダに入っているgtags.confをリネームしてください。
自分のdotfilesの中に入っているものですがこのような中身のファイルです。
https://raw.githubusercontent.com/coil398/dotfiles/master/.globalrc

自分で用意した場合は、gtags.conf及び.globalrcの中に

default:\
    :tc=native:tc=pygments:

といった部分がファイルの上の方に有るので

default:\
    :tc=native:tc=pygments:

このように書き換えてください。
これで通常のようにgtagsを実行するとpygmentsを使ってくれるようになります。

試しに適当なフォルダで

$ gtags -v --debug

というコマンドを打つと(-vはverboseオプション、--debugはそのままデバグ用?のオプション。どちらもなくても可)
するとGTAGS, GPATH, GRTAGSといったファイルが出来ていると思います。
この中にgtags用のデータが入っています。

試しに

$ global -f [file]

を実行すると、そのファイルに含まれる関数などの一覧が表示されます。

vim上でgnu globalを使う(便利なプラグイン)

では、これをvim上で使ってみましょう。
まず、先程の.globalrcのようにgtags.vimファイルが有ると思います。
これをvim上で読み込めば良いのですが、もしプラグインマネージャを利用しているのであれば、githubのレポジトリに公開してくださっている方がいらっしゃるのでこちらを利用することをおすすめします。

lighttiger2505/gtags.vim

参考https://qiita.com/lighttiger2505@github/items/6b1cd3bc79cb9806a743

これでvim上でgnu globalを使う準備ができましたので、実際に使っているキーマッピングを紹介します。

nnoremap <silent> <Space>f :Gtags -f %<CR>
nnoremap <silent> <Space>j :GtagsCursor<CR>
nnoremap <silent> <Space>d :<C-u>exe('Gtags '.expand('<cword>'))<CR>
nnoremap <silent> <Space>r :<C-u>exe('Gtags -r '.expand('<cword>'))<CR>

コマンドでのglobalと同じように使えます。

fで今のファイルの関数などの一覧
jでカーソル下の単語が含まれるタグの表示
dでカーソル下の単語の定義元を表示
rでカーソル下の単語の参照先を表示
いずれもQuickFixで表示されるため、QuickFix関連のキーマッピングを設定しておくとはかどります。

次に、おすすめのプラグインとしてgen_tags.vimを紹介します。
これはターミナル上でのctagsやgtagsの生成やそれらの自動化をしてくれるプラグインです。

jsfaint/gen_tags.vim

これもプラグインマネージャがあれば、そちらでインストールするのをおすすめします。
インストールしたら

let g:gen_tags#ctags_auto_gen = 1
let g:gen_tags#gtags_auto_gen = 1

と設定すると、自動でctags, gtagsを生成、更新してくれます。
ただし、ディレクトリにあるgitなどのSCMを参考にタグの生成を行うので、それらを用意する必要があります。
自動生成と更新は恐らくファイルの保存をした際に行われるようです。

一つ注意点として、自分もハマってしまったのですが、デフォルトでキャッシュを使う設定になるので
vim上で、生成したtagsファイルは、ホームの.cacheフォルダに有るtags_dirフォルダに格納され、そちらが参照されるようになります。
ターミナル上でglobalコマンドを使用する際には支障はありませんが、vim上でglobalコマンドやgtagsコマンドを使用した際は問答無用でそちらが参照されてしまうので、ターミナル上でgtagsを使ってGPATH, GTAGS, GRTAGSファイルを生成してもvim上でそれらを参照することはできないことに注意してください。
詳しくはhttps://github.com/jsfaint/gen_tags.vimを参照してください。

他にもdenite(unite)用のソースファイルもあるのですが、自分は基本的に使っていないのでそちらについては割愛させていただきます。

結論

めっちゃ捗る

最後に

遅くなってしまって申し訳ありませんでした。
ちょっと急いで書き上げてしまったのでわかりにくい部分があるかもしれません。というか自分も何故か結構苦労したので何かしら質問があればコメントお願いします。

CygwinのVIMで、コマンドモード復帰時にIMEをオフにする

$
0
0

経緯

過去に、いろいろな環境でVIMのコマンドモード復帰時にIMEをオフにする話題がありましたが、自分が使っているCygwin+VIMだと情報が乏しかったり、リンク切れだったりしたので、まとめなおしてみました。

必要なもの

以下のサイトを参考にしています。
Cygwin版VimでIME自動切り替えへの道 - 野望編

  1. minttyの置き換え
    以下のパッチをminttyのソースに当ててビルドする。といいたいところですが、パッチが古いのでいろいろ中身を解釈してマージして下さい。
    GitHubGist/kanonji/mintty-manage-ime.patch
    面倒な方は自分がビルドしたものをここに上げておきます。
    mintty.exeのzip書庫 (cygwin 64bit用)

  2. im_control.vimを ~/.vim/pluginにコピーする。

  3. ~/.vimrcに以下の設定を記述する

.vimrc
function! IMCtrl(cmd)let cmd =a:cmdif cmd =='On'silent!echo -n-e"\0033[1v"redraw!elseif cmd =='Off'silent!echo -n-e"\0033[0v"redraw!elseif cmd =='Toggle'silent!echo -n-e"\0033[2v"redraw!endifreturn''endfunction

以上です。

終わりに

atsuoishimotoさん、kanonjiさん、ありがとうございます。
おかげでめちゃ快適です。


Vim optionの設定/参照方法いろいろ

$
0
0

  
この記事は Vim Advent Calendar 2017、22日目の記事です。

Vimには様々なoptionがありますが、
本記事ではoptionの設定/参照方法についてご紹介していきます。

optionの種類毎の設定方法

optionにはいくつかの種類があります。

  1. 切替(boolean)
  2. 数値
  3. 文字列

対象のオプションが何に該当するかは:h 'option_name'で確認できます。
以下ではそれぞれの設定方法について記載していきます。

切替(boolean)

number, wrap, equalalwaysなどが該当します。
切替オプションの場合には:set option_nameという形でオンに変更できます。

:setnumber" 行番号を表示

切替オプションをオフにするにはprefixとしてnoを指定します。

:setnonumber" 行番号を表示しない

prefixにinv, またはsuffixにbang(!)を指定すると対象オプションの
オン/オフを切り替えるができます

" 行番号の表示/非表示を切り替え:setinvnumber:setnumber!

数値

cmdheight, tabstop, synmaxcolなどが該当します。
数値オプションの場合には:set <option_name>=<value> or :set <option_name>:<value>で数値を指定できます。

" コマンドラインの行数を2行に設定:setcmdheight=2:setcmdheight:2

+=, -=, ^=を使用すると数値オプションの値を計算式のように修正できます。

:setcmdheight=2" コマンドラインの行数を2行に設定:setcmdheight+=4" コマンドラインの行数を2 + 4 = 6行に設定:setcmdheight-=3" コマンドラインの行数を6 - 3 = 3行に設定:setcmdheight^=3" コマンドラインの行数を3 * 3 = 9行に設定

文字列

文字列オプションの場合にも数値オプションと同様に:set <option_name>=<value> or :set <option_name>:<value>という形で文字列を指定できます。

" grepprgにjvgrepを指定:setgrepprg=jvgrep:setgrepprg:jvgrep

ここから少しややこしいのですが、文字列オプションはさらに
以下3つに分類されています。

  1. ただの文字列
  2. カンマ区切りのリスト
  3. フラグのリスト

上記3つの種類毎、+=, -=, ^=の使われ方が少しずつ異なってきます。
(この分類も:set option_nameで確認できます。というかヘルプ見る以外に確認方法はありません)

文字列(ただの文字列)

grepprg, foldmethod, ambiwidthなどが該当します。
+=で後ろに文字追加, ^=で前に文字追加, -=で文字の削除が行えます。

" 以下で'grepprg'がgrep -> jvgrep -> j -> javaの順に変化:setgrepprg=grep:setgrepprg^=jv:setgrepprg-=vgrep:setgrepprg+=ava
文字列(カンマ区切りのリスト)

tags, path, backspace, viminfoなどが該当します。
+=で後ろにカンマと文字追加, ^=で先頭に文字とカンマ追加, -=でカンマと文字を削除します。
(※リストが単一か否かでカンマの追加, 削除は自動的に調整されます)

" 以下で'tags'が tags,./../tags -> tags -> ./tags,tags -> ./tags,tags,TAGSの順に変化:settags=tags,./../tags:settags-=./../tags:settags^=./tags:settags+=TAGS
文字列(フラグのリスト)

shortmess, guioptions, formatoptions,などが該当します。
+=でフラグの追加, -=でフラグを削除します。

" 以下で'shortmess'が filn -> filnoO -> flnoO の順に変化" NOTE: -= を使用してフラグを取り除く場合には1つずつ指定することが推奨されています:setshortmess=filn:setshortmess+=oO:setshortmess-=i

オプションを規定値に戻す

規定値に戻したいoption名に&を指定するだけで、
対象のoptionが規定値に戻ります

" grepprgを規定値に戻す:setgrepprg&" ほぼ全てのオプションを規定値に戻す(※若干例外がるので、詳細は:h :setで確認してください):setall&

また:set option_name&viでViの規定値に、
:set option_name&vimでVimの規定値に戻すこともできます。

式を使用したoptionの設定方法

式を使用してoptionに値を設定することもできます。
これもoption名に&を付けて実現できます。

式で使用する場合にはoption名の頭に&を指定します。

" $VIM(Windowsだとvim.exeがあるディレクトリ)のviminfoを使用するよう修正" viminfoの場所を動かして利便性があるかは無視してく(ry" 最初に既定値に戻すsetviminfo&" nフラグを指定, その後にviminfoのファイルパスを指定するlet&viminfo .=',n' . expand('$VIM') . '\_viminfo'" viminfoに設定されている値をecho
echo &viminfo

optionの参照方法 1

option名に?を付ければoptionに設定されている値を見ることができます。

" grepprgに設定されている値を確認:setgrepprg?

またexist()関数を使用してexist('&option_name')とすればそのオプションを設定可能かチェックすることもできます。

" 透明度のトグル" 参考:https://qiita.com/tekkoc/items/de25bbf595de8c5f73ec function! s:toggle_transparency() abort  " transparencyオプションが設定可能かチェックif exists('&transparency')if&transparency ==255set transparency=100elseset transparency=255endifendfunctionnnoremap<F12> :<C-u>call<SID>toggle_transparency()<CR>

optionの参照方法 2

:set:set allで設定値の一覧を見ることができます

" 既定値と異なるoptionについて全て表示:set" optionをほぼ全て表示(一部表示されないのもあります):setall

既定値通りのoptionの一覧を確認するには:set:set allのdiffをとれば可能だと思います。
こちらを参考にコマンド結果をキャプチャするとset1に:setの結果, set2に:set allの結果が格納されますので、
少し整形して好きなdiffツール(私の場合はVim)で比較してみてください。

:redir=> set1:set:redir END:redir=> set2:setall:redir END" キャプチャした内容(set1 or set2)をテキストで編集したい場合には" Insertモードで<C-r>=set1<CR>を実行してください。カーソル位置に張り付けられます。

OptionSet

Vimにはoption設定時に使用されるOptionSetというイベントが存在します。
OptionSetをつかえばPlugin等でどのoptionが書き換えられているか確認することもできます。

" 値が変更されたoption名, 変更前の値、変更後の値、変更されたオプションのスコープ(global or local)をecho
augroup option_set
  autocmd!
  autocmd OptionSet * echo expand('<amatch>') . ',''old value:' . v:option_old 'new value:' . v:option_new 'type:'v:option_type
augroup END

おまけ: 'showmatch'について

helpで開いてみてください(:h 'showmatch'@en or :h 'showmatch'@ja)。
しょーもないイースターエッグを見ることができます(笑)

まとめ

こんな感じで色々な方法でoptionの設定/参照がができます。
ただ、設定方法、参照方法は分かってもVimにどんなoptionが存在するか知らないと
意味がありませんよね。

便利なoption(よく使われているoption)を知るには他人のvimrcを見るのが一番だと思いますので、
おすすめはvimrc読書会に参加することですかねー。
(私は過去ログ参照(or ROM専)しかしておらず未参加ですが、、、、)

そして気になったoptionを見つけたらhelpで詳細を確認するのが良いのかと思います。
showmatchの様に新しい発見があるかもしれないですしね。

あとは、optionのグローバルローカルという話や
それに関連してsetlocalsetglobalというものについても紹介したかったのですが、
余り理解できていないので省きました。
こちらのリンクか:h local-optionsで確認してください。

色んなoptionを使って素晴らしいVim Lifeを送りましょー。

Happy Vim Life !!

" 参考:hoptions:hlet-&:h exist():h'showmatch'" その他" NOTE: Vim イースターエッグのまとめ(http://postd.cc/vim-galore-5/)

ctag, gtagsで超捗るコードリーディング

$
0
0

vimmerのみなさん初めまして。
vimアドベントカレンダー20日目です。

今回はvimでコードリーディングするのに必須であろうツール、ctagsとgtagsについて設定例も交えながら紹介しようと思います。
色々と導入に手こずった結果、今の自分の環境に沿う形になります。

お詫び

macとlinuxの両方でインストールできるようにしたかったのですが、メインマシンのlinux(debian)の方で再現しようとして再インストールしたらgtagsが動かなくなりました...orz助けて(調査します)
仮想環境でのdebianでの再インストール、および新規のubuntuでのインストールはうまくいった。

ctags

ctagsについてはvimについての記事をいくつか読んでいる方なら、既に導入している方も多いと思います。
記事自体はたくさんあるのでサクッと
これがあるとvimのノーマルモードで<C-]>を押すと、関数やメソッドの定義先に飛ぶことができます。
導入についてはbrewやaptなどで

$ brew install ctags
$ apt install exuberant-ctags

とすれば普通に導入できると思います。
実際はapt install ctagsでもexuberant-ctagsを入れてくれます。

これでctagsの導入は完了です。
あとはctagsを使いたいファイルがあるディレクトリで

$ ctags -R

と打てばtag情報の入ったファイルが作られるので、あとは実際のファイル上で
定義元の関数、メソッドに飛びたいときに、カーソルを上に置いて<C-]>を押せば定義元に飛ぶと思います。
ただしこの時、複数の定義があった場合ctagsの方ではどれが正しい関数かは判断できないので、とりあえず一番最初に見つけた定義元に飛んでしまいます。
これ自体は仕方ないのですが、対策としてg<C-]>とすると定義元が一覧として表示されるのでこちらを使うと良いでしょう。

以上がctagsとなります。これだけでもだいぶコードリーディングが捗ると思います。

gtags

ctagsだけでもだいぶコードリーディングが捗るとは思うのですが、今一歩物足りない...
というかvscodeをライバル視しているので、ここは是非とも定義元だけでなく参照先にもジャンプしたいところ。
そこで使うのがこちらgtags(gnu globalが正式名称?)

まず導入について

for mac

homebrewを使った方法

下準備

ctagsに加えpygmentsをインストールする必要があります。

ctagsのインストール
既にインストールしていれば飛ばして大丈夫です。

$ brew install ctags
もしくは
$ apt install exuberant-ctags

pygmentsのインストール
pygmentsはpythonを使ってパースするツールです。
こちらに依存しているので、まずインストールします。
python2.7の方のpygmentsを使うのでpyenvかなんかを使っている人はpython2.7も動くようにしてください。

pip install pygments
インストール後
pygmentize
コマンドが動くはずです。

上記二つインストールが完了したらgtagsをインストールします。
パッケージ名はglobalなので

gnu global

$ brew install global
もしくは
$ apt install global

注意点としてgnu globalのバージョンは6以上を想定しているので、バージョン5などがインストールされてしまう場合は、自分でビルドしてみてください。
参考https://qiita.com/akegashi/items/042c659c856d2092c443
環境を汚したくない場合は、別途ホームディレクトリなどにoptフォルダなどを作り、パスを作ってそこにインストールすることをおすすめします。

これで、globalコマンド及びgtagsコマンドが動くようになります。
これらはターミナル上でも使えます。
ただし、gnu globalはそのままだとpythonやrubyなどに対応していない、すなわちpygmentsを呼び出さないため、明示的にコマンドで指定するか、.globalrcというファイルをホームに配置する必要があります。

.globalrcはインストールしたgtagsのフォルダ、もしくはビルドに使ったgnu globalのフォルダに入っているgtags.confをリネームしてください。
自分のdotfilesの中に入っているものですがこのような中身のファイルです。
https://raw.githubusercontent.com/coil398/dotfiles/master/.globalrc

自分で用意した場合は、gtags.conf及び.globalrcの中に

default:\
    :tc=native:tc=pygments:

といった部分がファイルの上の方に有るので

default:\
    :tc=native:tc=pygments:

このように書き換えてください。
これで通常のようにgtagsを実行するとpygmentsを使ってくれるようになります。

試しに適当なフォルダで

$ gtags -v --debug

というコマンドを打つと(-vはverboseオプション、--debugはそのままデバグ用?のオプション。どちらもなくても可)
するとGTAGS, GPATH, GRTAGSといったファイルが出来ていると思います。
この中にgtags用のデータが入っています。

試しに

$ global -f [file]

を実行すると、そのファイルに含まれる関数などの一覧が表示されます。

vim上でgnu globalを使う(便利なプラグイン)

では、これをvim上で使ってみましょう。
まず、先程の.globalrcのようにgtags.vimファイルが有ると思います。
これをvim上で読み込めば良いのですが、もしプラグインマネージャを利用しているのであれば、githubのレポジトリに公開してくださっている方がいらっしゃるのでこちらを利用することをおすすめします。

lighttiger2505/gtags.vim

参考https://qiita.com/lighttiger2505@github/items/6b1cd3bc79cb9806a743

これでvim上でgnu globalを使う準備ができましたので、実際に使っているキーマッピングを紹介します。

nnoremap <silent> <Space>f :Gtags -f %<CR>
nnoremap <silent> <Space>j :GtagsCursor<CR>
nnoremap <silent> <Space>d :<C-u>exe('Gtags '.expand('<cword>'))<CR>
nnoremap <silent> <Space>r :<C-u>exe('Gtags -r '.expand('<cword>'))<CR>

コマンドでのglobalと同じように使えます。

fで今のファイルの関数などの一覧
jでカーソル下の単語が含まれるタグの表示
dでカーソル下の単語の定義元を表示
rでカーソル下の単語の参照先を表示
いずれもQuickFixで表示されるため、QuickFix関連のキーマッピングを設定しておくとはかどります。

次に、おすすめのプラグインとしてgen_tags.vimを紹介します。
これはターミナル上でのctagsやgtagsの生成やそれらの自動化をしてくれるプラグインです。

jsfaint/gen_tags.vim

これもプラグインマネージャがあれば、そちらでインストールするのをおすすめします。
インストールしたら

let g:gen_tags#ctags_auto_gen = 1
let g:gen_tags#gtags_auto_gen = 1

と設定すると、自動でctags, gtagsを生成、更新してくれます。
ただし、ディレクトリにあるgitなどのSCMを参考にタグの生成を行うので、それらを用意する必要があります。
自動生成と更新は恐らくファイルの保存をした際に行われるようです。

一つ注意点として、自分もハマってしまったのですが、デフォルトでキャッシュを使う設定になるので
vim上で、生成したtagsファイルは、ホームの.cacheフォルダに有るtags_dirフォルダに格納され、そちらが参照されるようになります。
ターミナル上でglobalコマンドを使用する際には支障はありませんが、vim上でglobalコマンドやgtagsコマンドを使用した際は問答無用でそちらが参照されてしまうので、ターミナル上でgtagsを使ってGPATH, GTAGS, GRTAGSファイルを生成してもvim上でそれらを参照することはできないことに注意してください。
詳しくはhttps://github.com/jsfaint/gen_tags.vimを参照してください。

他にもdenite(unite)用のソースファイルもあるのですが、自分は基本的に使っていないのでそちらについては割愛させていただきます。

結論

めっちゃ捗る

最後に

遅くなってしまって申し訳ありませんでした。
ちょっと急いで書き上げてしまったのでわかりにくい部分があるかもしれません。というか自分も何故か結構苦労したので何かしら質問があればコメントお願いします。

【Vim】シェルの実行結果を行としてではなく現在のカーソル位置に挿入する

$
0
0

例えば:read !dateなどと打つと、dateの結果を挿入することができるけど、行で出力されてしまうので、カーソルの右側に出力したいという用途には使えない。

挿入モードやコマンドラインモードで<C-r>=を使うと現在のカーソル位置にVim scriptの結果が挿入されるので、<C-r>=を打った後、system('date')と打つとやりたいことが大体できるが、最後の改行が入ってしまうのと、system('')を打つのがめんどい。

そこで、<C-r>!<command><command>の実行結果から最後の改行を取り除いたものをカーソル位置に挿入できるようにした。

inoremap<expr><C-r>!<SID>system()
cnoremap <expr><C-r>!<SID>system()function! s:system()let command = input("!",'','shellcmd')return substitute(system(command),'\n\+$','','')endfunction

上記をvimrcに書いて

わたしは<C-r>!whoami<CR>です。

と打つと

わたしはtmsanrinshaです。

となる。

Vimで挿入モードに入ったり出たりした時にIMEをコントロールする

$
0
0

この記事はVim2 Advent Calendar 2017の19日の記事(代打)です。

この記事ではmacOS High Sierraでvimの挿入モードに入ったり、挿入モードから出た時にIMEの状態を自動で切り替える方法を説明します。
私はATOKを使っていますが、標準の日本語入力やGoogle IMEを使っていても少しの修正で使えると思います。
挙動としては、挿入モードを抜けた時にIMEの状態を記憶して、挿入モードに入ったときに復元する感じです。

まず最初に、環境設定>キーボード>入力ソースでお好みの英語の入力用ソースを追加します。私の場合はU.S.を追加しました。
結果として入力ソースは以下の画像のようになります。
入力ソース

そして、macOSのIMEをcliで切り替えたりできる、swimを入れます。
IMEを切り替えながら swim list --currentを使って、日本語と英語のIMEの内部名称をメモしてください。

そんでもって、下記 Vim script を vimrc にどーん。
s:JapaneseIMs:AsciiIMの値は先ほどメモしたやつに書き換えてくださいね。

" input methodlet s:JapaneseIM ='com.justsystems.inputmethod.atok30'let s:AsciiIM ='com.apple.keyboardlayout.all'function! s:ImActivateFunc(active)ifa:activecall system('swim use ' . s:JapaneseIM)elsecall system('swim use ' . s:AsciiIM)endifendfunctionfunction! s:ImStatusFunc()return system('swim list --current')is# s:JapaneseIM . "\n"endfunctionlet s:ImStatus =0function! s:insertEnter()call s:ImActivateFunc(s:ImStatus)call s:ImStatusFunc()endfunctionfunction! s:insertLeave()let s:ImStatus = s:ImStatusFunc()call s:ImActivateFunc(0)call s:ImStatusFunc()endfunction

augroup ime
  autocmd!
  autocmd InsertEnter * call s:insertEnter()
  autocmd InsertLeave * call s:insertLeave()
augroup END

本当は、imafimsfを適切に設定すればvimがかってにうまいことやってくれるんですが、imsfは頻繁に呼ばれてしまい、それでvimがもたついてしまうので挿入モードに出入りするときだけ呼ぶようにしたのが上記になります。
macOS以外の人もImActivateFuncとかImStatusFuncを適切に実装すれば同じことができるはず?

Vimで快適な日本語執筆環境をめざして!

追記:
ImActivateFuncを呼んだ後にImStatusFuncを呼んでいるのは、swimがIMEの切り替えに失敗?することがあって、そんなときに swim list --currentを呼んでやるとうまくいくというworkaroundです。

Tmux + Zsh + Vim 時の dotfiles まとめ

$
0
0

なんとなく自分の開発環境を紹介したくなったので、書きます。
全てにコメントしているとキリがないので、独断と偏見によって選んだポイントの紹介もしていきます。
環境はTmux + Zsh + Vimです。私の三種の神器です。

リポジトリ: s4kr4/dotfiles

Vim

設定ファイル群は~/.vimフォルダにまとめて配置しているので、.vimrc内では、GVim/Cygwin用にruntimepathの追加をする以外は特に何もしていません。

~/.vimrc
if has('win32')|| has('win64')|| has('win32unix')setruntimepath+=$HOME/.vimsetruntimepath+=$HOME/.vim/afterendif

runtime! init/*.vim
runtime! functions.vim

~/.vim以下のファイル構成はこんな感じです。

image.png

~/.vim/init/*.vim

設定をなんとなく分類して管理しています。
読み込み順は、ファイル名に数字をつけることで制御しています。

10_dein.vim

Shougo/dein.vimとそのプラグインをインストールするスクリプトです。

20_general.vim

一般的な設定を記述しています。

ファイルエンコード

~/.vim/20_general.vim
setencoding=utf-8" バッファ内のエンコードsetfileencoding=utf-8" ファイル書き込み時のエンコードscriptencoding utf-8" Vim Scriptで使用するエンコード

Neocompleteでの補完時、プレビューウィンドウを表示しない

デフォルトだと、completeoptpreviewが含まれていて、補完時に関数の説明等が表示されます。
これがうっとおしいので、menuoneのみの設定に変更しています。

~/.vim/20_general.vim
setcompleteopt=menuone

split展開方向

~/.vim/20_general.vim
setsplitbelow" 上下分割時に、下側にファイルを開くsetsplitright" 左右分割時に、右側にファイルを開く

バックアップファイルやスワップファイルの作成を抑制

Vimでファイルを編集していると、ディレクトリに変なファイルが勝手に作成されます。
ファイル名末尾に~が付加されたものがバックアップファイル、
.swpが付加されたものがスワップファイル、
.un~が付加されたものがundoファイルです。
私はどれも特に必要を感じていないので、全て無効化しています。

~/.vim/20_general.vim
setnobackup" バックアップファイルを作成しないsetnowritebackup" 上書き成功時にバックアップファイルを破棄setnoswapfile" スワップファイルを作成しないsetnoundofile" undoファイルを作成しない

括弧対応ジャンプを強化

Vimにはデフォルトでカーソル下の括弧に対応する括弧へジャンプする機能がありますが、Vimにデフォルトで同梱されているmatchit.vimを読み込むことで、この機能を強化することができます。
HTMLやXMLのタグ、Rubyのdef~end等もジャンプできるようになります。

~/.vim/20_general.vim
runtime macros/matchit.vim

30_edit.vim

編集時の動作に関する設定を記述しています。

ファイル選択時のタブ補完強化

~/.vim/30_edit.vim
setwildmenuwildmode=list:full

未保存状態のバッファを切り替え可能にする

例えばfoo.txtを編集中、一時的にbar.txtを閲覧したくなったとき、未保存状態で:e bar.txt等と入力すると以下のようなメッセージが出て、バッファを切り替えることができません。

image.png

以下の設定を追加することで、バッファの切替が可能になります。

~/.vim/30_edit.vim
sethidden

ちなみに、裏に未保存のバッファがある状態でVimを終了しようとすると、ちゃんと警告してくれます。

image.png

40_keymap.vim

各種keymapを設定しています。
VimScriptのhasを使って、環境ごとに設定するkeymapを変化させたりしています。

Shift + Enter でノーマル状態のまま改行挿入 (GVim)

このkeymapはGVimでしか動作しないようです。

~/.vim/40_keymap.vim
if has("gui_running")nnoremap<silent><S-CR> :<C-u>call append(expand('.'),'')<CR>jendif

;, :キーの入れ替え (macOS)

英字キーボードのMacBookを使用していることと、;よりも :の使用頻度が高いことから、両者の入力を入れ替えています。

~/.vim/40_keymap.vim
if has("mac")nnoremap ; :nnoremap : ;endif

90_visual.vim

見た目に関する設定を記述しています。

ステータスライン

このあたりを参考にして、色々表示しています。
%{}で括るとコマンドの結果を表示できるので、tpope/vim-fugitiveでGitのブランチを表示したり、ファイルのエンコードを表示したりしています。

~/.vim/init/90_visual.vim
setstatusline=%F%m%r%h%w%{fugitive#statusline()}%=[TYPE:%Y][FMT:%{&fileformat}][ENC:%{&fileencoding}][LINE:%l/%L]

GUIパーツの非表示化 (GVim)

以前書いた以下の記事のとおりです。

透明感のあるVim環境をめざして - Qiita

全角スペース・行末スペースの可視化

プログラマたるもの、ソースコード中の無駄なスペースや全角スペースは殲滅していかなければなりません。
以下の設定で、それらを赤くハイライトしています。

~/.vim/init/90_visual.vim
augroup highlightSpace
  autocmd!
  autocmd Colorscheme * hi IdeographicSpace term=underline ctermbg=DarkRed guibg=DarkRed
  autocmd VimEnter,WinEnter * match IdeographicSpace / \|\s\+$/
augroup END

~/.vim/after/indent/*.vim

ファイルタイプごとのインデント設定です。
例えばRubyのインデントはスペース2つなので、ruby.vimに以下を記述しています。
tabstop, softtabstop, shiftwidthが紛らわしいですが、それぞれ

  • tabstop => タブ文字の表示幅
  • softtabstop => TabキーやBackSpaceキー等でカーソルが動く幅
  • shiftwidth => autoindentで挿入される幅

という意味です。

~/.vim/after/indent/ruby.vim
setlocalexpandtabsetlocaltabstop=2setlocalsofttabstop=2setlocalshiftwidth=2

~/.vim/ftdetect/*.vim

Vimはたいていのファイルタイプを自動で認識してくれますが、拡張子からファイルタイプを推測できないものはここで指定します。

例えば*.themeファイルをPHPとして読み込みたい場合、theme.vimに以下のように記述しておきます。

~/.vim/ftdetect/theme.vim
autocmd BufRead,BufNewFile *.theme setfiletype php

~/.vim/{dein,dein_lazy}.toml

dein.vimで読み込むプラグインリストです。
dein.tomlには、Vim起動時に読み込むプラグインを書いています。
また、dein_lazy.tomlには、ファイルタイプなどに合わせて遅延読み込みするプラグインを書いています。

各プラグインの個別設定は~/.vim/plugins/*.vimに配置し、こんな感じでプラグイン読み込み時のhook_addフックを利用して読み込んでいます。

~/.vim/dein.toml
[[plugins]]repo='terryma/vim-multiple-cursors'hook_add='source$HOME/.vim/plugins/vim-multiple-cursors.vim'

dein.toml

ファイルタイプにかかわらず、必ず読み込むプラグイン

~/.vim/plugins/vim-multiple-cursors.vim
" 複数箇所の同時編集時、NeoCompleteを無効にするfunction! Multiple_cursors_before()if exists(':NeoCompleteLock')==2
    exe 'NeoCompleteLock'
    echo 'Disabled Neocomplete'endifendfunctionfunction! Multiple_cursors_after()if exists(':NeoCompleteUnlock')==2
    exe 'NeoCompleteUnlock'
    echo 'Disabled Neocomplete'endifendfunction
~/.vim/plugins/vim-submode.vim
" submodeから抜けるまでの時間letg:submode_timeoutlen =300" Space + >>>...等で分割ウィンドウを連続リサイズcall submode#enter_with('winsize','n','s','<Space>>','<C-w>>')call submode#enter_with('winsize','n','s','<Space><','<C-w><')call submode#enter_with('winsize','n','s','<Space>+','<C-w>-')call submode#enter_with('winsize','n','s','<Space>-','<C-w>+')call submode#map('winsize','n','s','>','<C-w>>')call submode#map('winsize','n','s','<','<C-w><')call submode#map('winsize','n','s','+','<C-w>-')call submode#map('winsize','n','s','-','<C-w>+')" Space + hhh...等で分割ウィンドウを連続移動call submode#enter_with('winmove','n','s','<Space>h','<C-w>h')call submode#enter_with('winmove','n','s','<Space>j','<C-w>j')call submode#enter_with('winmove','n','s','<Space>k','<C-w>k')call submode#enter_with('winmove','n','s','<Space>l','<C-w>l')call submode#map('winmove','n','s','h','<C-w>h')call submode#map('winmove','n','s','j','<C-w>j')call submode#map('winmove','n','s','k','<C-w>k')call submode#map('winmove','n','s','l','<C-w>l')
  • osyo-manga/vim-over

    • %s等で一括置換するとき、どこが置換されるのかが動的にハイライトされる
  • tyru/caw.vim

    • ファイルタイプを判別して自動でコメントアウト/コメントインできる
~/.vim/plugins/caw.vim
" Ctrl + Cの連続でコメントをトグル
nmap <C-c><C-c><Plug>(caw:hatpos:toggle)
vmap <C-c><C-c><Plug>(caw:hatpos:toggle)
~/.vim/plugins/vim-splash.vim
" AAが書かれているファイルを指定letg:splash#path= $HOME."/.vim/splash/helloworld.txt"
~/.vim/splash/helloworld.txt
 _   _      _ _                               _     _   _|||| ___||| ___      __      _____  _ __|| __||||||_||/ _ \ | |/ _ \     \ \ /\ // _ \| '__| |/ _  ||||  _  |  __/ | | (_) | _   \ V  V /(_)||||(_|||_||_||_|\___|_|_|\___/ | )   \_/\_/ \___/|_||_|\__,_|(_)|/
s4kr4
github  : github.com/s4kr4
qiita   : qiita.com/s4kr4
twitter : @s4kr4m4

dein_lazy.toml

状況に応じて読み込むプラグイン

~/.vim/plugins/neocomplete.vim
" JSONファイルでダブルクォーテーションを表示letg:vim_json_syntax_conceal =0
~/.vim/plugins/vim-jsx.vim
" 拡張子が.jsのファイルでもJSXシンタックスを有効にするletg:jsx_ext_required =0
~/.vim/plugins/vim-javascript.vim
" flowの文法対応letg:javascript_plugin_flow =1
~/.vim/plugins/neocomplete.vim
" Use neocompleteletg:neocomplete#enable_at_startup =1" Use smartcaseletg:neocomplete#enable_smart_case =1" Start completion with 2 charsletg:neocomplete#auto_completion_start_length =2" Not ignore underbarsletg:neocomplete#enable_underbar_completion =1" Number of completion listletg:neocomplete#max_list =30if!exists('g:neocomplete#keyword_patterns')letg:neocomplete#keyword_patterns = {}endif" Ignore Japaneseletg:neocomplete#keyword_patterns['default'] ='\h\w*'" Use <TAB> to move listinoremap<expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>"inoremap<expr><S-TAB> pumvisible() ? "\<C-p>" : "\<S-TAB>"" Enable omni completion.
augroup SetOmniCompletionSetting
  autocmd FileType css setlocalomnifunc=csscomplete#CompleteCSS
  autocmd FileType html,markdown setlocalomnifunc=htmlcomplete#CompleteTags
  autocmd FileType javascript setlocalomnifunc=javascriptcomplete#CompleteJS
  autocmd FileType python setlocalomnifunc=pythoncomplete#Complete
  autocmd FileType php setlocalomnifunc=phpcomplete#CompletePHP
  autocmd FileTyperubysetlocalomnifunc=rubycomplete#Complete
  autocmd FileType xml setlocalomnifunc=xmlcomplete#CompleteTags
augroup END" Enable heavy omni completion.if!exists('g:neocomplete#sources#omni#input_patterns')letg:neocomplete#sources#omni#input_patterns = {}endif

Zsh

Zshの設定ファイル群は~/.zshに配置しています。

image.png

Vimと同様に、~/.zshrcを起点に順次読み込みます。

~/.zshrc
if[ -z "${DOTPATH:-}"];thenDOTPATH=~/.dotfiles;export DOTPATHfi# 設定ファイル順次読み込みfor file in "${HOME}"/.zsh/init/*.zsh;do
    . "$file"done# zplugはTmux内でだけ読み込むif[[ -n "$TMUX"]];then
    . "${HOME}"/.zsh/zplug.zshfi# Tmux起動if has tmux;then
    tmuxxfi

Zshのプラグイン管理には zplulg/zplugを使用していますが、Tmux外でプラグインを読み込むのは時間の無駄なので、Tmux内でZshを起動したときのみプラグインを読み込むようにしています。

~/.zsh/init/*.zsh

~/.zsh/init/10_env.zsh

環境変数の設定を行います。

自作スクリプトのPATHを通す

自分で書いたスクリプトは~/binに置くようにしているので、そこにPATHを通します。

~/.zsh/init/10_env.zsh
exportPATH=$PATH:$HOME/bin

anyenvのPATHを通す

各envの管理に riywo/anyenvを使っているので、こちらのPATHを通します。
Tmuxと併用すると問題があるようなので、公式のREADME通りではなく下記のようにしています。

~/.zsh/init/10_env.zsh
if[[ -d ${HOME}/.anyenv ]];thenPATH="$HOME/.anyenv/bin:$PATH"eval"$(anyenv init -)"for d in `ls $HOME/.anyenv/envs`;doexportPATH="$HOME/.anyenv/envs/$d/shims:$PATH"donefi

参考: anyenvで開発環境を整える - Qiita

ローカル設定用のPATHを通す

どんな環境でも使うようなスクリプトや環境変数はdotfilesで管理していますが、会社や家だけで使う設定まで管理下に入れると気持ち悪いので、そうしたものは管理下から外しています。
以下の設定により、ローカル限定のスクリプトを~/bin_localに配置、環境変数設定を~/.env_local.zshに書くことで、それぞれが存在するときだけ読み込ませることができます。

~/.zsh/init/10_env.zsh
if[[ -e ${HOME}/bin_local ]];thenPATH="$HOME/bin_local:$PATH"fiif[[ -e ${HOME}/.env_local.zsh ]];thensource${HOME}/.env_local.zshfi

~/.zsh/init/20_functions.zsh

Zsh内で使いたい関数をまとめて書いています。

例えば、作ったディレクトリにそのまま移動できるmkcd関数があります。

~/.zsh/init/20_functions.zsh
...

mkcd(){
    mkdir -p "$1"[$? -eq 0]&&cd"$1"}

...

~/.zsh/init/30_aliases.zsh

エイリアスを登録します。

lsのカラー設定(OS別)

lsコマンドの結果に色を付けます。
macOSとそれ以外ではlsに色を付けるためのオプションが異なるため、OS別に分岐しています。

~/.zsh/init/30_aliases.zsh
case"${OSTYPE}" in
darwin*)aliasls='ls -G';;
*)aliasls='ls --color=auto';;esac

ローカル設定を読み込む

~/.zsh/init/10_env.zshと同様に、特定の環境でのみ使用したいエイリアスを~/.local_aliasesに登録し、ここで読み込みます。

~/.zsh/init/30_aliases.zsh
if[[ -e ${HOME}/.local_aliases ]];thensource${HOME}/.local_aliasesfi

~/.zsh/init/40_keybinds.zsh

Zshのキーバインド設定です。

vi風のキーバインドを基本に、emacs風の操作を多少混ぜた感じにしています。

~/.zsh/init/40_keybinds.zsh
bindkey -d
bindkey -v

bindkey '^A' beginning-of-line
bindkey '^E' end-of-line
bindkey '^N' down-line-or-history
bindkey '^P' up-line-or-history

bindkey -M viins '^B' backward-char
bindkey -M viins '^F' forward-char

~/.zsh/init/80_others.zsh

その他の雑多な設定を詰め込んでいます。

lsの色設定

lsで表示されるファイルの色設定です。

環境変数によって設定できますが、GNU系とBSD系で参照する環境変数が違うので、同じ色になるようにしています。
また、lsのTAB補完で表示されるファイルにも色を付けるよう、zstyleを設定しています。

~/.zsh/init/80_others.zsh
# GNU系exportLS_COLORS='no=00:fi=00:di=01;36:ln=36:pi=31:so=33:bd=44;37:cd=44;37:ex=01;32:mi=00:or=36'# BSD系exportLSCOLORS=GxgxdxbxCxegedabagacad# TAB補完時に色表示
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}

ここにあるテストスクリプトで確認すると、こんな感じの色になります。

image.png

TAB補完強化

TAB補完の強化設定です。

~/.zsh/init/80_others.zsh
# ファイル名補完時、大文字/小文字を区別しない
zstyle ':completion:*' matcher-list '''m:{a-z}={A-Z}''+m:{a-z}={A-Z}'

comp.gif

~/.zsh/init/80_others.zsh
# "kill [TAB]" でプロセスIDを補完する
zstyle ':completion:*:processes'command"ps au"
zstyle ':completion:*:processes' menu yes select=2

kill.gif

~/.zsh/init/80_others.zsh
# オプション補完時の、オプション/説明のセパレータ
zstyle ':completion:*' list-separator '-->'

ls.gif

区切り文字設定

Ctrl+Wで単語を消すとき等の区切り文字を設定します。

~/.zsh/init/80_others.zsh
zstyle ':zle:*' word-chars ' /=;@:{}[]()<>,|.'
zstyle ':zle:*' word-style unspecified

cdコマンド省略

ディレクトリ移動のたびにcdなんて打ってられないので、auto_cdを有効にして、ディレクトリ名のみで移動できるようにします。
上記のファイル名補完と合わせると、かなり楽になります。

~/.zsh/init/80_others.zsh
setopt auto_cd

Shell内のVimで Ctrl + SCtrl + Qを使用可能にする

GVimでは問題ないのですが、Shell内でVimを立ち上げるとCtrl + SCtrl + Q等のキーバインドがShellに食われて使用できなくなります。
以下の設定でそれを抑制できます。

~/.zsh/init/80_others.zsh
stty -ixon

zmv有効化

解説は他サイトに譲りますが、mvコマンドをzshで拡張したzmvが超便利なので有効化しておきます。

~/.zsh/init/80_others.zsh
autoload -Uz zmv

参考: zsh の zmv を使って簡単に複数ファイルを一括リネームする

~/.zsh/init/90_visual.zsh

見た目の設定を書いています。

プロンプト

状況に応じて、プロンプトを出し分けています。

image.png

法則は以下のとおりです。

  • ユーザー名
    • 一般ユーザ => 緑
    • root => 赤
  • ホスト名+カレントディレクトリ
    • ローカル => 青
    • リモート => オレンジ
  • 末尾記号
    • 挿入(通常)モード => >
    • コマンドモード => |
  • カレントディレクトリの深さ
    • 5より浅い場合 => そのまま表示
    • 5以上深い場合 => 末尾の3つのみ表示、それ以前は...で省略
~/.zsh/init/90_visual.zsh
color_red="%{^[[38;5;196m%}"color_green="%{^[[38;5;046m%}"color_blue="%{^[[38;5;045m%}"color_orange="%{^[[38;5;202m%}"color_gray="%{^[[38;5;242m%}"color_end="%{^[[0m%}"case${UID} in# root0)PROMPT_USER="${color_red}%n${color_end}";;# other
    *)PROMPT_USER="${color_green}%n${color_end}";;esacif[ -n "${REMOTEHOST}${SSH_CONNECTION}"];then# remote connectionPROMPT_PATH_COLOR="${color_orange}"else# localPROMPT_PATH_COLOR="${color_blue}"fiPROMPT_PATH="%(5~,.../%3~,%~)"PROMPT_STRING="${PROMPT_USER}@${PROMPT_PATH_COLOR}%m:${PROMPT_PATH}${color_end}"function zle-line-init zle-keymap-select {case$KEYMAP in
        vicmd|visual)SUFFIX="|";;
        *)SUFFIX=">";;esacPROMPT=$'\n'"${PROMPT_STRING}${SUFFIX} "
    zle reset-prompt}

zle -N zle-line-init
zle -N zle-keymap-select

右プロンプト表示

ターミナル番号と時間を表示しています。

~/.zsh/init/90_visual.zsh
RPROMPT="${color_gray}%y [%D{%m/%d} %*]${color_end}"

~/.zsh/zplug.zsh

zplulg/zplugで管理するプラグインのリストです。

~/.zsh/zplug.zsh
if[[ ! -e ~/.zplug/init.zsh ]];then
    git clone https://github.com/zplug/zplug ~/.zplugfisource ~/.zplug/init.zsh

zplug "zplug/zplug"# コマンドに色をつける
zplug "zsh-users/zsh-syntax-highlighting", \
    defer:2# cd便利化
zplug "b4b4r07/enhancd", \
    use:init.sh# HTTPステータスコードの確認に便利
zplug "b4b4r07/http_code"# インタラクティブフィルタ
zplug "jhawthorn/fzy", \
    as:command, \
    rename-to:fzy, \
    hook-build:"make && sudo make install"# historyからコマンドをサジェストさせる
zplug "zsh-users/zsh-autosuggestions"if[[$OSTYPE== *darwin* ]];then# GitHub 操作をshellから可能にする
    zplug "github/hub", \
        from:gh-r, \
        as:command, \
        use:"*darwin*amd64*"fi

auto_cd 時も enhancd の候補に追加する

b4b4r07/enhancdは、過去に移動したディレクトリの候補リストからインタラクティブに選択し、移動できるプラグインです。
大変便利なのですが、上述のauto_cdを使ってディレクトリ移動した際は候補リストに挿入されないようなので、zsh-hookを使用して無理やり突っ込んでいます。

~/.zsh/zplug.zsh
if zplug check --verbose "b4b4r07/enhancd";then
    add-zsh-hook chpwd __enhancd::cd::afterfi

Tmux

~/.tmux.conf

よくローカル/リモートでTmuxを2重に立ち上げて作業をしているのですが、設定ファイル内で条件分岐等を行う術が無いようなので、ローカル用とリモート用でファイルを分けています。
実際に使うときは、~/.tmux.confをそれぞれに対するSymlinkとすることで、リネームの手間を省いています。

# ローカル
~/.tmux.conf  ->  ~/.dotfiles/.tmux.conf# リモート
~/.tmux.conf  ->  ~/.dotfiles/.tmux.remote.conf

下の画像は、ローカルTmuxのウィンドウでタブを3つ開き、そのうち1つのタブでサーバにsshして、サーバ内のTmuxでまたタブを3つ開いている様子です。

tmux.png

キーバインド

ローカル/リモートでプレフィックスキーが被らないようにしています。

~/.dotfiles/.tmux.conf
set-option -g prefix C-x
bind-key C-x send-prefix
~/.dotfiles/.tmux.remote.conf
set-option -g prefix C-r
bind-key C-r send-prefix

ローカル/リモートでステータスバーの色変更

zshのプロンプトと同様に、Tmuxのステータスバーも色分けをしています。
色味も統一して、青系とオレンジ系にしています。

~/.dotfiles/.tmux.conf
set-option -g status-left "  #[bg=colour021,fg=white] Host:#h #[bg=colour027,fg=white] Session:#S #[bg=colour033,fg=black] Window:#W(#P) #[bg=default,fg=default]"
set-option -g status-right "#(tmux-network)#[bg=colour021,fg=white] %Y-%m-%d (%a) %H:%M:%S #[bg=default,fg=default]"
~/.dotfiles/.tmux.remote.conf
set-option -g status-left "  #[bg=colour202,fg=black] Host:#h #[bg=colour208,fg=black] Session:#S #[bg=colour172,fg=black] Window:#W(#P) #[bg=default,fg=default]"
set-option -g status-right "#(tmux-network)#[bg=colour202,fg=black] %Y-%m-%d (%a) %H:%M:%S #[bg=default,fg=default]"

ネットワーク状況を表示 (ローカル/リモート共通)

以前 Cygwinでネットワーク状況を表示する記事を書きましたが、その後macOSにも対応しています。OSで分岐させて、こちらを参考にスクリプト(tmux-network)を修正しました。

~/.tmux.conf
set-option -g status-left-length 60
set-option -g status-right-length 60
set-option -g status-left "  #[bg=colour202,fg=black] Host:#h #[bg=colour208,fg=black] Session:#S #[bg=colour172,fg=black] Window:#W(#P) #[bg=default,fg=default]"
set-option -g status-right "#(tmux-network)#[bg=colour202,fg=black] %Y-%m-%d (%a) %H:%M:%S #[bg=default,fg=default]"

おわり

記事を書くにあたって、自分でも忘れていた設定を思い出したり、不要な設定を削除する等、いろいろ整理できてよかったです。

【追補】Cygwinインストール革命 (Mac/Linuxユーザーに朗報。Windows上で tmux(端末多重化ソフト) や vim が使える環境が3分で構築できます!emacs, git や Xサーバーも追加インストール可能)

$
0
0

この記事は、『Cygwinインストール革命 (Mac/Linuxユーザーに朗報。Windows上で tmux(端末多重化ソフト) や vim が使える環境が3分で構築できます!emacs, git や Xサーバーも追加インストール可能)』に対する最新・追加情報です。

1. OSのビット数自動判定の追加

バッチファイル内の CYG_BITS の指定を以下のようにすることで 32bit Windows では 32bit Cygwin が、64bit Windows では 64bit Cygwin が自動的にインストールされるようになりました。

set CYG_BITS=auto

2. Emacs のウィンドウ間移動について

tmux パッケージをインストールした場合には

「Shift+矢印キー(Shift↑ Shift↓ Shift← Shift→)でペイン間移動」ができます。
「Ctrl+矢印キー(Ctrl↑ Ctrl↓ Ctrl← Ctrl→)でペインリサイズ」ができます。

という旨を説明していましたが…

Emacs については
「Alt+矢印キー」または「Esc+矢印キー」でウィンドウ間の移動ができるように site-start.el に設定が書き込まれるようになっています(が説明を書いていませんでした)。emacs-w32 をウィンドウモードで起動した場合には、マウスクリックによるウィンドウ移動が可能ですが、コンソールモードでは C-x oを繰り返し押すことになり、移動方向も指定できませんので特に役に立ちます。

Alt+矢印キーによる Emacs のウィンドウ間移動は、Emacs単体でも役に立ちますが、tmux でペインの移動(Shift+矢印)やペインのリサイズ(Ctrl+矢印)をしながら、ペイン内で開いたコンソールモードの Emacs の中でウィンドウ分割した場合でも tmux 用のキー操作と干渉することなくウィンドウ移動することができるように意図(設計)されています。

3. Emacs のウィンドウサイズ自動調整について

Emacs のウィンドウを C-x 2 で上下に分割した後に、どちらかのウィンドウをさらに C-x 2 で分割すると、2分の1の高さのウィンドウが一つと4分の1の高さのウィンドウが2つできてしまいますが、これら全部を3分の1の高さに(均等に)そろえるコマンドとして M-x balance-windows があります(ちなみに、縦分割・横分割の両方に対応しています)。このコマンドは標準では C-x +にバインドされていますが、日本語キーボードでは +を入力するのに Shiftキーを 押さなければならないので C-x <kp-add>でも M-x balance-windows が起動できるように site-start.el に設定が書き込まれるようにしています(が説明を書いていませんでした)。 (<kp-add>はテンキー上の + キー)

以上です

Cygwinインストール革命 (Mac/Linuxユーザーに朗報。Windows上で tmux(端末多重化ソフト) や vim が使える環境が3分で構築できます!emacs, git や Xサーバーも追加インストール可能)』に情報を追加するとごちゃごちゃするので、別記事として整理した上で上記情報を別記事の方に組み込みます。
おかげさまで『Cygwinインストール革命 (…)』が当方の記事の中で一番アクセスの多い記事となっています。ありがとうございます。

vimでバッファの内容をコマンドとして実行する

$
0
0

こんにちは、アイスタイルアドベントカレンダー23日目を担当します塚本です。
今年は簡単なvimネタです。

僕はvimをコーディングの他、何かのコマンドの標準出力から新たなコマンド作るのに利用しています。

知っているとほんのり便利な小技だと思いますので、ありがちなユースケースに沿ってご紹介します。

コマンドを組み立てる

極端な例ですが、例えばgitでバージョン管理しているファイルに対して下記のように変更があったとしましょう。
7c9aec7332e49cc58a476fe8ad0c86e2.png

この時、特定のファイルだけをステージングするには一つ一つ git add [ファイル名]するかgit add -p .すれば良いですが、今回はvimを使ってみます。

まずはgit status の標準出力をvimで受け取ります。vim -とすることで標準入力をバッファに取り入れることができます。

git status | vim -

a0a0b9f6afa2cf918f33a8ea79f6f018.png

次にステージングしたいファイル名だけを残し、余分な行をすべて消します。短形選択やglobalコマンドが役に立つでしょう。
2f5ec37e6afbe6a12e473903d1d809d0.png

ここから更にctrl+jを複数回実行、行頭にgit addを付けることでコマンドを組み立てます。
b73068ef5f59b8ea9a0873f4bd003772.png

バッファの内容をシェルで処理する

この状態で :%!shすると目的のファイルがステージングされます。
19143777240f953266db2e4be5e35f11.png

!コマンドは指定範囲の内容を外部のコマンドを使って処理するコマンドです。{範囲}!{外部コマンド}とすることで指定された範囲を外部のコマンドで処理することが出来ます。

この例では!コマンドでバッファの内容をシェルの標準入力に渡し、実行しているわけですね。

!コマンドに関してはちょうど今年のvimアドベントカレンダーで解説されている方がいらっしゃいました。詳しくはこちらをどうぞ!
Vimと外部コマンドをつなぐ!コマンド(仮称)

まとめ

標準入力をvimの強力な編集機能で編集し、新たなコマンドとして実行する。地味ですが結構色々応用できそうな気がしませんか?

今回は極端な例でご紹介しましたが、僕は他にも外部APIへのリクエストログを加工してcurlコマンドを作成する等の用途で利用しています。

是非他にも色々な活用法を探してみてください。


Unityのコード編集にVimを使ってみた

$
0
0

初めに

CYBIRDエンジニア Advent Calendar 24日担当の@koki_yamadaです。新卒でCYBIRDに入社して1年目のまだまだ半人前のエンジニアです。
23日は@ntrvさんの GoでZabbixを爆速にしたかった でした。
Go言語、人気ですよね。私もマスターしたいです。

さて、私は普段業務でUnityを使用しているのですが、標準で用意されているIDEのMonoDevelopが、私の環境では頻繁に落ちてします。
なので、スクリプト編集用の新しいエディタとしてNeovimを使った環境を構築することにしました。
今回はその時の導入記録を公開します。

環境構築

今回導入するもの

OSは macOS Sierra です。

Neovimのインストール

Homebrewを使用してインストールします

$ brew install neovim

簡単ですね。

dein.vimのインストール

プラグインの管理ツールとしてdein.vimを使用します。

このプラグインはVim界で有名なShougoさんが開発されています。
'Dark powered Vim/Neovim plugin manager' らしいです。かっこいい

readmeによるとインストールするディレクトリはどこでも良いようなので、今回は例として候補にある ~/.cache/dein にインストールしました。

$ curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
$ sh ./installer.sh ~/.cache/dein

dein.vimの設定

Neovimの設定ファイルはVimと違い ~/.config/nvim/init.vim に配置されており、ここにdein.vimの設定を追加します。
今回は後述するTOMLファイルを使用するために、こちらの設定を参考にしました。

init.vim
if&compatiblesetnocompatibleendif" dein.vimインストール時に指定したディレクトリをセットlet s:dein_dir = expand('~/.cache/dein')" dein.vimの実体があるディレクトリをセットlet s:dein_repo_dir = s:dein_dir . '/repos/github.com/Shougo/dein.vim'" dein.vimが存在していない場合はgithubからcloneif&runtimepath!~# '/dein.vim'if!isdirectory(s:dein_repo_dir)
    execute '!git clone https://github.com/Shougo/dein.vim' s:dein_repo_direndif
  execute 'set runtimepath^=' . fnamemodify(s:dein_repo_dir,':p')endifif dein#load_state(s:dein_dir)call dein#begin(s:dein_dir)  " dein.toml, dein_layz.tomlファイルのディレクトリをセットlet s:toml_dir = expand('~/.config/nvim')  " 起動時に読み込むプラグイン群call dein#load_toml(s:toml_dir . '/dein.toml', {'lazy': 0})  " 遅延読み込みしたいプラグイン群call dein#load_toml(s:toml_dir . '/dein_lazy.toml', {'lazy': 1})call dein#end()call dein#save_state()endiffiletype plugin indent onsyntax enable" If you want to install not installed plugins on startup.if dein#check_install()call dein#install()endif

TOMLファイルを作成する

dein.vimでは管理するプラグインのリストをTOML形式の外部ファイルから取得することができます。
起動時にプラグインを読み込む場合はdein.toml、特定の条件で読み込む場合はtoml:dein_lazy.tomlにプラグインを追加します。
今回は上記の設定で指定したように ~/.config/nvim 配下にtomlファイルを配置します。

dein.toml
[[plugins]]repo="Shougo/dein.vim"

repoにはプラグインのGithubのリポジトリ名を指定します。

deoplete.nvimのインストール

VimにIDEのような入力補完機能を追加してくれるプラグインです。
ちなみに、このプラグインもShougoさんが開発されています。

このプラグインはPython3が必須となるので先にインストールしておきます。

$ brew install python3
$ pip3 install neovim

init.vimに以下を追加してNeovimでPython3が使えるようにします。

init.vim
letg:python3_host_prog ='/usr/local/bin/python3'

一度Neovimを起動してPython3が有効になっているか確認。

$ nvim
:echo has('python3')

1と表示されたらOK

dein_lazy.tomlに以下の項目を追加します。

dein_lazy.toml
[[plugins]]repo="Shougo/deoplete.nvim"hook_source="let g:deoplete#enable_at_startup = 1"on_i=1

hook_sourceはプラグインが読み込まれる直前に実行されます。
on_iにはvimのインサートモード時にプラグインを起動したい場合に1を指定します。

omnisharp-vimのインストール

C#の補完機能を追加するプラグインです。

OmniSharpは補完候補を提供するサーバーを立て、エディタとサーバー間で通信を行うことで補完表示する仕組みとなっています。
このサーバーはC#で書かれているのでmonoが必要です。

omnisharp-vimの方はPython2が必要になりますのでインストールします。
方法はPython3の場合と同じです。

$ brew install python
$ pip2 install neovim
init.vim
letg:python_host_prog ='/usr/local/bin/python2'
$ nvim
:echo has('python')

こちらも1と表示されたらOKです。

dein_lazy.tomlに以下の項目を追加します。

dein_lazy.toml
[[plugins]]repo="OmniSharp/omnisharp-vim"on_ft=["cs"]build="xbuild server/OmniSharp.sln"

on_ftにはプラグインを起動するファイルタイプを指定します。
今回はC#のソースコードファイルを開いた時に起動したいので、"cs"と指定しています。

サーバーをビルドする必要があるので、buildにはビルドするコマンドを指定しています。

OmniSharp用ソースをインストール

deopleteでOmniSharpの補完を表示するにはOmniSharp用のソースが必要になります。
deopleteとOmniSharpの橋渡しをしてくれるようなものです。

dein_lazy.tomlに以下の項目を追加します。

dein_lazy.toml
[[plugins]]repo="Robzz/deoplete-omnisharp"on_source=["deoplete.nvim"]

on_sourceは別のプラグインが読み込まれた時に一緒に読み込みたい時に指定します。
今回は、deoplete.nvimと同時に読み込むようにしました。

NeoVim起動

最後にNeoVimを起動します。
起動と同時にdein.vimのインストール機能で先ほど指定したプラグインがインストールされます。

使い方

OmniSharpサーバーを起動します。
パラメータにUnityのソリューションファイルを指定します。

cd ~/.cache/dein/repos/github.com/OmniSharp/omnisharp-vim/server/OmniSharp/bin/Debug
mono OmniSharp.exe -s ~/nvim_test/nvim_test.sln

あとは、NeoVimでプロジェクト内の.csファイルを開くだけです。
コードを入力すると補完機能が働いてくれます。

まとめ

使ってみた感想ですが、軽快に動作してくれます。
私の環境ではIDEを使っていると結構動作が重くなったりするのですが、そういったこともなく快適です。
Unityのライブラリも自動的に読み込んでくれるので、問題なく補完できました。

Unityを使用している方は是非、試してみてはどうでしょうか?

CYBIRD エンジニア Advent Calendar明日は @daisuke-senmyouさんの 恋愛ゲームにおけるキャッシュ戦略 です!

Mac で Vim ベースの JavaScript 開発環境を整える (その 1)

$
0
0

冬休みに入ったので、やろうやろうと思って放置してた、アプリ作りをしようと思い、結局、開発環境を新たに整えるのに時間を割いてて、アプリ作りをしていない今日この頃。
年取るにつれ、色々覚えが悪くなっているので、設定した内容をメモ。

きっかけ: Expo でアプリ開発を試したい

React Nativeでも手軽にアプリ開発感があったんですが、さらに手軽さがましそうな、Expoを勉強しようと思い、Node JS の開発環境を、ちゃんとしようと思い立ったのがきっかけ。
Atom + Nuclideを試してましたが、Vim バインディングの完成度に満足できず、やめました。他も、Vim 使ってた便利さに勝るメリットは得られなさそう。
Expo は、expo initでプロジェクトを作成して expo startすると QR コードが出てきて、Expo のアプリで QR コードを読み込めば、すぐに iPhone 上でアプリを実行しながら、コード編集、リロードの流れで開発できる感じ。スタンドアロンのアプリとしてパブリッシュも可能。Expo 用の API があるが、ほば React Native の開発的な感じ。ドキュメントも丁寧。
何より XCode、Android Studio を使わなくても、アプリを作れそうな感じが素敵。XCode を使うためには、Mac 一択だった縛りがなくなるの
ただ、現状、バックグラウンドの処理実行など、色々制約があるので注意。ただ、開発は活発そうだから、制約も、時が経てば減っていきそう。

exp start を実行した時に表示される QR コード

JS の Vim 開発環境は、こちらの記事の内容を試してみることに。

エディタ (Neovim、VimR)

Neovimを使うことに決めた。Neovim は、今では使わなくなった機能を消したり、今まで、ごく限られた人しか Vim のコードを把握できてなかったのを、いろんな人で開発できるようにソースコードをリファクタリングしてる Vim といった感じみたい。また、プラグインを、いろんな言語で作れるみたい。標準で、:terminalで Vim ないでターミナルエミュレータを開けるのも良さそう。
:terminalがあるので、GUI の Vim を使おうと思い、VimRをインストール。Swift を中心に使ってる OSX 用の Vim GUI で、元は MacVim を使ってたけど、今は、NeoVim を使ってるとのこと。

Neovim のインストール

Homebrew で入れるだけ。

brew install neovim

https://github.com/neovim/neovim/wiki/Installing-Neovim

VimR

ダウンロードして、解凍するだけ。
http://vimr.org/

:terminal の設定

ターミナルエミュレータ操作後は、そのままだと、Esc でコマンドモードに戻れない。戻れるようにするために、~/.config/nvim/init.vimに、以下を追加 (参考)。

tnoremap <silent><ESC><C-\><C-n>

あと、ターミナルエミュレーターでは、行数表示は消したいので、以下を追加 (参考)。

au TermOpen * setlocalnonumbernorelativenumber

色変え

MacVim を使ってる時は、そのまま使ってたんですが、せっかく GUI を使うので、少しオシャレ感がでる colorscheme を使うことに。background が dark の時の色が良さそうだったので、SOLARIZEDを使うことにしました。以下の画像は、SOLARIZED の GitHub より拝借。

SOLARIZED の GitHub より拝借

ただ、そのまま altercation/vim-colors-solarizedを使うと Neovim では動かないので、注意が必要。

frankier/neovim-colors-solarized-truecolor-onlyを使えば大丈夫。詳細は、こちらに書いてる。

vim-plug

Medium の記事に沿って、vim-plugをインストール。インストールは、curlでレポジトリのデータを落としてくるだけで簡単。
プラグインのインストールは、init.vim に、いれたいプラグインの GitHub のレポジトリ名を書いて、:PulgInstallするだけ。チュートリアルは、こちら

call plug#begin()
Plug 'w0rp/ale'call plug#end()

init.vim

とりあえず設定した init.vim。プラグインは、設定途中。

~/.config/nvim/init.vim
setincsearchsethlsearchsetts=4setetsyntax enableset termguicolorssetbackground=darkcolorscheme solarizedsetbackspace=indent,eol,startsetclipboard+=unnamedplussetnumbersetencoding=utf-8setfencs=utf-8,iso-2022-jp,sjis,euc-jpau TermOpen * setlocalnonumbernorelativenumber
tnoremap <silent><ESC><C-\><C-n>call plug#begin()
Plug 'w0rp/ale'call plug#end()

やりのこし

JS 開発用の、プラグインの設定。

Lambda 関数に俺はなる

$
0
0

この記事は Vim Advent Calendar 2017の25日、最終日の記事です。その1その2、多くの方に参加頂きました。参加頂いた皆様、本当にご苦労様でした。そして完走おめでとうございます。

今年のおさらい

今年は Vim の国際カンファレンス Vimconf2017も開催され、未だ衰えを知らない Vim の人気を再認識する年になったと思っています。

Vim バージョン 8.0 がリリースされたのが去年の9月の事。約1年くらいですが、最近になってようやく皆さんに認知されてきたのかなとも思います。Vim 8.0 の新機能を今一度おさらいしておくと、大きくは以下の物がありました。

  • チャネルによる非同期 I/O のサポート (Channel)
  • ジョブ (Job)
  • タイマー (Timer)
  • パーシャル (Partial)
  • ラムダ (Lambda)、クロージャ (Closure)
  • パッケージ (Packages)

引用: http://vim-jp.org/blog/2016/09/13/vim8.0-features.html

今考えると、これらが無い頃に Vimmer はいったいどうやって Vim script を書いていたんだろうと思うくらい重要な機能が入ったと思っています。

Lambda は凄い

特に僕が気に入っているのが Lambda です。これは元々、僕が sort関数の引数で比較演算の指定方法が面倒で、どうしても欲しくて作り始め、さらに kaoriya さんや vim-jp の皆さん、そして
k-takata さんに後押しして貰って入れて貰いました。

例えば辞書の配列を sortするには以下の様に書く必要がありました。

function! s:by_name(lhs, rhs)returna:lhs.name <a:rhs.nameendfunctionlet foo = [
\ {"name": "alice","age": 16},
\ {"name": "john","age": 14},
\ {"name": "bob","age": 13},
\]
echo sort(foo,function('s:by_name'))

比較処理を書くだけの為にいちいち関数を定義しないといけなかったのです。これが Lambda を使うと以下の様に簡単に書く事が出来るのです。

let foo = [
\ {"name": "alice","age": 16},
\ {"name": "john","age": 14},
\ {"name": "bob","age": 13},
\]
echo sort(foo, {lhs, rhs -> lhs.name < rhs.name})

Lambda は式しか書けません。例えば変数に値を代入したり echoコマンドなど、文は直接書けないのです。ただし方法がない訳ではありません。例えばタイマーを使い、1秒に1回、時刻を表示するのであれば以下の様に execute()関数を使う事で実現できます。

let s:timer = timer_start(1000, {t->
\ execute('echo strftime("%c", localtime())','')},
\ {'repeat': -1})

さらにカウントアップする数字を表示するのであれば以下の様に List を使います。

let s:count =0let s:timer = timer_start(1000, {t-> [
\   execute('let s:count += 1'),
\   execute('echo s:count',''),
\ ]}, {'repeat': -1})

Lambda と exechte()関数があればつまりはなんでも出来る訳です。

Lambda でもやれる

例えば List から Dict を作りたい時、皆さんはどうやっているでしょうか? ['key1', 'value1', 'key2', 'value2', ...]から {'key1': 'value1', 'key2': 'value2', ...}を作るといった場合です。関数を作りますか?いえ、出来るんです。Lambda でも。

letl= [['key1','value1'], ['key2','value2'], ['key3','value3']]
echo call({x,y-> [map(x,'execute("let y[v:val[0]]=v:val[1]")'),y]}, [l,{}])[1]

call()関数は第一引数に関数、第二引数に関数への引数を List で渡します。今回であれば対象の List と空の Dictionary {}を渡しています。Lambda 関数の引数 x には List が、y には {}が格納されます。map()関数は List と Dictionary のどちらでも引数として取れますが、戻り値も同じ型が返ります。つまり List として引数に与えた場合は map()および call()は List を返します。そこで List と空の Dictionary を双方保持する List をコンテナとして引数として与え、call()の戻り値から [1]で Dictionary 側を参照しているのです。

簡単ですね。

Lambda でスパイラル

例えば以下の様に、外側から数字が小さくなりつつ真ん中で終了する図形を描くにはどうすれば良いでしょうか?

99  98  97  96  95  94  93  92  91  90
64  63  62  61  60  59  58  57  56  89
65  36  35  34  33  32  31  30  55  88
66  37  16  15  14  13  12  29  54  87
67  38  17   4   3   2  11  28  53  86
68  39  18   5   0   1  10  27  52  85
69  40  19   6   7   8   9  26  51  84
70  41  20  21  22  23  24  25  50  83
71  42  43  44  45  46  47  48  49  82

出典: Challenge - Print Spiral

出来ます!Lambda でも。

echo join(call({n->map(range(n),{i,x->join(map(range(i*n,i*n+n-1),{->printf("%*i ",float2nr(ceil(log10(n*n-1))),call(function({...->a:1(a:1,a:2,a:3,a:4)},[{e,n,x,y->n%2==0?(y==0?n*n-1-x:(x==n-1?n*n-n-y:e(e,n-1,x,y-1))):(y==n-1?n*n-n+x:(x==0?n*n-n-(n-1)+y:e(e,n-1,x-1,y)))}]),[n,v:val%n,v:val/n]))}),' ')})},[10]),"\n")

スパイラル

作り方はそれほど難しくありません。まず上記 dev.to のリンク先にあるコードをそのまま Vim script に移植します。

function! s:e(n,x,y)let sq =a:n * a:nifa:n%2==0ifa:y==0return sq -1-a:xendififa:x==a:n-1return sq -a:n-a:yendifreturn s:e(a:n-1,a:x,a:y-1)endififa:y==a:n-1return sq -a:n+a:xendififa:x==0return sq -a:n-(a:n-1)+a:yendifreturn s:e(a:n-1,a:x-1,a:y)endfunctionletn=10letl= float2nr(ceil(log10(n * n-1)))foryin range(n)forxin range(n)echon printf("%*i ",l, s:e(n,x,y))endfor
  echo ""endfor

次に関数を Lambda に、そして if 文を三項演算子に置き換えます。

let s:e= {n,x,y->
\  n%2==0 ? (
\    y==0 ?
\      n * n-1-x
\    : (
\      x==n-1 ?
\        n * n-n-y
\      :
\        s:e(n-1,x,y-1)
\    )
\  ) : (
\    y==n-1 ?
\      n * n-n+x
\    : (
\      x==0 ?
\        n * n-n-(n-1)+y
\      :
\        s:e(n-1,x-1,y)
\    )
\  )
\}letn=10letl= float2nr(ceil(log10(n * n-1)))foryin range(n)forxin range(n)echon printf("%*i ",l, s:e(n,x,y))endfor
  echo ""endfor

ここで1つ問題が発生します。Lambda 関数を格納した変数 s:eは再帰呼び出しを行う必要があります。つまり変数を無くすという事は再帰呼び出しが出来なくなるのです。

そこで登場するのが Vim 8.0 で入った Parcial です。

let X =function('s:foo', [1,2,3])

Parcial を使うと X()という呼び出しの際に s:fooに引数 1, 2, 3 を渡す事が出来ます。つまり部分引数として Lambda を渡す事で、funcion()の第一引数で与える関数の引数としてバインドできる事になります。

let s:e=function({...->a:1(a:1,a:2,a:3,a:4)}, [{e,n,x,y->
\  n % 2==0 ? (
\    y==0 ?
\      n * n-1-x
\    : (
\      x==n-1 ?
\        n * n-n-y
\      :
\        e(e,n-1,x,y-1)
\    )
\  ) : (
\    y==n-1 ?
\      n * n-n+x
\    : (
\      x==0 ?
\        n * n-n-(n-1)+y
\      :
\        e(e,n-1,x-1,y)
\    )
\  )
\}])letn=10letl= float2nr(ceil(log10(n * n-1)))foryin range(n)forxin range(n)echon printf("%*i ",l, s:e(n,x,y))endfor
  echo ""endfor

これで s:eが消せます。あとは for 文で回している部分を range と map で実装し直せば、上記の様に1行でスパイラル図形が表示できるという訳です。

また最後の方にある 10 を大きくすれば、お好きな N x N の図形が表示されます。

簡単ですね。

Lambda で中華料理画像うpよろしく

こんな図形はどうでしょうか?

中華料理画像うpよろしく
華@@@@@@@@@@し
料@@@@@@@@@@ろ
理@@@@@@@@@@よ
画@@@@@@@@@@p
像@@@@@@@@@@う
う@@@@@@@@@@像
p@@@@@@@@@@画
よ@@@@@@@@@@理
ろ@@@@@@@@@@料
し@@@@@@@@@@華
くしろよpう像画理料華中

出典: https://anond.hatelabo.jp/20161015194043

出来ます。Lambda かわいいよ。

echo call({s->call({s,u->join([s]+map(range(2,len(u)-1),{i->u[i+1].repeat("@",len(u)-2).u[-i-2]})+[join(reverse(u),'')],"\n")}, [s, split(s,'\zs')])}, ['中華料理画像うpよろしく'])

中華料理画像うpよろしく

簡単ですね。

Lambda でカレンダー

UNIX で calコマンドを実行すると以下の様に表示されます。

Su Mo Tu We Th Fr Sa
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

これは難しいでしょうか?いえ、出来ます。Lambda なら。

echo
\ "Su Mo Tu We Th Fr Sa\n"
\ .join(split(
\  repeat('   ', strftime('%w', localtime()-(strftime('%d', localtime())-1)*60*60*24))
\  .join(map(range(1,
\     call(
\       {y,m->
\         [31,28,31,30,31,30,31,31,30,31,30,31][m-1] +((m==2&& y % 4==0&& (y % 100!=0||y % 400==0)) ? 1 : 0)
\       }, [strftime(strftime('%y', localtime())), strftime(strftime('%m', localtime()))]
\     )), {_,x->printf('%02d',x)}),' '), repeat('.',21).'\zs'),"\n")

うるう年の計算も入っていて安心ですね。見やすくする為に \を使って改行していますが、1行にすると以下の様になります。

echo "Su Mo Tu We Th Fr Sa\n".join(split(repeat('   ', strftime('%w', localtime()-(strftime('%d', localtime())-1)*60*60*24)).join(map(range(1,call({y,m->[31,28,31,30,31,30,31,31,30,31,30,31][m-1] +((m==2&& y % 4==0&& (y % 100!=0||y % 400==0)) ? 1 : 0)}, [strftime(strftime('%y', localtime())), strftime(strftime('%m', localtime()))])), {_,x->printf('%02d',x)}),' '), repeat('.',21).'\zs'),"\n")

実行してみましょう。

カレンダー1

カレンダー2

いちいち Vim を起動するの面倒だという人は、シェルで以下を実行すればいいのです。

$ vim --not-a-term --cmd 'echo "Su Mo Tu We Th Fr Sa\n".join(split(repeat('\''   '\'', strftime('\''%w'\'', localtime() - (strftime('\''%d'\'', localtime())-1)*60*60*24)).join(map(range(1, call({y,m->[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m-1] + ((m == 2 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? 1 : 0)}, [strftime(strftime('\''%y'\'', localtime())), strftime(strftime('\''%m'\'', localtime()))])), {_,x->printf('\''%02d'\'', x)}), '\'' '\''), repeat('\''.'\'', 21).'\''\zs'\''), "\n")' --cmd q > /dev/null

カレンダー3

簡単ですね。

Lambda があれば強くなれる

この様に、Lambda があれば Vim script は強くなれるのです。綺麗な図形を1行で書いて同僚に見せれば、皆が貴方を見る目も変わるはずです。みなさんもぜひ Lambda やりましょう。いや、して下さい。そして Lambda になりましょう。

Vimが本来もつ力を掘り下げる

$
0
0

注意

段取りが悪く書こうとしたことの3割程度しか書けておりません。
随時更新します。

動機

私はこれまでVimを軽量で高度なカスタマイズ可能なIDEとして使用してきました。
そのため、カスタマイズの方向性もIDEに近づける事を目指してきました。
しかし、カスタマイズを繰り返していくうちにプラグインを入れるまでもなく使用できる
Vimに本来備わっている機能群の多様さに気が付きました。

IDEの機能は、基本的に人間がするまでもなく機械的に仕事を私達が解釈し易いようにラッパーし、
ちょうどいいタイミングで自動で動作しいます。
いわば単純な作業を下請けしてくれるサポーターが常時横に居てくれるようなものと言っていいでしょう。

対してVimが提供するのはあくまでテキストを編集する機能であり、私達が任意で動作させる必要があります。
それはIDEのように人間の代わりに何かを勝手にやってくれるものではなく、
その用途を詳しく知るものが、効力を発揮する場面に用いて強力な力を発揮する
私達の手の延長といえるのではないでしょうか。

IDEではなくテキストエディタをあえてチョイスしている私たちは、これら手の延長をより深く理解することで、
特定の言語にとらわれることなく、テキストエディットを効率化することが可能です。

今回はそんなVimの側面について調べてみました。

結論

さていきなり結論ですが、この記事を読むのはいいですが

実践Vim 思考のスピードで編集しよう!

を読みましょう。貴方が本当にVim本来の機能を使って、より洗練されたエディットをしたいならば今すぐに購入すべき書籍です。
ですがそれでは記事にならないので、一応自分なりに咀嚼した内容を以下に記載します。

エディット力を高める機能

ファイル操作

Vimを使い始めの頃、GUIエディタのファイルメニューに相当するものが無いので私は相当混乱しました。
私は混乱を防ぐため、プラグインによりNERDTreeやVimFilterなどのファイラーを導入することで、
デフォルト機能を使わずにファイル操作を行っていました。
ファイラー系のプラグインはとても便利ですが、場合によっては標準のファイル操作の方がよっぽど早く操作できるときがあるのです。
あとサーバとかに入ったときにすぐ使えます。覚えておいて損はありません。

ファイルを開く

テキストエディタはテキストをエディットするプログラムなので、まずエディットの対象を開かねば話が始まりません。
ファイルを開くにはbash上でvim {file}で開きます。

しかし上記コマンドではVim起動時に指定したファイルしか開けません。
例えば貴方が100ファイルからなるプロジェクトを編集したいときにその1ファイルだけで事足りますか?
もちろん答えはNoです。

もし貴方がファイル色々触りたいときに、都度Vimを終了し、サイドVimを起動しているのであれば今すぐ:editを使ってください。
:editが長いと思う人は:eというショートカットコマンドが用意されているのでこちらを使用しましょう。
:editを使用するとVimを起動したディレクトリ(カレントディレクトリ)に存在するファイルを開くことができます。
ちなみにカレントディレクトリがどこを指しているかは:pwdで確認することが可能です。

もしもカレントディレクトリにどんなファイルがあるか解らないというのであれば、以下のオプションをセットしてみてください。
:edit <tab>というように:editの後にタブキーを押せば補完が表示されます。

:setnocompatible:setwildmenu

[ファイルを補完するGIF動画]()

補完を:setでいちいち設定せずに出したいときは.vimrcに以下を追加しておいてください

setnocompatiblesetwildmenu

なおファイルが多すぎるというときはファイルの前方と一致する文字列を打ち込めば補完候補が絞り込まれます。

相対パスでファイルを開く

さて先程はカレントディレクトリからファイルを開く方法でしたが、
もし編集したいファイルが深い階層にあったらいかがでしょうか?
例えば以下のようなディレクトリ構成があった際...

.
├── bar
│   ├── aaa
│   │   ├── xxx.html <-既に開いている
│   │   ├── yyy.html
│   │   └── zzz.html
│   └── bbb
└── foo

既にbar/aaa/xxx.htmlを開いていて、同じ階層上にあるyyy.htmlを開きたい場合どうするでしょう?
:edit bar/aaa/yyy.htmlを打ち込みますか?
いえ、それはナンセンスです。

xxx.htmlを開いている状態で:edit %:h<Tab>と押してみてください。
:edit bar/aaa/とファイルが展開されました。
これは%が現在開いているファイルのパスを意味しており、
:hが該当パスの親ディレクトリを指し示すキーワードだからです。
よって%:hを展開すればbar/aaa/という解が得られるのです。

[相対パスを開くGIF動画]()

新規にファイルを開く

先程は既存のファイルを開く方法をご紹介しましたが、
いまある既存ファイルだけでなく、新規ファイルを作成/編集するときもあります。
そんなときは:newコマンドです。そのままでわかりやすいですね。
また:newですとウィンドウを横分割して表示しますが、その他にも縦分割やタブで新規ファイルを表示する方法があります。

コマンド説明
:new新規ファイルを開く(横分割)
:vnew新規ファイルを開く(縦分割)
:tabnew新規ファイルを開く(タブ)

[新規にファイルを開くGIF動画]()

ファイルを保存する

新規作成したファイルを保存しようとして:write(:w)を実行していませんか?(私は実行してました)
Vimを覚えたての頃:wで保存できるよ。と教えられたので仕方ないかもしれませんね。
ところが:write(:w)は上書き保存のコマンドのため、新規ファイルに使用できないので注意です。
新規ファイルを保存するときは:saveを使いましょう。
なお:saveasで別名保存ができるので、ファイルコピーなどしたいときに便利です。

コマンド説明
:saveファイルを保存する
:saveasファイルを別名で保存する

なお保存先はカレントディレクトリとなるため、
相対パスで保存したいときなどには前述の%:hなんかで指定してあげてください。

ちなみに:newの時点では新しいファイルは作成されないという点についても言及しておきます。
:newは新規ファイルを作成するコマンドではなく新規バッファを作成するコマンドなのです。
バッファについては後術します。

編集し易いレイアウトを整える

Vimを始めた当初、ウィンドウやらタブやらの移動がどうにも馴染めないため、
いろんな記事で紹介されているキーバインドで押しやすくしていました。(実は最近までやってた)
<C-w>(ウィンドウ操作のPrefix)をsとか<Space>に割当したり、
gt(次のタブへ移動)をtlgT(前のタブへ移動)をthに割当したり。
ですがデフォルトをよく見てみると
キーバインドの統一感がでないとか、他のプラグインと干渉したりということがあって、
デフォルトのまま使うのが合理的だったりします。

ウィンドウを分割する

一つのウィンドウで編集に集中するのも良いですが、一つのファイルの複数箇所を見比べたり、
複数のファイルを同時に見たい場面などもあります。
そんな時はウィンドウを分割を分割しましょう。
:splitでウィンドウを横分割。:vsplitでウィンドウを縦分割できます。

コマンド短縮コマンドキーバインド説明
:split:sp<C-w>sウィンドウを横に分割する
:vsplit:vs<C-w>vウィンドウを縦に分割する

分割した後は以下のコマンドでウィンドウ間を移動しましょう。

コマンド説明
<C-w>wまたは <C-w><C-w>次のウィンドウへ移動
<C-w>j上のウィンドウへ移動
<C-w>k下のウィンドウへ移動
<C-w>h左のウィンドウへ移動
<C-w>l右のウィンドウへ移動

[ウィンドウを分割するGIF動画]()

サイズ変更は割愛します。

タブ

ウィンドウをいくつも分割してしまうと一度に表示できる領域が狭まってしまうため、
エディットに編集できなくなることがありますこんなときは<C-W>Tを押してください。
分割されたウィンドウに表示されていたファイルがタブで開かれます。

タブを開いた後で移動するには以下のコマンドを使用します。

コマンド短縮コマンドキーバインド説明
:tabnext:tabn{count}gt{count}で指定した番号のタブへ移動
:tabnext:tabngt次のタブへ移動
:tabprevious:tabpgT前のタブへ移動

[タブを開いて移動するGIF動画]()

Vimconf2017にいってvim-goの作者の話がよかったので書き記しておきます

$
0
0

この記事は、Vim2 Advent Calendar 2017 25日目の記事です。

そこまで長文でも無いです。軽くよんでください。

今年もvimconfが開催されました。vimconf2017です。今までと会場の規模もガラッと変わりまして、秋葉原のアキバホールというとても大きな会場でした。コーヒーも出て、お昼もでて、同時通訳もありまして、(日本語版はmattnさんの話がでるとみんな大好きmattnさんになってました。英語版を聞いてなかったので本当のところはどうだかしらないですが)。海外含めvimの開発者たちの話が聞けてしまうと言うとてもお得なカンファレンスです。

今回はですね。vimconf2017で発表はどれも素晴らしかったんですが、個人的に感動したのが、普段とてもお世話になっているpluginの作者の発表でした。

The Past and Future of Vim-go

こちらが発表の資料です。

vim-goの作者であるfaithの発表です。vim-goは、vimでgoを書いていたら、絶対お世話になっているだろうという。とてもすごいPluginです。

vim-go

何がすごいかといえば、そもそもPluginのセットアップとか普通割と面倒で初心者は心折れたりするんですが、GoInstallBinariesという素晴らしいコマンドにより何の苦労も無くセットアップが済みます。GoFmtとか開発していると必要なコマンドがきっちり備えられています。そして、現状このPlugin一択なのでたとえあまりvimに詳しくない人でも、適当にググるだけで使い方のサンプルとかも出てきます。Goを書きたい人が迷うこと無く開発に進んでいける。これは素晴らしいです。

このPluginの今に至るまでの過去とこれからについての発表でした。細かい内容は上記の資料の方を見てもらった方が良いと思います。

発表内容で、特に僕がすごいなと思ったところは、slideのtoo many pluginsのページ当たりからで、大量のPluginが乱立している状況を問題視したり、その後にあるべき姿(ドキュメントの不足等)をきちんと浮き彫りにした上でそれを解消して行ってるんですね。ものを作るというか、良いものをつくるというのは、こういうものなんだなという事例を見せてもらった感じでした。

前日楽しみすぎて寝れなくて遅刻するんじゃ無いかって、すごい不安だったんですが、遅刻しなくて良かったです。

ということで、vim-goみんな使いましょう。

そして、来年もvimconfあるようなので参加しましょう。

Viewing all 5692 articles
Browse latest View live


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