Як замінити основні прив’язки режиму


38

Іноді мої глобальні клавіші переосмислюються основним режимом. Простим прикладом є наступне налаштування у моєму файлі init

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

Але прикро це прив'язка клавіш прихована головним режимом "Ліпп взаємодія", який є типовим режимом буфера подряпин.

Коли я опиняюсь у ситуації, коли основний режим (або другорядний режим) приховує моє глобальне введення ключів, як я можу його повернути?

Примітка. Моє запитання не в тому, "Як я можу прив'язатись C-jдо newline-and-indentрежиму" Ліпп взаємодія "? Мене цікавить набагато більш загальна відповідь про те, як поводитися з картами клавіш, які зіштовхуються або пов’язаними з користувачами клавіатурними зв’язками, які приховуються деяким основним / другорядним режимом.


Відповіді:


39

Існує підхід "швидкого доступу" для того ж рішення, якщо ви не хочете визначати свій власний другорядний режим (про який я говорю у своїй першій відповіді).

Ви можете встановити use-packageпакет , доступний від Melpa і використання зробити з 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для забезпечення пріоритету).
phils

Я позначив це як відповідь через його простоту. Це по суті робиться те саме, що і ця відповідь , але зручно робити більшу частину роботи за вами за кадром.
nispio

@nispio Ви маєте рацію. З мого досвіду, різницею є лише метод, який застосовується для того, щоб прив'язки другорядних режимів перекривали інші режими в усьому світі. Але перевага іншого підходу (наявність власного другорядного режиму) полягає в тому, що ви можете вимкнути його на мить, щоб спробувати оригінальні прив’язки emacs, якщо вам це знадобиться (мені це потрібно було зробити кілька разів).
Каушал Моді

1
Додайте (bind-key* "C-M-&" 'override-global-mode)до свого init, і, як правило, ви можете швидко отримати прив'язки зі свого шляху. Оскільки override-global-modeце не "глобальний" другорядний режим, вам все одно доведеться деактивувати його на основі кожного буфера. Тож якщо ви часто виявляєте деактивацію глобальних ключів переопределення, це рішення не є зручним.
nispio

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

Насправді ви хочете, щоб це було foo-mode-map(мій приклад у відповіді був поганим), але так, це відключить в'язання клавіш у головному режимі, тому глобальне введення ключів буде використано замість нього (якщо не використовується інший другорядний режим, який використовує це).
shosti

Чи досить універсальним foo-modeбуде називатися ключова карта для foo-mode-map?
nispio

@nispio так, це справедливо для переважної більшості режимів (хоча там є кілька шахраїв).
shosti

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"))

І тоді перевизначення буде "скасовано".


ваш макрос ви отримуєте перевагу від використання зворотного котирування: `(ключ-ключ, карта, прив'язка (ключ пошуку (поточна-глобальна карта), прив’язка))
Sigma,

Чи можете ви прокоментувати, що робить макрос, і як ним користуватися? З коду мені незрозуміло.
nispio

Перший макрос просто шукає ключ на глобальній карті і присвоює результат тим other mapсамим, викриваючи прив'язку глобальної карти через other map. Другий дозволяє лише застосувати перше для списку прив’язок.
Ренан Ранеллі

Вибачте, якщо я щільний, але все ще не повністю розумію використання. Чи потрібно визначити власну спеціальну глобальну ключову карту? Чи потрібно належати до другорядного режиму? Чи виконую я expose-bindingsспочатку, а потім глобально прив’язую ці клавіші до тих команд, які я хочу? Можливо, ви можете показати приклад того, що я міг би помістити у свій файл init, щоб зробити цю роботу.
nispio

2
Зауважте, що ці імена макросів є неправильними. Вони не "викривають" глобальну обов'язковість, а скопіюють глобальну прив'язку. Якщо реальна глобальна прив'язка зміниться, ці копії копій не будуть.
phils
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.