反省はしても後悔はしない

Vim とか備忘録とか。それと関数型言語勉強中

vim-hier をフォークしてみた

背景

最近 watchdogs.vim の便利さ加減がもうどうしようもないのですが、vim-hier が行にしかハイライトしないので、長い行だとどの桁でエラーが出ているのかよくわからないという問題がありました。

ということでちょっと改造した

QuickFix が持っている情報には (あれば) col という名前でエラーの原因となった桁番号が取得出来ます。ということで Vimキモい素晴らしい正規表現を駆使してエラーのあった桁以降をハイライトするようにしてみました。

cohama/vim-hier

f:id:cohama:20130618220640p:plain

1行なのに処理たっぷりな関数型言語なんかでは非常に有用ですね。

残念ながら

マルチバイトな文字があるとずれます。

なんか Vim の relativenumber オプションの仕様が変わったっぽい

私は set relativenumbr するのが好きです。ちょっと前のパッチでカーソルのある行だけ普通の行番号を表示、それ以外で相対行数の表示という感じになっていたので気に入って使ってました。

ところが、最新のパッチ*1を含めてビルドするとカーソル行の現在行数表示の仕様が変わってしまったようです。 具体的には、set numberset relativenumbr が両方指定されているとカーソル行が現在行数、その他が相対行数になるようです。

私は numberrelativenumbr をトグルさせるコマンドを作ってたのですが、それを作り直すはめになりました。

以下が最新のパッチに対応しつつ、前のバージョンでも使えるトグルコマンドです。

nnoremap [Toggle]n :<C-u>call ToggleNumber()<CR>
nnoremap [Toggle]r :<C-u>call ToggleRelativeNumber()<CR>
function! ToggleNumber()
  if &l:number && !&l:relativenumber
    setlocal nonumber
  else
    setlocal number
  endif
  setlocal norelativenumber
endfunction
function! ToggleRelativeNumber()
  if &l:number && &l:relativenumber
    setlocal nonumber
    setlocal norelativenumber
  else
    setlocal number
    setlocal relativenumber
  endif
endfunction

*1:多分1115くらいから

Linux Mint 15 をいれたときにやることリスト

Linux Mint 15 が出てたので入れました。
そのとき最初に行う設定のメモ。
これは完全に自分用の備忘録です。いつも忘れるので。

初期状態のディレクトリを英語表記にする

ターミナルから使うときは日本語だとつらいので。

$ env LANGUAGE=C LC_MESSAGES=C xdg-user-dirs-gtk-update

Update Names -> 一旦ログアウト -> 次回から表示しないにチェック -> 古い名前のままにする
参考
Ubuntu 13.04をインストールした直後に行う設定 & インストールするソフト

Vim をコンパイル

これは前のエントリを参照。

Google Chrome を入れる

ブラウザは Chrome 使ってますね。
最初から入ってる FireFoxgoogle.co.jp にアクセスすれば OK。

Dropbox を入れる

Dropbox 重要。
スタート -> ソフトウェアの管理
から nautilus-dropbox をインストール。
インストール後、スタート -> Dropbox 起動でアカウント設定などを入力すれば OK。

Workspace の数を変更

デフォルトが2なんだけど、4つくらいは使いたいよね。

$ gsettings set org.cinnamon number-workspaces 4

なんか GUI じゃ設定できないのかな。調べたけどわからんかった。
あとはパネルに Workspace 切換器を設置すると便利。

Mozc を入れる

インプットメソッドは Anthy より IBus-Mozc 派なので。

$ sudo apt-get install ibus-mozc

インプットメソッドを再起動後、インプットメソッドを右クリック -> Preferences -> Input Method -> Customize active input methods にチェックを入れる -> Select an input method から Japanese > Mozc を選択 -> Add

ssh を入れる

外部から繋ぎたい時もあるよね。

$ sudo apt-get install ssh

Git を入れる

そういえば、いれてなかった。
Vim のプラグイン管理に必要なので。バージョン管理にも使いますがおまけです。(お

$ sudo apt-get install git

鍵を作る

GitHub にプッシュするときとかに必要なので。

$ ssh-keygen

鍵を GitHub に登録

~/.ssh/id_rsa.pub を登録する。

dotfiles とかを git cloen

.zshrc とか .gitconfig とかは github で管理してます。

シェルを zsh に変える

bashzsh の違いとかよくわかってないけど、割と前から zsh 使ってるので。

$ sudo apt-get install zsh
$ chsh
  .. /bin/zsh

そしてログオフ。

nodebrew を使って JavaScript 環境を入れる

職業 JS プログラマなので。
node は nodebrew で入れます。

$ sudo apt-get install curl
$ curl https://raw.github.com/hokaccha/nodebrew/master/nodebrew | perl - setup

zshrc にて ~/.nodebrew/current/bin を PATH に追加します。

$ nodebrew install stable
$ nodebrew use stable
$ npm install -g coffee-script
$ npm install -g jshint

OPAM 使って OCaml 環境を入れる

OCaml 面白いよ!
まず opam いれます。公式見ると 64 ビットだと apt で入れられるっぽい(ホントか?)ですが、私の場合は 32 ビットにしているのでソースからビルドします。

$ sudo apt-get install ocaml ocaml-native-compilers camlp4-extra m4
$ git clone https://github.com/OCamlPro/opam
$ git reset --hard latest
$ cd opam
$ ./configure --prefix=/path/to/opam
$ make
$ make install

.zshrc で $PATH に OPAM のパスを追加するのと $ export OCAML_ANNOT=1 という環境変数を定義しておく。

$ source ~/.zshrc
$ opam init
$ . $HOME/.opam/opam-init/init.zsh > /dev/null 2> /dev/null || true
$ opam isntall spotinstall
$ opam switch 4.00.1+annot
$ eval `opam config env`

あと、OCaml 用の便利ツールもインストールしておく。

$ opam install spotinstall
$ eval `opam config env`
$ spotinstall -v ocaml
$ opam install ocamlspot
$ eval `opam config env`

rbenv で Ruby その他

職業 Rubyist なので。(入れるの忘れてた)

$ git clone https://github.com/sstephenson/rbenv ~/.rbenv
$ git clone https://github.com/sstephenson/ruby-build ~/.rbenv/plugins/ruby-build

.zshrc に以下を追加

$ export RBENV_HOME=~/.rbenv
$ export PATH=$RBENV_HOME/bin:$PATH

執筆時点での最新は ruby 2.0.0-p195 なのでこれをインストール

$ rbenv install 2.0.0-p195
$ rbenv global 2.0.0-p195
$ source ~/.zshrc
$ ruby -v

bundler 重要

$ gem install bundler
$ rbenv rehash

このままだと gem をインストールするたびに rbenv rehash しないといけないんだけど、自分の場合はどうせ bundler 使ってプロジェクトローカルにしか gem を入れることがないので気にしない。

あと、rails4 環境の作り方

$ mkdir myapp & cd myapp
$ bundle init
$ echo 'gem "rails", "4.0.0.rc2"' >> Gemfile
$ sudo apt-get install libsqlite3-dev
$ bundle install --path vendor/bundle
$ bundle exec rails new . -T

参考

まだあった気がするけど、とりあえず、これくらいで。

OCaml のソースコードの型を表示したり定義にジャンプしたりする Vim のプラグイン作った

この記事は Vim Advent Calendar 2012 の 185 日目の記事です。
昨日は id:deris さんの Vimでできる脱出系パズルゲーム でした。

はじめに

OCaml という静的型付けの関数型言語があります。同じく静的な型をもつ関数型言語である Haskell とは異なり、副作用をもつ関数を定義したり破壊的な操作も行うことができます。

ところが、OCaml 界隈ではどうやら Emacsデファクトのエディタらしく、Vim での開発環境の情報は非常に少ない、またあったとしも情報が古くなっているものが大半というのが現状です。

参考 OCaml.jp > 開発環境
(追記:更新されたみたいです)

私は Vim でも OCaml をやりたいと思い、プラグインを開発することにしました。

OCamlSpotter (ocamlspot) について

実は、OCamlソースコードから型情報や定義情報を取得するためのプログラムはすでにあります。OCamlSpotter と言います。
インストールはこの辺が参考になりました。
OSXへOCamlの開発環境をOPAMで構築し直した - tmaeda 日記(2012-10-28)
例えば、下のような階乗を計算する OCaml のコードがあったとして、このファイルの 5 行目 12 桁目 (つまり print_int (factor 5) の factor の f) の位置を指定して OCamlSpottre を起動すると以下の様な出力が得られます。

$ ocamlspot test.ml:l5c12
load /home/cohama/tmp/test.cmt
Pathreparse: not supported: factor (Failure("The given position is not clear enough"))
Use: Value, factor__1008
Type: int -> int;
XType: int -> int;
At: Expr;
Tree: l5c11b78:l5c17b84
XTree: </home/cohama/tmp/test.ml:l5c11b78:l5c17b84>
In_module: 
Val: val factor : int -> int
Spot: </home/cohama/tmp/test.ml:l1c8b8:l1c14b14>
BYE!

この出力から型情報や定義情報なんかが取得できます。あとはこれを Vim Script でパースするだけなので簡単ですね。

というわけでプラグイン作った

実は前述の OCamlSpotter には公式の Vim 用のスクリプトも用意されているのですが、Emacs 版に比べると機能が少なく、また実装もいろいろ気に入らなかった*1ので自作することにしました。

the-ocamlspot.vim と言います。インストールは NeoBundle 等を使えば簡単に出来ます。依存する Vim プラグインはありませんが、OCamlSpotter のインストールは必須です。

NeoBundle 'cohama/the-ocamlspot.vim'

使ってみる

the-ocamlspot.vim は特に設定をしなくてもある程度最初から使えるようになっています。*2

型の表示

型を表示させたい項にカーソルをもっていってしばらく待ちます(この時間は set updatetime で設定出来ます)。

上図のようにエコーエリアに型の情報が表示されます。また、現在の項と定義位置がそれぞれ違う色でハイライトされます。ちなみに、<Leader>ot で明示的に呼び出すこともできます。


あと、GVim をお使いの場合にはマウスカーソルのホールドでも型情報の表示が可能です。

この時はエコーエリアではなくバルーンで表示されます。

定義位置の表示

定義位置へのジャンプもできます。調べたい項の上でおもむろに <Leader>op を押します。

この様に定義されたファイルの定義された位置がプレビューウィンドウので表示されます。まだプレビューウィンドウのハイライトが実装されていないので少し分かりづらいですが、、、近日中に実装する予定です。しばしお待ちをば。

the-ocamlspot.vim の今後について

今後追加で実装したいものとしては

  • (echodoc のように) 型情報の表示のときに簡単な色をつける
  • 定義位置の表示だけじゃなくてジャンプも
  • 定義されたファイルの開き方をプレビューウィンドウ以外にも水平、垂直分割やタブで開く

などなど。
ただ、私自身が OCaml 超初心者なのでなにが必要なのか分かっていないというのもあります。OCaml の習得も課題ですね。

最後に

今回は作ったプラグインの紹介がメインでしたが、そのうち VimOCaml 開発環境を記事にまとめたいと思っています。関数型言語を始めてみたいという Vimmer の方も今までやむなく Emacs を使っていた OCamler の方もこれを機に VimOCaml プログラミングを始めてみてはいかがでしょうか?

次回は id:manga_osyo さんです。

*1:OCamlSpotter の作者の方は Emacs 使いだそうです。そう考えると Vim のスクリプトが用意されているというだけでも脱帽です。

*2:もちろん設定をカスタマイズすることも可能です!

Linux Mint 15 で Vim (GVim) をコンパイル

はじめに

Linux Mint 15 が出たので早速 VM にインストールしてみました。
OS をインストールしたらまずやるのは勿論 Vim のコンパイルですね。apt-get だとちょっと古いので最新の機能を使いたかったらやっぱり自分でビルドするのが良いです。

基本的には vim-jp » Linuxでのビルド方法 と同じですが、Linux Mint 15 だとそのままではだめなので少し変えてます。

とりあえず、リポジトリに追加します

$ sudo vi /etc/apt/souces.list.d/official-package-repositories.list
  deb http://packages.linuxmint.com olivia main upstream import  #id:linuxmint_main

  deb http://archive.ubuntu.com/ubuntu raring main restricted universe multiverse
+ deb-src http://archive.ubuntu.com/ubuntu raring main restricted universe multiverse
  deb http://archive.ubuntu.com/ubuntu raring-updates main restricted universe multiverse

  deb http://security.ubuntu.com/ubuntu/ raring-security main restricted universe multiverse
  deb http://archive.canonical.com/ubuntu/ raring partner

色々入れます

Perl, Python, Python3, Ruby, Lua のインターフェースを使いたいので。あと GVim も。

$ sudo apt-get install mercurial gettext libncurses5-dev libxmu-dev libgnomeui-dev libperl-dev python-dev python3-dev ruby-dev libacl1-dev libgpm-dev libxpm-dev liblua5.1-0-dev lua5.1 tcl-dev

MercurialVim のソースをとってきます

$ hg clone https://vim.googlecode.com/hg/ vim

ビルド

ただし、vim-jp に書いてあるままだと Python のところでこけるのでちょっと修正してます。
参考
Ubuntu 13.04 での Vimコンパイル #Vim #Ubuntu - Qiita [キータ]

$ ./configure --with-features=huge --enable-gui=gnome2 --enable-fail-if-missing --enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-python3interp --enable-luainterp --with-python-config-dir=/usr/lib/python2.7/config-i386-linux-gnu --prefix=/path/to/vim
$ make
$ make install

パスを通します

.bashrc や .zshrc などに

export $VIM_HOME=/path/to/vim
export $PATH=$VIM_HOME/bin:$PATH

できた!

Vim のコマンドラインモードを使いこなそう

[Vim]Vim のコマンドラインモードを使いこなそう

この記事は Vim Advent Calendar 2012 の 180 日目の記事です。

昨日は @raa0121 さんの Sapporo.vim(仮称)発足(仮) のお知らせでした。

はじめに

この記事は Vim のカーソル移動などの基本操作を覚えて、自分の vimrc に自分用のマッピングも少しずつ設定できるようになってきたくらいの方向けの記事です。

コマンドラインモードとはなんでしょう?
そう! : (コロン) を押した時のあの下に行くモードです。

だれでもまず最初は :q で Vim の終了や :w で保存をしますよね。

この記事ではそんなコマンドラインモードをもっと便利に使うための Tips なんかを紹介します。

コマンドラインモードでも補完をする

コマンドラインモードでもコマンド名やファイル名などの補完ができます。

ある程度文字を入力してから <C-d> を押します。

その後 <C-l> を押すと、共通部分までは自動で入力してくれます。
このようになんの設定もしなくてもこれくらいの補完はできます。

設定をいじってもっとコマンドラインモードの補完を使いやすくする

前述のとおり、コマンドラインモードでも補完はできるのですが、デフォルトのままだとやはり微妙に使いづらいです。そこで設定をいろいろいじってもっと使いやすい補完にしましょう。

以下の設定を vimrc に追加します。

set wildmenu

これで、文字を入力した後に <Tab>*1 を打つだけで良い感じに補完することができます

さらに、さきほどの wildmenu での補完の挙動は wildmode オプションでいろいろ設定を変えることができます。
私は下のように設定しています。

set wildmode=longest:full,full

これで最初の1回目の <Tab> では共通部分までの補完をしつつ補完候補を出し、次回以降はこの補完候補を順に選択するような動作になります。

ほかにどういう機能や設定があるかは :help cmdline-completion してみてください。

コマンドラインモードでのマッピングを設定する

ノーマルモードでのマッピングは nmap、ビジュアルモードでのマッピングは xmap*2 で設定します。

これらと同様、コマンドラインモードでも cmap というコマンドでマッピングを設定することができます。

といっても何を設定すればいいのかわかりませんね。なので、いろいろ設定例を紹介します。


以下はコマンドラインモードで Emacs 風のキー操作を提供するものです。

cnoremap <C-a> <Home>
" 一文字戻る
cnoremap <C-b> <Left>
" カーソルの下の文字を削除
cnoremap <C-d> <Del>
" 行末へ移動
cnoremap <C-e> <End>
" 一文字進む
cnoremap <C-f> <Right>
" コマンドライン履歴を一つ進む
cnoremap <C-n> <Down>
" コマンドライン履歴を一つ戻る
cnoremap <C-p> <Up>
" 前の単語へ移動
cnoremap <M-b> <S-Left>
" 次の単語へ移動
cnoremap <M-f> <S-Right>

コマンドラインモードでも方向キーなどホームポジションから離れてしまうキーをおそうとすると生産性が低下してしまいます。コマンドラインモードでもなるべくホームポジションにとどまれるようにしましょう。*3


以下は検索時の / のエスケープを簡単に入力できるようにするものです。

cnoremap <expr> / (getcmdtype() == '/') '\/' : '/'

hoge/fuga を検索するときには Vim では hoge\/fuga と入力しないといけませんが、それを簡単に入力できるようになります。ただし、パスの区切りを入力するなど検索以外の時にマッピングされると困るので、getcmdtype を使って / による検索のときだけ \/ というマッピングが働くようにしています。
この設定は vimrc 読書会で誰かから教えて頂きました。*4

追記

? の検索の時は / のエスケープはいらないです。逆に ? のエスケープが必要です。

以下の設定は /? で検索時に現在の検索する語に単語境界を付与するものです。

cnoremap <C-o> <C-\>e(getcmdtype() == '/' <Bar><Bar> getcmdtype() == '?') ? '\<' . getcmdline() . '\>' : getcmdline()<CR>

どういうことかというと、たとえば /hoge と入力した後に <C-o> を押すと /\<hoge\> というように変わります。最初の /hoge では ahoge や hogera など単語の一部に hoge が含まれていても検索に引っかかりますが /\<hoge\> だと hoge という単語しか検索できないようにすることができます。

この設定だと一方的に単語境界を設定するだけですが、VimScript でちょっとした関数を作れば単語境界をトグルさせるようなことも可能です。(私はそのように設定しています)

smartinput プラグインを使ってさらに複雑なマッピングを設定する

上級編です。
smartinput という入力補助系プラグインがあります。これはもともと開き括弧を入力したら自動的に閉じ括弧を入力するというようなプラグインですが、非常に柔軟なカスタマイズができるためいろいろなことに使えます。

今回はこれをコマンドラインモードでのマッピングに応用します。

call smartinput#map_to_trigger('c', 'D', 'D', 'D')
call smartinput#map_to_trigger('c', 'I', 'I', 'I')
call smartinput#map_to_trigger('c', 'C', 'C', 'C')
call smartinput#define_rule({'at': 'Unite \%#', 'char': 'D', 'input': '<C-u>UniteWithInputDirectory<Space>', 'mode': ':'})
call smartinput#define_rule({'at': 'Unite \%#', 'char': 'I', 'input': '<C-u>UniteWithInput<Space>', 'mode': ':'})
call smartinput#define_rule({'at': 'Unite \%#', 'char': 'C', 'input': '<C-u>UniteWithCursorWord<Space>', 'mode': ':'})

これは Unite 系のコマンドを簡単に入力するためのものです。:Unite<Space> まで入力した時点で I を押すと、:UniteWithInput<Space> に変えることができます。Unite の source 名はだいたい小文字で始まるため大文字をマッピングしても問題ないことを利用しています。
:Unite<Space> を入力するマッピングを他に用意しておくと大変便利です。

このように smartinput を使うと、コマンドラインモードで文脈に応じた柔軟なマッピングを設定することができます。

まとめ

ノーマルモードだけではなく、コマンドラインモードも使いこなしてこそ真の Vimmer

最後に

vimrc 読書会に参加すると以下略

追記

最初コマンドモードと書いていましたが、コマンドモードは vi におけるノーマルモードのことで、Vim ではコマンドラインモードというそうです。id:thinca さん教えてくださりありがとうございました。

次回は @ujihisa さんです。

*1:このキーは wildchar オプションで変更できます

*2:vmap はセレクトモードでもマッピングしてしまいます。意味がわからなければビジュアルモードのマッピングは xmap と覚えた方が良いです

*3:気づいた人は気づいたかもしれませんが、実はこれは :help emacs-kes からのコピペです

*4:誰だったかは忘れた

Vim で絶対に OCaml を打ち間違わないための設定

というようなことがあったので。

今までは

abbreviate Ocaml OCaml

と設定することで対処していました。(:help type-mistakes)
しかし、OCamlSpotter のように続いた単語の場合は短縮入力では対応出来ません。

そこで、入力支援系プラグインである smartinput を使って以下のようにします。

call smartinput#map_to_trigger('c', 'l', 'l', 'l')
call smartinput#map_to_trigger('i', 'l', 'l', 'l')

call smartinput#define_rule({'at': 'Ocam\%#', 'char': 'l', 'input': '<BS><BS><BS>Caml', 'mode': 'i:/?'})

smartinput はもともとマッピングを利用して開き括弧 '(' を入力すると自動的に閉じ括弧 ')' を入力するためのものですが、これを応用して l を入力した時にカーソルの前方が Ocam だった場合に cam をバックスペースで消した後自動 Caml を入力するように設定出来ます。

これで怖い人から刺される心配がなくなりますね。