2013-04-18 2 views
5

나는 포인트가 어디에 있는지에 따라 다른 완료를 시도하는 사용자 정의 탭 완성 구현을 작성하려고합니다. 그러나 완료 조건 중 하나라도 충족되지 않으면 현재 모드에서 원래 의도 한대로 탭에서 수행하려고합니다. 이 같은Elisp : 조건부로 키 바인딩을 변경하십시오.

뭔가 :

(defun my-custom-tab-completion() 
    (interactive) 
    (cond 
    (some-condition 
    (do-something)) 
    (some-other-condition 
    (do-something-else)) 
    (t 
    (do-whatever-tab-is-supposed-to-do-in-the-current-mode))) ;; How do I do this? 

현재 나는 특정 모드에 대해 확인하고 해당 모드에 대한 옳은 일을하고,하지만 난 정말이 명시 적으로 할 필요없이 옳은 일을하는 솔루션을 원하는거야 해당 특정 모드에 대한 조건을 추가하십시오.

어떻게하는 지에 대한 아이디어가 있으십니까?

감사합니다./에릭

당신은 같은 key-binding (또는보다 구체적인 변종 global-key-binding, minor-mode-key-bindinglocal-key-binding)이 바인딩에 대해 활성화 키맵을 조사하는 기능을 사용할 수
+1

는'정의-key'와'로컬 설정 key'에 대한 설명서를 참조하십시오. 이는 일반적으로 모드 별 키 맵을 수정하여 수행됩니다. –

답변

2

. 예를 들어

: 보면서 무한 루프를 방지하기

(call-interactively (key-binding (kbd "TAB"))) 
;; in an emacs-lisp-mode buffer: 
;; --> indent-for-tab-command 
;; 
;; in a c++-mode buffer with yas/minor-mode: 
;; --> yas/expand 

한 가지 방법 명령은이 미성년자 모드에서 바인딩을 넣어 일시적으로 키맵을 비활성화 할 수 TAB에 바인딩 된 경우 바인딩 TAB을 위해 :

(define-minor-mode my-complete-mode 
    "Smart completion" 
    :keymap (let ((map (make-sparse-keymap))) 
      (define-key map (kbd "TAB") 'my-complete) 
      map)) 

(defun my-complete() 
    (interactive) 
    (message "my-complete") 
    (let ((my-complete-mode nil)) 
    (call-interactively (key-binding (kbd "TAB"))))) 
+0

답변 해 주셔서 감사합니다. 여기에서 문제는 탭에 명령을 바인딩하고 키 바인딩이 실제로 함수 자체를 반환하므로 무한 루프가 발생한다는 것입니다. 어떻게 든 원래의 키 맵에서 바인딩을 찾을 수 있을까요? –

+0

네가 맞아,이 일은 쉽게 끝나지 않는다. 가능한 해결 방법은 내 편집을 참조하십시오. – Francesco

+0

마이너 모드의 경우, 'minor-mode-map-alist'에서 엔트리를 제거 할 필요가 없습니다. 호출을 중심으로 마이너 모드 변수 (일명'my-complete-mode')를 let-bind 할 수 있습니다 '키 바인딩 ' – Stefan

2

그것은 가능하면 달성 할 수 있음 특별한 해결 방법이 전혀 필요 없습니다. 대부분의 모드에서 TAB은 기본적으로 들여 쓰기를 수행하지만, 글로벌 변수 tab-always-indent'complete으로 설정하면 먼저 완료를 시도하고 완료가 불가능할 경우 들여 쓰기를 시도합니다. TAB이 주요 모드 중 하나에서 다른 명령에 바인딩 된 경우 행운을 빕니다.

필요한 모드에서 작동하는 경우 사용자 지정 완성 기능을 적용 가능한 모든 버퍼 (아마도 모드 후크 사용)의 목록 completion-at-point-functions 앞에 추가해야합니다. completion-at-point 명령은 중 하나가 반환 될 때까지 completion-at-point-functions에 나열된 각 함수를 호출하므로 사용자 지정 완성 함수가 기존 동작에 "fall through"되도록하려면 return nil이 필요합니다.

이 질문에 대한 100 % 답변은 아니지만, 작업하는 주요 모드가 일반 지침에 따라 작성된 경우 가장 깨끗한 방법 일 수 있습니다.

+0

아주 좋은 지적이지만 많은 부 모드가 예를 들어 YASnippet이나 자동 완성과 같은'TAB' 키를 리바 인 딩할 수 있습니다. 그러한 사소한 모드가'(setq tab-always-indent 'complete)'를 존중하는지 알고 있습니까? – Francesco

+0

이러한 사소한 모드를 무시하려면, 그렇게하십시오. 당신은 여전히'indent-for-tab-command'를 사용할 수 있습니다. BTW, yasnippet으로'tab-always-indent'의'complete' 값이 작동하지 않는다면 이것을 (yasnippet에서) 버그로보고 싶을 것입니다. – Stefan

3

다음은 조건부로 키 바인딩을 정의하기 위해 Emacs key binding fallback을 기반으로 작성한 매크로입니다. 그것은 지정된 마이너 모드로 키 바인딩을 추가하지만 조건이 true가 아닌 경우, 이전에 할당 된 작업이 실행됩니다

(defmacro define-key-with-fallback (keymap key def condition &optional mode) 
    "Define key with fallback. Binds KEY to definition DEF in keymap KEYMAP, 
    the binding is active when the CONDITION is true. Otherwise turns MODE off 
    and re-enables previous definition for KEY. If MODE is nil, tries to recover 
    it by stripping off \"-map\" from KEYMAP name." 
    `(define-key ,keymap ,key 
    (lambda() (interactive) 
     (if ,condition ,def 
      (let* ((,(if mode mode 
        (let* ((keymap-str (symbol-name keymap)) 
          (mode-name-end (- (string-width keymap-str) 4))) 
         (if (string= "-map" (substring keymap-str mode-name-end)) 
          (intern (substring keymap-str 0 mode-name-end)) 
         (error "Could not deduce mode name from keymap name (\"-map\" missing?)")))) 
        nil) 
       (original-func (key-binding ,key))) 
      (call-interactively original-func)))))) 

그런 다음 나는이 나는 경우에만 TAB에 대한 특별한 바인딩을 사용하여 다음과 같은 일을 할 수있다 outline-minor-mode의 헤더에서.그렇지 않으면 내 기본 동작 (I 들여 쓰기 및 yasnippets 모두가)가 실행됩니다

(define-key-with-fallback outline-minor-mode-map (kbd "TAB") 
    (outline-cycle 1) (outline-on-heading-p)) 
3

은 BTW, 여기에 또 다른 솔루션입니다 :

(define-key <map> <key> 
    `(menu-item "" <my-cmd> :filter ,(lambda (cmd) (if <my-predicate> cmd)))) 
+0

이 속임수는 나를 여러 번 구해 냈습니다. –

0

define-key 인용 문자열이나이 예처럼 대화 형 람다를 받아 들일 수 있습니다.

;Static 
(define-key evil-normal-state-mapr "m" 'evil-motion-state) 
;Conditional 
(define-key evil-normal-state-map "m" 
    (lambda() (interactive) (message "%s" major-mode))) 

람다는 my-tab-completion과 같은 명명 된 함수로 대체 될 수 있으며보다 효과적으로 사용됩니다. 정의 키의 문서화 문자열 (이맥스 25)에서

DEF is anything that can be a key's definition: 
nil (means key is undefined in this keymap), 
a command (a Lisp function suitable for interactive calling), 
a string (treated as a keyboard macro), 
a keymap (to define a prefix key), 
a symbol (when the key is looked up, the symbol will stand for its 
    function definition, which should at that time be one of the above, 
    or another symbol whose function definition is used, etc.), 
a cons (STRING . DEFN), meaning that DEFN is the definition 
    (DEFN should be a valid definition in its own right), 
or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP, 
or an extended menu item definition. 
(See info node `(elisp)Extended Menu Items'.) 
관련 문제