Viを模倣する

Viper-mode

”M-X Viper-mode”を実行するとViのように挿入、ノーマルモードで活動ができるようになります。
でも、完全なViのキーバインドは使えません。
触った時は、以外とイイかもしれないとか思って楽しんでいたのですが、早々と限界を感じました。
ググりながら、途中まで設定をしたので記念に貼り付けておきます。

~/.viper

(setq viper-inhibit-startup-message 't)
(setq viper-expert-level '3)

;; backspace
(define-key viper-insert-global-user-map [backspace] 'backward-delete-char)
;; delete
(define-key viper-insert-global-user-map [delete] 'delete-char)

;; 行の初め/終わ
(define-key viper-vi-global-user-map(kbd"0") 'move-beginning-of-line)
(define-key viper-vi-global-user-map(kbd"$") 'move-end-of-line)

;; window操作
(define-key viper-vi-global-user-map(kbd"\C-w\C-w") 'other-window)
(define-key viper-emacs-global-user-map "\C-w\C-w" 'other-window)
(define-key viper-vi-global-user-map "\C-w\C-w" 'other-window)
(define-key viper-emacs-global-user-map "\C-w\C-o" 'delete-other-windows)
(define-key viper-vi-global-user-map "\C-w\C-o" 'delete-other-windows)
(define-key viper-vi-global-user-map "\C-w\h" 'windmove-left)
(define-key viper-vi-global-user-map "\C-w\j" 'windmove-down)
(define-key viper-vi-global-user-map "\C-w\k" 'windmove-up)
(define-key viper-vi-global-user-map "\C-w\l" 'windmove-right)
(define-key viper-emacs-global-user-map "\C-w\h" 'windmove-left)
(define-key viper-emacs-global-user-map "\C-w\j" 'windmove-down)
(define-key viper-emacs-global-user-map "\C-w\k" 'windmove-up)
(define-key viper-emacs-global-user-map "\C-w\l" 'windmove-right)

;; dired を少しだけ vi 風に
(define-key viper-dired-modifier-map "j" 'dired-next-line)
(define-key viper-dired-modifier-map "k" 'dired-previous-line)
(define-key viper-dired-modifier-map "/" 'dired-goto-file)
(define-key viper-dired-modifier-map "l" '(lambda () (interactive) (dired-next-line 10)))
(define-key viper-dired-modifier-map "h" '(lambda () (interactive) (dired-previous-line 10)))

Comment

  • 限界を感じた箇所はキーバインドで、Vimに似てるんだけどまだまだ足りない。
  • elispをもうちょい学習しとけば、それなりにキーバインド等が弄れて楽しいかもしれない。
  • 慣れていないせいで、elispで必要な物と意味を調べるのにやたらと手間がかかる。
    Vimだと適当に:h XXXXとかで探せるのになぁ)

自動補完を使う_その2

neocomplcache

前回の続きでneocomplcache偏です。
まず、自分の環境はばっさり書くとこんな感じになります。

  • OS
  • VIM
    • Insertモードでもカーソルキーで移動し始めることもしばしば。
    • mswin.vimから必要なキーバインドだけ.vimrcに取り込んでる。(C-X,C-C,C-Vは手放せない。)

前回のあらすじ

  • neocomplcacheを使うと暴走して置換されて大変な事になった。
  • AutoComplPopがお手軽だったので、一瞬で乗り換えた。
  • コメントでneocomplcacheについての助言をもらったので再挑戦。
  • せっかくなので高機能なものを使いたいから頑張ってみた←今ココ

neocomplcacheの設定

let NeoComplCache_EnableAtStartup = 1
let NeoComplCache_ManualCompletionStartLength = 3
let NeoComplCache_MaxList = 20
let NeoComplCache_EnableCursorHoldI = 0 "値を1にしてキー操作時に音が鳴る場合は set visualbell t_vb=

Shougo 2010/04/16 14:40
neocomplcacheの最新版で、CursorHoldIを使って補完できるようになりました。
let g:NeoComplCache_EnableCursorHoldI = 1
で使えます。試してみてください。
こちらでやってみたところ、カーソル移動では補完されないことを確認しました。

試してみました。
補完はされませんでしたが、拒否音?ピープ音がキー操作のたびに鳴っていました。

そこで、何とかならないかなーと思いつつ考えた結果、
s:skip_next_completeという変数を見つけたのでこれを利用してみることにしてみました。
更に補完ポップアップのタイミングを以下のように、ごにょごにょ。

  1. ポップアップ表示時、押しても補完が継続する
  2. ポップアップ非表示時、押しても補完しない
  3. ポップアップ非表示時、カーソル移動した場合補完しない
  4. 文字入力時、カーソル移動した場合、補完PopUpが表示されなくなる

/autoload/neocomplcache.vim に以下を追記

function! neocomplcache#skipcompl()
	let s:skip_next_complete = 1
endfunction

.vimrc に以下を追記

function! NeoComplCacheWrapper(Mapping)
	if !pumvisible()
		call neocomplcache#skipcompl()
	endif
	execute 'return "\<'.a:Mapping.'>"'
endfunction

inoremap <expr><Up> NeoComplCacheWrapper('Up')
inoremap <expr><Down> NeoComplCacheWrapper('Down')
inoremap <expr><Left> NeoComplCacheWrapper('Left')
inoremap <expr><Right> NeoComplCacheWrapper('Right')
inoremap <expr><BS> NeoComplCacheWrapper('BS')
inoremap <expr><Del> NeoComplCacheWrapper('Del')

ひとまず、これで個人的満足度は上がったかなぁ。
入力したい(してる)時だけ補完が見えるように。

Comment

  • return <引数>で上手く動作させれなかったので、if,elseif文が無駄に多いです。解決済み
  • ちょっと古いg:NeoComplCache_EnableCursorHoldIの含まれていないバージョンを触っていて、"あるぇー"とか言いつつキーバインド作ってました。
  • よく見ると、補完ポップアップのタイミングの一部間違ってる。(文字入力時、カーソル移動した場合、補完PopUpが表示されなくなる⇒PopUp非表示になるまでカーソルで移動するとその後表示されなくなるってのが正しい気がする。また今度考えよう…。)

自動補完を使う

Usability

VimだとC-N,C-Pを押すと補完が使えるのだけど、大文字小文字が含まれてる文字列を入力するのが辛いのでもっと良いものは無いかなと自動補完のプラグインを探してきました。

前から、色々記事を見ていて知っていたんだけど、必要になるような事をしていなかったので使っていなかっただけど。(正確には一度入れて合わなくてはずした)
参考記事はこのあたり。

実際に試したものは、

期待するものとしては、以前emacsを触っていた時と同じような補完が出来ること(auto-complete.el, anything.elとかを入れていたのは覚えていて、動作はかなりうろ覚え)

試した結果

"neocomplcache"は前に一度諦めて、尚且つ今回試して挫折しました。
"AutoComplPop"を使ってみる方向に決定。

neocomplcacheをろくに設定せずに使った結果、自分はWindows環境でgVim使っていてカーソルキーもよく押してしまう人なので案の定、移動する度に補完が暴走して果てました。
そこでNeoComplCache_SkipCompletionTimeなどの設定を見直しつつ、途中まで設定して諦めて次に移りました。
次に使ったAutoComplPopが意外とシンプルで期待に近い動きを何も設定しなくてもしていたので即採用しました。

AutoComplPopを使い易くする
TODO
  • 単語入力中だけ補完候補を出したい。(元からある単語を"BackSpace"で削除する時も補完候補が表示されても困ったり…)
  • よく似た大文字小文字の入り乱れた文字列入力の効率を上げたい。(ex. abcAef, abcBef...etc)

Comment

  • 用意されたものを使ったことがあるだけだったので、補完がどう動くと便利かなんて考えた事も無かった。けど、複数種類があると知るとどれを使おうか悩む。

Cygwinで削除できないファイル

Problem, Solution

Cygwinが必要なくなったので、アンインストールしようとしたときに詰まった。

一般的にインストールすると、"C:\cygwin\"にインストールされるので
このフォルダごと削除しようとした際に、"C:\cygwin\dev\nul"ファイルが削除できないエラーが出た。
Windows上においてのnulは特別らしく、そのせいで削除が出来なかった。
(補足:Cygwinアンインストーラーが無いので自分で削除する必要がある)

詳しくは以下のサイトに書かれてる

コマンド

以下のコマンドで削除できる。

C:\> del \\.\C:\cygwin\dev\nul

Comment

  • Cygwinをアンインストールした理由は、CygwinからMinGWに切り替えたため。

NetrwとNERD_tree

Problem

  1. 環境
  2. 再現手順:
    1. ファイラーを起動
    2. タブを作成
    3. ファイラーのタブに戻ってくる
    4. ExploreがNERD_treeに変わっている ←問題
  3. 問題
    • 普段のファイラーとしてはnetrwを使いたいのに、使えない時があるのは困る

コマンドで表すと以下の感じ

:Explore " ファイラーを起動
:tabedit " タブを作成
:tabNext " タブを移動(トグル)
" (NetrwからNERD_treeに変わる)

Comment

  • NERD_treeのオプションで指定して変更されないように出来るのかな。

vimからコマンドを実行する_その2

Problem,Solution

Netrwを利用して、x:execしようにも動かないので、色々試すと更にはまったので、DOSプロンプトで挙動を確認する。

  • 一般的に良くある、空白を含むフォルダ名を渡す
C:\>start C:\Documents and Settings\
ファイル C:\Documents が見つかりません。
  • ダブルクォートで囲む
C:\>start "C:\Documents and Settings\"

C:\>
(もう一個、DOSプロンプトが起動する)
  • ウィンドウタイトルを指定する
C:\>start "" "C:\Documents and Settings\"
rem シングルクォート ' で囲むとエラーなので注意

無事、エクスプローラを起動させる事に成功。

Netrwの動作

g:netrw_browsex_viewer = '' の時

" vim72-kaoriya-w32j/runtime/autoload/netrw.vimの以下の判定に入る
" :省略
  elseif has("win32") || has("win64")
   if executable("start") " 偽 うちのPCだけ?
"    call Decho('exe silent !start rundll32 url.dll,FileProtocolHandler '.shellescape(fname,1))
    exe 'silent !start rundll32 url.dll,FileProtocolHandler '.shellescape(fname,1)
   elseif executable("rundll32") " 真
"    call Decho('exe silent !rundll32 url.dll,FileProtocolHandler '.shellescape(fname,1))
    exe 'silent !rundll32 url.dll,FileProtocolHandler '.shellescape(fname,1)
   else
    call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
   endif
   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
   let ret= v:shell_error
" :省略
問題点
if executable("start") " 偽、うちの環境だけ?
elseif executable("rundll32") " 真
 exe 'silent !start rundll32 url.dll,FileProtocolHandler '.shellescape(fname,1) " ←問題はココ
サンプル
C:\>start rundll32 url.dll,"C:\Documents and Settings\"
" 実行結果:何も起きない、詳細は不明
C:\>rundll32 url.dll,"C:\Documents and Settings\"
" 実行結果:何も起きない、詳細は不明
DOS上で動いたようにコマンドを書き換える
 exe 'silent ! start "" "'.fname.'"'
" shellescapeの二番目の引数がヘルプを見ても、よく分からないが'(シングルクォート)で囲まれるため実行出来ない

WindowsでもNetrw上でxコマンドが使えるようになる!

補足説明

g:netrw_browsex_viewer = 'オプション'
  1. "kfmclient exec"
  2. gnome-open"
  3. "-"
    • netrw_filehandlerに基づいて、アプリを起動
      Linux用の設定が書かれています。
  4. ""(何も入れない)
    • Windowsであれば、これで問題無いかなと。

vimからコマンドを実行する

Problem,Solution

コマンド実行で詰まった所が解決した。

:! コマンド

という、単純な話なんですが、コマンド実行で失敗するパターンに遭遇した。
次のコマンドだと、失敗。

" Firefoxを起動させる
:!start firefox http://google.com/
E371: コマンドがありません
続けるにはENTERを押すかコマンドを入力してください

次のコマンドだと、成功。

" Firefoxを起動させる
:! start firefox http://google.com/

でも、次のコマンドも成功。

" ファイル一覧を表示
:!dir


更に、次のコマンドも成功(?)してプロンプトで表示される。

" ファイル一覧を表示(?)
:!dir dir

結果としては、最後の分だけ良く分からないが、(どこか参照した結果で最初に弾かれる?)
半角空白入れずに引数を付けると、どうも良くないらしい。
コマンド実行する場合は、半角空白を入れたほうが無難。

Comment

shell関連の設定は以下の通りでした。
NYACUSをshellに設定(参考サイト:Vim-users.jp - Hack #103: シェルをNYACUSに設定する)

" Shell settings.
" Use NYACUS.
set shell=nyacus.exe
set shellcmdflag=-e
set shellpipe=\|&\ tee
set shellredir=>%s\ 2>&1
set shellxquote=\"