メジャーモードバインディングをオーバーライドする方法


38

時々、私のグローバルキーバインドはメジャーモードによって上書きされます。簡単な例は、私のinitファイルの次の設定です

(global-set-key (kbd "C-j") 'newline-and-indent)

しかし、面倒なことに、このキーバインディングは、スクラッチバッファのデフォルトモードである「Lisp Interaction」メジャーモードによって隠されています。

メジャーモード(またはマイナーモード)がグローバルキーバインドを隠している状況にいるとき、どのように戻すことができますか?

注:私の質問ではありません「私はバインドすることができますどのようC-jnewline-and-indentLispの対話で『』モード?」 クラッシュするキーマップや、メジャー/マイナーモードによって非表示になるユーザーキーバインドを処理する方法に関する、より一般的な回答に興味があります。


回答:


39

独自のマイナーモードを定義したくない場合は、同じソリューションに対して「ショートカット」アプローチもあります(最初の回答で説明します)。

あなたはインストールできuse-packageMelpaから利用可能なパッケージとのメーク使用bind-key*またはbind-keys*の一部だマクロbind-keyその船を持つパッケージをuse-package

のドキュメントからbind-key.el

;; If you want the keybinding to override all minor modes that may also bind
;; the same key, use the `bind-key*' form:
;;
;;   (bind-key* "<C-return>" 'other-window)

;; To bind multiple keys in a `bind-key*' way (to be sure that your bindings
;; will not be overridden by other modes), you may use `bind-keys*' macro:
;;
;;    (bind-keys*
;;     ("C-o" . other-window)
;;     ("C-M-n" . forward-page)
;;     ("C-M-p" . backward-page))

誰もが好奇心が強い場合、これは舞台裏でマイナーモードを使用するだけであることに注意してください。emulation-mode-map-alists優先順位を強制するために使用することにより、他のマイナーモードとの競合に対して異なるアプローチを取ります)。
フィル14年

私はこれが簡単であるため、これを答えとしてマークしました。基本的にはこの回答と同じことをしていますが、ほとんどの作業をバックグラウンドで便利に行っています。
nispio 14年

@nispioそうですね。私の経験からの唯一の違いは、マイナーモードバインディングが他のモードをグローバルにオーバーライドするために使用される方法です。しかし、(独自のマイナーモードを持つ)他のアプローチの利点は、必要に応じて一時的にオフにして元のemacsバインディングを試すことができることです(これを数回行う必要がありました)。
カウシャルモディ14年

1
(bind-key* "C-M-&" 'override-global-mode)initにを追加すれば、通常、必要に応じてバインディングをすばやく解除できます。以来override-global-mode「グローバル」マイナーモードではありません、あなたはまだバッファ毎に、それを無効にする必要があります。そのため、グローバルオーバーライドキーを頻繁に無効にする場合は、このソリューションは便利ではありません。
nispio 14年

25

独自のマイナーモードとそのキーマップを定義し、他のすべてのモード(マイナー+メジャー)をオーバーライドすることができます。それがまさに私が自分のマイナーモードを書くことを選んだ理由です。

キーバインディングを使用してすべてのバインディングをオーバーライドする手順:

  • 以下に示すように、独自のマイナーモードとキーマップを定義します。
  • マイナーモードをグローバルにアクティブ化する
  • (define-key my-mode-map (kbd "C-j") #'newline-and-indent)

同様に、マイナーモードで設定された他のキーバインディングは、他のモードのキーバインディングをオーバーライドします。

クリストファー・ウェロンズによるマイナーモードの書き方に関するブログ投稿を読むことを強くお勧めします。このブログに加えてnil、複数のメジャーモードとマイナーモードで複数のキーバインディングを設定する必要があるという煩わしさから、自分でマイナーモードを作成することになりました。

このアプローチを使用する最良の部分は、emacsのデフォルト構成でキーバインディングが何を行うかを確認する場合、マイナーモードを単にオフにすることです。その後、再び有効にすると、カスタムキーバインディングが返されます。

;; Main use is to have my key bindings have the highest priority
;; https://github.com/kaushalmodi/.emacs.d/blob/master/elisp/modi-mode.el

(defvar my-mode-map (make-sparse-keymap)
  "Keymap for `my-mode'.")

;;;###autoload
(define-minor-mode my-mode
  "A minor mode so that my key settings override annoying major modes."
  ;; If init-value is not set to t, this mode does not get enabled in
  ;; `fundamental-mode' buffers even after doing \"(global-my-mode 1)\".
  ;; More info: http://emacs.stackexchange.com/q/16693/115
  :init-value t
  :lighter " my-mode"
  :keymap my-mode-map)

;;;###autoload
(define-globalized-minor-mode global-my-mode my-mode my-mode)

;; https://github.com/jwiegley/use-package/blob/master/bind-key.el
;; The keymaps in `emulation-mode-map-alists' take precedence over
;; `minor-mode-map-alist'
(add-to-list 'emulation-mode-map-alists `((my-mode . ,my-mode-map)))

;; Turn off the minor mode in the minibuffer
(defun turn-off-my-mode ()
  "Turn off my-mode."
  (my-mode -1))
(add-hook 'minibuffer-setup-hook #'turn-off-my-mode)

(provide 'my-mode)

;; Minor mode tutorial: http://nullprogram.com/blog/2013/02/06/

5

グローバルバインディングでメジャーモードバインディングをオーバーライドするには、バインディングをnilメジャーモードに設定するだけです。

(define-key my-major-mode-map (kbd "C-j") nil)

グローバルバインディングを一般的なすべてのモードよりも優先させることはできません(そうでない場合はメジャーモードを使用しても意味がありません)が、最も重要なバインディングを使用して独自のマイナーモードを作成することでハッキングできます。その後、少なくともほとんどの(必ずしもすべてではない)モードよりも優先されます。


これは任意のメジャーモードで機能しますか?つまり、「foo-mode」と呼ばれるメジャーモードをインストールする(define-key foo-mode (kbd "C-j") nil)と、.emacsファイルに入れて、これが機能することを期待できますか?
nispio 14

実際にはそれが必要ですfoo-mode-map(答えの私の例は悪かった)が、はい、それはメジャーモードでキーバインディングを無効にするので、代わりにグローバルキーバインディングが使用されます(それを使用している別のマイナーモードがない限り)。
shosti 14

キーマップfoo-modeが呼び出されることはかなり普遍的foo-mode-mapですか?
nispio 14

@nispioはい、それは大部分のモードに当てはまります(ただし、いくつかの不正があります)。
shosti 14

0

次のマクロを使用できます。

(defmacro expose-global-keybinding (binding map)
  `(define-key ,map ,binding (lookup-key (current-global-map) ,binding)))

(defmacro expose-bindings (map bindings)
  `(dolist (bnd ,bindings)
     (expose-global-keybinding (kbd bnd) ,map)))

編集

以下の例を確認してください。

キーマップXがグローバルバインディングYをオーバーライドしている場合、次のように記述します。

(expose-bindings X '("Y"))

そして、オーバーライドは「元に戻されます」。


バッククォートを使用することで恩恵を受けるマクロ: `(define-key、map、binding(lookup-key(current-global-map)、binding))
Sigma

マクロの動作と使用方法についてコメントできますか?コードから私には明らかではありません。
nispio 14

最初のマクロは、グローバルマップ内のキーを検索し、その結果をに割り当てます。other mapしたがって、を通じてグローバルマップバインディングを公開しother mapます。2番目の方法では、前者をバインディングのリストに適用できます。
レナンラネリ14

私が密集している場合は申し訳ありませんが、まだ使用法を完全に理解していません。独自の特別なグローバルキーマップを定義する必要がありますか?マイナーモードに属する必要がありますか?expose-bindings最初に実行してから、それらのキーを必要なコマンドにグローバルにバインドしますか?たぶん、この作業を行うために私の初期化ファイルに何を入れるか例を示すことができます。
nispio

2
これらのマクロ名は誤った名前であることに注意してください。グローバルバインディングを「公開」するのではなく、グローバルバインディングを複製します。実際のグローバルバインディングが変更されても、これらの重複コピーは変更されません。
PHILS
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.