├── Makefile ├── README.md └── hungry-delete.el /Makefile: -------------------------------------------------------------------------------- 1 | byte-compile: 2 | emacs -Q -L . -batch -f batch-byte-compile *.el 3 | 4 | clean: 5 | rm *.elc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hungry-delete.el - hungry delete minor mode 2 | ============ 3 | 4 | Copyright (C) 2009-2014 Nathaniel Flath 5 | 6 | Version: 1.0 7 | 8 | ### Commentary ### 9 | 10 | This package implements hungry deletion, meaning that deleting a whitespace character 11 | will delete all whitespace until the next non-whitespace character. 12 | 13 | cc-mode implements hungry deletion for its programming modes. This package borrows 14 | its implementation in a minor mode, so that hungry deletion can be used in all modes. 15 | 16 | The function global-hungry-delete-mode will turn on hungry-delete-mode in all 17 | buffers. 18 | 19 | ### Installation ### 20 | 21 | To use this mode, just put the following in your init.el: 22 | 23 | ```elisp 24 | (require 'hungry-delete) 25 | (global-hungry-delete-mode) 26 | ``` 27 | ### hungry-ish deletion ### 28 | 29 | Some users mght find hungry-delete's default behavior too aggressive, since it 30 | will often merge the words before and after the deletion point. This behavior 31 | can be changed by setting the `hungry-delete-join-reluctantly` flag to true. 32 | This will cause the hungry deletion functions to leave words seperated by a 33 | single space if they would have been joined, unless the words were separated by 34 | just one space to begin with 35 | 36 | As an example, suppose you're in the following state. 37 | 38 | ```elisp 39 | ;; State A 40 | foo bar 41 | ^ 42 | ``` 43 | 44 | Pressing backspace with `hungry-delete-join-reluctantly` as `nil` (the default) 45 | will land you here 46 | 47 | ```elisp 48 | ;; State B 49 | foobar 50 | ^ 51 | ``` 52 | 53 | Whereas if `hungry-delete-join-reluctantly`is enabled, you'll end up here 54 | 55 | ```elisp 56 | ;; State C 57 | foo bar 58 | ^ 59 | ``` 60 | whereupon you can press backspace again to get to state B 61 | -------------------------------------------------------------------------------- /hungry-delete.el: -------------------------------------------------------------------------------- 1 | ;;; hungry-delete.el --- hungry delete minor mode 2 | 3 | ;; Copyright (C) 2009 - 2014 Nathaniel Flath 4 | 5 | ;; Author: Nathaniel Flath 6 | ;; URL: http://github.com/nflath/hungry-delete 7 | ;; Version: 1.1.7 8 | 9 | ;; This file is not part of GNU Emacs. 10 | 11 | ;;; Commentary: 12 | 13 | ;; cc-mode implements hungry deletion for its programming modes. This 14 | ;; package borrows its implementation in a minor mode, so that hungry 15 | ;; deletion can be used in all modes. 16 | 17 | ;;; Installation 18 | 19 | ;; To use this mode, put the following in your init.el: 20 | ;; (require 'hungry-delete) 21 | 22 | ;; You then need to enable hungry-delete-mode, either in 23 | ;; relevant hooks, with turn-on-hungry-delete-mode, or with 24 | ;; global-hungry-delete-mode. 25 | 26 | ;;; License: 27 | 28 | ;; This program is free software; you can redistribute it and/or 29 | ;; modify it under the terms of the GNU General Public License 30 | ;; as published by the Free Software Foundation; either version 3 31 | ;; of the License, or (at your option) any later version. 32 | ;; 33 | ;; This program is distributed in the hope that it will be useful, 34 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 | ;; GNU General Public License for more details. 37 | ;; 38 | ;; You should have received a copy of the GNU General Public License 39 | ;; along with GNU Emacs; see the file COPYING. If not, write to the 40 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 41 | ;; Boston, MA 02110-1301, USA. 42 | 43 | ;;; Code: 44 | 45 | (defvar hungry-delete-mode-map (make-keymap) 46 | "Keymap for hungry-delete-minor-mode.") 47 | 48 | (if (fboundp 'delete-forward-char) 49 | (define-key hungry-delete-mode-map [remap delete-forward-char] 'hungry-delete-forward)) 50 | 51 | (if (fboundp 'delete-char) 52 | (define-key hungry-delete-mode-map [remap delete-char] 'hungry-delete-forward)) 53 | 54 | (define-key hungry-delete-mode-map [remap delete-backward-char] 'hungry-delete-backward) 55 | (define-key hungry-delete-mode-map [remap backward-delete-char-untabify] 'hungry-delete-backward) 56 | (define-key hungry-delete-mode-map [remap c-electric-backspace] 'hungry-delete-backward) 57 | (define-key hungry-delete-mode-map [remap c-electric-delete-forward] 'hungry-delete-forward) 58 | 59 | (defcustom hungry-delete-join-reluctantly nil 60 | "If truthy, the hungry deletion functions will leave words 61 | seperated by a single space if they would have been joined, 62 | unless the words were separated by just one space to begin with" 63 | :type 'boolean 64 | :group 'hungry-delete) 65 | 66 | (defcustom hungry-delete-chars-to-skip " \t\n\r\f\v" 67 | "String of characters to skip. Note that whitespace characters 68 | are not escaped and may look as if it is empty on the customize 69 | screen" 70 | :type 'string 71 | :group 'hungry-delete) 72 | 73 | (defcustom hungry-delete-except-modes '(help-mode minibuffer-inactive-mode calc-mode) 74 | "List of modes hungry-delete will not be turned on in." 75 | :type '(repeat (symbol :tag "Major mode exception")) 76 | :group 'hungry-delete) 77 | 78 | (defun hungry-delete-skip-ws-forward () 79 | "Skip over any whitespace following point. 80 | This function skips over horizontal and vertical whitespace and 81 | line continuations." 82 | (while (and 83 | (> (skip-chars-forward hungry-delete-chars-to-skip) 0) 84 | (eq (char-after) ?\\) 85 | (progn 86 | (forward-char) 87 | (or (eolp) (backward-char))))) 88 | (while (get-text-property (point) 'read-only) 89 | (backward-char))) 90 | 91 | (defun hungry-delete-skip-ws-backward () 92 | "Skip over any whitespace preceding point. 93 | This function skips over horizontal and vertical whitespace and 94 | line continuations." 95 | (let ((original-point (point))) 96 | (skip-chars-backward hungry-delete-chars-to-skip) 97 | 98 | (while (and 99 | (eolp) 100 | (eq (char-before) ?\\) 101 | (progn 102 | (backward-char) 103 | (or 104 | (= (point) (point-min)) 105 | (< (skip-chars-backward hungry-delete-chars-to-skip) 0) 106 | (forward-char))))) 107 | (while (and (get-text-property (point) 'read-only) (< (point) original-point)) 108 | (forward-char)))) 109 | 110 | ;;;###autoload 111 | (defun hungry-delete-forward (n &optional killflag) 112 | "Delete the following character, or all of the following 113 | whitespace, up to the next non-whitespace character. See 114 | \\[c-hungry-delete-forward]. 115 | 116 | hungry-delete-backward tries to mimic delete-backward-char's 117 | behavior in several ways: if the region is activate, it deletes 118 | the text in the region. If a prefix argument is given, delete 119 | the following N characters (previous if N is negative). 120 | 121 | Optional second arg KILLFLAG non-nil means to kill (save in kill 122 | ring) instead of delete. Interactively, N is the prefix arg, and 123 | KILLFLAG is set if N was explicitly specified." 124 | (interactive "p\nP") 125 | (unless (integerp n) 126 | (signal 'wrong-type-argument (list 'integerp n))) 127 | (if (bound-and-true-p rectangle-mark-mode) 128 | (delete-forward-char n killflag) 129 | (cond ((and 130 | (use-region-p) 131 | delete-active-region 132 | (= n 1)) 133 | ;; If a region is active, kill or delete it. 134 | (if (eq delete-active-region 'kill) 135 | (kill-region (region-beginning) (region-end)) 136 | (delete-region (region-beginning) (region-end)))) 137 | ;; If a prefix argument has been given, delete n characters. 138 | (current-prefix-arg (delete-char n killflag)) 139 | ;; Otherwise, call hungry-delete-forward-impl. 140 | (t (hungry-delete-forward-impl))))) 141 | 142 | 143 | 144 | 145 | ;;;###autoload 146 | (defun hungry-delete-backward (n &optional killflag) 147 | "Delete the preceding character or all preceding whitespace 148 | back to the previous non-whitespace character. See also 149 | \\[c-hungry-delete-backward]. 150 | 151 | hungry-delete-backward tries to mimic delete-backward-char's 152 | behavior in several ways: if the region is activate, it deletes 153 | the text in the region. If a prefix argument is given, delete 154 | the previous N characters (following if N is negative). 155 | 156 | In Overwrite mode, single character backward deletion may replace 157 | tabs with spaces so as to back over columns, unless point is at 158 | the end of the line. 159 | 160 | Optional second arg KILLFLAG, if non-nil, means to kill (save in 161 | kill ring) instead of delete. Interactively, N is the prefix 162 | arg, and KILLFLAG is set if N is explicitly specified." 163 | (interactive "p\nP") 164 | (unless (integerp n) 165 | (signal 'wrong-type-argument (list 'integerp n))) 166 | (if (bound-and-true-p rectangle-mark-mode) 167 | (delete-backward-char n killflag) 168 | (cond ((and 169 | (use-region-p) 170 | delete-active-region 171 | (= n 1)) 172 | ;; If a region is active, kill or delete it. 173 | (if (eq delete-active-region 'kill) 174 | (kill-region (region-beginning) (region-end)) 175 | (delete-region (region-beginning) (region-end)))) 176 | ;; In Overwrite mode, maybe untabify while deleting 177 | ((null (or (null overwrite-mode) 178 | (<= n 0) 179 | (memq (char-before) '(?\t ?\n)) 180 | (eobp) 181 | (eq (char-after) ?\n))) 182 | (let ((ocol (current-column))) 183 | (delete-char (- n) killflag) 184 | (save-excursion 185 | (insert-char ?\s (- ocol (current-column)) nil)))) 186 | ;; If a prefix has been given, delete n characters backwards. 187 | (current-prefix-arg (delete-char (- n) killflag)) 188 | ;; Otherwise, call hungry-delete-backward-impl. 189 | (t (hungry-delete-backward-impl))))) 190 | 191 | (defun hungry-delete-impl (fn n insertion-fn) 192 | "Implementation of hungry-delete functionality. 193 | FN is the function to call to go to the end of whitespace (will 194 | be either hungry-delete-skip-ws-forward or 195 | hungry-delete-skip-ws-backwards by default). N is the number of 196 | characters to delete if there is no whitespace (will be either 1 197 | or -1 by default). 198 | 199 | insertion-fn is inserts before point for delete backwards and after 200 | point for delete-forwards" 201 | (let ((here (point))) 202 | (funcall fn) 203 | (let* ((region-start (min (point) here)) 204 | (region-end (max (point) here)) 205 | (region-size (- region-end region-start))) 206 | (if (/= region-start region-end) 207 | (if (and hungry-delete-join-reluctantly 208 | (or (>= region-size 2) 209 | (and (= region-size 1) 210 | (not (seq-contains " " (char-before region-end))))) 211 | (not (= region-start (point-min))) 212 | (not (= region-end (point-max))) 213 | (not (seq-contains hungry-delete-chars-to-skip (char-before region-start))) 214 | (not (seq-contains hungry-delete-chars-to-skip (char-after region-end)))) 215 | (progn 216 | (delete-region region-start region-end) 217 | (funcall insertion-fn " ")) 218 | (delete-region region-start region-end)) 219 | (let ((hungry-delete-mode nil)) 220 | (delete-char n)))))) 221 | 222 | (defun hungry-delete-forward-impl () 223 | "Do the dirty work of calling hungry-delete-forward." 224 | (hungry-delete-impl 'hungry-delete-skip-ws-forward 1 225 | (lambda (x) (save-excursion (insert x))))) 226 | 227 | (defun hungry-delete-backward-impl () 228 | "Do the dirty work of calling hungry-delete-backward." 229 | (hungry-delete-impl 'hungry-delete-skip-ws-backward -1 #'insert)) 230 | 231 | ;;;###autoload 232 | (define-minor-mode hungry-delete-mode 233 | "Minor mode to enable hungry deletion. This will delete all 234 | whitespace after or before point when the deletion command is 235 | executed." 236 | :init-value nil 237 | :group 'hungry-delete 238 | :lighter " h") 239 | 240 | ;;;###autoload 241 | (defun turn-on-hungry-delete-mode () 242 | "Turn on hungry delete mode if the buffer is appropriate." 243 | (interactive) 244 | (unless (member major-mode hungry-delete-except-modes) 245 | (hungry-delete-mode t))) 246 | 247 | ;;;###autoload 248 | (define-globalized-minor-mode global-hungry-delete-mode hungry-delete-mode turn-on-hungry-delete-mode 249 | :group 'hungry-delete) 250 | 251 | (provide 'hungry-delete) 252 | ;;; hungry-delete.el ends here 253 | --------------------------------------------------------------------------------