Как перепривязать TAB и RET в второстепенном режиме Emacs? - PullRequest
2 голосов
/ 04 февраля 2012

Я пытаюсь определить мой второстепенный режим, имитируя его после isearch-mode (поскольку это своего рода интерактивный инструмент поиска и замены, я подумал, что это может быть хорошей отправной точкой). Мои команды работают хорошо (проверено на глобальных сочетаниях клавиш), но у меня есть серьезные проблемы с привязкой их локально (в карте второстепенных режимов) к некоторым ключам, а именно TAB и RET. Я делаю что-то вроде этого:

(defvar my-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\s" 'my-command)
    (define-key map "\t" 'another-one)
    (define-key map "\r" 'yet-another)
    map))

(Конечно, я действительно поместил свою раскладку ключей в minor-mode-map-alist.)

Хотя команда space-bound работает нормально, TAB и RET почему-то не работают. Если я изменю, например, "\ t" на "[f11]", он будет работать нормально. Я попытался использовать «векторную нотацию» ([? ​​\ T]) с идентичными результатами (после C-h C-v-моей карты клавиш это не удивительно). Что может происходить?

Редактировать: , чтобы прояснить проблему, я попытался изолировать ее и придумал следующий код. Предположим, что я хочу иметь искусственный, довольно минимальный второстепенный режим tabbang, в котором клавиша TAB вставляет восклицательный знак. Я делаю это:

(defvar tabbang-mode)
(add-to-list 'minor-mode-alist '(tabbang-mode tabbang-mode) t)

(defvar tabbang-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map [?\t] 'tabbang-insert-bang)
    (define-key map [?\C-\t] 'tabbang-insert-bang)
    (define-key map [f11] 'tabbang-insert-bang)
    (define-key map [?\r] 'tabbang-done)
    (define-key map [t] 'tabbang-other-char)
    map))
(add-to-list 'minor-mode-map-alist `(tabbang-mode . ,tabbang-mode-map) t)

(defun tabbang-insert-bang ()
  (interactive)
  (insert "!"))

(defun tabbang-mode ()
  (interactive)
  (setq tabbang-mode " tabbang"))

(defun tabbang-other-char ()
  (interactive)
  (tabbang-done)
  (setq unread-command-events
    (append (listify-key-sequence (this-command-keys))
        unread-command-events)))

(defun tabbang-done ()
  (interactive)
  (setq tabbang-mode nil))

В то время как в моем tabbang-mode «другие» клавиши корректно выходят из режима и вставляют себя, f11 вставляет удар (правильно), TAB не выходит из режима (правильно), но ничего не вставляет (неправильно), C-TAB выдает ошибку «неопределенный ключ» (определенно неправильно), и RET выходит из режима (правильно), но вставляет новую строку (неправильно). И я попробовал «свежий» emacs (без загрузки site-file и моего .emacs), чтобы не вмешивался другой код (я боялся, что yasnippet каким-то образом захватит TAB и т. Д.) Что происходит?

Ответы [ 3 ]

5 голосов
/ 04 февраля 2012

Я полагаю, что вы можете изменить их с помощью (kbd "<tab>") и (kbd "<return>") вместо "\ t" и "\ r" соответственно.


В ответ на ваши изменения, да, следующееу меня отлично работает:

...
(defvar tabbang-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "<tab>") 'tabbang-insert-bang)
    (define-key map (kbd "<C-tab>") 'tabbang-insert-bang)
    (define-key map (kbd "<f11>") 'tabbang-insert-bang)
    (define-key map (kbd "<return>") 'tabbang-done)
    (define-key map (kbd "t") 'tabbang-other-char)
    map))
(add-to-list 'minor-mode-map-alist `(tabbang-mode . ,tabbang-mode-map) t)
...
3 голосов
/ 09 февраля 2012

Проблема заключается в следующем: некоторые ключи переводятся через карту функциональных клавиш, которая выполняет перевод только тогда, когда ключ был бы несвязанным.Например, событие [tab], генерируемое в графическом интерфейсе при нажатии клавиши TAB, преобразуется в [? \ T], если нет привязки к [tab].То же самое для [return], который отображается на [? \ R].Теперь проблема в том, что ваша привязка catchall [t] означает, что любая последовательность клавиш имеет привязку, поэтому [tab] больше не переопределяется в [? \ T].isearch страдает от той же проблемы, см. искажения, которые мы делаем в isearch-other-meta-char.

Я думаю, что правильный подход к этой проблеме - избежать связывания [t] и вместо этого реализовать «режим выхода»для любого другого ключа «по-другому (мое эмпирическое правило в настоящее время таково:« если вам нужно вернуть вещи в непрочитанные-команды-события, вы, вероятно, делаете это неправильно »).Один из способов сделать это - использовать pre-command-hook, который проверяет, является ли `this-command 'одним из ваших или привязан ли (this-command-keys-vector) к вашей карте ключей.В Emacs-24 у нас, вероятно, будет что-то вроде приведенного ниже кода для таких видов использования:

(defun set-temporary-overlay-map (map &optional keep-pred)
  (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map"))
         (overlaysym (make-symbol "t"))
         (alist (list (cons overlaysym map)))
         (clearfun
          `(lambda ()
             (unless ,(cond ((null keep-pred) nil)
                            ((eq t keep-pred)
                             `(eq this-command
                                  (lookup-key ',map
                                              (this-command-keys-vector))))
                            (t `(funcall ',keep-pred)))
               (remove-hook 'pre-command-hook ',clearfunsym)
               (setq emulation-mode-map-alists
                     (delq ',alist emulation-mode-map-alists))))))
    (set overlaysym overlaysym)
    (fset clearfunsym clearfun)
    (add-hook 'pre-command-hook clearfunsym)
    (push alist emulation-mode-map-alists)))
0 голосов
/ 04 февраля 2012

Строка "tab" (то есть то, что вы получаете с "\t") не соответствует действительному имени ключа. Вы хотите что-то вроде "\C-i" для табуляции и "\C-j" для новой строки.

...