aboutsummaryrefslogtreecommitdiffstats
path: root/elpa/hungry-delete-20210409.1643/hungry-delete.el
blob: 2f697b6b44393e52b3b47e8f005d7bcc4c3ec6f3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
;;; hungry-delete.el --- hungry delete minor mode

;; Copyright (C) 2009 - 2014 Nathaniel Flath <flat0103@gmail.com>

;; Author: Nathaniel Flath <flat0103@gmail.com>
;; URL: http://github.com/nflath/hungry-delete
;; Package-Version: 20210409.1643
;; Package-Commit: d919e555e5c13a2edf4570f3ceec84f0ade71657
;; Version: 1.1.7

;; This file is not part of GNU Emacs.

;;; Commentary:

;; cc-mode implements hungry deletion for its programming modes.  This
;; package borrows its implementation in a minor mode, so that hungry
;; deletion can be used in all modes.

;;; Installation

;; To use this mode, put the following in your init.el:
;; (require 'hungry-delete)

;; You then need to enable hungry-delete-mode, either in
;; relevant hooks, with turn-on-hungry-delete-mode, or with
;; global-hungry-delete-mode.

;;; License:

;; 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 GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Code:

(defvar hungry-delete-mode-map (make-keymap)
  "Keymap for hungry-delete-minor-mode.")

(if (fboundp 'delete-forward-char)
    (define-key hungry-delete-mode-map [remap delete-forward-char] 'hungry-delete-forward))

(if (fboundp 'delete-char)
    (define-key hungry-delete-mode-map [remap delete-char] 'hungry-delete-forward))

(define-key hungry-delete-mode-map [remap delete-backward-char] 'hungry-delete-backward)
(define-key hungry-delete-mode-map [remap backward-delete-char-untabify] 'hungry-delete-backward)
(define-key hungry-delete-mode-map [remap c-electric-backspace] 'hungry-delete-backward)
(define-key hungry-delete-mode-map [remap c-electric-delete-forward] 'hungry-delete-forward)

(defcustom hungry-delete-join-reluctantly nil
  "If truthy, the hungry deletion functions will leave words
seperated by a single space if they would have been joined,
unless the words were separated by just one space to begin with"
  :type 'boolean
  :group 'hungry-delete)

(defcustom hungry-delete-chars-to-skip " \t\n\r\f\v"
  "String of characters to skip. Note that whitespace characters
are not escaped and may look as if it is empty on the customize
screen"
  :type 'string
  :group 'hungry-delete)

(defcustom hungry-delete-except-modes '(help-mode minibuffer-inactive-mode calc-mode)
  "List of modes hungry-delete will not be turned on in."
  :type '(repeat (symbol :tag "Major mode exception"))
  :group 'hungry-delete)

(defun hungry-delete-skip-ws-forward ()
  "Skip over any whitespace following point.
This function skips over horizontal and vertical whitespace and
line continuations."
  (while (and
          (> (skip-chars-forward hungry-delete-chars-to-skip) 0)
          (eq (char-after) ?\\)
          (progn
            (forward-char)
            (or (eolp) (backward-char)))))
  (while (get-text-property (point) 'read-only)
    (backward-char)))

(defun hungry-delete-skip-ws-backward ()
  "Skip over any whitespace preceding point.
This function skips over horizontal and vertical whitespace and
line continuations."
  (let ((original-point (point)))
    (skip-chars-backward hungry-delete-chars-to-skip)

    (while (and
            (eolp)
            (eq (char-before) ?\\)
            (progn
              (backward-char)
              (or
               (= (point) (point-min))
               (< (skip-chars-backward hungry-delete-chars-to-skip) 0)
               (forward-char)))))
    (while (and (get-text-property (point) 'read-only) (< (point) original-point))
      (forward-char))))

;;;###autoload
(defun hungry-delete-forward (n &optional killflag)
  "Delete the following character, or all of the following
whitespace, up to the next non-whitespace character.  See
\\[c-hungry-delete-forward].

hungry-delete-backward tries to mimic delete-backward-char's
behavior in several ways: if the region is activate, it deletes
the text in the region.  If a prefix argument is given, delete
the following N characters (previous if N is negative).

Optional second arg KILLFLAG non-nil means to kill (save in kill
ring) instead of delete.  Interactively, N is the prefix arg, and
KILLFLAG is set if N was explicitly specified."
  (interactive "p\nP")
  (unless (integerp n)
    (signal 'wrong-type-argument (list 'integerp n)))
  (if (bound-and-true-p rectangle-mark-mode)
      (delete-forward-char n killflag)
  (cond ((and
          (use-region-p)
	      delete-active-region
	      (= n 1))
	 ;; If a region is active, kill or delete it.
	 (if (eq delete-active-region 'kill)
	     (kill-region (region-beginning) (region-end))
	   (delete-region (region-beginning) (region-end))))
	;; If a prefix argument has been given, delete n characters.
	(current-prefix-arg (delete-char n killflag))
	;; Otherwise, call hungry-delete-forward-impl.
	(t (hungry-delete-forward-impl)))))




;;;###autoload
(defun hungry-delete-backward (n &optional killflag)
  "Delete the preceding character or all preceding whitespace
back to the previous non-whitespace character.  See also
\\[c-hungry-delete-backward].

hungry-delete-backward tries to mimic delete-backward-char's
behavior in several ways: if the region is activate, it deletes
the text in the region.  If a prefix argument is given, delete
the previous N characters (following if N is negative).

In Overwrite mode, single character backward deletion may replace
tabs with spaces so as to back over columns, unless point is at
the end of the line.

Optional second arg KILLFLAG, if non-nil, means to kill (save in
kill ring) instead of delete.  Interactively, N is the prefix
arg, and KILLFLAG is set if N is explicitly specified."
  (interactive "p\nP")
  (unless (integerp n)
    (signal 'wrong-type-argument (list 'integerp n)))
  (if (bound-and-true-p rectangle-mark-mode)
      (delete-backward-char n killflag)
    (cond ((and
            (use-region-p)
            delete-active-region
            (= n 1))
           ;; If a region is active, kill or delete it.
           (if (eq delete-active-region 'kill)
               (kill-region (region-beginning) (region-end))
             (delete-region (region-beginning) (region-end))))
          ;; In Overwrite mode, maybe untabify while deleting
          ((null (or (null overwrite-mode)
                     (<= n 0)
                     (memq (char-before) '(?\t ?\n))
                     (eobp)
                     (eq (char-after) ?\n)))
           (let ((ocol (current-column)))
             (delete-char (- n) killflag)
             (save-excursion
               (insert-char ?\s (- ocol (current-column)) nil))))
          ;; If a prefix has been given, delete n characters backwards.
          (current-prefix-arg (delete-char (- n) killflag))
          ;; Otherwise, call hungry-delete-backward-impl.
          (t (hungry-delete-backward-impl)))))

(defun hungry-delete-impl (fn n insertion-fn)
  "Implementation of hungry-delete functionality.
FN is the function to call to go to the end of whitespace (will
be either hungry-delete-skip-ws-forward or
hungry-delete-skip-ws-backwards by default).  N is the number of
characters to delete if there is no whitespace (will be either 1
or -1 by default).

insertion-fn is inserts before point for delete backwards and after
point for delete-forwards"
  (let ((here (point)))
    (funcall fn)
    (let* ((region-start (min (point) here))
           (region-end (max (point) here))
           (region-size (- region-end region-start)))
      (if (/= region-start region-end)
          (if (and hungry-delete-join-reluctantly
                   (or (>= region-size 2)
                       (and (= region-size 1)
                            (not (seq-contains " " (char-before region-end)))))
                   (not (= region-start (point-min)))
                   (not (= region-end (point-max)))
                   (not (seq-contains hungry-delete-chars-to-skip (char-before region-start)))
                   (not (seq-contains hungry-delete-chars-to-skip (char-after region-end))))
              (progn
                (delete-region region-start region-end)
                (funcall insertion-fn " "))
            (delete-region region-start region-end))
        (let ((hungry-delete-mode nil))
          (delete-char n))))))

(defun hungry-delete-forward-impl ()
  "Do the dirty work of calling hungry-delete-forward."
  (hungry-delete-impl 'hungry-delete-skip-ws-forward 1
                      (lambda (x) (save-excursion (insert x)))))

(defun hungry-delete-backward-impl ()
  "Do the dirty work of calling hungry-delete-backward."
  (hungry-delete-impl 'hungry-delete-skip-ws-backward -1 #'insert))

;;;###autoload
(define-minor-mode hungry-delete-mode
  "Minor mode to enable hungry deletion.  This will delete all
whitespace after or before point when the deletion command is
executed."
  :init-value nil
  :group 'hungry-delete
  :lighter " h")

;;;###autoload
(defun turn-on-hungry-delete-mode ()
  "Turn on hungry delete mode if the buffer is appropriate."
  (interactive)
  (unless (member major-mode hungry-delete-except-modes)
    (hungry-delete-mode t)))

;;;###autoload
(define-globalized-minor-mode global-hungry-delete-mode hungry-delete-mode turn-on-hungry-delete-mode
  :group 'hungry-delete)

(provide 'hungry-delete)
;;; hungry-delete.el ends here