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


38

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

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

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

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

참고 : 내 질문이 아닌 "내가 어떻게 바인딩 C-j에 newline-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.