windows.elの設定で酷い落とし穴にはまった

(setq win:switch-prefix "\C-cw")
(define-key global-map win:switch-prefix nil)
(define-key global-map "\C-cw1" 'win-switch-to-window)
(require 'windows)
(win:startup-with-window)

としても,C-c w 1がwin-switch-to-windowになるだけでデフォルトのC-c C-wも生きてるし,設定が全く反映されない.
(setq win:switch-prefix "\C-cw")(defvar win:switch-prefix "\C-cw")にするとデフォルトの方が生きてるので,requireを先にしたような挙動になってる.
そこで,(require 'windows)の前に

(message (if (featurep 'windows) "yes" "no"))

として再起動してみると1回目はyes,2回目の再起動でnoに.そこで気が付いた.バイトコンパイル時に(require 'windows)が評価されるために評価順が変わっている.require前にsetq(defvar)する手のものは全て同じ問題があるはず.
正解はおそらくこう

(eval-and-compile
  (defvar win:switch-prefix "\C-cw"))
(require 'windows)
(win:startup-with-window)

でとりあえず動いた.
C-c コントロール文字はメジャーモードに予約されてるので使いたくないし,かといってC-c wだとC-c w C-rとかでControlを押したり離したりするのが面倒なので,C-zを潰そうかと思う.
デフォルトのC-zをC-z C-zに退避する所まで含めてとりあえずこうなった.

(eval-and-compile
  (progn
    (defvar win:switch-prefix "\C-z")
    (lexical-let ((command (lookup-key global-map win:switch-prefix)))
      (require 'windows)
      (define-key win:switch-map win:switch-prefix command))))

(setq win:use-frame nil) ; 新規にフレームを作らない
(win:startup-with-window)
(define-key ctl-x-map "C" 'see-you-again)

requireがコンパイル時にも評価されるのはトップレベルのときだけなので,一緒にeval-and-compileの中に突っ込んだ(警告消しのため).lexical-letとか初めて使ったけどこんなんでいいんだろうか.

まとめ

  1. 設定ファイルを(起動時,ロード前に)バイトコンパイルしている
  2. require前にdefvar(あるいはsetq)している

ときは

  • そのdefvarをeval-and-compileで囲う

これでOK?