Как переопределить привязки основного режима


38

Иногда мои глобальные сочетания клавиш переопределяются основным режимом. Простой пример - следующая настройка в моем файле инициализации

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

Но досадно, что эта связка клавиш скрыта основным режимом «Лисп взаимодействия», который является режимом по умолчанию для рабочего буфера.

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

Примечание: Мой вопрос не «Как я могу связать C-jс newline-and-indent„? Режим“в» Lisp Interaction Меня интересует гораздо более общий ответ о том, как обращаться с сопоставлениями клавиш, которые конфликтуют, или с сочетаниями клавиш пользователя, которые скрываются в каком-то основном / второстепенном режиме.


Ответы:


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для обеспечения приоритета).
— Фил

Я отметил это как ответ из-за его простоты. По сути, он делает то же самое, что и этот ответ , но он удобно выполняет большую часть работы за кулисами.
— Ниспио

@nispio Ты прав. По моему опыту, единственное отличие состоит в том, что метод, который используется для привязки второстепенных режимов, перекрывает другие режимы во всем мире. Но преимущество другого подхода (наличия вашего собственного второстепенного режима) состоит в том, что вы можете на мгновение отключить его, чтобы попробовать исходные привязки emacs, если вам когда-либо понадобится (мне нужно было сделать это несколько раз).
— Каушал Моди

1
Добавьте (bind-key* "C-M-&" 'override-global-mode)к своей инициации, и вы можете быстро избавиться от привязок, если это необходимо. Поскольку override-global-modeэто не «глобальный» второстепенный режим, вам все равно придется деактивировать его для каждого буфера. Так что если вы часто деактивируете глобальные ключи переопределения, тогда это решение не удобно.
— Ниспио

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 и ожидать, что это сработает?
— Ниспио

На самом деле вы хотите, чтобы это было foo-mode-map(мой пример в ответе был плохим), но да, это отключит привязку клавиш в основном режиме, так что вместо этого будет использоваться глобальная привязка клавиш (если только не используется другой второстепенный режим).
— шости

Является ли достаточно универсальным, что foo-modeбудет называться раскладка клавиатуры foo-mode-map?
— Ниспио

@nispio Да, это верно для подавляющего большинства режимов (хотя есть несколько жуликов).
— шости

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 (ключ поиска (current-global-map), привязка))
— Sigma

Можете ли вы прокомментировать, что делает макрос, и как его использовать? Мне не понятно из кода.
— Ниспио

Первый макрос просто ищет ключ в глобальной карте и присваивает результат other map, таким образом, выставляя привязку глобальной карты через other map. Второй просто позволяет применить первый для списка привязок.
— Ренан Ранелли

Извините, если я плотный, но я все еще не полностью понимаю использование. Нужно ли мне определять свою собственную специальную глобальную таблицу ключей? Это должно принадлежать второстепенному режиму? Должен ли я выполнить expose-bindingsсначала, а затем глобально связать эти клавиши с командами, которые я хочу? Может быть, вы могли бы показать пример того, что я мог бы поместить в мой файл инициализации, чтобы сделать эту работу.
— Ниспио

2
Обратите внимание, что эти имена макросов являются неправильными. Они не «выставляют» глобальное связывание, а скорее дублируют глобальное связывание. Если реальная глобальная привязка изменится, этих дубликатов не будет.
— Фил
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.