Vim で Esc を置き換えたキーマッピングと本来の Esc の挙動が違うことがある?

まだ根本解決できてないけどメモ。

現象

こんな設定をしてみたのだけど、 をしてもハイライトが消えない。

"ノーマルモード時 <Esc> を <C-j> にマッピング
nnoremap <C-j> <Esc>

"Escの2回押しでハイライト消去
nnoremap <Esc><Esc> :<C-u>nohlsearch<CR><Esc>

試したこと

何人かの方から noremap だからじゃない?と教えてもらったのでこんな風にした。

"ノーマルモード時 <Esc> を <C-j> にマッピング 
nmap <C-j> <Esc>

やっぱりできない。
Key mapping についての理解が足りないのを痛感したので、この辺読んで勉強する。
Vim: Key mappingを極める - while (“im automaton”);

以下引用。

:map等のコマンドに対して:noremapというコマンドが存在します。両者の違いは、{rhs}に他のkey mappingsの{lhs}が含まれていた場合、それが再帰的に展開されるかどうかです(この再展開のことをremapと呼びます)。:noremap系のコマンドではremapが行われず、:map系のコマンドではremapが行われます。

Vim: Key mappingを極める - while (“im automaton”);

nnoremap では再帰的に展開されなくてだめなのは分かったけど、今回のケースだと {rhs} は で、 単独で {lhs} になっているマッピングはないので、これが原因じゃない気がする。
根本的に理解が間違ってるとかあったら指摘をしてもらえるとうれしいです。

試行錯誤の中で だとタイムアウトが一回だけど、 だとタイムアウト 2 回ということに気づいた。
色々ググって、この辺が参考になりそうだったので熟読する。
VimでESCの反応を素早くする,再び ~timeoutlenとttimeoutlen~ | PCと遊ぶ日々の記録
Vim documentation: options

他に と組み合わせたマッピングはないので、キーコード待ちでタイムアウトになっているらしい。
は、キーコード待ち -> のキーコードと認識されるが、 は、キーコード待ち -> キーコード待ちになってるみたい。
結局、原因はよくわかっていない。

暫定対策

"ノーマルモード時 <Esc> を <C-j> にマッピング 
nmap <C-j> <Esc>

"Escでハイライト消去
nnoremap <Esc> :<C-u>nohlsearch<CR><Esc>

他に で始まるキーマップがなければ、即ハイライトが消える。
ある場合はマッピング待ちが発生するので、timeoutlen だけ待つ or 2 回押しでハイライトが消える。

またはこっちでもいいかも。

"<C-j>2回でハイライト消去
nnoremap <C-j><C-j> :<C-u>nohlsearch<CR><Esc>

とりあえずこれで良しとする。

TDD ミートアップに参加しました

TDDミートアップ - connpass
TDDミートアップ #TDDMeetUp - Togetterまとめ

TDD 実践してないけど面白そうなので行ってきました!
いろんなトピックがあったなかで自分が提案したトピックが取り上げられてよかったです。
ディスカッションした感想というか考えたことを書きました。

TDD とプログラミングパラダイム

個人的に TDD はオブジェクト指向プログラミングと一緒に語られることが多いと感じています。
テスト駆動開発入門』や『実践テスト駆動開発』では、サンプルコードが Java なので当たり前っぽいですが、『テスト駆動開発による組み込みプログラミング』などは、サブタイトルが "C 言語とオブジェクト指向で学ぶアジャイルな設計" です。

疑問としては手続き型言語で TDD をする場合でもオブジェクト指向な設計に洗練して行くべきなのか?ということでした。*1
一応断っておきますが、別に手続き型万歳!オブジェクト指向なんて嫌い!とか思っていません。
むしろ OOP 好きですし、『テスト駆動開発による組み込みプログラミング』はとても良い本です。
ただ、現実には C のレガシーコードと戦っているので何かヒントを得たいと思った次第です。

ディスカッションでは TDD のために言語が前提としているパラダイムを変えることに意義は少ないということに落ち着きましたが、ちょっと自分のミスリードもあったかもしれません。
帰りの電車の中で自分なりにつらつら考えてみました。

  • 手続き型言語で TDD のサイクルを行うには、少なくとも小さな機能単位での関数に分割する必要がある
    • だめなコードにありがちな、1 つの関数にダラダラと手続きが書かれているとTDD のサイクルに乗せるには大きすぎる
    • 上記のようなコードを作りにくいのは TDD のメリット
    • 特にオブジェクト指向は関係ない
  • レガシーコード改善ガイド』によれば、手続き型言語のテストのしにくさは "接合部" が少なく、依存関係が複雑になりがち
    • 要はモックが使いにくいということだと理解
    • C での接合部としては、リンカ、プリプロセッサ、関数ポインタ
    • 設計で接合部は増えない
    • やっぱりオブジェクト指向は関係ない
  • 関数を分割する指針として SOLID原則のようなオブジェクト指向プログラミングの考え方を取り入れるのは有効

当たり障りのない結論になっちゃいますが、手続き型言語で無理矢理クラスっぽいものを作ったりするのはあまり意味がないけど、テストしやすさのために SOLID 原則とかを意識した設計を行うのは意味があるのかなあと思います。
テストしやすい = 良い設計とは限らないけど目安にはなるはず。*3

他にもいろいろとディスカッションのネタはありましたが、他の人がまとめてくれるのを期待して割愛。
TDD 実践してないけどみんなでディスカッションするのはとても楽しかったです。

主催の @kyon_mm さん、会場提供頂いた株式会社インターファクトリーさん、 中の人の @susumuis さん、参加者のみなさん、ありがとうございました!

*1:ディスカッション中に疑問がまとまりました

*2:テスト駆動開発による組み込みプログラミング』での LSP の説明はちょっと苦しいかなあと思いますが…

*3:全部 static メソッドでも、グローバル変数ばかりでもテストしやすくできますよね

プラグイン常習者が素の Vim しかない状況になったときに便利だったコマンド

普段は vimfiler や unite を常用していますが、最近、素の Vim を使う機会が多いです。
とは言っても、Linux サーバ上でテスト用の設定ファイルをちょっと編集したり、コードの確認をしたりといった簡単なものですが。

PC にダウンロードしてきて秀丸で編集という方法もあるのですが*1vimmer の端くれとしてはそれもどうかと思うのとダウンロード/アップロードがめんどくさいというのもあり、復習がてらよく使うコマンドをまとめてみました。
カーソル移動系や各種編集系など、プラグイン有無に関係なくよく使う基本機能は使える前提です。

さすがは Vimです。いくつかコマンドを覚えただけで、前述の簡単な内容であればほとんどストレスなく使えるようになりました。

プラグインや .vimrc で自分好みにカスタマイズできるのは Vim の魅力ですが、素のままでも使いこなせば充分パワフルなのも Vim の魅力ですね!

バッファ

普段は unite でバッファ一覧を開いて操作してます。

:ls バッファ一覧を表示
:bn 次のバッファに移動
:bp 前のバッファに移動
:b バッファ名*2 指定したバッファを開く
:ene 無名バッファを開く

一時的なメモ取ったりするのに無名バッファが地味に便利。

補完

普段は neocomplcache で自動補完。

or インサートモードでの補完

Vim の補完系は他にも色々ありますが、とりあえずこれで最低限は問題なし。

検索

これはいつも使ってるかな。

* カーソル下の word を検索
:cope grep 結果の quickfix を開く
:ccl quickfix を閉じる
:cn quickfix で次の該当箇所へジャンプ
:cp quickfix で前の該当箇所 へジャンプ

 

ファイル操作

普段は vimfiler にお任せ。

:e ディレクトリパス ファイルリストを開く
gf カーソル下の文字列をファイル名として開く

 

シェル

普段は vimfiler 経由で vimshell か bash を使ってます。

:suspend or Vimサスペンドする
fg Vim をフォアグラウンドに戻す

*1:自分の PC ではないので Vim は入ってない

*2:ls の表示結果

複数 UI のバージョンを管理するベストプラクティスがわからない

これだ!っていう管理方法を思いつきませんでした。
こうすると良いよ!こうしてるよ!っていうのがあれば是非教えてください。

概要

開発用ツールとして UI 及び使用可能な機能に差を持たせたデスクトップアプリを作っています。
仕様はホワイトボードの落書きレベルで、使ってもらってフィードバックと改善を繰り返すので、UI も機能も更新頻度はそこそこあります。

実際とは違いますが、例えばこんな感じ。

  • 開発チーム用
    • 全機能使用可能
    • 画面から各種パラメータを細かく設定可能
  • 評価チーム用
    • 特定機能のみ使用可能
      • 非表示にしているだけ
    • パラメータはデフォルト値を使用
      • 画面上にもパラメータは表示しない
      • 評価チームはパラメータの詳細を知らない

いわゆる MVC なプログラムで UI の違いを管理するような場合、どのようにするのがベストプラクティスなんですかね。

現状

試行錯誤しつつ、現在はこのようにしています。

  • UI ごとにブランチを作成
  • 機能の更新がある程度区切りが付いたら、各ブランチにマージして反映

課題というか不満

  • ブランチ毎にマージするのがめんどくさい
    • コミットフックとか使えばいいのかな…

また何か思いついたりしたら書くかも。

複数ファイルを横断的に操作する

毎度忘れてググってるのでメモ。

やりたいこと

  • 複数ファイルを横断的に操作したい
    • 代表的なのは置換とか

vim でも当然できます。

方法

args に対象ファイルを設定する。

:args *.groovy
:args **/*.groovy <-サブディレクトリも対象にする

argdo でコマンドを実行

:argdo %s/old/new/g
:argdo %s/old/new/g | update <-update は変更があった場合に保存まで実行

これでOK。
例によって :help に全部書いてありますね。

Yokohama.groovy #14 に参加しました

Yokohama.groovy #14 #yokohamagroovy - connpass

いつの間にやら 14 回目の Yokohama.groovy に参加してきました。
今回は mattari.grails と合同での開催となりました。

ここしばらくいなかった初参加の方もいましたよ!

やったこと

Griffon で brainfuck インタプリタを作ってました。
コードを入力して実行すると、バッファの動きと出力結果がわかるようになっています。
UI が適当だったり、バッファサイズが固定だったり、"," が未実装だったりしますが、とりあえず動きます。

Griffon でのテストやSwingbuilder の使い方など、まだまだ勉強しないとなあ。

スクリーンショット

お約束の Hello World を表示するサンプルコード実行中。

その他

grails 組はお題に沿って Web アプリを作成していたようです。
残念ながらあまり絡めなかったので、次回こそ合同っぽく交流できればいいなあと思いました。

初参加の方とは色々お話しできました。
普段 groovy をどう使ってるかとか、スライドをテキストベースで作るのは sphinx や blockdiagなどがよさげですよと紹介したり、雑談も含めて楽しい時間が過ごせました。

参加された皆さん、ありがとうございました!

Git 天空闘技場に参加しました

Git天空闘技場 - connpass

普段は SVNMercurial を使っているのですが、Git 力を上げつつ、違いを知ることで Mercurial の理解も深まればいいと思って参加しました。

感想

オブジェクトの内容を直接確認したり、コマンドを使わずにブランチを作ったり、通常の使い方ではやらないようなことを体験できて、とても楽しかったです!

Git は難しいというイメージでしたが、内部構造はとてもシンプルで合理的な印象を受けました。
また、元々 Linux の開発のために作られただけあって、説明を聞きながら Linux っぽいなあとか思ってました。*1
内部構造や思想を知ることが理解を助けるというのは本当ですね。

ヒソカは言い過ぎですが、ズシくらいにはレベルアップしたのではないでしょうか。

主催の @skowata さん、講師の@sinsoku_listy さん、参加者の皆さん、ありがとうございました!

メモ

  • GIt のオブジェクト ※@sinsoku_listy さんの資料から抜粋
    • blob
      • ファイルの中身を表すオブジェクト
    • tree
      • ディレクトリの中身と各blobとの対応を表すオブジェクト
    • commit
  • 各オブジェクトはハッシュ値で識別
    • commit -> tree -> blob と参照している
    • 1 byte でも差があれば、blob オブジェクトが作られる
      • バイナリの管理にはやや不向き
    • 同一内容の場合は、同一ハッシュになるので blob オブジェクトは1つ

やったこと

*1:treeオブジェクトとかコマンドとかetc