(in-package :editor) ;; Modes (defmode "Vim Command" :setup-function 'setup-vim-command) (defmode "Vim Insert") (defmode "Vim Operator Pending") (defun setup-vim-command (buffer) (use-buffer buffer (setf *vim-pending-action* (constantly nil) *vim-last-action* #'identity *vim-repeat-multiplier* nil))) (defun mode-p (mode) (and (current-buffer) (find mode (buffer-mode-names (current-buffer)) :test #'string=))) (defun vim-command-mode-p () (mode-p "Vim Command")) (defun vim-operator-pending-mode-p () (mode-p "Vim Operator Pending")) (defcommand "All Vim" (p) "Put all buffers in Vim Command mode." "Put all buffers in Vim Command mode." (declare (ignore p)) (dolist (b *buffer-list*) (when (buffer-pathname b) (use-buffer b (vim-command-mode-command t))))) (defcommand "Vim Command Mode" (p) "Start Vim Command mode" "Start Vim Command mode" (declare (ignore p)) (setf (buffer-minor-mode (current-buffer) "Vim Insert") nil) (setf (buffer-minor-mode (current-buffer) "Vim Operator Pending") nil) (setf (buffer-minor-mode (current-buffer) "Vim Command") t)) (defcommand "Vim Mode" (p) "" "" (vim-command-mode-command p)) (defcommand "Vim Insert Mode" (p) "" "" (declare (ignore p)) (setf (buffer-minor-mode (current-buffer) "Vim Insert") t) (setf (buffer-minor-mode (current-buffer) "Vim Command") nil)) (defcommand "Exit Vim Mode" (p) "Exit Vim Command Mode" "Exit Vim Command Mode" (declare (ignore p)) (dolist (mode '("Vim Command" "Vim Operator Pending" "Vim Insert")) (setf (buffer-minor-mode (current-buffer) mode) nil))) (defcommand "Vim Scroll Window Down" (p) "" "" (scroll-window-down-command (or p 1))) (defcommand "Vim Scroll Window Up" (p) "" "" (scroll-window-up-command (or p 1))) (defcommand "Vim Repeat" (p) "" "" (funcall *vim-last-action* p)) (defcommand "Vim Append Text at End of Line" (p) "" "" (declare (ignore p)) (end-of-line-command nil) (vim-insert-mode-command nil)) (defcommand "Vim Insert Text at Beginning of Line" (p) "" "" (declare (ignore p)) (back-to-indentation-command nil) (vim-insert-mode-command nil)) (defcommand "Vim Open Line Down" (p) "" "" (declare (ignore p)) (line-end (current-point)) (new-line-command nil) (vim-insert-mode-command nil)) (defcommand "Vim Open Line Up" (p) "" "" (declare (ignore p)) (line-start (current-point)) (open-line-command nil) (vim-insert-mode-command nil)) (defcommand "Vim Save All Files" (p) "" "" (declare (ignore p)) (save-all-files-command t)) (defcommand "Vim Save All Files and Exit" (p) "" "" (declare (ignore p)) (save-all-files-command t) (lispworks-tools::confirm-quit-lispworks)) ;; This isn't really the right way (i.e. the Vim way) to do a ;; setting like this. Oh well. #+nil (defcommand "Vim Toggle hlsearch" (p) "" "" (setq v+hlsearch (cond ((not p) (not v+hlsearch)) ((plusp p) t) (t nil))) (if v+hlsearch (highlight-search) (font-lock-fontify-buffer-command nil))) ; (defcommand "Vim Jump To Match" (p) "Currently only works on ()" "" ; (declare (ignore p)) (def-vim-move "Vim Next Line" (p) :linewise :inclusive "" "" (next-line-command p)) (def-vim-move "Vim Next Screen Line" (p) nil :inclusive "" "" (next-line-command p)) (def-vim-move "Vim Previous Line" (p) :linewise :inclusive "" "" (previous-line-command p)) (def-vim-move "Vim Previous Screen Line" (p) nil :inclusive "" "" (previous-line-command p)) (def-vim-move "Vim Backward Character" (p) nil :exclusive "" "" (backward-character-command p)) (def-vim-move "Vim Forward Character" (p) nil :exclusive "" "" (forward-character-command p)) (def-vim-move "Vim Forward Word" (p) nil :exclusive "" "" (forward-word-command (+ (or p 1) 1)) (backward-word-command 1)) (def-vim-move "Vim Backward Word" (p) nil :exclusive "" "" (backward-word-command p)) (def-vim-move "Vim Goto Line or End of File" (p) :linewise :inclusive "" "" (if p (editor::goto-line-command p) (editor::end-of-buffer-command nil))) (def-vim-change "Vim Delete Next Character" (p) "" "" (delete-next-character-command p)) (def-vim-change "Vim Delete Previous Character" (p) "" "" (delete-previous-character-command p)) (def-vim-move "Vim Top of Window" (p) :linewise :inclusive "" "" (top-of-window-command p)) (def-vim-move "Vim Bottom of Window" (p) :linewise :inclusive "" "" (bottom-of-window-command p)) (def-vim-move "Vim Move to Window Line" (p) :linewise :inclusive "" "" (move-to-window-line-command p)) (def-vim-move "Vim Forward Form" (p) nil :exclusive "" "" (forward-form-command p)) (def-vim-move "Vim Backward Form" (p) nil :exclusive "" "" (backward-form-command p)) (def-vim-move "Vim Forward List" (p) nil :exclusive "" "" (forward-list-command p)) (def-vim-move "Vim Backward List" (p) nil :exclusive "" "" (backward-list-command p)) (def-vim-move "Vim Beginning of Line" (p) nil :exclusive "" "" (beginning-of-line-command p)) (def-vim-move "Vim End of Line" (p) nil :exclusive "" "" (end-of-line-command p)) (def-vim-move "Vim Move Over Whole Line" (p) :linewise :exclusive "" "" nil) ; Note: Emacs's kill-region-command does not include the character at the "end" mark. I ; think this just reflects a difference in approach. To Emacs a point lies *between* ; two characters, so if you have 123^456^789 it deletes the "456". To Vim a point lines *on* ; a character, so if you have ; 123456789 ; ^ ^ ; an "exclusive" motion d2l deletes the "45". (def-vim-movement-pending "Vim Delete Motion" (begin end) "" "" ; (format t "~&starting Vim Delete Motion: begin is ~S, end is ~S~%" begin end) (when (point< end begin) (rotatef end begin)) ; (format t "begin is ~S, end is ~S~%" begin end) (when (and (not (linewise)) (not (same-line-p begin end)) (blanks-before begin) (blanks-after end)) (setf (linewise) t)) (when (linewise) (line-start begin) (line-end end) (character-offset end 1)) ; (format t "begin is ~S, end is ~S~%" begin end) (with-point ((after-end end :after-insert)) (unless (linewise) (character-offset after-end 1)) (set-current-mark begin) (move-point (current-point) end) (kill-region-command nil) (move-point (current-point) begin)))