2013-10-11 2 views
3

emacs 24에서 set-temporary-overlay-map은 활성화 된 키맵을 사용자가 해당 키맵에 정의되지 않은 키를 누르면 바로 비활성화합니다.임시 오버레이 맵을 수동으로 종료

오버레이 키맵을 수동으로 비활성화해야하지만이 작업을 수행하는 기능은 제공되지 않습니다.

  1. 는 함수 clearfun, 모든 명령을하기 전에 실행하도록 정의 된 경우 확인하고 있습니다 : 나는 다음과 같이 현재 오버레이 키맵을 비활성화하는 메커니즘이 있음을 수집

    (defun set-temporary-overlay-map (map &optional keep-pred) 
        "Set MAP as a temporary keymap taking precedence over most other keymaps. 
    Note that this does NOT take precedence over the \"overriding\" maps 
    `overriding-terminal-local-map' and `overriding-local-map' (or the 
    `keymap' text property). Unlike those maps, if no match for a key is 
    found in MAP, the normal key lookup sequence then continues. 
    
    Normally, MAP is used only once. If the optional argument 
    KEEP-PRED is t, MAP stays active if a key from MAP is used. 
    KEEP-PRED can also be a function of no arguments: if it returns 
    non-nil then MAP stays active." 
        (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map")) 
         (overlaysym (make-symbol "t")) 
         (alist (list (cons overlaysym map))) 
         (clearfun 
          ;; FIXME: Use lexical-binding. 
          `(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))) 
           (set ',overlaysym nil) ;Just in case. 
           (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) 
        ;; FIXME: That's the keymaps with highest precedence, except for 
        ;; the `keymap' text-property ;-(
        (push alist emulation-mode-map-alists))) 
    

    : 나는 소스 코드에 살짝했습니다 이전에 호출 된 명령이 맵에있었습니다. 이지도에 아니었다면

  2. 은, 다음의 코드가 실행됩니다 :

(이유는 무엇입니까 제대로하지이 형식 좋아, 지금은 무엇입니까?) 내가 정말 이렇게

(set ',overlaysym nil) ;Just in case. 
       (remove-hook 'pre-command-hook ',clearfunsym) 
       (setq emulation-mode-map-alists 
        (delq ',alist emulation-mode-map-alists)) 

, 위의 코드를 적절한 변수와 함께 실행하는 것이 좋습니다. 그러나이 코드는 클로저의 일부이며 닫는 부분에 overlaysym, clearfunsym, alist 같은 값을 결정하는 데 문제가 있습니다. eval -ing pre-command-hook에 의해 clearfunsym을 찾으려고했으나 이상하게도 아무 것도 없습니다 (다른 관련없는 후크 제외).

나는 함수 정의를 다시 평가하고 에베 벅징을 시도했는데 (add-hook 'pre-command-hook clearfunsym) 이후에 pre-command-hook이 여전히 nil 인 퍼즐을 썼다. 앞으로도 계속해서 소스 코드를 파헤쳐 보겠다. 나중에이 함수를 내 자신의 버전으로 다시 작성하여 나중에 호출 할 수있는 force-clear 함수를 추가로 작성하지만 누군가가 더 깨끗한 솔루션을 볼 수있다.

+0

위대한 질문 (들). @Stefan (또는 누군가 다른 사람)의 흥미 있고 유익한 답변을 기대하십시오. 이것에 대해 더 많은 것을 배우기를 고대하고 있습니다. – Drew

+0

고마워요, 드류, 내가 실망 스럽긴하지만, 필자는 이맥스/엘프와 관련된 모든 질문에 대답 할 수 있다고 생각했다. 이제이 문제로 돌아가겠습니다. 나중에 표준 버전을 개선 할 수 있을지는 모르겠지만, 나중에 사용할 수있는'강제력 '을 제공하는 함수를 다시 작성할 것입니다. – erjoalgo

+0

"오버레이 키맵을 수동으로 비활성화해야합니다."라는 의미를 설명하십시오. – Stefan

답변

1

쓴 : "overlaysym 같은 값을 결정하는 데 문제가 있습니다" 하지만 overlaysym이 평가됩니다. 값은 (기호 "t")입니다. 이름이 t 인 심볼입니다. 이것은 접근하기 어렵지만 불가능하지는 않습니다. 다음 줄의 평가는 아웃 주석 결과를 제공합니다 :

(setq mysym (make-symbol "t")) 
;; t 
(set mysym 'test) 
;; test 
(symbol-value mysym) 
;; test 

동일 취소 - 임시 오버레이지도를 위해 평가하는 clearfunsym 적용됩니다.

덧글 1 개 더보기 : set-temporary-overlay-map을 디버깅 할 때 키를 치고 있습니다. 이러한 키 입력이 명확한 임시 오버레이 맵을 표시하고 사전 명령 훅 (pre-command hook)을 분명하게 호출 할 수 있습니까?

것을보십시오 :

(defadvice set-temporary-overlay-map (after test activate) 
    (setq test-pre-command-hook pre-command-hook)) 

그런 다음 텍스트 스케일 모드 (C- +)를 입력하고 테스트 사전 명령 훅 봐. 내 컴퓨터에서 test-pre-command-hook을 평가하면 다음 목록이 표시됩니다.

(clear-temporary-overlay-map tooltip-hide).

emulation-mode-map-alists과 동일하게 처리하겠습니다.그럼 우리가 얻을 :

(((t keymap (67108912 . #[0 "\301\302\300!!\207" [1 text-scale-adjust abs] 3 " 
... 

(fn)" nil]) (45 . #[0 "\301\302\300!!\207" [1 text-scale-adjust abs] 3 " 
(fn)" nil])))) 

특히, 처음에 t을 확인합니다. 즉 처음에는 t 기호로 목록을 검색하여 오버레이 맵을 찾습니다. 다음 코드 조각 같은

뭔가 오버레이 맵을 삭제하기에 충분해야한다 :

(when (assoc-string "t" (car emulation-mode-map-alists)) 
    (setq emulation-mode-map-alists (cdr emulation-mode-map-alists))) 

when은 보호이다. (아마도 다른지도가 전에지도를 죽인 적이 있습니까?) pushset-temporary-overlay-map에 있기 때문에 임시지도가 항상 앞에 있어야합니다. 어떤 것도 그 앞에 다른 키맵을 넣을 기회가 있습니까? 어쩌면, 시간 조절되는 뭔가? 그런 다음 (make-symbol "t") 키맵을 사용하여 알리 스트에 대해 emulation-mode-map-alists을 검색해야합니다.

+0

답장을 보내 주셔서 감사 드리며 미안합니다. 이전에 그것을 보지 마라. 해킹과 가독성을 없애기 위해이 함수를 다시 작성했다. 게다가 사용자에게 현재의 오버레이가 존재하면 그것을 지우는 좋은'force-overlay-clear'를 제공한다. – erjoalgo

0

원본 set-temporary-overlay-map은 매우 혼란스럽고 읽을 수 없으며 많은 불필요한 더러운 해킹과 트릭을 사용합니다. 어휘 바인딩을 사용하여 더 명확하고 모듈화 된 방식으로 함수를 다시 작성했습니다.

  1. 수정 된 기능은 eager-lazy 평가 해킹을 대체하기 위해 어휘 바인딩을 사용합니다 (이 경우 완전히 필요하지 않습니다).
  2. 원래 기능은 불필요하게 각 기능에 대한 두 개의 심볼들을 생성하고, 호출
  3. 가 조정 함수는 force-overlay-clear 제공 (clearfunsymclear-fun는 기본적으로 이상은 이전의 기능 셀로서 만 사용되는 똑같은이다) 조건이 충족 될 때 (즉, 마지막 키가 오버레이 맵에 없음) 사전 명령 후크 인 clear-temporary-overlay-map에 의해 수행됩니다. 이 맵을 수동으로 지우려면 사용자가 호출 할 수도 있습니다. 이 함수는 force-overlay-clear 자신의 함수 셀을 무효화하므로 두 번 호출하면 오류가 발생합니다.
  4. 명확한 지 여부를 테스트하는 코드는 단순화됩니다.

는 좀 다른 코드이 t 기호에 의존 할 수 있음을 두려워 멀리 매우 이상한 (overlaysym (make-symbol "t"))과 함께 할 수 없습니다. 따라서 수정 된 버전은 원래 버전과 거의 동일합니다. 나는 이것을 시험해 보았고, 잘 작동한다.

(defun set-temporary-overlay-map (map &optional keep-pred) 
    (lexical-let* (
    (map map) 
    (keep-pred keep-pred) 
    (clear-temporary-overlay-map nil) 
    (force-overlay-clear nil) 
    (overlaysym (make-symbol "t")) 
    (alist (list (cons overlaysym map)))) 

    (fset 'force-overlay-clear (lambda() 
      (message "clearing overlay")    
      ;this is a copy of the original code to clear 
      (set overlaysym nil) ;Just in case. 
      (remove-hook 'pre-command-hook 'clear-temporary-overlay-map) 
      (setq emulation-mode-map-alists 
      (delq alist emulation-mode-map-alists)) 
      ;void the function cell of 'force-overlay-clear', an attempt to clear overlay twice will err 
      (fset 'force-overlay-clear nil) 
    )) 
    (fset 'clear-temporary-overlay-map (lambda() 
      (unless (cond 
     ((null keep-pred) nil) 
     (keep-pred 
      (lookup-key map (this-command-keys-vector))) 
     (t (funcall keep-pred))) 
     (force-overlay-clear) 
    ))) 

    (set overlaysym overlaysym) 
    (add-hook 'pre-command-hook 'clear-temporary-overlay-map) 
    ;; FIXME: That's the keymaps with highest precedence, except for 
    ;; the `keymap' text-property ;- 
    (push alist emulation-mode-map-alists)) 
) 
+0

@Drew, Stefan 나는이 주제들에 대해 매우 적극적으로 활동하고있는 것을 보았으므로, 이것에 관해서 약간의 의견을 가지고있을 것이다. – erjoalgo

+0

'fset' 해당 심볼의 정의를 전역 적으로 변경하여 잘못 된 부분을 없애줍니다. bly는 두 개의'set-temporary-overlay-map'이 동시에 사용될 때 사용됩니다. – Stefan

0

는 다음과 같은 작업을 수행 할 수 있습니다

(defun my-exit-command() 
    (do-what-the-q-key-should-do)) 

....(set-temporary-overlay-map 
    my-overlay-map 
    (lambda() 
     (and (eq this-command (lookup-key my-overlay-map 
             (this-single-command-keys))) 
      (not (eq this-command 'my-exit-command))))) 
.... 
관련 문제