Skip to content

Commit

Permalink
Merge pull request #37 from alexispurslane/develop
Browse files Browse the repository at this point in the history
Improve evil mode.
  • Loading branch information
alexispurslane authored Jan 22, 2025
2 parents 0ebf49f + b6933b8 commit b515d17
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 272 deletions.
212 changes: 63 additions & 149 deletions evil-layer.el
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,26 @@ the second object is either a string or a list containing the
query to be made for that text object minus the .inner and .outer
qualifiers."
:group 'quake)

(defun quake--evil-escape-dwim ()
"Intuitive escape behavior.
Kills, exits, or escapes literally everything with successive
repetitions."
(interactive)
(when (and (fboundp 'corfu-quit) completion-in-region-mode) (corfu-quit))
(when overwrite-mode (overwrite-mode -1))
(cond ((region-active-p) (deactivate-mark))
((not (evil-normal-state-p)) (evil-normal-state))
(god-local-mode (god-local-mode -1)
(evil-normal-state))
(isearch-mode (isearch-exit))
((eq last-command 'mode-exited) nil)
((> (minibuffer-depth) 0) (abort-recursive-edit))
(current-prefix-arg nil)
((> (recursion-depth) 0) (exit-recursive-edit))
(buffer-quit-function (funcall buffer-quit-function))
((string-match "^ \\*" (buffer-name (current-buffer)))
(bury-buffer))))
(defun optional/evil-layer ()
"'Emacs is a great OS, if only it had a good editor.' With
the powerful text-object based command language of Vim, and the
Expand All @@ -81,76 +100,62 @@ qualifiers."
Loads:
- `evil', the Emacs editor of choice
- `evil-collection', to integrate Evil mode with everything else
- `evil-org-mode', for good org mode keybindings for Evil
- `treemacs-evil', for good treemacs keybindings for Evil
- `evil-god-state', to use god mode as an automatic leader key
for evil mode that supports all the existing emacs
keybindings"
- `evil-god-state', to use `god-mode' as a leader key"

;;;;; Evil mode itself (and associated integrations)
(use-package evil
:custom
(evil-want-integration t)
(evil-want-minibuffer t)
(evil-want-keybinding nil)
(evil-want-C-u-scroll t)
(evil-want-C-i-jump nil)
(evil-undo-system 'undo-redo)
(evil-kill-on-visual-paste nil) ;; oh thank god
(evil-move-beyond-eol t) ;; so that it's easier to evaluate sexprs in normal mode
(evil-disable-insert-state-bindings t) ; so that to access Emacs keybindings for any mode your in, you only need to enter insert mode.
(evil-want-integration t) ; some little mods evil mode provides to work better with various built in things
(evil-want-minibuffer t) ; enable evil in the minibuffer
(evil-want-keybinding nil) ; not sure what this does
(evil-want-C-u-scroll nil) ; you want access to C-u so that you can send numeric arguments (usually for repeat counts) to Emacs commands
(evil-want-C-d-scroll nil) ; disabling C-d for symmetry
(evil-want-C-i-jump t) ; C-i should probably do what Vimmers expect it to do
(evil-undo-system 'undo-redo) ; use the built in Emacs undo system (this has different, but imo much superior, behavior)
(evil-kill-on-visual-paste nil) ;; oh thank god (don't copy what you just replaced when pasting over something that was selected in visual mode)
(evil-move-beyond-eol t) ;; so that it's easier to evaluate sexprs in normal mode, let you go one char past the end of the line
:config
(evil-mode 1)

;;;;; Enable evil motion mode for all Emacsy UI buffers

;; we want to do this so that basic motion keys like
;; hjkl, w, b, etc, all work as expected. You can use
;; insert mode, or the backslash key, to send commands
;; through to the Emacs buffer underneath.
(setq evil-motion-state-modes (append evil-motion-state-modes
evil-emacs-state-modes))
(setq evil-emacs-state-modes nil)

;; Disable fully toggling off Evil mode though, because
;; we already have emacs keybindings in insert mode, and
;; through the god-mode leader state, and this method of
;; toggling is... really hard to exit and really
;; confusing.
(global-unset-key (kbd "C-z"))

;; Pass the return and tab characters through motion mode directly for easier interaction with many UIs
(delete (assoc 13 evil-motion-state-map) evil-motion-state-map)
(delete (assoc 9 evil-motion-state-map) evil-motion-state-map)

(remove-hook 'post-command-hook 'quake-god-mode-update-cursor-type)

(quake-emacs-define-key god-local-mode-map
"<escape>" 'quake--evil-escape-dwim)
(quake-evil-define-key (motion god visual normal insert) override-global-map
"<escape>" 'quake--evil-escape-dwim)
(global-set-key (kbd "<escape>") 'motion-selection--escape-dwim)

;;;;; Custom evil mode key bindings
;; Make :q close the buffer and window, not quit the entire
;; Emacs application (we never leave Emacs!)
(global-set-key [remap evil-quit] 'kill-buffer-and-window)

;; Override evil mode's exceptions to defaulting to normal-mode
(evil-set-initial-state 'enlight-mode 'motion)
(evil-set-initial-state 'minibuffer-mode 'insert)

;;;;;; CUA integration
(add-hook 'evil-insert-state-entry-hook (lambda () (cua-mode 1)))
(add-hook 'evil-normal-state-entry-hook (lambda () (cua-mode -1)))
;;;;;; Miscillanious useful keybindings for emacs capabilities
(quake-evil-define-key (normal visual) global-map
"g ." 'embark-act
"g RET" 'embark-dwim
;; buffers
"gb" 'evil-switch-to-windows-last-buffer
;; org mode
"gt" 'org-toggle-checkbox
;; fill-region >> vim gqq
"gq" 'fill-region-as-paragraph
;; Support for visual fill column mode and visual line mode
;; Make evil-mode up/down operate in screen lines instead of logical lines
"j" 'evil-next-visual-line
"k" 'evil-previous-visual-line
;; outline keybindings
"gh" 'outline-up-heading
"gj" 'outline-forward-same-level
"gk" 'outline-backward-same-level
"gl" 'outline-next-visible-heading
"gu" 'outline-previous-visible-heading)

(quake-evil-define-key (normal motion) global-map
;; tab bar mode
"gR" 'tab-rename
"gn" 'tab-bar-new-tab
"gx" 'tab-bar-close-tab
"gX" 'tab-bar-close-other-tabs
;; Nice commenting
"gc" 'comment-region
"gC" 'uncomment-region)

(quake-evil-define-key (normal motion) (outline-minor-mode-map org-mode-map outline-mode-map diff-mode-map)
"TAB" 'evil-toggle-fold)
(quake-evil-define-key (normal motion) (org-mode-map)
"RET" 'evil-org-return)
;;;;;; Miscillanious useful keybindings for emacs capabilities
(quake-evil-define-key (god) global-map
"C-w" evil-window-map
"C-w C-u" 'winner-undo))
Expand All @@ -160,10 +165,11 @@ qualifiers."
:config
(quake-evil-define-key (motion normal visual) override-global-map
"SPC" 'evil-execute-in-god-state)
;;;;; Make which-key for the top level keybindings show up when you enter evil-god-state
;;;;; Allow you to run leader key commands on selected text
(add-hook 'evil-local-mode-hook
(lambda () (remove-hook 'activate-mark-hook 'evil-visual-activate-hook t)))


;;;;; Make which-key for the top level keybindings show up when you enter evil-god-state
(add-hook 'evil-god-state-exit-hook
(lambda ()
(which-key--hide-popup)))
Expand All @@ -173,96 +179,4 @@ qualifiers."
nil
(lambda (x) (and (not (null (car x)))
(not (null (cdr x)))))
"Top-level bindings"))))

(use-package evil-collection
:after (evil)
:config
(evil-collection-init))

(use-package treemacs-evil
:after (treemacs evil)
:ensure t)

(use-package evil-org
:after org
:hook (org-mode . evil-org-mode))

;;;;; Evil mode text object support

;; NOTE: Eventually replace this *entire* boondoggle with
;; [[https://github.com/dvzubarev/evil-ts-obj/tree/master]],
;; which provides an even better set of text objects, and a
;; far more complete set of operations on them, instead of me
;; manually having to implement them. This would mean *all*
;; tree-sitter langauges get slurp/barf/convolute/etc,
;; meaning that we could eliminate evil-cleverparents and
;; just have a generalized structural editing system on our
;; hands. Currently however, it depends on Emacs 30.0.50.
(use-package evil-textobj-tree-sitter
:after (evil evil-collection)
:config
;; Thanks to foxfriday/evil-ts for this one
(defun evil-ts-expand-region ()
"Expand selection to the closest tree-sitter parent node."
(let* ((point (point))
(mark (or (mark t) point))
(start (min point mark))
(end (max point mark))
(node (treesit-node-at start))
(parent (treesit-parent-until node
(lambda (n) (and (> start (treesit-node-start n))
(< end (treesit-node-end n))))
nil))
(pstart (if parent (treesit-node-start parent) nil))
(pend (if parent (treesit-node-end parent) nil)))
(when parent
(goto-char pstart)
(list pstart pend))))

;; make "tree sitter expand region" a manipulable text object
(evil-define-text-object evil-ts-text-obj-expand-region (count &optional beg end type)
(evil-ts-expand-region))

;; bind it to "x"
(define-key evil-outer-text-objects-map "x" 'evil-ts-text-obj-expand-region)
(define-key evil-inner-text-objects-map "x" 'evil-ts-text-obj-expand-region)

;; This being a macro is necessary because define-key does not
;; evaluate its arguments so it won't work in a regular loop.
(eval-when-compile
(defmacro define-textobjs ()
"Loop through `quake-evil-text-objects' and construct
a flat list of the `define-key' expressions to set the text objects up."
`(progn ,@(cl-loop for thing in quake-evil-text-objects
for key = (car thing)
for query = (if (listp (cdr thing)) (cdr thing) (list (cdr thing)))

for outer-query = (mapcar (lambda (x) (concat x ".outer")) query)
for inner-query = (mapcar (lambda (x) (concat x ".inner")) query)

for docname-start = (concat "go-to-next-" (car query) "-start")
for docname-end = (concat "go-to-next-" (car query) "-end")

appending
`((define-key evil-outer-text-objects-map ,key
(evil-textobj-tree-sitter-get-textobj ,outer-query))
(define-key evil-inner-text-objects-map ,key
(evil-textobj-tree-sitter-get-textobj ,inner-query))
(quake-evil-define-key (normal visual) global-map
;; go to next start
,(concat "[" key) (cons
,(concat "goto-textobj-" (car query) "-start")
(lambda ()
(interactive)
(evil-textobj-tree-sitter-goto-textobj ,(car outer-query) t nil)))
;; go to next end
,(concat "]" key) (cons
,(concat "goto-textobj-" (car query) "-end")
(lambda ()
(interactive)
(evil-textobj-tree-sitter-goto-textobj ,(car outer-query) nil t)))))
into exprs

finally (return exprs)))))
(define-textobjs)))
"Top-level bindings")))))
Loading

0 comments on commit b515d17

Please sign in to comment.