diff options
Diffstat (limited to '.config/emacs/lisp/expand-region')
| -rw-r--r-- | .config/emacs/lisp/expand-region/cc-mode-expansions.el | 186 | ||||
| -rw-r--r-- | .config/emacs/lisp/expand-region/er-basic-expansions.el | 267 | ||||
| -rw-r--r-- | .config/emacs/lisp/expand-region/expand-region-core.el | 322 | ||||
| -rw-r--r-- | .config/emacs/lisp/expand-region/expand-region-custom.el | 115 | ||||
| -rw-r--r-- | .config/emacs/lisp/expand-region/expand-region.el | 198 |
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 |
