Add emacs directory

git-svn-id: http://photonzero.com/dotfiles/trunk@54 23f722f6-122a-0410-8cef-c75bd312dd78
This commit is contained in:
michener 2010-08-12 01:19:45 +00:00
parent e50f8f4bc8
commit 5b6729933d
100 changed files with 37586 additions and 0 deletions

Binary file not shown.

View file

@ -0,0 +1 @@
default

View file

@ -0,0 +1,2 @@
9c9e1bf0c4a2ed90304bab5e7b00bbbe23ea1fe7 286
9c9e1bf0c4a2ed90304bab5e7b00bbbe23ea1fe7 default

Binary file not shown.

View file

@ -0,0 +1,2 @@
[paths]
default = http://bitbucket.org/lyro/vim-mode

View file

@ -0,0 +1,3 @@
revlogv1
store
fncache

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,22 @@
data/.hgignore.i
data/.hgtags.i
data/vim-combat.el.i
data/vim-commands.el.i
data/vim-compat.el.i
data/vim-ex-commands.el.i
data/vim-ex.el.i
data/vim-insert-mode.el.i
data/vim-keymap.el.i
data/vim-keys.el.i
data/vim-maps.el.i
data/vim-modes.el.i
data/vim-motions.el.i
data/vim-node.el.i
data/vim-normal-mode.el.i
data/vim-scroll.el.i
data/vim-search.el.i
data/vim-undo.el.i
data/vim-vim.el.i
data/vim-visual-mode.el.i
data/vim-window.el.i
data/vim.el.i

Binary file not shown.

View file

@ -0,0 +1,5 @@
286 9c9e1bf0c4a2ed90304bab5e7b00bbbe23ea1fe7 e20b66a15626ce3c3dedc3de035c0d65915f1159
1f59539819aa706d915e97ecdf7a513d1e5e664e v0.1
9c22feb593237c76560cfc1b817c2ece500e6ac9 v0.2
15dff001f097be2ffc0b717edb7fd019a36e407a v0.3

View file

@ -0,0 +1 @@
default

View file

View file

@ -0,0 +1,2 @@
~$
\.elc$

View file

@ -0,0 +1,3 @@
1f59539819aa706d915e97ecdf7a513d1e5e664e v0.1
9c22feb593237c76560cfc1b817c2ece500e6ac9 v0.2
15dff001f097be2ffc0b717edb7fd019a36e407a v0.3

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
;;; vim-ex-commands.el - Implementation of some ex-mode commands.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Code:
(defun* vim:save-buffer (file-name &key begin end mustbenew append)
"Saves the lines from `begin' to `end' to file `file-name'."
(with-current-buffer vim:ex-current-buffer
(when (null file-name)
(setq file-name (buffer-file-name))
(unless file-name
(error "Please specify a file-name for this buffer!")))
(let (beg-pos end-pos)
(when begin
(setq beg-pos (save-excursion
(goto-line begin)
(line-beginning-position)))
(setq end-pos (if end
(save-excursion
(goto-line end)
(line-end-position))
beg-pos)))
(cond
((and (null beg-pos)
(string= file-name (buffer-file-name)))
(save-buffer))
((and (null beg-pos)
(null (buffer-file-name)))
(write-file file-name))
(t
(write-region beg-pos end-pos file-name append nil nil mustbenew))))))
(vim:defcmd vim:cmd-write (motion (argument:file file) nonrepeatable)
"Saves file `file'."
(vim:save-buffer file
:begin (and motion (vim:motion-first-line motion))
:end (and motion (vim:motion-last-line motion))
:mustbenew t))
(vim:defcmd vim:cmd-write-q (motion (argument:file file) nonrepeatable)
"Overwrites file `file'."
(vim:save-buffer file
:begin (and motion (vim:motion-first-line motion))
:end (and motion (vim:motion-last-line motion))
:mustbenew nil))
(vim:defcmd vim:cmd-write-all (nonrepeatable)
"Saves all buffers."
(save-some-buffers nil))
(vim:defcmd vim:cmd-write-all-q (nonrepeatable)
"Overwrites all buffers."
(save-some-buffers t))
(vim:defcmd vim:cmd-edit ((argument:file file) nonrepeatable)
"Visits a certain file."
(if file
(find-file file)
(when (buffer-file-name)
(find-file (buffer-file-name)))))
(vim:defcmd vim:cmd-buffer ((argument:buffer buffer) nonrepeatable)
"Switches to another buffer."
(if buffer
(when (or (get-buffer buffer)
(y-or-n-p (format "No buffer with name \"%s\" exists. Create new buffer? " buffer)))
(switch-to-buffer buffer))
(switch-to-buffer (other-buffer))))
(vim:defcmd vim:cmd-delete-buffer ((argument:buffer buffer) nonrepeatable)
"Deletes a buffer."
(kill-buffer buffer))
(vim:defcmd vim:cmd-delete-buffer-q ((argument:buffer buffer) nonrepeatable)
"Deletes a buffer without saving."
(if buffer
(with-current-buffer buffer
(set-buffer-modified-p nil))
(set-buffer-modified-p nil))
(kill-buffer buffer))
(vim:defcmd vim:cmd-quit (nonrepeatable)
"Closes the current window, exits Emacs if this is the last window."
(condition-case nil
(delete-window)
(error
(condition-case nil
(delete-frame)
(error (save-buffers-kill-emacs))))))
(vim:defcmd vim:cmd-quit-q (nonrepeatable)
"Closes the current window, exits Emacs if this is the last window."
(condition-case nil
(delete-window)
(error
(condition-case nil
(delete-frame)
(error (kill-emacs))))))
(vim:defcmd vim:cmd-quit-all (nonrepeatable)
"Exits Emacs, asking for saving."
(save-buffers-kill-emacs))
(vim:defcmd vim:cmd-quit-all-q (nonrepeatable)
"Exits Emacs, without saving."
(kill-emacs))
(vim:defcmd vim:cmd-save-and-quit (nonrepeatable)
"Exits Emacs, without saving."
(save-buffers-kill-emacs 1))
(vim:defcmd vim:cmd-save-and-close ((argument:file file) nonrepeatable)
"Saves the current buffer and closes the window."
(vim:cmd-write :argument file)
(vim:cmd-quit))
(vim:defcmd vim:cmd-save-and-close-q ((argument:file file) nonrepeatable)
"Saves the current buffer and closes the window."
(vim:cmd-write-q :argument file)
(vim:cmd-quit))
(provide 'vim-ex-commands)
;;; vim-ex-commands.el ends here

440
.emacs.d/vim-mode/vim-ex.el Normal file
View file

@ -0,0 +1,440 @@
;;; vim-ex.el - Ex-mode.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Code:
(defvar vim:ex-commands nil
"List of pairs (command . function).")
(defvar vim:ex-current-buffer)
(vim:deflocalvar vim:ex-local-commands nil
"List of pairs (command . function).")
(defvar vim:ex-history nil
"History of ex-commands.")
(defun vim:emap (keys command)
"Maps an ex-command to some function."
(unless (find-if #'(lambda (x) (string= (car x) keys)) vim:ex-commands)
(add-to-list 'vim:ex-commands (cons keys command))))
(defun vim:local-emap (keys command)
"Maps an ex-command to some function buffer-local."
(unless (find-if #'(lambda (x) (string= (car x) keys)) vim:ex-local-commands)
(add-to-list 'vim:ex-local-commands (cons keys command))))
(defun vim:ex-binding (cmd)
"Returns the current binding of `cmd' or nil."
(with-current-buffer vim:ex-current-buffer
(or (cdr-safe (assoc cmd vim:ex-local-commands))
(cdr-safe (assoc cmd vim:ex-commands)))))
(defvar vim:ex-keymap (make-sparse-keymap)
"Keymap used in ex-mode.")
(define-key vim:ex-keymap "\t" 'minibuffer-complete)
(define-key vim:ex-keymap [return] 'exit-minibuffer)
(define-key vim:ex-keymap (kbd "RET") 'exit-minibuffer)
(define-key vim:ex-keymap " " 'vim:ex-expect-argument)
(define-key vim:ex-keymap (kbd "C-j") 'vim:ex-execute-command)
(define-key vim:ex-keymap (kbd "C-g") 'abort-recursive-edit)
(define-key vim:ex-keymap [up] 'previous-history-element)
(define-key vim:ex-keymap [down] 'next-history-element)
(define-key vim:ex-keymap "\d" 'vim:ex-delete-backward-char)
(defun vim:ex-delete-backward-char (n)
"Delete the previous `n' characters. If ex-buffer is empty,
cancel ex-mode."
(interactive "p")
(if (and (>= n 1)
(zerop (length (minibuffer-contents))))
(exit-minibuffer))
(delete-backward-char n))
(defvar vim:ex-keep-reading nil)
(defvar vim:ex-cmdline nil)
(defvar vim:ex-cmd nil)
(defvar vim:ex-beg nil)
(defvar vim:ex-end nil)
(defun vim:ex-split-cmdline (cmdline)
(multiple-value-bind (cmd-region beg end) (vim:ex-parse cmdline)
(if (null cmd-region)
(values cmdline "" cmdline "" beg end)
(let ((range (substring cmdline 0 (car cmd-region)))
(cmd (substring cmdline (car cmd-region) (cdr cmd-region)))
(spaces "")
(arg (substring cmdline (cdr cmd-region))))
;; skip whitespaces
(when (string-match "\\`\\s-*" arg)
(setq spaces (match-string 0 arg)
arg (substring arg (match-end 0))))
(values range cmd spaces arg beg end)))))
(defun vim:ex-expect-argument (n)
;; called if the space separating the command from the argument has
;; been pressed
(interactive "p")
(let ((cmdline (vim:minibuffer-contents)))
(self-insert-command n)
(multiple-value-bind (range cmd spaces arg beg end) (vim:ex-split-cmdline cmdline)
(when (and (= (point) (point-max))
(zerop (length spaces))
(zerop (length arg)))
(while (stringp cmd)
(setq cmd (vim:ex-binding cmd)))
(if (null cmd) (ding)
(let ((result (case (vim:cmd-arg cmd)
(file
(vim:ex-complete-file-argument nil nil nil))
(buffer
(vim:ex-complete-buffer-argument nil nil nil))
((t)
(vim:ex-complete-text-argument nil nil nil)))))
(when result (insert result))))))))
(defun vim:ex-complete (cmdline predicate flag)
(multiple-value-bind (range cmd spaces arg beg end) (vim:ex-split-cmdline cmdline)
(setq vim:ex-cmd cmd)
(cond
;; only complete at the end of the command
((< (point) (point-max)) nil)
;; if at the end of a command, complete the command
((and (zerop (length spaces)) (zerop (length arg)))
(let ((result (vim:ex-complete-command cmd predicate flag)))
(cond
((null result) nil)
((eq t result) t)
((stringp result)
(if flag result (concat range result)))
((listp result) (if flag result (mapcar #'(lambda (x) (concat range x)) result)))
(t (error "Completion returned unexpected value.")))))
;; otherwise complete the argument
(t
(let ((result (vim:ex-complete-argument arg predicate flag)))
(cond
((null result) nil)
((eq t result) t)
((stringp result) (if flag result (concat range cmd spaces result)))
((listp result) (if flag result (mapcar #'(lambda (x) (concat range cmd spaces x)) result)))
(t (error "Completion returned unexpected value."))))))))
(defun vim:ex-complete-command (cmd predicate flag)
;; completes the command
(with-current-buffer vim:ex-current-buffer
(cond
((null flag) (or (try-completion cmd vim:ex-local-commands predicate)
(try-completion cmd vim:ex-commands predicate)))
((eq t flag) (or (all-completions cmd vim:ex-local-commands predicate)
(all-completions cmd vim:ex-commands predicate)))
((eq 'lambda flag) (or (vim:test-completion cmd vim:ex-local-commands predicate)
(vim:test-completion cmd vim:ex-commands predicate))))))
(defun vim:ex-complete-argument (arg predicate flag)
;; completes the argument
(let ((cmd vim:ex-cmd))
(while (stringp cmd)
(setq cmd (vim:ex-binding cmd)))
(if (null cmd) (ding)
(case (vim:cmd-arg cmd)
(file
(vim:ex-complete-file-argument arg predicate flag))
(buffer
(vim:ex-complete-buffer-argument arg predicate flag))
((t)
(vim:ex-complete-text-argument arg predicate flag))
(t (ding))))))
(defun vim:ex-complete-file-argument (arg predicate flag)
;; completes a file-name
(if (null arg)
default-directory
(let ((dir (or (file-name-directory arg)
(with-current-buffer vim:ex-current-buffer default-directory)))
(fname (file-name-nondirectory arg)))
(cond
((null dir) (ding))
((null flag)
(let ((result (file-name-completion fname dir)))
(case result
((nil) nil)
((t) t)
(t (concat dir result)))))
((eq t flag)
(file-name-all-completions fname dir))
((eq 'lambda flag)
(eq (file-name-completion fname dir) t))))))
(defun vim:ex-complete-buffer-argument (arg predicate flag)
;; completes a buffer name
(when arg
(let ((buffers (mapcar #'(lambda (buffer) (cons (buffer-name buffer) nil)) (buffer-list t))))
(cond
((null flag)
(try-completion arg buffers predicate))
((eq t flag)
(all-completions arg buffers predicate))
((eq 'lambda flag)
(vim:test-completion arg buffers predicate))))))
(defun vim:ex-complete-text-argument (arg predicate flag)
;; completes an arbitrary text-argument
(when arg
(case flag
((nil) t)
((t) (list arg))
('lambda t))))
(defun vim:ex-execute-command (cmdline)
(interactive)
(multiple-value-bind (range cmd spaces arg beg end) (vim:ex-split-cmdline cmdline)
(setq vim:ex-cmd cmd)
(let ((cmd vim:ex-cmd)
(motion (cond
((and beg end)
(vim:make-motion :begin (save-excursion
(goto-line beg)
(line-beginning-position))
:end (save-excursion
(goto-line end)
(line-beginning-position))
:has-begin t
:type 'linewise))
(beg
(vim:make-motion :begin (save-excursion
(goto-line beg)
(line-beginning-position))
:end (save-excursion
(goto-line beg)
(line-beginning-position))
:has-begin t
:type 'linewise))))
(count (and (not end) beg)))
(while (stringp cmd)
(setq cmd (vim:ex-binding cmd)))
(when (zerop (length arg))
(setq arg nil))
(with-current-buffer vim:ex-current-buffer
(cond
(cmd (case (vim:cmd-type cmd)
('complex
(if (vim:cmd-arg-p cmd)
(funcall cmd :motion motion :argument arg)
(funcall cmd :motion motion)))
('simple
(when end
(error "Command does not take a range: %s" vim:ex-cmd))
(if (vim:cmd-arg-p cmd)
(if (vim:cmd-count-p cmd)
(funcall cmd :count beg :argument arg)
(funcall cmd :argument arg))
(if (vim:cmd-count-p cmd)
(funcall cmd :count count)
(funcall cmd))))
(t (error "Unexpected command-type bound to %s" vim:ex-cmd))))
(beg (vim:motion-go-to-first-non-blank-beg :count (or end beg)))
(t (ding)))))))
;; parser for ex-commands
(defun vim:ex-parse (text)
"Extracts the range-information from `text'.
Returns a list of up to three elements: (cmd beg end)"
(let (begin
(begin-off 0)
sep
end
(end-off 0)
(pos 0)
(cmd nil))
(multiple-value-bind (beg npos) (vim:ex-parse-address text pos)
(when npos
(setq begin beg
pos npos)))
(multiple-value-bind (off npos) (vim:ex-parse-offset text pos)
(when npos
(unless begin (setq begin 'current-line))
(setq begin-off off
pos npos)))
(when (and (< pos (length text))
(or (= (aref text pos) ?\,)
(= (aref text pos) ?\;)))
(setq sep (aref text pos))
(incf pos)
(multiple-value-bind (e npos) (vim:ex-parse-address text pos)
(when npos
(setq end e
pos npos)))
(multiple-value-bind (off npos) (vim:ex-parse-offset text pos)
(when npos
(unless end (setq end 'current-line))
(setq end-off off
pos npos))))
;; handle the special '%' range
(when (or (eq begin 'all) (eq end 'all))
(setq begin 'first-line
begin-off 0
end 'last-line
end-off 0
sep ?,))
(when (= pos (or (string-match "[a-zA-Z0-9!]+" text pos) -1))
(setq cmd (cons (match-beginning 0) (match-end 0))))
(multiple-value-bind (start end) (vim:ex-get-range (and begin (cons begin begin-off)) sep (and end (cons end end-off)))
(values cmd start end))))
(defun vim:ex-parse-address (text pos)
(cond
((>= pos (length text)) nil)
((= pos (or (string-match "[0-9]+" text pos) -1))
(values (cons 'abs (string-to-number (match-string 0 text)))
(match-end 0)))
((= (aref text pos) ?$)
(values (cons 'abs (line-number-at-pos (point-max))) (1+ pos)))
((= (aref text pos) ?\%)
(values 'all (1+ pos)))
((= (aref text pos) ?.)
(values 'current-line (1+ pos)))
((= (aref text pos) ?')
(if (>= (1+ pos) (length text))
nil
(values `(mark ,(aref text (1+ pos))) (+ 2 pos))))
((= (aref text pos) ?/)
(when (string-match "\\([^/]+\\|\\\\.\\)\\(?:/\\|$\\)"
text (1+ pos))
(values (cons 're-fwd (match-string 1 text))
(match-end 0))))
((= (aref text pos) ??)
(when (string-match "\\([^?]+\\|\\\\.\\)\\(?:?\\|$\\)"
text (1+ pos))
(values (cons 're-bwd (match-string 1 text))
(match-end 0))))
((and (= (aref text pos) ?\\)
(< pos (1- (length text))))
(case (aref text (1+ pos))
(?/ (values 'next-of-prev-search (1+ pos)))
(?? (values 'prev-of-prev-search (1+ pos)))
(?& (values 'next-of-prev-subst (1+ pos)))))
(t nil)))
(defun vim:ex-parse-offset (text pos)
(let ((off nil))
(while (= pos (or (string-match "\\([-+]\\)\\([0-9]+\\)?" text pos) -1))
(if (string= (match-string 1 text) "+")
(setq off (+ (or off 0) (if (match-beginning 2)
(string-to-number (match-string 2 text))
1)))
(setq off (- (or off 0) (if (match-beginning 2)
(string-to-number (match-string 2 text))
1))))
(setq pos (match-end 0)))
(and off (values off pos))))
(defun vim:ex-get-range (start sep end)
(with-current-buffer vim:ex-current-buffer
(when start
(setq start (vim:ex-get-line start)))
(when (and sep end)
(save-excursion
(when (= sep ?\;) (goto-line start))
(setq end (vim:ex-get-line end))))
(values start end)))
(defun vim:ex-get-line (address)
(let ((base (car address))
(offset (cdr address)))
(cond
((null base) nil)
((consp offset)
(let ((line (vim:ex-get-line (car address))))
(when line
(save-excursion
(goto-line line)
(vim:ex-get-line (cdr address))))))
(t
(+ offset
(case (or (car-safe base) base)
(abs (cdr base))
;; TODO: (1- ...) may be wrong if the match is the empty string
(re-fwd (save-excursion
(beginning-of-line 2)
(and (re-search-forward (cdr base))
(line-number-at-pos (1- (match-end 0))))))
(re-bwd (save-excursion
(beginning-of-line 0)
(and (re-search-backward (cdr base))
(line-number-at-pos (match-beginning 0)))))
(current-line (line-number-at-pos (point)))
(first-line (line-number-at-pos (point-min)))
(last-line (line-number-at-pos (point-max)))
(mark (line-number-at-pos (vim:get-local-mark (cadr base))))
(next-of-prev-search (error "Next-of-prev-search not yet implemented."))
(prev-of-prev-search (error "Prev-of-prev-search not yet implemented."))
(next-of-prev-subst (error "Next-of-prev-subst not yet implemented."))
(t (error "Invalid address: %s" address))))))))
(defun vim:ex-read-command (&optional initial-input)
"Starts ex-mode."
(interactive)
(let ((vim:ex-current-buffer (current-buffer)))
(let ((minibuffer-local-completion-map vim:ex-keymap))
(let ((result (completing-read ":" 'vim:ex-complete nil nil initial-input 'vim:ex-history)))
(when (and result
(not (zerop (length result))))
(vim:ex-execute-command result))))))
(provide 'vim-ex)
;;; vim-ex.el ends here

View file

@ -0,0 +1,79 @@
;;; vim-insert-mode.el - VIM insert-mode.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; TODO :
;; - for some reason GNU Emacs does not show '-- REPLACE --'
;;; Code:
(vim:deflocalvar vim:last-insert-undo nil)
(defcustom vim:insert-mode-replace-cursor 'hbar
"Cursor for replace-mode."
:group 'vim-mode)
(vim:define-keymap insert-mode "insert-mode" :map-command imap)
(vim:define-mode insert "VIM insert-mode"
:ident "I"
:message "-- INSERT --"
:keymaps '(vim:insert-mode-keymap)
:command-function 'vim:insert-mode-command
:cursor 'bar)
(add-hook 'vim:insert-mode-on-hook 'vim:insert-mode-activated)
(add-hook 'vim:insert-mode-off-hook 'vim:insert-mode-deactivated)
(vim:defcmd vim:insert-mode-toggle-replace ()
"Toggles overwrite-mode in insert-mode."
(unless (vim:insert-mode-p)
(error "Toggling overwrite-mode only allowed in insert-mode."))
(overwrite-mode nil)
(if overwrite-mode
(progn
(let (message-log-max) (message "-- REPLACE --"))
(setq cursor-type vim:insert-mode-replace-cursor)
(vim:update-mode-line "R"))
(progn
(let (message-log-max) (message "-- INSERT --"))
(setq cursor-type vim:insert-mode-cursor)
(vim:update-mode-line "I"))))
(defun vim:insert-mode-command (command)
"Executes a simple command in insert mode."
(case (vim:cmd-type command)
('simple (vim:normal-execute-simple-command command))
('complex (error "No complex command allowed in insert-mode."))
(t (vim:normal-execute-motion command))))
(defun vim:insert-mode-activated ()
"Called when insert-mode is activated."
(overwrite-mode -1)
(setq vim:last-insert-undo vim:last-undo)
(add-hook 'pre-command-hook 'vim:insert-save-key-sequence))
(defun vim:insert-mode-deactivated ()
"Called when insert-mode is deactivated."
(overwrite-mode -1)
(vim:set-mark ?^)
(remove-hook 'pre-command-hook 'vim:insert-save-key-sequence)
;; the command that has just ended insert-mode should NOT be repeatable
;; and will therefore NOT override repeat-sequence.
(setq vim:repeat-events (vconcat vim:repeat-events
vim:current-key-sequence))
(setq vim:last-undo vim:last-insert-undo))
(defun vim:insert-save-key-sequence ()
"Called in insert-mode to save key-events."
(when (and (vim:toplevel-execution)
(not (eq this-command 'vim:intercept-ESC)))
(setq vim:current-key-sequence (vconcat vim:current-key-sequence
(vim:this-command-keys)))))
(provide 'vim-insert-mode)
;;; vim-insert-mode.el ends here

View file

@ -0,0 +1,144 @@
;;; vim-keymap.el - Basic keymapping for vim-mode
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Code:
(defmacro vim:kbdmacro-to-command (events)
"Creates a command passing prefix-argument to given keyboard-macro `events'."
(let ((arg (gensym)))
`(lambda (,arg)
(interactive "P")
(execute-kbd-macro
(if ,arg
(vconcat (number-to-string (prefix-numeric-value ,arg))
,events)
,events)))))
(defun* vim:map (keys command &key (keymap nil))
"Maps the sequence of events `keys' to a `command' in a certain
`keymap.'"
(if (or (stringp command)
(vectorp command))
(lexical-let ((kbdevents command))
(define-key keymap keys (vim:kbdmacro-to-command kbdevents)))
(define-key keymap keys command)))
(defun vim:make-keymap (&optional parent)
"Creates a new keymap with a certain `parent' keymap."
(let ((kmap (make-sparse-keymap)))
(when parent (set-keymap-parent kmap parent))
kmap))
(defmacro vim:define-keymap (name
doc
&key
map-command)
"Defines global and local keymaps for a mode with name
vim:`name'-[local-]keymap and a map command vim:`map-command'
and vim:local-`map-command'."
(let ((glbkeym (concat "vim:" (symbol-name name) "-keymap"))
(lockeym (concat "vim:" (symbol-name name) "-local-keymap")))
`(progn
(defconst ,(intern glbkeym) (vim:make-keymap)
,(concat "VIM global keymap: " doc))
(defconst ,(intern lockeym) (vim:make-keymap)
,(concat "VIM buffer local keymap: " doc))
,@(when map-command
`((defsubst ,(intern (concat "vim:" (symbol-name map-command)))
(keys command)
,(concat "Maps the sequence of events `keys' to a `command' in keymap "
glbkeym)
(vim:map keys command :keymap ,(intern glbkeym)))
(defsubst ,(intern (concat "vim:local-" (symbol-name map-command)))
(keys command)
,(concat "Maps the sequence of events `keys' to a `command' in keymap "
lockeym)
(vim:map keys command :keymap ,(intern lockeym))))))))
(font-lock-add-keywords 'emacs-lisp-mode '("vim:define-keymap"))
;; Interception of ESC event. The ESC event is intercepted. If not
;; followed by another key, i.e. not used as a prefix-key, the event
;; [escape] is sent, otherwise the interception-keymap is disabled for
;; the next command and the ESC event is resent.
(defcustom vim:intercept-ESC-timeout 0.1
"Time in seconds to wait for another key after an ESC event."
:group 'vim-mode)
(defconst vim:intercept-ESC-keymap (make-sparse-keymap)
"Keymap to map ESC to [escape].")
(define-minor-mode vim:intercept-ESC-mode
"VIM minor mode to capture ESC."
nil nil nil)
;; This function is defined in vim:compat.el
;; (defun vim:intercept-ESC () ...)
(defun vim:enable-intercept-ESC ()
"Enables interception of ESC after executing a (prefix-)command."
(unless (eq this-command 'vim:intercept-ESC)
(remove-hook 'pre-command-hook 'vim:enable-intercept-ESC)
(vim:intercept-ESC-mode 1)))
;; Catch '\e' and convert it to [escape] if not used as prefix key.
(vim:map (kbd "ESC") 'vim:intercept-ESC :keymap vim:intercept-ESC-keymap)
;; The override keymap, useful especially in normal-mode.
(defconst vim:override-keymap (make-keymap)
"Global parent keymap to override some Emacs default bindings.")
(suppress-keymap vim:override-keymap)
(vim:map (kbd "ESC ESC ESC")
(lambda ()
"Exits any VIM mode and returns to normal-mode."
(interactive)
(vim:activate-normal-mode)
(ding))
:keymap vim:override-keymap)
;; This function sets up the keymaps for the current mode.
(defmacro vim:set-keymaps (mode-name keymaps)
(when (eq (car-safe mode-name) 'quote)
(setq mode-name (cadr mode-name)))
(when (eq (car-safe keymaps) 'quote)
(setq keymaps (cadr keymaps)))
`(setq vim:emulation-mode-alist
(list ,@(cons '(cons 'vim:intercept-ESC-mode vim:intercept-ESC-keymap)
(mapcan #'(lambda (keym)
(let ((localname (intern (replace-regexp-in-string "mode-keymap" "mode-local-keymap"
(symbol-name keym)))))
(if (eq localname keym)
(list `(cons ',mode-name ,keym))
(list `(cons ',mode-name ,localname)
`(cons ',mode-name ,keym)))))
keymaps)))))
;; TODO: This function is currently empty and serves only as hook for
;; defadvice.
(defun vim:reset-key-state ()
"Resets the current internal key-state."
nil)
(vim:deflocalvar vim:current-key-sequence nil
"The key-sequence of the current command.")
(vim:deflocalvar vim:new-buffer nil
"The buffer the be made current at the end of key-handline.")
(defun vim:clear-key-sequence ()
"Clears the internal log of key-sequences."
(setq vim:current-key-sequence nil))
(provide 'vim-keymap)
;;; vim-keymap.el ends here

View file

@ -0,0 +1,364 @@
;;; vim-maps.el
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Commentary:
;; This file contains all standard keymaps. Key mappings are defined
;; using one of the following vim-like macros:
;; - vim:map ... general mapping in an arbitrary mode
;; - vim:nmap ... mapping in the normal-mode keymap
;; - vim:omap ... mapping in the operator-pending keymap
;; - vim:imap ... mapping in the insert-mode keymap
;; - vim:vmap ... mapping in the visual-mode keymap
;; - vim:emap ... mapping in the ex-mode keymap
;;
;; Furthermore, for each of these map-function there's a buffer-local
;; variant
;;
;; - vim:local-nmap ... mapping in the normal-mode local keymap
;; - vim:local-omap ... mapping in the operator-pending local keymap
;; - vim:local-imap ... mapping in the insert-mode local keymap
;; - vim:local-vmap ... mapping in the visual-mode local keymap
;; - vim:local-emap ... mapping in the ex-mode local keymap
;;
;; The local versions should be used to define mode specific bindings
;; as local-set-key would do.
;;
;; Commands should usually be placed in the normal-mode keymap.
;; Motions should be placed in the operator-pending keymap. All
;; commands in the operator-pending-keymap are available as
;; operator-pending in normal-mode and visual-mode (but may be
;; overwritten by the corresponding keymaps) and as motion-arguments
;; for complex commands in normal-mode.
;;
;; A mapping has one of the following two forms:
;;
;; (vim:map KEYEVENTS 'my-command)
;;
;; (vim:map KEYEVENTS MAPEVENTS)
;;
;; The first form maps the events in KEYEVENTS to the command
;; my-command. The second form defines a vim-like mapping of
;; KEYEVENTS to MAPEVENTS, i.e. the activation of KEYEVENTS invokes
;; the (key-)events in MAPEVENTS.
;;
;; KEYEVENTS is a usual Emacs-sequence of events as it would be used by
;; define-key.
;;; TODO:
;; - better mapping to support stuff like
;; (vim:def-map "c" "d{motion}a")
;;
;; - because of this, mapping "cc" to "0C" does not work with a
;; count since the count is eaten by the '0'
;;
;; - similarily 'o' and 'O' won't work
;;
;; - should we have a 'deep-mapping' function: for example, "x" is
;; mapped to "dl" in the default keymap. If someone decides to
;; redefine "l" to some other command, "x" will change its
;; behaviour, too. A 'deep-mapping' should save the mapping on
;; definition of "x", therefor let "x" behave as usual even after
;; redefining "l"
;;; Code:
(vim:nmap "\\" 'vim:cmd-emacs)
(vim:nmap (kbd "C-z") 'vim:activate-emacs-mode)
(vim:map (kbd "C-z") 'vim:activate-normal-mode :keymap vim:emacs-keymap)
(vim:omap [escape] 'vim:operator-pending-mode-exit)
(vim:omap "0" 'vim:motion-beginning-of-line-or-digit-argument)
(vim:omap "1" 'digit-argument)
(vim:omap "2" 'digit-argument)
(vim:omap "3" 'digit-argument)
(vim:omap "4" 'digit-argument)
(vim:omap "5" 'digit-argument)
(vim:omap "6" 'digit-argument)
(vim:omap "7" 'digit-argument)
(vim:omap "8" 'digit-argument)
(vim:omap "9" 'digit-argument)
(vim:nmap "\"" 'vim:select-register)
(vim:nmap "ZZ" 'vim:cmd-write-and-close)
(vim:mmap "h" 'vim:motion-left)
(vim:mmap "l" 'vim:motion-right)
(vim:mmap "^" 'vim:motion-first-non-blank)
(vim:mmap "$" 'vim:motion-end-of-line)
(vim:mmap "g_" 'vim:motion-last-non-blank)
(vim:mmap "k" 'vim:motion-up)
(vim:mmap "j" 'vim:motion-down)
(vim:mmap "-" "k^")
(vim:mmap "+" "j^")
(vim:mmap "G" 'vim:motion-go-to-first-non-blank-end)
(vim:mmap "gg" 'vim:motion-go-to-first-non-blank-beg)
(vim:mmap "w" 'vim:motion-fwd-word)
(vim:mmap "W" 'vim:motion-fwd-WORD)
(vim:mmap "e" 'vim:motion-fwd-word-end)
(vim:mmap "E" 'vim:motion-fwd-WORD-end)
(vim:mmap "b" 'vim:motion-bwd-word)
(vim:mmap "B" 'vim:motion-bwd-WORD)
(vim:mmap "ge" 'vim:motion-bwd-word-end)
(vim:mmap "gE" 'vim:motion-bwd-WORD-end)
(vim:mmap "(" 'vim:motion-bwd-sentence)
(vim:mmap ")" 'vim:motion-fwd-sentence)
(vim:mmap "{" 'vim:motion-bwd-paragraph)
(vim:mmap "}" 'vim:motion-fwd-paragraph)
(vim:mmap "]]" 'vim:motion-fwd-section)
(vim:mmap "][" 'vim:motion-fwd-section)
(vim:mmap "[[" 'vim:motion-bwd-section)
(vim:mmap "[]" 'vim:motion-bwd-section)
(vim:omap "f" 'vim:motion-find)
(vim:omap "F" 'vim:motion-find-back)
(vim:omap "t" 'vim:motion-find-to)
(vim:omap "T" 'vim:motion-find-back-to)
(vim:omap ";" 'vim:motion-repeat-last-find)
(vim:omap "," 'vim:motion-repeat-last-find-opposite)
(vim:omap "%" 'vim:motion-jump-item)
(vim:omap "'" 'vim:motion-mark-line)
(vim:omap "`" 'vim:motion-mark)
(vim:omap "iw" 'vim:motion-inner-word)
;(vim:nmap "x" "dl")
(vim:nmap "m" 'vim:cmd-set-mark)
(vim:nmap "x" 'vim:cmd-delete-char)
(vim:nmap "D" "d$")
(vim:nmap "d" 'vim:cmd-delete)
(vim:nmap "C" 'vim:cmd-change-rest-of-line)
(vim:nmap "c" 'vim:cmd-change)
(vim:nmap "s" 'vim:cmd-change-char)
(vim:nmap "r" 'vim:cmd-replace-char)
(vim:nmap "R" 'vim:cmd-replace)
(vim:nmap "y" 'vim:cmd-yank)
(vim:nmap "Y" "yy")
(vim:nmap "p" 'vim:cmd-paste-behind)
(vim:nmap "P" 'vim:cmd-paste-before)
(vim:nmap "J" 'vim:cmd-join-lines)
(vim:nmap "/" 'vim:search-start)
(vim:nmap "?" 'vim:search-start-backward)
(vim:nmap "*" 'vim:search-word)
(vim:nmap "#" 'vim:search-word-backward)
(vim:nmap "g*" 'vim:search-unbounded-word)
(vim:nmap "g#" 'vim:search-unbounded-word-backward)
(vim:nmap "n" 'vim:search-repeat)
(vim:nmap "N" 'vim:search-repeat-opposite)
;; The next two maps are very special for an active search.
(vim:map "n" 'vim:search-repeat :keymap vim:search-keymap)
(vim:map "N" 'vim:search-repeat-opposite :keymap vim:search-keymap)
(vim:nmap "i" 'vim:cmd-insert)
(vim:nmap "a" 'vim:cmd-append)
(vim:nmap "I" 'vim:cmd-Insert)
(vim:nmap "A" 'vim:cmd-Append)
(vim:nmap "o" 'vim:cmd-insert-line-below)
(vim:nmap "O" 'vim:cmd-insert-line-above)
(vim:nmap "u" 'vim:cmd-undo)
(vim:nmap (kbd "C-r") 'vim:cmd-redo)
(vim:nmap "." 'vim:cmd-repeat)
(vim:nmap "=" 'vim:cmd-indent)
(vim:nmap "<" 'vim:cmd-shift-left)
(vim:nmap ">" 'vim:cmd-shift-right)
(vim:nmap "~" "g~l")
(vim:nmap "g~" 'vim:cmd-toggle-case)
(vim:nmap "gU" 'vim:cmd-make-upcase)
(vim:nmap "gu" 'vim:cmd-make-downcase)
(vim:omap (kbd "C-e") 'vim:scroll-line-down)
(vim:omap (kbd "C-d") 'vim:scroll-down)
(vim:omap (kbd "C-f") 'vim:scroll-page-down)
(vim:omap "z+" 'vim:scroll-bottom-line-to-top)
(vim:omap (kbd "C-y") 'vim:scroll-line-up)
(vim:omap (kbd "C-u") 'vim:scroll-up)
(vim:omap (kbd "C-b") 'vim:scroll-page-up)
(vim:omap "z^" 'vim:scroll-top-line-to-bottom)
(vim:omap "zt" 'vim:scroll-line-to-top)
(vim:omap (vconcat "z" [return]) "zt^")
(vim:omap (kbd "z RET") (vconcat "z" [return]))
(vim:omap "zz" 'vim:scroll-line-to-center)
(vim:omap "z." "z.^")
(vim:omap "zb" 'vim:scroll-line-to-bottom)
(vim:omap "z-" "zb^")
(vim:wmap (kbd "C-w +") 'vim:window-increase-height)
(vim:wmap (kbd "C-w -") 'vim:window-decrease-height)
(vim:wmap (kbd "C-w =") 'vim:window-balance)
(vim:wmap (kbd "C-w >") 'vim:window-increase-width)
(vim:wmap (kbd "C-w <") 'vim:window-decrease-width)
(vim:wmap (kbd "C-w H") 'vim:window-move-far-left)
(vim:wmap (kbd "C-w J") 'vim:window-move-very-bottom)
(vim:wmap (kbd "C-w K") 'vim:window-move-very-top)
(vim:wmap (kbd "C-w L") 'vim:window-move-far-right)
(vim:wmap (kbd "C-w R") 'vim:window-rotate-upwards)
(vim:wmap (kbd "C-w C-R") (kbd "C-w R"))
(vim:wmap (kbd "C-w r") 'vim:window-rotate-downwards)
(vim:wmap (kbd "C-w C-r") (kbd "C-w r"))
(vim:wmap (kbd "C-w _") 'vim:window-set-height)
(vim:wmap (kbd "C-w C-_") (kbd "C-w _"))
(vim:wmap (kbd "C-w |") 'vim:window-set-width)
(vim:wmap (kbd "C-w b") 'vim:window-bottom-right)
(vim:wmap (kbd "C-w C-b") (kbd "C-w b"))
(vim:wmap (kbd "C-w t") 'vim:window-top-left)
(vim:wmap (kbd "C-w C-t") (kbd "C-w t"))
(vim:wmap (kbd "C-w c") 'vim:window-close)
(vim:wmap (kbd "C-w h") 'vim:window-left)
(vim:wmap (kbd "C-w C-h") (kbd "C-w h"))
(vim:wmap (kbd "C-w j") 'vim:window-down)
(vim:wmap (kbd "C-w C-j") (kbd "C-w j"))
(vim:wmap (kbd "C-w k") 'vim:window-up)
(vim:wmap (kbd "C-w C-k") (kbd "C-w k"))
(vim:wmap (kbd "C-w l") 'vim:window-right)
(vim:wmap (kbd "C-w C-l") (kbd "C-w l"))
(vim:wmap (kbd "C-w p") 'vim:window-lru)
(vim:wmap (kbd "C-w C-p") (kbd "C-w p"))
(vim:wmap (kbd "C-w w") 'vim:window-next)
(vim:wmap (kbd "C-w C-w") (kbd "C-w w"))
(vim:wmap (kbd "C-w W") 'vim:window-prev)
(vim:wmap (kbd "C-w n") 'vim:window-new)
(vim:wmap (kbd "C-w C-n") (kbd "C-w n"))
(vim:wmap (kbd "C-w o") 'vim:window-only)
(vim:wmap (kbd "C-w C-o") (kbd "C-w o"))
(vim:wmap (kbd "C-w s") 'vim:window-split)
(vim:wmap (kbd "C-w C-s") (kbd "C-w s"))
(vim:wmap (kbd "C-w S") (kbd "C-w s"))
(vim:wmap (kbd "C-w v") 'vim:window-vsplit)
(vim:wmap (kbd "C-w C-v") (kbd "C-w v"))
(vim:nmap "v" 'vim:visual-toggle-normal)
(vim:nmap "V" 'vim:visual-toggle-linewise)
(vim:nmap (kbd "C-v") 'vim:visual-toggle-block)
(vim:nmap "gv" 'vim:visual-mode-reactivate)
(vim:nmap ":" 'vim:ex-read-command)
(vim:nmap "q" 'vim:cmd-toggle-macro-recording)
(vim:nmap "@" 'vim:cmd-execute-macro)
(vim:imap (vector vim:ESC-event) 'vim:insert-mode-exit)
(vim:imap [insert] 'vim:insert-mode-toggle-replace)
(vim:imap [kp-insert] [insert])
(vim:imap [insertchar] [insert])
(vim:vmap (vector vim:ESC-event) 'vim:visual-mode-exit)
(vim:vmap "v" 'vim:visual-toggle-normal)
(vim:vmap "V" 'vim:visual-toggle-linewise)
(vim:vmap (kbd "C-v") 'vim:visual-toggle-block)
(vim:vmap "\"" 'vim:select-register)
(vim:vmap "d" 'vim:cmd-delete)
(vim:vmap "D" 'vim:cmd-delete)
(vim:vmap "x" 'vim:cmd-delete)
(vim:vmap "c" 'vim:cmd-change)
(vim:vmap "C" "Vc")
(vim:vmap "r" 'vim:cmd-replace-region)
(vim:vmap "R" 'vim:cmd-change)
(vim:vmap "s" 'vim:cmd-change)
(vim:vmap "S" 'vim:cmd-change)
(vim:vmap "y" 'vim:cmd-yank)
(vim:vmap "Y" 'vim:cmd-yank)
(vim:vmap "J" 'vim:cmd-join)
(vim:vmap "=" 'vim:cmd-indent)
(vim:vmap "<" 'vim:cmd-shift-left)
(vim:vmap ">" 'vim:cmd-shift-right)
(vim:vmap "~" 'vim:cmd-toggle-case)
(vim:vmap "U" 'vim:cmd-make-upcase)
(vim:vmap "u" 'vim:cmd-make-downcase)
(vim:vmap "I" 'vim:visual-insert)
(vim:vmap "A" 'vim:visual-append)
(vim:vmap "o" 'vim:visual-exchange-point-and-mark)
(vim:vmap "O" 'vim:visual-jump-point)
(vim:vmap ":" 'vim:visual-ex-read-command)
(vim:emap "edit" 'vim:cmd-edit)
(vim:emap "e" "edit")
(vim:emap "write" 'vim:cmd-write)
(vim:emap "w" "write")
(vim:emap "write!" 'vim:cmd-write-q)
(vim:emap "w!" "write!")
(vim:emap "wall" 'vim:cmd-write-all)
(vim:emap "wa" "wall")
(vim:emap "wall!" 'vim:cmd-write-all-q)
(vim:emap "wa!" "wall!")
(vim:emap "buffer" 'vim:cmd-buffer)
(vim:emap "b" "buffer")
(vim:emap "split" 'vim:window-split)
(vim:emap "sp" "split")
(vim:emap "vsplit" 'vim:window-vsplit)
(vim:emap "vs" "vsplit")
(vim:emap "new" 'vim:window-new)
(vim:emap "vnew" 'vim:window-vnew)
(vim:emap "vne" "vnew")
(vim:emap "close" 'vim:window-close)
(vim:emap "clo" "close")
(vim:emap "only" 'vim:window-only)
(vim:emap "on" "only")
(vim:emap "quit" 'vim:cmd-quit)
(vim:emap "q" "quit")
(vim:emap "quit!" 'vim:cmd-quit-q)
(vim:emap "q!" "quit")
(vim:emap "wq" 'vim:cmd-save-and-close)
(vim:emap "wq!" 'vim:cmd-save-and-close-q)
(vim:emap "quitall" 'vim:cmd-quit-all)
(vim:emap "quita" "quitall")
(vim:emap "qall" "quitall")
(vim:emap "qa" "qall")
(vim:emap "quitall!" 'vim:cmd-quit-all-q)
(vim:emap "quita!" "quitall!")
(vim:emap "qall!" "quitall!")
(vim:emap "qa!" "qall!")
(vim:emap "wqall" 'vim:cmd-save-and-quit)
(vim:emap "wqa" "wqall")
(vim:emap "xall" "wqall")
(vim:emap "xa" "xall")
(vim:emap "bdelete" 'vim:cmd-delete-buffer)
(vim:emap "bd" "bdelete")
(vim:emap "bdelete!" 'vim:cmd-delete-buffer-q)
(vim:emap "bd!" "bdelete!")
(vim:emap "substitute" 'vim:cmd-substitute)
(vim:emap "s" "substitute")
(vim:emap "marks" 'vim:cmd-show-marks)
(vim:nmap (vector vim:down-mouse-1) 'vim:visual-mouse-clicked)
(vim:vmap (vector vim:down-mouse-1) 'vim:visual-mouse-clicked)
(provide 'vim-maps)
;;; vim-maps.el ends here

View file

@ -0,0 +1,87 @@
;;; vim-modes.el
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Code:
(vim:deflocalvar vim:mode-string)
(defun vim:update-mode-line (ident)
"Updates the mode-line to show the specified identifier `ident'."
(setq vim:mode-string (concat "<" (or ident "?") ">"))
(force-mode-line-update))
(defun vim:mode-name (mode)
"Converts a mode-name to vim-mode naming conventions, e.g.
'normal is converted to 'vim:normal-mode."
(intern (concat "vim:" (symbol-name mode) "-mode")))
(vim:deflocalvar vim:active-mode nil
"The currently active vim-mode.")
(vim:deflocalvar vim:active-command-function nil
"The command function of the currently active vim-mode.")
(defun vim:activate-mode (mode)
"Activates a certain vim-mode, disabling the currently active one."
(when vim:active-mode
(funcall vim:active-mode -1))
(when mode
(funcall (vim:mode-name mode) 1)))
(defmacro* vim:define-mode (name doc
&rest body
&key
ident
message
command-function
(cursor ''box)
keymaps)
"Defines a new VIM-mode with certain `name', mode-line-identifier `ident',
activation `message', a `command-function' to be called when a
vim-command should be executed, a `cursor' shape and a list of `keymaps'."
(let* ((mode-name (vim:mode-name name))
(pred-name (intern (concat (symbol-name mode-name) "-p")))
(on-name (intern (concat "vim:activate-" (symbol-name name) "-mode")))
(cursor-name (intern (concat (symbol-name mode-name)
"-cursor"))))
`(progn
(defcustom ,cursor-name ,cursor
,(concat "The cursor-type for vim-mode " (symbol-name name) ".")
:group 'vim-mode)
(define-minor-mode ,mode-name ,doc nil nil nil
(when ,mode-name
,@(when ident `((vim:update-mode-line ,ident)))
,@(when message `((let (message-log-max) (message ,message))))
(setq vim:active-mode ',mode-name)
(setq vim:active-command-function
,(if command-function
command-function
'vim:default-command-function))
(vim:set-cursor ,cursor-name)
(vim:set-keymaps ',mode-name ,keymaps))
,@(progn
(while (keywordp (car body)) (pop body) (pop body))
body))
(defun ,pred-name ()
,(concat "Returns t iff vim-mode is in " (symbol-name name) " mode.")
(and ,mode-name t))
(defun ,on-name ()
,(concat "Activates " (symbol-name name) " mode.")
(interactive)
(vim:activate-mode ',name)))))
(font-lock-add-keywords 'emacs-lisp-mode '("vim:define-mode"))
(provide 'vim-modes)
;;; vim-modes.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,192 @@
;;; vim-insert-mode.el - VIM normal mode.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; TODO:
;; - bindings in local-omap keymap will not be seen as motions in
;; normal-mode since the parent-keymap of the normal-mode keymap
;; is operator-pending-keymap and not its local counterpart. The
;; reason is that the binding of the local counterpart will be
;; changed to a buffer-local binding.
;;; Code:
(defconst vim:operator-repeat-keymap (vim:make-keymap)
"Keymap to bind the repeat-operator-event.")
(vim:define-keymap operator-pending-mode
"operator pending mode"
:map-command omap)
(vim:define-mode operator-pending "VIM operator-pending mode"
:ident "O"
:keymaps '(vim:operator-pending-mode-keymap
vim:motion-mode-keymap
vim:operator-repeat-keymap
vim:override-keymap)
:command-function 'vim:operator-pending-mode-command)
(add-hook 'vim:operator-pending-mode-hook 'vim:operator-pending-activate)
(add-hook 'vim:operator-pending-mode-off-hook 'vim:operator-pending-deactivate)
(defun vim:operator-pending-activate ()
(cond
(vim:operator-pending-mode
(setq vim:operator-repeat-last-event (vector last-command-event))
(vim:map vim:operator-repeat-last-event 'vim:motion-lines
:keymap vim:operator-repeat-keymap)
(add-hook 'post-command-hook 'vim:operator-pending-mode-exit))
(vim:operator-repeat-last-event
(vim:map vim:operator-repeat-last-event nil :keymap vim:operator-repeat-keymap))))
(defun vim:operator-pending-deactivate ()
(remove-hook 'post-command-hook 'vim:operator-pending-mode-exit))
(defun vim:operator-pending-mode-exit ()
"Exits operator-pending-mode and returns to normal-mode."
(interactive)
(unless (or (vim:cmd-function this-command)
(eq this-command 'digit-argument)
(eq this-command 'universal-argument-other-key))
(vim:activate-normal-mode)))
(defun vim:operator-pending-mode-command (command)
"Executes a complex command in operator-pending mode."
(case (vim:cmd-type command)
('simple (error "No simple-commands allowed in operator-pending mode."))
('complex (error "No complex-commands allowed in operator-pending mode."))
(t (vim:normal-execute-complex-command command)))
(when (vim:operator-pending-mode-p)
(vim:activate-normal-mode)))
(vim:define-keymap normal-mode "normal mode" &map-command nmap)
(vim:define-mode normal "VIM normal mode"
:ident "N"
:message "-- NORMAL --"
:keymaps '(vim:normal-mode-keymap
vim:operator-pending-mode-keymap
vim:motion-mode-keymap
vim:window-mode-keymap
vim:override-keymap)
:command-function 'vim:normal-mode-command)
(defun vim:normal-mode-command (command)
"Executes a motion or simple-command or prepares a complex command."
(case (vim:cmd-type command)
('simple (vim:normal-execute-simple-command command))
('complex (vim:normal-prepare-complex-command command))
('special (error "no special so far"))
(t (vim:normal-execute-motion command))))
(defun vim:normal-execute-motion (command)
"Executes a motion."
(setq vim:current-motion command)
(when current-prefix-arg
(setq vim:current-motion-count (prefix-numeric-value current-prefix-arg)))
(when (vim:cmd-char-arg-p command)
(setq vim:current-motion-arg (read-char-exclusive)))
(vim:execute-current-motion)
(vim:reset-key-state)
(vim:clear-key-sequence)
(vim:adjust-point))
(defun vim:normal-execute-simple-command (command)
"Executes a simple command."
(when current-prefix-arg
(setq vim:current-cmd-count (prefix-numeric-value current-prefix-arg)))
(when (vim:cmd-char-arg-p command)
(setq vim:current-cmd-arg (read-char-exclusive)))
(let ((parameters nil)
(vim:last-undo buffer-undo-list))
(when (vim:cmd-count-p command)
(push vim:current-cmd-count parameters)
(push :count parameters))
(when (vim:cmd-char-arg-p command)
(push vim:current-cmd-arg parameters)
(push :argument parameters))
(when (and (vim:cmd-register-p command)
vim:current-register)
(push vim:current-register parameters)
(push :register parameters))
(vim:apply-save-buffer (vim:cmd-function command) parameters)
(when (vim:cmd-repeatable-p command)
(setq vim:repeat-events (vconcat vim:current-key-sequence
(vim:this-command-keys))))
(vim:connect-undos vim:last-undo))
(vim:reset-key-state)
(vim:clear-key-sequence)
(vim:adjust-point))
(defun vim:normal-prepare-complex-command (command)
"Prepares a complex command, switching to operator-pending mode."
(when current-prefix-arg
(setq vim:current-cmd-count (prefix-numeric-value current-prefix-arg)))
(setq vim:current-cmd command)
(setq vim:current-key-sequence (vconcat vim:current-key-sequence (vim:this-command-keys)))
(vim:activate-operator-pending-mode))
(defun vim:normal-execute-complex-command (motion-command)
"Executes a complex command with a certain motion command."
(setq vim:current-motion motion-command)
(when current-prefix-arg
(setq vim:current-motion-count (prefix-numeric-value current-prefix-arg)))
(when (or vim:current-motion-count vim:current-cmd-count)
(setq vim:current-motion-count (* (or vim:current-cmd-count 1)
(or vim:current-motion-count 1)))
(setq vim:current-cmd-count nil))
(when (vim:cmd-char-arg-p motion-command)
(setq vim:current-motion-arg (read-char-exclusive)))
(let ((vim:last-undo buffer-undo-list))
(if (and (vim:cmd-register-p vim:current-cmd) vim:current-register)
(vim:funcall-save-buffer (vim:cmd-function vim:current-cmd)
:motion (vim:get-current-cmd-motion)
:register vim:current-register)
(vim:funcall-save-buffer (vim:cmd-function vim:current-cmd)
:motion (vim:get-current-cmd-motion)))
(when (vim:cmd-repeatable-p vim:current-cmd)
(setq vim:repeat-events (vconcat vim:current-key-sequence
(vim:this-command-keys))))
(vim:connect-undos vim:last-undo))
(vim:reset-key-state)
(vim:clear-key-sequence)
(vim:adjust-point))
(vim:define-mode operator-pending "VIM operator-pending mode"
:ident "O"
:keymaps '(vim:operator-pending-mode-keymap
vim:motion-mode-keymap
vim:operator-repeat-keymap
vim:override-keymap)
:command-function 'vim:operator-pending-mode-command)
(provide 'vim-normal-mode)
;;; vim-normal-mode.el ends here

View file

@ -0,0 +1,136 @@
;;; vim-scroll.el - Implementation of scrolling commands
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Commentary:
;; This file contains implementations for the scrolling. Scroll
;; operations are usually just simple commands and should not be
;; repeatable but should keep visual mode.
;;; Code:
(vim:define-keymap motion-mode "motion mode" :map-command mmap)
(vim:define-mode motion "VIM motion mode"
:ident "M"
:keymaps '(vim:motion-mode-keymap vim:window-mode-keymap)
:command-function 'vim:normal-mode-command)
(defun vim:num-visible-lines ()
"Returns the number of currently visible lines."
(- (window-height) 1))
(defun vim:max-scroll-up ()
"Returns the maximal number of lines that can be scrolled up."
(1- (line-number-at-pos (window-start))))
(defun vim:max-scroll-down ()
"Returns the maximal number of lines that can be scrolled down."
(if (pos-visible-in-window-p (window-end))
0
(1+ (- (line-number-at-pos (point-max))
(line-number-at-pos (window-end))))))
(vim:defcmd vim:scroll-line-up (count nonrepeatable keep-visual)
"Scrolls the window `count' lines upwards."
(vim:use-last-column)
(scroll-down (or count 1)))
(vim:defcmd vim:scroll-line-down (count nonrepeatable keep-visual)
"Scrolls the window `count' lines downwards."
(vim:use-last-column)
(scroll-up (or count 1)))
(vim:defcmd vim:scroll-up (count nonrepeatable keep-visual)
"Scrolls the window and the cursor `count' lines upwards, default half of the screen."
(vim:use-last-column)
(let ((p (point))
(c (or count (/ (vim:num-visible-lines) 2))))
(save-excursion
(scroll-down (min (vim:max-scroll-up) c)))
(forward-line (- c))
(when (= (line-number-at-pos p)
(line-number-at-pos (point)))
(ding))))
(vim:defcmd vim:scroll-down (count nonrepeatable keep-visual)
"Scrolls the window and the cursor `count' lines downwards, default half of the screen."
(vim:use-last-column)
(let ((p (point))
(c (or count (/ (vim:num-visible-lines) 2))))
(save-excursion
(scroll-up (min (vim:max-scroll-down) c)))
(forward-line c)
(when (= (line-number-at-pos p)
(line-number-at-pos (point)))
(ding))))
(vim:defcmd vim:scroll-page-up (count nonrepeatable keep-visual)
"Scrolls the window `count' pages upwards."
(vim:use-last-column)
(condition-case nil
(dotimes (i (or count 1))
(scroll-down nil))
(error (goto-char (point-min)))))
(vim:defcmd vim:scroll-page-down (count nonrepeatable keep-visual)
"Scrolls the window `count' pages upwards."
(vim:use-last-column)
(condition-case nil
(dotimes (i (or count 1))
(scroll-up nil))
(error (goto-char (point-max)))))
(vim:defcmd vim:scroll-line-to-top (count nonrepeatable keep-visual)
"Scrolls line number `count' (or the cursor line) to the top of the window."
(vim:use-last-column)
(goto-line (or count (line-number-at-pos (point))))
(recenter 0))
(vim:defcmd vim:scroll-line-to-center (count nonrepeatable keep-visual)
"Scrolls line number `count' (or the cursor line) to the center of the window."
(vim:use-last-column)
(goto-line (or count (line-number-at-pos (point))))
(recenter nil))
(vim:defcmd vim:scroll-line-to-bottom (count nonrepeatable keep-visual)
"Scrolls line number `count' (or the cursor line) to the bottom of the window."
(vim:use-last-column)
(goto-line (or count (line-number-at-pos (point))))
(recenter -1))
(vim:defcmd vim:scroll-bottom-line-to-top (count nonrepeatable keep-visual)
"Scrolls the line right below the window or line `count' to the top of the window."
(if count
(goto-line count)
(goto-char (window-end))
(unless (bobp) (backward-char)))
(recenter 0)
(vim:motion-first-non-blank))
(vim:defcmd vim:scroll-top-line-to-bottom (count nonrepeatable keep-visual)
"Scrolls the line right below the window or line `count' to the top of the window."
(if count
(goto-line count)
(goto-char (window-start)))
(recenter -1)
(vim:motion-first-non-blank))
(provide 'vim-scroll)
;;; vim-scroll.el ends here

View file

@ -0,0 +1,243 @@
;;; vim-search.el - Search und substitute commands for ex-mode.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;; TODO:
;;
;; - searching currently uses isearch. Although this is quite powerful,
;; it's only usuably as interactive search and difficult to use with
;; semi-interactive stuff like the "*" command. The current implementation
;; using unread-command-events is quite ugly.
;; - the substitute command should be more interactive and especially an operation
;; without the 'g' option should highlight all future occurences
;;; Code:
(defconst vim:search-keymap (make-sparse-keymap))
(vim:set-keymap-default-binding vim:search-keymap 'vim:search-mode-exit)
(vim:deflocalvar vim:search-last-direction nil
"The last search direction, either 'forward or 'backward.")
(defun vim:search-mode-activate ()
(setq cursor-type vim:normal-mode-cursor))
(defun vim:search-mode-deactivate ()
(isearch-exit))
(vim:defcmd vim:search-mode-exit ()
(vim:activate-normal-mode)
(push last-command-event unread-command-events))
;; Search mode is a very special mode being activated during a search
;; command. Its purpose is to disable highlighting of search results
;; if something else than a repeat-search event occurs.
(vim:define-mode search "VIM search mode"
:ident "S"
:keymaps '(vim:search-keymap)
:command-function 'vim:search-mode-command)
(add-hook 'vim:search-mode-on-hook 'vim:search-mode-activate)
(add-hook 'vim:search-mode-off-hook 'vim:search-mode-activate)
(defun vim:search-mode-command (command)
"Executes a simple-command in search-mode."
(case (vim:cmd-type command)
('simple (vim:normal-execute-simple-command command))
(t (error "Only simple commands allowed in search-mode."))))
(vim:defcmd vim:search-start (nonrepeatable)
"Starts an incremental regexp search."
(let ((search-nonincremental-instead nil))
(ad-activate 'isearch-message-prefix)
(isearch-forward-regexp)
(ad-deactivate 'isearch-message-prefix)
(setq vim:last-search-direction (if isearch-forward 'forward 'backward))))
(vim:defcmd vim:search-start-backward (nonrepeatable)
"Starts an incremental regexp search."
(let ((search-nonincremental-instead nil))
(ad-activate 'isearch-message-prefix)
(isearch-backward-regexp)
(ad-deactivate 'isearch-message-prefix)
(setq vim:last-search-direction (if isearch-forward 'forward 'backward))))
(vim:defcmd vim:search-repeat (nonrepeatable)
"Repeats the last incremental search."
(unless (vim:search-mode-p)
(vim:activate-search-mode))
(ad-activate 'isearch-message-prefix)
(isearch-repeat vim:last-search-direction)
(ad-deactivate 'isearch-message-prefix))
(vim:defcmd vim:search-repeat-opposite (nonrepeatable)
"Starts an incremental regexp search."
(unless (vim:search-mode-p)
(vim:activate-search-mode))
(ad-activate 'isearch-message-prefix)
(isearch-repeat (if (eq vim:last-search-direction 'forward) 'backward 'forward))
(ad-deactivate 'isearch-message-prefix))
(defadvice isearch-message-prefix (after vim:isearch-message-prefix (&optional c-q-hack ellipsis nonincremental))
"This advice changes the minibuffer indicator to '/' or '?'"
(setq ad-return-value (if isearch-forward "/" "?")))
(defun vim:start-word-search (unbounded direction)
(condition-case nil
(goto-char (vim:motion-bwd-word-end :count 1))
(error nil))
(save-excursion
(re-search-forward (concat "\\<[" vim:word "]+\\>")))
(when (eq direction 'backward)
(goto-char (1+ (match-end 0))))
(let ((events (reverse (append (if (eq direction 'forward)
"/"
"?")
(if unbounded
(regexp-quote (match-string 0))
(concat "\\<"
(regexp-quote (match-string 0))
"\\>"))
[return]
"n"
nil))))
(while events
(push (car events) unread-command-events)
(setq events (cdr events)))))
(vim:defcmd vim:search-word (nonrepeatable)
"Searches the next occurence of word under the cursor."
(vim:start-word-search nil 'forward))
(vim:defcmd vim:search-word-backward (nonrepeatable)
"Searches the next occurence of word under the cursor."
(vim:start-word-search nil 'backward))
(vim:defcmd vim:search-unbounded-word (nonrepeatable)
"Searches the next occurence of word under the cursor."
(vim:start-word-search t 'forward))
(vim:defcmd vim:search-unbounded-word-backward (nonrepeatable)
"Searches the next occurence of word under the cursor."
(vim:start-word-search t 'backward))
(vim:defcmd vim:cmd-substitute (motion argument nonrepeatable)
"The VIM substitutde command: [range]s/pattern/replacement/flags"
(multiple-value-bind (pattern replacement flags) (vim:parse-substitute argument)
(lexical-let* ((pattern pattern)
(replacement replacement)
(first-line (if motion (vim:motion-first-line motion) (line-number-at-pos (point))))
(last-line (if motion (vim:motion-last-line motion) (line-number-at-pos (point))))
(whole-line (and flags (find ?g flags)))
(confirm (and flags (find ?c flags)))
(ignore-case (and flags (find ?i flags)))
(dont-ignore-case (and flags (find ?I flags)))
(case-fold-search (or (and case-fold-search
(not dont-ignore-case))
(and (not case-fold-search)
ignore-case)))
(case-replace case-fold-search)
(last-point (point))
(overlay (make-overlay (point) (point)))
(next-line (line-number-at-pos (point)))
(nreplaced 0))
(unwind-protect
(if whole-line
;; this one is easy, just use the built in function
(vim:perform-replace pattern replacement confirm t nil nil nil
(save-excursion
(goto-line first-line)
(line-beginning-position))
(save-excursion
(goto-line last-line)
(line-end-position)))
(if confirm
(progn
;; this one is more difficult, we have to do the
;; highlighting and questioning on our own
(overlay-put overlay 'face
(if (internal-find-face 'isearch nil)
'isearch 'region))
(map-y-or-n-p #'(lambda (x)
(set-match-data x)
(move-overlay overlay (match-beginning 0) (match-end 0))
(concat "Query replacing "
(match-string 0)
" with "
(match-substitute-replacement replacement case-fold-search)
": "))
#'(lambda (x)
(set-match-data x)
(replace-match replacement case-fold-search)
(incf nreplaced)
(setq last-point (point)))
#'(lambda ()
(let ((end (save-excursion
(goto-line last-line)
(line-end-position))))
(goto-line next-line)
(beginning-of-line)
(when (and (> end (point))
(re-search-forward pattern end t nil))
(setq last-point (point))
(setq next-line (1+ (line-number-at-pos (point))))
(match-data))))))
;; just replace the first occurences per line
;; without highlighting and asking
(goto-line first-line)
(beginning-of-line)
(while (and (<= (line-number-at-pos (point)) last-line)
(re-search-forward pattern (save-excursion
(goto-line last-line)
(line-end-position))
t nil))
(incf nreplaced)
(replace-match replacement)
(setq last-point (point))
(forward-line)
(beginning-of-line)))
(goto-char last-point)
(if (= nreplaced 1)
(message "Replaced 1 occurence")
(message "Replaced %d occurences" nreplaced)))
;; clean-up the overlay
(delete-overlay overlay)))))
(defun vim:parse-substitute (text)
(when (string-match "\\`\\s-*/\\(\\(?:[^/]\\|\\\\.\\)+\\)/\\(\\(?:[^/]\\|\\\\.\\)*\\)\\(?:/\\([giIc]*\\)\\)?\\s-*\\'"
text)
(let ((pattern (match-string 1 text))
(replacement (match-string 2 text))
(flags (match-string 3 text)))
(values pattern
;; handle some special escapes, especially \\ and \/
(replace-regexp-in-string "\\\\."
(lambda (x)
(cond ((string= x "\\n") "\n")
((string= x "\\t") "\t")
((string= x "\\r") "\r")
((string= x "\\/") "/")
((string= x "\\\\") "\\\\\\\\")
(t x)))
replacement)
flags))))
(provide 'vim-search)
;;; vim-search.el ends here

View file

@ -0,0 +1,71 @@
;;; vim-undo.el - Undo/Redo for VIM.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Before the execution of an editing command, the calling function
;; should save the current head of buffer-undo-list. When the
;; editing-command has finished, the calling function should use
;; vim:connect-undos to connect the changes made during editing to one
;; single undo-block.
;;
;; Insert-mode has a special handling: when activated, it stores the
;; current head of buffer-undo-list in vim:last-insert-undo and used
;; this pointer to connect all editing actions during insert-mode to
;; one undo-block when insert-mode is deactivated. If a function
;; activates insert-mode it may modify vim:last-insert-undo to an
;; apropriate value (see vim:execute-mapping for an example).
;;; Code:
(condition-case nil
(require 'redo)
(error
(message "vim-mode: Could not load 'redo', redo-command not available.")))
(defvar vim:last-undo)
;; undo stuff
(defun vim:connect-undos (last-undo)
(labels
((find-mark (lst)
(while (not (or (null lst)
(eq lst last-undo)))
(setq lst (cdr lst)))
(not (null lst))))
;; ensure last-undo is still in the undo list
(when (and last-undo
(not (eq last-undo buffer-undo-list))
(find-mark buffer-undo-list))
;; add the end-of-command mark if not already there
(unless (null (car buffer-undo-list))
(push nil buffer-undo-list))
;; remove all nils until the mark
(let ((lst buffer-undo-list))
(while (and lst
(not (eq (cdr lst) last-undo)))
(if (null (cadr lst))
(setcdr lst (cddr lst))
(setq lst (cdr lst))))))))
(vim:defcmd vim:cmd-undo (count nonrepeatable)
(setq vim:last-undo nil)
(dotimes (i (or count 1))
(undo)))
(vim:defcmd vim:cmd-redo (count nonrepeatable)
(setq vim:last-undo nil)
(redo (or count 1)))
(provide 'vim-undo)
;;; vim-undo.el ends here

View file

@ -0,0 +1,404 @@
;;; vim-vim.el - Basic functions and macros for vim-mode.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Code:
(defvar vim:repeat-events nil
"The sequence of events for the repeat command.")
(vim:deflocalvar vim:current-register nil
"The register of the current command.")
(vim:deflocalvar vim:current-cmd-count nil
"The count of the current command.")
(vim:deflocalvar vim:current-cmd nil
"The node of the current command.")
(vim:deflocalvar vim:current-cmd-arg nil
"The argument of the current command.")
(vim:deflocalvar vim:current-motion-count nil
"The count of the current motion.")
(vim:deflocalvar vim:current-motion nil
"The node of the current motion.")
(vim:deflocalvar vim:current-motion-arg nil
"The argument of the current motion.")
(vim:deflocalvar vim:current-motion-type nil
"The type of the current motion (inclusive, exclusive, linewise).")
(defun vim:toplevel-execution ()
"Returns t iff this is a toplevel execution, not a mapping or repeat."
(not executing-kbd-macro))
(defadvice vim:reset-key-state (before vim:vim-reset-key-state)
"Resets the current state of the keymap."
(setq vim:current-register nil
vim:current-cmd-count nil
vim:current-cmd nil
vim:current-cmd-arg nil
vim:current-motion-count nil
vim:current-motion nil
vim:current-motion-arg nil
vim:current-motion-type nil))
(ad-activate 'vim:reset-key-state)
(defmacro* vim:defcmd (name (&rest args) &rest body)
"Defines a new VIM-command."
(declare (indent defun))
(let ((count nil)
(register nil)
(motion nil)
(argument nil)
(keep-visual nil)
(repeatable t)
(params nil)
(named-params nil)
(doc nil))
;; extract documentation string
(if (and (consp body)
(cdr body)
(stringp (car body)))
(setq doc (car body)
body (cdr body))
(setq doc (format "VIM - command (%s %s)" name args)))
;; collect parameters
(dolist (arg args)
(case (if (consp arg) (car arg) arg)
('count
(setq count t)
(push '(count nil) params)
(when (and (consp arg)
(not (eq (cadr arg) 'count)))
(push `(,(cadr arg) count) named-params)))
('register
(setq register t)
(push '(register nil) params)
(when (and (consp arg)
(not (eq (cadr arg) 'register)))
(push `(,(cadr arg) register) named-params)))
('motion
(when motion
(error "%s: only one motion argument may be specified: %s" 'vim:defcmd arg))
(setq motion t)
(push 'motion params)
(when (and (consp arg)
(not (eq (cadr arg) 'motion)))
(push `(,(cadr arg) motion) named-params)))
('motion:optional
(when motion
(error "%s: only one motion argument may be specified: %s" 'vim:defcmd arg))
(setq motion ''optional)
(push 'motion params)
(when (and (consp arg)
(not (eq (cadr arg) 'motion)))
(push `(,(cadr arg) motion) named-params)))
((argument argument:char argument:file argument:buffer)
(when argument
(error "%s: only one argument may be specified: %s" 'vim:defcmd arg))
(let* ((arg-name (symbol-name (if (consp arg) (car arg) arg)))
(pos (position ?: arg-name))
(arg-type (if pos
`',(intern (substring arg-name (1+ pos)))
t)))
(setq argument arg-type)
(push 'argument params)
(when (and (consp arg)
(not (eq (cadr arg) 'argument)))
(push `(,(cadr arg) argument) named-params))))
('keep-visual (setq keep-visual t))
('do-not-keep-visual (setq keep-visual nil))
('repeatable (setq repeatable t))
('nonrepeatable (setq repeatable nil))
(t (error "%s: Unexpected argument: %s" 'vim:defcmd arg))))
`(progn
(put ',name 'type ',(if motion 'complex 'simple))
(put ',name 'count ,count)
(put ',name 'motion ,motion)
(put ',name 'argument ,argument)
(put ',name 'register ,register)
(put ',name 'keep-visual ,keep-visual)
(put ',name 'repeatable ,repeatable)
(put ',name 'function
(function* (lambda (,@(when params `(&key ,@params))
,@(when named-params `(&aux ,@named-params)))
,@body)))
(defun* ,name (&rest args)
,doc
(interactive)
(if (vim:called-interactively-p)
(funcall vim:active-command-function ',name)
(apply (get ',name 'function) args))))))
(defmacro* vim:defmotion (name (&rest args) &rest body)
(declare (indent defun))
(let ((type nil)
(count nil)
(argument nil)
(params nil)
(named-params nil)
(doc nil))
;; extract documentation string
(if (and (consp body)
(cdr body)
(stringp (car body)))
(setq doc (car body)
body (cdr body))
(setq doc (format "VIM - motion (%s %s)" name args)))
;; collect parameters
(dolist (arg args)
(case (if (consp arg) (car arg) arg)
((inclusive exclusive linewise block)
(setq type arg))
('count
(setq count t)
(push '(count nil) params)
(when (and (consp arg)
(not (eq (cadr arg) 'count)))
(push `(,(cadr arg) count) named-params)))
((argument argument:char)
(when argument
(error "%s: only one argument may be specified: %s" 'vim:defcmd arg))
(setq argument ''char)
(push 'argument params)
(when (and (consp arg)
(not (eq (cadr arg) 'argument)))
(push `(,(cadr arg) argument) named-params)))
(t (error "%s: Unexpected argument: %s" 'vim:defmotion arg))))
(unless type
(error "%s: Motion type must be specified" 'vim:defmotion))
`(progn
(put ',name 'type ',type)
(put ',name 'count ,count)
(put ',name 'argument ,argument)
(put ',name 'function
(function* (lambda (,@(when params `(&key ,@params))
,@(when named-params `(&aux ,@named-params)))
(vim:do-motion ',type (progn ,@body)))))
(defun* ,name (&rest args)
,doc
(interactive)
(if (vim:called-interactively-p)
(vim:execute-command ',name)
(apply (get ',name 'function) args))))))
(font-lock-add-keywords 'emacs-lisp-mode '("vim:defcmd" "vim:defmotion"))
(defun vim:cmd-count-p (cmd)
"Returns non-nil iff command cmd takes a count."
(get cmd 'count))
(defun vim:cmd-register-p (cmd)
"Returns non-nil iff command may take a register."
(get cmd 'register))
(defun vim:cmd-motion-p (cmd)
"Returns non-nil iff command `cmd' takes a motion parameter."
(get cmd 'motion))
(defun vim:cmd-arg (cmd)
"Returns the type of command's argument."
(get cmd 'argument))
(defun vim:cmd-arg-p (cmd)
"Returns non-nil iff command cmd takes an argument of arbitrary type."
(not (null (get cmd 'argument))))
(defun vim:cmd-text-arg-p (cmd)
"Returns non-nil iff command cmd takes a text argument."
(eq (vim:cmd-arg cmd) t))
(defun vim:cmd-char-arg-p (cmd)
"Returns non-nil iff command cmd takes a char argument."
(eq (vim:cmd-arg cmd) 'char))
(defun vim:cmd-file-arg-p (cmd)
"Returns non-nil iff command cmd takes a file argument."
(eq (vim:cmd-arg cmd) 'file))
(defun vim:cmd-buffer-arg-p (cmd)
"Returns non-nil iff command cmd takes a buffer argument."
(eq (vim:cmd-arg cmd) 'buffer))
(defun vim:cmd-repeatable-p (cmd)
"Returns non-nil iff command cmd is repeatable."
(get cmd 'repeatable))
(defun vim:cmd-keep-visual-p (cmd)
"Returns non-nil iff command cmd should stay in visual mode."
(get cmd 'keep-visual))
(defun vim:cmd-type (cmd)
"Returns the type of command cmd."
(get cmd 'type))
(defun vim:cmd-function (cmd)
"Returns the function of command `cmd'."
(get cmd 'function))
(defmacro vim:apply-save-buffer (&rest args)
"Like `apply' but stores the current buffer."
(let ((ret (gensym)))
`(progn
(save-current-buffer
(let ((,ret (apply ,@args)))
(setq vim:new-buffer (current-buffer))
,ret)))))
(defmacro vim:funcall-save-buffer (&rest args)
"Like `funcall' but stores the current buffer."
(let ((ret (gensym)))
`(progn
(save-current-buffer
(let ((,ret (funcall ,@args)))
(setq vim:new-buffer (current-buffer))
,ret)))))
(defun vim:select-register ()
"Sets the register for the next command."
(interactive)
(setq vim:current-register (read-char-exclusive)))
(defun vim:get-register (register)
"Returns the content of `register', signals error on fail."
(let ((txt (get-register register)))
(unless txt
(error "Register '%c' empty." register))
txt))
(defun vim:execute-command (cmd)
"Executes the vim-command `cmd'.
If an error occures, this function switches back to normal-mode.
Since all vim-mode commands go through this function, this is
the perfect point to do some house-keeping."
(condition-case err
(funcall vim:active-command-function cmd)
(error
(vim:reset-key-state)
(vim:clear-key-sequence)
(vim:adjust-point)
(vim:activate-normal-mode)
(signal (car err) (cdr err)))))
(defun vim:execute-current-motion ()
"Executes the current motion and returns the representing
vim:motion object."
(if (null vim:current-motion)
nil
(let ((cmd vim:current-motion)
(count (if (or vim:current-cmd-count
vim:current-motion-count)
(* (or vim:current-cmd-count 1)
(or vim:current-motion-count 1))
nil))
(parameters nil))
;; build the parameter-list
(when (vim:cmd-char-arg-p cmd)
(push vim:current-motion-arg parameters)
(push :argument parameters))
(when (vim:cmd-count-p cmd)
(push count parameters)
(push :count parameters))
(vim:apply-save-buffer cmd parameters))))
(defun vim:get-current-cmd-motion ()
"Returns the motion range for the current command w.r.t.
command-specific transformations."
(let ((motion (save-excursion (vim:execute-current-motion))))
(when (and (eq (vim:motion-type motion) 'exclusive)
(save-excursion
(goto-char (vim:motion-end-pos motion))
(bolp)))
;; exclusive motions may be modified
(let ((end (vim:adjust-end-of-line-position (1- (vim:motion-end-pos motion)))))
(if (< (vim:motion-begin motion)
(vim:motion-end motion))
(setf (vim:motion-end motion) end)
(setf (vim:motion-begin motion) end)))
(if (save-excursion
(goto-char (vim:motion-begin-pos motion))
(vim:looking-back "^\\s-*"))
;; motion becomes linewise(-exclusive)
(setf (vim:motion-type motion) 'linewise)
;; motion becomes inclusive
(setf (vim:motion-type motion) 'inclusive)))
motion))
(defconst vim:emacs-keymap (vim:make-keymap)
"Keymap for EMACS mode.")
(vim:define-mode emacs "VIM emacs-mode"
:ident "E"
:message "-- EMACS --"
:keymaps '(vim:emacs-keymap)
:command-function 'vim:normal-mode-command)
;; from viper
(defsubst vim:ESC-event-p (event)
(let ((ESC-keys '(?\e (control \[) escape))
(key (event-basic-type event)))
(member key ESC-keys)))
;; from viper
(defun vim:escape-to-emacs (events)
"Executes some `events' in emacs."
(let* ((vim-key-mode nil)
(unread-command-events events)
(keys (read-key-sequence nil))
(event (elt (listify-key-sequence keys) 0)))
(when (vim:ESC-event-p event)
(let ((unread-command-events keys))
(setq keys (read-key-sequence nil))))
(let ((command (key-binding keys)))
(setq this-command command)
(setq last-command-event (elt keys (1- (length keys))))
(setq last-command-char last-command-event)
(command-execute command)
(when (memq command '(digit-argument
universal-argument))
(vim:escape-to-emacs nil)))))
(provide 'vim-vim)
;;; vim-vim.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,328 @@
;;; vim-window.el - Implementation of window commands.
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;;
;; This file is not part of GNU Emacs.
;;; Commentary:
;; This file contains implementations for the window operations.
;; Window operations are usually just simple commands and should not
;; be repeatable.
;;; Code:
(condition-case nil
(require 'windmove)
(error
(message "vim-mode: Could not load 'windmove', window-commands not available.")
nil))
(vim:define-keymap window-mode "window mode" :map-command wmap)
(vim:define-mode window "VIM window mode"
:ident "W"
:keymaps '(vim:window-mode-keymap)
:command-function 'vim:normal-mode-command)
(defun vim:resize-window (new-size &optional horizontal)
"Sets the current window's with or height to `new-size'."
(let ((wincfg (current-window-configuration))
(nwins (length (window-list)))
(count (if horizontal
(- new-size (window-width))
(- new-size (window-height)))))
(catch 'loop
(save-window-excursion
(while (not (zerop count))
(if (> count 0)
(progn (enlarge-window 1 horizontal) (decf count))
(progn
(shrink-window 1 horizontal)
(incf count)))
(if (= nwins (length (window-list)))
(setq wincfg (current-window-configuration))
(throw 'loop t)))))
(set-window-configuration wincfg)))
(defun vim:get-buffer-tree (wintree)
"Extracts the buffer tree from a given window-tree."
(if (consp wintree)
(cons (car wintree) (mapcar #'vim:get-buffer-tree (cddr wintree)))
(window-buffer wintree)))
(defun vim:restore-window-tree (win tree)
"Restores the given buffer-tree layout as subwindows of win."
(cond
((and (consp tree) (cddr tree))
(let ((newwin (split-window win nil (not (car tree)))))
(vim:restore-window-tree win (cadr tree))
(vim:restore-window-tree newwin (cons (car tree) (cddr tree)))))
((consp tree)
(set-window-buffer win (cadr tree)))
(t (set-window-buffer win tree))))
(vim:defcmd vim:window-split (count (argument:file file) nonrepeatable)
"Splits the current window horizontally, `count' lines height, editing a certain `file'."
(let ((new-win (split-window (selected-window) count)))
(when file
(vim:cmd-edit :argument file))))
(vim:defcmd vim:window-vsplit (count (argument:file file) nonrepeatable)
"Splits the current window vertically, `count' columns width, editing a certain `file'."
(let ((new-win (split-window (selected-window) count t)))
(when file
(vim:cmd-edit :argument file))))
(vim:defcmd vim:window-close (nonrepeatable)
"Closes the current window."
(delete-window))
(vim:defcmd vim:window-only (nonrepeatable)
"Closes all but the current window."
(delete-other-windows))
(vim:defcmd vim:window-left (count nonrepeatable)
"Move the cursor to new `count'-th window left of the current one."
(dotimes (i (or count 1))
(windmove-left)))
(vim:defcmd vim:window-right (count nonrepeatable)
"Move the cursor to new `count'-th window right of the current one."
(dotimes (i (or count 1))
(windmove-right)))
(vim:defcmd vim:window-up (count nonrepeatable)
"Move the cursor to new `count'-th window above the current one."
(dotimes (i (or count 1))
(windmove-up)))
(vim:defcmd vim:window-down (count nonrepeatable)
"Move the cursor to new `count'-th window below the current one."
(dotimes (i (or count 1))
(windmove-down)))
(vim:defcmd vim:window-bottom-right (nonrepeatable)
"Move the cursor to bottom-right window."
(do ((success t))
((not success))
(setq success nil)
(condition-case nil
(progn
(windmove-right)
(setq success t))
(error nil))
(condition-case nil
(progn
(windmove-down)
(setq success t))
(error nil))))
(vim:defcmd vim:window-top-left (nonrepeatable)
"Move the cursor to top-left window."
(do ((success t))
((not success))
(setq success nil)
(condition-case nil
(progn
(windmove-left)
(setq success t))
(error nil))
(condition-case nil
(progn
(windmove-up)
(setq success t))
(error nil))))
(vim:defcmd vim:window-lru (nonrepeatable)
"Move the cursor to the previous (last accessed) window."
(select-window (get-lru-window)))
(vim:defcmd vim:window-next (count nonrepeatable)
"Move the cursor to the next window in the cyclic order.
With `count' go to the count-th window in the order starting from
top-left."
(if (not count)
(select-window (next-window))
(vim:window-top-left)
(other-window (1- (or count 1)))))
(vim:defcmd vim:window-prev (count nonrepeatable)
"Move the cursor to the previous window in the cyclic order.
With `count' go to the count-th window in the order starting from
top-left."
(if (not count)
(select-window (previous-window))
(vim:window-top-left)
(other-window (1- (or count 1)))))
(vim:defcmd vim:window-new (count (argument:file file) nonrepeatable)
"Splits the current window horizontally and opens a new buffer or edits a certain `file'."
(split-window (selected-window) count)
(if file
(vim:cmd-edit :argument file)
(let ((buffer (generate-new-buffer "*new*")))
(set-window-buffer (selected-window) buffer)
(with-current-buffer buffer (normal-mode)))))
(vim:defcmd vim:window-vnew (count (argument:file file) nonrepeatable)
"Splits the current window vertically and opens a new buffer name or edits a certain `file'."
(split-window (selected-window) count t)
(if file
(vim:cmd-edit :argument file)
(let ((buffer (generate-new-buffer "*new*")))
(set-window-buffer (selected-window) buffer)
(with-current-buffer buffer (normal-mode)))))
(vim:defcmd vim:window-balance (nonrepeatable)
"Balances all window sizes."
(balance-windows))
(vim:defcmd vim:window-increase-height (count nonrepeatable)
"Increase current window height by `count'."
(vim:resize-window (+ (window-height) (or count 1))))
(vim:defcmd vim:window-decrease-height (count nonrepeatable)
"Decrease current window height by `count'."
(vim:resize-window (- (window-height) (or count 1))))
(vim:defcmd vim:window-increase-width (count nonrepeatable)
"Increase current window width by `count'."
(vim:resize-window (+ (window-width) (or count 1)) t))
(vim:defcmd vim:window-decrease-width (count nonrepeatable)
"Decrease current window width by `count'."
(vim:resize-window (- (window-width) (or count 1)) t))
(vim:defcmd vim:window-set-height (count nonrepeatable)
"Sets the height of the current window to `count'."
(vim:resize-window (or count (frame-height)) nil))
(vim:defcmd vim:window-set-width (count nonrepeatable)
"Sets the width of the current window to `count'."
(vim:resize-window (or count (frame-width)) t))
(vim:defcmd vim:window-rotate-upwards (nonrepeatable)
"Rotates the windows according to the currenty cyclic ordering."
(let ((wlist (window-list))
(blist (mapcar #'(lambda (w) (window-buffer w))
(window-list))))
(setq blist (append (cdr blist) (list (car blist))))
(while (and wlist blist)
(set-window-buffer (car wlist) (car blist))
(setq wlist (cdr wlist)
blist (cdr blist)))
(select-window (car (last (window-list))))))
(vim:defcmd vim:window-rotate-downwards (nonrepeatable)
"Rotates the windows according to the currenty cyclic ordering."
(let ((wlist (window-list))
(blist (mapcar #'(lambda (w) (window-buffer w))
(window-list))))
(setq blist (append (last blist) blist))
(while (and wlist blist)
(set-window-buffer (car wlist) (car blist))
(setq wlist (cdr wlist)
blist (cdr blist)))
(select-window (cadr (window-list)))))
(vim:defcmd vim:window-move-very-top (nonrepeatable)
"Closes the current window, splits the upper-left one horizontally
and redisplays the current buffer there."
(unless (one-window-p)
(let ((b (current-buffer)))
(delete-window)
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
(vim:window-only)
(let ((newwin (selected-window))
(subwin (split-window)))
(vim:restore-window-tree subwin btree)
(set-window-buffer newwin b)
(select-window newwin))))
(balance-windows)))
(vim:defcmd vim:window-move-far-left (nonrepeatable)
"Closes the current window, splits the upper-left one vertically
and redisplays the current buffer there."
(unless (one-window-p)
(let ((b (current-buffer)))
(delete-window)
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
(vim:window-only)
(let ((newwin (selected-window))
(subwin (split-window-horizontally)))
(vim:restore-window-tree subwin btree)
(set-window-buffer newwin b)
(select-window newwin))))
(balance-windows)))
(vim:defcmd vim:window-move-far-right (nonrepeatable)
"Closes the current window, splits the lower-right one vertically
and redisplays the current buffer there."
(unless (one-window-p)
(let ((b (current-buffer)))
(delete-window)
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
(vim:window-only)
(let ((subwin (selected-window))
(newwin (split-window-horizontally)))
(vim:restore-window-tree subwin btree)
(set-window-buffer newwin b)
(select-window newwin))))
(balance-windows)))
(vim:defcmd vim:window-move-very-bottom (nonrepeatable)
"Closes the current window, splits the lower-right one horizontally
and redisplays the current buffer there."
(unless (one-window-p)
(let ((b (current-buffer)))
(delete-window)
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
(vim:window-only)
(let ((subwin (selected-window))
(newwin (split-window)))
(vim:restore-window-tree subwin btree)
(set-window-buffer newwin b)
(select-window newwin))))
(balance-windows)))
(provide 'vim-window)
;;; vim-window.el ends here

223
.emacs.d/vim-mode/vim.el Normal file
View file

@ -0,0 +1,223 @@
;;; vim.el --- a VIM-emulation for Emacs
;; Copyright (C) 2009, 2010 Frank Fischer
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;; Maintainer: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
;; URL: http://www.emacswiki.org/emacs/VimMode
;; License: GPLv2 or later, as described below under "License"
;; Compatibility: Emacs 22, 23, XEmacs 21.4
;; Version: 0.3.0
;; Keywords: emulation, vim
;; Human-Keywords: vim, emacs
;;
;; This file is not part of GNU Emacs.
;;; Acknowledgements:
;; This package contains code from several other packages:
;;
;; - rect-mark.el
;; - viper
;; - vimpulse.el
;; - windmove.el
;;
;; Special thanks go to the authors of those packages.
;;; Commentary:
;; A simple VIM-mode for Emacs
;;
;; This project is in a VERY early development state and many function
;; have not been implemented yet.
;;
;; If you want to try, open this file in your Emacs and evaluate the buffer.
;; The mode can be activated by 'M-x vim-mode'.
;;
;; Don't forget to disable Viper if you want to try vim-mode.
;;
;; The project is divided into many files. Each file implements some
;; almost-independent feature. If you want to learn how to implement
;; new commands or motions, look at the files vim-commands.el and
;; vim-motions.el.
;;
;; Here is a short description of the contents of each file:
;;
;; - vim.el: This file just sets up the mode and loads the other files.
;;
;; - vim-compat.el: Compatibility layer for different Emacsen.
;;
;; - vim-keymap.el: A few functions for defining keymaps for vim-mode.
;;
;; - vim-vim.el: This file contains the macros for defining motions
;; and commands as well as some utility functions for
;; calling them.
;;
;; - vim-modes.el: Each VIM-mode (normal-mode, insert-mode, ...) corresponds
;; to an Emacs-minor-mode. This file contains some macros and
;; functions to define new vim-modes in this context.
;;
;; - vim-insert-mode.el: The implementation of insert-mode.
;;
;; - vim-normal-mode.el: The implementation of normal-mode.
;;
;; - vim-visual-mode.el: The implementation of visual-mode.
;;
;; - vim-ex-mode.el: The implementation of ex-mode.
;;
;; - vim-commands.el: The implementations of commands like 'delete',
;; 'yank', 'paste' and so on.
;;
;; - vim-motions.el: The implementations of motion commands like 'h',
;; 'i', 'j', 'k', 'f', 'w', ...
;;
;; - vim-scroll.el: The implementation of scrolling commands like
;; 'zz', 'Ctrl-F'.
;;
;; - vim-window-el: The implementation of window commands like 'C-w s'.
;;
;; - vim-ex-commands.el: The implementations of commands like ':edit'
;; or ':buffer'.
;;
;; - vim-search.el: The implementation of '/' and ':substitute'.
;;
;; - vim-undo.el: Some variables and functions for undo/redo.
;;
;; - vim-maps.el: The definition of the basic keymaps. This file
;; connects the keymaps with the commands and motions
;; defined in vim-commands.el and vim-motions.el.
;;
;; TODO:
;;
;; HAVE:
;; - framework for keymaps, motions, commands and command-mappings
;; - insert-mode, normal-mode, visual-mode and ex-mode
;; - simple motions
;; - deletion, yank, paste, change, replace
;; - undo/redo
;; - repeat
;;
;; MISSING:
;; - better Emacs integration (modes, buffer local variables, ...)
;; - text objects
;; - several commands
;; - marks and register
;; - ...
;; - several calls 'looking-back' may be inefficient
;;; Code:
(eval-when-compile
(require 'cl))
(defgroup vim-mode nil
"A VIM emulation mode."
:group 'emulations)
(defcustom vim:default-initial-mode
'normal
"The default initial vim sub-mode."
:type '(symbol :tag "vim-mode start mode")
:group 'vim-mode)
(defcustom vim:initial-modes
'((debugger-mode . window)
(compilation-mode . window)
(grep-mode . window)
(gud-mode . window)
(sldb-mode . window)
(slime-repl-mode . window)
(reftex-select-bib-mode . window)
(completion-list-mode . window)
(help-mode . motion)
(Info-mode . motion))
"Associated list of (major-mode . vim:mode) which specifies the
vim sub-mode in which vim-mode should start when a buffer with the
given major-mode is created."
:type '(repeat (cons (symbol :tag "major mode") (symbol :tag "vim-mode start mode")))
:group 'vim-mode)
(defmacro vim:deflocalvar (name &rest args)
"Defines a buffer-local variable."
(declare (indent defun))
`(progn
(defvar ,name ,@args)
(make-variable-buffer-local ',name)))
(font-lock-add-keywords 'emacs-lisp-mode '("vim:deflocalvar"))
(defvar vim:emulation-mode-alist nil
"List of all keymaps used by some modes.")
(let ((load-path (cons (expand-file-name ".") load-path)))
(eval-when-compile
(load "vim-compat")
(load "vim-keymap")
(load "vim-modes")
(load "vim-vim")
(load "vim-normal-mode")
(load "vim-insert-mode")
(load "vim-visual-mode")
(load "vim-commands")
(load "vim-motions")
(load "vim-scroll")
(load "vim-window")
(load "vim-undo")
(load "vim-ex")
(load "vim-ex-commands")
(load "vim-search")
(load "vim-maps"))
(require 'vim-compat)
(require 'vim-keymap)
(require 'vim-modes)
(require 'vim-vim)
(require 'vim-normal-mode)
(require 'vim-insert-mode)
(require 'vim-visual-mode)
(require 'vim-commands)
(require 'vim-motions)
(require 'vim-scroll)
(require 'vim-window)
(require 'vim-undo)
(require 'vim-ex)
(require 'vim-ex-commands)
(require 'vim-search)
(require 'vim-maps))
(define-minor-mode vim-local-mode
"VIM emulation mode."
:lighter " VIM"
:init-value nil
:global nil
(if vim-local-mode
(progn
(make-local-variable 'vim:emulation-mode-alist)
(vim:initialize-keymaps t))
(progn
(vim:initialize-keymaps nil)
(setq global-mode-string
(delq 'vim:mode-string global-mode-string ))
(vim:activate-mode nil))))
(define-globalized-minor-mode vim-mode vim-local-mode vim:initialize)
(defun vim:initialize ()
(unless (vim:minibuffer-p)
(let ((mode (cdr (or (assoc major-mode vim:initial-modes)
(cons t vim:default-initial-mode)))))
(when mode
(setq vim:active-mode nil)
(vim-local-mode 1)
(vim:intercept-ESC-mode 1)
(vim:activate-mode mode)
(unless (memq 'vim:mode-string global-mode-string)
(setq global-mode-string
(append '("" vim:mode-string) (cdr global-mode-string))))))))
(provide 'vim)
;;; vim.el ends here