rxvt: 何故かShift-Tabが使えない

2007-01-31T00:43:00 / software, cygwin / comment

普段ja patched rxvt-2.7.10-6 on Cygwinを使っているのですが、何故かShift-Tabが使えないことに気付きました。より正確には、Shift-Tabを押したときに送られる文字が\033 [ Zではなく\011 (水平タブ) になります。このままだとShift-Tabに何か機能を割り当てることができません。無くても生きていけますが、少々不便。

何でだろう。ソースを見たところ、Shift-Tabに対して\033 [ Zを送る箇所があるので、取り敢えず原因はそれ以前の段階のはず。どこだ。

Vim: 怠惰になってきた

2007-01-31T00:38:00 / vim / comment

最近の.vimrcの追加内容:

nnoremap ; :
vnoremap ; :

もうShiftを押すことすら諦めた。

Vim: :highlightの設定をコピー

2007-01-23T23:36:00 / vim / comment

Vimの:highlightの設定を変更する場合、既存の設定をそのまま使うには:highlight link {from-group} {to-group}を使います。大抵の場合はこれでも十分なのですが、linkしたグループの設定を変更することはできないので、「既存の設定をそのまま使うが一部の値は変更したい」という場合には使えません。

という訳で発想を変えて「:highlightの設定をコピーして一部の値を変更する」ことにしました。

function! s:ExtendHighlight(target_group, original_group, new_settings)
  redir => resp
  silent execute 'highlight' a:original_group
  redir END
  if resp =~# 'xxx cleared'
    let original_settings = ''
  elseif resp =~# 'xxx links to'
    return s:ExtendHighlight(
         \   a:target_group,
         \   substitute(resp, '\_.*xxx links to\s\+\(\S\+\)', '\1', ''),
         \   a:new_settings
         \ )
  else  " xxx {key}={arg} ...
    let t = substitute(resp,'\_.*xxx\(\(\_s\+[^= \t]\+=[^= \t]\+\)*\)','\1','')
    let original_settings = substitute(t, '\_s\+', ' ', 'g')
  endif

  silent execute 'highlight' a:target_group 'NONE'
           \ '|' 'highlight' a:target_group original_settings
           \ '|' 'highlight' a:target_group a:new_settings
endfunction

使用例は次のような感じ:

autocmd ColorScheme *
    \   call <SID>ExtendHighlight('Pmenu', 'Normal', 'cterm=underline')
    \ | call <SID>ExtendHighlight('PmenuSel', 'Search', 'cterm=underline')
    \ | call <SID>ExtendHighlight('PmenuSbar', 'Normal', 'cterm=reverse')
    \ | call <SID>ExtendHighlight('PmenuThumb', 'Search', '')

しかし、Vim7のデフォルトのPmenuのハイライトはどうにかならないものかなぁ。それに添付のcolor scheme全て (ただしdelekを除く) で設定がないため、color schemeによっては見れたものではない場合があります。

bluewind 1.60r1でメモリリーク

2007-01-23T22:21:00 / software, windows / comment

以前から稀にbluewindシステムリソースが足りませんというエラーが出ます。一度出るとbluewindを再起動しない限り直りません。エラーの発生するタイミングは補完中のため、使用不能に近い状態になります。

で、今回、何となくエラーが発生し始める条件が分かりました。Windowsを長時間起動していたときに良く起こります (私の場合、PCの電源を落とす代わりに休止状態にするのですが、起動しっぱなしと同様の状態と考えられます)。

「長時間起動 + リソース不足のメッセージ = メモリリーク」と思ったのでタスクマネージャを開いてみたところ……こりゃアウトだ。USERオブジェクトとGDIオブジェクトの数が異常。起動直後はどちらも3桁に届かないレベルなのに。

その後、色々と試しているうちに補完動作でリークが起こっていることが判明。どうしたものか。

Vim: 行継続は:sourceでのみ有効

2007-01-22T06:37:00 / vim / comment

Vim scriptの行継続が使えるのは:sourceされた場合のみです。

Vim scriptの行継続は「次の行の行頭が\なら継続」という文法なので、コマンドラインからインタラクティブに実行する場合に使えないのは当然なのですが、:executeで実行するスクリプト内でも使えません。

別に:execute中で使えてもいいんじゃないかなぁ……

Opera: サーチエンジンのキーワードに2文字以上使えるようになってる

2007-01-22T00:34:00 / opera / comment

ふと思いついて試してみたところ、Operaのサーチエンジンのキーワード (デフォルトだとg fooでGoogle検索できる。このgのこと) に2文字以上の文字列が使えるようになってました。昔 (記憶している限りではOpera7まで) は1文字しか登録できなかったのですが、何時の間に変わったのやら (Opera 9.10で確認)。

ずっと1文字限定だと思っていたので少々不便に思っていたのですが、これである程度改善されました。例えばweを英語版Wikipediaの検索に、wjを日本語版Wikipediaの検索に割り当てることができます。1文字限定だとこういう場合に困るのです。

ただ、キーワードの大文字小文字を区別しない点は昔から変わっていないようです。個人的には「小文字で通常の検索」、「大文字でその変化形」という風に使いたいのでけどね (例: gでGoogle検索、GでI'm feeling lucky)。

Vim: Emacs like scratch buffer

2007-01-20T22:56:00 / vim, release / comment

VimでEmacs likeなscratch bufferを提供するプラグインを書いてみました。あったらあったで便利なものですし。細かいところは使っていくうちに弄るかな。

欠点としては、複数行のスクリプトの実行は明示的に選択してから行うことと、スクリプトの実行結果をバッファに挿入できないことです。どちらもVim scriptなので仕方がありません。あれば便利なのですが、使う機会を考えるとなくても別に困らないと思います。

Vim: 任意の名前のバッファを作成する (警告は出さずに)

2007-01-20T02:20:00 / vim / comment

Vimで任意の名前のバッファを作成する方法:

  1. hide enew -- 無名のバッファを作る。
  2. setlocal noswapfile -- スワップファイルを使わないように設定する。
  3. file `='set name as you like'` -- バッファの名前を設定する。ワイルドカード等の問題を回避するため、変数か文字列を`=...`経由で渡すとよい。

作成するバッファがスワップファイル不要かつ分かり易さのために任意の名前を付けたい場合 (例えばプラグイン等で一時的な情報を提供するため) に使います。スワップファイルはバッファ名をベースとした名前で作成されるため、バッファ名にワイルドカード等が含まれていると警告 (E303) が表示されます。自動処理したい場面で一部の種類の警告が発生すると確認のプロンプトが表示されるため、困ったことになります。

今日はこれだけのためにかなり時間を食われました。無名バッファを開く方法はnewしか知らなかったのが主な原因。本来の目的はEmacs likeなscratchバッファを提供するプラグインを書くことだったのですが、今日はもう公開する気力が尽きたのでまた今度。

親指が痛む

2007-01-16T22:18:00 / diary / comment

何故か急に右手の親指が痛み始めました。指の付け根から手首までの間辺りに時折痛みが感じられます。親指を曲げたり力んだりした際に痛むことが多い気がするし、痛みが何だか腱鞘炎に似てるので、多分腱鞘炎気味なのかな。

仮に腱鞘炎だとすれば何か原因があります。そして思いつくのはキーボードの叩きすぎしかありません。でも右親指はそんなに使う指ではないしなぁ……

……と書いてたら気付きました。日本語入力時のIMEのON/OFFの切り替えです。切り替えは右Altで行っているのですが、これを押すときの右手の位置や姿勢に少し無理があります。

使用しているキーボードはHHK Lite2 (US配列) なのですが、これで右Altを右手の親指で打つことを想像してください (ただしAltの位置は交換しています)。どうしても右親指を内側に曲げなければなりません。右手首をずらせばある程度軽減できるものの、それでも少々無理があります。

しかし仮にこれが原因だとしても、ホットキーをどこに変えればいいんでしょう? スペースキーの右側を分割して独立させれば無理なく押せる位置になりますけど、それは物理的に無理です。これが普通のJIS配列のキーボードであれば、Ctrl (小指で付け根で押す) か変換ひらがな (親指で押す) を右Altに割り当てることで解決できるのですけど。こういう時はHHKのコンパクトさがデメリットになりますね。

財布に余裕があればキーボードを買い換えようかなぁ。最近はKinesis Contoured Keyboardに心を惹かれるものがあるのですが、さすがに「高い」・「でかい」・「海外」の三拍子が揃ってるので迷ってます。

痛みは大分引いてきました。でもIME ON/OFFのキーは変えようかと思います。やはり今のままだと遠い。

ホームポジションでLの上に置いた薬指を滑らせる感じの押し方は……うーん、キーボードに対して手首の位置が高ければそれも良いかな。というのも、普段から手首を机に置いてタイピングしているので、その方法だと.が薬指に引っかかります。小指で右◇を押すなら引っかかりませんけど、これだと指の曲げ具合が大きくなるので今一。

位置的にが右手の側面で押せてナイスなのですが、さすがにを潰すのは怖い。次に良いのは右Shiftなのですが、既に\に割り当ててるので無理。

うーん、Vimの+multi_byte_imeがWindows GUI版以外でも使えたら大分軽減されるんですけどね……

RSS: 記事の全文配信を開始

2007-01-14T21:41:00 / site / comment

このサイトの更新情報配信用のRSSですが、各記事の全文も含めるようにしました。

内容については一通り確認しましたが何か問題が残ってるかも知れません。調べた範囲では、Bloglinesだと<rss:description><content:encoded>よりも優先されてしまうことを確認しました。でも他のサイトのRSSだと<content:encoded>の方が優先されるという謎。ぱっと見た感じでは両者に差異はないと思うのですけどね。

Vim: セクション/関数単位の移動の改善 (2)

2007-01-13T02:20:00 / vim / comment

Vim: セクション/関数単位の移動の改善で書いた設定ですが、実は落とし穴がありました。設定自体は間違っていないものの、ファイルの種類によってはftpluginにより後からバッファローカルなkey mappingsが追加されるため、結果として設定がオーバーライドされてしまいます。

という訳で、問題のkey mappingsを強制的に削除すればOK。

autocmd FileType * call <SID>FileType_any()

function! s:FileType_any()
  silent! vunmap <buffer> ]]
  silent! vunmap <buffer> ][
  silent! vunmap <buffer> []
  silent! vunmap <buffer> [[
  silent! ounmap <buffer> ]]
  silent! ounmap <buffer> ][
  silent! ounmap <buffer> []
  silent! ounmap <buffer> [[
endfunction

問題はこの対策が必要になるファイルの種類がデフォルトでは三つしかないこと。その一つがvimなのでまあいいかな (実際、上記コードのコピーに役に立ったし)。

ところで、削除するkey mappingsが未定義だった場合のエラーの抑制は簡潔にできないんですね。他のコマンドと同様にunmap! {lhs}で済むのかと思ったら、これだと別の意味になってしまう。この辺は歴史的事情というものなのかな。

ああああ……エラーを無視するだけならsilent! {command}でできる。こちらを使うように修正。

Vim: Key mappingの落とし穴

2007-01-09T18:33:00 / vim / comment

Vimの落とし穴: Key mappingの展開結果でもモードの切り替えは起こる。当然のことなのだけど、特定のモードのmappingしか定義してないときに引っかかることがある。例えば次のような感じ:

nnoremap (some-action) ...
nnoremap (another-action) ...

nmap (wrong-action) (some-action)v(another-action)

この場合(wrong-action)の展開結果は「(some-action)の後、visual modeに切り替え、(another-action)を行う」という動作になり、(another-action)に対してvisual mode用のmappingが定義されていないので困ったことになります。

今日はこれで30分くらい詰まった。

Vim: Abbreviationsとkey mapping

2007-01-09T17:48:00 / vim / comment

Vimのabbreviations (:abbreviate) だけど、これはkey mappingと何が違うんだろうか? 少々の差異はあるものの、abbreviationsでできることはkey mappingで十分に賄えるはず。ならばこの二つを分けている理由は何なのだろうか?

両者の差異は:help usr_40.txtのMAPPINGS AND ABBREVIATIONSに述べられている:

ポイント Abbreviations Key mapping
展開するタイミング Non-word characterを入力したとき Key mappingの最後の文字を入力したとき
入力中 入力した文字列はそのまま挿入され、abbreviationが展開される際に置き換えられる。 Key mappingが動作するまで何も入力されない (入力状況はオプション'showcmd'が設定されていれば表示される)。
曖昧な展開元文字列 存在しない (動作するタイミングから曖昧になりえない)。 一定時間の間に入力があるかないかで判別。

……こうやって眺めてたら分けてるのは当然な気がしてきた。

Vimの嫌いなところ: Key mapping

2007-01-09T00:32:00 / vim / comment

Vimの嫌いなところ: 原因は各機能に名前がなく、デフォルトのキーバインドで指定しなければならない点。特にkey mappingやnormal modeのコマンドを指定する際に顕著になる。

些細なもの (例えばcnoremap <C-U> <C-E><C-U>程度) ならまだ読めるからいいものの、ちょっと凝ったことをすると即座に解読不能な代物になる。normal! ggj0vG$hyなんて何がしたいのか書いた本人でさえさっぱり分からない。

少しでも良いから読みやすくしようと、normal! ggj0 v G$h yのようにある程度の塊で分けて書きたくなるのだが、そうすると動作が変わってしまう。どうしろと。

……と、ここまで書いてて思いついたのだけれど、

noremap (forward-char) l
noremap (backward-char) h
noremap (next-line) j
noremap (previous-line) k

という風に「名前」を付けてやれば

map <C-L> 4(forward-char)

のようにして名前で指定することもできなくはない。

さらに読みやすさのためのスペースもnoremap <Space> <Nop>とすれば不可能ではない。

まあnoremap等の{rhs}には使えないし、command-line modeに適用するには少々無理がある (大体は問題ないと思うが)。結局のところ解決にはならない。

Vim: dosini (*.ini) 用: セクション単位の移動

2007-01-07T03:23:00 / vim, windows / comment

Vimでdosini (*.ini) 用のセクション単位の移動を行う設定。JumpSectionN自体は汎用なので他のものを書くときにも使える (と思う)。

autocmd FileType dosini call <SID>FileType_dosini()
function! s:FileType_dosini()
  nnoremap <buffer> <silent> ]] :<C-U>call JumpSectionN('/^\[')<Return>
  nnoremap <buffer> <silent> ][ :<C-U>call JumpSectionN('/\n\(\[\)\@=')<Return>
  nnoremap <buffer> <silent> [[ :<C-U>call JumpSectionN('?^\[')<Return>
  nnoremap <buffer> <silent> [] :<C-U>call JumpSectionN('?\n\(\[\)\@=')<Return>
endfunction

function! JumpSectionN(pattern)
  let pattern = strpart(a:pattern, '1')
  if strpart(a:pattern, 0, 1) == '/'
    let flags = 'W'
  else
    let flags = 'Wb'
  endif

  mark '
  let i = 0
  while i < v:count1
    if search(pattern, flags) == 0
      if stridx(flags, 'b') != -1
        normal! gg
      else
        normal! G
      endif
      break
    endif
    let i = i + 1
  endwhile
endfunction

Vim: セクション/関数単位の移動の改善

2007-01-07T03:02:00 / vim / comment

Vimのセクション/関数単位の移動コマンド]]等ですが、ファイルの種類によっては適切なものにmapされています。例えばvim scriptではnoremap <silent><buffer> ]] m':call search('^\s*fu\%[nction]\>', "W")</CR>となっています。

しかし、ほとんどの場合normal modeのmappingしか定義されていないため、visual modeやoperator-pending modeではデフォルトの動作になってしまい、少々不便です。

という訳で汎用的な設定を考えてみました。Visual modeとoperator-pending modeでもnormal modeと同様の]]等が使えます。

vnoremap <silent> ]] :<C-U>call JumpSectionV(']]')<Return>
vnoremap <silent> ][ :<C-U>call JumpSectionV('][')<Return>
vnoremap <silent> [[ :<C-U>call JumpSectionV('[[')<Return>
vnoremap <silent> [] :<C-U>call JumpSectionV('[]')<Return>
onoremap <silent> ]] :<C-U>call JumpSectionO(']]')<Return>
onoremap <silent> ][ :<C-U>call JumpSectionO('][')<Return>
onoremap <silent> [[ :<C-U>call JumpSectionO('[[')<Return>
onoremap <silent> [] :<C-U>call JumpSectionO('[]')<Return>

function! JumpSectionV(motion)
  execute 'normal!' "gv\<Esc>"
  execute 'normal' v:count1 . a:motion
  let line = line('.')
  let col = col('.')

  normal! gv
  call cursor(line, col)
endfunction

function! JumpSectionO(motion)
  execute 'normal' v:count1 . a:motion
endfunction

書いてみたのはいいのですが、Vim同梱のftpluginで]]等を定義しなおしているものの数はそんなにないんですよね (6種類だけ)。しかもやりかたがまちまち。どうにかならないものかな。

Vim: セクション/関数単位の移動の改善 (2) に続く。

Vim: ファイルの種類別の設定

2007-01-05T21:45:00 / vim / comment

Vimでファイルの種類別に設定を行う方法は次の2通り:

.vimrcにautocmd FileType FOO {cmd}を書く。
ちょっとしたこと (例えばsetlocal expandtab softtabstop=2 shitwidth=2) だけならこれで十分。
設定する種類の数が増えるに従って起動時のロード時間が長くなる。
~/.vim/after/ftplugin/FOO.vimに書く。
別のファイルに分けるのが面倒。
~/.vim/ftplugin/FOO.vimに書いてもいいけど、そうするとデフォルトの設定を上書きできない。

Cygwin上のVimでWindowsのクリップボードにアクセスしたい (解決編)

2007-01-04T01:49:00 / vim, prog, cygwin, windows / comment

Cygwin上のVimでレジスタを使ってWindowsのクリップボードにアクセスしたいと思っていたのですが、ちょっと頑張ったらvim scriptのみでできました。基本的にVim6/7のどちらでも動作しますが、"+y'operatorfunc'を使うのでVim7でしか動作しません。

基本的に通常のものと同様に動作しますが、次の欠点があります:

p/Pが常にcharacterwiseになる
Yankした際にlinewise等の情報を付加できないのが原因。一つのVimプロセス内でなら対処できますが、普通のクリップボードの用途はアプリケーション間でのテキストのやりとりなのであまり意味がありません。
アドホックな方法 (yankするテキストにlinewise等の情報を含める) も考えられますが、他のアプリケーションでyankした場合にlinewise等の情報を (普通は) 付加できないので、やはり意味がありません。
p/Pするテキストの最後の行の改行文字が取り除かれる
データの取得は:read !getclipで行っているのですが、最後の行の改行文字がない場合はVimが自動的に付加します。よって改行文字の有無をスクリプト側で判断することができません。
Vimが/dev/clipboardを普通のファイルとして読み込んでくれるなら可能なのですが。

完全を期すならVim本体に手を入れた方がいいのですが、そこまでやる気力はありませんでした。

" Yank/Put with the Windows' clipboard.
" BUGS: Putting is always characterwise.
" BUGS: The last <EOL> in text to be put is always stripped.
if has('win32unix') && !has('clipboard')
  " Key mapping
  nmap "* "+
  vmap "* "+

  nnoremap <silent> "+y :set operatorfunc=<SID>YankToClipboard<Return>g@
  nmap "+yy V"+y
  nmap "+Y "+yy
  vnoremap <silent> "+y :<C-U>call <SID>YankToClipboard(visualmode())<Return>
  vnoremap <silent> "+Y :<C-U>call <SID>YankToClipboard('V')<Return>

  nnoremap <silent> "+p :call <SID>PutFromClipboard('', 'p')<Return>
  nnoremap <silent> "+P :call <SID>PutFromClipboard('', 'P')<Return>
  vnoremap <silent> "+p :<C-U>call <SID>PutFromClipboard(visualmode(), 'p')<Return>
  vnoremap <silent> "+P :<C-U>call <SID>PutFromClipboard(visualmode(), 'P')<Return>


  " Main functions
  function! s:YankToClipboard(motion_type)
    let old_reg = @@
    call s:SelectLastMotion(a:motion_type)
    normal! y
    new
    setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted
    setlocal binary noendofline
    silent normal! P
    silent write! /dev/clipboard
    bwipe
    let @@ = old_reg
  endfunction

  function! s:PutFromClipboard(motion_type, put_type)
    let old_reg = @@
    call s:GetClipboardContent()

    if a:motion_type == ''
      execute 'normal' a:put_type
      let @@ = old_reg
    else
      call s:SelectLastMotion(a:motion_type)
      execute 'normal' a:put_type
    endif
  endfunction


  " Misc. functions
  function! s:SelectLastMotion(motion_type)
    let old_selection = &selection
    let &selection = 'inclusive'

    if a:motion_type == 'char'
      silent normal! `[v`]
    elseif a:motion_type == 'line'
      silent normal! '[V']
    elseif a:motion_type == 'block'
      silent execute "normal! `[\<C-V>`]"
    else  " invoked from visual mode
      silent execute "normal! `<" . a:motion_type . "`>"
    endif

    let &selection = old_selection
  endfunction

  function! s:GetClipboardContent()
    new
    setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted
    read !getclip
    silent normal! ggj0vG$hy
    bwipe
  endfunction
endif

エコーの抑制方法を修正 (:help :map-<silent>)。

あ、良く考えたらcdについての定義が足りない。まああんまり使わないからいいか。

cereja 0.0a2

2007-01-01T23:59:00 / cereja, release / comment

cereja 0.0a2をリリースしました。細かいバグフィックスのみ。

2007年の抱負: Vimを極める

2007-01-01T22:13:00 / vim / comment

現在の.vimrc、ほとんどがオプションの設定だけで凝ったことはしていない。ここ数年ぐらいは全然編集していない気がするし。

でも最近は色々と考え方が変わってきたので、もっと凝ったことをしようと思っている。Normal modeで<Space>は全然使わないので、まずはこれをベースに色々と弄ってみるかな。

という訳で、今年の抱負は「Vimを極める」ことにする。

set nocompatible

set encoding=japan
if has('iconv')
  let s:enc_euc = 'euc-jp'
  let s:enc_jis = 'iso-2022-jp'

  if iconv("\x87\x64\x87\x6a", 'cp932', 'euc-jisx0213') ==# "\xad\xc5\xad\xcb"
    let s:enc_euc = 'euc-jisx0213,euc-jp'
    let s:enc_jis = 'iso-2022-jp-3'
  endif

  let &fileencodings = &fileencodings . ',' . s:enc_jis
  set fileencodings+=utf-8,ucs-2le,ucs-2

  if &encoding =~# '^euc-\%(jp\|jisx0213\)$'
    set fileencodings+=cp932
    let &encoding = s:enc_euc
  else
    let &fileencodings = &fileencodings . ',' . s:enc_euc
  endif

  unlet s:enc_euc
  unlet s:enc_jis
endif


if 1 < &t_Co && has('syntax')
  syntax enable
  colorscheme default
  set background=dark
endif

set autoindent
set backspace=indent,eol,start
set backup
set backupcopy&
set backupdir=.,~/tmp
set directory=.,~/tmp
set noequalalways
set history=100
set hlsearch
set incsearch
set mouse=
set ruler
set showcmd
set showmode
set smartindent
set updatetime=60000
set title
set titlestring=vi:\ %f\ %h%r%m

set viminfo=<50,'10,h,r/a,n~/.viminfo

filetype plugin indent on


function ToggleOption(opt_name)
  execute "if &" . a:opt_name . "\n"
      \ . "  let &" . a:opt_name . " = 0\n"
      \ . "  echo '" . a:opt_name . " off'\n"
      \ . "else\n"
      \ . "  let &" . a:opt_name . " = 1\n"
      \ . "  echo '" . a:opt_name . " on'\n"
      \ . "endif"
endfunction

nnoremap \ :call ToggleOption("wrap")<CR>

nnoremap <C-J> :cn<CR>
nnoremap <C-K> :cN<CR>

nnoremap <F2> :e #<CR>
nnoremap <Esc>2 :e #<CR> 

cnoremap <Esc>h <Left>
cnoremap <Esc>j <Down>
cnoremap <Esc>k <Up>
cnoremap <Esc>l <Right>
cnoremap <Esc>H <Home>
cnoremap <Esc>L <End>
cnoremap <Esc>w <S-Right>
cnoremap <Esc>b <S-Left>
cnoremap <Esc>x <Del>
cnoremap <C-U> <C-E><C-U>

let mapleader=','
inoremap <Leader>df <C-R>=strftime('%Y-%m-%dT%H:%M:%S+09:00')<CR>
inoremap <Leader>dd <C-R>=strftime('%Y-%m-%d')<CR>
inoremap <Leader>dt <C-R>=strftime('%H:%M:%S')<CR>


set secure