Emacsでのmyvim-mode、その結果のガラパゴスインターフェース

およそユーザーエクスペリエンスとは全てはインターフェースの所与であり、Emacs/Vimユーザーにとってのインターフェースとはキーバインドに他ならない。


Emacsenならvimキーバインドにある種の利便性があることがわかっても、たかがそれだけの為に溜め込んだemacs lispを手放すのは辛いでしょう。
僕は小学生でドッジボールで小指を骨折して以来、小指がちゃんと動かないので、デフォルトのバインドには辛いものがあります。そこで、vimのようにノーマルモードを分離するマイナーモードを作ってみた。


myvim.el
前回晒した vls-modeとほとんど同じですが、機能は逆に絞ってあります


(require 'myvim)して'myvimするとviキーバインドで移動でき、iでインサートモードに入る。

myvim.elには最小限のモードしか持たせてなくて、およそあらゆる 'self-insert なキーを 'ignore してから hjkliをもたせただけ。
iでインサートモード(ただのemacsキーバインド)に入る。ノーマルモードに戻るのは C-g。


それだけ。しかしこれだけで大量のキーが自由になるのです。

どんどんひどくなるキーバインド

最初は

(define-key myvim-normal-map "v" 'set-mark-command)
(define-key myvim-normal-map "y" 'kill-ring-save)
(define-key myvim-normal-map "x" 'delete-char)

みたいにvimのコマンドの代替としてたんですが、途中からどんどん自由になり

(define-key myvim-normal-map "o" 'anything-c-yas-complete)
(define-key myvim-normal-map "m" 'anything-imenu)
(define-key myvim-normal-map "n" 'hs-toggle-hiding)
(define-key myvim-normal-map "," 'tabbar-backward-tab)
(define-key myvim-normal-map "." 'tabbar-forward-tab)

となっていった。ここらへんとか超怪しい

(define-key myvim-normal-map "1" 'delete-other-windows)
(define-key myvim-normal-map "2" 'hs-hide-all)
(define-key myvim-normal-map "3" 'hs-show-all)
(define-key myvim-normal-map "4" 'linum-mode)
(define-key myvim-normal-map "5" 'simple-hatena)
(define-key myvim-normal-map "6" "5\C-i\C-m\C-j\C-ti")
(define-key myvim-normal-map "7" "c6\C-j\C-y")
(define-key myvim-normal-map "8" 'howm-menu)
(define-key myvim-normal-map "9" 'navi2ch)


誰にでもおすすめできる構成じゃありませんが、自分が覚えられるならそれは便利なのです

だから

結局キーバインドなんて人それぞれに自由でいいんだよ!
そしてあらゆるエディタはあらゆるキーマップへのアクセスを提供すべきなんだってばよ!!!
そしてエディタの実力は、キーマッピングの自由度を提供した上での補完機能とか他インターフェースの抽象化にあると思います!!!


って anything-c-source-yas-completeで yasnipettのスニペット書きながら思った。


その点ではEclipseは決め打ちな部分が多くて好きになれない。
Textmateいいよね、日本語対応しないまま更新止まってるけど

自由にやりすぎた結果がこれだよ! keymap.el

Emacsノーマルモードを持たせた結果ver俺
大量のライブラリに依存しているのは適当に間引いてみてください。
キーバインドだけで設定ファイル300行あるし、やっぱりやりすぎたと思う。


(defun my-insert-super-pre-notation ()
  (interactive)
  (when (region-active-p)
    (let ((lang (completing-read "lang:" '("php" "python" "shellscript" "javascript" "lisp" "go" "scala" "groovy"))))
      (save-excursion
        (save-restriction
          (narrow-to-region (region-beginning) (region-end))
          (goto-char (region-beginning))
          (insert (concat ">|" lang "|\n"))
          (goto-char (point-max))
          (insert "||<")))
      (forward-line 1))))
(defun dired-my-advertised-find-file ()
  (interactive)
  (let ((kill-target (current-buffer))
        (check-file (dired-get-filename)))
    (funcall 'dired-advertised-find-file)
    (if (file-directory-p check-file)
        (kill-buffer kill-target))))
(defun dired-my-up-directory (&optional other-window)
  "Run dired on parent directory of current directory.
Find the parent directory either in this buffer or another buffer.
Creates a buffer if necessary."
  (interactive "P")
  (let* ((dir (dired-current-directory))
         (up (file-name-directory (directory-file-name dir))))
    (or (dired-goto-file (directory-file-name dir))
        ;; Only try dired-goto-subdir if buffer has more than one dir.
        (and (cdr dired-subdir-alist)
             (dired-goto-subdir up))
        (progn
          (if other-window
              (dired-other-window up)
            (progn
              (kill-buffer (current-buffer))
              (dired up))
          (dired-goto-file dir))))))
(defun reopen-file ()
  (interactive)
  (let ((file-name (buffer-file-name))
        (old-supersession-threat
         (symbol-function 'ask-user-about-supersession-threat))
        (point (point)))
    (when file-name
      (fset 'ask-user-about-supersession-threat (lambda (fn)))
      (unwind-protect
          (progn
            (erase-buffer)
            (insert-file file-name)
            (set-visited-file-modtime)
            (goto-char point))
        (fset 'ask-user-about-supersession-threat
              old-supersession-threat)))))
(defun my-open ()
  (interactive)
  (shell-command
   (concat "open " (buffer-name))
   )
  )

;;_____  meta-key ______

;;コマンドキーをsuperに
(when (eq system-type 'darwin)	     
  (setq mac-command-key-is-meta nil) ; コマンドキーをメタにしない
  (setq mac-option-modifier 'meta)   ; オプションキーをメタに
  (setq mac-command-modifier 'super) ; コマンドキーを Super に
  (setq mac-pass-control-to-system t)) ; コントロールキーを Mac ではなく Emacs に渡す

(require 'space-chord);;Spaceをメタキーに;;なんか動いてない
  
;; (setq default-input-method "MacOSX")
;; (mac-set-input-method-parameter "com.google.inputmethod.Japanese.base" `title "漢")

;;global-set-key
(global-set-key (kbd "C-;") 'anything)
(global-set-key "\C-cv" 'myvim)
(global-set-key "\C-xb" 'ibuffer-other-window)
(global-set-key "\C-x\C-b" 'ibuffer)

;; (global-set-key "\C-ct" 'multi-term)
;; (global-set-key "\C-cn" 'multi-term-next)
;; (global-set-key "\C-cp" 'multi-term-prev)
(global-set-key [(super right)] 'tabbar-forward-tab)
(global-set-key [(super left)] 'tabbar-backward-tab)
(global-set-key [(super up)] 'scroll-down)
(global-set-key [(super down)] 'scroll-up)
(global-set-key [(super o)] 'my-open)
(define-key global-map [165] nil)
(define-key global-map [67109029] nil)
(define-key global-map [134217893] nil)
(define-key global-map [201326757] nil)
(define-key function-key-map [165] [?\\])
(define-key function-key-map [67109029] [?\C-\\])
(define-key function-key-map [134217893] [?\M-\\])
(define-key function-key-map [201326757] [?\C-\M-\\])
(define-key global-map [C-return] 'other-window)
(global-set-key (kbd "C-c M-a") 'align-regexp)
(global-set-key (kbd "C-h")     'backward-delete-char)
(global-set-key (kbd "C-c d")   'delete-indentation)
(global-set-key (kbd "M-g")     'goto-line)
(global-set-key (kbd "C-S-i")   'indent-region)
(global-set-key (kbd "C-m")     'newline-and-indent)
(global-set-key (kbd "C-t")     'next-multiframe-window)
(global-set-key (kbd "M-<RET>") 'ns-toggle-fullscreen)
(global-set-key (kbd "C-S-t")   'previous-multiframe-window)
(global-set-key (kbd "C-v")     'myvim)

;;dired
(define-key dired-mode-map "p" 'dired-my-up-directory)
(define-key dired-mode-map "j" 'next-line)
(define-key dired-mode-map "k" 'previous-line)
(define-key dired-mode-map "\C-h" 'tabbar-backward-tab)
(define-key dired-mode-map "\C-l" 'tabbar-forward-tab)
(define-key dired-mode-map "," 'tabbar-backward-tab)
(define-key dired-mode-map "." 'tabbar-forward-tab)

(define-key dired-mode-map "\C-m" 'dired-my-advertised-find-file)
(define-key dired-mode-map "^" 'dired-my-up-directory)

;;undo-tree-visualize-map
(define-key undo-tree-visualizer-map "j" 'next-line)
(define-key undo-tree-visualizer-map "k" 'previous-line)
(define-key undo-tree-visualizer-map "h" 'undo-tree-visualize-switch-branch-left)
(define-key undo-tree-visualizer-map "l" 'undo-tree-visualize-switch-branch-)
(define-key undo-tree-visualizer-map "o" 'other-window)
(define-key undo-tree-visualizer-map "q" 'undo-tree-visualizer-quit)

;;ファイルを開き直す
(define-key ctl-x-map "\C-r"  'reopen-file)

;;anything
(define-key anything-map (kbd "C-k") 'anything-previous-line)
(define-key anything-map (kbd "C-j") 'anything-next-line)
(define-key anything-map (kbd "C-n") 'anything-next-source)
(define-key anything-map (kbd "M-p") 'anything-previous-source)
(define-key anything-map (kbd "C-o") 'anything-mark-current-line)
(global-set-key (kbd "M-s") 'anything-c-moccur-occur-by-moccur) ;バッファ内検索
(global-set-key (kbd "M-d") 'anything-c-moccur-dmoccur) ;ディレクトリ


;;simple-hatena
(define-key simple-hatena-mode-map "\C-t" 'simple-hatena-timestamp)
(define-key simple-hatena-mode-map "\C-p" 'my-insert-super-pre-notation)

;;multi-term

(add-hook 'term-mode-hook '(lambda ()
			(define-key term-raw-map "\C-y" 'term-paste)			     
			(define-key term-raw-map "\C-q" 'move-beginning-of-line)
			(define-key term-raw-map "\C-f" 'forward-char)
			(define-key term-raw-map "\C-b" 'backward-char)			     
			(define-key term-raw-map (kbd "C-h") 'term-send-backspace)
			(define-key term-raw-map "\C-t" 'set-mark-command)			     
			(define-key term-raw-map (kbd "ESC") 'term-send-raw)
			(define-key term-raw-map "\C-h" 'term-send-raw)
			(lookup-key (current-global-map) "\C-z")))
;; (define-key term-raw-map "\C-x\C-s" 'term-send-raw)
;; (define-key term-raw-map "\C-x\C-f" 'term-send-raw)
;; (define-key term-raw-map "\C-x\C-c" 'term-send-raw)
;; (define-key term-raw-map "\M-x" 'term-send-raw)
;; (define-key term-raw-map [delete] 'term-send-raw)

;;org-mode
(define-key org-mode-map [C-return] 'other-window)
(define-key org-mode-map "\C-p" 'org-export-as-html-and-open)
(define-key org-mode-map [(super p)] 'org-export-as-html-and-open)
;; (define-key org-mode-map [(super 1)] "*")
;; (define-key org-mode-map [(super 2)] "**")
;; (define-key org-mode-map [(super 3)] "***")
;; (define-key org-mode-map [(super 4)] "****")

;   myvim [ normal - insert ] 
;==============================================
;;myvim-normal-mode
(define-key myvim-normal-map "i" 'myvim-insert)
(define-key myvim-normal-map "h" 'backward-char) 
(define-key myvim-normal-map "j" 'next-line)
(define-key myvim-normal-map "k" 'previous-line)
(define-key myvim-normal-map "l" 'forward-char)
(define-key myvim-normal-map "g" 'beginning-of-buffer)
(define-key myvim-normal-map "G" 'end-of-buffer)
(define-key myvim-normal-map "y" 'yank)
(define-key myvim-normal-map "d" 'kill-whole-line)
(define-key myvim-normal-map "/" 're-search-forward)
(define-key myvim-normal-map "?" 're-search-backward)
(define-key myvim-normal-map "!" 'shell-command)
(define-key myvim-normal-map "a" "li")
(define-key myvim-normal-map "f" 'find-file )
(define-key myvim-normal-map "T" 'multi-term-next)
(define-key myvim-normal-map "x" 'delete-char)
(define-key myvim-normal-map "X" 'backward-kill-word)
(define-key myvim-normal-map "u" 'undo)
(define-key myvim-normal-map "U" 'undo-tree-visualize)
(define-key myvim-normal-map "o" 'anything-c-yas-complete)
(define-key myvim-normal-map "n" 'hs-toggle-hiding)
(define-key myvim-normal-map "w" 'backward-word) 
(define-key myvim-normal-map "e" 'forward-word)
(define-key myvim-normal-map "P" "\C-x\C-f\C-m")
(define-key myvim-normal-map "m" 'anything-imenu)
(define-key myvim-normal-map "o" 'anything-c-yas-complete)
(define-key myvim-normal-map "v" 'set-mark-command)
(define-key myvim-normal-map "c" 'kill-ring-save)
(define-key myvim-normal-map "x" 'delete-char)
(define-key myvim-normal-map "b" 'multi-term-dedicated-toggle)
(define-key myvim-normal-map "t" 'anything)
(define-key myvim-normal-map ":" 'execute-extended-command) 
(define-key myvim-normal-map ";" 'comment-dwim)
(define-key myvim-normal-map "J" "j\C-a\C-i")
(define-key myvim-normal-map "K" "k\C-a\C-i")
(define-key myvim-normal-map "R" 'replace-regexp)
(define-key myvim-normal-map "\M-r" 'dmoccur)
(define-key myvim-normal-map "s" 'save-buffer)
(define-key myvim-normal-map "S" 'hs-show-all)
(define-key myvim-normal-map "H" 'hs-hide-all)
(define-key myvim-normal-map "\C-d" 'kill-this-buffer)
(define-key myvim-normal-map "0" 'save-buffer)
(define-key myvim-normal-map "?" 'describe-bindings)
(define-key myvim-normal-map "," 'tabbar-backward-tab)
(define-key myvim-normal-map "." 'tabbar-forward-tab)
(define-key myvim-normal-map " " 'anything)
(define-key myvim-normal-map "1" 'delete-other-windows)
(define-key myvim-normal-map "2" 'hs-hide-all)
(define-key myvim-normal-map "3" 'hs-show-all)
(define-key myvim-normal-map "4" 'linum-mode)
(define-key myvim-normal-map "5" 'simple-hatena)
(define-key myvim-normal-map "6" "5\C-i\C-m\C-j\C-ti")
(define-key myvim-normal-map "7" "c6\C-j\C-y")
(define-key myvim-normal-map "8" "\C-c,,")

;; with-meta-key
(define-key myvim-normal-map [C-return] 'other-window)
(define-key myvim-normal-map "\C-h" 'tabbar-backward-tab)
(define-key myvim-normal-map "\C-l" 'tabbar-forward-tab)
(define-key myvim-normal-map "\C-g" 'keyboard-quit)
(define-key myvim-normal-map "\C-d" "\C-v")
(define-key myvim-normal-map "\C-u" "\M-v")
(define-key myvim-normal-map "\C-cn" 'multi-term-next)
(define-key myvim-normal-map "\C-z" 'myvim-sleep)
(define-key myvim-normal-map "\M-e" 'eval-region)
(define-key myvim-normal-map "\M-b" "\C-xrm")
(define-key myvim-normal-map "\M-y" 'anything-show-kill-ring)
(define-key myvim-normal-map "\M-h" 'scroll-down)
(define-key myvim-normal-map "\M-l" 'scroll-up) 
(define-key myvim-normal-map "\M-i" 'zencoding-expand-yas) 
(define-key myvim-normal-map "z" 'e2wm:dp-code-main-maximize-toggle-command)
(define-key myvim-normal-map "\M-z" 'ewm:start-management)

;; ______________ myvim-insert-map
(define-key myvim-insert-map [C-return] 'myvim-normal)
(define-key myvim-insert-map "\C-g"     'myvim-normal) 
(define-key myvim-insert-map "\C-h" 'delete-backward-char)
(define-key myvim-insert-map "\M-h" 'backward-kill-word)
(define-key myvim-insert-map "\C-o" 'anything-c-yas-complete)
(define-key myvim-insert-map "\M-o" 'yas/expand)
(define-key myvim-insert-map "\C-d" 'backward-delete-char-untabify)
(define-key myvim-insert-map "\C-v" "\C-gv")

;; shortcut inputs
(define-key myvim-insert-map "\C-r" " = ")
(define-key myvim-insert-map "\C-q" "''\C-b")
(define-key myvim-insert-map "\C-w" "()\C-b")
(define-key myvim-insert-map "\M-w" "''\C-b")
(define-key myvim-insert-map [(super q)] "''\C-b")
(define-key myvim-insert-map [(super e)] " = ")
(define-key myvim-insert-map [(super s)] " = ''\C-b")

;;default-tab-width
;;myvim-sleep-mode-map
;;========================================================
(define-key myvim-sleep-map "\C-z" 'myvim-normal)