深酒とお昼寝で忘れる

深酒とお昼寝で忘れる

素面でも意図したことを忘れがちなしらふいとさんは、忘れる前に何かしら書き残せたらとても満足のようです

(Neo)vim で同じ列内のウィンドウのみ高さを等しくする

Vim のウィンドウを縦に分割し、さらにそれぞれの列を横に分割します。それぞれの列内のウィンドウは高さが等しいとは限らず、最大化されているウィンドウがあったりします。 f:id:someneat:20170816033006p:plain

沢山ファイルを開いて作業をしていると、こんな風にウィンドウの配置が最適化されていくことがあります。さて、そんなときに一つの列内のウィンドウ「のみ」高さをそろえたくなったときには、どうすれば良いのでしょうか。

CTRL-W = とすると、他の列のウィンドウも含む「全ての」ウィンドウの高さ(と幅)がそろってしまいます。 f:id:someneat:20170816033027p:plain

気になったので 聞いてみたところ、速攻で解決しました。:new | q としましょう(:new の代わりに :split でも可)。

マニュアルによると、Vimequalalways というオプションが有効の場合(デフォルトで有効です)、ウィンドウを分割したり(:new)、閉じたり(:q)する際に全てのウィンドウの大きさをそろえようとします。と書いてあるのですが、その挙動はもう少し複雑で全てのウィンドウではなく動作に関連する特定のウィンドウ(?)の大きさがそろうようです。:new するとウィンドウは横に分割され、その列内のウィンドウのみ、高さがそろいます。その後続いて :q すると新しく開いたウィンドウは閉じられ、その列内のウィンドウの高さがそろいます。このようにして所望の動作になるわけです。 f:id:someneat:20170816033046p:plain

既存のウィンドウ操作のショートカットに似たマッピングにしてみます。

nnoremap <C-w>e :new \| q<CR>
nnoremap <C-w><C-e> :new \| q<CR>

地味に便利。

Zsh のカスタマイズは日進月歩 − 失敗したコマンドを履歴に残さない

日々、かなりの頻度でシェルのコマンド履歴を検索します(よね?)。長かったりよく覚えていなかったりするコマンド(複数のコマンドをパイプでつないだり、コマンドに様々なオプションや引数を渡したり…)を、履歴の検索なしに再度実行するのはとてもつらいです。

ということでそんな便利なコマンド履歴の検索ですが、気になることもあるにはあります。その一つが、タイプミスをしたりオプションを間違えたりして失敗したコマンドを、うっかりまた履歴から検索して実行してしまうことです。これは失敗したコマンドを履歴から消去しない限り起こり得る問題なので、初めから失敗したコマンドは履歴に残さないように設定してみました。なお、タイトルにあるとおり対象のシェルは zsh になります。

こちら を参考にしました。zshフック関数(9.3.1 Hook Functions) という仕組みを使います。下記のような設定を .zshrc などに記入すれば良いはずです。

__record_command() {
  typeset -g _LASTCMD=${1%%$'\n'}
  return 1
}
zshaddhistory_functions+=(__record_command)

__update_history() {
  local last_status="$?"

  # hist_ignore_space
  if [[ ! -n ${_LASTCMD%% *} ]]; then
    return
  fi

  # hist_reduce_blanks
  local cmd_reduce_blanks=$(echo ${_LASTCMD} | tr -s ' ')

  # Record the commands that have succeeded
  if [[ ${last_status} == 0 ]]; then
    print -sr -- "${cmd_reduce_blanks}"
  fi
}
precmd_functions+=(__update_history)

コマンド履歴の保存に関するフック関数 zshaddhistory は、ドキュメントによるとコマンドの実行直前に呼ばれるようです。通常はこのタイミングで保存されるのですが、今回は実行結果の成否を見てから保存するかを決めたいのでここでは保存しません。そこで __record_command() という関数内でコマンドをグローバルな変数 _LASTCMD に保存しておき 1 を返します(0 を返せば通常どおり HISTFILE に保存されます。2 を返すと履歴ファイルには保存されませんが、Ctrl-P/N などでさかのぼれる内部ヒストリには保存されます)。この関数を zshaddhistory_functions に追加します。

続いて実際に履歴を保存する関数が __update_history になります。postcmd というフック関数があるのかと期待したところ、ないのですが、どうやら precmd 関数がコマンドの実行直後に呼ばれるようなので(呼ばれるタイミングについては この記事 が詳しいです)、こちらを使います。まずはじめに、実行したコマンドの終了ステータスを last_status 変数に保存します。なお、自前でヒストリファイルを更新するため zsh の履歴保存に関するオプション相当の機能はここで実装する必要がある気がします。ということで、スペースで始まる行(やスペースだけの行)は保存しないようにチェックを行ない(hist_ignore_space 相当)、複数のスペースは tr で一つにまとめます(hist_reduce_blanks 相当)。最後に、終了ステータスが 0 の場合は履歴に print コマンドで保存します(参考:こちら)。この関数を precmd_functions に追加します。

これでおおよそ所望の動作にはなったはずです。*1 ストレスが減って良いですね!

*1:直前の終了ステータスを見ているため失敗するコマンドと成功するコマンドを ; でつなげた場合などには記録されてしまいます。コマンドをつなげる場合には && を使うなどしましょう。

必要なときにはいつも忘れてしまっている (Neo)vim のコマンドたち(その1)

diffoff

差分モードを終了する。例えば :diffsplit などして差分を見つつ作業をし、用が済んだ後に一方のファイルを閉じる。ところが sign(特定の行を強調するために、例えば +-> などの印を表示する、左端に表示される一列)が残ってしまい、はてどうやって元に戻すんだっけかな?というときに :diffoff する。

windo

あとに続くコマンドを(現タブ内の)全てのウィンドウに対して実行する。例えばスペースをタブに置換する場合は :windo %s/ /\t/ge とする(最後の e はパターンが見つからない場合にエラーの発生を抑制するオプション)。

g/pattern/d

ファイル内で pattern を含ファイル内で pattern を含む行を削除する。上記 windo に書いたような置換のコマンドは忘れないのだけれど、この行の削除についてはどうも忘れてしまう。ちなみにこの g コマンドは ここ にあるように色々と強力らしい。