Как привязать ваши ключи к раскладкам, которые еще не загружены?

9

Я использую use-packageдля управления установленными пакетами и bind-keyназначения действий для пользовательских ключей, которые мне нравятся.

Я переопределяю большую часть стандартной привязки клавиш Emacs (например, C-nстановится M-k, C-pстановится M-i), но я в порядке с другими режимами, переопределяющими мою схему привязки клавиш. Однако иногда я хочу, чтобы связывание клавиш сохранялось. Я хочу иметь в M-kвиду что-то еще, чем по умолчанию Gnus или Helm.

Однако все они конфликтуют друг с другом при запуске Emacs, потому что я не могу добавить привязку к use-packageкарте ключей , если она не существует (потому что иногда откладывает загрузку пакета). Например, следующие команды выдают ошибки (например (void-variable helm-map)), потому что Helm и Gnus еще не полностью загружены.

(bind-key "M-Y" 'helm-end-of-buffer helm-map)
(bind-key "M-k" 'helm-next-line helm-find-files-map)
(bind-key "M-s" 'other-window gnus-summary-mode-map)

У меня есть все мои use-packageвызовы в одном файле и bind-keyдля пользовательских сочетаний клавиш в другом файле. Я не хочу помещать привязки в use-packageвызовы, потому что, возможно, я хочу опубликовать свою собственную схему привязки клавиш в виде отдельного пакета. Что, если я хочу, чтобы кто-то устанавливал мою схему, также были переопределены локальные сочетания клавиш Helm и Gnus?

Как мне управлять привязками клавиш в режиме, используя bind-keyвсе ключи, даже если пакеты загружаются в последнее время, а все настройки ключей находятся внутри одного файла?

Миржан Иркегулов
источник

Ответы:

20

Вы можете использовать, with-eval-after-loadчтобы отложить привязку ключа до тех пор, пока не будет загружен определенный модуль (и, следовательно, не определена таблица ключей):

(with-eval-after-load "helm"
  (bind-key "M-Y" #'helm-end-of-buffer helm-map))

Используйте, C-h v helm-mapчтобы найти, в каком модуле определена таблица ключей, и, следовательно, что поместить в строку в первой строке.


with-eval-after-loadбыл введен в Emacs 24.4. Если у вас есть более ранняя версия Emacs, вы должны использовать eval-after-loadвместо этого и поставить кавычку перед bind-keyвызовом:

(eval-after-load "helm"
  '(bind-key "M-Y" #'helm-end-of-buffer helm-map))

Если вы хотите сделать несколько bind-keyзвонков в этой форме, with-eval-after-loadпросто поместите их один за другим, но eval-after-loadвам нужно обернуть их все в progn:

(eval-after-load "helm"
  '(progn
     (bind-key "M-Y" #'helm-end-of-buffer helm-map)
     (bind-key "M-k" #'helm-next-line helm-find-files-map)))
legoscia
источник
9

Решение

Для того , чтобы выполнить вещи после загрузки данного пакета, вы должны положить , что после того, как :configв use-package.

Вот пример использования фрагмента в вашем вопросе:

Фрагмент №1

(use-package helm
  :config
  (progn
    (bind-key "M-Y" #'helm-end-of-buffer helm-map)
    (bind-key "M-k" #'helm-next-line helm-find-files-map)))

(use-package gnus
  :config
  (bind-key "M-s" #'other-window gnus-summary-mode-map))

объяснение

Это нормально, если нижеуказанные 2 фрагмента находятся в разных местах вашего emacs init.elили в любом из вложенных файлов, загруженных / требуемых.

Фрагмент № 2

(use-package gnus)

Фрагмент № 3

(use-package gnus
  :config
  (bind-key "M-s" #'other-window gnus-summary-mode-map))

Причина в том, что не имеет значения, какой из 2 приведенных выше фрагментов выполняется первым.

Вот почему ... ниже приведен фрагмент кода # 3.

Вы получаете следующее, делая, M-x pp-macroexpand-last-sexpкогда точка (курсор) находится после последней закрывающей скобки этого фрагмента.

Фрагмент № 4

(if (not (require 'gnus nil t))
    (ignore (message (format "Could not load %s" 'gnus)))
  (condition-case-unless-debug err
      (bind-key "M-s" #'other-window gnus-summary-mode-map)
    (error
     (ignore
      (display-warning 'use-package
                       (format "%s %s: %s" "gnus" ":config"
                               (error-message-string err))
                       :error))))
  t)

Приведенный выше фрагмент в основном означает, что

  • gnusсначала требуется, а затем bind-keyформа выполняется.
  • Если gnusон не найден, вы увидите в буфере * Messages * сообщение о том, что этот пакет не может быть загружен.
  • Он выдаст ошибку, если есть какие-либо проблемы в выполнении (bind-key "M-s" #'other-window gnus-summary-mode-map)

Кроме того, если gnusуже требуется Snippet # 2 выше , и требуется снова Snippet # 3 , это не имеет значения , потому что requireне загружает пакет снова , если он уже загружен.


Ссылка

Из use-packageоснов его github,

:configможет использоваться для выполнения кода после загрузки пакета. В тех случаях, когда загрузка выполняется лениво (см. Подробнее об автозагрузке ниже), это выполнение откладывается до тех пор, пока не произойдет автозагрузка:

Фрагмент № 5

(use-package foo
  :init
  (setq foo-variable t)
  :config
  (foo-mode 1))

Выше выполняет :initsection ( (setq foo-variable t)) перед foo загрузкой пакета. Но (foo-mode 1)в :configразделе выполняется после foo загрузки.

Каушал Моди
источник
3

В противоположность другим ответам, я всегда использовал крючки для этого:

(defun my-company-maps()
  (define-key company-active-map "\C-x\M-h" 'company-show-doc-buffer)
  (define-key company-active-map "\C-n" 'company-select-next)
  (define-key company-active-map "\C-p" 'company-select-previous)
  (define-key company-active-map "\C-h" 'delete-backward-char))

(add-hook 'company-mode-hook 'my-company-maps)
Джесси
источник
Я тоже, я думал, что это предпочтительный способ сделать это.
Значимое имя пользователя
2

Поскольку вы уже используете bind-key, прямо из документации bind-key.el:

Если вы хотите, чтобы связывание клавиш перекрывало все второстепенные режимы, которые также могут связывать один и тот же ключ, используйте форму `bind-key * ':

(bind-key* "<C-return>" 'other-window)

Чтобы отменить привязку ключа в таблице ключей (например, чтобы запретить вашему любимому основному режиму изменять привязку, которую вы не хотите переопределять везде), используйте команду unbind-key:

(unbind-key "C-c x" some-other-mode-map)

Последняя форма ломается, если раскладка клавиатуры в настоящее время не определена, поскольку определяющий файл some-other-mode-mapеще не загружен. Таким образом, вы можете поместить это в use-packagefor some-other-mode(определение пакета some-other-mode-map) или используя with-eval-after-load:

(with-eval-after-load 'some-other-mode
  (unbind-key "C-c x" some-other-mode-map))

Другой альтернативой будет определение вашего собственного второстепенного режима, содержащего все привязки, которые не должны быть переопределены основными режимами:

(defvar my-very-own-keymap (make-keymap) "my very own keymap.")

(define-key my-very-own-keymap (kbd "M-i") 'my-foo)

(define-minor-mode my-very-own-keys-minor-mode
  "Minor mode with my very own keybindings."
  t " my-own-keys" my-very-own-keymap)
cogsci
источник