ホーム > タグ > lv2

lv2

Hack #241: Haskellで使いたい関数を使ってからそのモジュールをimportする

Haskell Advent Calendar 2011への寄稿記事です。

問題

Haskellを書いていて、長いソースコードの末尾の方にて、急にとあるモジュールのとある関数を使いたい、そんなときはよくあります。ありがちなのがApplicativeの演算子いくつかと、Data.Function.onと、Data.Listのアレとコレと・・・。いくらでもあります。

Haskellでは一般的に、モジュールのimportはソースコードのかなりはじめの方にまとめて記述します。importしたい関数を一度しか使わず、しかもソースコードの末尾の方に位置していようと、おかまい無しです。このとき、ggなどでソースコード上部まで移動し、neco-ghcなどを駆使してmoduleとその関数を的確にimportし、そして<C-o>などでもといた場所に戻ることになると思います。:spなどで画面分割してから行ったり、あるいはmarkをつけるという方法もありますが、いずれにせよこれらの作業のため脳内の作業メモリがスタックオーバーフローするのは明らかでしょう。

解決

unite-haskellimportを用います。

https://github.com/ujihisa/unite-haskellimport

まずは上記プラギンをインストールします。依存プラギンはunite.vim、依存ツールはhoogleです。

$ cabal update && cabal install hoogle && hoogle data

たとえば急に==>という関数を使いたくなったとしましょう。

:Unite haskellimport

としてunite窓を開き、==>と打鍵しましょう。

Test.QuickCheck.Property (==>) :: Testable prop => Bool -> prop -> Property
Test.QuickCheck (==>) :: Testable prop => Bool -> prop -> Property

インストールしているcabalパッケージにもよりますが、たとえば上記のような項目が選択肢にでてくることでしょう。実際にimportしたい側を選択します。

候補を選択すると、unite-haskellimportはdefaultのactionとして:Haskellimportコマンドを発行します。これは、対象を、ソースコードのそれらしい場所に挿入するものです。既に他のimport文がある場合は、最後のimportのあとに挿入します。

Before

import qualified Data.Text as T

f x = ...

After

import qualified Data.Text as T
import Test.QuickCheck ((==>))

f x = ...

今回importしたのは記号からなる関数でした。が、もしも記号ではない関数、つまりVimの<cword>になるようなものならば、:Uniteのかわりに

:UniteWithCursorWord haskellimport

とするとよいでしょう。これを頻繁に行うようならば、適切なキーにマッピングしておくべきです。たとえば以下を ~/.vim/ftplugin/haskell.vimに記述すると、<space>Iと打鍵するだけでカーソル以下にある単語の関数をimportしてくれます。

nnoremap <buffer> <space>I :<C-u>UniteWithCursorWord haskellimport<Cr>
ujihisa

Hack #240: <C-[> での誤爆を防止する

挿入モードから抜ける方法は多数ありますが、その中に <C-[> キーがあります。

しかしこの [ キーは、日本語キーボードではすぐ左に @ キーがあり、誤って <C-@> を押してしまうと直前に挿入したテキストがさらに挿入されてから挿入モードを抜けるため、誤爆すると大惨事となります。

誤爆を防止する

誤爆をすると言うことは、本来行いたい操作があるということです。 このような誤爆を簡単かつ確実に防止するには、対象の機能を本来押したいキーに置き換えてしまうのが効果的です。

考えてみましょう。この <C-@> の機能「直前に挿入されたテキストをもう一度挿入し、挿入を終了する。」は、あなたにとって必要でしょうか? もし必要ないと判断したら、本来押したいキー、この場合は <C-[> に置き換えましょう。以下のようにします。

imap <C-@> <C-[>

こうすることで誤爆を防ぐことができます。この @ は [ よりも近いため押し易く、しかもこの位置は英字キーボードと同じ位置であるため、英字キーボードに乗り換える練習にもなります。

もし万が一 <C-@> の機能が使いたい場合、しかし誤爆は避けたい場合は、別の位置に <C-@> をマッピングするとよいでしょう。

thinca

Hack #238: neobundle.vim で plugin をモダンに管理する

こんにちは。Shougoです。Vimテクニックバイブルの執筆で長らくお休みを頂いていました。 執筆が終わってからも、プラグインの更新で忙しいのが難点です。 とはいえ、あまりに間隔が空いているのは執筆者としてまずいと感じたため、久しぶりに復帰します。

みなさん、Vimプラグイン管理には何をお使いでしょうか。残念ながら、Vimのプラグイン管理には良い方法がなく、 各々が「自分の考える最強のプラグイン管理プラグイン」を作ってきました。 つまり、長らくプラグイン管理プラグインは戦国時代の様相を呈していたわけです。 実装が存在しないVimJoltsもその一つです:-)。 しかし最近、Vimのプラグイン管理はVundleに一元化されることが多くなってきました。 「Hack #215: Vundleでプラグインをモダンに管理する」やVimテクニックバイブルでも紹介されています。 私も最初はpathogenを使っていましたが、アップデートが簡単なVundleに乗り換えた経緯があります。 ただしVundleにもいくつか不満があったため、自分でforkしたVundleをしばらく使用していました。 しかし、最終的にVundleの仕様変更に追随できなくなったため、forkしたVundleを元にneobundle.vimを開発することにしました。 変更点をVundleにマージするには、変更点が多すぎたということもあります。 今回はneobundle.vimについて紹介します。

neobundle.vimとVundleの違い

Vundleをベースにしたため、基本的な機能は同じです。 Vundleを知っているなら、すぐに乗り換えることも可能でしょう。 変更点は幾つかありますが、主なものは以下の通りです。

コマンド名が改善されている

VundleはBundleを意識して付けられたコマンド名になっているため、コマンド名とプラグイン名が対応していません。 例えば、プラグインをインストールするコマンド名は:VundleInstallではなく、:BundleInstallです。 この辺りは、議論がされているようですが、まだ結論は出ていません。 neobundle.vimはプラグイン名をプレフィクスとした、:NeoBundleInstallとなっています。 BundleをNeoBundleに改名するだけで、基本的に使用することができます。

vital化されている

ルーチンを他のプラグインと共通化するために、vital.vimを使用しています。 プラグインの開発が楽になります。

shellslashがオンでも動作する

shellescape()を使用していますが、shellslashオプションがオンの場合、クオートが”になってしまうという問題があります。 つまりWindows環境で、cmd.exeをshellとして使用している場合、shellslashを有効にしていると動きません。 neobundle.vimではshellescape()を使用していません。

vimprocに対応している

vimprocが利用できる環境では、アップデートにvimprocを使用します。 Windows環境では、DOS窓が出ないという利点につながります。

unite.vimインタフェースの実装

実は、これがneobundle.vimで一番やりたかった機能です。 neobundle.vimはunite.vimのインタフェースを実装しているため、unite.vimからVimプラグインをアップデートすることができます。 非同期でアップデートを行うため、使用にはvimprocが必要です。 neobundle.vimはunite.vimやvimprocがない環境でも動作しなくてはならないため、従来のインタフェースも残っています。 ただし、従来のインタフェースは緊急用のため重視していません。

Subversion, Mercurialへの対応

tsukkeeさんがVundleに追加していた機能をマージし、Subversion, Mercurialに試験的な対応をしました。 まだ実験段階ですが、試していただければと思います。

リビジョン指定

:NeoBundle {repository} {revision}という構文でリビジョン指定ができます。まだ実験段階の機能です。 不具合のあるプラグインのバージョンを固定する時に便利だと思います。

neobundle.vimの導入

neobundle.vimの開発は、github上で行われています。https://github.com/Shougo/neobundle.vim 導入する場合、~/.vimにリポジトリをcloneすると楽でしょう。

$ git clone https://github.com/Shougo/neobundle.vim ~/.vim/neobundle.vim.git

plugin の管理

plugin の管理は以下の様に .vimrc に NeoBundle 'plugin name' と記述することで行います。 極端な話、BundleNeoBundleに変更するだけです。

set nocompatible
filetype off

if has('vim_starting')
  set runtimepath+='path to neobundle directory'

  call neobundle#rc(expand('~/.bundle'))
endif

NeoBundle 'git://github.com/Shougo/clang_complete.git'
NeoBundle 'git://github.com/Shougo/echodoc.git'
NeoBundle 'git://github.com/Shougo/neocomplcache.git'
NeoBundle 'git://github.com/Shougo/neobundle.vim.git'
NeoBundle 'git://github.com/Shougo/unite.vim.git'
NeoBundle 'git://github.com/Shougo/vim-vcs.git'
NeoBundle 'git://github.com/Shougo/vimfiler.git'
NeoBundle 'git://github.com/Shougo/vimshell.git'
NeoBundle 'git://github.com/Shougo/vinarise.git'

filetype plugin on
filetype indent on

Vundleと同様、先にfiletypeをoffにしてから、neobundle.vimの設定を行います。 最初、neobudle.vimの関数を呼べるよう、neobundle.vimのパスを&runtimepathに追加します。 そしてneobundle#rc(expand('~/.bundle'))で初期化します。 neobudle#rc()の引数はプラグインをインストールする基準となるパスです。 NeoBundleコマンドで設定をしたあと、最後にfiletype pluginをオンにします。

NeoBundle コマンドの使い方

Vundleと全く同じです。基本的にBundleコマンドがNeoBundleコマンドに変わっただけです。

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

NeoBundle 'user_name/repository_name'

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

NeoBundle 'script_name'

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

NeoBundle 'git://repository_url'
NeoBundle 'http://svn.macports.org/repository/macports/contrib/mpvim/'
NeoBundle 'https://bitbucket.org/ns9tks/vim-fuzzyfinder'

Gitリポジトリのフルパスを指定します。 MercurialやSubversionにも試験的に対応しています。

pluginの管理

plugin のインストールには、:NeoBundleInstall コマンドを使用します。 .vimrcで設定したplugin が自動的に取得され、インストールまで行われます。 ただし、アップデートしたプラグインを使用するには、Vimを再起動したほうが良いです。

:NeoBundleInstall

既にインストールされている plugin をアップデートするには、 :NeoBundleInstall! コマンドを利用します。 通常のNeoBundleInstallでは、アップデートが行われないからです。

:NeoBundleInstall!

不要になったプラグインを削除するには、:NeoBundleの設定を.vimrcから削除した後、 :NeoBundleCleanコマンドを実行します。

neobundle.vimはplugin検索には対応していません。

neobudle.vimはneobundle/install sourceを使用することで、 unite.vimインタフェースによりアップデートを行うことができます。 アップデートは非同期に行われます。 neobundle/install sourceの引数に!を与えると、:NeoBundleInstall!相当になります。 プラグイン名を引数に与えることで、個別にアップデートをすることも可能です。

:Unite neobundle/install:!
:Unite neobundle/install:neocomplcache
:Unite neobundle/install:neocomplcache:unite.vim

ドキュメントの更新

プラグインのインストール時に、自動的に:helptagsコマンドが実行されるため、 ユーザーは何もする必要がありません。

参考

  • :help neobundle
Shougo

Hack #237: 古い quickfix を参照する

quickfix は :grep:make の結果として使われたり、時にはプラグインが何かの結果を表示するのに使ったりと、様々な状況で使用されます。

それだけ便利なものですが、時には、以前の内容をまだ見たいのにうっかり新しい内容を quickfix へ出力してしまうことがあります。

:colder :cnewer コマンド

実は、quickfix は過去のリストを10個まで保持しています。これは :colder :cnewer コマンドで切り替えられます。

:colder [count]
:cnewer [count]

:colder[count] 個分古い quickfix へ移動します。:cnewer[count] 個分新しい quickfix へ移動します。

もし誤って quickfix を上書きしてしまった場合でも、慌てず騒がず :colder すれば安心です。

thinca

Hack #235: リストの要素の総和や総乗を簡単に求める

こんにちは、ujihisaです。無事引っ越しが完了しましたが、インターネット回線の確保にはもうしばらく時間がかかるらしく、しばらく家でオフラインな状態です。ちなみに来日することが決まりました。こんなカンファレンスや、勉強会を企画してみました。いずれも来月です。ふるってプレゼンに応募ください。

問題

リストlistの和は、他の言語ならば以下のようにして求めることが一般的です。

  • Ruby
    • list.inject(:+)
    • これは list.inject {|i, j| i + j }の意。Enumerable#injectの特殊用法
    • list.inject(0, :+)
    • 同じくこれは list.inject(0) {|i, j| i + j }の意。
  • Haskell
    • foldl1 (+) list
    • これはfoldl1 (\i j -> i + j) listの意。言語仕様として演算子は括弧でくくるだけで2引数関数のような振る舞いになる(*1)。
    • sum list
  • Python
    • reduce(lambda a, b: a + b, list)
    • sum(list) と、sumといった直接的な方法がサポートされているかは別にして、なんらかの「リストと関数を受け取り、(リストに限らない)なんらかの値を返す」関数が提供されるのが一般的であることがわかります。

Vim scriptには残念ながらそういった関数が標準では提供されていないようです。どうすればよいでしょうか。

解決

vital.vimという、プラギン埋め込み型の汎用ライブラリを使います。

前述の問題を解決するには、vitalのData.Listモジュールを用いるのがよいでしょう。Data.Listの上記要件を満たす関数は以下の4つで、意味はそれぞれHaskellのPreludeに定義されているものと同じです。

  • foldl
  • foldl1
  • foldr
  • foldr1

たとえばfoldl1を用いると、以下のようにしてリストlistの要素の値の総和を求めることができます。

let L = vital#of('プラギン名').import('Data.List')
echo L.foldl1('v:memo + v:val', list)

非常に書きやすく読みやすく、理想的です。なお、実験的にvitalを用いる場合は、vitalを&rtpに入れた上でvital#of('vital')とするとそのvitalを読み込むことができます。

ujihisa

Hack #232: Clojure開発環境を整える

こんにちは、ujihisaです。Vancouverでは空前のClojureブームが発生しており、毎週のようにClojure勉強会があり、Vim使いやEmacs使いが集結しています。

問題1

Clojureでシンタックスハイライトや自動インデントを行いたい。

解決1

VimClojureというプラギンをインストールします。

https://github.com/jondistad/vimclojure

なお、g:clj_highlight_builtinsを設定すると標準関数のハイライトが、またg:clj_paren_rainbowを設定すると括弧の対応が虹色に美しく輝き、便利です。筆者は以下のようにして両方とも利用可能にしています。

~/.vimrc:

let g:clj_highlight_builtins = 1
let g:clj_paren_rainbow = 1

vimclojure highlighting

問題2

改行するたびにyankしている文字列が消える?

解決2

VimClojureをアンインストールするか、頑張ってパッチを書きます。

VimClojureには深刻なバグがあり、インデントを調整するたびにyankしている文字列が完全に破壊されます。

問題3

Clojureのコードを即座に実行し、結果を別バッファに表示しつづけたい。

解決3

quickrunを用います。もしcljというコマンドを持っていれば、ファイルタイプがclojureであるバッファに対してquickrunは無設定で動作します。

https://github.com/thinca/vim-quickrun

quickrun clj

問題4

quickrunに時間がかかりすぎる。

解決4

JVMの立ち上げ時間とライブラリの読み込み時間がとても長いのが原因です。Clojure処理系を立ち上げたままにしておくことで、劇的な高速化が実現できます。そのための道具としてNailGunとJarkがあります。筆者のオススメはJarkです。

https://github.com/icylisper/jark

Jarkをインストールしたら、まずはJarkサーバを立ち上げましょう。vimshellなどで

$ jark vm start

として事前にJarkサーバを立ち上げ、そしてquickrunします。OSを終了するときまで、すなわちVimを終了するときまで、Jarkサーバを終了する必要はありません。

quickrunは既にjarkに対応していますので、無設定でいきなり使えるはずです。

以下に感動的なベンチマーク結果を載せます。

(println "hello")

とだけ書いたコードをcljjarkのそれぞれでtimeコマンドで比較してみたところ、それぞれ

  • clj

      1.40 real         2.09 user         0.15 sys
    
  • jark

      0.19 real         0.11 user         0.06 sys
    

となりました。実験はかなりパワフルなiMacを用いて行ったので、一般的な初代MacBook Airなどのマシンで行うと、さらに顕著な差が出るでしょう。

ujihisa

Hack #231: Rubyで入力と出力からメソッド名を自動補完する

こんにちは、ujihisaです。社内Hackathonがあるということで土日に出社したものの、どちらも僕以外全員不参加で涙目でした。

問題

Rubyでメソッド名を補完する方法をHack #229: 動的型付け言語Rubyでメソッド名などを自動補完するで紹介しました。これは、オブジェクトからそのメソッドをすべて網羅することで補完を行うというアプローチでした。

では、オブジェクトと、メソッドを呼び出すことで得られる返り値の両方から補完を行うことはできないのでしょうか。

例示します。Rubyでは、1というオブジェクトから2というオブジェクトを得るには、1に対してsuccまたはnextというメソッドを呼び出すことで実現できます。

1.succ #=> 2

また、[:a, :b, :c]というオブジェクトから:aというオブジェクトを得るには、[:a, :b, :c]というオブジェクトにfirstなどのメソッドを呼び出すことで実現できます。

[:a, :b, :c].first #=> :a

カーソル位置がオブジェクトの直後のメソッド呼び出しの.にあるとき、メソッド名が自動補完されるのを期待するのはごく自然なことと思います。

解決

つい先日リリースされたばかりの、neco-rubymfというneocomplcacheプラギンを用います。

インストール:

  • Rubygemsパッケージmethodfinderをインストールします。

      $ gem install methodfinder
    
  • neocomplcacheプラギンneco-rubymfをインストールします。もしも未だにneocomplcacheをインストールしていなければ、そちらもインストールして下さい。

続いて、'filetype'rubyであるバッファで、以下のように入力します(ただしはカーソルのつもりです。)

1.¶ #=> 2

すると、1というオブジェクトが持つメソッドでかつ返り値が2であるメソッド nextsuccが補完候補にあらわれます。

neco-rubymf

同様に、

[:a, :b, :c].¶ #=> :a

に対して

array

が得られます。

以下に他の例を画像で示します。

1

2

3

※最後の例は確率的に発生します。

ujihisa

Hack #229: 動的型付け言語Rubyでメソッド名などを自動補完する

問題

静的型付け言語Haskellでの自動補完はHack #211で紹介しました。このときは補完候補の取得にghc-modという外部コマンドを用いました。補完候補を自動的に出力するためにneocomplcacheというVimプラギンを用いました。

動的型付け言語Rubyにおける自動補完はどのようにすれば達成できるでしょうか。Rubyのように非常に静的な解析が難しい言語では、メソッド名などの候補の取得が非常に困難であることが知られています。そもそも現在参照している式あるいは変数がどのクラスに属しているか、ほとんどのケースでは静的に決定することができません。クラスが分かったとしても、その変数のみが特異メソッドを持っているかもしれません。

解決(1/2)

Rubyでメソッド名を手動補完するために使えるものは、標準添付のvim-rubyというVimプラギンと、m2ymさんによって開発されたRSenseがあります。

vim-rubyは、+rubyであるVim環境(*1)における補完機能を提供します。 Ruby組み込み定数・クラス・グローバル関数(*2)などが補完できます。 詳しくは:h ft-ruby-omniを参照してください(*3)。 補完関数はオムニ補完として定義されているので、デフォルトの設定では、挿入モードで<C-x><C-o>と打鍵することで補完機能を実行することができます。

vim-rubyが諦めた部分は

  • 編集中ファイル内で定義された定数・クラス・メソッドなどへの補完
  • 文脈に応じたメソッド名の補完 (例えば1という数値オブジェクトに対してはFixnumクラスに定義されたメソッドのみが補完されるべき)

です。これらに対応するためには、Rubyのパーサなどを実装する必要があり、かなり大変です。またそもそも処理に時間がかかりすぎ、補完機構としはやりすぎと判断したのかもしれません(*4)。

図1: vim-rubyが正しく補完候補を生成している例

図2: vim-rubyが正しくない補完候補を生成してしまっている例

一方RSenseは、vim-rubyが提供している機能にさらに加えて、上記の諦めた部分にも対応しています。

図3: RSenseが正しく補完候補を生成している例

RSenseの補完関数もオムニ補完として定義されています。デフォルトでは、挿入モード時に<C-x><C-o>と打鍵することで補完のポップアップがでてきます。なお、初回起動時は若干時間がかかりますが、二回目からは非常にすばやいです(*5)。

解決(2/2)

手動補完がいかに実用的でないかは過去のVim Hacksで散々と述べられてきました。

通常の補完ではユーザーが明示的に補完のためのキーを押す必要がありました。つま り、「頭が補完をする」と考えなければ補完ができないのです。これにより、作業効 率が落ちてしまいます。それならばシステムが自動的に判断して、補完のためのキー を押したらどうでしょうか。これでユーザーはやらなければならない作業のみに集中 することができます。Vim7よりオムニ補完が実装されたので、Visual Studioのように 「関数やメンバを補完」は実現できるようになりました。しかし、そこには「自動的 に」が欠けているのです。

Shougo 2009 http://vim-users.jp/2009/07/hack-44/

自動補完を用いましょう。RSenseはneocomplcacheと連携することで自動補完として使うことができます。

RSenseを公式ドキュメントに従ってインストールした上で、~/.vimrcに以下の記述を行ないましょう。

if !exists('g:neocomplcache_omni_patterns')
  let g:neocomplcache_omni_patterns = {}
endif
let g:rsenseUseOmniFunc = 1
if filereadable(expand('~/git/rsense/bin/rsense'))
  let g:rsenseHome = expand('~/git/rsense')

  let g:neocomplcache_omni_patterns.ruby = '[^. *\t]\.\w*\|\h\w*::'
endif

ただし、'~/git/rsense/bin/rsense''~/git/rsense'の部分を自身の環境に合致する内容にしてください。

なお、この設定は、neocomplcache作者により書かれた以下の記事を参考にしています。

http://vinarian.blogspot.com/2010/03/rsenseneocomplcache.html

補足

RSenseですら、特異メソッドには対応していないようです。

a = Object.new
def a.hello
  :world
end
a.

ここからhelloを補完することはできません。(*6)

脚注

  • *1 :versionして+rubyがあるかどうか調べてみてください。まあ、不必要です。
  • *2 本記事の読者がRuby使いには限らないことを考慮して”グローバル関数”と記述しましたが、実際にはRubyに関数は存在しません。Kernelなどに定義されているpなどのメソッドを便宜的にそのように読んでみました。
  • *3 なお、ドキュメントに書かれているからといって実際に動作するとは限りません。私の環境では実際に試してみると動作しないものがたくさんありました…。
  • *4 g:rubycomplete_buffer_loadingg:rubycomplete_classes_in_globalを設定し、かつ+rubyな環境であればそれらにも対応しているとドキュメントに書かれています。お試しください。常用するのはかなり難しいようです。
  • *5 初回起動時にこっそりと補完サーバを立ち上げるためです。なお、Windows環境の場合は特別な設定が必要なようです。詳しくは公式ドキュメントを参照ください。
  • *6 この例だとhelloメソッドが同じバッファで定義されているのでneocomplcacheのバッファ内キーワード補完が働き、helloが補完対象にあらわれます。が、これはオブジェクトaだけでなくすべての対象に働いてしまいます。また、helloの定義がそのバッファ内でないなら、当然ながらお手上げです。

参考文献

Vanrb Lightning Talk Slides: Ruby and Vim

非常にわかりやすい図がたくさんあります。

ujihisa

Hack #228: 見た目を気軽に変更する(その2) ColorRoller版

問題

vim を長い間使用していると、お気に入りの定番カラースキームが3、4種類は決まってくるものです。

お気に入りのカラースキームを探す場合は、

  1. Color Sampler Pack をインストールする。
  2. :Unite colorscheme を駆使して片っ端から気に入るものを探す。

という流れで探すのが便利で手軽だと思います。

:Unite colorscheme によるカラースキームの変更は一つ一つ :colorscheme コマンドでカラースキームを入力する手間に比べればとても手軽です。
しかし、一度お気に入りが決まってしまうと、 もっと手早くカラースキームを切り替えたいと感じる方もいるのではないでしょうか?

問題提起が少し強引な気もしますが、筆者はお気に入りの3、4種類のカラースキームをワンキーで手早く切り替えたいと感じていました。

対処

下記のコードを .vimrc に貼り付けます。

let ColorRoller = {}
let ColorRoller.colors = [
      \ 'molokai_custom',
      \ 'tomorrow_night_custom',
      \ 'lucius_custom',
      \ 'github256_custom',
      \ 'pyte',
      \ 'newspaper',
      \ ]

function! ColorRoller.change()
  let color = get(self.colors, 0)
  " tabpagecolorscheme を使用している場合は↓の "colorscheme" を "Tcolorscheme" に変える。
  silent exe "colorscheme " . color
  redraw
  echo self.colors
endfunction

function! ColorRoller.roll()
  let item = remove(self.colors, 0)
  call insert(self.colors, item, len(self.colors))
  call self.change()
endfunction

function! ColorRoller.unroll()
  let item = remove(self.colors, -1)
  call insert(self.colors, item, 0)
  call self.change()
endfunction

nnoremap <silent><F9>   :<C-u>call ColorRoller.roll()<CR>
nnoremap <silent><S-F9> :<C-u>call ColorRoller.unroll()<CR>

解説

お気に入りのカラースキーム群をローラー( ColorRoller )に見立てて、ローラーを回す( roll )、戻す( unroll )ことで、カラースキームを切り替えます。
roll()<F9>unroll()<S-F9> (Shiftキーを押しながら <F9> )にそれぞれ割り当てています。

使い方

お気に入りのカラースキームを、 ColorRoller.colors に設定して使用します。

tabpagecolorscheme を使用している場合、 ColorRoller.change() 内のコメントを参考に、
silent exe "colorscheme " . color の行を silent exe "Tcolorscheme " . color に変更して使用して下さい。

最後に

これまでに紹介したカラースキームに関する下記の記事も合わせて参考にして下さい。

t9md

Hack #227: surround.vim の囲むルールを独自に拡張する

surround.vim について

テキストを好きな文字列で”囲む”ことに特化したプラグインとして、surround.vim があります。
定番プラグインなので使用している方も多いでしょう。

デフォルトで、テキストを括弧( [([{ 等)や、HTMLタグで囲んだりする事が出来ます。

surround.vim は囲むルール( 以降 surrounding rule と記載 )を拡張する機能を用意しており、ユーザーが独自に surrounding rule を追加することが出来ます。

surrounding rule の拡張

例えば下記のような設定は

autocmd FileType ruby let b:surround_45 = "<% \r %>"

&filetype が ruby 場合に let b:surround_45 = "<% \r %>" を設定しています。

  • b:surround_4545- の ASCII コード番号です。
  • \r は囲まれるテキストが入るプレースホルダです。

上記のように設定すると、

puts "Hello world!"

の行にカーソルを合わせ、ノーマルモードで yss- と入力すると、下記のように eruby のコードとして囲む事ができます。

<% puts "Hello world!" %>

しかし、毎回 ASCII コードを確認して設定するのは面倒なので、 char2nr() を使用し、下記のように設定する方が分かりやすいでしょう。
以下の設定は E で囲まれるテキストをヒアドキュメント化します。

let b:surround_{char2nr("E")} = "<<EOS \r EOS"

surrounding rule のより詳細な説明は :help surround-customizing を参考にして下さい。

さらに簡単に surrounding rule を拡張する

さて、ここまでは前置きで、目的は基本知識の整理だったのでした。
上述の surrounding rule の拡張をより簡単に行う為の、簡単なプラグインを作成しました。

インストール

Vundle を使用している場合以下のコマンドでインストール出来ます。

:BundleInstall t9md/vim-surround_custom_mapping

設定

g:surround_custom_mapping ディクショナリを設定します。
キー に surrounding rule が設定される &filetype 、値には surrounding rule をディクショナリとして設定します。
キー _(アンダースコア)は特殊なキーで、ここに設定された surrounding rule は全てのファイルタイプで利用できるようになります。

例えば下記の様に設定すると

let g:surround_custom_mapping = {}
let g:surround_custom_mapping._ = {
            \ 'p':  "<pre> \r </pre>",
            \ 'w':  "%w(\r)",
            \ }
let g:surround_custom_mapping.ruby = {
            \ '-':  "<% \r %>",
            \ '=':  "<%= \r %>",
            \ }
  • ppre タグで囲む(全てのファイルタイプで有効)
  • w%w() で囲む(全てのファイルタイプで有効)
  • -%<%> で囲む(ruby ファイルのみ)
  • =%<=%> で囲む(ruby ファイルのみ)

という意味になります。

より具体的な例

もともと私がこのヘルパープラグインを作ったのは

  • html を編集していようが、
  • textile を編集していようが、
  • vim のヘルプを編集していようが

p で整形済みテキストとして囲むというように、似た様な意味(=整形済みテキスト)で囲む場合は、指運動を同じにしたかった からです。
意味に対応する指運動(=運指)が別だと覚えるのが大変です。
上記を実現する設定は下記になります。

let g:surround_custom_mapping = {}
let g:surround_custom_mapping.help = {
            \ 'p':  "> \r <",
            \ }
let g:surround_custom_mapping.textile = {
            \ 'p':  "<pre> \r </pre>",
            \ }
let g:surround_custom_mapping.html = {
            \ 'p':  "<pre> \r </pre>",
            \ }

最後に

このプラグインを作った際、surround.vim 作者の tpope さんに Pull Request を送りました。
取り込まれはしませんでしたが、8/7 日頃に「 来月か、再来月位に新しいのを出す予定、それまでこの pull request はオープンにしておくよ。」と返事をくれました。
ですので、もしかすると9月か10月頃には surround.vim のニューバージョンがリリースされ、今回紹介したプラグインは不要になっているかもしれません。

t9md

Home > Tags > lv2

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

    Return to page top