2008.04.10 初版。
WordStar風のキーバインディングが好きなわけです。
ダイヤモンドカーソルとも呼ばれるアレです。
好きって言うほどのことはないか。でも、Windows流儀に比べてホームポジションから指が離れない分ずっと心地よいし、GNU Emacs流儀よりも操作しやすいと思う。
今はもうどこにも見かけなくなってしまったけど(MIFESか、VzをCUIウィンドウで使う場合くらい?)、ちょっとレトロにダイアモンドカーソルを実装してみようと思った。あ、ちなみにGNU Emacs(Meadow含む)を使う時はオリジナルのキーバインディングにしている。Xyzzyをいじったのは、GNU Emacs"風"ではあってもGNU Emacsじゃないしクローンでもないでしょ、だからいいよね、てな気持から。
XyzzyでVz風キーバインディングを実装した人もいて、ウェブで公開されていたけれど、何だか随分頑張っておられて、そのままお借りするのは難しそうだったので、全部自力で書いた。*1
といっても、「WordStarを完全に再現」という代物じゃない。大体WordStarの操作感を隅まで憶えているわけじゃないし。それどころか触ったこともそう多くはないし。WordStarっぽくダイアモンドカーソルを使えればいいので、Xyzzyの機能を呼び出せばいいところはそうしているし、Xyzzyの機能を殺すことはしていない。WordStarにはなかったであろう機能も入っている。無駄な引数があったり無駄なコードがあったりするのは愛敬と思って勘弁してください。
単語単位の移動(wss-next-word, wss-prev-word)はちょっと面倒なことをしている。解説も別ページ(XyzzyMovingByWord?)にあります。
; wss-diamond.l ; WorsStar-style key bindings.
; save C-x map and C-x map (global-set-key #\M-1 #'ctl-x-prefix) (global-set-key #\M-2 #'specific-command-prefix)
;;; single key operations (global-set-key #\C-e 'previous-virtual-line) (global-set-key #\C-x 'next-virtual-line) (global-set-key #\C-s 'backward-char) (global-set-key #\C-d 'forward-char) (global-set-key #\C-w 'wss-scroll-up) (global-set-key #\C-z 'wss-scroll-down)
(global-set-key #\C-r 'previous-page) (global-set-key #\C-c 'next-page) ; (global-set-key #\C-a 'previous-word) ; (global-set-key #\C-f 'next-word) (global-set-key #\C-a 'wss-prev-word) (global-set-key #\C-f 'wss-next-word)
(global-set-key #\C-g 'delete-char) (global-set-key #\C-t 'kill-word) (global-set-key #\C-y 'wss-yank-line)
(global-set-key #\C-l 'recenter) (global-set-key #\C-n 'wss-open-line)
; ^Pはput, paste. 行、単語、文字それぞれでバッファを持っていると ; いいのだが(VZとかPSEとかそうだった気がする)、Emacs系はそうでは ; ないので、ひとまとめ。 (global-set-key #\C-p 'wss-put)
(global-set-key #\C-v 'quote-char)
; アンドゥ、リドゥはデフォルトでC-\, C-_なのでそのままとする。 ; 前置引数はえげぇ便利なので活かすべし。 (global-set-key #\C-u 'universal-argument)
;; ^Q prefix... (global-set-key '(#\C-q #\C-e) 'wss-top-of-win) (global-set-key '(#\C-q #\C-x) 'wss-bot-of-win) (global-set-key '(#\C-q #\C-s) 'beginning-of-line) (global-set-key '(#\C-q #\C-d) 'end-of-line) (global-set-key '(#\C-q #\C-w) 'dup-lines)
(global-set-key '(#\C-q #\C-r) 'beginning-of-buffer) (global-set-key '(#\C-q #\C-c) 'end-of-buffer) (global-set-key '(#\C-q #\C-a) 'query-replace-regexp) (global-set-key '(#\C-q #\C-f) 'isearch-forward) (global-set-key '(#\C-q #\C-f) 'wss-search)
(global-set-key '(#\C-q #\C-g) 'wss-delete-to-eol) (global-set-key '(#\C-q #\C-h) 'wss-delete-to-bol) ; (global-set-key '(#\C-q #\C-t) 'kill-word) ; (global-set-key '(#\C-q #\C-y) 'wss-yank-line)
(global-set-key '(#\C-q #\C-v) 'toggle-read-only)
(global-set-key '(#\C-q #\C-j) 'goto-line) ; (global-set-key '(#\C-q #\C-j) 'goto-virtual-line) (global-set-key '(#\C-q #\C-]) 'goto-matched-parenthesis)
(global-set-key '(#\C-q #\C-l) 'eval-expression)
(global-set-key '(#\C-q #\C-q) 'quit)
;; ^K prefix... (global-set-key '(#\C-k #\C-n) 'new-file) (global-set-key '(#\C-k #\C-o) 'find-file) (global-set-key '(#\C-k #\C-s) 'save-buffer) (global-set-key '(#\C-k #\C-d) 'write-file) (global-set-key '(#\C-k #\C-r) 'find-file-read-only) (global-set-key '(#\C-k #\C-i) 'insert-file) (global-set-key '(#\C-k #\C-e) 'rename) (global-set-key '(#\C-k #\C-w) 'kill-buffer) (global-set-key '(#\C-k #\C-q) 'wss-exit-editor)
; (global-set-key '(#\C-k #\C-f) 'open-filer) (global-set-key '(#\C-k #\C-g) 'quit) (global-set-key '(#\C-k #\C-h) 'wss-split-window-toggle)
(global-set-key '(#\C-k #\C-j) 'previous-buffer) (global-set-key '(#\C-k #\C-k) 'next-buffer) (global-set-key '(#\C-k #\C-l) 'other-window)
(global-set-key '(#\C-k #\#) 'filter-buffer) (global-set-key '(#\C-k #\|) 'filter-region)
; リングバッファはWindowsのクリップボードと独立のようだ(Meadowと違う) ; クリップボードを使うようにしたい。。。 (global-set-key '(#\C-k #\C-b) 'set-mark-command) ; (global-set-key '(#\C-k #\C-x) 'kill-region) (global-set-key '(#\C-k #\C-x) 'kill-region-to-clipboard) ; (global-set-key '(#\C-k #\C-c) 'copy-region-as-kill) (global-set-key '(#\C-k #\C-c) 'copy-region-to-clipboard) ; (global-set-key '(#\C-k #\C-v) 'yank) (global-set-key '(#\C-k #\C-v) 'paste-from-clipboard)
; ウィンドウの最小化は特別扱い (global-set-key '(#\C-k #\C-z) 'minimize-window)
; ファイラーは特殊につきファンクションキーで起動 (global-set-key #\S-F1 'open-filer) ; 印刷も特殊につきファンクションキーで起動 (global-set-key #\S-F12 'print-selected-buffer-dialog)
;; マークとジャンプ ;; Vzは次のような感じだったと思うが(0~4くらいまで?)…… ; (global-set-key '(#\C-k #\0) 'set-mark-0) ; (global-set-key '(#\C-q #\0) 'jump-mark-0) ; (defun set-mark-0 () ; (interactive) ; (point-to-register 0)) ; ; (defun jump-mark-0 () ; (interactive) ; (jump-to-register 0)) ;; xyzzyではこちらの方が使い勝手がいいし、コマンドをやたらと増やすのも ;; 考えものなのでこうしとこう (global-set-key '(#\C-k #\C-m) 'point-to-register) (global-set-key '(#\C-q #\C-m) 'jump-to-register)
;;; ;;; WordStarスタイルを実現する関数群 ;;; ; カーソルは追随しないからあまり嬉しくないけど (defun wss-scroll-down (&optional arg) (interactive "p") (scroll-window 1))
(defun wss-scroll-up (&optional arg) (interactive "p") (scroll-window -1))
(defun wss-top-of-win () (interactive) (move-to-window-line 0))
(defun wss-bot-of-win () (interactive) (move-to-window-line -1))
(defun wss-search (&optional dir)
(interactive "p")
(if (null dir)
(isearch-forward)
(isearch-backward)))
(defun wss-yank-line () (interactive) (beginning-of-line) (kill-line 1))
(defun dup-lines (&optional n)
(interactive "p")
(if (not (typep n 'number))
(setq n 1))
(beginning-of-line)
(set-mark (point))
(next-line n)
(copy-region-as-kill (region-beginning) (region-end))
(yank-and-pop)
(previous-line))
;;
(defun wss-open-line (&optional n)
(interactive "p")
(if (not (typep n 'number))
(setq n 1))
(beginning-of-line)
(open-line n))
(defun wss-delete-to-bol () (interactive) (kill-line 0))
(defun wss-delete-to-eol () (interactive) (kill-line))
; 前置引数がなければ、キルリングから貼りつける。
; 前置引数があれば、キルリングからポップして貼りつける。
(defun wss-put (&optional n)
(interactive "p")
(if (not (typep n 'number))
(yank)
(yank-and-pop)))
; wss-split-window-toggle: ウィンドウ分割(トグル)
; フレーム上の現在のウィンドウの数が1なら分割、そうでなければ
; 他のウィンドウを削除。
(defun wss-split-window-toggle ()
(interactive)
(let ((wn (count-windows)))
(if (= wn 1)
(split-window)
(delete-other-windows)
)))
(defun wss-exit-editor ()
(interactive)
(if (y-or-n-p "Really quit xyzzy?: ")
(kill-xyzzy))
)
; 以下、「次の単語」と「前の単語」
(setq wss-word-re "\\([A-Za-z0-9]+\\|[!-/:-@[-`{-~]+\\|[ \t\n ]+\\|
[、-◯]+\\|[0-9a-zA-Z]+\\|[ぁ-んー]+\\|[ァ-ヶー]+\\|[亜-熙]+\\|
[Α-╂]+\\|[①-∪]+\\|[-]+\\)")
; wss-next-word
(defun wss-next-word (&optional dir)
(interactive "p")
(if (looking-at wss-word-re)
(let ((nchar (length (match-string 0))))
(if (= nchar 0)
(setq nchar 1))
(forward-char nchar)))
(if (< (point) (point-max))
(re-search-forward wss-word-re)))
; wss-prev-word
(defun wss-prev-word (&optional dir)
(interactive "p")
(save-restriction
(narrow-to-region (point-min) (point))
(goto-char (point-min))
(scan-buffer (format nil "~A\\'" wss-word-re)
:regexp t)))
; ウィンドウの最小化はWin32の力を借りなければならない (require "wip/winapi") (c:define-dll-entry winapi:BOOL ShowWindow (winapi:HWND c:int) "user32") (defun minimize-window () (interactive) (ShowWindow (get-window-handle) 6))
ここを参照しているページ
#related: relatedプラグインは廃止されました。