From c047eaa18bc95a9b74f0758b1ea710956e998dcf Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Tue, 2 Jul 2024 21:53:59 -0700 Subject: [PATCH] Fix scrolling preferences in Evil As well as address a bug when selecting an _inclusive_ function as a text object. Now `d a d` will delete a function and the surround whitespace and comments. --- ha-config.org | 7 +++++ ha-evil.org | 87 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/ha-config.org b/ha-config.org index 6ac62b4..c2f1d42 100644 --- a/ha-config.org +++ b/ha-config.org @@ -44,6 +44,13 @@ Changes and settings I like introduced that were introduced in Emacs 28: completions-detailed t) #+end_src +I’ve got preferences for how I like scrolling, and with my org files, I need a little more of the of the context, so this increases from =2= to =3=, but I really like to keep the cursor in place when I can: +#+begin_src emacs-lisp +(setq next-screen-context-lines 3 + scroll-error-top-bottom t + scroll-preserve-screen-position t) +#+end_src + Emacs has some new code to display line-numbers, and the =visual= value works well with my Org files, allowing a jump to a line via ~6 j~: #+begin_src emacs-lisp (setq display-line-numbers-type 'visual) diff --git a/ha-evil.org b/ha-evil.org index e02d1ff..ad8ea21 100644 --- a/ha-evil.org +++ b/ha-evil.org @@ -37,18 +37,6 @@ Some advice that I followed: - [[https://github.com/noctuid/evil-guide][Evil Guide]] - [[https://nathantypanski.com/blog/2014-08-03-a-vim-like-emacs-config.html][A Vim-like Emacs Configuration from Nathan Typanski]] - [[https://stackoverflow.com/questions/25542097/emacs-evil-mode-how-to-change-insert-state-to-emacs-state-automatically][Evil insert state is really Emacs?]] Real answer to that is to set [[help:evil-disable-insert-state-bindings][evil-disable-insert-state-bindings]] - -My Evil configuration should be /optionally/ included, so I define this variable: -#+begin_src emacs-lisp - (defvar ha-evil-on t - "If non-nil, it means that Evil configuration has been turned on.") -#+end_src -Then code through over files (but not this one), would have something like: -#+begin_src emacs-lisp :tangle no - (when (and (boundp 'ha-evil-on) ha-evil-one) - ;; ...access evil... - ) -#+end_src * Evil-Specific Keybindings I split the configuration of Evil mode into sections. First, global settings: #+begin_src emacs-lisp @@ -118,18 +106,10 @@ I’m not a long term VI user, and I generally like /easy keys/, e.g. ~w~, have (evil-define-key '(normal visual motion operator) 'global "b" 'evil-backward-WORD-begin) (evil-define-key '(normal visual motion operator) 'global - "B" 'evil-backward-word-begin) + "B" 'evil-backward-word-begin)) ;; Note that evil-backward-word-end is on the `g e': - - ;; Not a long-term VI user, so let's Emacsify some other keybindings: - (evil-define-key '(normal visual motion operator) 'global - (kbd "C-b") 'scroll-up-command - (kbd "C-f") 'scroll-down-command - (kbd "C-p") 'previous-line - (kbd "C-n") 'next-line - ;; I have better window control: - (kbd "C-w") 'sp-kill-region)) #+end_src + Testing: - =word-subword-subword= - =word_subword_subword= @@ -174,6 +154,33 @@ What text objects are known? - ~c~ :: for comments - ~u~ :: for URLs, really? Useful much? - ~a~ :: function arguments (probably a lot like symbol, ~o~), but the ~a~ can include commas. This comes from [[https://github.com/wcsmith/evil-args][evil-args]] extension (see below). + +I am not a long term VI user, and don’t have much need for any of its control sequences (well, not all), so I made the following more Emacsy. I’ll admit, I like ~C-v~ (and use that all the time), so I need to futz around with the scrolling: + +#+begin_src emacs-lisp + (use-package evil + :config + (evil-define-key '(normal visual motion operator) 'global + (kbd "C-a") 'move-beginning-of-line + (kbd "C-e") 'move-end-of-line + + ;; Since C-y scrolls the window down, Shifted Y goes up: + (kbd "C-y") 'evil-scroll-line-down + (kbd "C-b") 'evil-scroll-line-up + (kbd "C-S-y") 'evil-scroll-line-up + + (kbd "C-d") 'scroll-down-command + (kbd "C-S-d") 'scroll-other-window-down + (kbd "C-f") 'scroll-up-command + (kbd "C-S-f") 'scroll-other-window + + (kbd "C-o") 'open-line ; matches evil's o + (kbd "C-p") 'previous-line + (kbd "C-n") 'next-line + + ;; I have better window control: + (kbd "C-w") 'sp-kill-region)) +#+end_src ** Evil Text Object Line Delete a line, ~d d~ is in basic VI. Since some commands use text objects, and the basic text object doesn’t include lines, the [[https://github.com/emacsorphanage/evil-textobj-line][evil-textobj-line]] project adds that: #+begin_src emacs-lisp @@ -264,6 +271,7 @@ And the keybindings: #+end_src ** Text Object for Functions While Emacs has the ability to recognize functions, the Evil text object does not. But text objects have both an /inner/ and /outer/ form, and what does that mean for a function? The /inner/ will be the /function itself/ and the /outer/ (like words) would be the surrounding /non-function/ stuff … in other words, the distance between the next functions. + #+begin_src emacs-lisp (defun ha-evil-defun-range (count beg end type inclusive) "Get minimum range of `defun` as a text object. @@ -272,16 +280,30 @@ While Emacs has the ability to recognize functions, the Evil text object does no inclusive acquiring the areas between the surrounding defuns." (let ((start (save-excursion (beginning-of-defun) - (when inclusive - (beginning-of-defun) - (end-of-defun)) (point))) (end (save-excursion (end-of-defun count) - (when inclusive - (end-of-defun) - (beginning-of-defun)) (point)))) + (when inclusive + ;; Let's see if we can grab more text ... + (save-excursion + ;; Don't bother if we are at the start of buffer: + (when (> start (point-min)) + (goto-char start) + ;; go to the end of the previous function: + (beginning-of-defun) + (end-of-defun count) + ;; if we found some more text to grab, reset start: + (if (< (point) start) + (setq start (point)))) + ;; Same approach with the end: + (when (< end (point-max)) + (goto-char end) + (end-of-defun) + (beginning-of-defun) + (if (> (point) end) + (setq end (point)))))) + (list start end))) #+end_src @@ -303,6 +325,7 @@ And the keybindings: (define-key evil-inner-text-objects-map "d" #'ha-evil-inner-defun) (define-key evil-outer-text-objects-map "d" #'ha-evil-a-defun) #+end_src + Why not use ~f~? I’m reserving the ~f~ for a tree-sitter version that is not always available for all modes… yet. * Evil Extensions ** Evil Exchange @@ -414,10 +437,10 @@ Not sure what is in a register? Have it show you when you hit ~”~ or ~@~ with :after posframe :config (setq evil-owl-display-method 'posframe - evil-owl-extra-posframe-args '(:width 50 :height 20 :background-color "#444") + evil-owl-extra-posframe-args + '(:width 50 :height 20 :background-color "#444") evil-owl-max-string-length 50) (evil-owl-mode)) - #+end_src ** Evil Surround I like both [[https://github.com/emacs-evil/evil-surround][evil-surround]] and Henrik's [[https://github.com/hlissner/evil-snipe][evil-snipe]], but they both start with ~s~, and conflict, and getting them to work together means I have to remember when does ~s~ call sniper and when it calls surround. As an original Emacs person, I am not bound by that key history, but I do need them consistent, so I’m choosing the ~s~ to be /surround/. @@ -460,8 +483,8 @@ The [[https//github.com/gilbertw1/better-jumper][better-jumper project]] replace (better-jumper-mode +1) (with-eval-after-load 'evil-maps - (define-key evil-motion-state-map (kbd "C-o") 'better-jumper-jump-backward) - (define-key evil-motion-state-map (kbd "C-i") 'better-jumper-jump-forward))) + (define-key evil-motion-state-map (kbd "M-[") 'better-jumper-jump-backward) + (define-key evil-motion-state-map (kbd "M-]") 'better-jumper-jump-forward))) #+end_src * Technical Artifacts :noexport: