diff --git a/chimera.el b/chimera.el index af0532c..5c3457a 100644 --- a/chimera.el +++ b/chimera.el @@ -3,29 +3,39 @@ name (enter nil :documentation "Primitive mode entry function.") ; this is required (exit nil :documentation "Primitive mode exit function.") ; we don't need to rely on exit being defined + (pre-entry-hook nil) (entry-hook nil) (exit-hook nil) + (post-exit-hook nil) (manage-hooks nil - :documentation "Whether hooks should be managed internally. \ + :documentation "Whether within-mode hooks should be managed internally. \ If not, they are expected to be run by the underlying mode provider \ -(e.g. evil or hydra).")) +(e.g. evil or hydra). Wrapping hooks (pre-entry and post-exit) are \ +always managed by chimera.")) (defvar chimera-evil-states - (list "normal" "insert" "emacs" "visual" "replace")) + (list "normal" "insert" "emacs" "visual" "replace" "word" "line" "char" "symex")) + +(defvar chimera-insertion-states + (list "insert" "emacs")) (defun chimera-enter-mode (mode) "Enter MODE." (interactive) (let ((name (chimera-mode-name mode))) - ;; call a function (perform-entry-actions ...) that - ;; handles any provider-specific jankiness, like checking - ;; for hydras that didn't exit cleanly, and perform their - ;; exit actions (which should be in a dedicated function - ;; that can be called from here as well as the original - ;; spot in the hydra exit lifecycle phase). + ;; TODO: maybe call a function (perform-entry-actions ...) that + ;; handles any provider-specific jankiness, like checking for + ;; hydras that didn't exit cleanly, and perform their exit actions + ;; (which should be in a dedicated function that can be called + ;; from here as well as the original spot in the hydra exit + ;; lifecycle phase). + ;; we're using evil state variables to keep track of state (even + ;; for non-evil backed modes), so ensure that the evil state is + ;; entered here (unless (member name chimera-evil-states) (let ((evil-state-entry (intern (concat "evil-" name "-state")))) (funcall evil-state-entry))) + (run-hooks (chimera-mode-pre-entry-hook mode)) (funcall (chimera-mode-enter mode)) (when (chimera-mode-manage-hooks mode) ;; for now, we rely on evil hooks for all modes (incl. diff --git a/rigpa-activity-mode.el b/rigpa-activity-mode.el index 8ed5efe..68c5cec 100644 --- a/rigpa-activity-mode.el +++ b/rigpa-activity-mode.el @@ -82,6 +82,8 @@ (defvar chimera-activity-mode (make-chimera-mode :name "activity" :enter #'hydra-activity/body + :pre-entry-hook 'chimera-activity-mode-entry-hook + :post-exit-hook 'chimera-activity-mode-exit-hook :entry-hook 'evil-activity-state-entry-hook :exit-hook 'evil-activity-state-exit-hook)) diff --git a/rigpa-application-mode.el b/rigpa-application-mode.el index 1fdfd66..9dc8616 100644 --- a/rigpa-application-mode.el +++ b/rigpa-application-mode.el @@ -117,6 +117,8 @@ (defvar chimera-application-mode (make-chimera-mode :name "application" :enter #'hydra-application/body + :pre-entry-hook 'chimera-application-mode-entry-hook + :post-exit-hook 'chimera-application-mode-exit-hook :entry-hook 'evil-application-state-entry-hook :exit-hook 'evil-application-state-exit-hook)) diff --git a/rigpa-buffer-mode.el b/rigpa-buffer-mode.el index 9cf544c..82b3043 100644 --- a/rigpa-buffer-mode.el +++ b/rigpa-buffer-mode.el @@ -198,6 +198,8 @@ current ('original') buffer." (defvar chimera-buffer-mode (make-chimera-mode :name "buffer" :enter #'hydra-buffer/body + :pre-entry-hook 'chimera-buffer-mode-entry-hook + :post-exit-hook 'chimera-buffer-mode-exit-hook :entry-hook 'evil-buffer-state-entry-hook :exit-hook 'evil-buffer-state-exit-hook)) diff --git a/rigpa-char-mode.el b/rigpa-char-mode.el index 6d6a9e3..ecee3a8 100644 --- a/rigpa-char-mode.el +++ b/rigpa-char-mode.el @@ -1,13 +1,17 @@ (require 'chimera) -(require 'chimera-hydra) +(require 'rigpa-evil-support) + +(defvar rigpa-char-mode-map (make-sparse-keymap)) + +(define-minor-mode rigpa-char-mode + "Minor mode to modulate keybindings in rigpa char mode." + :lighter "char" + :keymap rigpa-char-mode-map) (evil-define-state char "Char state." :tag " " :message "-- CHAR --" - ;;:cursor ;; inherit from normal - ;;:exit-hook ;; none - ;;:suppress-keymap) ;; should be t, but probably inherits from normal :enable (normal)) (defun rigpa-char-info () @@ -15,68 +19,91 @@ (interactive) (what-cursor-position)) -(defun rigpa-char-delete () - "Delete character" +(evil-define-command rigpa-char-move-left (count) + "Move character left." + (interactive "p") + (forward-char) + (transpose-chars (- count)) + (backward-char)) + +(defun rigpa-char-move-left-more () + "Move character left more." + (interactive) + (rigpa-char-move-left 3)) + +(defun rigpa-char-move-left-most () + "Move character left most." + (interactive) + (evil-delete-char (point) (1+ (point))) + (beginning-of-line) + (evil-paste-before nil nil) + (backward-char)) + +(evil-define-command rigpa-char-move-right (count) + "Move character right." + (interactive "p") + (forward-char) + (transpose-chars count) + (backward-char)) + +(defun rigpa-char-move-right-more () + "Move character right more." (interactive) - (evil-delete-char (point) - (+ (point) 1) - (quote exclusive) nil)) + (rigpa-char-move-right 3)) -;; TODO: seems to vary depending on the value of evil-move-cursor-back -(defun rigpa-char-move-left (&optional superlative) - "Move character left" +(defun rigpa-char-move-right-most () + "Move character right most." (interactive) - (when (not (bolp)) - (rigpa-char-delete) - (let ((at-eol (eolp))) - (cond ((eq superlative nil) (evil-backward-char)) - ((eq superlative 'more) (evil-backward-char 3)) - ((eq superlative 'most) (evil-beginning-of-line))) - (if at-eol - ;; for some reason delete-char doesn't update point - ;; while in hydra at EOL, so the handling here - ;; is different than it otherwise would be - (if (bolp) - (evil-paste-before nil nil) - (progn (evil-paste-after nil nil) - (backward-char))) - (evil-paste-before nil nil))))) - -(defun rigpa-char-move-right (&optional superlative) - "Move character right" + (evil-delete-char (point) (1+ (point))) + (end-of-line) + (evil-paste-after nil nil)) + +(evil-define-command rigpa-char-move-down (count) + "Move character down." + (interactive "p") + (evil-delete-char (point) (1+ (point))) + (evil-next-line count) + (evil-paste-before nil nil) + (backward-char)) + +(defun rigpa-char-move-down-more () + "Move character down more." + (interactive) + (rigpa-char-move-down 3)) + +(defun rigpa-char-move-down-most () + "Move character down most." (interactive) - (when (not (eolp)) - (rigpa-char-delete) - (cond ((eq superlative 'more) - (condition-case nil - (evil-forward-char 2) - (error nil))) - ((eq superlative 'most) (evil-end-of-line))) - (evil-paste-after nil nil) - ;; Note: The above is sufficient when this command is run - ;; interactively via M-x. But when run via the hydra, it - ;; moves point forward an extra character. Not sure why this - ;; happens but since hydra is the main entry point to this, - ;; adding the line below for usage via hydra. + (let ((orig-column (current-column))) + (evil-delete-char (point) (1+ (point))) + (goto-char (nth 1 (evil-inner-paragraph))) + (evil-previous-line) + (evil-goto-column orig-column) + (evil-paste-before nil nil) (backward-char))) -(defun rigpa-char-move-down (&optional superlative) - "Move character down" +(evil-define-command rigpa-char-move-up (count) + "Move character up." + (interactive "p") + (evil-delete-char (point) (1+ (point))) + (evil-previous-line count) + (evil-paste-before nil nil) + (backward-char)) + +(defun rigpa-char-move-up-more () + "Move character up more." (interactive) - (rigpa-char-delete) - (cond ((eq superlative nil) (evil-next-line)) - ((eq superlative 'more) (evil-next-line 3)) - ((eq superlative 'most) (evil-forward-paragraph))) - (evil-paste-before nil nil)) - -(defun rigpa-char-move-up (&optional superlative) - "Move character up" + (rigpa-char-move-up 3)) + +(defun rigpa-char-move-up-most () + "Move character up most." (interactive) - (rigpa-char-delete) - (cond ((eq superlative nil) (evil-previous-line)) - ((eq superlative 'more) (evil-previous-line 3)) - ((eq superlative 'most) (evil-backward-paragraph))) - (evil-paste-before nil nil)) + (let ((orig-column (current-column))) + (evil-delete-char (point) (1+ (point))) + (goto-char (nth 0 (evil-inner-paragraph))) + (evil-goto-column orig-column) + (evil-paste-before nil nil) + (backward-char))) (defun rigpa-char-change () "Change character" @@ -86,72 +113,62 @@ (quote exclusive) nil)) -(defun rigpa-char-yank () +(evil-define-operator rigpa-char-yank (beg end type register yank-handler) "Yank (copy) character" - (interactive) - (evil-yank-characters (point) (+ (point) 1))) - -(defun rigpa-char-toggle-case () - "Toggle upper-/lower-case" - (interactive) - (evil-invert-char (point) (+ (point) 1) (quote exclusive))) - -(defhydra hydra-char (:columns 4 - :post (chimera-hydra-portend-exit chimera-char-mode t) - :after-exit (chimera-hydra-signal-exit chimera-char-mode - #'chimera-handle-hydra-exit)) - "Character mode" - ("h" evil-backward-char "left") - ("j" evil-next-line "down") - ("k" evil-previous-line "up") - ("l" evil-forward-char "right") - ("C-h" (lambda () - (interactive) - (evil-backward-char 3)) "more left") - ("C-j" (lambda () - (interactive) - (evil-next-line 3)) "more down") - ("C-k" (lambda () - (interactive) - (evil-previous-line 3)) "more up") - ("C-l" (lambda () - (interactive) - (evil-forward-char 3)) "more right") - ("M-h" (lambda () - (interactive) - (evil-beginning-of-line)) "most left") - ("M-j" (lambda () - (interactive) - (evil-forward-paragraph) - (evil-previous-line)) "most down") - ("M-k" (lambda () - (interactive) - (evil-backward-paragraph) - (evil-next-line)) "most up") - ("M-l" (lambda () - (interactive) - (evil-end-of-line)) "most right") - ("H" rigpa-char-move-left "move left") - ("J" rigpa-char-move-down "move down") - ("K" rigpa-char-move-up "move up") - ("L" rigpa-char-move-right "move right") - ("C-S-h" (lambda () (interactive) (rigpa-char-move-left 'more)) "move left more") - ("C-S-j" (lambda () (interactive) (rigpa-char-move-down 'more)) "move down more") - ("C-S-k" (lambda () (interactive) (rigpa-char-move-up 'more)) "move up more") - ("C-S-l" (lambda () (interactive) (rigpa-char-move-right 'more)) "move right more") - ("M-H" (lambda () (interactive) (rigpa-char-move-left 'most)) "move to far left") - ("M-J" (lambda () (interactive) (rigpa-char-move-down 'most)) "move to bottom") - ("M-K" (lambda () (interactive) (rigpa-char-move-up 'most)) "move to top") - ("M-L" (lambda () (interactive) (rigpa-char-move-right 'most)) "move to far right") - ("c" rigpa-char-change "change" :exit t) - ("y" rigpa-char-yank "yank (copy)" :exit t) - ("x" rigpa-char-delete "delete") - ("~" rigpa-char-toggle-case "toggle case") - ("i" rigpa-char-info "info" :exit t) - ("?" rigpa-char-info "info" :exit t) - ("H-m" rigpa-toggle-menu "show/hide this menu") - ("" rigpa-enter-lower-level "enter lower level" :exit t) - ("" rigpa-enter-higher-level "escape to higher level" :exit t)) + :motion evil-forward-char + (evil-yank beg end type register yank-handler)) + +(defvar rigpa--char-mode-keyspec + '(("h" . evil-backward-char) + ("j" . evil-next-line) + ("k" . evil-previous-line) + ("l" . evil-forward-char) + ("c" . evil-substitute) + ("y" . rigpa-char-yank) + ("C-h" . (lambda () + (interactive) + (evil-backward-char 3))) + ("C-j" . (lambda () + (interactive) + (evil-next-line 3))) + ("C-k" . (lambda () + (interactive) + (evil-previous-line 3))) + ("C-l" . (lambda () + (interactive) + (evil-forward-char 3))) + ("M-h" . (lambda () + (interactive) + (evil-beginning-of-line))) + ("M-j" . (lambda () + (interactive) + (evil-forward-paragraph) + (evil-previous-line))) + ("M-k" . (lambda () + (interactive) + (evil-backward-paragraph) + (evil-next-line))) + ("M-l" . (lambda () + (interactive) + (evil-end-of-line))) + ("H" . rigpa-char-move-left) + ("J" . rigpa-char-move-down) + ("K" . rigpa-char-move-up) + ("L" . rigpa-char-move-right) + ("?" . rigpa-char-info) + ("C-S-h" . rigpa-char-move-left-more) + ("C-S-j" . rigpa-char-move-down-more) + ("C-S-k" . rigpa-char-move-up-more) + ("C-S-l" . rigpa-char-move-right-more) + ("M-H" . rigpa-char-move-left-most) + ("M-J" . rigpa-char-move-down-most) + ("M-K" . rigpa-char-move-up-most) + ("M-L" . rigpa-char-move-right-most)) + "Key specification for rigpa char mode.") + +(rigpa--define-evil-keys-from-spec rigpa--char-mode-keyspec + rigpa-char-mode-map + 'char) (defvar chimera-char-mode-entry-hook nil "Entry hook for rigpa char mode.") @@ -159,9 +176,19 @@ (defvar chimera-char-mode-exit-hook nil "Exit hook for rigpa char mode.") +(defun rigpa--enable-char-minor-mode () + "Enable char minor mode." + (rigpa-char-mode 1)) + +(defun rigpa--disable-char-minor-mode () + "Disable char minor mode." + (rigpa-char-mode -1)) + (defvar chimera-char-mode (make-chimera-mode :name "char" - :enter #'hydra-char/body + :enter #'evil-char-state + :pre-entry-hook 'chimera-char-mode-entry-hook + :post-exit-hook 'chimera-char-mode-exit-hook :entry-hook 'evil-char-state-entry-hook :exit-hook 'evil-char-state-exit-hook)) diff --git a/rigpa-evil-support.el b/rigpa-evil-support.el new file mode 100644 index 0000000..34fe4c3 --- /dev/null +++ b/rigpa-evil-support.el @@ -0,0 +1,18 @@ +(defun rigpa--define-evil-key (key fn map state) + "Define an evil keybinding in an evil-backed rigpa mode." + (evil-define-key (list state 'visual 'operator) + map + (kbd key) + fn)) + +(defun rigpa--define-evil-keys-from-spec (keyspec keymap state) + "Define evil keys from a specification." + (dolist (keybinding keyspec) + (rigpa--define-evil-key (car keybinding) + (cdr keybinding) + keymap + state))) + + +(provide 'rigpa-evil-support) +;;; rigpa-evil-support.el ends here diff --git a/rigpa-file-mode.el b/rigpa-file-mode.el index 48b45dd..cb76e67 100644 --- a/rigpa-file-mode.el +++ b/rigpa-file-mode.el @@ -67,6 +67,8 @@ Version 2016-04-04" (defvar chimera-file-mode (make-chimera-mode :name "file" :enter #'hydra-file/body + :pre-entry-hook 'chimera-file-mode-entry-hook + :post-exit-hook 'chimera-file-mode-exit-hook :entry-hook 'evil-file-state-entry-hook :exit-hook 'evil-file-state-exit-hook)) diff --git a/rigpa-history-mode.el b/rigpa-history-mode.el index e29f951..b2f6c72 100644 --- a/rigpa-history-mode.el +++ b/rigpa-history-mode.el @@ -34,6 +34,8 @@ (defvar chimera-history-mode (make-chimera-mode :name "history" :enter #'hydra-history/body + :pre-entry-hook 'chimera-history-mode-entry-hook + :post-exit-hook 'chimera-history-mode-exit-hook :entry-hook 'evil-history-state-entry-hook :exit-hook 'evil-history-state-exit-hook)) diff --git a/rigpa-line-mode.el b/rigpa-line-mode.el index a2b1cbd..96b5265 100644 --- a/rigpa-line-mode.el +++ b/rigpa-line-mode.el @@ -8,7 +8,14 @@ ;; similarly for "region-mode", possibly by invoking multiple cursors (require 'chimera) -(require 'chimera-hydra) +(require 'rigpa-evil-support) + +(defvar rigpa-line-mode-map (make-sparse-keymap)) + +(define-minor-mode rigpa-line-mode + "Minor mode to modulate keybindings in rigpa line mode." + :lighter "line" + :keymap rigpa-line-mode-map) (evil-define-state line "Line state." @@ -16,33 +23,30 @@ :message "-- LINE --" :enable (normal)) -(defun rigpa-line-move-down (&optional count) +(evil-define-command rigpa-line-move-down (count) "Move line down" - (interactive) + (interactive "p") (unless (save-excursion (end-of-line) (or (eobp) (save-excursion (evil-next-line) (eobp)))) - (unless count (setq count 1)) (evil-next-line) (transpose-lines count) (evil-previous-line))) -(defun rigpa-line-move-up (&optional count) +(evil-define-command rigpa-line-move-up (count) "Move line up" - (interactive) - (unless (save-excursion (beginning-of-line) - (bobp)) - (unless count (setq count 1)) - (transpose-lines count) - (evil-previous-line 2))) + (interactive "p") + (dotimes (i count) + (unless (= 1 (line-number-at-pos)) + (transpose-lines 1) + (evil-previous-line 2)))) -(defun rigpa-line-move-left (&optional count) +(evil-define-command rigpa-line-move-left (count) "Move line left" - (interactive) - (unless count (setq count 1)) + (interactive "p") (save-excursion (evil-first-non-blank) (setq starting-from (- (point) count)) @@ -54,10 +58,9 @@ 'exclusive nil))) -(defun rigpa-line-move-right (&optional count) +(evil-define-command rigpa-line-move-right (count) "Move line right" - (interactive) - (unless count (setq count 1)) + (interactive "p") (save-excursion (evil-first-non-blank) (insert-char #x20 count))) @@ -99,17 +102,10 @@ (evil-execute-in-normal-state) (execute-kbd-macro (kbd ":.m0"))) -(defun rigpa-line-delete () - "Delete line" - (interactive) - (let* ((line-start-position (line-beginning-position)) - (line-end-position (if (eobp) - (line-end-position) - (1+ (line-end-position))))) - (evil-delete-whole-line line-start-position - line-end-position - (quote line) - nil))) +(evil-define-operator rigpa-line-delete (beg end type register yank-handler) + "Delete line." + :motion evil-line + (evil-delete beg end type register yank-handler)) (defun rigpa-line-flashback () "Flashback to prev line" @@ -119,15 +115,16 @@ (defun rigpa-line-split () "Split line on word separators" (interactive) - (evil-beginning-of-line) - (while (not (eolp)) - (unless (equal (- (line-end-position) - (line-beginning-position)) - 1) - (evil-forward-word-end)) - (execute-kbd-macro (kbd "a")) - (newline) - (evil-force-normal-state))) + (with-undo-collapse + (evil-beginning-of-line) + (while (not (eolp)) + (unless (equal (- (line-end-position) + (line-beginning-position)) + 1) + (evil-forward-word-end)) + (execute-kbd-macro (kbd "a")) + (newline) + (evil-force-normal-state)))) (defun rigpa-line-pulverize () "Split on every character" @@ -154,63 +151,49 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- (setq current-line-length (line-length current-line-number)) (message "Line %d, length = %d" current-line-number current-line-length)) -(defun rigpa-line-toggle-comment () +(evil-define-command rigpa-line-toggle-comment (count) "Comment / uncomment line" - (interactive) - (comment-line 1)) + (interactive "p") + (comment-line count)) -(defun rigpa-line-yank () +(evil-define-operator rigpa-line-yank (beg end type register yank-handler) "Yank (copy) line" - (interactive) - (evil-yank-line (line-beginning-position) (line-end-position) 'line nil)) + :motion evil-line + (evil-yank-line beg end type register)) -(defun rigpa-line-change () - "Change line" - (interactive) - (evil-change-whole-line (line-beginning-position) - (+ 1 (line-end-position)) - (quote line) - nil)) +(evil-define-operator rigpa-line-change (beg end type register yank-handler) + "Change line." + :motion evil-line + (evil-change beg end type register yank-handler)) -(defun rigpa-line-indent-left () - "Reduce line indent" - (interactive) - (indent-rigidly-left-to-tab-stop (line-beginning-position) - (line-end-position))) +(evil-define-operator rigpa-line-indent (beg end type register yank-handler) + "Indent line" + :motion evil-line + (evil-indent beg end)) -(defun rigpa-line-indent-right () - "Increase line indent" - (interactive) - (indent-rigidly-right-to-tab-stop (line-beginning-position) - (line-end-position))) - -(defun rigpa-line-insert-newline () +(evil-define-command rigpa-line-insert-newline (count) "Insert newline and reindent." - (interactive) - (save-excursion - (beginning-of-line) - (newline-and-indent))) + (interactive "p") + (if (bolp) + (newline-and-indent count) + (save-excursion + (beginning-of-line) + (newline-and-indent count)))) -(defun rigpa-line-append-newline () +(evil-define-command rigpa-line-append-newline (count) "Append newline and reindent." - (interactive) + (interactive "p") (save-excursion (forward-line) - (newline-and-indent))) + (newline-and-indent count))) -(defun rigpa-line-join (&optional backwards) - "Join lines." - (interactive) +(evil-define-command rigpa-line-join-backwards (count) + "Join lines backwards." + (interactive "p") (save-excursion - (if backwards - (progn (evil-previous-line) - (if (current-line-empty-p) - (evil-join (line-beginning-position) - (1+ (line-beginning-position))) - (evil-join (line-beginning-position) - (line-end-position)))) - (evil-join (line-beginning-position) - (line-end-position))))) + (evil-previous-line count) + (let ((current-prefix-arg count)) + (call-interactively #'evil-join)))) (defun rigpa-line-top () (interactive) @@ -228,53 +211,49 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- (interactive) (evil-previous-line 9)) -(defhydra hydra-line (:columns 4 - :post (chimera-hydra-portend-exit chimera-line-mode t) - :after-exit (chimera-hydra-signal-exit chimera-line-mode - #'chimera-handle-hydra-exit)) - "Line mode" - ("h" evil-previous-line "previous") - ("j" evil-next-line "next") - ("k" evil-previous-line "previous") - ("l" evil-next-line "next") - ("C-j" rigpa-line-jump-down "jump down") - ("C-k" rigpa-line-jump-up "jump up") - ("M-j" rigpa-line-top "top line") - ("M-k" rigpa-line-bottom "bottom line") - ("H" rigpa-line-move-left "move left") - ("J" rigpa-line-move-down "move down") - ("K" rigpa-line-move-up "move up") - ("L" rigpa-line-move-right "move right") - ("C-." rigpa-line-indent-right "indent right") - ("C-," rigpa-line-indent-left "indent left") - ("M-H" rigpa-line-move-far-left "move to far left") - ("M-J" rigpa-line-move-very-bottom "move to bottom") - ("M-K" rigpa-line-move-very-top "move to top") - ("M-L" rigpa-line-move-far-right "move to far right") - ("x" rigpa-line-delete "delete") - ("c" rigpa-line-change "change") - ("s-l" indent-according-to-mode "autoindent") - ("'" rigpa-line-flashback "flashback") - ("s" rigpa-line-split "split by word") - ("v" rigpa-line-pulverize "pulverize") - ("y" rigpa-line-yank "yank (copy)") - ("p" evil-paste-after "paste after") - ("P" evil-paste-before "paste before") - ("+" evil-open-above "add new line") - ("i" evil-open-above "add new line") - ("a" evil-open-below "add new line below") - ("n" rigpa-line-insert-newline "insert newline") - ("C-S-o" rigpa-line-append-newline "append newline") - ("o" rigpa-line-join "join") - ("O" (lambda () - (interactive) - (rigpa-line-join t)) - "join backwards") - (";" rigpa-line-toggle-comment "toggle comment") - ("?" rigpa-line-info "info" :exit t) - ("H-m" rigpa-toggle-menu "show/hide this menu") - ("" rigpa-enter-lower-level "enter lower level" :exit t) - ("" rigpa-enter-higher-level "escape to higher level" :exit t)) +(defvar rigpa--line-mode-keyspec + '(("h" . evil-previous-line) + ("j" . evil-next-line) + ("k" . evil-previous-line) + ("l" . evil-next-line) + ("C-j" . rigpa-line-jump-down) + ("C-k" . rigpa-line-jump-up) + ("M-j" . rigpa-line-top) + ("M-k" . rigpa-line-bottom) + ("H" . rigpa-line-move-left) + ("J" . rigpa-line-move-down) + ("K" . rigpa-line-move-up) + ("L" . rigpa-line-move-right) + ("" . rigpa-line-indent) + ("s-l" . rigpa-line-indent) + (">" . evil-shift-right-line) + ("<" . evil-shift-left-line) + ("M-H" . rigpa-line-move-far-left) + ("M-J" . rigpa-line-move-very-bottom) + ("M-K" . rigpa-line-move-very-top) + ("M-L" . rigpa-line-move-far-right) + ("x" . rigpa-line-delete) + ("c" . rigpa-line-change) + ("y" . rigpa-line-yank) + ("p" . evil-paste-after) + ("P" . evil-paste-before) + ("'" . rigpa-line-flashback) + ("s" . rigpa-line-split) + ("v" . rigpa-line-pulverize) + ("+" . evil-open-above) + ("i" . evil-open-above) + ("a" . evil-open-below) + ("n" . rigpa-line-insert-newline) + ("C-S-o" . rigpa-line-append-newline) + ("o" . evil-join) + ("O" . rigpa-line-join-backwards) + (";" . rigpa-line-toggle-comment) + ("?" . rigpa-line-info)) + "Key specification for rigpa line mode.") + +(rigpa--define-evil-keys-from-spec rigpa--line-mode-keyspec + rigpa-line-mode-map + 'line) (defvar chimera-line-mode-entry-hook nil "Entry hook for rigpa line mode.") @@ -282,9 +261,19 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- (defvar chimera-line-mode-exit-hook nil "Exit hook for rigpa line mode.") +(defun rigpa--enable-line-minor-mode () + "Enable line minor mode." + (rigpa-line-mode 1)) + +(defun rigpa--disable-line-minor-mode () + "Disable line minor mode." + (rigpa-line-mode -1)) + (defvar chimera-line-mode (make-chimera-mode :name "line" - :enter #'hydra-line/body + :enter #'evil-line-state + :pre-entry-hook 'chimera-line-mode-entry-hook + :post-exit-hook 'chimera-line-mode-exit-hook :entry-hook 'evil-line-state-entry-hook :exit-hook 'evil-line-state-exit-hook)) diff --git a/rigpa-mode-mode.el b/rigpa-mode-mode.el index 79fc420..aea1157 100644 --- a/rigpa-mode-mode.el +++ b/rigpa-mode-mode.el @@ -15,23 +15,68 @@ (defvar rigpa-modes (ht)) +(defun rigpa--minor-mode-enable-hook (name) + "Return a function to enable the minor mode for the mode named NAME. + +We modulate keybindings in evil states (e.g. in particular visual and +operator states) via a minor mode. As it looks like this only works if +the minor mode is activated *before* entering the evil state, we need +to define pre-entry hooks at the chimera level and can't just use the +evil entry hooks. + +We need this extra layer of indirection because lambdas as hooks +can't be removed since they are anonymous. This just gives us a way +to parametrize the hook but still be able to remove it." + (let ((enable-mode + (intern + (concat "rigpa--enable-" name "-minor-mode")))) + enable-mode)) + +(defun rigpa--disable-other-minor-modes () + "Disable all rigpa mode minor modes. + +This is called on state transitions to ensure that all minor modes are +first disabled prior to the minor mode for new state being enabled." + (dolist (name (ht-keys rigpa-modes)) + (let ((disable-mode + (intern + (concat "rigpa--disable-" name "-minor-mode")))) + (when (fboundp disable-mode) + (funcall disable-mode))))) + (defun rigpa-register-mode (mode) - "Register MODE-NAME for use with rigpa." + "Register MODE for use with rigpa. + +This registers callbacks with the hooks provided by the chimera MODE +to ensure, upon state transitions, that: +(1) the correct state is reflected, +(2) any lingering config from prior states is cleaned, and +(3) the previous state is remembered for possible recall." (let ((name (chimera-mode-name mode)) + (pre-entry-hook (chimera-mode-pre-entry-hook mode)) (entry-hook (chimera-mode-entry-hook mode)) (exit-hook (chimera-mode-exit-hook mode))) (ht-set! rigpa-modes name mode) - (add-hook exit-hook #'rigpa-remember-for-recall) - (add-hook entry-hook #'rigpa-reconcile-level))) + (let ((minor-mode-entry (rigpa--minor-mode-enable-hook name))) + (when (fboundp minor-mode-entry) + (add-hook pre-entry-hook minor-mode-entry))) + (add-hook entry-hook #'rigpa-reconcile-level) + (add-hook pre-entry-hook #'rigpa--disable-other-minor-modes) + (add-hook exit-hook #'rigpa-remember-for-recall))) (defun rigpa-unregister-mode (mode) - "Unregister MODE-NAME." + "Unregister MODE." (let ((name (chimera-mode-name mode)) + (pre-entry-hook (chimera-mode-pre-entry-hook mode)) (entry-hook (chimera-mode-entry-hook mode)) (exit-hook (chimera-mode-exit-hook mode))) (ht-remove! rigpa-modes name) - (remove-hook exit-hook #'rigpa-remember-for-recall) - (remove-hook entry-hook #'rigpa-reconcile-level))) + (let ((minor-mode-entry (rigpa--minor-mode-enable-hook name))) + (when (fboundp minor-mode-entry) + (remove-hook pre-entry-hook minor-mode-entry))) + (remove-hook entry-hook #'rigpa-reconcile-level) + (remove-hook pre-entry-hook #'rigpa--disable-other-minor-modes) + (remove-hook exit-hook #'rigpa-remember-for-recall))) (defun rigpa-enter-mode (mode-name) "Enter mode MODE-NAME." @@ -233,17 +278,30 @@ is precisely the thing to be done." (rigpa--tower-view-narrow (rigpa--ground-tower)) (rigpa--tower-view-reflect-ground (rigpa--ground-tower))))) +(defun rigpa--reload-tower-wrapper (orig-fn count &rest args) + "Wrap interactive commands and reload the tower. + +For interactive commands accepting a count argument, we can't use just +any function as advice since the underying command expects to receive +an interactive argument from the user. The advising function needs to +be interactive itself." + (interactive "p") + (let ((result (apply orig-fn count args))) + (rigpa--reload-tower) + result)) + (defun rigpa--add-meta-side-effects () "Add side effects for primitive mode operations while in meta mode." - ;; this should lookup the appropriate side-effect based on the coordinates - (advice-add #'rigpa-line-move-down :after #'rigpa--reload-tower) - (advice-add #'rigpa-line-move-up :after #'rigpa--reload-tower) + ;; this should lookup the appropriate side-effect based on the + ;; coordinates and the ground level mode being employed + (advice-add #'rigpa-line-move-down :around #'rigpa--reload-tower-wrapper) + (advice-add #'rigpa-line-move-up :around #'rigpa--reload-tower-wrapper) (advice-add #'rigpa-line-change :around #'rigpa--mode-mode-change)) (defun rigpa--remove-meta-side-effects () "Remove side effects for primitive mode operations that were added for meta modes." - (advice-remove #'rigpa-line-move-down #'rigpa--reload-tower) - (advice-remove #'rigpa-line-move-up #'rigpa--reload-tower) + (advice-remove #'rigpa-line-move-down #'rigpa--reload-tower-wrapper) + (advice-remove #'rigpa-line-move-up #'rigpa--reload-tower-wrapper) (advice-remove #'rigpa-line-change #'rigpa--mode-mode-change)) ;; TODO: should have a single function that enters diff --git a/rigpa-symex-mode.el b/rigpa-symex-mode.el index 48c1803..fd76e54 100644 --- a/rigpa-symex-mode.el +++ b/rigpa-symex-mode.el @@ -6,9 +6,19 @@ (defvar chimera-symex-mode-exit-hook nil "Exit hook for rigpa symex mode.") +(defun rigpa--enable-symex-minor-mode () + "Enable symex minor mode." + (symex-enable-editing-minor-mode)) + +(defun rigpa--disable-symex-minor-mode () + "Disable symex minor mode." + (symex-disable-editing-minor-mode)) + (defvar chimera-symex-mode (make-chimera-mode :name "symex" :enter #'symex-mode-interface + :pre-entry-hook 'chimera-symex-mode-entry-hook + :post-exit-hook 'chimera-symex-mode-exit-hook :entry-hook 'evil-symex-state-entry-hook :exit-hook 'evil-symex-state-exit-hook)) diff --git a/rigpa-system-mode.el b/rigpa-system-mode.el index c4d0507..1cdb9cd 100644 --- a/rigpa-system-mode.el +++ b/rigpa-system-mode.el @@ -33,6 +33,8 @@ (defvar chimera-system-mode (make-chimera-mode :name "system" :enter #'hydra-system/body + :pre-entry-hook 'chimera-system-mode-entry-hook + :post-exit-hook 'chimera-system-mode-exit-hook :entry-hook 'evil-system-state-entry-hook :exit-hook 'evil-system-state-exit-hook)) diff --git a/rigpa-tab-mode.el b/rigpa-tab-mode.el index 6da831e..a532a2e 100644 --- a/rigpa-tab-mode.el +++ b/rigpa-tab-mode.el @@ -106,6 +106,8 @@ buffer mode." (defvar chimera-tab-mode (make-chimera-mode :name "tab" :enter #'hydra-tab/body + :pre-entry-hook 'chimera-tab-mode-entry-hook + :post-exit-hook 'chimera-tab-mode-exit-hook :entry-hook 'evil-tab-state-entry-hook :exit-hook 'evil-tab-state-exit-hook)) diff --git a/rigpa-text-mode.el b/rigpa-text-mode.el index 104769d..cbc9a44 100644 --- a/rigpa-text-mode.el +++ b/rigpa-text-mode.el @@ -29,6 +29,8 @@ (defvar chimera-text-mode (make-chimera-mode :name "text" :enter #'hydra-text/body + :pre-entry-hook 'chimera-text-mode-entry-hook + :post-exit-hook 'chimera-text-mode-exit-hook :entry-hook 'evil-text-state-entry-hook :exit-hook 'evil-text-state-exit-hook)) diff --git a/rigpa-view-mode.el b/rigpa-view-mode.el index 0193b16..f4efffa 100644 --- a/rigpa-view-mode.el +++ b/rigpa-view-mode.el @@ -152,6 +152,8 @@ (defvar chimera-view-mode (make-chimera-mode :name "view" :enter #'hydra-view/body + :pre-entry-hook 'chimera-view-mode-entry-hook + :post-exit-hook 'chimera-view-mode-exit-hook :entry-hook 'evil-view-state-entry-hook :exit-hook 'evil-view-state-exit-hook)) diff --git a/rigpa-window-mode.el b/rigpa-window-mode.el index e0b36b5..bff37a2 100644 --- a/rigpa-window-mode.el +++ b/rigpa-window-mode.el @@ -220,6 +220,8 @@ positions." (defvar chimera-window-mode (make-chimera-mode :name "window" :enter #'hydra-window/body + :pre-entry-hook 'chimera-window-mode-entry-hook + :post-exit-hook 'chimera-window-mode-exit-hook :entry-hook 'evil-window-state-entry-hook :exit-hook 'evil-window-state-exit-hook)) diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index 96e047a..8ef2680 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -1,5 +1,12 @@ (require 'chimera) -(require 'chimera-hydra) +(require 'rigpa-evil-support) + +(defvar rigpa-word-mode-map (make-sparse-keymap)) + +(define-minor-mode rigpa-word-mode + "Minor mode to modulate keybindings in rigpa word mode." + :lighter "word" + :keymap rigpa-word-mode-map) (evil-define-state word "Word state." @@ -7,134 +14,188 @@ :message "-- WORD --" :enable (normal)) -(defun rigpa-word-move-backward () - "Move word backwards" - (interactive) - (evil-inner-word nil nil nil nil) - (evil-backward-WORD-begin nil) - (transpose-words 1) - (evil-backward-WORD-begin 2)) +(evil-define-motion rigpa-word-backward (count) + "Motion for moving backward by a word." + :type exclusive + (let ((count (or count 1))) + (evil-backward-WORD-begin count))) -(defun rigpa-word-move-forward () - "Move word forward" - (interactive) - (evil-forward-WORD-begin nil) - (transpose-words 1)) +(evil-define-motion rigpa-word-forward (count) + "Motion for moving forward by a word." + :type exclusive + (let ((count (or count 1))) + (evil-forward-WORD-begin count))) -(defun rigpa-word-move-down () - "Move word down" - (interactive) - (evil-inner-word nil nil nil nil) - (setq word-end-position (point)) - (evil-backward-WORD-begin nil) - (evil-delete (point) word-end-position 'exclusive nil nil) - (evil-next-line) - (evil-paste-before nil nil)) - -(defun rigpa-word-move-up () - "Move word up" - (interactive) - (evil-inner-word nil nil nil nil) - (setq word-end-position (point)) - (evil-backward-WORD-begin nil) - (evil-delete (point) word-end-position 'exclusive nil nil) - (evil-previous-line) - (evil-paste-before nil nil)) - -(defun rigpa-word-delete () - "Delete word" - (interactive) - (apply 'evil-delete (evil-inner-word))) +(defun rigpa-word--select-word () + "Select nearest word, going backwards if necessary." + (let ((on-word-p (save-excursion + (let ((original-position (point))) + (evil-backward-WORD-begin) + (evil-forward-WORD-begin) + (= (point) original-position))))) + (unless on-word-p + (let ((original-line (line-number-at-pos))) + (cond ((save-excursion (evil-backward-WORD-begin) + (= (line-number-at-pos) + original-line)) + (evil-backward-WORD-begin)) + ((save-excursion (evil-forward-WORD-begin) + (= (line-number-at-pos) + original-line)) + (evil-forward-WORD-begin))))))) -(defun rigpa-word-change () - "Change word" - (interactive) - (apply 'evil-change (evil-inner-word))) +(evil-define-motion rigpa-word-up (count) + "Motion for moving up by a word." + :type exclusive + (let ((count (or count 1))) + (evil-previous-line count) + (rigpa-word--select-word))) -(defun rigpa-word-toggle-case () - "Toggle case" - (interactive) - (save-excursion - (apply 'evil-invert-case (evil-inner-word)))) +(evil-define-motion rigpa-word-down (count) + "Motion for moving down by a word." + :type exclusive + (let ((count (or count 1))) + (evil-next-line count) + (rigpa-word--select-word))) -(defun rigpa-word-upper-case () - "Make upper case" - (interactive) - (save-excursion - (apply 'evil-upcase (evil-inner-word)))) +(evil-define-operator rigpa-word-delete (beg end type register yank-handler) + "Delete word." + :motion rigpa-word-forward + (evil-delete beg end type register yank-handler)) -(defun rigpa-word-lower-case () - "Make lower case" - (interactive) - (save-excursion - (apply 'evil-downcase (evil-inner-word)))) +(evil-define-operator rigpa-word-change (beg end type register yank-handler) + "Change word." + :motion rigpa-word-forward + (evil-change beg end type register yank-handler)) + +(evil-define-operator rigpa-word-toggle-case (beg end type register yank-handler) + "Toggle case." + :motion rigpa-word-forward + (evil-invert-case beg end)) + +(evil-define-operator rigpa-word-upper-case (beg end type register yank-handler) + "Make upper case." + :motion rigpa-word-forward + (evil-upcase beg end)) + +(evil-define-operator rigpa-word-lower-case (beg end type register yank-handler) + "Make lower case." + :motion rigpa-word-forward + (evil-downcase beg end)) + +(evil-define-operator rigpa-word-title-case (beg end type register yank-handler) + "Make title case." + :motion rigpa-word-forward + (capitalize-region beg end)) + +(evil-define-command rigpa-word-move-backward (count) + "Move word backwards." + (interactive "p") + (dotimes (i count) + (evil-inner-word) + (evil-backward-WORD-begin) + (transpose-words 1) + (evil-backward-WORD-begin 2))) + +(evil-define-command rigpa-word-move-forward (count) + "Move word forward" + (interactive "p") + (dotimes (i count) + (evil-forward-WORD-begin) + (transpose-words 1) + (evil-backward-WORD-begin))) + +(evil-define-command rigpa-word-move-down (count) + "Move word down" + (interactive "p") + (dotimes (i count) + (evil-inner-word nil nil nil nil) + (setq word-end-position (point)) + (evil-backward-WORD-begin nil) + (evil-delete (point) word-end-position 'exclusive nil nil) + (evil-next-line) + (evil-paste-before nil nil))) + +(evil-define-command rigpa-word-move-up (count) + "Move word up" + (interactive "p") + (dotimes (i count) + (evil-inner-word nil nil nil nil) + (setq word-end-position (point)) + (evil-backward-WORD-begin nil) + (evil-delete (point) word-end-position 'exclusive nil nil) + (evil-previous-line) + (evil-paste-before nil nil))) (defun rigpa-word-split () - "Split word into characters on separate lines" + "Split word into characters on separate lines." (interactive) - (rigpa-word-delete) - (evil-open-below 1) - (evil-force-normal-state) - (evil-paste-after nil nil) - (evil-beginning-of-line) - (while (not (eolp)) - (evil-forward-char) - (newline) - (evil-force-normal-state))) + (with-undo-collapse + (apply #'rigpa-word-delete (evil-inner-WORD)) + (evil-open-below 1) + (evil-force-normal-state) + (evil-paste-after nil nil) + (evil-beginning-of-line) + (while (not (eolp)) + (evil-forward-char) + (newline) + (evil-force-normal-state)))) (defun rigpa-word-delete-others () - "Delete other words in line" + "Delete other words in line." (interactive) - (rigpa-word-delete) - (evil-open-below 1) - (evil-force-normal-state) - (evil-paste-after nil nil) - (evil-previous-line) - (rigpa-line-delete)) - -(defun rigpa-word-rotate-chars-right () + (with-undo-collapse + (apply #'rigpa-word-delete (evil-inner-WORD)) + (evil-open-below 1) + (evil-force-normal-state) + (evil-paste-after nil nil) + (evil-previous-line) + (rigpa-line-delete))) + +(evil-define-command rigpa-word-rotate-chars-right (count) "Rotate characters to the right" - (interactive) - (save-excursion - (let* ((word-bounds (evil-inner-word)) - (word-start (nth 0 word-bounds)) - (word-end (nth 1 word-bounds))) - (evil-delete-backward-char (- word-end 1) - word-end - 'exclusive - nil) - (goto-char word-start) - (evil-paste-before nil nil)))) - -(defun rigpa-word-rotate-chars-left () + (interactive "p") + (dotimes (i count) + (save-excursion + (let* ((word-bounds (evil-inner-word)) + (word-start (nth 0 word-bounds)) + (word-end (nth 1 word-bounds))) + (evil-delete-backward-char (- word-end 1) + word-end + 'exclusive + nil) + (goto-char word-start) + (evil-paste-before nil nil))))) + +(evil-define-command rigpa-word-rotate-chars-left (count) "Rotate characters to the left" - (interactive) - (save-excursion - (let* ((word-bounds (evil-inner-word)) - (word-start (nth 0 word-bounds)) - (word-end (nth 1 word-bounds))) - (evil-delete-char word-start - (+ word-start 1) - 'exclusive - nil) - (goto-char (- word-end 1)) - (evil-paste-before nil nil)))) + (interactive "p") + (dotimes (i count) + (save-excursion + (let* ((word-bounds (evil-inner-word)) + (word-start (nth 0 word-bounds)) + (word-end (nth 1 word-bounds))) + (evil-delete-char word-start + (+ word-start 1) + 'exclusive + nil) + (goto-char (- word-end 1)) + (evil-paste-before nil nil))))) (defun rigpa-word-scroll-jump-backward () "Scroll jump back across words." (interactive) - (evil-backward-WORD-begin 3)) + (rigpa-word-backward 3)) (defun rigpa-word-scroll-jump-forward () "Scroll jump forward across words." (interactive) - (evil-forward-WORD-begin 3)) + (rigpa-word-forward 3)) (defun rigpa-word-first-word () "Jump backward to the first word in the paragraph." (interactive) - (evil-backward-paragraph) - (evil-forward-WORD-begin)) + (goto-char (nth 0 (evil-inner-paragraph)))) (defun rigpa-word-last-word () "Jump forward to the last word in the paragraph." @@ -170,44 +231,54 @@ (interactive) (evil-insert-state)) +(evil-define-command rigpa-word-paste-after (count &optional register yank-handler) + "Paste after word." + (interactive "p") + (evil-forward-WORD-end) + (forward-char) + (evil-paste-after count register yank-handler)) + +(defvar rigpa--word-mode-keyspec + '(("h" . rigpa-word-backward) + ("j" . rigpa-word-down) + ("k" . rigpa-word-up) + ("l" . rigpa-word-forward) + ("H" . rigpa-word-move-backward) + ("J" . rigpa-word-move-down) + ("K" . rigpa-word-move-up) + ("L" . rigpa-word-move-forward) + ("x" . rigpa-word-delete) + ("c" . rigpa-word-change) + ("~" . rigpa-word-toggle-case) + ("gU" . rigpa-word-upper-case) + ("gu" . rigpa-word-lower-case) + ("gt" . rigpa-word-title-case) + ("s" . rigpa-word-split) + ("s-o" . rigpa-word-delete-others) + ("C-S-h" . rigpa-word-rotate-chars-left) + ("C-S-l" . rigpa-word-rotate-chars-right) + ("C-h" . rigpa-word-scroll-jump-backward) + ("C-k" . rigpa-word-scroll-jump-backward) + ("C-j" . rigpa-word-scroll-jump-forward) + ("C-l" . rigpa-word-scroll-jump-forward) + ("M-h" . rigpa-word-first-word) + ("0" . rigpa-word-first-word) + ("M-l" . rigpa-word-last-word) + ("$" . rigpa-word-last-word) + ("a" . rigpa-word-add-to-end) + ("i" . rigpa-word-add-to-beginning) + ("A" . rigpa-word-add-after) + ("I" . rigpa-word-add-before) + ("p" . rigpa-word-paste-after) + ("?" . dictionary-lookup-definition)) + "Key specification for rigpa word mode.") -(defhydra hydra-word (:columns 2 - :post (chimera-hydra-portend-exit chimera-word-mode t) - :after-exit (chimera-hydra-signal-exit chimera-word-mode - #'chimera-handle-hydra-exit)) - "Word mode" - ("h" evil-backward-WORD-begin "backward") - ("j" evil-next-line "down") - ("k" evil-previous-line "up") - ("l" evil-forward-WORD-begin "forward") - ("C-h" rigpa-word-scroll-jump-backward "backward") - ("C-j" rigpa-word-scroll-jump-forward "down") - ("C-k" rigpa-word-scroll-jump-backward "up") - ("C-l" rigpa-word-scroll-jump-forward "forward") - ("C-S-h" rigpa-word-rotate-chars-left "rotate chars left") - ("C-S-l" rigpa-word-rotate-chars-right "rotate chars right") - ("M-h" rigpa-word-first-word "first word") - ("M-l" rigpa-word-last-word "last word") - ("H" rigpa-word-move-backward "move left") - ("L" rigpa-word-move-forward "move right") - ("J" rigpa-word-move-down "move down") - ("K" rigpa-word-move-up "move up") - ("x" rigpa-word-delete "delete") - ("c" rigpa-word-change "change" :exit t) - ("a" rigpa-word-add-to-end "append" :exit t) - ("i" rigpa-word-add-to-beginning "insert" :exit t) - ("A" rigpa-word-add-after "add after" :exit t) - ("I" rigpa-word-add-before "add before" :exit t) - ("~" rigpa-word-toggle-case "toggle case") - ("U" rigpa-word-upper-case "upper case") - ("u" rigpa-word-lower-case "lower case") - ("s" rigpa-word-split "split into characters") - ("s-r" rigpa-word-delete "delete" :exit t) - ("s-o" rigpa-word-delete-others "delete other words" :exit t) - ("?" dictionary-lookup-definition "lookup in dictionary" :exit t) - ("H-m" rigpa-toggle-menu "show/hide this menu") - ("" rigpa-enter-lower-level "enter lower level" :exit t) - ("" rigpa-enter-higher-level "escape to higher level" :exit t)) +;; TODO: review these: +;; exiting keys: c, a, i, A, I, s-r (delete), s-o (delete others), ?, Esc, Ret + +(rigpa--define-evil-keys-from-spec rigpa--word-mode-keyspec + rigpa-word-mode-map + 'word) (defvar chimera-word-mode-entry-hook nil "Entry hook for rigpa word mode.") @@ -215,9 +286,20 @@ (defvar chimera-word-mode-exit-hook nil "Exit hook for rigpa word mode.") +(defun rigpa--enable-word-minor-mode () + "Enable word minor mode." + (rigpa-word-mode 1)) + +(defun rigpa--disable-word-minor-mode () + "Disable word minor mode." + (rigpa-word-mode -1)) + + (defvar chimera-word-mode (make-chimera-mode :name "word" - :enter #'hydra-word/body + :enter #'evil-word-state + :pre-entry-hook 'chimera-word-mode-entry-hook + :post-exit-hook 'chimera-word-mode-exit-hook :entry-hook 'evil-word-state-entry-hook :exit-hook 'evil-word-state-exit-hook)) diff --git a/rigpa.el b/rigpa.el index a36c459..d278e5e 100644 --- a/rigpa.el +++ b/rigpa.el @@ -109,33 +109,73 @@ and simply toggles whether the menu is visible or not." (define-key rigpa-meta-tower-mode-map (kbd "g r") 'rigpa--reload-tower)) ;; wrap native evil states in chimera modes +(defvar chimera-normal-mode-entry-hook nil + "Entry hook for rigpa normal mode.") + +(defvar chimera-normal-mode-exit-hook nil + "Exit hook for rigpa normal mode.") + (defvar chimera-normal-mode (make-chimera-mode :name "normal" :enter #'evil-normal-state + :pre-entry-hook 'chimera-normal-mode-entry-hook + :post-exit-hook 'chimera-normal-mode-exit-hook :entry-hook 'evil-normal-state-entry-hook :exit-hook 'evil-normal-state-exit-hook)) +(defvar chimera-insert-mode-entry-hook nil + "Entry hook for rigpa insert mode.") + +(defvar chimera-insert-mode-exit-hook nil + "Exit hook for rigpa insert mode.") + (defvar chimera-insert-mode (make-chimera-mode :name "insert" :enter #'evil-insert-state + :pre-entry-hook 'chimera-insert-mode-entry-hook + :post-exit-hook 'chimera-insert-mode-exit-hook :entry-hook 'evil-insert-state-entry-hook :exit-hook 'evil-insert-state-exit-hook)) +(defvar chimera-emacs-mode-entry-hook nil + "Entry hook for rigpa emacs mode.") + +(defvar chimera-emacs-mode-exit-hook nil + "Exit hook for rigpa emacs mode.") + (defvar chimera-emacs-mode (make-chimera-mode :name "emacs" :enter #'evil-emacs-state + :pre-entry-hook 'chimera-emacs-mode-entry-hook + :post-exit-hook 'chimera-emacs-mode-exit-hook :entry-hook 'evil-emacs-state-entry-hook :exit-hook 'evil-emacs-state-exit-hook)) +(defvar chimera-visual-mode-entry-hook nil + "Entry hook for rigpa visual mode.") + +(defvar chimera-visual-mode-exit-hook nil + "Exit hook for rigpa visual mode.") + (defvar chimera-visual-mode (make-chimera-mode :name "visual" :enter #'evil-visual-state + :pre-entry-hook 'chimera-visual-mode-entry-hook + :post-exit-hook 'chimera-visual-mode-exit-hook :entry-hook 'evil-visual-state-entry-hook :exit-hook 'evil-visual-state-exit-hook)) +(defvar chimera-replace-mode-entry-hook nil + "Entry hook for rigpa replace mode.") + +(defvar chimera-replace-mode-exit-hook nil + "Exit hook for rigpa replace mode.") + (defvar chimera-replace-mode (make-chimera-mode :name "replace" :enter #'evil-replace-state + :pre-entry-hook 'chimera-replace-mode-entry-hook + :post-exit-hook 'chimera-replace-mode-exit-hook :entry-hook 'evil-replace-state-entry-hook :exit-hook 'evil-replace-state-exit-hook)) @@ -179,29 +219,29 @@ and simply toggles whether the menu is visible or not." (Custom-newline (point))) (t (rigpa-enter-lower-level))))) -(defun rigpa--integrate-evil () +(defun rigpa--integrate-evil-states () "Map standard evil state entry and exit points so they're managed by rigpa." ;; evil interop keybindings - (define-key evil-normal-state-map [escape] 'rigpa-enter-higher-level) - (define-key evil-normal-state-map [return] 'rigpa--enter-lower-or-pass-through) + ;; TODO: these (Esc/Ret) should be dependent on whether there are any + ;; other modes in the tower. If not, then this shouldn't be bound + ;; IOW this keybinding (and some class of bindings more generally) + ;; is tower-specific + (dolist (state chimera-evil-states) + (let ((keymap (symbol-value + (intern + (concat "evil-" state "-state-map"))))) + (define-key keymap [escape] #'rigpa-enter-higher-level) + (unless (member state chimera-insertion-states) + (define-key keymap [return] #'rigpa--enter-lower-or-pass-through)))) + ;; exit visual state gracefully (define-key evil-visual-state-map [escape] (lambda () (interactive) - ;; exit visual state gracefully (evil-exit-visual-state) (rigpa-enter-higher-level))) (define-key evil-visual-state-map [return] (lambda () (interactive) - ;; exit visual state gracefully (evil-exit-visual-state) - (rigpa-enter-lower-level))) - (define-key evil-replace-state-map [escape] 'rigpa-enter-higher-level) - (define-key evil-replace-state-map [return] 'rigpa-enter-lower-level) - (define-key evil-insert-state-map [escape] 'rigpa-enter-higher-level) - ;; TODO: this keybinding should be dependent on whether there are any - ;; other modes in the tower. If not, then this shouldn't be bound - ;; IOW this keybinding (and some class of bindings more generally) - ;; is tower-specific - (define-key evil-emacs-state-map [escape] 'rigpa-enter-higher-level)) + (rigpa-enter-lower-level)))) (defun rigpa--register-modes () "Register the standard modes with the framework." @@ -331,7 +371,7 @@ and simply toggles whether the menu is visible or not." ;; should make this optional via a defcustom flag ;; or potentially even have it in a separate evil-adapter package (when (boundp 'evil-mode) - (rigpa--integrate-evil)) + (rigpa--integrate-evil-states)) (rigpa--create-editing-structures) (rigpa--provide-editing-structures) (if (and (boundp 'rigpa-show-menus) rigpa-show-menus)