diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index 014b42ada..7fe9652ca 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -54,27 +54,49 @@ ;; misc :n "C-S-f" #'toggle-frame-fullscreen - ;; Global evil keybinds - :m "]a" #'evil-forward-arg - :m "[a" #'evil-backward-arg - :m "]o" #'outline-next-visible-heading - :m "[o" #'outline-previous-visible-heading + ;; ported vim keys + :nv "z=" #'flyspell-correct-word-generic + :v "@" #'+evil:apply-macro + + ;; ported from vim-unimpaired + :n "] SPC" #'+evil/insert-newline-below + :n "[ SPC" #'+evil/insert-newline-above :n "]b" #'next-buffer :n "[b" #'previous-buffer - :n "zx" #'kill-current-buffer - :n "ZX" #'bury-buffer + :n "]f" #'+evil/next-file + :n "[f" #'+evil/previous-file + :m "]u" #'+evil:url-encode + :m "[u" #'+evil:url-decode + :m "]y" #'+evil:c-string-encode + :m "[y" #'+evil:c-string-decode + ;; NOTE hl-todo-{next,previous} have ]t/[t, use ]F/[F instead + ;; NOTE {next,previous}-error have ]e/[e, use ddp/ddP or gx instead + (:when (featurep! :lang web) + :m "]x" #'+web:encode-html-entities + :m "[x" #'+web:decode-html-entities) + + ;; custom vim-unmpaired-esque keys + :m "]a" #'evil-forward-arg + :m "[a" #'evil-backward-arg + :n "]F" #'+evil/next-frame + :n "[F" #'+evil/previous-frame + :m "]h" #'outline-next-visible-heading + :m "[h" #'outline-previous-visible-heading + :n "[o" #'+evil/insert-newline-above + :n "]o" #'+evil/insert-newline-below :n "gp" #'+evil/reselect-paste + :v "gp" #'+evil/paste-preserve-register + :nv "g@" #'+evil:apply-macro + :nv "gc" #'evil-commentary + :nv "gx" #'evil-exchange :n "g=" #'evil-numbers/inc-at-pt :n "g-" #'evil-numbers/dec-at-pt :v "g=" #'evil-numbers/inc-at-pt-incremental :v "g-" #'evil-numbers/dec-at-pt-incremental :v "g+" #'evil-numbers/inc-at-pt - :nv "z=" #'flyspell-correct-word-generic - :nv "g@" #'+evil:apply-macro - :nv "gc" #'evil-commentary - :nv "gx" #'evil-exchange - :v "gp" #'+evil/paste-preserve-register - :v "@" #'+evil:apply-macro + ;; custom evil keybinds + :n "zx" #'kill-current-buffer + :n "ZX" #'bury-buffer ;; repeat in visual mode (FIXME buggy) :v "." #'+evil:apply-macro ;; don't leave visual mode after shifting diff --git a/modules/editor/evil/autoload/evil.el b/modules/editor/evil/autoload/evil.el index 9d453a45f..298be82f4 100644 --- a/modules/editor/evil/autoload/evil.el +++ b/modules/editor/evil/autoload/evil.el @@ -31,16 +31,6 @@ (evil-normal-state) (evil-visual-restore)) -;;;###autoload -(defun +evil/reselect-paste () - "Return to visual mode and reselect the last pasted region." - (interactive) - (cl-destructuring-bind (_ _ _ beg end &optional _) - evil-last-paste - (evil-visual-make-selection - (save-excursion (goto-char beg) (point-marker)) - end))) - ;;;###autoload (defun +evil/paste-preserve-register () "Call `evil-paste-after' without overwriting the clipboard (by writing to the diff --git a/modules/editor/evil/autoload/unimpaired.el b/modules/editor/evil/autoload/unimpaired.el new file mode 100644 index 000000000..e2fcf4b52 --- /dev/null +++ b/modules/editor/evil/autoload/unimpaired.el @@ -0,0 +1,131 @@ +;;; editor/evil/autoload/unimpaired.el -*- lexical-binding: t; -*- + +;; These are ported from vim-unimpaired https://github.com/tpope/vim-unimpaired +;; and bound in the :config default module (in +evil-bindings.el). + +;; +;;; Next/Previous commands + +;;; ] SPC / [ SPC +;;;###autoload +(defun +evil/insert-newline-below (count) + "Insert COUNT blank line(s) below current line. Does not change modes." + (interactive "p") + (dotimes (_ count) + (save-excursion (evil-insert-newline-below)))) + +;;;###autoload +(defun +evil/insert-newline-above (count) + "Insert COUNT blank line(s) above current line. Does not change modes." + (interactive "p") + (dotimes (_ count) + (save-excursion (evil-insert-newline-above)))) + +;;; ]t / [t +;;;###autoload +(defun +evil/next-frame (count) + "Focus next frame." + (interactive "p") + (dotimes (_ (abs count)) + (let ((frame (if (> count 0) (next-frame) (previous-frame)))) + (if (eq frame (selected-frame)) + (user-error "No other frame") + (select-frame-set-input-focus frame))))) + +;;;###autoload +(defun +evil/previous-frame (count) + "Focus previous frame." + (interactive "p") + (+evil/next-frame (- count))) + +;;; ]f / [f +(defun +evil--next-file (n) + (unless buffer-file-name + (user-error "Must be called from a file-visiting buffer")) + (let* ((directory (file-name-directory buffer-file-name)) + (filename (file-name-nondirectory buffer-file-name)) + (files (doom-files-in directory :depth 0 :sort t :match "/[^._][^/]*$")) + (index (cl-position filename files :test #'string=))) + (when (null index) + (user-error "Couldn't find this file in current directory")) + (let ((index (+ index n))) + (cond ((>= index (length files)) + (user-error "No files after this one")) + ((< index 0) + (user-error "No files before this one")) + ((expand-file-name (nth index files) directory)))))) + +;;;###autoload +(defun +evil/next-file (count) + "Open file following this one, alphabetically, in the same directory." + (interactive "p") + (find-file (+evil--next-file count))) + +;;;###autoload +(defun +evil/previous-file (count) + "Open file preceding this one, alphabetically, in the same directory." + (interactive "p") + (find-file (+evil--next-file (- count)))) + + +;; +;;; Encoding/Decoding + +;; NOTE For ]x / [x see :lang web +;; - `+web:encode-html-entities' +;; - `+web:decode-html-entities' + +(defun +evil--encode (beg end fn) + (save-excursion + (goto-char beg) + (let* ((end (if (eq evil-this-type 'line) (1- end) end)) + (text (buffer-substring-no-properties beg end))) + (delete-region beg end) + (insert (funcall fn text))))) + +;;; ]u / [u +;;;###autoload (autoload '+evil:url-encode "editor/evil/autoload/unimpaired" nil t) +(evil-define-operator +evil:url-encode (count &optional beg end type) + "TODO" + (interactive "") + (+evil--encode beg end #'url-encode-url)) + +;;;###autoload (autoload '+evil:url-decode "editor/evil/autoload/unimpaired" nil t) +(evil-define-operator +evil:url-decode (count &optional beg end type) + "TODO" + (interactive "") + (+evil--encode beg end #'url-unhex-string)) + +;;; ]y / [y +;;;###autoload (autoload '+evil:c-string-encode "editor/evil/autoload/unimpaired" nil t) +(evil-define-operator +evil:c-string-encode (count &optional beg end type) + "TODO" + (interactive "") + (+evil--encode + beg end + (lambda (text) + (replace-regexp-in-string "[\"\\]" (lambda (ch) (concat "\\" ch)) text)))) + +;;;###autoload (autoload '+evil:c-string-decode "editor/evil/autoload/unimpaired" nil t) +(evil-define-operator +evil:c-string-decode (count &optional beg end type) + "TODO" + (interactive "") + (+evil--encode + beg end + (lambda (text) + (replace-regexp-in-string "\\\\[\"\\]" (lambda (str) (substring str 1)) text)))) + + +;; +;;; Standalone + +;;; gp +;;;###autoload +(defun +evil/reselect-paste () + "Return to visual mode and reselect the last pasted region." + (interactive) + (cl-destructuring-bind (_ _ _ beg end &optional _) + evil-last-paste + (evil-visual-make-selection + (save-excursion (goto-char beg) (point-marker)) + end)))