From d1ef627b2bdff58a6ef0fa9fa2d7e19b21b941aa Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Thu, 11 Mar 2021 20:53:43 -0800 Subject: [PATCH 01/18] add pre-entry and post-exit wrapper hooks in chimera --- chimera.el | 23 ++++++++++++++-------- rigpa-activity-mode.el | 2 ++ rigpa-application-mode.el | 2 ++ rigpa-buffer-mode.el | 2 ++ rigpa-char-mode.el | 2 ++ rigpa-file-mode.el | 2 ++ rigpa-history-mode.el | 2 ++ rigpa-line-mode.el | 2 ++ rigpa-symex-mode.el | 2 ++ rigpa-system-mode.el | 2 ++ rigpa-tab-mode.el | 2 ++ rigpa-text-mode.el | 2 ++ rigpa-view-mode.el | 2 ++ rigpa-window-mode.el | 2 ++ rigpa-word-mode.el | 11 +++++++++++ rigpa.el | 40 +++++++++++++++++++++++++++++++++++++++ 16 files changed, 92 insertions(+), 8 deletions(-) diff --git a/chimera.el b/chimera.el index af0532c..7c65406 100644 --- a/chimera.el +++ b/chimera.el @@ -3,12 +3,15 @@ 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")) @@ -17,15 +20,19 @@ If not, they are expected to be run by the underlying mode provider \ "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..c7e3a7c 100644 --- a/rigpa-char-mode.el +++ b/rigpa-char-mode.el @@ -162,6 +162,8 @@ (defvar chimera-char-mode (make-chimera-mode :name "char" :enter #'hydra-char/body + :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-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..20c2913 100644 --- a/rigpa-line-mode.el +++ b/rigpa-line-mode.el @@ -285,6 +285,8 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- (defvar chimera-line-mode (make-chimera-mode :name "line" :enter #'hydra-line/body + :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-symex-mode.el b/rigpa-symex-mode.el index 48c1803..ad2ecd5 100644 --- a/rigpa-symex-mode.el +++ b/rigpa-symex-mode.el @@ -9,6 +9,8 @@ (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..ae33f4b 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -215,9 +215,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 + :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..2cc4abe 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)) From d79ce9d93162d1d53c6c67dab5dbcbd5a070a59a Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Thu, 11 Mar 2021 20:59:53 -0800 Subject: [PATCH 02/18] couple mode-specific minor modes to rigpa modes / evil states --- rigpa-mode-mode.el | 49 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/rigpa-mode-mode.el b/rigpa-mode-mode.el index 79fc420..d4c0003 100644 --- a/rigpa-mode-mode.el +++ b/rigpa-mode-mode.el @@ -15,23 +15,60 @@ (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 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 rigpa minor modes other than the one corresponding to the current state." + (dolist (name (ht-keys rigpa-modes)) + (unless (equal name evil-state) + (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." From ccf9a47ef94412d9a06af99e359331bac85a0457 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Thu, 11 Mar 2021 21:00:51 -0800 Subject: [PATCH 03/18] wip evil-backed word mode --- chimera.el | 2 +- rigpa-evil-support.el | 9 +++ rigpa-word-mode.el | 163 ++++++++++++++++++++++++++++++++---------- 3 files changed, 135 insertions(+), 39 deletions(-) create mode 100644 rigpa-evil-support.el diff --git a/chimera.el b/chimera.el index 7c65406..aa3be2e 100644 --- a/chimera.el +++ b/chimera.el @@ -14,7 +14,7 @@ If not, they are expected to be run by the underlying mode provider \ always managed by chimera.")) (defvar chimera-evil-states - (list "normal" "insert" "emacs" "visual" "replace")) + (list "normal" "insert" "emacs" "visual" "replace" "word")) (defun chimera-enter-mode (mode) "Enter MODE." diff --git a/rigpa-evil-support.el b/rigpa-evil-support.el new file mode 100644 index 0000000..760f2b0 --- /dev/null +++ b/rigpa-evil-support.el @@ -0,0 +1,9 @@ +(defun rigpa--define-evil-key (key fn map) + "Define an evil keybinding in an evil-backed rigpa mode." + (evil-define-key '(word visual operator) + map + (kbd key) + fn)) + + +(provide 'rigpa-evil-support) diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index ae33f4b..b4d520b 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -1,5 +1,13 @@ (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,6 +15,85 @@ :message "-- WORD --" :enable (normal)) +(defun rigpa-word--define-evil-key (key fn) + "Define an evil keybinding in rigpa word mode." + (rigpa--define-evil-key key + fn + rigpa-word-mode-map)) + +(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))) + +(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--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))))))) + +(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))) + +(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))) + +(rigpa-word--define-evil-key "h" + #'rigpa-word-backward) + +(rigpa-word--define-evil-key "j" + #'rigpa-word-down) + +(rigpa-word--define-evil-key "k" + #'rigpa-word-up) + +(rigpa-word--define-evil-key "l" + #'rigpa-word-forward) + +;; (evil-define-key '(word visual operator) rigpa-word-mode-map +;; (kbd "H") +;; #'rigpa-word-move-backward) + +;; (evil-define-key '(word visual operator) rigpa-word-mode-map +;; (kbd "L") +;; #'rigpa-word-move-forward) + +;; (evil-define-key '(word visual operator) rigpa-word-mode-map +;; (kbd "J") +;; #'rigpa-word-move-down) + +;; (evil-define-key '(word visual operator) rigpa-word-mode-map +;; (kbd "K") +;; #'rigpa-word-move-up) + + (defun rigpa-word-move-backward () "Move word backwards" (interactive) @@ -171,43 +258,43 @@ (evil-insert-state)) -(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)) +;; (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)) (defvar chimera-word-mode-entry-hook nil "Entry hook for rigpa word mode.") @@ -226,7 +313,7 @@ (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 From a37009295de5e9d012e36c0c80f64d5f7becb267 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Thu, 11 Mar 2021 21:20:24 -0800 Subject: [PATCH 04/18] define mode evil keybindings from a specification --- rigpa-evil-support.el | 7 +++++++ rigpa-mode-mode.el | 6 ++++++ rigpa-word-mode.el | 24 ++++++++---------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/rigpa-evil-support.el b/rigpa-evil-support.el index 760f2b0..cbb3658 100644 --- a/rigpa-evil-support.el +++ b/rigpa-evil-support.el @@ -5,5 +5,12 @@ (kbd key) fn)) +(defun rigpa--define-evil-keys-from-spec (keyspec keymap) + "Define evil keys from a specification." + (dolist (keybinding keyspec) + (rigpa--define-evil-key (car keybinding) + (cdr keybinding) + keymap))) + (provide 'rigpa-evil-support) diff --git a/rigpa-mode-mode.el b/rigpa-mode-mode.el index d4c0003..49b5e81 100644 --- a/rigpa-mode-mode.el +++ b/rigpa-mode-mode.el @@ -18,6 +18,12 @@ (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." diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index b4d520b..101fda8 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -15,12 +15,6 @@ :message "-- WORD --" :enable (normal)) -(defun rigpa-word--define-evil-key (key fn) - "Define an evil keybinding in rigpa word mode." - (rigpa--define-evil-key key - fn - rigpa-word-mode-map)) - (evil-define-motion rigpa-word-backward (count) "Motion for moving backward by a word." :type exclusive @@ -65,17 +59,15 @@ (evil-next-line count) (rigpa-word--select-word))) -(rigpa-word--define-evil-key "h" - #'rigpa-word-backward) - -(rigpa-word--define-evil-key "j" - #'rigpa-word-down) - -(rigpa-word--define-evil-key "k" - #'rigpa-word-up) +(defvar rigpa--word-mode-keyspec + '(("h" . rigpa-word-backward) + ("j" . rigpa-word-down) + ("k" . rigpa-word-up) + ("l" . rigpa-word-forward)) + "Key specification for rigpa word mode.") -(rigpa-word--define-evil-key "l" - #'rigpa-word-forward) +(rigpa--define-evil-keys-from-spec rigpa--word-mode-keyspec + rigpa-word-mode-map) ;; (evil-define-key '(word visual operator) rigpa-word-mode-map ;; (kbd "H") From fbb7bce0299affa6f72c19eeb86bb3cf957d1266 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 12:04:46 -0800 Subject: [PATCH 05/18] convert word state from hydra to evil --- rigpa-word-mode.el | 191 +++++++++++++++++++++------------------------ 1 file changed, 87 insertions(+), 104 deletions(-) diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index 101fda8..a59bf32 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -59,33 +59,6 @@ (evil-next-line count) (rigpa-word--select-word))) -(defvar rigpa--word-mode-keyspec - '(("h" . rigpa-word-backward) - ("j" . rigpa-word-down) - ("k" . rigpa-word-up) - ("l" . rigpa-word-forward)) - "Key specification for rigpa word mode.") - -(rigpa--define-evil-keys-from-spec rigpa--word-mode-keyspec - rigpa-word-mode-map) - -;; (evil-define-key '(word visual operator) rigpa-word-mode-map -;; (kbd "H") -;; #'rigpa-word-move-backward) - -;; (evil-define-key '(word visual operator) rigpa-word-mode-map -;; (kbd "L") -;; #'rigpa-word-move-forward) - -;; (evil-define-key '(word visual operator) rigpa-word-mode-map -;; (kbd "J") -;; #'rigpa-word-move-down) - -;; (evil-define-key '(word visual operator) rigpa-word-mode-map -;; (kbd "K") -;; #'rigpa-word-move-up) - - (defun rigpa-word-move-backward () "Move word backwards" (interactive) @@ -120,56 +93,60 @@ (evil-previous-line) (evil-paste-before nil nil)) -(defun rigpa-word-delete () - "Delete word" - (interactive) - (apply 'evil-delete (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-change () - "Change word" - (interactive) - (apply 'evil-change (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)) -(defun rigpa-word-toggle-case () - "Toggle case" - (interactive) - (save-excursion - (apply 'evil-invert-case (evil-inner-word)))) +(evil-define-operator rigpa-word-toggle-case (beg end type register yank-handler) + "Toggle case." + :motion rigpa-word-forward + (evil-invert-case beg end)) -(defun rigpa-word-upper-case () - "Make upper case" - (interactive) - (save-excursion - (apply 'evil-upcase (evil-inner-word)))) +(evil-define-operator rigpa-word-upper-case (beg end type register yank-handler) + "Make upper case." + :motion rigpa-word-forward + (evil-upcase beg end)) -(defun rigpa-word-lower-case () - "Make lower case" - (interactive) - (save-excursion - (apply 'evil-downcase (evil-inner-word)))) +(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)) (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)) + (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))) (defun rigpa-word-rotate-chars-right () "Rotate characters to the right" @@ -249,44 +226,50 @@ (interactive) (evil-insert-state)) +(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) + ("?" . dictionary-lookup-definition)) + "Key specification for rigpa word mode.") + +;; TODO: review these: +;; exiting keys: c, a, i, A, I, s-r (delete), s-o (delete others), ?, Esc, Ret -;; (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 remaining defuns for possible conversion +;; to evil operators, motions, and commands + +;; TODO: review accuracy and behavior + +(rigpa--define-evil-keys-from-spec rigpa--word-mode-keyspec + rigpa-word-mode-map) (defvar chimera-word-mode-entry-hook nil "Entry hook for rigpa word mode.") From d4c117e423bdb358bb0dc31b0d09c4b864bc8adf Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 13:01:16 -0800 Subject: [PATCH 06/18] make move word operations into evil commands --- rigpa-word-mode.el | 73 +++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index a59bf32..2b807e6 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -59,40 +59,6 @@ (evil-next-line count) (rigpa-word--select-word))) -(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)) - -(defun rigpa-word-move-forward () - "Move word forward" - (interactive) - (evil-forward-WORD-begin nil) - (transpose-words 1)) - -(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)) - (evil-define-operator rigpa-word-delete (beg end type register yank-handler) "Delete word." :motion rigpa-word-forward @@ -123,6 +89,45 @@ :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." (interactive) From c054545cecc589bcaed87ba6b60bd6d6fbb996c4 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 16:13:38 -0800 Subject: [PATCH 07/18] evil word mode.. --- rigpa-word-mode.el | 64 ++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index 2b807e6..0d78d07 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -153,49 +153,50 @@ (evil-previous-line) (rigpa-line-delete))) -(defun rigpa-word-rotate-chars-right () +(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." @@ -268,11 +269,6 @@ ;; TODO: review these: ;; exiting keys: c, a, i, A, I, s-r (delete), s-o (delete others), ?, Esc, Ret -;; TODO: review remaining defuns for possible conversion -;; to evil operators, motions, and commands - -;; TODO: review accuracy and behavior - (rigpa--define-evil-keys-from-spec rigpa--word-mode-keyspec rigpa-word-mode-map) From 2d0302716e24e2e87425d9db7df2b6deb84e61b0 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 16:32:24 -0800 Subject: [PATCH 08/18] evil shell for line mode --- chimera.el | 2 +- rigpa-evil-support.el | 9 +-- rigpa-line-mode.el | 126 ++++++++++++++++++++++++++---------------- rigpa-word-mode.el | 4 +- 4 files changed, 85 insertions(+), 56 deletions(-) diff --git a/chimera.el b/chimera.el index aa3be2e..25b26b8 100644 --- a/chimera.el +++ b/chimera.el @@ -14,7 +14,7 @@ If not, they are expected to be run by the underlying mode provider \ always managed by chimera.")) (defvar chimera-evil-states - (list "normal" "insert" "emacs" "visual" "replace" "word")) + (list "normal" "insert" "emacs" "visual" "replace" "word" "line")) (defun chimera-enter-mode (mode) "Enter MODE." diff --git a/rigpa-evil-support.el b/rigpa-evil-support.el index cbb3658..01123e3 100644 --- a/rigpa-evil-support.el +++ b/rigpa-evil-support.el @@ -1,16 +1,17 @@ -(defun rigpa--define-evil-key (key fn map) +(defun rigpa--define-evil-key (key fn map state) "Define an evil keybinding in an evil-backed rigpa mode." - (evil-define-key '(word visual operator) + (evil-define-key (list state 'visual 'operator) map (kbd key) fn)) -(defun rigpa--define-evil-keys-from-spec (keyspec keymap) +(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))) + keymap + state))) (provide 'rigpa-evil-support) diff --git a/rigpa-line-mode.el b/rigpa-line-mode.el index 20c2913..521d3ab 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." @@ -228,53 +235,66 @@ 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)) +(setq rigpa--line-mode-keyspec + '(("h" . evil-previous-line) + ("j" . evil-next-line) + ("k" . evil-previous-line) + ("l" . evil-next-line)) + ;"Key specification for rigpa line mode." + ) + +(rigpa--define-evil-keys-from-spec rigpa--line-mode-keyspec + rigpa-line-mode-map + 'line) + + +;; (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 chimera-line-mode-entry-hook nil "Entry hook for rigpa line mode.") @@ -282,9 +302,17 @@ 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 diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index 0d78d07..f6cf9ec 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -1,5 +1,4 @@ (require 'chimera) -(require 'chimera-hydra) (require 'rigpa-evil-support) (defvar rigpa-word-mode-map (make-sparse-keymap)) @@ -270,7 +269,8 @@ ;; 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) + rigpa-word-mode-map + 'word) (defvar chimera-word-mode-entry-hook nil "Entry hook for rigpa word mode.") From bbb6f95882d0661c93bea9c1607f1c2744740f21 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 18:09:34 -0800 Subject: [PATCH 09/18] convert line mode from hydra to evil --- rigpa-line-mode.el | 222 ++++++++++++++++++--------------------------- 1 file changed, 88 insertions(+), 134 deletions(-) diff --git a/rigpa-line-mode.el b/rigpa-line-mode.el index 521d3ab..671239b 100644 --- a/rigpa-line-mode.el +++ b/rigpa-line-mode.el @@ -23,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)) @@ -61,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))) @@ -106,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" @@ -126,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" @@ -161,63 +151,44 @@ 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)) - -(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-change (beg end type register yank-handler) + "Change line." + :motion evil-line + (evil-change beg end type register yank-handler)) -(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) @@ -235,67 +206,50 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- (interactive) (evil-previous-line 9)) -(setq rigpa--line-mode-keyspec +(defvar rigpa--line-mode-keyspec '(("h" . evil-previous-line) ("j" . evil-next-line) ("k" . evil-previous-line) - ("l" . evil-next-line)) - ;"Key specification for rigpa line mode." - ) + ("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) + ("" . indent-according-to-mode) + ("s-l" . indent-according-to-mode) + (">" . 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) - -;; (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 chimera-line-mode-entry-hook nil "Entry hook for rigpa line mode.") From 8f499efb085f76d7097862b682eb9cdcbe299258 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 18:10:05 -0800 Subject: [PATCH 10/18] integrate rigpa evil states along with built-in ones --- chimera.el | 3 +++ rigpa.el | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/chimera.el b/chimera.el index 25b26b8..53482f6 100644 --- a/chimera.el +++ b/chimera.el @@ -16,6 +16,9 @@ always managed by chimera.")) (defvar chimera-evil-states (list "normal" "insert" "emacs" "visual" "replace" "word" "line")) +(defvar chimera-insertion-states + (list "insert" "emacs")) + (defun chimera-enter-mode (mode) "Enter MODE." (interactive) diff --git a/rigpa.el b/rigpa.el index 2cc4abe..9cd56d0 100644 --- a/rigpa.el +++ b/rigpa.el @@ -219,29 +219,27 @@ 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 (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." @@ -371,7 +369,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) From c72a9ae4b441c0868828c13dc7429fe6648a41f3 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 18:16:45 -0800 Subject: [PATCH 11/18] fix: dereference symbol for evil keymap --- rigpa.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rigpa.el b/rigpa.el index 9cd56d0..d278e5e 100644 --- a/rigpa.el +++ b/rigpa.el @@ -227,7 +227,9 @@ and simply toggles whether the menu is visible or not." ;; IOW this keybinding (and some class of bindings more generally) ;; is tower-specific (dolist (state chimera-evil-states) - (let ((keymap (intern (concat "evil-" state "-state-map")))) + (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)))) From 54f52c98fea641c819a4d67367fd1437ed84c709 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 18:40:55 -0800 Subject: [PATCH 12/18] indent line as an operator --- rigpa-line-mode.el | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rigpa-line-mode.el b/rigpa-line-mode.el index 671239b..96b5265 100644 --- a/rigpa-line-mode.el +++ b/rigpa-line-mode.el @@ -166,6 +166,11 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- :motion evil-line (evil-change beg end type register yank-handler)) +(evil-define-operator rigpa-line-indent (beg end type register yank-handler) + "Indent line" + :motion evil-line + (evil-indent beg end)) + (evil-define-command rigpa-line-insert-newline (count) "Insert newline and reindent." (interactive "p") @@ -219,8 +224,8 @@ From: https://emacs.stackexchange.com/questions/17846/calculating-the-length-of- ("J" . rigpa-line-move-down) ("K" . rigpa-line-move-up) ("L" . rigpa-line-move-right) - ("" . indent-according-to-mode) - ("s-l" . indent-according-to-mode) + ("" . rigpa-line-indent) + ("s-l" . rigpa-line-indent) (">" . evil-shift-right-line) ("<" . evil-shift-left-line) ("M-H" . rigpa-line-move-far-left) From a201614c522db82d5151fc967610666f18de655a Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 18:44:57 -0800 Subject: [PATCH 13/18] evil shell for character mode --- chimera.el | 2 +- rigpa-char-mode.el | 139 +++++++++++++++++++++++++-------------------- 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/chimera.el b/chimera.el index 53482f6..b532dc6 100644 --- a/chimera.el +++ b/chimera.el @@ -14,7 +14,7 @@ If not, they are expected to be run by the underlying mode provider \ always managed by chimera.")) (defvar chimera-evil-states - (list "normal" "insert" "emacs" "visual" "replace" "word" "line")) + (list "normal" "insert" "emacs" "visual" "replace" "word" "line" "char")) (defvar chimera-insertion-states (list "insert" "emacs")) diff --git a/rigpa-char-mode.el b/rigpa-char-mode.el index c7e3a7c..499daf8 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 () @@ -96,62 +100,67 @@ (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)) +(setq rigpa--char-mode-keyspec + '(("h" . evil-backward-char) + ("j" . evil-next-line) + ("k" . evil-previous-line) + ("l" . evil-forward-char) + + ;; "Key specification for rigpa char mode." + )) + +(rigpa--define-evil-keys-from-spec rigpa--char-mode-keyspec + rigpa-char-mode-map + 'char) + +;; (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" +;; ("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") +;; ("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)) (defvar chimera-char-mode-entry-hook nil "Entry hook for rigpa char mode.") @@ -159,9 +168,17 @@ (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 From 63e819e11e7c795c9a918d8475972a3c0e97e33e Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 12 Mar 2021 20:28:32 -0800 Subject: [PATCH 14/18] convert character mode from hydra to evil --- rigpa-char-mode.el | 248 +++++++++++++++++++++++---------------------- 1 file changed, 128 insertions(+), 120 deletions(-) diff --git a/rigpa-char-mode.el b/rigpa-char-mode.el index 499daf8..ecee3a8 100644 --- a/rigpa-char-mode.el +++ b/rigpa-char-mode.el @@ -19,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) - (evil-delete-char (point) - (+ (point) 1) - (quote exclusive) nil)) + (rigpa-char-move-left 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-left-most () + "Move character left 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))) + (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) - (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. + (rigpa-char-move-right 3)) + +(defun rigpa-char-move-right-most () + "Move character right most." + (interactive) + (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) + (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" @@ -90,78 +113,63 @@ (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))) - -(setq rigpa--char-mode-keyspec - '(("h" . evil-backward-char) - ("j" . evil-next-line) - ("k" . evil-previous-line) - ("l" . evil-forward-char) - - ;; "Key specification for rigpa char mode." - )) + :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) -;; (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" -;; ("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") -;; ("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)) - (defvar chimera-char-mode-entry-hook nil "Entry hook for rigpa char mode.") From 6fb5e08e3013162b9f968b32ea604ea60b8c568a Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Sat, 13 Mar 2021 09:21:06 -0800 Subject: [PATCH 15/18] handle interactive line mode commands in meta side effects --- rigpa-mode-mode.el | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/rigpa-mode-mode.el b/rigpa-mode-mode.el index 49b5e81..c036174 100644 --- a/rigpa-mode-mode.el +++ b/rigpa-mode-mode.el @@ -276,17 +276,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 From 266b852a7e984273b47c4a14ad993b87e1e47724 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Sun, 14 Mar 2021 16:30:55 -0700 Subject: [PATCH 16/18] improve paste word after --- rigpa-word-mode.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rigpa-word-mode.el b/rigpa-word-mode.el index f6cf9ec..8ef2680 100644 --- a/rigpa-word-mode.el +++ b/rigpa-word-mode.el @@ -231,6 +231,13 @@ (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) @@ -262,6 +269,7 @@ ("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.") From 822d879ce585767e12a3be99192e515bd2965da2 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Tue, 16 Mar 2021 06:49:14 -0700 Subject: [PATCH 17/18] incorporate symex as an evil-backed mode --- chimera.el | 2 +- rigpa-evil-support.el | 1 + rigpa-mode-mode.el | 21 ++++++++++++++++++++- rigpa-symex-mode.el | 8 ++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/chimera.el b/chimera.el index b532dc6..5c3457a 100644 --- a/chimera.el +++ b/chimera.el @@ -14,7 +14,7 @@ If not, they are expected to be run by the underlying mode provider \ always managed by chimera.")) (defvar chimera-evil-states - (list "normal" "insert" "emacs" "visual" "replace" "word" "line" "char")) + (list "normal" "insert" "emacs" "visual" "replace" "word" "line" "char" "symex")) (defvar chimera-insertion-states (list "insert" "emacs")) diff --git a/rigpa-evil-support.el b/rigpa-evil-support.el index 01123e3..34fe4c3 100644 --- a/rigpa-evil-support.el +++ b/rigpa-evil-support.el @@ -15,3 +15,4 @@ (provide 'rigpa-evil-support) +;;; rigpa-evil-support.el ends here diff --git a/rigpa-mode-mode.el b/rigpa-mode-mode.el index c036174..6716088 100644 --- a/rigpa-mode-mode.el +++ b/rigpa-mode-mode.el @@ -35,7 +35,26 @@ to parametrize the hook but still be able to remove it." (defun rigpa--disable-other-minor-modes () "Disable rigpa minor modes other than the one corresponding to the current state." (dolist (name (ht-keys rigpa-modes)) - (unless (equal name evil-state) + ;; it works even without this exclusion, i.e. even if we + ;; simply turn off ALL minor modes. Not exactly sure why. + ;; but it seems to have something to do with the fact that + ;; this function is only called when we intentionally enter + ;; a rigpa mode via Esc or Enter. And furthermore, by a stroke + ;; of luck, the enabling of the minor mode is at the tail end + ;; of the pre-entry hook and this function is at the head, + ;; meaning that it disables all modes first and then enables + ;; the right one. + ;; it's because visual, operator, and replace states aren't + ;; ever explicitly entered in this manner that they work + ;; correctly when entered from within a rigpa state, i.e. + ;; even though these are considered rigpa evil states, the + ;; pre-entry hooks aren't triggered upon implicit entry + ;; That may be just fine. We could explicitly say that, yes, + ;; we only want to trigger minor mode modulation upon + ;; explicit, user-directed state transitions. + ;; But as a separate issue, these hooks not being triggered on + ;; implicit transitions could be a problem + (unless (equal name (symbol-name evil-state)) (let ((disable-mode (intern (concat "rigpa--disable-" name "-minor-mode")))) diff --git a/rigpa-symex-mode.el b/rigpa-symex-mode.el index ad2ecd5..fd76e54 100644 --- a/rigpa-symex-mode.el +++ b/rigpa-symex-mode.el @@ -6,6 +6,14 @@ (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 From 49a57ed10b932817ad91c8c8ecbb5f16c8fd7e31 Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Tue, 16 Mar 2021 11:17:56 -0700 Subject: [PATCH 18/18] fix lingering minor mode in evil states --- rigpa-mode-mode.el | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/rigpa-mode-mode.el b/rigpa-mode-mode.el index 6716088..aea1157 100644 --- a/rigpa-mode-mode.el +++ b/rigpa-mode-mode.el @@ -33,33 +33,16 @@ to parametrize the hook but still be able to remove it." enable-mode)) (defun rigpa--disable-other-minor-modes () - "Disable rigpa minor modes other than the one corresponding to the current state." + "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)) - ;; it works even without this exclusion, i.e. even if we - ;; simply turn off ALL minor modes. Not exactly sure why. - ;; but it seems to have something to do with the fact that - ;; this function is only called when we intentionally enter - ;; a rigpa mode via Esc or Enter. And furthermore, by a stroke - ;; of luck, the enabling of the minor mode is at the tail end - ;; of the pre-entry hook and this function is at the head, - ;; meaning that it disables all modes first and then enables - ;; the right one. - ;; it's because visual, operator, and replace states aren't - ;; ever explicitly entered in this manner that they work - ;; correctly when entered from within a rigpa state, i.e. - ;; even though these are considered rigpa evil states, the - ;; pre-entry hooks aren't triggered upon implicit entry - ;; That may be just fine. We could explicitly say that, yes, - ;; we only want to trigger minor mode modulation upon - ;; explicit, user-directed state transitions. - ;; But as a separate issue, these hooks not being triggered on - ;; implicit transitions could be a problem - (unless (equal name (symbol-name evil-state)) - (let ((disable-mode - (intern - (concat "rigpa--disable-" name "-minor-mode")))) - (when (fboundp disable-mode) - (funcall disable-mode)))))) + (let ((disable-mode + (intern + (concat "rigpa--disable-" name "-minor-mode")))) + (when (fboundp disable-mode) + (funcall disable-mode))))) (defun rigpa-register-mode (mode) "Register MODE for use with rigpa.