header

2013年12月15日日曜日

Emacsのキーバインドをひとつのキーに複数登録する拡張mykie.elの紹介

2014/1/5 blog更新しました
mykie.el version 0.1.1になりました。

  • :err,:C-u&err,:region&errのキーワード指定ができるようになりました。
    flycheck か flymake のエラーがあるときに使えます。
  • どのキーワードを優先するかをキーバインド登録時の順番でかえることができ
    るようになりました。(デフォルトではオフです)
  • 上の変更に伴いキーワード分岐のための条件のデータ構造が変わりました。
    独自に条件を追加している人は注意が必要です。

※過去の更新は下の方に移動しました

この記事は.emacs Advent Calender 15日目の記事です。


mykie.elとは

Emacsはそれ自体が拡張できるのが特徴ですが、拡張をどんどんいれていくと使
えるキーバインドがなくなってしまうのが問題です。
そこで今回の拡張mykie.elの出番です。
この拡張は通常の呼び出しと、リージョン選択時、bol(beginning of line),
eol(end of line), C-u(prefix-argument)を押した時などで、呼び出す関数を
変更できます。
※もともとはmine.elという名前でしたが、改名しました。


インストール

MELPA に登録したのでM-x package-install RET mykieでインストールできる
と思います。もし MELPA をpackage-archivesに登録してなければ以下を
スクラッチバッファなどで評価してから試してください。

(add-to-list 'package-archives
'("melpa" . "http://melpa.milkbox.net/packages/"))
(package-initialize)

el-getをつかっているなら以下のコードを評価して、M-x el-get-install RET
mykie でインストールできると思います。

(push '(:name mykie-el
:type git
:url "https://github.com/yuutayamada/mykie-el.git"
:load-path ("./"))
el-get-sources)

使い方

インストールができたら、init.el などで設定します。
下は簡単な設定例

(require 'mykie) ; <- これはmykie.elを読み込む必須の設定
;; major-modeのキーをglobal-mapのmykieの同じキーで上書きするかどうか
;; の設定。上書きしますが元のメジャーモードキーは:default用の関数に
;; 登録されるのでそのまま使用できます。
;; defaultではnilとなっています。
(setq mykie:use-major-mode-key-override t)
;; 上のメジャーモードの上書き設定の変更や条件の変更をおこなった場合は
;; ↓これを呼び出してください。
(mykie:initialize)
;; mykie:set-keysの第一引数にnilを指定するとグローバルマップに登録され
;; ます。emacs-lisp-mode-mapと指定して特定のメジャーモードを指定することも
;; できます。
(mykie:set-keys nil
"C-a"
:default '(beginning-of-line)
:C-u 'mark-whole-buffer
"C-e"
:default '(end-of-line)
:C-u '(message "Hello")
;; ... You can add more keybinds
)

上の例はC-a, C-eキーにC-uを押した時の設定を追加します。

関数の指定方法についてですが、上の例のようにリスト形式で渡す方法のほかに
'query-replace-regexpのようにシンボルで渡すこともできます。
この場合そのシンボルがインタラクティブだった場合、call-interactively
関数からそのシンボルを呼び出します。(コマンドとして実行する)


指定できるキーワード引数

以下は現在の指定できるキーワード引数です。
最新の情報は GitHubのmykieのページ に書くつもりなので、そのうち情報が古
くなるかもしれません。

KEYWORDDESCRIPTION
:defaultデフォルトで呼ばれる
:C-uC-uをそのキーを押す前に押すと呼ばれる
:C-u*NC-uをN回押したとき呼ばれる
:M-Nメタ(alt)キー + [0-9] の数字を押した時に呼ばれる
:regionリージョン選択中に呼ばれる
:region&C-u:regionと:C-u条件をみたすとよばれる
:repeat同じコマンドを同じポイントで行うと呼ばれる
:bolpbeginning of line で呼ばれる
:eolpend of line で呼ばれる
:bobpbeginning of buffer でよばれる
:eobpend of buffer で呼ばれる
:C-u&bolp:C-uと:bolpの条件をみたすとよばれる
:C-u&eolp:C-uと:eolpの条件をみたすとよばれる
:C-u&bobp:C-uと:bobpの条件をみたすとよばれる
:C-u&eobp:C-uと:eobpの条件をみたすとよばれる
:email現在のポイントが e-mail だと呼ばれる
:C-u&email:C-uと:emailの条件をみたすとよばれる
:url現在のポイントが URL だと呼ばれる
:C-u&url:C-uと:urlの条件をみたすとよばれる
:MAJOR-MODEemacs-lisp-mode などの 現在の major-modeに マッチ
:C-u&MAJOR-MODE:C-uと:MAJOR-MODEの条件をみたすとよばれる
:region&MAJOR-MODE:regionと:MAJOR-MODEの条件をみたすとよばれる
:progプログラミングモードに関連したバッファだと呼ばれる
:C-u&prog:C-uと:progの条件をみたすとよばれる
:region&prog:regionと:progの条件をみたすとよばれる
:errflymakeかflycheckのエラーがあるときよばれる
:C-u&err:C-uと:errの条件をみたすとよばれる
:region&err:regionと:errの条件をみたすとよばれる
:minibuffミニバッファでよばれる
:readonlyread only だとよばれる
:commentコメントか文字列だとよばれる

以下は関数の指定ではなく、違う効果を持ったキーワード引数

KEYWORDvalueDESCRIPTION
 (example)<30>
:cloneKEY as stringClone mykie's functions to other KEY. this function is convenient if you use Emacs either situation terminal and GUI. Because terminal Emacs can't use partial keybind such as C-;, this keyword can clone same functions to another key without :default function. For example: :clone ";" (<- if you want to clone origin key to ";")
 "a" 
:deactivate-regionsymboldeactivate selecting region after mykie executed command. You can specify this t, 'region, 'region&C-u.
 t 
:region-handle-flagsymbolDo copying or killing before command executing. This function is convenience if you want to use kill-ring's variable. But there is mykie:region-str variable that always store region's strings.
 'copy or 'kill 

:cloneはself-insert-commandに:default以外のコマンドを引き継ぐ設定です。
どういう時に便利かというと、ターミナルではC-;は使えないので";"キーで
リージョンに指定した関数を使いたいというときに便利です。
ユーザー側からすると同じキーバインドが使えてると錯覚できます。
(:defaultの設定は使えないですが)

(mykie:set-keys nil
"C-;"
:default 'newline-and-indent
:region 'comment-dwim
:clone ";")

その他の例

mykie.el のページにキーワードを使った例がありますのでそちらを参考にして
ください。


メジャーモードのキーの上書き

最近のmykie.elに実装された機能ですので不具合があるかもしれません。

(setq mykie:use-major-mode-key-override t)
(mykie:initialize)

のようにしないと設定されないので、つかいたくなければ上記の設定をしない
でください。

mykie:use-major-mode-key-overrideには 'both, 'global, 'self or t が設
定できます。'bothはself-insert-commandとglobal-mapのC-jなどのprefix付
きのコマンド両方、'globalは C-j などのprefix付きのglobal-mapのコマンド、
'self と t は self-insert-command(a-z0-9など) を意味します。

目的: major-modeのキーバインドにmykieのglobal-mapのキーを埋め込もうというの
が目的です。

;; You can specify 'both or 'global 'self or t to
;; mykie:use-major-mode-key-override.
;; 'both means use overriding major-mode keys both case.
;; 'global means use overriding major-mode keys by global-map's keys
;; without self-insert-command keys.
;; 'self means use overriding major-mode keys by self-insert-command keys.
;; if you set nil, then don't overriding major-mode key.
;; `mykie:use-major-mode-key-override' is nil by default.
(setq mykie:use-major-mode-key-override 'both)
(mykie:initialize)
(mykie:set-keys nil ; <- nil means registering global-map
"C-w" :default 'tetris :C-u '(message "C-u+C-w"))

;; self-insert-commandはこの方法で登録する
(mykie:set-keys 'with-self-key
"1" :region 'sort-lines
"2" :region 'align
"3" :region 'query-replace
"c" :C-u '(message "C-u+c"))

この機能を使うとき、self-insert-commandとそれ以外を意識する必要があります。
a-zや0-9などがself-insert-commandです。
それ以外というのは、global-mapのC-jやC-wなどprefix付きのコマンドです。
上の例はどちらの場合でも上書きする例です。

-Magitなど一部のパッケージでは、自動で上書きしてくれません。
僕のコードがバグってました。最新のmykie.elではmagitでも上書きしてくれ
ます。ごめんなさい

もしそういう場合どうしても上書きしたい場合、以下のようにしてください。
シンボル名でモード名を指定してください。

個別のモードごとに上書きの設定をしたい場合:

;; specify major-mode name as symbol.
(mykie:attach-mykie-func-to 'emacs-lisp-mode)

逆に MagitのようにC-uを押すと動作を変えるので上書きしてほしくない場合
以下のようにできます。

(setq mykie:major-mode-ignore-list '(magit-status-mode))

特定のキーだけに指定したい場合以下の指定方法もあります。

;; You can use below configuration. This way can specify specific keybind
;; only. you enjoy playing tetris.
(mykie:set-keys nil ; <- nil means registering global-map
"C-t"
:default 'tetris :C-u '(message "C-u+C-t")
:ignore-major-modes '(emacs-lisp-mode)
:ignore-major-modes '(diff-minor-mode))

個別のキーバインドごとにキーワード引数の優先度の設定をする

これはVersion 0.1.1からの機能です。
mykie:use-lazy-order 変数にtを設定することで、キーバインドごとにどの
キーワード引数を優先するか設定できます。

(setq mykie:use-lazy-order t)
(mykie:set-keys nil
\"C-0\"
:default '(message \"hi\")
:C-u*2 '(message \"howdy\")
:C-u '(message \"hello\")
:C-u*3 '(message \"hey\") ; <- you can't see
\"C-1\"
:default '(message \"hi\")
:C-u*3 '(message \"howdy\")
:C-u '(message \"hello\")
:C-u*2 '(message \"hey\")) ; <- you can't see

上の例はC-u*2とC-u*3の順番が入れ変わっているのがわかると思います。
これを実際試してみると、コメントでyou can't seeとかいてある行の
キーワード引数の関数は呼ばれないのがわかると思います。
つまり、C-u*3 or C-u*2 より:C-uを優先しているということです。
(上にある方を優先します。:default以外)
Mykie.el にはいくつか指定できるキーワード引数がありますが、
どれを優先するかはその時々で変わると思いこの機能を実装しました。
たとえば、エラーがでていてコメントのurlを参照しようとするとき
:err と :url をどちらを優先するかとか(ちょっと強引ですかね?)
あとは既存のキーバインドに追加するとき、その部分だけみれば実装の条件を
確認する必要がないというメリットがあります。

注意点としては、条件の評価は、リージョン -> C-u -> それ以外(normal)
という順番で見ていきます。
なので:C-uより下にリージョン系の関数を配置してもリージョンがアクティブであれば
リージョンの条件を先に見に行きます。


条件の変更

今まではmykie.el側で用意した条件の説明でしたが、自分で定義したいときも
あるかもしれません。
Version 0.1.1 から条件データ構造が変わりました。
(個別のキーバインドごとにキーワード引数の優先度の設定をする機能を実装するため)
以前の指定方法の最初のリスト要素に以降の条件が返すキーワード(state)を
入れます。
それとregion系,prefix-arg系に条件を登録するときは、(region-active-p)
やcurrent-prefix-argで確認する必要はなくなりました。

(setq mykie:before-user-normal-conditions
'((:skk-active :skk-on)
;; ↓は :skk-active か :skk-on を返す関数
(mykie:get-skk-state)
;; もっと条件を追加できます
;; (when t :something)
;; この場合 (:skk-active :skk-on) は
;; (:skk-active :skk-on :something)
;; になります。
))
(mykie:initialize)

他にもmykie:before-user-XXX-conditionsまたは
mykie:after-user-XXX-conditionsがあります。XXXがnormal, region,
prefix-argにかわります。

注意: mykie:use-lazy-orderがnon-nilだった場合はこのbeforeとafterに
意味はなくなりキーバインドを登録する時の順番が優先されます。


おすすめ関数とちょっと便利な C-j キーの例

標準の関数で便利な関数です。参考程度に

  • 非リージョン系
    delete-trailing-whitespace
    delete-blank-lines
    just-one-space
    ispell-word
  • リージョン系
    align
    sort-lines
    fill-region

下はちょっと便利にしたC-jの例です。

(global-set-key (kbd "C-j")
'(lambda ()
(interactive)
(mykie
:default '(progn
;; 無駄なスペースを削除
(delete-trailing-whitespace)
(case major-mode
(org-mode (org-return-indent))
(t (newline-and-indent))))
;; 行末で C-u+C-j で fill-region を実行する
:C-u&eolp '(fill-region (point-at-bol) (point-at-eol))
:region 'query-replace-regexp)))

おわり

region系の関数を開いてるキーにいれるだけでもまぁまぁ便利なのでよかった
らつかってください。以上 mykie.el の紹介でした。
明日は r_takaishi さんです。

更新履歴
2013/12/27ブログ&mykie.el(v0.1.0)更新しました

  • major-modeキーバインドのmykieの関数での上書きができるようになりました。
  • mykie:set-keys関数でまとめてキーバインドを登録できるようになりました。
  • 指定できるキーワードがいっぱい増えました。

2013/12/19ブログ&mykie.el(v0.0.6)更新しました

  • mykieのキーワード引数に:M-N(NがM-[0-9]の押した数字にかわります。)が
    指定できるようになりました。
    ShingoFukuyama さんpull-requestありがとうございます。
  • Version 0.0.6からmykie:get-C-u-keywordが:M-Nも返すようになったので
    mykie:get-prefix-arg-stateという名前になりました。
    自分でmykie:conditions変数を変更している場合注意が必要です。
  • last-commandが正常に保存されず winner-(undo|redo)不具合がでる件
    @rubikitch から pull-request いただきました。いつもありがとうございます。
    ↓これは勘違いしました。すいません↓
    mykie:loop中ではlast-commandが正常に保存されないバグが直りました。

2013/12/18ブログ&mykie.el(v0.0.5)更新しました

  • mykieのキーワード引数に:C-u*N(NはC-uを押した数が入ります)が指定でき
    るようになりました。
    これに伴い記事も若干修正

2013/12/17ブログ&mykie.el(v0.0.4)更新しました

  • mykie:condition変数で条件指定の順番や内容を変更できるようになりました。
    詳細は優先度の変更や条件のカスタマイズの項をご覧ください。
  • 一部のキーワードの引数の名前がみじかくなりました。
    (:default&bolp -> :bolpなど)
    詳細は優先度の変更や条件のカスタマイズの項をご覧ください。
  • @rubikitch さんからリージョン指定を解除する pull-request いただきました。
    ありがとうございます!(それとリファクタリングも)
    詳細はリージョンのマークを解除するをご覧ください。

2013/12/27 blog更新
変更が結構あるので最新のmykie.elの情報にあわせるようにしました。
以前設定したものが使えなくなるような変更は入っていません(たぶん)。
以前より簡単に設定できる(defunとかinteractiveいらない)ようになったので
ぜひ試してみてください!


Popular Posts

Blogger templates

Blogger news