diff --git a/lisp/mitch-orgstuff.el b/lisp/mitch-orgstuff.el index 59ea4f3..152b4ea 100644 --- a/lisp/mitch-orgstuff.el +++ b/lisp/mitch-orgstuff.el @@ -47,10 +47,13 @@ (bury-buffer) (other-window 1)) +(defvar org-vw-pre-hook nil + "Hook to run before org-vw-mode has been loaded.") (define-minor-mode org-vw-mode "Org VimWiki mode." :lighter " VW" :keymap (make-sparse-keymap) + (run-hooks org-vw-pre-hook) ;; TODO: This is a hack, because hyperbole is scary. Ideal implementation ;; would add a proper case rather than this weird fallback. (require 'hyperbole) @@ -60,7 +63,12 @@ (general-define-key :keymaps 'local :states 'normal - "DEL" 'org-vw-back)) + "DEL" 'org-vw-back) + (dolist (key mitch/org-dwim-char-chars) + (general-define-key + :keymaps 'local + key 'mitch/org-dwim-char)) + ) ;; (add-to-list 'auto-mode-alist `(,org-wiki-regex . org-vw-mode)) (add-hook 'org-mode-hook #'org-vw-mode) @@ -84,6 +92,7 @@ Start insert mode." ;; ------------------ ABANDON ALL SANITY, YE WHO ENTER HERE -------------------- +(defvar mitch/org-dwim-char-chars '("_" "/" "*" "+" "~" "=")) (defun mitch/org-dwim-char (&optional char) "If a region is active (visual mode), surround selection with CHAR. @@ -100,28 +109,49 @@ character CHAR. Otherwise, insert two of CHAR and put point between them like `electric-pair'." (interactive) ; TODO: can we make CHAR an arg to `interactive'? - (let ((char (or char (string-to-char (this-command-keys)))) - (word (thing-at-point 'word 'no-properties))) + (let* ((char (or char (string-to-char (this-command-keys)))) + (word (thing-at-point 'word 'no-properties)) + ;;; test conditions here to be eval'd, separating flow from data + ;; at beginning of word + (beginning-of-word-test '(or (bolp) (eq (char-before (point)) ?\ ))) + ;; word is surrounded by `char' + (surrounded-by-char-test + '(and (eq (char-before (beginning-of-thing 'word)) char) + (eq (char-after (end-of-thing 'word)) char))) + ;; char before and char after are the same + (double-char-test (eq char (char-after))) + ;; Weird Org exceptions because org + (org-exceptions-test + '(or (string-match-p (rx bol (or "#" "*")) + (thing-at-point 'line 'no-properties)) + (org-in-block-p org-protecting-blocks) + (org-at-property-p)) + ) + ) (cond ((eq evil-state 'visual) (let* ((beg (region-beginning)) (end (region-end))) (evil-surround-region beg end evil-visual-selection char nil))) ((eq evil-state 'normal) - (if (or (bolp) (eq (char-before (point)) ?\ )) ; at beginning of word + (if (eval beginning-of-word-test) ;; run original function bound to key (let ((charstr (make-string 1 char))) - (pcase charstr - ;; TODO: can we not hard-code this? - ("_" (call-interactively 'evil-next-line-1-first-non-blank)) - ("/" (call-interactively 'evil-search-forward)) - ("*" (call-interactively 'evil-search-word-forward)) - ("+" (call-interactively 'evil-next-line-first-non-blank)) - ("~" (call-interactively 'evil-invert-char)) - ("=" (call-interactively 'evil-indent)))) + ;; (pcase charstr + ;; ;; TODO: can we not hard-code this? + ;; ;; MAYBE: with Advice on each below function. + ;; ;; MAYBE: with `key-binding' fn + ;; ("_" (call-interactively 'evil-next-line-1-first-non-blank)) + ;; ("/" (call-interactively 'evil-search-forward)) + ;; ("*" (call-interactively 'evil-search-word-forward)) + ;; ("+" (call-interactively 'evil-next-line-first-non-blank)) + ;; ("~" (call-interactively 'evil-invert-char)) + ;; ("=" (call-interactively 'evil-indent))) + (call-interactively (alist-get charstr org-vw-old-binds-alist + nil nil #'string=)) + ) (save-excursion - (if (and (eq (char-before (beginning-of-thing 'word)) char) - (eq (char-after (end-of-thing 'word)) char)) + (if (eval surrounded-by-char-test) (progn (search-backward (char-to-string char)) (delete-char 1) (search-forward (char-to-string char)) (delete-char -1)) @@ -130,16 +160,21 @@ Otherwise, insert two of CHAR and put point between them like `electric-pair'." (insert char) (end-of-thing 'word) (insert char)))))) - ((eq char (char-after)) - (right-char)) - ((or (string-match-p (rx bol (or "#" "*" "")) - (thing-at-point 'line 'no-properties)) - (org-in-block-p org-protecting-blocks) - (org-at-property-p)) - (insert char)) + ((eval double-char-test) (right-char)) + ((eval org-exceptions-test) (insert char)) (t (progn (insert (make-string 2 char)) (left-char)))))) +(defun org-vw-snapshot-bindings () + "Make an alist of the functions formerly ran by keys to be bound to `mitch/org-dwim-char'. + +Store it in the variable `org-vw-old-binds-alist'." + (unless org-vw-old-binds-alist + (defvar-local org-vw-old-binds-alist + (mapcar (lambda (key) + (cons key (key-binding key))) + mitch/org-dwim-char-chars)))) +(add-hook 'org-vw-pre-hook #'org-vw-snapshot-bindings nil 'local) ;; (setq debug-on-error t) ;; --------- LET THY BRAIN NO LONGER TREMBLE, FOR I AM BECOME COMPLETE ---------