Глобальное переопределение привязки клавиш в Emacs

101

Как я могу установить привязку ключа, которая глобально переопределяет и имеет приоритет над всеми другими привязками для этого ключа? Я хочу переопределить все карты основного / второстепенного режима и убедиться, что моя привязка всегда действует.

Это, конечно, не работает:

(global-set-key "\C-i" 'some-function)

Он работает text-mode, но когда я использую lisp-mode, C-iон восстанавливается lisp-indent-line.

Я могу пройти и переопределить эту привязку в lisp-modeкаждом другом режиме индивидуально, но должен быть более простой способ. Каждый раз, когда я устанавливаю новый режим для нового типа файла, мне приходилось возвращаться и проверять, не отменяются ли все мои привязки клавиш в новом режиме.

Я хочу сделать это, потому что хочу имитировать привязки, которые я уже изучил и усвоил у других редакторов.

Брайан Карпер
источник

Ответы:

151

Я использую второстепенный режим для всех своих привязок клавиш "override":

(defvar my-keys-minor-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-i") 'some-function)
    map)
  "my-keys-minor-mode keymap.")

(define-minor-mode my-keys-minor-mode
  "A minor mode so that my key settings override annoying major modes."
  :init-value t
  :lighter " my-keys")

(my-keys-minor-mode 1)

Это дает дополнительное преимущество, заключающееся в возможности отключить все мои модификации одним махом (просто отключите второстепенный режим) в случае, если кто-то еще управляет клавиатурой или мне нужно увидеть, что делает привязка клавиш по умолчанию.

Обратите внимание, что вам может потребоваться отключить это в минибуфере:

(defun my-minibuffer-setup-hook ()
  (my-keys-minor-mode 0))

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
Скоттфрейзер
источник
1
Это кажется хорошей идеей. Есть ли способ убедиться, что ваш второстепенный режим не противоречит другим второстепенным режимам?
Брайан Карпер,
3
Убедитесь, что ваш второстепенный режим стоит первым в списке minor-mode-map-alist.
Trey Jackson,
2
Трей прав. Обычно достаточно поместить это в конец вашего .emacs. Кроме того, большинство привязок, которые вы переопределяете, устанавливаются основными режимами ... второстепенные режимы обычно не мешают.
scottfrazer
Я последовал этому подходу, но затем понял, что все, что я привязываю к Ci, также связывается с клавишей TAB. Какие-либо предложения?
Steve
3
Брайан Карпер: Вот усовершенствование для работы с загруженными впоследствии второстепенными режимами: stackoverflow.com/questions/683425/…
phils
30

В дополнение к ответу scottfrazer я написал следующее, чтобы мои привязки клавиш сохраняли приоритет, даже если впоследствии загруженные библиотеки вводят новые собственные таблицы клавиш.

Поскольку раскладки клавиатуры могут быть сгенерированы во время компиляции, loadмне показалось, что это лучшее место для этого.

(add-hook 'after-load-functions 'my-keys-have-priority)

(defun my-keys-have-priority (_file)
  "Try to ensure that my keybindings retain priority over other minor modes.

Called via the `after-load-functions' special hook."
  (unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
    (let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
      (assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
      (add-to-list 'minor-mode-map-alist mykeys))))
филы
источник
Я вставил свой сценарий , но он не сделал никакого влияния :(
Alper
@alper Я предлагаю вам опубликовать вопрос со всеми соответствующими деталями, включая код, который вы фактически используете, и конкретный пример / рецепт для воспроизведения проблемы.
Филс
21

Установите use-package, оцените, и все готово:

(require 'bind-key)
(bind-key* "C-i" 'some-function)
Миржан Иркегулов
источник
5
Установить только bind-key достаточно для варианта использования, хотя use-package зависит от bind-key.
xuchunyang
2
Этот (пакет bind-key) кажется наиболее удобным решением; Спасибо, что поделился.
oligilo
Я не смог найти матч за use-package:Install package: use-package [No Match]
Альпер
15

Я нашел этот вопрос при поиске «emacs undefine org mode keybindings», потому что я хотел отвязать существующее поведение Cc Cb, чтобы моя глобальная карта для скрытого буфера работала в организационном буфере.

Это оказалось для меня самым простым решением:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))
Джей Доан
источник
1
Это зависит от режима и не затрагивает более широкую картину, хотя и работает для вашего единственного варианта использования.
RichieHH
12

Хотя ответ Скоттфразера - это именно то, о чем вы просили, я упомяну для потомков другое решение.

Из руководства Emacs :

«Не определяйте букву Cc как ключ в программах на Лиспе. Последовательности, состоящие из Cc и буквы (верхнего или нижнего регистра), зарезервированы для пользователей; это единственные последовательности, зарезервированные для пользователей, поэтому не блокируйте их».

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

Киркланд
источник
3
Я не ожидал, что из всех режимов org-mode нарушит это правило. Cc Ch сообщает мне, что Cc a, b, c и l связаны с org-повесткой дня, org-iswitchb, org-capture и org-store-link соответственно.
Нейт Парсонс,
7
Afaik, привязка их - это первый шаг, который предлагает org-mode, чтобы использовать его, но пользователь должен определить их сам (т.е. это не выполняется по умолчанию), и при этом может выбрать любой другой. (также потому, что эти привязки должны быть глобальными, не привязанными к основному режиму организации)
Никана Реклавикс
3

Если вы хотите «всегда использовать привязки клавиш на карте, если я явно не переопределяю их для конкретной карты режимов» и предполагая, что вы используете подход Скоттфразье , вам нужно:

(defun locally-override (key cmd)
  (unless (local-variable-p 'my-keys-minor-mode-map)
    (set (make-variable-buffer-local 'my-keys-minor-mode-map)
         (make-sparse-keymap))
    (set-keymap-parent my-keys-minor-mode-map 
                       (default-value 'my-keys-minor-mode-map)))
  (define-key my-keys-minor-mode-map key cmd))

Так

(locally-override "\C-i" nil)

должен удалить привязку "\ Ci" только из второстепенного режима в текущем буфере. Предупреждение: это полностью непроверено, но похоже на правильный подход. Точка установки родителя, а не просто копирование глобального значения my-keys-minor-mode-map заключается в том, чтобы любые последующие изменения глобального значения автоматически отражались в локальном значении.

gbrunick
источник
2

Я не думаю, что ты сможешь. Это примерно эквивалентно тому, что вы хотите определить глобальную переменную, которую нельзя скрыть с помощью объявлений локальных переменных в функциях. Сфера просто так не работает.

Однако может быть способ написать функцию elisp для просмотра списка режимов и переназначения ее для каждого отдельного пользователя.

ТЕД
источник
Эта идея определения области видимости технически верна, но overriding-local-mapспециально разработана для отмены всех других карт. Однако пользоваться им опасно.
event_jr 01
2

Если вы действительно не хотите сделать это самостоятельно, вам следует проверить, не делал ли это кто-нибудь еще.

Для Emacs есть пакет, который дает вашим Windows-подобным сочетаниям клавиш. Вы сможете найти его через Google.

JesperE
источник
4
Пакет, о котором вы думаете, вероятно cua-mode.
Дрю
1
Да, это пакет.
JesperE