Emacs desktop-save-mode和autoload冲突

问题: 开启desktop-save-mode之后, 连不上CLojure REPL, 提示

 
Key sequence C-c M-j starts with non-prefix key C-c
 

查看了一下cider的代码的确有下面的代码

 
;;;###autoload
(eval-after-load 'clojure-mode
  '(progn
     (define-key clojure-mode-map (kbd "C-c M-j") 'cider-jack-in)
     (define-key clojure-mode-map (kbd "C-c M-c") 'cider-connect)))
 

同时我自己也写了一个hook

 
(add-hook 'clojure-mode-hook
  (lambda ()
    (define-key clojure-mode-map "\C-c" 'kill-ring-save)
  )
)
 

但是让我不解的的, 没有开启desktop-save-mode也是同样的东西, 但是并没有问题.

猜测原因是谁先谁后的问题, hook先执行, 那么后面的define-key就会出现non prefix的错误, 但是如果eval-after-load先执行, 则没有此问题. 分别打开和关闭desktop-save-mode的情况下打印clojure-mode-map的内容如下

 
ELISP> clojure-map
*** Eval error ***  Symbol's value as variable is void: clojure-map
ELISP> clojure-mode-map
(keymap
 (3 . kill-ring-save) ; 开启desktop-save-mode
 (menu-bar keymap
           (Clojure menu-item "Clojure"
                    (keymap "Clojure"
                            (Toggle\ between\ string\ &\ keyword menu-item "Toggle between string & keyword" clojure-toggle-keyword-string)
                            (Mark\ string menu-item "Mark string" clojure-mark-string)
                            (Insert\ ns\ form\ at\ point menu-item "Insert ns form at point" clojure-insert-ns-form-at-point)
                            (Insert\ ns\ form\ at\ beginning menu-item "Insert ns form at beginning" clojure-insert-ns-form)
                            (Update\ ns\ form menu-item "Update ns form" clojure-update-ns)
                            (nil menu-item "--")
                            (Version menu-item "Version" clojure-mode-display-version))))
 (67108922 . clojure-toggle-keyword-string)
 keymap
 (27 keymap
     (17 . prog-indent-sexp)))
 
ELISP> (define-key clojure-mode-map (kbd "C-c M-j") 'cider-jack-in)
*** Eval error ***  Key sequence C-c M-j starts with non-prefix key C-c
ELISP> 
 
*** Welcome to IELM ***  Type (describe-mode) for help.
ELISP> clojure-mode-map
(keymap
 (3 keymap
    (27 keymap
        (99 . cider-connect) ; 关闭desktop-save-mode
        (106 . cider-jack-in)))
 (menu-bar keymap
           (Clojure menu-item "Clojure"
                    (keymap "Clojure"
                            (Toggle\ between\ string\ &\ keyword menu-item "Toggle between string & keyword" clojure-toggle-keyword-string)
                            (Mark\ string menu-item "Mark string" clojure-mark-string)
                            (Insert\ ns\ form\ at\ point menu-item "Insert ns form at point" clojure-insert-ns-form-at-point)
                            (Insert\ ns\ form\ at\ beginning menu-item "Insert ns form at beginning" clojure-insert-ns-form)
                            (Update\ ns\ form menu-item "Update ns form" clojure-update-ns)
                            (nil menu-item "--")
                            (Version menu-item "Version" clojure-mode-display-version))))
 (67108922 . clojure-toggle-keyword-string))
 
ELISP> 
 

eval-after-load add-hook的区别

eval-after-load只会执行一次, 而且时间上会不add-hook要早. 但是在开启desktop-save-mode只后, 可以看到add-hook是先执行了.

猜测, desktop-save-mode开启之后, 重启Emacs的时候, 会出现clojure-mode已经载入, 但是他的eval-after-load却还没有执行的情况. 在正常的情况下不会出现这种情况, 因为eval-after-load中代码是在载入clojure-mode之前执行的. 而且只会执行一次, 也就是说如果clojure-mode已载入, 那么eval-after-load的代码必然已经执行, 而且以后都不再执行.

没有开启desktop-save-mode的情况下, 启动Emacs之后, 执行cider-connect会导致载入clojure-mode, 从而触发eval-after-load, 但是并不会触发clojure-mode hook. 因为还没有buffer使用clojure-mode, REPL用的是cider-repl-mode.