Help us understand the problem. What is going on with this article?

selected.el で「選択して右クリック」的な概念を

はじめに

この記事は,Emacs 使いに「右クリックしてメニューから選択」的な概念をもたらす selected.elhelm-selected.el/counsel-selected.el の紹介です.Macユーザを前提としていますが,他のプラットフォームでも通用する話です.

簡単な(?)設定をするだけで,作業効率が劇的に向上します.

Screen Shot 2017-12-11 at 1.18.11 PM.png

Note - ガチンコの右クリック実装には@tad3氏の「right-click-context」があります!オススメ!

選択して,実行

マウス操作の「右クリック」はとても便利で,メニューから選択領域に限定したアクションを選択するだけで,所定の処理を簡単かつ高速に行えます.Emacsにおいても,選択領域を引数とするコマンドを容易に発行できますが,各コマンドが独立していてグループ化されていません.「ユーザが領域選択した時だけ発行できるコマンド群」をグループ化し,かつ,簡単な操作でそれらを選ぶことができれば,選択領域に対する追加処理を最小の操作で実行できます.

わかりやすい例では「Emacsバッファ内の言葉をブラウザでググりたい」があります.通常のシーケンスですと,

  1. 領域指定: C-<space> + C-M-<right> or C-<space> + <right>連打 or C-M-<space>
  2. 領域複製: M-w
  3. ブラウザを開く(ランチャーから選ぶ,/Applications フォルダから選ぶ,M-<tab>でアクティブ化,等)
  4. フォームに単語・文章をペースト: M-v
  5. 検索実行: <ENT>

と5ステップです.こんな複雑な処理を日々,何度も繰り返すのは嫌ですね.

一方,selected.el(とhelm-selected.el)を使えば,もっと楽です.

  1. 領域指定: C-<space> + C-M-<right> or C-<space> + <right>|C-f連打 or C-M-<space>
  2. 検索実行: g(設定済みのシングルキー)

わずか2ステップです!

前出の処理の2-4が所定のコマンドで自動化されているので,ちょうど「右クリックして実行」の感覚です.「この英単語を辞書で調べたい!」というような,選択領域に対する同様の処理事例がたくさんあるはずです.

selected.el (とhelm, ivy/counsel拡張)の導入

インストール

selected.el は,MELPAからインストールできます.
Githubから取り寄せる場合は,https://github.com/Kungsgeten/selected.el から.

次に,helm-selected.elです.これは selected.el で設定したコマンド群を helm インターフェイスで絞り込む拡張で, Githubで公開しています(拙作).
https://github.com/takaxp/helm-selected

MELPA登録は申請中で,しばらく先になりそうです.また,記事に合わせて急いで作成したので,まだバグが残っているかもしれません.

(Updated: 2017-12-23) マージされました. Many thanks to purcell!!

(Updated: 2019-05-31) counsel-selected.el を公開しました.

設定

selected.el

まずselected.elの設定です.以下は一例で,選択領域の処理に紐付けたいコマンドをselected-keymapに追加していくだけです.また,特定のメジャーモードに限定したコマンドの設定も可能です.

(when (require 'selected nil t)

    ;; コメントアウト・アンコメントアウト
    (define-key selected-keymap (kbd ";") #'comment-dwim)

    ;; 選択領域の単語数をカウント,ミニバッファに表示   
    (define-key selected-keymap (kbd "=") #'count-words-region)

    ;; 選択した関数のヘルプを表示
    (define-key selected-keymap (kbd "f") #'describe-function)

    ;; 選択した変数のヘルプを表示
    (define-key selected-keymap (kbd "v") #'describe-variable)

    ;; 選択した単語・文をググる
    (define-key selected-keymap (kbd "g") #'my:google-this)

    ;; 選択した単語をOSに発声させる
    ;; 要osx-lib.el (https://github.com/raghavgautam/osx-lib/blob/master/osx-lib.el)
    (define-key selected-keymap (kbd "s") #'osx-lib-say-region)

    ;; 選択領域を評価して結果をミニバッファに表示(結構危険かも...)
    (define-key selected-keymap (kbd "e") #'my:eval-region)

    ;; 英単語を調べて結果を表示
    ;; 要osx-dictionary.el (https://github.com/xuchunyang/osx-dictionary.el)
    (define-key selected-keymap (kbd "w") #'osx-dictionary-search-pointer)

    ;; 選択した単語を一括変換する
    ;; 要replace-from-region.el (replace+.elでも良いらしい)
    (define-key selected-keymap (kbd "5") #'query-replace-from-region)

    ;; 実行中止(ただし,selecte.elでは selected-offの紐付けが推奨されている)
    (define-key selected-keymap (kbd "q") #'keyboard-quit)

    ;; メジャーモードがOrg Modeの時,選択領域をテーブルに変換する
    (setq selected-org-mode-map (make-sparse-keymap))
    (define-key selected-org-mode-map (kbd "t") #'org-table-convert-region)

    (selected-global-mode 1))

上記設定に出てくるプライベート関数は次のようなものです.

(defun my:eval-region ()
  (interactive)
  (when mark-active
    (eval-region (region-beginning) (region-end) t)))

;; 要google-this.el (https://github.com/Malabarba/emacs-google-this)
(with-eval-after-load "google-this"
    (defun my:google-this ()
      "検索確認をスキップして直接検索実行"
      (interactive)
      (google-this (current-word) t)))

helm-selected.el

ほぼ設定不要で,helm-selectedの発動コマンドを設定するだけです.ただし,次の章で説明しますが,IMEの切り替えをコマンドでできない環境では,ASCIIのシングルキーがIMEに取られてしまうので,その場合は <f5>S-<f5>などを指定しておくべきです.

(with-eval-after-load "selected"
  (when (require 'helm-selected nil t)
    (define-key selected-keymap (kbd "h") 'helm-selected)))

領域選択後にh押下すると,helmインターフェイスが出てきますので,希望のコマンドを選んで<ENT>すればOKです.

selected.elにたくさんのコマンドを紐付けると,どのキーに何を割り振ったのか忘れてしまいがちです.そんな時にhelm-selectedが役に立ちます.

Screen Shot 2017-12-11 at 3.47.56 PM.png

counsel-selected.el

Ivy/counsel用のインターフェイスを準備しました.helm-selected.el と同じように使えます.

Screen Shot 2019-05-31 at 16.08.06.png

IMEユーザの一手間

selected.el の最大の欠点は,IMEとの相性が悪いことです.つまり,IMEがオンの時,選択領域に対するコマンドを選択すると,押下キーがバッファにそのまま入力されてしまいます.

これを避ける方法は二つあります(あるいは,毎回IMEを手動で切り替えるか...Orz).

一つは,helm-selectedの発動をASCII以外のキー(S-<f5>など)に割り当てて,各コマンドはhelmインターフェイスから選択することです.コマンド実行までのステップが一つ増えますが,右クリック相当の処理1回分と考えれば許容範囲です.

もう一つの方法は,IMEパッチを適用して IMEのオン・オフを制御可能にする方法です.そうすることで,領域を選択し始める時にIMEをオフにして,コマンド発行後にIMEを元に戻すことができます.同制御は,マークのhookを使って自動化できます.正しく動作すれば,任意のコマンドにシングルキーを割り当てることができ,IMEユーザも selected.elの本来の性能を引き出せます.

(when (and (fboundp 'mac-get-current-input-source)
           (fboundp 'mac-toggle-input-method))

  ;; IME ON/OFF ステータスフラグ
  (defvar my:ime-flag nil)
  ;; 判定
  (defun my:ime-active-p ()
    (not (string-match "\\.Roman$" (mac-get-current-input-source))))
  ;; IME ON
  (defun my:ime-on ()
    (interactive)
    (mac-toggle-input-method t))
  ;; IME OFF
  (defun my:ime-off ()
    (interactive)
    (mac-toggle-input-method nil))

  ;; 領域選択開始に合わせて IMEを OFF
  (add-hook 'activate-mark-hook
            #'(lambda ()
                (when (setq my:ime-flag (my:ime-active-p))
                  (my:ime-off))))
  ;; 選択解除で IME ONを復帰
  (add-hook 'deactivate-mark-hook
            #'(lambda ()
                (when my:ime-flag
                  (my:ime-on)))))

IMEパッチの適用については,emacs-25.3 をインラインパッチをあてて使う(OSX)をご参照ください.

おわりに

本記事では,selected.elhelm-selected.elを紹介しました.選択した領域に対する処理は,今回紹介した事例以外にもたくさん存在すると思います.「右クリックして実行」に相当する任意の関数を好みに合わせて設定してみましょう.作業効率が向上すること間違い無しです.

紐付けるべきオススメのコマンドがありましたら,コメント欄へお願いします m(_''_)m

また,hydra使いさんからのツッコミもお待ちしております.


<< 10日目Emacs Advent Calendar 201711日目 >>

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away