주요 모드 바인딩을 재정의하는 방법


38

때로는 전역 키 바인딩이 주요 모드로 재정의되는 경우가 있습니다. 쉬운 예는 내 init 파일의 다음 설정입니다.

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

그러나이 키 바인딩은 스크래치 버퍼의 기본 모드 인 "Lisp Interaction"주요 모드에 의해 숨겨져 있습니다.

메이저 모드 (또는 마이너 모드)가 글로벌 키 바인딩을 숨기고있는 상황에서 자신을 발견하면 어떻게 되돌릴 수 있습니까?

참고 : 내 질문이 아닌 "내가 어떻게 바인딩 C-jnewline-and-indent?"모드 "에서"리스프 상호 작용 충돌하는 키맵 또는 일부 주요 / 부모 모드에 의해 숨겨지는 사용자 키 바인딩을 처리하는 방법에 대한 훨씬 일반적인 답변에 관심이 있습니다.


답변:


39

자신의 마이너 모드를 정의하지 않으려는 경우 (첫 번째 답변에서 언급 한) 동일한 솔루션에 대한 "바로 가기"접근 방식도 있습니다.

use-packageMelpa에서 제공 하는 패키지 를 설치하고 함께 제공 되는 패키지 의 일부 bind-key*또는 bind-keys*매크로를 사용할 수 있습니다 .bind-keyuse-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 바인딩을 시도하기 위해 일시적으로 끌 수 있다는 것입니다 (몇 번 그렇게해야했습니다).
Kaushal Modi

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)

마찬가지로 부 모드에서 설정된 다른 키 바인딩은 다른 모드의 키 바인딩보다 우선합니다.

마이너 모드 작성 방법에 대한 Christopher Wellons 의 블로그 게시물 을 읽는 것이 좋습니다 . 그 블로그와 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"))

그리고 재정의는 '취소'됩니다.


당신의 매크로는 당신이 역 따옴표를 사용하여 이익을 얻는다 :`(define-key, map, binding (look-key (current-global-map), binding))
Sigma

매크로가하는 일과 사용 방법에 대해 언급 할 수 있습니까? 코드에서 분명하지 않습니다.
nispio

첫 번째 매크로는 전역지도에서 키를 조회하고 결과를에 할당하여를 other map통해 전역지도 바인딩을 노출시킵니다 other map. 두 번째는 바인딩 목록에 전자를 적용하는 것입니다.
Renan Ranelli

밀도가 높아서 죄송하지만 사용법을 완전히 이해하지 못합니다. 나만의 특수 글로벌 키맵을 정의해야합니까? 부 모드에 속해야합니까? expose-bindings먼저 수행 한 다음 해당 키를 원하는 명령에 전체적으로 바인딩합니까? 어쩌면이 작업을 수행하기 위해 init 파일에 넣을 수있는 예를 보여줄 수 있습니다.
nispio

2
이 매크로 이름은 잘못된 이름입니다. 전역 바인딩을 "노출"하지 않고 전역 바인딩을 복제 합니다. 실제 글로벌 바인딩이 변경되면 이러한 복제본은 변경되지 않습니다.
phils
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.