1 ;;; simple.el --- basic editing commands for SXEmacs
3 ;; Copyright (C) 1985-7, 1993-5, 1997 Free Software Foundation, Inc.
4 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
5 ;; Copyright (C) 2000, 2001, 2002, 2003 Ben Wing.
6 ;; Copyright (C) 2006, Steve Youngs.
8 ;; Maintainer: SXEmacs Development Team
9 ;; Keywords: lisp, extensions, internal, dumped
11 ;; This file is part of SXEmacs.
13 ;; SXEmacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
18 ;; SXEmacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
26 ;;; Synched up with: FSF 19.34 [But not very closely].
30 ;; This file is dumped with SXEmacs.
32 ;; A grab-bag of basic SXEmacs commands not specifically related to some
33 ;; major mode or to file-handling.
35 ;; Changes for zmacs-style active-regions:
37 ;; beginning-of-buffer, end-of-buffer, count-lines-region,
38 ;; count-lines-buffer, what-line, what-cursor-position, set-goal-column,
39 ;; set-fill-column, prefix-arg-internal, and line-move (which is used by
40 ;; next-line and previous-line) set zmacs-region-stays to t, so that they
41 ;; don't affect the current region-hilighting state.
43 ;; mark-whole-buffer, mark-word, exchange-point-and-mark, and
44 ;; set-mark-command (without an argument) call zmacs-activate-region.
46 ;; mark takes an optional arg like the new Fmark_marker() does. When
47 ;; the region is not active, mark returns nil unless the optional arg is true.
49 ;; push-mark, pop-mark, exchange-point-and-mark, and set-marker, and
50 ;; set-mark-command use (mark t) so that they can access the mark whether
51 ;; the region is active or not.
53 ;; shell-command, shell-command-on-region, yank, and yank-pop (which all
54 ;; push a mark) have been altered to call exchange-point-and-mark with an
55 ;; argument, meaning "don't activate the region". These commands only use
56 ;; exchange-point-and-mark to position the newly-pushed mark correctly, so
57 ;; this isn't a user-visible change. These functions have also been altered
58 ;; to use (mark t) for the same reason.
60 ;; 97/3/14 Jareth Hein (jhod@po.iijnet.or.jp) added kinsoku processing (support
61 ;; for filling of Asian text) into the fill code. This was ripped bleeding from
62 ;; Mule-2.3, and could probably use some feature additions (like additional wrap
65 ;; 97/06/11 Steve Baur (steve@xemacs.org) Convert use of
66 ;; (preceding|following)-char to char-(after|before).
70 (defgroup editing-basics nil
71 "Most basic editing variables."
75 "Killing and yanking commands."
78 (defgroup fill-comments nil
79 "Indenting and filling of comments."
83 (defgroup paren-matching nil
84 "Highlight (un)matching of parens and expressions."
88 (defgroup log-message nil
89 "Messages logging and display customizations."
92 (defgroup warnings nil
93 "Warnings customizations."
97 (defcustom search-caps-disable-folding t
98 "*If non-nil, upper case chars disable case fold searching.
99 This does not apply to \"yanked\" strings."
101 :group 'editing-basics)
103 ;; This is stolen (and slightly modified) from FSF emacs's
104 ;; `isearch-no-upper-case-p'.
105 (defun no-upper-case-p (string &optional regexp-flag)
106 "Return t if there are no upper case chars in STRING.
107 If REGEXP-FLAG is non-nil, disregard letters preceded by `\\' (but not `\\\\')
108 since they have special meaning in a regexp."
109 (let ((case-fold-search nil))
110 (not (string-match (if regexp-flag
111 #r"\(^\|\\\\\|[^\]\)[A-Z]"
116 (defmacro with-search-caps-disable-folding (string regexp-flag &rest body)
117 "Eval BODY with `case-fold-search' let to nil if `search-caps-disable-folding'
118 is non-nil, and if STRING (either a string or a regular expression according
119 to REGEXP-FLAG) contains uppercase letters."
120 `(let ((case-fold-search
121 (if (and case-fold-search search-caps-disable-folding)
122 (no-upper-case-p ,string ,regexp-flag)
125 (put 'with-search-caps-disable-folding 'lisp-indent-function 2)
126 (put 'with-search-caps-disable-folding 'edebug-form-spec
127 '(sexp sexp &rest form))
129 (defmacro with-interactive-search-caps-disable-folding (string regexp-flag
131 "Same as `with-search-caps-disable-folding', but only in the case of a
132 function called interactively."
133 `(let ((case-fold-search
134 (if (and (interactive-p)
135 case-fold-search search-caps-disable-folding)
136 (no-upper-case-p ,string ,regexp-flag)
139 (put 'with-interactive-search-caps-disable-folding 'lisp-indent-function 2)
140 (put 'with-interactive-search-caps-disable-folding 'edebug-form-spec
141 '(sexp sexp &rest form))
143 (defun newline (&optional n)
144 "Insert a newline, and move to left margin of the new line if it's blank.
145 The newline is marked with the text-property `hard'.
146 With optional arg N, insert that many newlines.
147 In Auto Fill mode, if no numeric arg, break the preceding line if it's long."
149 (barf-if-buffer-read-only nil (point))
150 ;; Inserting a newline at the end of a line produces better redisplay in
151 ;; try_window_id than inserting at the beginning of a line, and the textual
152 ;; result is the same. So, if we're at beginning of line, pretend to be at
153 ;; the end of the previous line.
154 ;; #### Does this have any relevance in XEmacs?
155 (let ((flag (and (not (bobp))
157 ;; Make sure the newline before point isn't intangible.
158 (not (get-char-property (1- (point)) 'intangible))
159 ;; Make sure the newline before point isn't read-only.
160 (not (get-char-property (1- (point)) 'read-only))
161 ;; Make sure the newline before point isn't invisible.
162 (not (get-char-property (1- (point)) 'invisible))
163 ;; This should probably also test for the previous char
164 ;; being the *last* character too.
165 (not (get-char-property (1- (point)) 'end-open))
166 ;; Make sure the newline before point has the same
167 ;; properties as the char before it (if any).
168 (< (or (previous-extent-change (point)) -2)
170 (was-page-start (and (bolp)
171 (looking-at page-delimiter)))
173 (if flag (backward-char 1))
174 ;; Call self-insert so that auto-fill, abbrev expansion etc. happens.
175 ;; Set last-command-char to tell self-insert what to insert.
176 (let ((last-command-char ?\n)
177 ;; Don't auto-fill if we have a numeric argument.
178 ;; Also not if flag is true (it would fill wrong line);
179 ;; there is no need to since we're at BOL.
180 (auto-fill-function (if (or n flag) nil auto-fill-function)))
182 (self-insert-command (prefix-numeric-value n))
183 ;; If we get an error in self-insert-command, put point at right place.
184 (if flag (forward-char 1))))
185 ;; If we did *not* get an error, cancel that forward-char.
186 (if flag (backward-char 1))
187 ;; Mark the newline(s) `hard'.
188 (if use-hard-newlines
189 (let* ((from (- (point) (if n (prefix-numeric-value n) 1)))
190 (sticky (get-text-property from 'end-open))) ; XEmacs
191 (put-text-property from (point) 'hard 't)
192 ;; If end-open is not "t", add 'hard to end-open list
193 (if (and (listp sticky) (not (memq 'hard sticky)))
194 (put-text-property from (point) 'end-open ; XEmacs
195 (cons 'hard sticky)))))
196 ;; If the newline leaves the previous line blank,
197 ;; and we have a left margin, delete that from the blank line.
200 (goto-char beforepos)
202 (and (looking-at "[ \t]$")
203 (> (current-left-margin) 0)
204 (delete-region (point) (progn (end-of-line) (point))))))
205 (if flag (forward-char 1))
206 ;; Indent the line after the newline, except in one case:
207 ;; when we added the newline at the beginning of a line
208 ;; which starts a page.
210 (move-to-left-margin nil t)))
213 (defun set-hard-newline-properties (from to)
214 (let ((sticky (get-text-property from 'rear-nonsticky)))
215 (put-text-property from to 'hard 't)
216 ;; If rear-nonsticky is not "t", add 'hard to rear-nonsticky list
217 (if (and (listp sticky) (not (memq 'hard sticky)))
218 (put-text-property from (point) 'rear-nonsticky
219 (cons 'hard sticky)))))
222 "Insert a newline and leave point before it.
223 If there is a fill prefix and/or a left-margin, insert them on the new line
224 if the line would have been blank.
225 With arg N, insert N newlines."
227 (let* ((do-fill-prefix (and fill-prefix (bolp)))
228 (do-left-margin (and (bolp) (> (current-left-margin) 0)))
234 (if do-left-margin (indent-to (current-left-margin)))
235 (if do-fill-prefix (insert fill-prefix))))
242 "Split current line, moving portion beyond point vertically down."
244 (skip-chars-forward " \t")
245 (let ((col (current-column))
251 (defun quoted-insert (arg)
252 "Read next input character and insert it.
253 This is useful for inserting control characters.
254 You may also type up to 3 octal digits, to insert a character with that code.
256 In overwrite mode, this function inserts the character anyway, and
257 does not handle octal digits specially. This means that if you use
258 overwrite as your normal editing mode, you can use this function to
259 insert characters when necessary.
261 In binary overwrite mode, this function does overwrite, and octal
262 digits are interpreted as a character code. This is supposed to make
263 this function useful in editing binary files."
265 (let ((char (if (or (not overwrite-mode)
266 (eq overwrite-mode 'overwrite-mode-binary))
268 ;; read-char obeys C-g, so we should protect. FSF
269 ;; doesn't have the protection here, but it's a bug in
271 (let ((inhibit-quit t))
274 (if (eq overwrite-mode 'overwrite-mode-binary)
278 (setq arg (1- arg)))))
280 (defun delete-indentation (&optional arg)
281 "Join this line to previous and fix up whitespace at join.
282 If there is a fill prefix, delete it from the beginning of this line.
283 With argument, join this line to following line."
286 (if arg (forward-line 1))
287 (if (eq (char-before (point)) ?\n)
289 (delete-region (point) (1- (point)))
290 ;; If the second line started with the fill prefix,
291 ;; delete the prefix.
293 (<= (+ (point) (length fill-prefix)) (point-max))
295 (buffer-substring (point)
296 (+ (point) (length fill-prefix)))))
297 (delete-region (point) (+ (point) (length fill-prefix))))
298 (fixup-whitespace))))
300 (defalias 'join-line 'delete-indentation)
302 (defun fixup-whitespace ()
303 "Fixup white space between objects around point.
304 Leave one space or none, according to the context."
307 (delete-horizontal-space)
308 (if (or (looking-at #r"^\|\s)")
309 (save-excursion (backward-char 1)
310 (looking-at #r"$\|\s(\|\s'")))
314 (defun delete-horizontal-space ()
315 "Delete all spaces and tabs around point."
317 (skip-chars-backward " \t")
318 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
320 (defun just-one-space ()
321 "Delete all spaces and tabs around point, leaving one space."
323 (if abbrev-mode ; XEmacs
325 (skip-chars-backward " \t")
326 (if (eq (char-after (point)) ? ) ; XEmacs
329 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
331 (defun delete-blank-lines ()
332 "On blank line, delete all surrounding blank lines, leaving just one.
333 On isolated blank line, delete that one.
334 On nonblank line, delete any immediately following blank lines."
336 (let (thisblank singleblank)
339 (setq thisblank (looking-at "[ \t]*$"))
340 ;; Set singleblank if there is just one blank line here.
343 (not (looking-at "[ \t]*\n[ \t]*$"))
345 (progn (forward-line -1)
346 (not (looking-at "[ \t]*$")))))))
347 ;; Delete preceding blank lines, and this one too if it's the only one.
351 (if singleblank (forward-line 1))
352 (delete-region (point)
353 (if (re-search-backward "[^ \t\n]" nil t)
354 (progn (forward-line 1) (point))
356 ;; Delete following blank lines, unless the current line is blank
357 ;; and there are no following blank lines.
358 (if (not (and thisblank singleblank))
362 (delete-region (point)
363 (if (re-search-forward "[^ \t\n]" nil t)
364 (progn (beginning-of-line) (point))
366 ;; Handle the special case where point is followed by newline and eob.
367 ;; Delete the line, leaving point at eob.
368 (if (looking-at "^[ \t]*\n\\'")
369 (delete-region (point) (point-max)))))
371 (defun back-to-indentation ()
372 "Move point to the first non-whitespace character on this line."
375 (beginning-of-line 1)
376 (skip-chars-forward " \t"))
378 (defun newline-and-indent ()
379 "Insert a newline, then indent according to major mode.
380 Indentation is done using the value of `indent-line-function'.
381 In programming language modes, this is the same as TAB.
382 In some text modes, where TAB inserts a tab, this command indents to the
383 column specified by the function `current-left-margin'."
385 (delete-region (point) (progn (skip-chars-backward " \t") (point)))
387 (indent-according-to-mode))
389 (defun reindent-then-newline-and-indent ()
390 "Reindent current line, insert newline, then indent the new line.
391 Indentation of both lines is done according to the current major mode,
392 which means calling the current value of `indent-line-function'.
393 In programming language modes, this is the same as TAB.
394 In some text modes, where TAB inserts a tab, this indents to the
395 column specified by the function `current-left-margin'."
398 (delete-region (point) (progn (skip-chars-backward " \t") (point)))
399 (indent-according-to-mode))
401 (indent-according-to-mode))
403 ;; Internal subroutine of delete-char
404 (defun kill-forward-chars (arg)
405 (if (listp arg) (setq arg (car arg)))
406 (if (eq arg '-) (setq arg -1))
407 (kill-region (point) (+ (point) arg)))
409 ;; Internal subroutine of backward-delete-char
410 (defun kill-backward-chars (arg)
411 (if (listp arg) (setq arg (car arg)))
412 (if (eq arg '-) (setq arg -1))
413 (kill-region (point) (- (point) arg)))
415 (defun backward-delete-char-untabify (arg &optional killp)
416 "Delete characters backward, changing tabs into spaces.
417 Delete ARG chars, and kill (save in kill ring) if KILLP is non-nil.
418 Interactively, ARG is the prefix arg (default 1)
419 and KILLP is t if a prefix arg was specified."
420 (interactive "*p\nP")
423 (while (and (> count 0) (not (bobp)))
424 (if (eq (char-before (point)) ?\t) ; XEmacs
425 (let ((col (current-column)))
427 (setq col (- col (current-column)))
431 (setq count (1- count)))))