Home > Vim Hacks

Vim Hacks Archive

Hack #221: MacVimで半透明処理が狂う問題に対処する

問題

MacVimをお使いの方に捧げる記事です。

MacVimをはじめとするGUIのVimの特徴の一つとして、半透明具合をVimから操作できるという点があります。

transpacent vim

MacVimの場合、半透明具合は'transparency'で調整できます。0が不透明、100が完全に透明です。例えば20%の透明具合にするには、

:set transparency=20

とします。これは

:let &transparency = 20

としても同様の結果が得られます。現在の透明度の値を得たければ、変数&transparencyを参照してください。

MacVimにおける半透明処理はまだExperimentalで、Preferencesから以下のような設定を行う必要があります。

Preferences

まだExperimentalと主張していることからわかるように、半透明処理には既知のバグがあります。不特定のタイミングで、画面の一部が不透明になり、だんだんと不透明部分が全体に浸食していきます。

bug

見てのとおり、かなり深刻な問題かつ数多くのユーザに確認されつつも、この問題は数年間に渡り解決されないまま今に至っております。

対処

実は、オプション値'transparency'がいつのまにか勝手に書き変わっています。これを再び書き換えて<C-l>を打鍵するだけで、うまく再描画されます。

:set transparency=10

ただ、それ描画が狂う時点の前にどんな'transparency'を設定していたかその具体的な忘れている場合がほとんどでしょう。普段からset transparencyするときに常に同時にg:transparencyなどの変数にその値を格納しておき、そしてその値に戻ることができるようにKey mappingを設定するのがよいでしょう。

例として、筆者は半透明度の変更と、半透明再描画をそれぞれ以下のように割り当てています。すべて、~/.vimrcではなく~/.gvimrcです。

  • より透明にする: ↑

      nnoremap <up> :<C-u>call <SID>relative_tranparency(5)<Cr>
      inoremap <up> <C-o>:call <SID>relative_tranparency(5)<Cr>
    
  • より不透明にする: ↓

      nnoremap <down> :<C-u>call <SID>relative_tranparency(-5)<Cr>
      inoremap <down> <C-o>:call <SID>relative_tranparency(-5)<Cr>
    
  • 再描画: <esc><esc

      nnoremap <Esc><Esc> :<C-u>let &transparency = g:transparency<Cr><C-l>
    

ただし以下の関数を同じファイル内で定義しておくものとします。

function! s:relative_tranparency(diff)
  let &transparency = a:diff + &transparency
  let g:transparency = &transparency
endfunction

補足

筆者はもともと<esc><esc>:set nohlsearchの副作用を持たせるkey mappingをしていました。これを組み合わせため、筆者の設定は以下のようになっています。

    nnoremap <Esc><Esc> :<C-u>set nohlsearch<Cr>:let &transparency = g:transparency<Cr><C-l>
ujihisa

Hack #220: コマンドラインからコピペする

コマンドラインに何か赤いハイライトで出力されたけど 見えなくなってしまった場合、:messagesあるいは 短縮形である:mesと入力すれば見ることができます。 しかしそのエラーを何か別の場所(twitter,gist,…)に コピペするにはどうすればいいのでしょうか?

解決策1: gvimでマウスで選択し<C-y>を使う

gvimでのみ使える技です。

:mesと入力したあと、 図のようにマウスで選択して<C-y>を押します。 something wrong

解決策2: :redir > {file}を使う

gvimでも端末版vimでも使えます。

:redirというExコマンドを使うと、 Exコマンドの出力をキャプチャーし、 ファイルや変数に保存できます。

:redir > messages
:silent messages
:redir END

これでmessagesというファイルに出力結果が保存されます。 :silentはつけると:messagesの出力をコマンドラインに出力しません。 つけなくてもファイルの中身に変わりはありませんが、 今回はコマンドラインに出力されてもうっとうしいだけなので付けただけです。

tyru

Hack #219: Gitを使う2 – Fugitive.vim

Vim の中で Git を快適に使うためのプラグインがいつくかあります。 その中から Time Pope さん作の Fugitive.vim を紹介します。

motemen さんの git.vim については Hack #67: Gitを使う を参照してください。 今回の記事は対比のためフォーマットを似せています。

インストール

plugin は github から入手可能です。 https://github.com/tpope/vim-fugitive

また Vundle でもインストール可能です。

:BundleInstall tpope/vim-fugitive

使い方

以下のコマンドが定義されます。

  • Git arg: git コマンドと同様の機能を有し、自分で定義した alias も使用出来ます。

Git コマンドを使用した場合は結果を pager に表示します。 以下のコマンドを使用すると結果は状況に応じてバッファ内、quickfix list 等に表示されます。 また、diff を vimdiff で表示したり、blame もハイライトされた状態で表示されたりと、それだけでも利用価値があると筆者は考えます。

  • :Gdiff[ rev]: git diff[ --cached] {編集中のファイル}
  • :Gstatus: git status
  • :GlLog[ rev]: git log {編集中のファイル}
  • :Gwrite: git add {編集中のファイル}
  • :Gread[ rev]: git checkout {編集中のファイル}
  • :Gcommit: staged なファイルがあれば git commit なければ git status
  • :Gblame[ rev]: git blame {編集中のファイル}

上記以外にも Git を扱ううえで有用なコマンドが多数定義されます。:help fugitive を参照してください。

Gstatus 時の挙動について

:Gstatus を使用すると、Window が split され git status の結果が表示されます。

定義されたいくつかの mapping を利用することで、更に便利になります。

  • : カーソル下にあるファイルを edit
  • -: カーソル下にあるファイルを git add
  • p: カーソル下にあるファイルを git add -p
  • D: カーソル下にあるファイルを git diff[ --cached]
  • C: git commit

応用

筆者は以下のように mapping して利用しています。

" for Fugitive {{{
nnoremap <Space>gd :<C-u>Gdiff<Enter>
nnoremap <Space>gs :<C-u>Gstatus<Enter>
nnoremap <Space>gl :<C-u>Glog<Enter>
nnoremap <Space>ga :<C-u>Gwrite<Enter>
nnoremap <Space>gc :<C-u>Gcommit<Enter>
nnoremap <Space>gC :<C-u>Git commit --amend<Enter>
nnoremap <Space>gb :<C-u>Gblame<Enter>
" }}}

参照資料

Sixeight

Hack #218: Vimでsshに接続する

問題

最も普及しているシェルvimshellを用いて、ローカルなマシン上で快適な環境を堪能していることと思います。neocomplcacheなどのもつファイル名補完などと見事な連携を遂げています。またvimshellの内部コマンドvimは、vimshellを動作させているVim上の別バッファにファイルを開くというつくりになっておりますが、これがまた見事に、昔懐かしのzshやbashなどと似た動作をすることで、非常に容易に移行できたことに感動した方は多いでしょう。

しかしこれらはsshを介することで本来の実力を活かすことができず、残念な思いをすることになります。sshを使うためにはvimshellのiexeコマンドを用いることになります。あとはもうvimshellはiexeでssh経由先のサーバのシェルであるbashやzshを叩くだけの存在になってしまいます。そして接続先で誤ってvimコマンドなどを発行してしまうと・・・あとはもう悲惨の一言です。

解決

vimshell-sshという、今日完成したばかりのプラギンを用います。

このプラギンはコマンドも関数も提供せず、ただ、あなたがvimshellのiexeでsshコマンドを用いたときの、接続先でのvimコマンドの挙動のみを上書きします。

  • 従来のiexe ssh上でのvimコマンド:
    • 接続先サーバでvimのプロセスを立ち上げ、その出力をvimshell上で表示しようとする。
  • 上書きされたiexe ssh上でのvimコマンド:
    • コマンド発行時点では接続先サーバでは何もおこらない
    • こっそりとscpでいま接続しているサーバに新規接続、引数のファイルを取得する
    • ファイルをダウンロードできればそれを、なければ空のものを、別バッファに分割して表示する
    • そのバッファで保存を行うと、こっそりとscpで中身をアップロードする

いかがでしょうか。また、隠れたメリットとして、

  • 接続先サーバにvimがインストールされている必要がない
  • そのため~/.vimrcのコピーは不要。プラギンのインストールも不要。
  • vim自体が手元で動作するため、補完などで画面描画書き換えが頻繁に発生するものの、通信速度に関係なく快適な操作が可能

ということが挙げられます。

今後の課題

vimshellのiexe ssh上で、neocomplcacheのファイル名補完が行われません。これは将来誰かが開発するであろうneocomplcache-vimshell-sshによって解決されるでしょう。また、vimshell-sshへのパッチという形で解決するかもしれません。

vimとsshの連携の今後に期待されます。

ujihisa

Hack #217: 横幅が長いコードをハイライトする

表示幅に入りきらないコードは読む人に必要以上にストレスを与えます。
プログラミングの70割は読む時間だといいます。
読む人にストレスを与えないよう、
横幅が長いコードを書かないようにするにはどうすればいいでしょうか?

解決

Vim 7.3 *1 では 以下を.vimrcに入れると80文字以上長い列をハイライトしてくれます。

set textwidth=80
if exists('&colorcolumn')
    set colorcolumn=+1
endif

どのファイルに対してもハイライトされてしまうため多少うっとうしいです。
この問題は.vimrcで'textwidth'を0に指定しておき、
コードを書く時のみ:setlocal textwidth=80とすることで回避できます。

set textwidth=0
if exists('&colorcolumn')
    set colorcolumn=+1
    " sh,cpp,perl,vim,...の部分は自分が使う
    " プログラミング言語のfiletypeに合わせてください
    autocmd FileType sh,cpp,perl,vim,ruby,python,haskell,scheme setlocal textwidth=80
endif
tyru

Hack #216: 消してしまった直前のメッセージを再表示する

Vim でプラグインなどが下部に表示されたメッセージを読まずに消してしまった場合はどうすればいいでしょう。:echomsg で表示されていた場合は履歴に記録されているので、:messages を実行すれば表示できます。しかし、常に :echomsg が使われているとは限りません。

g<

g< を使うことで、最後に表示されたメッセージを再表示させることができます。ただし、本当に最後に表示されたものしか表示できないので注意してください。例えば、:messages を1度実行してしまうと、g< を押しても :messages の結果が表示されてしまいます。

また、メッセージを途中で q で閉じていた場合は、g< を使っても表示されたところまでしか表示されません。

thinca

Hack #215: Vundle で plugin をモダンに管理する

みなさんは増え続ける plugin のどのように管理されていますか。 pathogen+submodule を使う方法でしょうか。それとも未来に生き VimJolt を使用されているのでしょうか。

今回はモダンな plugin 管理方法として、Vundle を使った方法をご紹介します。

Vundle は Ruby on Rails 3 で採用されている、Gem 管理システム Bundler に影響を受けた、plugin 管理システムです。

開発は Github 上で行われています。 https://github.com/gmarik/vundle

導入

導入は以下の様に ~/.vim にリポジトリを clone すると完了します。

$ git clone http://github.com/gmarik/vundle.git ~/.vim/vundle.git

ドットファイルを git で管理されている方は、submodule として取り込んで下さい。

plugin の管理

plugin の管理は以下の様に .vimrc に Bundle ‘plugin name’ と記述することで行います。

set nocompatible
filetype off                   " (1)

set rtp+=~/.vim/vundle.git/    " (2)
call vundle#rc()               " (3)

" original repos on github
Bundle 'tpope/vim-fugitive'

" vim-scripts repos
Bundle 'rails.vim'

" non github repos
Bundle 'git://git.wincent.com/command-t.git'

filetype plugin indent on     " (5)

特徴的なのは (1) で filetype を一度 off にしている点です。 Vundle の処理が終り次第、(5) で ftplugin と indent を読み込むように指定しています。

(2), (3) で Vundle を初期化し、Bundle ‘plugin name’ を書くことで、plugin を読み込む準備が完了します。

Bundle コマンド

Github 上のリポジトリから取得する場合

Bundle 'user_name/repository_name'

の様に、Github のユーザ名とリポジトリ名を指定します。

vim-scripts 上のリポジトリから取得する場合

Bundle 'script_name'

の様に、plugin の名前を指定します。

それ以外の git リポジトリから取得する場合

Bundle 'git://repository_url'

の様に、Git リポジトリ のフルパスを指定します。

plugin の管理

plugin のインストールには、:BundleInstall コマンドを使用します。 先程、.vimrc に Bundle ‘name’ と記述した plugin が自動的に取得され、インストールまで行われます。

:BundleInstall

また、既にインストールされている plugin をアップデートするには、 :BundleInstall! コマンドを利用します。

:BundleInstall!

plugin を検索して、インタラクティブに管理することも出来ます。

:Bundles unite

上記のコマンドを実行すると、検索結果が split されて表示されます。リストから目的の plugin を選択し、インストール、削除などが行えます。

ドキュメント

以下のようにしてヘルプを生成します。

:helptags ~/.vim/vundle.git/doc

生成したヘルプは通常通り以下のように引くことが出来ます

:help vundle

参照

Sixeight

Hack #214: 括弧までを消したり置き換えたりする

問題

プログラミングを行うということは、それすなわち括弧と友達になるということです。

現在のカーソル位置から次の閉じ括弧までの文字を一気に置き換えたい、というシーンは多々あると思います。

let l:lines = getbufline(buf■r(a:filename), 1, '$')

例えば上記のようなコードを記述しており、カーソル位置は■とし、この位置からa:filenameの直後の閉じ括弧までをまとめて削除し、bufnrのかわりにbufloadedと記述したいというケースを考えてみましょう。直後に開き括弧が存在し、これらは1トークンではないため、weなどをそのまま使うことはできません。文字数を正確に数えることも困難です。おそらくt)feの二択となるでしょう。ただし後者を使う場合、正確にeがそれまで存在しないことを確認する必要があるため、より非存在性を確認しやすい括弧を用いて指定することになると思います。

こういった操作をする機会は、ほとんど意識されないものの、かなり多いことが最近の研究で明らかになっています。(*1)

解決

文単位モーションの()の使用をやめ、これにt(などを割り当てましょう。~/.vimrcに以下を記述します。

onoremap ) t)
onoremap ( t(
vnoremap ) t)
vnoremap ( t(

あとはt)などを使用するかわりにたんに)などと打鍵します。上記設定のおかげで、あなたのソフトウェア開発にかかる時間の50%が短縮できます。

参考

  • (*1) 要出典
  • :h )
  • :h t
ujihisa

Hack #213: ダブルクリックで単語検索するようにする

きっかけ

Vimユーザの方は一日を端末で過ごしている方も多いでしょう。 しかしマウスとはとても便利なものです。 トラックボールを使ったりすると新しい発見があるかもしれません。

キーボードで操作している時はキーボードで操作でき、 マウスで操作している時はマウスで最低限の操作はできるというのが理想です。 最低限の操作とは何でしょうか。 結論から言いますと、あなたがマウスでコードを見ている時必要だと思うことは、大半が単語検索でしょう。

  • 離れた所にある同じ単語に飛ぶ
  • 変数がどこで定義されているか調べる
  • 検索目的ではなくバッファ中にあるテキストをハイライトさせたい

など単語検索でできることは実に様々です。

自分は普通にコードを書いている時でも/コマンドをよく使います。 移動の80%はこれといっていいかもしれません。 言い過ぎだとしても70割かもしれません。 それほど汎用的なコマンドなのです。

(脱線) IDEの場合

IDEだとしたら変数にマウスオーバーした時点で定義場所などの情報がポップアップで表示されるかもしれません。 ただこういう機能は「便利すぎて」ユーザが能動的に情報を探そうとした場合邪魔になることが多いと思うのです。 ちなみにマウスオーバーした時点でポップアップするようなIDEを筆者は知りません。勘で言いました。

自動補完にもこういう側面があると私は思います。 キーをタイプしたらポップアップがめまぐるしく表示され、 頭の中にあったコードがデリートされてしまうなどといったことがありました。

Twitterでチカチカしたアイコンをした人をフォローしてる人には身に覚えがあるかもしれませんが、 気分転換にTwitterを見たらTLにアイコンがチカチカした人がいてとても気分を害されたということがあります。 この対処法としてはtermtterなどの画像が表示されないTwitterクライアントを使うことです。 ちなみにTwitter社はサードパーティ製クライアントを推奨していません

ちなみに筆者は以前自動補完はあまり好きではありませんでしたが慣れました。 自動補完プラグインとしてはautocomplpopneocomplcacheというプラグインが代表的です。 自動補完はとても便利な機能なのでぜひ使いましょう。

閑話休題

無理矢理話を戻すと、マウスでの単語検索を快適にするために必要な設定を本稿では解説したいと思います。

ダブルクリックへのマッピング

ダブルクリックへのマッピングは<2-LeftMouse>を使えばできます。

nnoremap <2-LeftMouse> g*

これで終わりでしょうか?いいえ、まだです。

これだとダブルクリックをしようとした時、 シングルクリック(<LeftMouse>)の時点で<LeftMouse>本来の操作、 つまりクリックした場所にカーソルを移動、が実行されてしまうのです。 カーソルが移動するのは多いに結構なのですが、 問題は'scrolloff'の設定も効いてしまうことです。

'scrolloff'は正の値をセットするとカーソルの上部か下部が 常に'scrolloff'分の行だけ表示されるようになるという非常に便利なオプションですが、 これがマウスのシングルクリックの時に効いてしまうと

  1. シングルクリック (クリック1回目)
  2. カーソル移動
  3. ‘scrolloff’分だけ行を開ける
  4. 表示領域がずれて、マウスカーソルが指していた場所にあった単語も移動してしまう
  5. ダブルクリック (クリック2回目)
  6. 検索するつもりじゃなかった単語を検索してしまう
  7. 一瞬何が起こったのか分からない
  8. 理解し悲しみに暮れる

ということになり非常に悲しいです。 そして「9.Vimを説得する」というのがこの記事を書くに至るまでの過程でした。 ちなみに説得というのはEmacsで言うsetqとかけています。

'scrolloff'の再実装 〜yak shaving〜

これを解決するには、つまりシングルクリック(<LeftMouse>)時の移動を抑制すればいい訳です。 しかし'scrolloff'は設定しておきたい。 ならば'scrolloff'がやることをVimスクリプトで再実装して制御可能にし、一時的に無効にすればいい訳です。 以下がその'scrolloff'の実装です。 'scrolloff'オプションの代わりにg:scrolloffグローバル変数で指定するようになっています。

set scrolloff=0
let g:scrolloff = 15

" Hack for <LeftMouse> not to adjust ('scrolloff') when single-clicking.
" Implement 'scrolloff' by auto-command to control the fire.
autocmd vimrc CursorMoved * call s:reinventing_scrolloff()
let s:last_lnum = -1
function! s:reinventing_scrolloff()
    if s:last_lnum > 0 && line('.') ==# s:last_lnum
        return
    endif
    let s:last_lnum = line('.')
    let winline     = winline()
    let winheight   = winheight(0)
    let middle      = winheight / 2
    let upside      = (winheight / winline) >= 2
    " If upside is true, add winlines to above the cursor.
    " If upside is false, add winlines to under the cursor.
    if upside
        let up_num = g:scrolloff - winline + 1
        let up_num = winline + up_num > middle ? middle - winline : up_num
        if up_num > 0
            execute 'normal!' up_num."\<C-y>"
        endif
    else
        let down_num = g:scrolloff - (winheight - winline)
        let down_num = winline - down_num < middle ? winline - middle : down_num
        if down_num > 0
            execute 'normal!' down_num."\<C-e>"
        endif
    endif
endfunction

そしてこれは:autocmdを使って実装されているので 以下のように'eventignore'オプションという Vimスクリプトを書いているような人しか知らないオプションを使って 一時的に無効にできます。

nnoremap <silent> <LeftMouse> <Esc>:set eventignore=all<CR><LeftMouse>:set eventignore=<CR>

visualstar.vim

ここまででも十分ですが、マウスで選択し、クリックで検索できたらどんなに良い事でしょうか。 visualstar.vimを使えばそれができます。

vmap <LeftMouse> <Plug>(visualstar-g*)

まとめ

ここまでのまとめとして、以下を.vimrcに貼り付ければ完了です。

set scrolloff=0
let g:scrolloff = 15

" Hack for <LeftMouse> not to adjust ('scrolloff') when single-clicking.
" Implement 'scrolloff' by auto-command to control the fire.
autocmd vimrc CursorMoved * call s:reinventing_scrolloff()
let s:last_lnum = -1
function! s:reinventing_scrolloff()
    if s:last_lnum > 0 && line('.') ==# s:last_lnum
        return
    endif
    let s:last_lnum = line('.')
    let winline     = winline()
    let winheight   = winheight(0)
    let middle      = winheight / 2
    let upside      = (winheight / winline) >= 2
    " If upside is true, add winlines to above the cursor.
    " If upside is false, add winlines to under the cursor.
    if upside
        let up_num = g:scrolloff - winline + 1
        let up_num = winline + up_num > middle ? middle - winline : up_num
        if up_num > 0
            execute 'normal!' up_num."\<C-y>"
        endif
    else
        let down_num = g:scrolloff - (winheight - winline)
        let down_num = winline - down_num < middle ? winline - middle : down_num
        if down_num > 0
            execute 'normal!' down_num."\<C-e>"
        endif
    endif
endfunction

" Do not adjust current scroll position (do not fire 'scrolloff') on single-click.
nnoremap <silent> <LeftMouse>   <Esc>:set eventignore=all<CR><LeftMouse>:set eventignore=<CR>
" Double-click for searching the word under the cursor.
nnoremap          <2-LeftMouse> g*
" Single-click for searching the word selected in visual-mode.
vmap              <LeftMouse> <Plug>(visualstar-g*)
tyru

Hack #212: コマンドライン引数を活用する

今回は Vim 起動後のあれこれや、Plugin のあれこれではなく、便利なコマンドライン引数を紹介します。

紹介するもの以外にも沢山のコマンドライン引数が用意されています。さらに知るには :help vim-arguments を参照してください。

–startuptime {fname}
{fname} で指定したファイルに、起動に要した時間が記録されます。
.vimrc の読み込みに何秒というように細かく出ますので、起動が遅い時の原因調査に利用出来ます。
–noplugin
Plugin を読み込まずに起動します
+[num]
起動直後に [num] 行目に移動します。
+/{pattern}
起動直後に {pattern} に最初にマッチする箇所に移動します。
-c {command}
起動直後に {command} を実行します。
-S {fname}
起動直後に {fname} を :source {fname} で読み込みます。
-R
Readonly モードで起動します。このモードではファイルへの書き込みを禁止します。
-Z
Restricted モードで起動します。このモードでは外部シェルの実行 (:shell など) を禁止します。
-b
Binary モードで起動します。
-l
Lisp モードで起動します
-C
Compatible モードで起動します。
-n
:set updatecount=0 として、Swap ファイルの生成を禁止した状態となります。
-o[n]
水平に 分割した状態で起動します。
-p[n]
[n] 個のタブを開いた状態で起動します。
-d
Diff モードで起動します。
-x
ファイルを暗号化したうえに、パスワードでロックします。

参照資料

Sixeight

ホーム > Vim Hacks

Search
Feeds
Links
  • 公式
  • 勉強会
  • 情報
  • コミュニティ
  • Meta
    Etc
    Creative Commons License
    This blog is licensed under a Creative Commons License.

    Return to page top