aboutsummaryrefslogtreecommitdiff
path: root/.config/emacs/lisp/expand-region
diff options
context:
space:
mode:
authorJack Jamison <jackqjamison@gmail.com>2026-07-05 01:19:30 -0400
committerJack Jamison <jackqjamison@gmail.com>2026-07-05 01:19:30 -0400
commitbdf9a71ab7baa2b1de9abcfd5df1a9107a55d141 (patch)
treec4524e6c41aa5107211103401dabfaefc81aa882 /.config/emacs/lisp/expand-region
parentfe3984f541bd32bdfa418afb305b614176b55ca0 (diff)
add a bunch of emacs packages HELP
Diffstat (limited to '.config/emacs/lisp/expand-region')
-rw-r--r--.config/emacs/lisp/expand-region/cc-mode-expansions.el186
-rw-r--r--.config/emacs/lisp/expand-region/er-basic-expansions.el267
-rw-r--r--.config/emacs/lisp/expand-region/expand-region-core.el322
-rw-r--r--.config/emacs/lisp/expand-region/expand-region-custom.el115
-rw-r--r--.config/emacs/lisp/expand-region/expand-region.el198
5 files changed, 1088 insertions, 0 deletions
diff --git a/.config/emacs/lisp/expand-region/cc-mode-expansions.el b/.config/emacs/lisp/expand-region/cc-mode-expansions.el
new file mode 100644
index 0000000..126b7f1
--- /dev/null
+++ b/.config/emacs/lisp/expand-region/cc-mode-expansions.el
@@ -0,0 +1,186 @@
+;;; cc-mode-expansions.el --- C-specific expansions for expand-region -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2023 Free Software Foundation, Inc
+
+;; Author: François Févotte
+;; Based on js-mode-expansions by: Magnar Sveen <magnars@gmail.com>
+;; Keywords: marking region
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Extra expansions for C-like modes that I've found useful so far:
+;;
+;; er/c-mark-statement
+;; Captures simple and more complex statements.
+;;
+;; er/c-mark-fully-qualified-name
+;; Captures identifiers composed of several '::'-separated parts.
+;;
+;; er/c-mark-function-call[-1|-2]
+;; Captures an identifier followed by a '()'-enclosed block.
+;;
+;; er/c-mark-statement-block[-1|-2]
+;; Captures a statement followed by a '{}'-enclosed block.
+;; This matches function definitions and if/for/... constructs.
+;;
+;; er/c-mark-vector-access[-1|-2]
+;; Captures an identifier followed by a '[]'-enclosed block.
+;;
+;; Feel free to contribute any other expansions for C at
+;;
+;; https://github.com/magnars/expand-region.el
+
+;;; Code:
+
+(require 'expand-region-core)
+(require 'er-basic-expansions)
+(require 'cc-cmds)
+
+(defun er/c-mark-statement ()
+ "Mark the current C statement.
+
+This function tries to ensure that pair-delimited substring are
+either fully inside or fully outside the statement."
+ (interactive)
+ (unless (use-region-p)
+ (set-mark (point)))
+
+ (if (< (point) (mark))
+ (exchange-point-and-mark))
+
+ ;; Contract the region a bit to make the
+ ;; er/c-mark-statement function idempotent
+ (when (>= (- (point) (mark)) 2)
+ (exchange-point-and-mark)
+ (forward-char)
+ (exchange-point-and-mark)
+ (backward-char))
+
+ (let (beg end)
+ ;; Determine boundaries of the outside-pairs region
+ (save-mark-and-excursion
+ (c-end-of-statement)
+ (er/mark-outside-pairs)
+ (setq beg (point)
+ end (mark)))
+
+ ;; Determine boundaries of the statement as given
+ ;; by c-beginning-of-statement/c-end-of-statement
+ (c-end-of-statement)
+ (exchange-point-and-mark)
+ (c-end-of-statement)(c-beginning-of-statement 1)
+
+ ;; If the two regions overlap, expand the region
+ (cond ((and (<= (point) beg)
+ (< (mark) end))
+ (set-mark end))
+ ((and (> (point) beg)
+ (>= (mark) end))
+ (goto-char beg)
+ (c-end-of-statement)
+ (c-beginning-of-statement 1)))))
+
+(defun er/c-mark-fully-qualified-name ()
+ "Mark the current C++ fully qualified identifier.
+
+This function captures identifiers composed of multiple
+'::'-separated parts."
+ (interactive)
+ (er/mark-symbol)
+ (when (use-region-p)
+ (when (> (point) (mark))
+ (exchange-point-and-mark))
+ (while (er/looking-back-exact "::")
+ (backward-char 2)
+ (skip-syntax-backward "_w"))
+ (exchange-point-and-mark)
+ (while (looking-at "::")
+ (forward-char 2)
+ (skip-syntax-forward "_w"))
+ (exchange-point-and-mark)))
+
+(defmacro er/c-define-construct (name mark-first-part open-brace doc)
+ (let ((docstring (make-symbol "docstring-tmp")))
+ (setq docstring
+ (concat
+ doc "\n\n"
+ "This function tries to mark a region consisting of two parts:\n"
+ (format " - the first part is marked using `%s'\n" (symbol-name mark-first-part))
+ (format " - the second part is a block beginning with %S\n\n" open-brace)))
+ `(progn
+ (defun ,(intern (concat (symbol-name name) "-1")) ()
+ ,(concat docstring
+ "This function assumes that point is in the first part and the\n"
+ "region is active.\n\n"
+ (format "See also `%s'." (concat (symbol-name name) "-2")))
+ (interactive)
+ (when (use-region-p)
+ (,mark-first-part)
+ (exchange-point-and-mark)
+ (let ((oldpos (point)))
+ (skip-syntax-forward " ")
+ (if (looking-at ,open-brace)
+ (progn (forward-sexp)
+ (exchange-point-and-mark))
+ (goto-char oldpos)))))
+ (defun ,(intern (concat (symbol-name name) "-2")) ()
+ ,(concat docstring
+ "This function assumes that the block constituting the second part\n"
+ "is already marked and active.\n\n"
+ (format "See also `%s'." (concat (symbol-name name) "-1")))
+ (interactive)
+ (when (use-region-p)
+ (when (> (point) (mark))
+ (exchange-point-and-mark))
+ (when (looking-at ,open-brace)
+ (let ((beg (point))
+ (end (progn (forward-sexp 1)
+ (point))))
+ (goto-char beg)
+ (skip-syntax-backward " ")
+ (backward-char)
+ (deactivate-mark)
+ (,mark-first-part)
+ (set-mark end))))))))
+
+(er/c-define-construct er/c-mark-function-call er/c-mark-fully-qualified-name "("
+ "Mark the current function call.")
+(er/c-define-construct er/c-mark-statement-block er/c-mark-statement "{"
+ "Mark the current block construct (like if, for, etc.)")
+(er/c-define-construct er/c-mark-vector-access er/c-mark-fully-qualified-name "\\["
+ "Mark the current vector access.")
+
+(defun er/add-cc-mode-expansions ()
+ "Adds expansions for buffers in c-mode."
+ (set (make-local-variable 'er/try-expand-list)
+ (append er/try-expand-list
+ '(er/c-mark-statement
+ er/c-mark-fully-qualified-name
+ er/c-mark-function-call-1 er/c-mark-function-call-2
+ er/c-mark-statement-block-1 er/c-mark-statement-block-2
+ er/c-mark-vector-access-1 er/c-mark-vector-access-2))))
+
+(er/enable-mode-expansions 'c-mode #'er/add-cc-mode-expansions)
+(er/enable-mode-expansions 'c++-mode #'er/add-cc-mode-expansions)
+(er/enable-mode-expansions 'objc-mode #'er/add-cc-mode-expansions)
+(er/enable-mode-expansions 'java-mode #'er/add-cc-mode-expansions)
+(er/enable-mode-expansions 'idl-mode #'er/add-cc-mode-expansions)
+(er/enable-mode-expansions 'pike-mode #'er/add-cc-mode-expansions)
+(er/enable-mode-expansions 'awk-mode #'er/add-cc-mode-expansions)
+
+(provide 'cc-mode-expansions)
+
+;; cc-mode-expansions.el ends here
diff --git a/.config/emacs/lisp/expand-region/er-basic-expansions.el b/.config/emacs/lisp/expand-region/er-basic-expansions.el
new file mode 100644
index 0000000..08cdc56
--- /dev/null
+++ b/.config/emacs/lisp/expand-region/er-basic-expansions.el
@@ -0,0 +1,267 @@
+;;; er-basic-expansions.el --- Words, symbols, strings, et al -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011-2023 Free Software Foundation, Inc
+
+;; Author: Magnar Sveen <magnars@gmail.com>
+;; Keywords: marking region
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Expansions that are useful in any major mode.
+
+;;; Code:
+
+(require 'expand-region-core)
+
+(defun er/mark-word ()
+ "Mark the entire word around or in front of point."
+ (interactive)
+ (let ((word-regexp "\\sw"))
+ (when (or (looking-at word-regexp)
+ (er/looking-back-on-line word-regexp))
+ (skip-syntax-forward "w")
+ (set-mark (point))
+ (skip-syntax-backward "w"))))
+
+(defun er/mark-symbol ()
+ "Mark the entire symbol around or in front of point."
+ (interactive)
+ (let ((symbol-regexp "\\s_\\|\\sw"))
+ (when (or (looking-at symbol-regexp)
+ (er/looking-back-on-line symbol-regexp))
+ (skip-syntax-forward "_w")
+ (set-mark (point))
+ (skip-syntax-backward "_w"))))
+
+(defun er/mark-symbol-with-prefix ()
+ "Mark the entire symbol around or in front of point, including prefix."
+ (interactive)
+ (let ((symbol-regexp "\\s_\\|\\sw")
+ (prefix-regexp "\\s'"))
+ (when (or (looking-at prefix-regexp)
+ (looking-at symbol-regexp)
+ (er/looking-back-on-line symbol-regexp))
+ (skip-syntax-forward "'")
+ (skip-syntax-forward "_w")
+ (set-mark (point))
+ (skip-syntax-backward "_w")
+ (skip-syntax-backward "'"))))
+
+;; Mark method call
+
+(defun er/mark-next-accessor ()
+ "Presumes that current symbol is already marked, skips over one
+period and marks next symbol."
+ (interactive)
+ (when (use-region-p)
+ (when (< (point) (mark))
+ (exchange-point-and-mark))
+ ;; (let ((symbol-regexp "\\s_\\|\\sw"))
+ (when (looking-at "\\.")
+ (forward-char 1)
+ (skip-syntax-forward "_w")
+ (exchange-point-and-mark)))) ;; )
+
+(defun er/mark-method-call ()
+ "Mark the current symbol (including dots) and then paren to closing paren."
+ (interactive)
+ (let ((symbol-regexp "\\(\\s_\\|\\sw\\|\\.\\)+"))
+ (when (or (looking-at symbol-regexp)
+ (er/looking-back-on-line symbol-regexp))
+ (skip-syntax-backward "_w.")
+ (set-mark (point))
+ (when (looking-at symbol-regexp)
+ (goto-char (match-end 0)))
+ (if (looking-at "(")
+ (forward-list))
+ (exchange-point-and-mark))))
+
+;; Comments
+
+(defun er--point-is-in-comment-p ()
+ "t if point is in comment, otherwise nil"
+ (or (nth 4 (syntax-ppss))
+ (memq (get-text-property (point) 'face) '(font-lock-comment-face font-lock-comment-delimiter-face))))
+
+(defun er/mark-comment ()
+ "Mark the entire comment around point."
+ (interactive)
+ (when (er--point-is-in-comment-p)
+ (let ((p (point)))
+ (while (and (er--point-is-in-comment-p) (not (eobp)))
+ (forward-char 1))
+ (skip-chars-backward "\n\r")
+ (set-mark (point))
+ (goto-char p)
+ (while (er--point-is-in-comment-p)
+ (forward-char -1))
+ (forward-char 1))))
+
+;; Quotes
+
+(defun er--current-quotes-char ()
+ "The char that is the current quote delimiter"
+ (nth 3 (syntax-ppss)))
+
+(defalias 'er--point-inside-string-p #'er--current-quotes-char)
+
+(defun er--move-point-forward-out-of-string ()
+ "Move point forward until it exits the current quoted string."
+ (er--move-point-backward-out-of-string)
+ (forward-sexp))
+
+(defun er--move-point-backward-out-of-string ()
+ "Move point backward until it exits the current quoted string."
+ (goto-char (nth 8 (syntax-ppss))))
+
+(defun er/mark-inside-quotes ()
+ "Mark the inside of the current string, not including the quotation marks."
+ (interactive)
+ (when (er--point-inside-string-p)
+ (er--move-point-backward-out-of-string)
+ (forward-char)
+ (set-mark (point))
+ (er--move-point-forward-out-of-string)
+ (backward-char)
+ (exchange-point-and-mark)))
+
+(defun er/mark-outside-quotes ()
+ "Mark the current string, including the quotation marks."
+ (interactive)
+ (if (er--point-inside-string-p)
+ (er--move-point-backward-out-of-string)
+ (when (and (not (use-region-p))
+ (er/looking-back-on-line "\\s\""))
+ (backward-char)
+ (er--move-point-backward-out-of-string)))
+ (when (looking-at "\\s\"")
+ (set-mark (point))
+ (forward-char)
+ (er--move-point-forward-out-of-string)
+ (exchange-point-and-mark)))
+
+;; Pairs - ie [] () {} etc
+
+(defun er--point-inside-pairs-p ()
+ "Is point inside any pairs?"
+ (> (car (syntax-ppss)) 0))
+
+(defun er/mark-inside-pairs ()
+ "Mark inside pairs (as defined by the mode), not including the pairs."
+ (interactive)
+ (when (er--point-inside-pairs-p)
+ (goto-char (nth 1 (syntax-ppss)))
+ (set-mark (save-excursion
+ (forward-char 1)
+ (skip-chars-forward er--space-str)
+ (point)))
+ (forward-list)
+ (backward-char)
+ (skip-chars-backward er--space-str)
+ (exchange-point-and-mark)))
+
+(defun er--looking-at-pair ()
+ "Is point looking at an opening pair char?"
+ (looking-at "\\s("))
+
+(defun er--looking-at-marked-pair ()
+ "Is point looking at a pair that is entirely marked?"
+ (and (er--looking-at-pair)
+ (use-region-p)
+ (>= (mark)
+ (save-excursion
+ (forward-list)
+ (point)))))
+
+(defun er/mark-outside-pairs ()
+ "Mark pairs (as defined by the mode), including the pair chars."
+ (interactive)
+ (if (and (er/looking-back-on-line "\\s)+\\=")
+ (not (er--looking-at-pair)))
+ (ignore-errors (backward-list 1))
+ (skip-chars-forward er--space-str))
+ (when (and (er--point-inside-pairs-p)
+ (or (not (er--looking-at-pair))
+ (er--looking-at-marked-pair)))
+ (goto-char (nth 1 (syntax-ppss))))
+ (when (er--looking-at-pair)
+ (set-mark (point))
+ (forward-list)
+ (exchange-point-and-mark)))
+
+(require 'thingatpt)
+
+(defun er/mark-url ()
+ (interactive)
+ (end-of-thing 'url)
+ (set-mark (point))
+ (beginning-of-thing 'url))
+
+(defun er/mark-email ()
+ (interactive)
+ (end-of-thing 'email)
+ (set-mark (point))
+ (beginning-of-thing 'email))
+
+(defun er/mark-defun ()
+ "Mark defun around or in front of point."
+ (interactive)
+ (end-of-defun)
+ (skip-chars-backward er--space-str)
+ (set-mark (point))
+ (beginning-of-defun)
+ (skip-chars-forward er--space-str))
+
+;; Methods to try expanding to
+(setq er/try-expand-list
+ (append '(er/mark-word
+ er/mark-symbol
+ er/mark-symbol-with-prefix
+ er/mark-next-accessor
+ er/mark-method-call
+ er/mark-inside-quotes
+ er/mark-outside-quotes
+ er/mark-inside-pairs
+ er/mark-outside-pairs
+ er/mark-comment
+ er/mark-url
+ er/mark-email
+ er/mark-defun)
+ er/try-expand-list))
+
+(when (and (>= emacs-major-version 29)
+ (treesit-available-p))
+ (defun er/mark-ts-node ()
+ "Mark tree sitter node around or after point."
+ (interactive)
+ (when (treesit-language-at (point))
+ (let* ((node (if (use-region-p)
+ (treesit-node-on (region-beginning) (region-end))
+ (treesit-node-at (point))))
+ (node-start (treesit-node-start node))
+ (node-end (treesit-node-end node)))
+ ;; when the node fits the region exactly, try its parent node instead
+ (when (and (= (region-beginning) node-start)
+ (= (region-end) node-end))
+ (when-let ((node (treesit-node-parent node)))
+ (setq node-start (treesit-node-start node)
+ node-end (treesit-node-end node))))
+ (goto-char node-start)
+ (set-mark node-end))))
+ (setq er/try-expand-list (append er/try-expand-list '(er/mark-ts-node))))
+
+(provide 'er-basic-expansions)
+;;; er-basic-expansions.el ends here
diff --git a/.config/emacs/lisp/expand-region/expand-region-core.el b/.config/emacs/lisp/expand-region/expand-region-core.el
new file mode 100644
index 0000000..c239fd1
--- /dev/null
+++ b/.config/emacs/lisp/expand-region/expand-region-core.el
@@ -0,0 +1,322 @@
+;;; expand-region-core.el --- Increase selected region by semantic units. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011-2023 Free Software Foundation, Inc
+
+;; Author: Magnar Sveen <magnars@gmail.com>
+;; Keywords: marking region
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The core functionality of expand-region.
+
+;; See README.md
+
+;;; Code:
+
+(require 'expand-region-custom)
+(declare-function er/expand-region "expand-region")
+
+(defvar er/history '()
+ "A history of start and end points so we can contract after expanding.")
+
+;; history is always local to a single buffer
+(make-variable-buffer-local 'er/history)
+
+(defvar er--space-str " \t\n")
+(defvar er--blank-list (append er--space-str nil))
+
+(defvar er--show-expansion-message nil)
+
+(defvar er/try-expand-list nil
+ "A list of functions that are tried when expanding.")
+
+(defvar er/save-mode-excursion nil
+ "A function to save excursion state when expanding.")
+
+(defsubst er--first-invocation ()
+ "t if this is the first invocation of `er/expand-region' or `er/contract-region'."
+ (not (memq last-command '(er/expand-region er/contract-region))))
+
+(defun er--prepare-expanding ()
+ (when (and (er--first-invocation)
+ (not (use-region-p)))
+ (push-mark nil t) ;; one for keeping starting position
+ (push-mark nil t)) ;; one for replace by set-mark in expansions
+
+ (when (not transient-mark-mode)
+ (setq-local transient-mark-mode (cons 'only transient-mark-mode))))
+
+(defun er--copy-region-to-register ()
+ (when (and (stringp expand-region-autocopy-register)
+ (> (length expand-region-autocopy-register) 0))
+ (set-register (aref expand-region-autocopy-register 0)
+ (filter-buffer-substring (region-beginning) (region-end)))))
+
+;; save-mark-and-excursion in Emacs 25 works like save-excursion did before
+(eval-when-compile
+ (when (< emacs-major-version 25)
+ (defmacro save-mark-and-excursion (&rest body)
+ `(save-excursion ,@body))))
+
+(defmacro er--save-excursion (&rest body)
+ `(let ((action (lambda ()
+ (save-mark-and-excursion ,@body))))
+ (if er/save-mode-excursion
+ (funcall er/save-mode-excursion action)
+ (funcall action))))
+
+(defun er--expand-region-1 ()
+ "Increase selected region by semantic units.
+Basically it runs all the mark-functions in `er/try-expand-list'
+and chooses the one that increases the size of the region while
+moving point or mark as little as possible."
+ (let* ((p1 (point))
+ (p2 (if (use-region-p) (mark) (point)))
+ (start (min p1 p2))
+ (end (max p1 p2))
+ (try-list er/try-expand-list)
+ (best-start (point-min))
+ (best-end (point-max))
+ ;; (set-mark-default-inactive nil)
+ )
+
+ ;; add hook to clear history on buffer changes
+ (unless er/history
+ (add-hook 'after-change-functions #'er/clear-history t t))
+
+ ;; remember the start and end points so we can contract later
+ ;; unless we're already at maximum size
+ (unless (and (= start best-start)
+ (= end best-end))
+ (push (cons p1 p2) er/history))
+
+ (when (and expand-region-skip-whitespace
+ (er--point-is-surrounded-by-white-space)
+ (= start end))
+ (skip-chars-forward er--space-str)
+ (setq start (point)))
+
+ (while try-list
+ (er--save-excursion
+ (ignore-errors
+ (funcall (car try-list))
+ (when (and (region-active-p)
+ (er--this-expansion-is-better start end best-start best-end))
+ (setq best-start (point))
+ (setq best-end (mark))
+ (when (and er--show-expansion-message (not (minibufferp)))
+ (message "%S" (car try-list))))))
+ (setq try-list (cdr try-list)))
+
+ (setq deactivate-mark nil)
+ ;; if smart cursor enabled, decide to put it at start or end of region:
+ (if (and expand-region-smart-cursor
+ (not (= start best-start)))
+ (progn (goto-char best-end)
+ (set-mark best-start))
+ (goto-char best-start)
+ (set-mark best-end))
+
+ (er--copy-region-to-register)
+
+ (when (and (= best-start (point-min))
+ (= best-end (point-max))) ;; We didn't find anything new, so exit early
+ 'early-exit)))
+
+(defun er--this-expansion-is-better (start end best-start best-end)
+ "t if the current region is an improvement on previous expansions.
+
+This is provided as a separate function for those that would like
+to override the heuristic."
+ (and
+ (<= (point) start)
+ (>= (mark) end)
+ (> (- (mark) (point)) (- end start))
+ (or (> (point) best-start)
+ (and (= (point) best-start)
+ (< (mark) best-end)))))
+
+;;;###autoload
+(defun er/contract-region (arg)
+ "Contract the selected region to its previous size.
+With prefix argument contracts that many times.
+If prefix argument is negative calls `er/expand-region'.
+If prefix argument is 0 it resets point and mark to their state
+before calling `er/expand-region' for the first time."
+ (interactive "p")
+ (if (< arg 0)
+ (er/expand-region (- arg))
+ (when er/history
+ ;; Be sure to reset them all if called with 0
+ (when (= arg 0)
+ (setq arg (length er/history)))
+
+ (when (not transient-mark-mode)
+ (setq-local transient-mark-mode (cons 'only transient-mark-mode)))
+
+ ;; Advance through the list the desired distance
+ (while (and (cdr er/history)
+ (> arg 1))
+ (setq arg (- arg 1))
+ (setq er/history (cdr er/history)))
+ ;; Reset point and mark
+ (let* ((last (pop er/history))
+ (start (car last))
+ (end (cdr last)))
+ (goto-char start)
+ (set-mark end)
+
+ (er--copy-region-to-register)
+
+ (when (eq start end)
+ (deactivate-mark)
+ (er/clear-history))))))
+
+(defun er/prepare-for-more-expansions-internal (repeat-key-str)
+ "Return bindings and a message to inform user about them"
+ (let ((msg (format "Type %s to expand again" repeat-key-str))
+ (bindings (list (cons repeat-key-str '(er/expand-region 1)))))
+ ;; If contract and expand are on the same binding, ignore contract
+ (unless (string-equal repeat-key-str expand-region-contract-fast-key)
+ (setq msg (concat msg (format ", %s to contract" expand-region-contract-fast-key)))
+ (push (cons expand-region-contract-fast-key '(er/contract-region 1)) bindings))
+ ;; If reset and either expand or contract are on the same binding, ignore reset
+ (unless (or (string-equal repeat-key-str expand-region-reset-fast-key)
+ (string-equal expand-region-contract-fast-key expand-region-reset-fast-key))
+ (setq msg (concat msg (format ", %s to reset" expand-region-reset-fast-key)))
+ (push (cons expand-region-reset-fast-key '(er/expand-region 0)) bindings))
+ (cons msg bindings)))
+
+(defun er/prepare-for-more-expansions ()
+ "Let one expand more by just pressing the last key."
+ (let* ((repeat-key (event-basic-type last-input-event))
+ (repeat-key-str (single-key-description repeat-key))
+ (msg-and-bindings (er/prepare-for-more-expansions-internal repeat-key-str))
+ (msg (car msg-and-bindings))
+ (bindings (cdr msg-and-bindings)))
+ (when repeat-key
+ (er/set-temporary-overlay-map
+ (let ((map (make-sparse-keymap)))
+ (dolist (binding bindings map)
+ (define-key map (read-kbd-macro (car binding))
+ `(lambda ()
+ (interactive)
+ (setq this-command `,(cadr ',binding))
+ (or (not expand-region-show-usage-message) (minibufferp) (message "%s" ,msg))
+ (eval `,(cdr ',binding))))))
+ t)
+ (or (not expand-region-show-usage-message) (minibufferp) (message "%s" msg)))))
+
+(defalias 'er/set-temporary-overlay-map
+ (if (fboundp 'set-temporary-overlay-map) ;Emacs≥24.3
+ #'set-temporary-overlay-map
+ ;; Backport this function from newer emacs versions
+ (lambda (map &optional keep-pred)
+ "Set a new keymap that will only exist for a short period of time.
+The new keymap to use must be given in the MAP variable. When to
+remove the keymap depends on user input and KEEP-PRED:
+
+- if KEEP-PRED is nil (the default), the keymap disappears as
+ soon as any key is pressed, whether or not the key is in MAP;
+
+- if KEEP-PRED is t, the keymap disappears as soon as a key *not*
+ in MAP is pressed;
+
+- otherwise, KEEP-PRED must be a 0-arguments predicate that will
+ decide if the keymap should be removed (if predicate returns
+ nil) or kept (otherwise). The predicate will be called after
+ each key sequence."
+
+ (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map"))
+ (overlaysym (make-symbol "t"))
+ (alist (list (cons overlaysym map)))
+ (clearfun
+ `(lambda ()
+ (unless ,(cond ((null keep-pred) nil)
+ ((eq t keep-pred)
+ `(eq this-command
+ (lookup-key ',map
+ (this-command-keys-vector))))
+ (t `(funcall ',keep-pred)))
+ (remove-hook 'pre-command-hook ',clearfunsym)
+ (setq emulation-mode-map-alists
+ (delq ',alist emulation-mode-map-alists))))))
+ (set overlaysym overlaysym)
+ (fset clearfunsym clearfun)
+ (add-hook 'pre-command-hook clearfunsym)
+
+ (push alist emulation-mode-map-alists)))))
+
+(advice-add 'keyboard-quit :before #'er--collapse-region-before)
+(advice-add 'cua-cancel :before #'er--collapse-region-before)
+(defun er--collapse-region-before (&rest _)
+ ;; FIXME: Re-use `er--first-invocation'?
+ (when (memq last-command '(er/expand-region er/contract-region))
+ (er/contract-region 0)))
+
+(advice-add 'minibuffer-keyboard-quit
+ :around #'er--collapse-region-minibuffer-keyboard-quit)
+(defun er--collapse-region-minibuffer-keyboard-quit (orig-fun &rest args)
+ ;; FIXME: Re-use `er--first-invocation'?
+ (if (memq last-command '(er/expand-region er/contract-region))
+ (er/contract-region 0)
+ (apply orig-fun args)))
+
+
+(defun er/clear-history (&rest _)
+ "Clear the history."
+ (setq er/history '())
+ (remove-hook 'after-change-functions #'er/clear-history t))
+
+(defun er--point-is-surrounded-by-white-space ()
+ (and (or (memq (char-before) er--blank-list)
+ (eq (point) (point-min)))
+ (memq (char-after) er--blank-list)))
+
+(defun er/enable-mode-expansions (mode add-fn)
+ (add-hook (intern (format "%s-hook" mode)) add-fn)
+ (save-window-excursion ;; FIXME: Why?
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when (derived-mode-p mode)
+ (funcall add-fn))))))
+
+(defun er/enable-minor-mode-expansions (mode add-fn)
+ (add-hook (intern (format "%s-hook" mode)) add-fn)
+ (save-window-excursion
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when (symbol-value mode)
+ (funcall add-fn))))))
+
+;; Some more performant version of `looking-back'
+
+(defun er/looking-back-on-line (regexp)
+ "Version of `looking-back' that only checks current line."
+ (looking-back regexp (line-beginning-position)))
+
+(defun er/looking-back-exact (s)
+ "Version of `looking-back' that only looks for exact matches, no regexp."
+ (string= s (buffer-substring (- (point) (length s))
+ (point))))
+
+(defun er/looking-back-max (regexp count)
+ "Version of `looking-back' that only check COUNT chars back."
+ (looking-back regexp (max 1 (- (point) count))))
+
+(provide 'expand-region-core)
+
+;;; expand-region-core.el ends here
diff --git a/.config/emacs/lisp/expand-region/expand-region-custom.el b/.config/emacs/lisp/expand-region/expand-region-custom.el
new file mode 100644
index 0000000..f86f861
--- /dev/null
+++ b/.config/emacs/lisp/expand-region/expand-region-custom.el
@@ -0,0 +1,115 @@
+;;; expand-region-custom.el --- Increase selected region by semantic units. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2023 Free Software Foundation, Inc
+
+;; Author: Magnar Sveen <magnars@gmail.com>
+;; Keywords: marking region
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file holds customization variables.
+
+;;; Code:
+
+;;;###autoload
+(defgroup expand-region nil
+ "Increase selected region by semantic units."
+ :group 'tools)
+
+;;;###autoload
+(defcustom expand-region-preferred-python-mode 'python
+ "The name of your preferred python mode."
+ :type '(choice (const :tag "Emacs' python.el" python)
+ (const :tag "fgallina's python.el" fgallina-python)
+ (const :tag "python-mode.el" python-mode)))
+
+;;;###autoload
+(defcustom expand-region-guess-python-mode t
+ "If expand-region should attempt to guess your preferred python mode."
+ :type '(choice (const :tag "Guess" t)
+ (const :tag "Do not guess" nil)))
+
+(defun expand-region-guess-python-mode ()
+ "Guess the user's preferred python mode."
+ (setq expand-region-preferred-python-mode
+ (if (fboundp 'python-setup-brm)
+ 'python
+ 'fgallina-python)))
+
+;;;###autoload
+(defcustom expand-region-autocopy-register ""
+ "Register to copy most recent expand or contract to.
+
+Activated when set to a string of a single character (for example, \"e\")."
+ :type 'string)
+
+;;;###autoload
+(defcustom expand-region-skip-whitespace t
+ "If expand-region should skip past whitespace on initial expansion."
+ :type '(choice (const :tag "Skip whitespace" t)
+ (const :tag "Do not skip whitespace" nil)))
+
+;;;###autoload
+(defcustom expand-region-fast-keys-enabled t
+ "If expand-region should bind fast keys after initial expand/contract."
+ :type '(choice (const :tag "Enable fast keys" t)
+ (const :tag "Disable fast keys" nil)))
+
+;;;###autoload
+(defcustom expand-region-contract-fast-key "-"
+ "Key to use after an initial expand/contract to contract once more."
+ :type 'string)
+
+;;;###autoload
+(defcustom expand-region-reset-fast-key "0"
+ "Key to use after an initial expand/contract to undo."
+ :type 'string)
+
+;;;###autoload
+(defcustom expand-region-exclude-text-mode-expansions
+ '(html-mode nxml-mode)
+ "List of modes derived from `text-mode' to exclude from text mode expansions."
+ :type '(repeat (symbol :tag "Major Mode" unknown)))
+
+;;;###autoload
+(defcustom expand-region-smart-cursor nil
+ "Defines whether the cursor should be placed intelligently after expansion.
+
+If set to t, and the cursor is already at the beginning of the new region,
+keep it there; otherwise, put it at the end of the region.
+
+If set to nil, always place the cursor at the beginning of the region."
+ :type '(choice (const :tag "Smart behaviour" t)
+ (const :tag "Standard behaviour" nil)))
+
+;;;###autoload
+(define-obsolete-variable-alias 'er/enable-subword-mode?
+ 'expand-region-subword-enabled "2019-03-23")
+
+;;;###autoload
+(defcustom expand-region-subword-enabled nil
+ "Whether expand-region should use subword expansions."
+ :type '(choice (const :tag "Enable subword expansions" t)
+ (const :tag "Disable subword expansions" nil)))
+
+(defcustom expand-region-show-usage-message t
+ "Whether expand-region should show usage message."
+ :group 'expand-region
+ :type 'boolean)
+
+(provide 'expand-region-custom)
+
+;;; expand-region-custom.el ends here
diff --git a/.config/emacs/lisp/expand-region/expand-region.el b/.config/emacs/lisp/expand-region/expand-region.el
new file mode 100644
index 0000000..9f63d51
--- /dev/null
+++ b/.config/emacs/lisp/expand-region/expand-region.el
@@ -0,0 +1,198 @@
+;;; expand-region.el --- Increase selected region by semantic units. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011-2023 Free Software Foundation, Inc
+
+;; Author: Magnar Sveen <magnars@gmail.com>
+;; Keywords: marking region
+;; URL: https://github.com/magnars/expand-region.el
+;; Version: 1.0.0
+;; Package-Requires: ((emacs "24.4"))
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Expand region increases the selected region by semantic units. Just keep
+;; pressing the key until it selects what you want.
+
+;; An example:
+
+;; (setq alphabet-start "abc def")
+
+;; With the cursor at the `c`, it starts by marking the entire word `abc`, then
+;; expand to the contents of the quotes `abc def`, then to the entire quote
+;; `"abc def"`, then to the contents of the sexp `setq alphabet-start "abc def"`
+;; and finally to the entire sexp.
+
+;; You can set it up like this:
+
+;; (require 'expand-region)
+;; (global-set-key (kbd "C-=") 'er/expand-region)
+
+;; There's also `er/contract-region` if you expand too far.
+
+;; ## Video
+
+;; You can [watch an intro to expand-region at Emacs Rocks](http://emacsrocks.com/e09.html).
+
+;; ## Language support
+
+;; Expand region works fairly well with most languages, due to the general
+;; nature of the basic expansions:
+
+;; er/mark-word
+;; er/mark-symbol
+;; er/mark-method-call
+;; er/mark-inside-quotes
+;; er/mark-outside-quotes
+;; er/mark-inside-pairs
+;; er/mark-outside-pairs
+
+;; However, most languages also will benefit from some specially crafted
+;; expansions. For instance, expand-region comes with these extra expansions for
+;; html-mode:
+
+;; er/mark-html-attribute
+;; er/mark-inner-tag
+;; er/mark-outer-tag
+
+;; You can add your own expansions to the languages of your choice simply by
+;; creating a function that looks around point to see if it's inside or looking
+;; at the construct you want to mark, and if so - mark it.
+
+;; There's plenty of examples to look at in these files.
+
+;; After you make your function, add it to a buffer-local version of
+;; the `er/try-expand-list`.
+
+;; **Example:**
+
+;; Let's say you want expand-region to also mark paragraphs and pages in
+;; text-mode. Incidentally Emacs already comes with `mark-paragraph` and
+;; `mark-page`. To add it to the try-list, do this:
+
+;; (defun er/add-text-mode-expansions ()
+;; (setq-local er/try-expand-list (append
+;; er/try-expand-list
+;; '(mark-paragraph
+;; mark-page))))
+
+;; (er/enable-mode-expansions 'text-mode #'er/add-text-mode-expansions)
+
+;; Add that to its own file, and require it at the bottom of this one,
+;; where it says "Mode-specific expansions"
+
+;; **Warning:** Badly written expansions might slow down expand-region
+;; dramatically. Remember to exit quickly before you start traversing
+;; the entire document looking for constructs to mark.
+
+;; ## Contribute
+
+;; If you make some nice expansions for your favorite mode, it would be
+;; great if you opened a pull-request. The repo is at:
+
+;; https://github.com/magnars/expand-region.el
+
+;; Changes to `expand-region-core` itself must be accompanied by feature tests.
+;; They are written in [Ecukes](http://ecukes.info), a Cucumber for Emacs.
+
+;; To fetch the test dependencies:
+
+;; $ cd /path/to/expand-region
+;; $ git submodule init
+;; $ git submodule update
+
+;; Run the tests with:
+
+;; $ ./util/ecukes/ecukes features
+
+;; If you want to add feature-tests for your mode-specific expansions as well,
+;; that is utterly excellent.
+
+;; ## Contributors
+
+;; * [Josh Johnston](https://github.com/joshwnj) contributed `er/contract-region`
+;; * [Le Wang](https://github.com/lewang) contributed consistent handling of the mark ring, expanding into pairs/quotes just left of the cursor, and general code clean-up.
+;; * [Matt Briggs](https://github.com/mbriggs) contributed expansions for ruby-mode.
+;; * [Ivan Andrus](https://github.com/gvol) contributed expansions for python-mode, text-mode, LaTeX-mode and nxml-mode.
+;; * [Raimon Grau](https://github.com/kidd) added support for when transient-mark-mode is off.
+;; * [Gleb Peregud](https://github.com/gleber) contributed expansions for erlang-mode.
+;; * [fgeller](https://github.com/fgeller) and [edmccard](https://github.com/edmccard) contributed better support for python and its multiple modes.
+;; * [François Févotte](https://github.com/ffevotte) contributed expansions for C and C++.
+;; * [Roland Walker](https://github.com/rolandwalker) added option to copy the contents of the most recent action to a register, and some fixes.
+;; * [Damien Cassou](https://github.com/DamienCassou) added option to continue expanding/contracting with fast keys after initial expand.
+
+;; Thanks!
+
+;;; Code:
+
+(require 'expand-region-core)
+(require 'expand-region-custom)
+(require 'er-basic-expansions)
+
+;;;###autoload
+(defun er/expand-region (arg)
+ "Increase selected region by semantic units.
+
+With prefix argument expands the region that many times.
+If prefix argument is negative calls `er/contract-region'.
+If prefix argument is 0 it resets point and mark to their state
+before calling `er/expand-region' for the first time."
+ (interactive "p")
+ (if (< arg 1)
+ (er/contract-region (- arg))
+ (er--prepare-expanding)
+ (while (>= arg 1)
+ (setq arg (- arg 1))
+ (when (eq 'early-exit (er--expand-region-1))
+ (setq arg 0)))
+ (when (and expand-region-fast-keys-enabled
+ (not (memq last-command '(er/expand-region er/contract-region))))
+ (er/prepare-for-more-expansions))))
+
+;; (eval-after-load 'clojure-mode '(require 'clojure-mode-expansions))
+;; (eval-after-load 'erlang-mode '(require 'erlang-mode-expansions))
+;; (eval-after-load 'feature-mode '(require 'feature-mode-expansions))
+;; (eval-after-load 'sgml-mode '(require 'html-mode-expansions)) ;; html-mode is defined in sgml-mode.el
+;; (eval-after-load 'rhtml-mode '(require 'html-mode-expansions))
+;; (eval-after-load 'nxhtml-mode '(require 'html-mode-expansions))
+;; (eval-after-load 'web-mode '(require 'web-mode-expansions))
+;; (eval-after-load 'js '(require 'js-mode-expansions))
+;; (eval-after-load 'js2-mode '(require 'js-mode-expansions))
+;; (eval-after-load 'js2-mode '(require 'js2-mode-expansions))
+;; (eval-after-load 'js3-mode '(require 'js-mode-expansions))
+;; (eval-after-load 'latex '(require 'latex-mode-expansions))
+;; (eval-after-load 'nxml-mode '(require 'nxml-mode-expansions))
+;; (eval-after-load 'octave-mod '(require 'octave-expansions))
+;; (eval-after-load 'octave '(require 'octave-expansions))
+;; (eval-after-load 'python '(progn
+;; (when expand-region-guess-python-mode
+;; (expand-region-guess-python-mode))
+;; (if (eq 'python expand-region-preferred-python-mode)
+;; (require 'python-el-expansions)
+;; (require 'python-el-fgallina-expansions))))
+;; (eval-after-load 'python-mode '(require 'python-mode-expansions))
+;; (eval-after-load 'ruby-mode '(require 'ruby-mode-expansions))
+;; (eval-after-load 'org '(require 'the-org-mode-expansions))
+(eval-after-load 'cc-mode '(require 'cc-mode-expansions))
+;; (eval-after-load 'text-mode '(require 'text-mode-expansions))
+;; (eval-after-load 'cperl-mode '(require 'cperl-mode-expansions))
+;; (eval-after-load 'sml-mode '(require 'sml-mode-expansions))
+;; (eval-after-load 'enh-ruby-mode '(require 'enh-ruby-mode-expansions))
+;; (eval-after-load 'subword '(require 'subword-mode-expansions))
+;; (eval-after-load 'yaml-mode '(require 'yaml-mode-expansions))
+
+(provide 'expand-region)
+
+;;; expand-region.el ends here