dotfiles/emacs/.emacs.d/config/init-editing.el
2024-06-06 11:49:48 -04:00

176 lines
5.1 KiB
EmacsLisp

;; -*- lexical-binding: t; -*-
;; General text editing configuration
;; Better isearch
(use-package ctrlf
:config
(ctrlf-mode 1))
(use-package avy
:config
(with-eval-after-load 'embark
(defun avy-action-embark (point)
(unwind-protect
(save-excursion
(goto-char point)
(embark-act))
(select-window
(cdr (ring-ref avy-ring 0))))
t)
(setf (alist-get ?. avy-dispatch-alist)
#'avy-action-embark)
(add-to-list 'avy-dispatch-alist '(?\C-. . avy-action-embark)))
:bind
("M-f" . avy-goto-char-timer))
;; "pair" management, where pairs are parentheses, braces, etc.
(use-package smartparens
:init
(leader-def-key "s" '(nil :which-key "smartparens"))
:config
(require 'smartparens-config)
(smartparens-global-mode)
(defun sp-wrap-double-quote ()
(interactive)
(sp-wrap-with-pair "\""))
(defun sp-wrap-single-quote ()
(interactive)
(sp-wrap-with-pair "'"))
(defun sp-wrap-angle-bracket ()
(interactive)
(sp-wrap-with-pair "<"))
(defun sp-wrap-backtick ()
(interactive)
(sp-wrap-with-pair "`"))
(defun sp-after-equals-p (_id action _context)
(when (memq action '(insert navigate))
(sp--looking-back-p "=>" 2)))
;; Enable ES6 arrow functions in web mode
(defun sp-after-equals-skip-p (ms mb _me)
(when (eq ms ">")
(save-excursion
(goto-char mb)
(sp--looking-back-p "=" 1))))
(defun sp-web-mode-is-code-context (id action context)
(and (eq action 'insert)
(not (or (get-text-property (point) 'part-side)
(get-text-property (point) 'block-side)))))
(sp-local-pair '(web-mode) "<" nil
:when '(sp-web-mode-is-code-context)
:unless '(:add sp-after-equals-p)
:skip-match 'sp-after-equals-skip-p)
:hook
(prog-mode . smartparens-strict-mode)
(eshell-mode . smartparens-strict-mode)
:general
;; Wrapping
(leader-map
"s(" #'sp-wrap-round
"s{" #'sp-wrap-curly
"s'" #'sp-wrap-single-quote
"s\"" #'sp-wrap-double-quote
"sW" #'sp-unwrap-sexp
"sl" #'sp-next-sexp
"sh" #'sp-backward-sexp
"sj" #'sp-down-sexp
"sk" #'sp-backward-up-sexp
"sL" #'sp-forward-symbol
"sH" #'sp-backward-symbol
"s^" #'sp-beginning-of-sexp
"s$" #'sp-end-of-sexp
"st" #'sp-transpose-sexp
"su" #'undo-tree-undo
"sy" #'sp-copy-sexp
"sd" #'sp-kill-sexp
"ss" #'sp-forward-slurp-sexp
"sS" #'sp-backward-slurp-sexp
"sb" #'sp-forward-barf-sexp
"sB" #'sp-backward-barf-sexp
"sv" #'sp-select-next-thing
"sV" #'sp-select-previous-thing)
(normal "g(" #'sp-wrap-round
"g[" #'sp-wrap-square
"g{" #'sp-wrap-curly
"g\"" #'sp-wrap-double-quote
"g'" #'sp-wrap-single-quote
"g<" #'sp-wrap-angle-bracket
"g`" #'sp-wrap-backtick))
(use-package evil-smartparens
:after (evil smartparens)
:hook (smartparens-enabled . evil-smartparens-mode))
;; Automagical indent
(use-package aggressive-indent
:hook ((lisp-mode . aggressive-indent-mode)
(emacs-lisp-mode . aggressive-indent-mode)
(clojure-mode . aggressive-indent-mode)))
;; Highlight indent level for whitespace-sensitive languages
(use-package highlight-indent-guides
:commands highlight-indent-guides-mode
:custom
(highlight-indent-guides-method 'character)
(highlight-indent-guides-auto-character-face-perc 7)
(highlight-indent-guides-responsive 'stack)
(highlight-indent-guides-auto-stack-character-face-perc 10))
;; Handy mode for prose writing and reading
(use-package olivetti
:general
("C-c o" #'olivetti-mode)
:custom
(olivetti-body-width 120))
;; Multiple cursors
(use-package evil-multiedit
:defer 2
:config
(evil-multiedit-default-keybinds))
;; Don't choke on files with long lines
(use-package so-long
:straight (:type built-in)
:demand t
:config
(global-so-long-mode))
;; Polite white-space trimming
(use-package ws-butler
:hook (prog-mode . ws-butler-mode))
;; Inc/dec numbers
(use-package evil-numbers
:straight (:host github :repo "juliapath/evil-numbers")
:general
(normal "g+" #'evil-numbers/inc-at-pt)
(normal "g-" #'evil-numbers/dec-at-pt)
(normal "g M-+" #'evil-numbers/inc-at-pt-incremental)
(normal "g M--" #'evil-numbers/dec-at-pt-incremental))
;; Manipulate string inflection, e.g. camelCase -> snake_case
(use-package evil-string-inflection
:general
(normal "gc" #'evil-operator-string-inflection))
(use-package origami
:hook ((prog-mode . origami-mode)
(text-mode . origami-mode))
:config
(defun origami-toggle-all-nodes-same-level (buffer point)
(interactive (list (current-buffer) (point)))
(when-let ((tree (origami-get-fold-tree buffer)))
(when-let ((path (origami-fold-find-path-containing tree point)))
(let ((parent (origami-fold-parent path)))
(dolist (fold (origami-fold-children parent))
(origami-toggle-node buffer (origami-fold-beg fold)))))))
(defun origami-setup ()
(evil-local-set-key 'normal (kbd "zM") #'origami-toggle-all-nodes-same-level))
(add-hook 'origami-mode-hook #'origami-setup))
(provide 'init-editing)