Mercurial > emacs
diff lisp/simple.el @ 88155:d7ddb3e565de
sync with trunk
author | Henrik Enberg <henrik.enberg@telia.com> |
---|---|
date | Mon, 16 Jan 2006 00:03:54 +0000 |
parents | 48e671543e1e |
children |
line wrap: on
line diff
--- a/lisp/simple.el Sun Jan 15 23:02:10 2006 +0000 +++ b/lisp/simple.el Mon Jan 16 00:03:54 2006 +0000 @@ -1,8 +1,7 @@ ;;; simple.el --- basic editing commands for Emacs -;; Copyright (C) 1985, 86, 87, 93, 94, 95, 96, 97, 98, 99, -;; 2000, 2001, 2002, 2003 -;; Free Software Foundation, Inc. +;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +;; 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: internal @@ -21,8 +20,8 @@ ;; 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., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: @@ -35,52 +34,373 @@ (autoload 'widget-convert "wid-edit") (autoload 'shell-mode "shell")) +(defvar compilation-current-error) + +(defcustom idle-update-delay 0.5 + "*Idle time delay before updating various things on the screen. +Various Emacs features that update auxiliary information when point moves +wait this many seconds after Emacs becomes idle before doing an update." + :type 'number + :group 'display + :version "22.1") (defgroup killing nil - "Killing and yanking commands" + "Killing and yanking commands." :group 'editing) (defgroup paren-matching nil "Highlight (un)matching of parens and expressions." :group 'matching) -(define-key global-map [?\C-x right] 'next-buffer) -(define-key global-map [?\C-x left] 'prev-buffer) +(defun get-next-valid-buffer (list &optional buffer visible-ok frame) + "Search LIST for a valid buffer to display in FRAME. +Return nil when all buffers in LIST are undesirable for display, +otherwise return the first suitable buffer in LIST. + +Buffers not visible in windows are preferred to visible buffers, +unless VISIBLE-OK is non-nil. +If the optional argument FRAME is nil, it defaults to the selected frame. +If BUFFER is non-nil, ignore occurrences of that buffer in LIST." + ;; This logic is more or less copied from other-buffer. + (setq frame (or frame (selected-frame))) + (let ((pred (frame-parameter frame 'buffer-predicate)) + found buf) + (while (and (not found) list) + (setq buf (car list)) + (if (and (not (eq buffer buf)) + (buffer-live-p buf) + (or (null pred) (funcall pred buf)) + (not (eq (aref (buffer-name buf) 0) ?\s)) + (or visible-ok (null (get-buffer-window buf 'visible)))) + (setq found buf) + (setq list (cdr list)))) + (car list))) + +(defun last-buffer (&optional buffer visible-ok frame) + "Return the last non-hidden displayable buffer in the buffer list. +If BUFFER is non-nil, last-buffer will ignore that buffer. +Buffers not visible in windows are preferred to visible buffers, +unless optional argument VISIBLE-OK is non-nil. +If the optional third argument FRAME is non-nil, use that frame's +buffer list instead of the selected frame's buffer list. +If no other buffer exists, the buffer `*scratch*' is returned." + (setq frame (or frame (selected-frame))) + (or (get-next-valid-buffer (frame-parameter frame 'buried-buffer-list) + buffer visible-ok frame) + (get-next-valid-buffer (nreverse (buffer-list frame)) + buffer visible-ok frame) + (progn + (set-buffer-major-mode (get-buffer-create "*scratch*")) + (get-buffer "*scratch*")))) + (defun next-buffer () "Switch to the next buffer in cyclic order." (interactive) - (let ((buffer (current-buffer))) - (switch-to-buffer (other-buffer buffer)) - (bury-buffer buffer))) - -(defun prev-buffer () + (let ((buffer (current-buffer)) + (bbl (frame-parameter nil 'buried-buffer-list))) + (switch-to-buffer (other-buffer buffer t)) + (bury-buffer buffer) + (set-frame-parameter nil 'buried-buffer-list + (cons buffer (delq buffer bbl))))) + +(defun previous-buffer () "Switch to the previous buffer in cyclic order." (interactive) - (let ((list (nreverse (buffer-list))) - found) - (while (and (not found) list) - (let ((buffer (car list))) - (if (and (not (get-buffer-window buffer)) - (not (string-match "\\` " (buffer-name buffer)))) - (setq found buffer))) - (setq list (cdr list))) - (switch-to-buffer found))) + (let ((buffer (last-buffer (current-buffer) t)) + (bbl (frame-parameter nil 'buried-buffer-list))) + (switch-to-buffer buffer) + ;; Clean up buried-buffer-list up to and including the chosen buffer. + (while (and bbl (not (eq (car bbl) buffer))) + (setq bbl (cdr bbl))) + (set-frame-parameter nil 'buried-buffer-list bbl))) + + +;;; next-error support framework + +(defgroup next-error nil + "`next-error' support framework." + :group 'compilation + :version "22.1") + +(defface next-error + '((t (:inherit region))) + "Face used to highlight next error locus." + :group 'next-error + :version "22.1") + +(defcustom next-error-highlight 0.1 + "*Highlighting of locations in selected source buffers. +If number, highlight the locus in `next-error' face for given time in seconds. +If t, use persistent overlays fontified in `next-error' face. +If nil, don't highlight the locus in the source buffer. +If `fringe-arrow', indicate the locus by the fringe arrow." + :type '(choice (number :tag "Delay") + (const :tag "Persistent overlay" t) + (const :tag "No highlighting" nil) + (const :tag "Fringe arrow" 'fringe-arrow)) + :group 'next-error + :version "22.1") + +(defcustom next-error-highlight-no-select 0.1 + "*Highlighting of locations in non-selected source buffers. +If number, highlight the locus in `next-error' face for given time in seconds. +If t, use persistent overlays fontified in `next-error' face. +If nil, don't highlight the locus in the source buffer. +If `fringe-arrow', indicate the locus by the fringe arrow." + :type '(choice (number :tag "Delay") + (const :tag "Persistent overlay" t) + (const :tag "No highlighting" nil) + (const :tag "Fringe arrow" 'fringe-arrow)) + :group 'next-error + :version "22.1") + +(defcustom next-error-hook nil + "*List of hook functions run by `next-error' after visiting source file." + :type 'hook + :group 'next-error) + +(defvar next-error-highlight-timer nil) + +(defvar next-error-overlay-arrow-position nil) +(put 'next-error-overlay-arrow-position 'overlay-arrow-string "=>") +(add-to-list 'overlay-arrow-variable-list 'next-error-overlay-arrow-position) + +(defvar next-error-last-buffer nil + "The most recent `next-error' buffer. +A buffer becomes most recent when its compilation, grep, or +similar mode is started, or when it is used with \\[next-error] +or \\[compile-goto-error].") + +(defvar next-error-function nil + "Function to use to find the next error in the current buffer. +The function is called with 2 parameters: +ARG is an integer specifying by how many errors to move. +RESET is a boolean which, if non-nil, says to go back to the beginning +of the errors before moving. +Major modes providing compile-like functionality should set this variable +to indicate to `next-error' that this is a candidate buffer and how +to navigate in it.") + +(make-variable-buffer-local 'next-error-function) + +(defsubst next-error-buffer-p (buffer + &optional avoid-current + extra-test-inclusive + extra-test-exclusive) + "Test if BUFFER is a `next-error' capable buffer. + +If AVOID-CURRENT is non-nil, treat the current buffer +as an absolute last resort only. + +The function EXTRA-TEST-INCLUSIVE, if non-nil, is called in each buffer +that normally would not qualify. If it returns t, the buffer +in question is treated as usable. + +The function EXTRA-TEST-EXCLUSIVE, if non-nil, is called in each buffer +that would normally be considered usable. If it returns nil, +that buffer is rejected." + (and (buffer-name buffer) ;First make sure it's live. + (not (and avoid-current (eq buffer (current-buffer)))) + (with-current-buffer buffer + (if next-error-function ; This is the normal test. + ;; Optionally reject some buffers. + (if extra-test-exclusive + (funcall extra-test-exclusive) + t) + ;; Optionally accept some other buffers. + (and extra-test-inclusive + (funcall extra-test-inclusive)))))) + +(defun next-error-find-buffer (&optional avoid-current + extra-test-inclusive + extra-test-exclusive) + "Return a `next-error' capable buffer. + +If AVOID-CURRENT is non-nil, treat the current buffer +as an absolute last resort only. + +The function EXTRA-TEST-INCLUSIVE, if non-nil, is called in each buffer +that normally would not qualify. If it returns t, the buffer +in question is treated as usable. + +The function EXTRA-TEST-EXCLUSIVE, if non-nil, is called in each buffer +that would normally be considered usable. If it returns nil, +that buffer is rejected." + (or + ;; 1. If one window on the selected frame displays such buffer, return it. + (let ((window-buffers + (delete-dups + (delq nil (mapcar (lambda (w) + (if (next-error-buffer-p + (window-buffer w) + avoid-current + extra-test-inclusive extra-test-exclusive) + (window-buffer w))) + (window-list)))))) + (if (eq (length window-buffers) 1) + (car window-buffers))) + ;; 2. If next-error-last-buffer is an acceptable buffer, use that. + (if (and next-error-last-buffer + (next-error-buffer-p next-error-last-buffer avoid-current + extra-test-inclusive extra-test-exclusive)) + next-error-last-buffer) + ;; 3. If the current buffer is acceptable, choose it. + (if (next-error-buffer-p (current-buffer) avoid-current + extra-test-inclusive extra-test-exclusive) + (current-buffer)) + ;; 4. Look for any acceptable buffer. + (let ((buffers (buffer-list))) + (while (and buffers + (not (next-error-buffer-p + (car buffers) avoid-current + extra-test-inclusive extra-test-exclusive))) + (setq buffers (cdr buffers))) + (car buffers)) + ;; 5. Use the current buffer as a last resort if it qualifies, + ;; even despite AVOID-CURRENT. + (and avoid-current + (next-error-buffer-p (current-buffer) nil + extra-test-inclusive extra-test-exclusive) + (progn + (message "This is the only next-error capable buffer") + (current-buffer))) + ;; 6. Give up. + (error "No next-error capable buffer found"))) + +(defun next-error (&optional arg reset) + "Visit next `next-error' message and corresponding source code. + +If all the error messages parsed so far have been processed already, +the message buffer is checked for new ones. + +A prefix ARG specifies how many error messages to move; +negative means move back to previous error messages. +Just \\[universal-argument] as a prefix means reparse the error message buffer +and start at the first error. + +The RESET argument specifies that we should restart from the beginning. + +\\[next-error] normally uses the most recently started +compilation, grep, or occur buffer. It can also operate on any +buffer with output from the \\[compile], \\[grep] commands, or, +more generally, on any buffer in Compilation mode or with +Compilation Minor mode enabled, or any buffer in which +`next-error-function' is bound to an appropriate function. +To specify use of a particular buffer for error messages, type +\\[next-error] in that buffer when it is the only one displayed +in the current frame. + +Once \\[next-error] has chosen the buffer for error messages, it +runs `next-error-hook' with `run-hooks', and stays with that buffer +until you use it in some other buffer which uses Compilation mode +or Compilation Minor mode. + +See variables `compilation-parse-errors-function' and +\`compilation-error-regexp-alist' for customization ideas." + (interactive "P") + (if (consp arg) (setq reset t arg nil)) + (when (setq next-error-last-buffer (next-error-find-buffer)) + ;; we know here that next-error-function is a valid symbol we can funcall + (with-current-buffer next-error-last-buffer + (funcall next-error-function (prefix-numeric-value arg) reset) + (run-hooks 'next-error-hook)))) + +(defun next-error-internal () + "Visit the source code corresponding to the `next-error' message at point." + (setq next-error-last-buffer (current-buffer)) + ;; we know here that next-error-function is a valid symbol we can funcall + (with-current-buffer next-error-last-buffer + (funcall next-error-function 0 nil) + (run-hooks 'next-error-hook))) + +(defalias 'goto-next-locus 'next-error) +(defalias 'next-match 'next-error) + +(defun previous-error (&optional n) + "Visit previous `next-error' message and corresponding source code. + +Prefix arg N says how many error messages to move backwards (or +forwards, if negative). + +This operates on the output from the \\[compile] and \\[grep] commands." + (interactive "p") + (next-error (- (or n 1)))) + +(defun first-error (&optional n) + "Restart at the first error. +Visit corresponding source code. +With prefix arg N, visit the source code of the Nth error. +This operates on the output from the \\[compile] command, for instance." + (interactive "p") + (next-error n t)) + +(defun next-error-no-select (&optional n) + "Move point to the next error in the `next-error' buffer and highlight match. +Prefix arg N says how many error messages to move forwards (or +backwards, if negative). +Finds and highlights the source line like \\[next-error], but does not +select the source buffer." + (interactive "p") + (let ((next-error-highlight next-error-highlight-no-select)) + (next-error n)) + (pop-to-buffer next-error-last-buffer)) + +(defun previous-error-no-select (&optional n) + "Move point to the previous error in the `next-error' buffer and highlight match. +Prefix arg N says how many error messages to move backwards (or +forwards, if negative). +Finds and highlights the source line like \\[previous-error], but does not +select the source buffer." + (interactive "p") + (next-error-no-select (- (or n 1)))) + +;;; Internal variable for `next-error-follow-mode-post-command-hook'. +(defvar next-error-follow-last-line nil) + +(define-minor-mode next-error-follow-minor-mode + "Minor mode for compilation, occur and diff modes. +When turned on, cursor motion in the compilation, grep, occur or diff +buffer causes automatic display of the corresponding source code +location." + :group 'next-error :init-value nil :lighter " Fol" + (if (not next-error-follow-minor-mode) + (remove-hook 'post-command-hook 'next-error-follow-mode-post-command-hook t) + (add-hook 'post-command-hook 'next-error-follow-mode-post-command-hook nil t) + (make-local-variable 'next-error-follow-last-line))) + +;;; Used as a `post-command-hook' by `next-error-follow-mode' +;;; for the *Compilation* *grep* and *Occur* buffers. +(defun next-error-follow-mode-post-command-hook () + (unless (equal next-error-follow-last-line (line-number-at-pos)) + (setq next-error-follow-last-line (line-number-at-pos)) + (condition-case nil + (let ((compilation-context-lines nil)) + (setq compilation-current-error (point)) + (next-error-no-select 0)) + (error t)))) + + +;;; (defun fundamental-mode () "Major mode not specialized for anything in particular. Other major modes are defined by comparison with this one." (interactive) - (kill-all-local-variables)) + (kill-all-local-variables) + (unless delay-mode-hooks + (run-hooks 'after-change-major-mode-hook))) ;; Making and deleting lines. +(defvar hard-newline (propertize "\n" 'hard t 'rear-nonsticky '(hard))) + (defun newline (&optional arg) "Insert a newline, and move to left margin of the new line if it's blank. If `use-hard-newlines' is non-nil, the newline is marked with the text-property `hard'. With ARG, insert that many newlines. Call `auto-fill-function' if the current column number is greater -than the value of `fill-column' and ARG is `nil'." +than the value of `fill-column' and ARG is nil." (interactive "*P") (barf-if-buffer-read-only) ;; Inserting a newline at the end of a line produces better redisplay in @@ -159,10 +479,10 @@ (put-text-property from (point) 'rear-nonsticky (cons 'hard sticky))))) -(defun open-line (arg) +(defun open-line (n) "Insert a newline and leave point before it. -If there is a fill prefix and/or a left-margin, insert them on the new line -if the line would have been blank. +If there is a fill prefix and/or a `left-margin', insert them +on the new line if the line would have been blank. With arg N, insert N newlines." (interactive "*p") (let* ((do-fill-prefix (and fill-prefix (bolp))) @@ -170,23 +490,23 @@ (loc (point)) ;; Don't expand an abbrev before point. (abbrev-mode nil)) - (newline arg) + (newline n) (goto-char loc) - (while (> arg 0) + (while (> n 0) (cond ((bolp) (if do-left-margin (indent-to (current-left-margin))) (if do-fill-prefix (insert-and-inherit fill-prefix)))) (forward-line 1) - (setq arg (1- arg))) + (setq n (1- n))) (goto-char loc) (end-of-line))) (defun split-line (&optional arg) "Split current line, moving portion beyond point vertically down. If the current line starts with `fill-prefix', insert it on the new -line as well. With prefix arg, don't insert fill-prefix on new line. - -When called from Lisp code, the arg may be a prefix string to copy." +line as well. With prefix ARG, don't insert `fill-prefix' on new line. + +When called from Lisp code, ARG may be a prefix string to copy." (interactive "*P") (skip-chars-forward " \t") (let* ((col (current-column)) @@ -303,14 +623,14 @@ In some text modes, where TAB inserts a tab, this indents to the column specified by the function `current-left-margin'." (interactive "*") - (delete-horizontal-space t) (let ((pos (point))) ;; Be careful to insert the newline before indenting the line. ;; Otherwise, the indentation might be wrong. (newline) (save-excursion (goto-char pos) - (indent-according-to-mode)) + (indent-according-to-mode) + (delete-horizontal-space t)) (indent-according-to-mode))) (defun quoted-insert (arg) @@ -333,7 +653,7 @@ digits are interpreted as a character code. This is intended to be useful for editing binary files." (interactive "*p") - (let* ((char (let (translation-table-for-input) + (let* ((char (let (translation-table-for-input input-method-function) (if (or (not overwrite-mode) (eq overwrite-mode 'overwrite-mode-binary)) (read-quoted-char) @@ -352,24 +672,25 @@ (insert-and-inherit char) (setq arg (1- arg))))) -(defun forward-to-indentation (arg) +(defun forward-to-indentation (&optional arg) "Move forward ARG lines and position at first nonblank character." (interactive "p") - (forward-line arg) + (forward-line (or arg 1)) (skip-chars-forward " \t")) -(defun backward-to-indentation (arg) +(defun backward-to-indentation (&optional arg) "Move backward ARG lines and position at first nonblank character." (interactive "p") - (forward-line (- arg)) + (forward-line (- (or arg 1))) (skip-chars-forward " \t")) (defun back-to-indentation () "Move point to the first non-whitespace character on this line." (interactive) (beginning-of-line 1) - (let ((limit (line-end-position))) - (skip-syntax-forward " " limit))) + (skip-syntax-forward " " (line-end-position)) + ;; Move back over chars that have whitespace syntax but have the p flag. + (backward-prefix-chars)) (defun fixup-whitespace () "Fixup white space between objects around point. @@ -381,7 +702,7 @@ (save-excursion (forward-char -1) (looking-at "$\\|\\s(\\|\\s'"))) nil - (insert ?\ )))) + (insert ?\s)))) (defun delete-horizontal-space (&optional backward-only) "Delete all spaces and tabs around point. @@ -398,15 +719,16 @@ (skip-chars-backward " \t") (constrain-to-field nil orig-pos))))) -(defun just-one-space () - "Delete all spaces and tabs around point, leaving one space." - (interactive "*") +(defun just-one-space (&optional n) + "Delete all spaces and tabs around point, leaving one space (or N spaces)." + (interactive "*p") (let ((orig-pos (point))) (skip-chars-backward " \t") (constrain-to-field nil orig-pos) - (if (= (following-char) ? ) - (forward-char 1) - (insert ? )) + (dotimes (i (or n 1)) + (if (= (following-char) ?\s) + (forward-char 1) + (insert ?\s))) (delete-region (point) (progn @@ -415,7 +737,8 @@ (defun beginning-of-buffer (&optional arg) "Move point to the beginning of the buffer; leave mark at previous position. -With arg N, put point N/10 of the way from the beginning. +With \\[universal-argument] prefix, do not set mark at previous position. +With numeric arg N, put point N/10 of the way from the beginning. If the buffer is narrowed, this command uses the beginning and size of the accessible part of the buffer. @@ -423,9 +746,11 @@ Don't use this command in Lisp programs! \(goto-char (point-min)) is faster and avoids clobbering the mark." (interactive "P") - (push-mark) + (or (consp arg) + (and transient-mark-mode mark-active) + (push-mark)) (let ((size (- (point-max) (point-min)))) - (goto-char (if arg + (goto-char (if (and arg (not (consp arg))) (+ (point-min) (if (> size 10000) ;; Avoid overflow for large buffer sizes! @@ -437,7 +762,8 @@ (defun end-of-buffer (&optional arg) "Move point to the end of the buffer; leave mark at previous position. -With arg N, put point N/10 of the way from the end. +With \\[universal-argument] prefix, do not set mark at previous position. +With numeric arg N, put point N/10 of the way from the end. If the buffer is narrowed, this command uses the beginning and size of the accessible part of the buffer. @@ -445,9 +771,11 @@ Don't use this command in Lisp programs! \(goto-char (point-max)) is faster and avoids clobbering the mark." (interactive "P") - (push-mark) + (or (consp arg) + (and transient-mark-mode mark-active) + (push-mark)) (let ((size (- (point-max) (point-min)))) - (goto-char (if arg + (goto-char (if (and arg (not (consp arg))) (- (point-max) (if (> size 10000) ;; Avoid overflow for large buffer sizes! @@ -477,10 +805,49 @@ ;; Counting lines, one way or another. -(defun goto-line (arg) - "Goto line ARG, counting from line 1 at beginning of buffer." - (interactive "NGoto line: ") - (setq arg (prefix-numeric-value arg)) +(defun goto-line (arg &optional buffer) + "Goto line ARG, counting from line 1 at beginning of buffer. +Normally, move point in the current buffer. +With just \\[universal-argument] as argument, move point in the most recently +displayed other buffer, and switch to it. When called from Lisp code, +the optional argument BUFFER specifies a buffer to switch to. + +If there's a number in the buffer at point, it is the default for ARG." + (interactive + (if (and current-prefix-arg (not (consp current-prefix-arg))) + (list (prefix-numeric-value current-prefix-arg)) + ;; Look for a default, a number in the buffer at point. + (let* ((default + (save-excursion + (skip-chars-backward "0-9") + (if (looking-at "[0-9]") + (buffer-substring-no-properties + (point) + (progn (skip-chars-forward "0-9") + (point)))))) + ;; Decide if we're switching buffers. + (buffer + (if (consp current-prefix-arg) + (other-buffer (current-buffer) t))) + (buffer-prompt + (if buffer + (concat " in " (buffer-name buffer)) + ""))) + ;; Read the argument, offering that number (if any) as default. + (list (read-from-minibuffer (format (if default "Goto line%s (%s): " + "Goto line%s: ") + buffer-prompt + default) + nil nil t + 'minibuffer-history + default) + buffer)))) + ;; Switch to the desired buffer, one way or another. + (if buffer + (let ((window (get-buffer-window buffer))) + (if window (select-window window) + (switch-to-buffer-other-window buffer)))) + ;; Move to the specified line number in that buffer. (save-restriction (widen) (goto-char 1) @@ -497,20 +864,15 @@ (defun what-line () "Print the current buffer line number and narrowed line number of point." (interactive) - (let ((opoint (point)) start) - (save-excursion - (save-restriction - (goto-char (point-min)) - (widen) - (forward-line 0) - (setq start (point)) - (goto-char opoint) - (forward-line 0) - (if (/= start (point-min)) - (message "line %d (narrowed line %d)" - (1+ (count-lines (point-min) (point))) - (1+ (count-lines start (point)))) - (message "Line %d" (1+ (count-lines (point-min) (point))))))))) + (let ((start (point-min)) + (n (line-number-at-pos))) + (if (= start 1) + (message "Line %d" n) + (save-excursion + (save-restriction + (widen) + (message "line %d (narrowed line %d)" + (+ n (line-number-at-pos start) -1) n)))))) (defun count-lines (start end) "Return number of lines between START and END. @@ -535,6 +897,17 @@ done))) (- (buffer-size) (forward-line (buffer-size))))))) +(defun line-number-at-pos (&optional pos) + "Return (narrowed) buffer line number at position POS. +If POS is nil, use current buffer location." + (let ((opoint (or pos (point))) start) + (save-excursion + (goto-char (point-min)) + (setq start (point)) + (goto-char opoint) + (forward-line 0) + (1+ (count-lines start (point)))))) + (defun what-cursor-position (&optional detail) "Print info on cursor position (on screen and within buffer). Also describe the character after point, and give its character code @@ -564,40 +937,62 @@ (col (current-column))) (if (= pos end) (if (or (/= beg 1) (/= end (1+ total))) - (message "point=%d of %d (%d%%) <%d - %d> column %d %s" + (message "point=%d of %d (%d%%) <%d-%d> column=%d%s" pos total percent beg end col hscroll) - (message "point=%d of %d (%d%%) column %d %s" - pos total percent col hscroll)) + (message "point=%d of %d (EOB) column=%d%s" + pos total col hscroll)) (let ((coding buffer-file-coding-system) - encoded encoding-msg) + encoded encoding-msg display-prop under-display) (if (or (not coding) (eq (coding-system-type coding) t)) (setq coding default-buffer-file-coding-system)) (if (not (char-valid-p char)) (setq encoding-msg - (format "(0%o, %d, 0x%x, invalid)" char char char)) - (setq encoded (and (>= char 128) (encode-coding-char char coding))) + (format "(%d, #o%o, #x%x, invalid)" char char char)) + ;; Check if the character is displayed with some `display' + ;; text property. In that case, set under-display to the + ;; buffer substring covered by that property. + (setq display-prop (get-text-property pos 'display)) + (if display-prop + (let ((to (or (next-single-property-change pos 'display) + (point-max)))) + (if (< to (+ pos 4)) + (setq under-display "") + (setq under-display "..." + to (+ pos 4))) + (setq under-display + (concat (buffer-substring-no-properties pos to) + under-display))) + (setq encoded (and (>= char 128) (encode-coding-char char coding)))) (setq encoding-msg - (if encoded - (format "(0%o, %d, 0x%x, file %s)" - char char char - (if (> (length encoded) 1) - "..." - (encoded-string-description encoded coding))) - (format "(0%o, %d, 0x%x)" char char char)))) + (if display-prop + (if (not (stringp display-prop)) + (format "(%d, #o%o, #x%x, part of display \"%s\")" + char char char under-display) + (format "(%d, #o%o, #x%x, part of display \"%s\"->\"%s\")" + char char char under-display display-prop)) + (if encoded + (format "(%d, #o%o, #x%x, file %s)" + char char char + (if (> (length encoded) 1) + "..." + (encoded-string-description encoded coding))) + (format "(%d, #o%o, #x%x)" char char char))))) (if detail ;; We show the detailed information about CHAR. (describe-char (point))) (if (or (/= beg 1) (/= end (1+ total))) - (message "Char: %s %s point=%d of %d (%d%%) <%d - %d> column %d %s" + (message "Char: %s %s point=%d of %d (%d%%) <%d-%d> column=%d%s" (if (< char 256) (single-key-description char) (buffer-substring-no-properties (point) (1+ (point)))) encoding-msg pos total percent beg end col hscroll) - (message "Char: %s %s point=%d of %d (%d%%) column %d %s" - (if (< char 256) - (single-key-description char) - (buffer-substring-no-properties (point) (1+ (point)))) + (message "Char: %s %s point=%d of %d (%d%%) column=%d%s" + (if enable-multibyte-characters + (if (< char 128) + (single-key-description char) + (buffer-substring-no-properties (point) (1+ (point)))) + (single-key-description char)) encoding-msg pos total percent col hscroll)))))) (defvar read-expression-map @@ -610,26 +1005,43 @@ (defvar read-expression-history nil) (defcustom eval-expression-print-level 4 - "*Value to use for `print-level' when printing value in `eval-expression'. + "Value for `print-level' while printing value in `eval-expression'. A value of nil means no limit." :group 'lisp :type '(choice (const :tag "No Limit" nil) integer) :version "21.1") (defcustom eval-expression-print-length 12 - "*Value to use for `print-length' when printing value in `eval-expression'. + "Value for `print-length' while printing value in `eval-expression'. A value of nil means no limit." :group 'lisp :type '(choice (const :tag "No Limit" nil) integer) :version "21.1") (defcustom eval-expression-debug-on-error t - "*Non-nil means set `debug-on-error' when evaluating in `eval-expression'. + "If non-nil set `debug-on-error' to t in `eval-expression'. If nil, don't change the value of `debug-on-error'." :group 'lisp :type 'boolean :version "21.1") +(defun eval-expression-print-format (value) + "Format VALUE as a result of evaluated expression. +Return a formatted string which is displayed in the echo area +in addition to the value printed by prin1 in functions which +display the result of expression evaluation." + (if (and (integerp value) + (or (not (memq this-command '(eval-last-sexp eval-print-last-sexp))) + (eq this-command last-command) + (if (boundp 'edebug-active) edebug-active))) + (let ((char-string + (if (or (if (boundp 'edebug-active) edebug-active) + (memq this-command '(eval-last-sexp eval-print-last-sexp))) + (prin1-char value)))) + (if char-string + (format " (#o%o, #x%x, %s)" value value char-string) + (format " (#o%o, #x%x)" value value))))) + ;; We define this, rather than making `eval' interactive, ;; for the sake of completion of names like eval-region, eval-current-buffer. (defun eval-expression (eval-expression-arg @@ -660,23 +1072,31 @@ (let ((print-length eval-expression-print-length) (print-level eval-expression-print-level)) - (prin1 (car values) - (if eval-expression-insert-value (current-buffer) t)))) + (if eval-expression-insert-value + (with-no-warnings + (let ((standard-output (current-buffer))) + (eval-last-sexp-print-value (car values)))) + (prog1 + (prin1 (car values) t) + (let ((str (eval-expression-print-format (car values)))) + (if str (princ str t))))))) (defun edit-and-eval-command (prompt command) "Prompting with PROMPT, let user edit COMMAND and eval result. COMMAND is a Lisp expression. Let user edit that expression in the minibuffer, then read and evaluate the result." (let ((command - (unwind-protect - (read-from-minibuffer prompt - (prin1-to-string command) - read-expression-map t - '(command-history . 1)) - ;; If command was added to command-history as a string, - ;; get rid of that. We want only evaluable expressions there. - (if (stringp (car command-history)) - (setq command-history (cdr command-history)))))) + (let ((print-level nil) + (minibuffer-history-sexp-flag (1+ (minibuffer-depth)))) + (unwind-protect + (read-from-minibuffer prompt + (prin1-to-string command) + read-expression-map t + 'command-history) + ;; If command was added to command-history as a string, + ;; get rid of that. We want only evaluable expressions there. + (if (stringp (car command-history)) + (setq command-history (cdr command-history))))))) ;; If command to be redone does not match front of history, ;; add it to the history. @@ -727,11 +1147,11 @@ This is used for all minibuffer input except when an alternate history list is specified.") (defvar minibuffer-history-sexp-flag nil - "Non-nil when doing history operations on the variable `command-history'. -More generally, indicates that the history list being acted on -contains expressions rather than strings. -It is only valid if its value equals the current minibuffer depth, -to handle recursive uses of the minibuffer.") + "Control whether history list elements are expressions or strings. +If the value of this variable equals current minibuffer depth, +they are expressions; otherwise they are strings. +\(That convention is designed to do the right thing for +recursive uses of the minibuffer.)") (setq minibuffer-history-variable 'minibuffer-history) (setq minibuffer-history-position nil) (defvar minibuffer-history-search-history nil) @@ -773,7 +1193,8 @@ nil minibuffer-local-map nil - 'minibuffer-history-search-history))) + 'minibuffer-history-search-history + (car minibuffer-history-search-history)))) ;; Use the last regexp specified, by default, if input is empty. (list (if (string= regexp "") (if minibuffer-history-search-history @@ -843,11 +1264,13 @@ nil minibuffer-local-map nil - 'minibuffer-history-search-history))) + 'minibuffer-history-search-history + (car minibuffer-history-search-history)))) ;; Use the last regexp specified, by default, if input is empty. (list (if (string= regexp "") - (setcar minibuffer-history-search-history - (nth 1 minibuffer-history-search-history)) + (if minibuffer-history-search-history + (car minibuffer-history-search-history) + (error "No previous history search regexp")) regexp) (prefix-numeric-value current-prefix-arg)))) (previous-matching-history-element regexp (- n))) @@ -928,7 +1351,7 @@ ;; For compatibility with the old subr of the same name. (defun minibuffer-prompt-width () "Return the display width of the minibuffer prompt. -Return 0 if current buffer is not a mini-buffer." +Return 0 if current buffer is not a minibuffer." ;; Return the width of everything before the field at the end of ;; the buffer; this should be 0 for normal buffers. (1- (minibuffer-prompt-end))) @@ -936,13 +1359,28 @@ ;Put this on C-x u, so we can force that rather than C-_ into startup msg (defalias 'advertised-undo 'undo) +(defconst undo-equiv-table (make-hash-table :test 'eq :weakness t) + "Table mapping redo records to the corresponding undo one. +A redo record for undo-in-region maps to t. +A redo record for ordinary undo maps to the following (earlier) undo.") + +(defvar undo-in-region nil + "Non-nil if `pending-undo-list' is not just a tail of `buffer-undo-list'.") + +(defvar undo-no-redo nil + "If t, `undo' doesn't go through redo entries.") + +(defvar pending-undo-list nil + "Within a run of consecutive undo commands, list remaining to be undone. +If t, we undid all the way to the end of it.") + (defun undo (&optional arg) "Undo some previous changes. Repeat this command to undo more changes. A numeric argument serves as a repeat count. In Transient Mark mode when the mark is active, only undo changes within -the current region. Similarly, when not in Transient Mark mode, just C-u +the current region. Similarly, when not in Transient Mark mode, just \\[universal-argument] as an argument limits undo to changes within the current region." (interactive "*P") ;; Make last-command indicate for the next command that this was an undo. @@ -951,23 +1389,58 @@ ;; another undo command will find the undo history empty ;; and will get another error. To begin undoing the undos, ;; you must type some other command. - (setq this-command 'undo) (let ((modified (buffer-modified-p)) - (recent-save (recent-auto-save-p))) - (or (eq (selected-window) (minibuffer-window)) - (message (if (and transient-mark-mode mark-active) - "Undo in region!" - "Undo!"))) - (unless (eq last-command 'undo) - (if (if transient-mark-mode mark-active (and arg (not (numberp arg)))) + (recent-save (recent-auto-save-p)) + message) + ;; If we get an error in undo-start, + ;; the next command should not be a "consecutive undo". + ;; So set `this-command' to something other than `undo'. + (setq this-command 'undo-start) + + (unless (and (eq last-command 'undo) + (or (eq pending-undo-list t) + ;; If something (a timer or filter?) changed the buffer + ;; since the previous command, don't continue the undo seq. + (let ((list buffer-undo-list)) + (while (eq (car list) nil) + (setq list (cdr list))) + ;; If the last undo record made was made by undo + ;; it shows nothing else happened in between. + (gethash list undo-equiv-table)))) + (setq undo-in-region + (if transient-mark-mode mark-active (and arg (not (numberp arg))))) + (if undo-in-region (undo-start (region-beginning) (region-end)) (undo-start)) ;; get rid of initial undo boundary (undo-more 1)) + ;; If we got this far, the next command should be a consecutive undo. + (setq this-command 'undo) + ;; Check to see whether we're hitting a redo record, and if + ;; so, ask the user whether she wants to skip the redo/undo pair. + (let ((equiv (gethash pending-undo-list undo-equiv-table))) + (or (eq (selected-window) (minibuffer-window)) + (setq message (if undo-in-region + (if equiv "Redo in region!" "Undo in region!") + (if equiv "Redo!" "Undo!")))) + (when (and (consp equiv) undo-no-redo) + ;; The equiv entry might point to another redo record if we have done + ;; undo-redo-undo-redo-... so skip to the very last equiv. + (while (let ((next (gethash equiv undo-equiv-table))) + (if next (setq equiv next)))) + (setq pending-undo-list equiv))) (undo-more (if (or transient-mark-mode (numberp arg)) (prefix-numeric-value arg) 1)) + ;; Record the fact that the just-generated undo records come from an + ;; undo operation--that is, they are redo records. + ;; In the ordinary case (not within a region), map the redo + ;; record to the following undos. + ;; I don't know how to do that in the undo-in-region case. + (puthash buffer-undo-list + (if undo-in-region t pending-undo-list) + undo-equiv-table) ;; Don't specify a position in the undo record for the undo command. ;; Instead, undoing this should move point to where the change is. (let ((tail buffer-undo-list) @@ -975,9 +1448,9 @@ (while (car tail) (when (integerp (car tail)) (let ((pos (car tail))) - (if (null prev) - (setq buffer-undo-list (cdr tail)) - (setcdr prev (cdr tail))) + (if prev + (setcdr prev (cdr tail)) + (setq buffer-undo-list (cdr tail))) (setq tail (cdr tail)) (while (car tail) (if (eq pos (car tail)) @@ -988,27 +1461,45 @@ (setq tail (cdr tail))) (setq tail nil))) (setq prev tail tail (cdr tail)))) - + ;; Record what the current undo list says, + ;; so the next command can tell if the buffer was modified in between. (and modified (not (buffer-modified-p)) - (delete-auto-save-file-if-necessary recent-save)))) - -(defvar pending-undo-list nil - "Within a run of consecutive undo commands, list remaining to be undone.") + (delete-auto-save-file-if-necessary recent-save)) + ;; Display a message announcing success. + (if message + (message message)))) + +(defun buffer-disable-undo (&optional buffer) + "Make BUFFER stop keeping undo information. +No argument or nil as argument means do this for the current buffer." + (interactive) + (with-current-buffer (if buffer (get-buffer buffer) (current-buffer)) + (setq buffer-undo-list t))) + +(defun undo-only (&optional arg) + "Undo some previous changes. +Repeat this command to undo more changes. +A numeric argument serves as a repeat count. +Contrary to `undo', this will not redo a previous undo." + (interactive "*p") + (let ((undo-no-redo t)) (undo arg))) (defvar undo-in-progress nil "Non-nil while performing an undo. Some change-hooks test this variable to do something different.") -(defun undo-more (count) +(defun undo-more (n) "Undo back N undo-boundaries beyond what was already undone recently. Call `undo-start' to get ready to undo recent changes, then call `undo-more' one or more times to undo them." - (or pending-undo-list - (error (format "No further undo information%s" - (if (and transient-mark-mode mark-active) - " for region" "")))) + (or (listp pending-undo-list) + (error (concat "No further undo information" + (and transient-mark-mode mark-active + " for region")))) (let ((undo-in-progress t)) - (setq pending-undo-list (primitive-undo count pending-undo-list)))) + (setq pending-undo-list (primitive-undo n pending-undo-list)) + (if (null pending-undo-list) + (setq pending-undo-list t)))) ;; Deep copy of a list (defun undo-copy-list (list) @@ -1172,6 +1663,77 @@ (t '(0 . 0))) '(0 . 0))) + +(defcustom undo-ask-before-discard t + "If non-nil ask about discarding undo info for the current command. +Normally, Emacs discards the undo info for the current command if +it exceeds `undo-outer-limit'. But if you set this option +non-nil, it asks in the echo area whether to discard the info. +If you answer no, there a slight risk that Emacs might crash, so +only do it if you really want to undo the command. + +This option is mainly intended for debugging. You have to be +careful if you use it for other purposes. Garbage collection is +inhibited while the question is asked, meaning that Emacs might +leak memory. So you should make sure that you do not wait +excessively long before answering the question." + :type 'boolean + :group 'undo + :version "22.1") + +(defvar undo-extra-outer-limit nil + "If non-nil, an extra level of size that's ok in an undo item. +We don't ask the user about truncating the undo list until the +current item gets bigger than this amount. + +This variable only matters if `undo-ask-before-discard' is non-nil.") +(make-variable-buffer-local 'undo-extra-outer-limit) + +;; When the first undo batch in an undo list is longer than +;; undo-outer-limit, this function gets called to warn the user that +;; the undo info for the current command was discarded. Garbage +;; collection is inhibited around the call, so it had better not do a +;; lot of consing. +(setq undo-outer-limit-function 'undo-outer-limit-truncate) +(defun undo-outer-limit-truncate (size) + (if undo-ask-before-discard + (when (or (null undo-extra-outer-limit) + (> size undo-extra-outer-limit)) + ;; Don't ask the question again unless it gets even bigger. + ;; This applies, in particular, if the user quits from the question. + ;; Such a quit quits out of GC, but something else will call GC + ;; again momentarily. It will call this function again, + ;; but we don't want to ask the question again. + (setq undo-extra-outer-limit (+ size 50000)) + (if (let (use-dialog-box track-mouse executing-kbd-macro ) + (yes-or-no-p (format "Buffer %s undo info is %d bytes long; discard it? " + (buffer-name) size))) + (progn (setq buffer-undo-list nil) + (setq undo-extra-outer-limit nil) + t) + nil)) + (display-warning '(undo discard-info) + (concat + (format "Buffer %s undo info was %d bytes long.\n" + (buffer-name) size) + "The undo info was discarded because it exceeded \ +`undo-outer-limit'. + +This is normal if you executed a command that made a huge change +to the buffer. In that case, to prevent similar problems in the +future, set `undo-outer-limit' to a value that is large enough to +cover the maximum size of normal changes you expect a single +command to make, but not so large that it might exceed the +maximum memory allotted to Emacs. + +If you did not execute any such command, the situation is +probably due to a bug and you should report it. + +You can disable the popping up of this buffer by adding the entry +\(undo discard-info) to the user option `warning-suppress-types'.\n") + :warning) + (setq buffer-undo-list nil) + t)) (defvar shell-command-history nil "History list for some commands that read shell commands.") @@ -1305,8 +1867,7 @@ (if (yes-or-no-p "A command is running. Kill it? ") (kill-process proc) (error "Shell command in progress"))) - (save-excursion - (set-buffer buffer) + (with-current-buffer buffer (setq buffer-read-only nil) (erase-buffer) (display-buffer buffer) @@ -1399,7 +1960,7 @@ (defun shell-command-on-region (start end command &optional output-buffer replace - error-buffer) + error-buffer display-error-buffer) "Execute string COMMAND in inferior shell with region as input. Normally display output (if any) in temp buffer `*Shell Command Output*'; Prefix arg means replace the region with it. Return the exit code of @@ -1412,10 +1973,10 @@ `buffer-file-coding-system'. If the output is going to replace the region, then it is decoded from that same coding system. -The noninteractive arguments are START, END, COMMAND, OUTPUT-BUFFER, -REPLACE, ERROR-BUFFER. Noninteractive callers can specify coding -systems by binding `coding-system-for-read' and -`coding-system-for-write'. +The noninteractive arguments are START, END, COMMAND, +OUTPUT-BUFFER, REPLACE, ERROR-BUFFER, and DISPLAY-ERROR-BUFFER. +Noninteractive callers can specify coding systems by binding +`coding-system-for-read' and `coding-system-for-write'. If the command generates output, the output may be displayed in the echo area or in a buffer. @@ -1445,6 +2006,8 @@ If optional sixth argument ERROR-BUFFER is non-nil, it is a buffer or buffer name to which to direct the command's standard error output. If it is nil, error output is mingled with regular output. +If DISPLAY-ERROR-BUFFER is non-nil, display the error buffer if there +were any errors. (This is always t, interactively.) In an interactive call, the variable `shell-command-default-error-buffer' specifies the value of ERROR-BUFFER." (interactive (let (string) @@ -1462,7 +2025,8 @@ string current-prefix-arg current-prefix-arg - shell-command-default-error-buffer))) + shell-command-default-error-buffer + t))) (let ((error-file (if error-buffer (make-temp-file @@ -1571,7 +2135,8 @@ (format-insert-file error-file nil) ;; Put point after the inserted errors. (goto-char (- (point-max) pos-from-end))) - (display-buffer (current-buffer)))) + (and display-error-buffer + (display-buffer (current-buffer))))) (delete-file error-file)) exit-status)) @@ -1581,6 +2146,39 @@ (with-current-buffer standard-output (call-process shell-file-name nil t nil shell-command-switch command)))) + +(defun process-file (program &optional infile buffer display &rest args) + "Process files synchronously in a separate process. +Similar to `call-process', but may invoke a file handler based on +`default-directory'. The current working directory of the +subprocess is `default-directory'. + +File names in INFILE and BUFFER are handled normally, but file +names in ARGS should be relative to `default-directory', as they +are passed to the process verbatim. \(This is a difference to +`call-process' which does not support file handlers for INFILE +and BUFFER.\) + +Some file handlers might not support all variants, for example +they might behave as if DISPLAY was nil, regardless of the actual +value passed." + (let ((fh (find-file-name-handler default-directory 'process-file)) + lc stderr-file) + (unwind-protect + (if fh (apply fh 'process-file program infile buffer display args) + (when infile (setq lc (file-local-copy infile))) + (setq stderr-file (when (and (consp buffer) (stringp (cadr buffer))) + (make-temp-file "emacs"))) + (prog1 + (apply 'call-process program + (or lc infile) + (if stderr-file (list (car buffer) stderr-file) buffer) + display args) + (when stderr-file (copy-file stderr-file (cadr buffer))))) + (when stderr-file (delete-file stderr-file)) + (when lc (delete-file lc))))) + + (defvar universal-argument-map (let ((map (make-sparse-keymap))) @@ -1618,6 +2216,26 @@ `universal-argument-other-key' uses this to discard those events from (this-command-keys), and reread only the final command.") +(defvar overriding-map-is-bound nil + "Non-nil when `overriding-terminal-local-map' is `universal-argument-map'.") + +(defvar saved-overriding-map nil + "The saved value of `overriding-terminal-local-map'. +That variable gets restored to this value on exiting \"universal +argument mode\".") + +(defun ensure-overriding-map-is-bound () + "Check `overriding-terminal-local-map' is `universal-argument-map'." + (unless overriding-map-is-bound + (setq saved-overriding-map overriding-terminal-local-map) + (setq overriding-terminal-local-map universal-argument-map) + (setq overriding-map-is-bound t))) + +(defun restore-overriding-map () + "Restore `overriding-terminal-local-map' to its saved value." + (setq overriding-terminal-local-map saved-overriding-map) + (setq overriding-map-is-bound nil)) + (defun universal-argument () "Begin a numeric argument for the following command. Digits or minus sign following \\[universal-argument] make up the numeric argument. @@ -1631,7 +2249,7 @@ (interactive) (setq prefix-arg (list 4)) (setq universal-argument-num-events (length (this-command-keys))) - (setq overriding-terminal-local-map universal-argument-map)) + (ensure-overriding-map-is-bound)) ;; A subsequent C-u means to multiply the factor by 4 if we've typed ;; nothing but C-u's; otherwise it means to terminate the prefix arg. @@ -1642,7 +2260,7 @@ (if (eq arg '-) (setq prefix-arg (list -4)) (setq prefix-arg arg) - (setq overriding-terminal-local-map nil))) + (restore-overriding-map))) (setq universal-argument-num-events (length (this-command-keys)))) (defun negative-argument (arg) @@ -1656,7 +2274,7 @@ (t (setq prefix-arg '-))) (setq universal-argument-num-events (length (this-command-keys))) - (setq overriding-terminal-local-map universal-argument-map)) + (ensure-overriding-map-is-bound)) (defun digit-argument (arg) "Part of the numeric argument for the next command. @@ -1675,7 +2293,7 @@ (t (setq prefix-arg digit)))) (setq universal-argument-num-events (length (this-command-keys))) - (setq overriding-terminal-local-map universal-argument-map)) + (ensure-overriding-map-is-bound)) ;; For backward compatibility, minus with no modifiers is an ordinary ;; command if digits have already been entered. @@ -1696,8 +2314,44 @@ (append (nthcdr universal-argument-num-events keylist) unread-command-events))) (reset-this-command-lengths) - (setq overriding-terminal-local-map nil)) + (restore-overriding-map)) +(defvar buffer-substring-filters nil + "List of filter functions for `filter-buffer-substring'. +Each function must accept a single argument, a string, and return +a string. The buffer substring is passed to the first function +in the list, and the return value of each function is passed to +the next. The return value of the last function is used as the +return value of `filter-buffer-substring'. + +If this variable is nil, no filtering is performed.") + +(defun filter-buffer-substring (beg end &optional delete) + "Return the buffer substring between BEG and END, after filtering. +The buffer substring is passed through each of the filter +functions in `buffer-substring-filters', and the value from the +last filter function is returned. If `buffer-substring-filters' +is nil, the buffer substring is returned unaltered. + +If DELETE is non-nil, the text between BEG and END is deleted +from the buffer. + +Point is temporarily set to BEG before calling +`buffer-substring-filters', in case the functions need to know +where the text came from. + +This function should be used instead of `buffer-substring' or +`delete-and-extract-region' when you want to allow filtering to +take place. For example, major or minor modes can use +`buffer-substring-filters' to extract characters that are special +to a buffer, and should not be copied into other buffers." + (save-excursion + (goto-char beg) + (let ((string (if delete (delete-and-extract-region beg end) + (buffer-substring beg end)))) + (dolist (filter buffer-substring-filters string) + (setq string (funcall filter string)))))) + ;;;; Window system cut and paste hooks. (defvar interprogram-cut-function nil @@ -1712,8 +2366,8 @@ The function takes one or two arguments. The first argument, TEXT, is a string containing the text which should be made available. -The second, PUSH, if non-nil means this is a \"new\" kill; -nil means appending to an \"old\" kill.") +The second, optional, argument PUSH, has the same meaning as the +similar argument to `x-set-cut-buffer', which see.") (defvar interprogram-paste-function nil "Function to call to get text cut from other programs. @@ -1726,7 +2380,8 @@ The function should be called with no arguments. If the function returns nil, then no other program has provided such text, and the top of the Emacs kill ring should be used. If the function returns a -string, that string should be put in the kill ring as the latest kill. +string, then the caller of the function \(usually `current-kill') +should put this string in the kill ring as the latest kill. Note that the function should return a string only if a program other than Emacs has provided a string for pasting; if Emacs provided the @@ -1767,16 +2422,16 @@ Optional third arguments YANK-HANDLER controls how the STRING is later inserted into a buffer; see `insert-for-yank' for details. When a yank handler is specified, STRING must be non-empty (the yank -handler is stored as a `yank-handler'text property on STRING). +handler, if non-nil, is stored as a `yank-handler' text property on STRING). When the yank handler has a non-nil PARAM element, the original STRING argument is not used by `insert-for-yank'. However, since Lisp code -may access and use elements from the kill-ring directly, the STRING +may access and use elements from the kill ring directly, the STRING argument should still be a \"useful\" string for such uses." (if (> (length string) 0) (if yank-handler - (put-text-property 0 1 'yank-handler yank-handler string) - (remove-list-of-text-properties 0 1 '(yank-handler) string)) + (put-text-property 0 (length string) + 'yank-handler yank-handler string)) (if yank-handler (signal 'args-out-of-range (list string "yank-handler specified for empty string")))) @@ -1784,7 +2439,7 @@ (menu-bar-update-yank-menu string (and replace (car kill-ring)))) (if (and replace kill-ring) (setcar kill-ring string) - (setq kill-ring (cons string kill-ring)) + (push string kill-ring) (if (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))) (setq kill-ring-yank-pointer kill-ring) @@ -1794,11 +2449,12 @@ (defun kill-append (string before-p &optional yank-handler) "Append STRING to the end of the latest kill in the kill ring. If BEFORE-P is non-nil, prepend STRING to the kill. -Optional third argument YANK-HANDLER specifies the yank-handler text -property to be set on the combined kill ring string. If the specified -yank-handler arg differs from the yank-handler property of the latest -kill string, STRING is added as a new kill ring element instead of -being appending to the last kill. +Optional third argument YANK-HANDLER, if non-nil, specifies the +yank-handler text property to be set on the combined kill ring +string. If the specified yank-handler arg differs from the +yank-handler property of the latest kill string, this function +adds the combined string to the kill ring as a new element, +instead of replacing the last kill with it. If `interprogram-cut-function' is set, pass the resulting kill to it." (let* ((cur (car kill-ring))) (kill-new (if before-p (concat string cur) (concat cur string)) @@ -1860,24 +2516,27 @@ you can use the killing commands to copy text from a read-only buffer. This is the primitive for programs to kill text (as opposed to deleting it). -Supply two arguments, character numbers indicating the stretch of text +Supply two arguments, character positions indicating the stretch of text to be killed. Any command that calls this function is a \"kill command\". If the previous command was also a kill command, the text killed this time appends to the text killed last time to make one entry in the kill ring. -In Lisp code, optional third arg YANK-HANDLER specifies the yank-handler -text property to be set on the killed text. See `insert-for-yank'." +In Lisp code, optional third arg YANK-HANDLER, if non-nil, +specifies the yank-handler text property to be set on the killed +text. See `insert-for-yank'." (interactive "r") (condition-case nil - (let ((string (delete-and-extract-region beg end))) + (let ((string (filter-buffer-substring beg end t))) (when string ;STRING is nil if BEG = END ;; Add that string to the kill ring, one way or another. (if (eq last-command 'kill-region) (kill-append string (< end beg) yank-handler) (kill-new string nil yank-handler))) - (setq this-command 'kill-region)) + (when (or string (eq last-command 'kill-region)) + (setq this-command 'kill-region)) + nil) ((buffer-read-only text-read-only) ;; The code above failed because the buffer, or some of the characters ;; in the region, are read-only. @@ -1889,7 +2548,7 @@ (setq this-command 'kill-region) ;; This should barf, if appropriate, and give us the correct error. (if kill-read-only-ok - (message "Read only text copied to kill ring") + (progn (message "Read only text copied to kill ring") nil) ;; Signal an error if the buffer is read-only. (barf-if-buffer-read-only) ;; If the buffer isn't read-only, the text is. @@ -1905,8 +2564,8 @@ system cut and paste." (interactive "r") (if (eq last-command 'kill-region) - (kill-append (buffer-substring beg end) (< end beg)) - (kill-new (buffer-substring beg end))) + (kill-append (filter-buffer-substring beg end) (< end beg)) + (kill-new (filter-buffer-substring beg end))) (if transient-mark-mode (setq deactivate-mark t)) nil) @@ -1924,6 +2583,8 @@ visual feedback indicating the extent of the region being copied." (interactive "r") (copy-region-as-kill beg end) + ;; This use of interactive-p is correct + ;; because the code it controls just gives the user visual feedback. (if (interactive-p) (let ((other-end (if (= (point) beg) end beg)) (opoint (point)) @@ -1931,11 +2592,12 @@ ;; look like a C-g typed as a command. (inhibit-quit t)) (if (pos-visible-in-window-p other-end (selected-window)) - (unless transient-mark-mode + (unless (and transient-mark-mode + (face-background 'region)) ;; Swap point and mark. (set-marker (mark-marker) (point) (current-buffer)) (goto-char other-end) - (sit-for 1) + (sit-for blink-matching-delay) ;; Swap back. (set-marker (mark-marker) other-end (current-buffer)) (goto-char opoint) @@ -1968,11 +2630,13 @@ ;; This is actually used in subr.el but defcustom does not work there. (defcustom yank-excluded-properties '(read-only invisible intangible field mouse-face help-echo local-map keymap - yank-handler) - "*Text properties to discard when yanking." + yank-handler follow-link) + "*Text properties to discard when yanking. +The value should be a list of text properties to discard or t, +which means to discard all text properties." :type '(choice (const :tag "All" t) (repeat symbol)) - :group 'editing - :version "21.4") + :group 'killing + :version "22.1") (defvar yank-window-start nil) (defvar yank-undo-function nil @@ -1981,7 +2645,7 @@ the value of the mark and point; it is guaranteed that START <= END. Normally set from the UNDO element of a yank-handler; see `insert-for-yank'.") -(defun yank-pop (arg) +(defun yank-pop (&optional arg) "Replace just-yanked stretch of killed text with a different stretch. This command is allowed only immediately after a `yank' or a `yank-pop'. At such a time, the region contains a stretch of reinserted @@ -1993,11 +2657,16 @@ If N is negative, this is a more recent kill. The sequence of kills wraps around, so that after the oldest one -comes the newest one." +comes the newest one. + +When this command inserts killed text into the buffer, it honors +`yank-excluded-properties' and `yank-handler' as described in the +doc string for `insert-for-yank-1', which see." (interactive "*p") (if (not (eq last-command 'yank)) (error "Previous command was not a yank")) (setq this-command 'yank) + (unless arg (setq arg 1)) (let ((inhibit-read-only t) (before (< (point) (mark t)))) (if before @@ -2024,6 +2693,11 @@ With just \\[universal-argument] as argument, same but put point at beginning (and mark at end). With argument N, reinsert the Nth most recently killed stretch of killed text. + +When this command inserts killed text into the buffer, it honors +`yank-excluded-properties' and `yank-handler' as described in the +doc string for `insert-for-yank-1', which see. + See also the command \\[yank-pop]." (interactive "*P") (setq yank-window-start (window-start)) @@ -2033,7 +2707,7 @@ (push-mark (point)) (insert-for-yank (current-kill (cond ((listp arg) 0) - ((eq arg '-) -1) + ((eq arg '-) -2) (t (1- arg))))) (if (consp arg) ;; This is like exchange-point-and-mark, but doesn't activate the mark. @@ -2091,7 +2765,7 @@ (let ((col (current-column))) (forward-char -1) (setq col (- col (current-column))) - (insert-char ?\ col) + (insert-char ?\s col) (delete-char 1))) (forward-char -1) (setq count (1- count)))))) @@ -2111,6 +2785,8 @@ Case is ignored if `case-fold-search' is non-nil in the current buffer. Goes backward if ARG is negative; error if CHAR not found." (interactive "p\ncZap to char: ") + (if (char-table-p translation-table-for-input) + (setq char (or (aref translation-table-for-input char) char))) (kill-region (point) (progn (search-forward (char-to-string char) nil nil arg) ; (goto-char (if (> arg 0) (1- (point)) (1+ (point)))) @@ -2145,7 +2821,9 @@ If the buffer is read-only, Emacs will beep and refrain from deleting the line, but put the line in the kill ring anyway. This means that -you can use this command to copy text from a read-only buffer." +you can use this command to copy text from a read-only buffer. +\(If the variable `kill-read-only-ok' is non-nil, then this won't +even beep.)" (interactive "P") (kill-region (point) ;; It is better to move point to the other end of the kill @@ -2162,13 +2840,52 @@ (save-excursion (end-of-visible-line) (point)))) (if (or (save-excursion - (skip-chars-forward " \t" end) + ;; If trailing whitespace is visible, + ;; don't treat it as nothing. + (unless show-trailing-whitespace + (skip-chars-forward " \t" end)) (= (point) end)) (and kill-whole-line (bolp))) (forward-visible-line 1) (goto-char end)))) (point)))) +(defun kill-whole-line (&optional arg) + "Kill current line. +With prefix arg, kill that many lines starting from the current line. +If arg is negative, kill backward. Also kill the preceding newline. +\(This is meant to make \\[repeat] work well with negative arguments.\) +If arg is zero, kill current line but exclude the trailing newline." + (interactive "p") + (if (and (> arg 0) (eobp) (save-excursion (forward-visible-line 0) (eobp))) + (signal 'end-of-buffer nil)) + (if (and (< arg 0) (bobp) (save-excursion (end-of-visible-line) (bobp))) + (signal 'beginning-of-buffer nil)) + (unless (eq last-command 'kill-region) + (kill-new "") + (setq last-command 'kill-region)) + (cond ((zerop arg) + ;; We need to kill in two steps, because the previous command + ;; could have been a kill command, in which case the text + ;; before point needs to be prepended to the current kill + ;; ring entry and the text after point appended. Also, we + ;; need to use save-excursion to avoid copying the same text + ;; twice to the kill ring in read-only buffers. + (save-excursion + (kill-region (point) (progn (forward-visible-line 0) (point)))) + (kill-region (point) (progn (end-of-visible-line) (point)))) + ((< arg 0) + (save-excursion + (kill-region (point) (progn (end-of-visible-line) (point)))) + (kill-region (point) + (progn (forward-visible-line (1+ arg)) + (unless (bobp) (backward-char)) + (point)))) + (t + (save-excursion + (kill-region (point) (progn (forward-visible-line 0) (point)))) + (kill-region (point) + (progn (forward-visible-line arg) (point)))))) (defun forward-visible-line (arg) "Move forward by ARG lines, ignoring currently invisible newlines only. @@ -2208,8 +2925,8 @@ (unless (bolp) (goto-char opoint)))) (let ((first t)) - (while (or first (< arg 0)) - (if (zerop arg) + (while (or first (<= arg 0)) + (if first (beginning-of-line) (or (zerop (forward-line -1)) (signal 'beginning-of-buffer nil))) @@ -2218,13 +2935,12 @@ (unless (bobp) (let ((prop (get-char-property (1- (point)) 'invisible))) - (if (if (eq buffer-invisibility-spec t) - prop - (or (memq prop buffer-invisibility-spec) - (assq prop buffer-invisibility-spec))) - (setq arg (1+ arg))))) - (setq first nil) - (setq arg (1+ arg))) + (unless (if (eq buffer-invisibility-spec t) + prop + (or (memq prop buffer-invisibility-spec) + (assq prop buffer-invisibility-spec))) + (setq arg (1+ arg))))) + (setq first nil)) ;; If invisible text follows, and it is a number of complete lines, ;; skip it. (let ((opoint (point))) @@ -2272,7 +2988,7 @@ BUFFER may be a buffer or a buffer name. This function is meant for the user to run interactively. -Don't call it from programs!" +Don't call it from programs: use `insert-buffer-substring' instead!" (interactive (list (progn @@ -2282,16 +2998,10 @@ (other-buffer (current-buffer)) (window-buffer (next-window (selected-window)))) t)))) - (or (bufferp buffer) - (setq buffer (get-buffer buffer))) - (let (start end newmark) - (save-excursion - (save-excursion - (set-buffer buffer) - (setq start (point-min) end (point-max))) - (insert-buffer-substring buffer start end) - (setq newmark (point))) - (push-mark newmark)) + (push-mark + (save-excursion + (insert-buffer-substring (get-buffer buffer)) + (point))) nil) (defun append-to-buffer (buffer start end) @@ -2341,8 +3051,7 @@ START and END specify the portion of the current buffer to be copied." (interactive "BCopy to buffer: \nr") (let ((oldbuf (current-buffer))) - (save-excursion - (set-buffer (get-buffer-create buffer)) + (with-current-buffer (get-buffer-create buffer) (barf-if-buffer-read-only) (erase-buffer) (save-excursion @@ -2351,11 +3060,21 @@ (put 'mark-inactive 'error-conditions '(mark-inactive error)) (put 'mark-inactive 'error-message "The mark is not active now") +(defvar activate-mark-hook nil + "Hook run when the mark becomes active. +It is also run at the end of a command, if the mark is active and +it is possible that the region may have changed") + +(defvar deactivate-mark-hook nil + "Hook run when the mark becomes inactive.") + (defun mark (&optional force) - "Return this buffer's mark value as integer; error if mark inactive. -If optional argument FORCE is non-nil, access the mark value -even if the mark is not currently active, and return nil -if there is no mark at all. + "Return this buffer's mark value as integer, or nil if never set. + +In Transient Mark mode, this function signals an error if +the mark is not active. However, if `mark-even-if-inactive' is non-nil, +or the argument FORCE is non-nil, it disregards whether the mark +is active, and returns an integer or nil in the usual way. If you are using this in an editing command, you are most likely making a mistake; see the documentation of `set-mark'." @@ -2383,7 +3102,7 @@ mark position to be lost. Normally, when a new mark is set, the old one should go on the stack. -This is why most applications should use push-mark, not set-mark. +This is why most applications should use `push-mark', not `set-mark'. Novice Emacs Lisp programmers often try to use the mark for the wrong purposes. The mark saves a location for the user's convenience. @@ -2442,18 +3161,36 @@ (if (or arg (null mark) (/= mark (point))) (push-mark nil nomsg t) (setq mark-active t) + (run-hooks 'activate-mark-hook) (unless nomsg (message "Mark activated"))))) +(defcustom set-mark-command-repeat-pop nil + "*Non-nil means that repeating \\[set-mark-command] after popping will pop. +This means that if you type C-u \\[set-mark-command] \\[set-mark-command] +will pop twice." + :type 'boolean + :group 'editing) + (defun set-mark-command (arg) "Set mark at where point is, or jump to mark. -With no prefix argument, set mark, push old mark position on local mark -ring, and push mark on global mark ring. Immediately repeating the -command activates `transient-mark-mode' temporarily. - -With argument, jump to mark, and pop a new position for mark off the ring -\(does not affect global mark ring\). Repeating the command without -an argument jumps to the next position off the mark ring. +With no prefix argument, set mark, and push old mark position on local +mark ring; also push mark on global mark ring if last mark was set in +another buffer. Immediately repeating the command activates +`transient-mark-mode' temporarily. + +With argument, e.g. \\[universal-argument] \\[set-mark-command], \ +jump to mark, and pop a new position +for mark off the local mark ring \(this does not affect the global +mark ring\). Use \\[pop-global-mark] to jump to a mark off the global +mark ring \(see `pop-global-mark'\). + +Repeating the \\[set-mark-command] command without the prefix jumps to +the next position off the local (or global) mark ring. + +With a double \\[universal-argument] prefix argument, e.g. \\[universal-argument] \ +\\[universal-argument] \\[set-mark-command], unconditionally +set mark where point is. Novice Emacs Lisp programmers often try to use the mark for the wrong purposes. See the documentation of `set-mark' for more information." @@ -2461,15 +3198,21 @@ (if (eq transient-mark-mode 'lambda) (setq transient-mark-mode nil)) (cond + ((and (consp arg) (> (prefix-numeric-value arg) 4)) + (push-mark-command nil)) ((not (eq this-command 'set-mark-command)) (if arg (pop-to-mark-command) (push-mark-command t))) - ((eq last-command 'pop-to-mark-command) - (if (and (consp arg) (> (prefix-numeric-value arg) 4)) - (push-mark-command nil) - (setq this-command 'pop-to-mark-command) - (pop-to-mark-command))) + ((and set-mark-command-repeat-pop + (eq last-command 'pop-to-mark-command)) + (setq this-command 'pop-to-mark-command) + (pop-to-mark-command)) + ((and set-mark-command-repeat-pop + (eq last-command 'pop-global-mark) + (not arg)) + (setq this-command 'pop-global-mark) + (pop-global-mark)) (arg (setq this-command 'pop-to-mark-command) (pop-to-mark-command)) @@ -2491,13 +3234,11 @@ purposes. See the documentation of `set-mark' for more information. In Transient Mark mode, this does not activate the mark." - (if (null (mark t)) - nil + (unless (null (mark t)) (setq mark-ring (cons (copy-marker (mark-marker)) mark-ring)) - (if (> (length mark-ring) mark-ring-max) - (progn - (move-marker (car (nthcdr mark-ring-max mark-ring)) nil) - (setcdr (nthcdr (1- mark-ring-max) mark-ring) nil)))) + (when (> (length mark-ring) mark-ring-max) + (move-marker (car (nthcdr mark-ring-max mark-ring)) nil) + (setcdr (nthcdr (1- mark-ring-max) mark-ring) nil))) (set-marker (mark-marker) (or location (point)) (current-buffer)) ;; Now push the mark on the global mark ring. (if (and global-mark-ring @@ -2506,11 +3247,9 @@ ;; Don't push another one. nil (setq global-mark-ring (cons (copy-marker (mark-marker)) global-mark-ring)) - (if (> (length global-mark-ring) global-mark-ring-max) - (progn - (move-marker (car (nthcdr global-mark-ring-max global-mark-ring)) - nil) - (setcdr (nthcdr (1- global-mark-ring-max) global-mark-ring) nil)))) + (when (> (length global-mark-ring) global-mark-ring-max) + (move-marker (car (nthcdr global-mark-ring-max global-mark-ring)) nil) + (setcdr (nthcdr (1- global-mark-ring-max) global-mark-ring) nil))) (or nomsg executing-kbd-macro (> (minibuffer-depth) 0) (message "Mark set")) (if (or activate (not transient-mark-mode)) @@ -2520,14 +3259,13 @@ (defun pop-mark () "Pop off mark ring into the buffer's actual mark. Does not set point. Does nothing if mark ring is empty." - (if mark-ring - (progn - (setq mark-ring (nconc mark-ring (list (copy-marker (mark-marker))))) - (set-marker (mark-marker) (+ 0 (car mark-ring)) (current-buffer)) - (deactivate-mark) - (move-marker (car mark-ring) nil) - (if (null (mark t)) (ding)) - (setq mark-ring (cdr mark-ring))))) + (when mark-ring + (setq mark-ring (nconc mark-ring (list (copy-marker (mark-marker))))) + (set-marker (mark-marker) (+ 0 (car mark-ring)) (current-buffer)) + (move-marker (car mark-ring) nil) + (if (null (mark t)) (ding)) + (setq mark-ring (cdr mark-ring))) + (deactivate-mark)) (defalias 'exchange-dot-and-mark 'exchange-point-and-mark) (defun exchange-point-and-mark (&optional arg) @@ -2565,12 +3303,20 @@ Many commands change their behavior when Transient Mark mode is in effect and the mark is active, by acting on the region instead of their usual default part of the buffer's text. Examples of such commands include -\\[comment-dwim], \\[flush-lines], \\[ispell], \\[keep-lines], -\\[query-replace], \\[query-replace-regexp], and \\[undo]. Invoke -\\[apropos-documentation] and type \"transient\" or \"mark.*active\" at -the prompt, to see the documentation of commands which are sensitive to -the Transient Mark mode." - :global t :group 'editing-basics :require nil) +\\[comment-dwim], \\[flush-lines], \\[keep-lines], \ +\\[query-replace], \\[query-replace-regexp], \\[ispell], and \\[undo]. +Invoke \\[apropos-documentation] and type \"transient\" or +\"mark.*active\" at the prompt, to see the documentation of +commands which are sensitive to the Transient Mark mode." + :global t :group 'editing-basics) + +(defvar widen-automatically t + "Non-nil means it is ok for commands to call `widen' when they want to. +Some commands will do this in order to go to positions outside +the current accessible part of the buffer. + +If `widen-automatically' is nil, these commands will do something else +as a fallback, and won't change the buffer bounds.") (defun pop-global-mark () "Pop off global mark ring and jump to the top location." @@ -2588,7 +3334,9 @@ (set-buffer buffer) (or (and (>= position (point-min)) (<= position (point-max))) - (widen)) + (if widen-automatically + (widen) + (error "Global mark position is outside accessible part of buffer"))) (goto-char position) (switch-to-buffer buffer))) @@ -2598,8 +3346,9 @@ :version "21.1" :group 'editing-basics) -(defun next-line (&optional arg) +(defun next-line (&optional arg try-vscroll) "Move cursor vertically down ARG lines. +Interactively, vscroll tall lines if `auto-window-vscroll' is enabled. If there is no character in the target line exactly under the current column, the cursor is positioned after the character in that line which spans this column, or at the end of the line if it is not long enough. @@ -2618,24 +3367,25 @@ If you are thinking of using this in a Lisp program, consider using `forward-line' instead. It is usually easier to use and more reliable (no dependence on goal column, etc.)." - (interactive "p") - (unless arg (setq arg 1)) + (interactive "p\np") + (or arg (setq arg 1)) (if (and next-line-add-newlines (= arg 1)) (if (save-excursion (end-of-line) (eobp)) ;; When adding a newline, don't expand an abbrev. (let ((abbrev-mode nil)) (end-of-line) - (insert "\n")) - (line-move arg)) + (insert (if use-hard-newlines hard-newline "\n"))) + (line-move arg nil nil try-vscroll)) (if (interactive-p) (condition-case nil - (line-move arg) + (line-move arg nil nil try-vscroll) ((beginning-of-buffer end-of-buffer) (ding))) - (line-move arg))) + (line-move arg nil nil try-vscroll))) nil) -(defun previous-line (&optional arg) +(defun previous-line (&optional arg try-vscroll) "Move cursor vertically up ARG lines. +Interactively, vscroll tall lines if `auto-window-vscroll' is enabled. If there is no character in the target line exactly over the current column, the cursor is positioned after the character in that line which spans this column, or at the end of the line if it is not long enough. @@ -2650,13 +3400,13 @@ If you are thinking of using this in a Lisp program, consider using `forward-line' with a negative argument instead. It is usually easier to use and more reliable (no dependence on goal column, etc.)." - (interactive "p") - (unless arg (setq arg 1)) + (interactive "p\np") + (or arg (setq arg 1)) (if (interactive-p) (condition-case nil - (line-move (- arg)) + (line-move (- arg) nil nil try-vscroll) ((beginning-of-buffer end-of-buffer) (ding))) - (line-move (- arg))) + (line-move (- arg) nil nil try-vscroll)) nil) (defcustom track-eol nil @@ -2679,13 +3429,13 @@ at the start of current run of vertical motion commands. When the `track-eol' feature is doing its job, the value is 9999.") -(defcustom line-move-ignore-invisible nil +(defcustom line-move-ignore-invisible t "*Non-nil means \\[next-line] and \\[previous-line] ignore invisible lines. Outline mode sets this." :type 'boolean :group 'editing-basics) -(defun line-move-invisible (pos) +(defun line-move-invisible-p (pos) "Return non-nil if the character after POS is currently invisible." (let ((prop (get-char-property pos 'invisible))) @@ -2694,14 +3444,55 @@ (or (memq prop buffer-invisibility-spec) (assq prop buffer-invisibility-spec))))) +;; This is like line-move-1 except that it also performs +;; vertical scrolling of tall images if appropriate. +;; That is not really a clean thing to do, since it mixes +;; scrolling with cursor motion. But so far we don't have +;; a cleaner solution to the problem of making C-n do something +;; useful given a tall image. +(defun line-move (arg &optional noerror to-end try-vscroll) + (if (and auto-window-vscroll try-vscroll + ;; But don't vscroll in a keyboard macro. + (not defining-kbd-macro) + (not executing-kbd-macro)) + (let ((forward (> arg 0)) + (part (nth 2 (pos-visible-in-window-p (point) nil t)))) + (if (and (consp part) + (> (if forward (cdr part) (car part)) 0)) + (set-window-vscroll nil + (if forward + (+ (window-vscroll nil t) + (min (cdr part) + (* (frame-char-height) arg))) + (max 0 + (- (window-vscroll nil t) + (min (car part) + (* (frame-char-height) (- arg)))))) + t) + (set-window-vscroll nil 0) + (when (line-move-1 arg noerror to-end) + (when (not forward) + ;; Update display before calling pos-visible-in-window-p, + ;; because it depends on window-start being up-to-date. + (sit-for 0) + ;; If the current line is partly hidden at the bottom, + ;; scroll it partially up so as to unhide the bottom. + (if (and (setq part (nth 2 (pos-visible-in-window-p + (line-beginning-position) nil t))) + (> (cdr part) 0)) + (set-window-vscroll nil (cdr part) t))) + t))) + (line-move-1 arg noerror to-end))) + ;; This is the guts of next-line and previous-line. ;; Arg says how many lines to move. -(defun line-move (arg) +;; The value is t if we can move the specified number of lines. +(defun line-move-1 (arg &optional noerror to-end) ;; Don't run any point-motion hooks, and disregard intangibility, ;; for intermediate positions. (let ((inhibit-point-motion-hooks t) (opoint (point)) - new line-end line-beg) + (forward (> arg 0))) (unwind-protect (progn (if (not (memq last-command '(next-line previous-line))) @@ -2712,6 +3503,7 @@ (or (not (bolp)) (eq last-command 'end-of-line))) 9999 (current-column)))) + (if (and (not (integerp selective-display)) (not line-move-ignore-invisible)) ;; Use just newline characters. @@ -2727,42 +3519,80 @@ (and (zerop (forward-line arg)) (bolp) (setq arg 0))) - (signal (if (< arg 0) - 'beginning-of-buffer - 'end-of-buffer) - nil)) + (unless noerror + (signal (if (< arg 0) + 'beginning-of-buffer + 'end-of-buffer) + nil))) ;; Move by arg lines, but ignore invisible ones. - (while (> arg 0) - ;; If the following character is currently invisible, - ;; skip all characters with that same `invisible' property value. - (while (and (not (eobp)) (line-move-invisible (point))) - (goto-char (next-char-property-change (point)))) - ;; Now move a line. - (end-of-line) - (and (zerop (vertical-motion 1)) - (signal 'end-of-buffer nil)) - (setq arg (1- arg))) - (while (< arg 0) - (beginning-of-line) - (and (zerop (vertical-motion -1)) - (signal 'beginning-of-buffer nil)) - (setq arg (1+ arg)) - (while (and (not (bobp)) (line-move-invisible (1- (point)))) - (goto-char (previous-char-property-change (point))))))) + (let (done) + (while (and (> arg 0) (not done)) + ;; If the following character is currently invisible, + ;; skip all characters with that same `invisible' property value. + (while (and (not (eobp)) (line-move-invisible-p (point))) + (goto-char (next-char-property-change (point)))) + ;; Now move a line. + (end-of-line) + ;; If there's no invisibility here, move over the newline. + (cond + ((eobp) + (if (not noerror) + (signal 'end-of-buffer nil) + (setq done t))) + ((and (> arg 1) ;; Use vertical-motion for last move + (not (integerp selective-display)) + (not (line-move-invisible-p (point)))) + ;; We avoid vertical-motion when possible + ;; because that has to fontify. + (forward-line 1)) + ;; Otherwise move a more sophisticated way. + ((zerop (vertical-motion 1)) + (if (not noerror) + (signal 'end-of-buffer nil) + (setq done t)))) + (unless done + (setq arg (1- arg)))) + ;; The logic of this is the same as the loop above, + ;; it just goes in the other direction. + (while (and (< arg 0) (not done)) + (beginning-of-line) + (cond + ((bobp) + (if (not noerror) + (signal 'beginning-of-buffer nil) + (setq done t))) + ((and (< arg -1) ;; Use vertical-motion for last move + (not (integerp selective-display)) + (not (line-move-invisible-p (1- (point))))) + (forward-line -1)) + ((zerop (vertical-motion -1)) + (if (not noerror) + (signal 'beginning-of-buffer nil) + (setq done t)))) + (unless done + (setq arg (1+ arg)) + (while (and ;; Don't move over previous invis lines + ;; if our target is the middle of this line. + (or (zerop (or goal-column temporary-goal-column)) + (< arg 0)) + (not (bobp)) (line-move-invisible-p (1- (point)))) + (goto-char (previous-char-property-change (point)))))))) + ;; This is the value the function returns. + (= arg 0)) (cond ((> arg 0) ;; If we did not move down as far as desired, ;; at least go to end of line. (end-of-line)) ((< arg 0) - ;; If we did not move down as far as desired, - ;; at least go to end of line. + ;; If we did not move up as far as desired, + ;; at least go to beginning of line. (beginning-of-line)) (t - (line-move-finish (or goal-column temporary-goal-column) opoint))))) - nil) - -(defun line-move-finish (column opoint) + (line-move-finish (or goal-column temporary-goal-column) + opoint forward)))))) + +(defun line-move-finish (column opoint forward) (let ((repeat t)) (while repeat ;; Set REPEAT to t to repeat the whole thing. @@ -2772,10 +3602,14 @@ (line-beg (save-excursion (beginning-of-line) (point))) (line-end ;; Compute the end of the line - ;; ignoring effectively intangible newlines. - (let ((inhibit-point-motion-hooks nil) - (inhibit-field-text-motion t)) - (save-excursion (end-of-line) (point))))) + ;; ignoring effectively invisible newlines. + (save-excursion + ;; Like end-of-line but ignores fields. + (skip-chars-forward "^\n") + (while (and (not (eobp)) (line-move-invisible-p (point))) + (goto-char (next-char-property-change (point))) + (skip-chars-forward "^\n")) + (point)))) ;; Move to the desired column. (line-move-to-column column) @@ -2797,7 +3631,13 @@ ;; try the previous allowable position. ;; See if it is ok. (backward-char) - (if (<= (point) line-end) + (if (if forward + ;; If going forward, don't accept the previous + ;; allowable position if it is before the target line. + (< line-beg (point)) + ;; If going backward, don't accept the previous + ;; allowable position if it is still after the target line. + (<= (point) line-end)) (setq new (point)) ;; As a last resort, use the end of the line. (setq new line-end)))) @@ -2826,13 +3666,13 @@ (move-to-column col)) (when (and line-move-ignore-invisible - (not (bolp)) (line-move-invisible (1- (point)))) + (not (bolp)) (line-move-invisible-p (1- (point)))) (let ((normal-location (point)) (normal-column (current-column))) ;; If the following character is currently invisible, ;; skip all characters with that same `invisible' property value. (while (and (not (eobp)) - (line-move-invisible (point))) + (line-move-invisible-p (point))) (goto-char (next-char-property-change (point)))) ;; Have we advanced to a larger column position? (if (> (current-column) normal-column) @@ -2845,9 +3685,62 @@ ;; but with a more reasonable buffer position. (goto-char normal-location) (let ((line-beg (save-excursion (beginning-of-line) (point)))) - (while (and (not (bolp)) (line-move-invisible (1- (point)))) + (while (and (not (bolp)) (line-move-invisible-p (1- (point)))) (goto-char (previous-char-property-change (point) line-beg)))))))) +(defun move-end-of-line (arg) + "Move point to end of current line as displayed. +\(If there's an image in the line, this disregards newlines +which are part of the text that the image rests on.) + +With argument ARG not nil or 1, move forward ARG - 1 lines first. +If point reaches the beginning or end of buffer, it stops there. +To ignore intangibility, bind `inhibit-point-motion-hooks' to t." + (interactive "p") + (or arg (setq arg 1)) + (let (done) + (while (not done) + (let ((newpos + (save-excursion + (let ((goal-column 0)) + (and (line-move arg t) + (not (bobp)) + (progn + (while (and (not (bobp)) (line-move-invisible-p (1- (point)))) + (goto-char (previous-char-property-change (point)))) + (backward-char 1))) + (point))))) + (goto-char newpos) + (if (and (> (point) newpos) + (eq (preceding-char) ?\n)) + (backward-char 1) + (if (and (> (point) newpos) (not (eobp)) + (not (eq (following-char) ?\n))) + ;; If we skipped something intangible + ;; and now we're not really at eol, + ;; keep going. + (setq arg 1) + (setq done t))))))) + +(defun move-beginning-of-line (arg) + "Move point to beginning of current line as displayed. +\(If there's an image in the line, this disregards newlines +which are part of the text that the image rests on.) + +With argument ARG not nil or 1, move forward ARG - 1 lines first. +If point reaches the beginning or end of buffer, it stops there. +To ignore intangibility, bind `inhibit-point-motion-hooks' to t." + (interactive "p") + (or arg (setq arg 1)) + (if (/= arg 1) + (line-move (1- arg) t)) + (beginning-of-line 1) + (let ((orig (point))) + (vertical-motion 0) + (if (/= orig (point)) + (goto-char (constrain-to-field (point) orig (/= arg 1) t nil))))) + + ;;; Many people have said they rarely use this feature, and often type ;;; it by accident. Maybe it shouldn't even be on a key. (put 'set-goal-column 'disabled t) @@ -2865,9 +3758,18 @@ (setq goal-column nil) (message "No goal column")) (setq goal-column (current-column)) - (message (substitute-command-keys - "Goal column %d (use \\[set-goal-column] with an arg to unset it)") - goal-column)) + ;; The older method below can be erroneous if `set-goal-column' is bound + ;; to a sequence containing % + ;;(message (substitute-command-keys + ;;"Goal column %d (use \\[set-goal-column] with an arg to unset it)") + ;;goal-column) + (message "%s" + (concat + (format "Goal column %d " goal-column) + (substitute-command-keys + "(use \\[set-goal-column] with an arg to unset it)"))) + + ) nil) @@ -2881,7 +3783,6 @@ (if (eq lines '-) nil (if (null lines) '- (- (prefix-numeric-value lines)))))) -(define-key esc-map [?\C-\S-v] 'scroll-other-window-down) (defun beginning-of-buffer-other-window (arg) "Move point to the beginning of the buffer in the other window. @@ -2896,7 +3797,8 @@ (progn (select-window window) ;; Set point and mark in that window's buffer. - (beginning-of-buffer arg) + (with-no-warnings + (beginning-of-buffer arg)) ;; Set point accordingly. (recenter '(t))) (select-window orig-window)))) @@ -2912,7 +3814,8 @@ (unwind-protect (progn (select-window window) - (end-of-buffer arg) + (with-no-warnings + (end-of-buffer arg)) (recenter '(t))) (select-window orig-window)))) @@ -3023,24 +3926,33 @@ (if (> (cdr pos1) (car pos2)) (error "Don't have two things to transpose")) (atomic-change-group (let (word2) + ;; FIXME: We first delete the two pieces of text, so markers that + ;; used to point to after the text end up pointing to before it :-( (setq word2 (delete-and-extract-region (car pos2) (cdr pos2))) (goto-char (car pos2)) (insert (delete-and-extract-region (car pos1) (cdr pos1))) (goto-char (car pos1)) (insert word2)))) -(defun backward-word (arg) +(defun backward-word (&optional arg) "Move backward until encountering the beginning of a word. With argument, do this that many times." (interactive "p") - (forward-word (- arg))) - -(defun mark-word (arg) - "Set mark arg words away from point. -If this command is repeated, it marks the next ARG words after the ones -already marked." - (interactive "p") - (cond ((and (eq last-command this-command) (mark t)) + (forward-word (- (or arg 1)))) + +(defun mark-word (&optional arg allow-extend) + "Set mark ARG words away from point. +The place mark goes is the same place \\[forward-word] would +move to with the same argument. +Interactively, if this command is repeated +or (in Transient Mark mode) if the mark is active, +it marks the next ARG words after the ones already marked." + (interactive "P\np") + (cond ((and allow-extend + (or (and (eq last-command this-command) (mark t)) + (and transient-mark-mode mark-active))) + (setq arg (if arg (prefix-numeric-value arg) + (if (< (mark) (point)) -1 1))) (set-mark (save-excursion (goto-char (mark)) @@ -3049,7 +3961,7 @@ (t (push-mark (save-excursion - (forward-word arg) + (forward-word (prefix-numeric-value arg)) (point)) nil t)))) @@ -3065,37 +3977,43 @@ (interactive "p") (kill-word (- arg))) -(defun current-word (&optional strict) - "Return the word point is on (or a nearby word) as a string. +(defun current-word (&optional strict really-word) + "Return the symbol or word that point is on (or a nearby one) as a string. +The return value includes no text properties. If optional arg STRICT is non-nil, return nil unless point is within -or adjacent to a word." +or adjacent to a symbol or word. In all cases the value can be nil +if there is no word nearby. +The function, belying its name, normally finds a symbol. +If optional arg REALLY-WORD is non-nil, it finds just a word." (save-excursion - (let ((oldpoint (point)) (start (point)) (end (point))) - (skip-syntax-backward "w_") (setq start (point)) + (let* ((oldpoint (point)) (start (point)) (end (point)) + (syntaxes (if really-word "w" "w_")) + (not-syntaxes (concat "^" syntaxes))) + (skip-syntax-backward syntaxes) (setq start (point)) (goto-char oldpoint) - (skip-syntax-forward "w_") (setq end (point)) - (if (and (eq start oldpoint) (eq end oldpoint)) - ;; Point is neither within nor adjacent to a word. - (and (not strict) - (progn - ;; Look for preceding word in same line. - (skip-syntax-backward "^w_" - (save-excursion (beginning-of-line) - (point))) - (if (bolp) - ;; No preceding word in same line. - ;; Look for following word in same line. - (progn - (skip-syntax-forward "^w_" - (save-excursion (end-of-line) - (point))) - (setq start (point)) - (skip-syntax-forward "w_") - (setq end (point))) - (setq end (point)) - (skip-syntax-backward "w_") - (setq start (point))) - (buffer-substring-no-properties start end))) + (skip-syntax-forward syntaxes) (setq end (point)) + (when (and (eq start oldpoint) (eq end oldpoint) + ;; Point is neither within nor adjacent to a word. + (not strict)) + ;; Look for preceding word in same line. + (skip-syntax-backward not-syntaxes + (save-excursion (beginning-of-line) + (point))) + (if (bolp) + ;; No preceding word in same line. + ;; Look for following word in same line. + (progn + (skip-syntax-forward not-syntaxes + (save-excursion (end-of-line) + (point))) + (setq start (point)) + (skip-syntax-forward syntaxes) + (setq end (point))) + (setq end (point)) + (skip-syntax-backward syntaxes) + (setq start (point)))) + ;; If we found something nonempty, return it as a string. + (unless (= start end) (buffer-substring-no-properties start end))))) (defcustom fill-prefix nil @@ -3116,9 +4034,7 @@ This function is only called during auto-filling of a comment section. The function should take a single optional argument, which is a flag -indicating whether it should use soft newlines. - -Setting this variable automatically makes it local to the current buffer.") +indicating whether it should use soft newlines.") ;; This function is used as the auto-fill-function of a buffer ;; when Auto-Fill mode is enabled. @@ -3126,15 +4042,14 @@ ;; (Actually some major modes use a different auto-fill function, ;; but this one is the default one.) (defun do-auto-fill () - (let (fc justify bol give-up + (let (fc justify give-up (fill-prefix fill-prefix)) (if (or (not (setq justify (current-justification))) (null (setq fc (current-fill-column))) (and (eq justify 'left) (<= (current-column) fc)) - (save-excursion (beginning-of-line) - (setq bol (point)) - (and auto-fill-inhibit-regexp + (and auto-fill-inhibit-regexp + (save-excursion (beginning-of-line) (looking-at auto-fill-inhibit-regexp)))) nil ;; Auto-filling not required (if (memq justify '(full center right)) @@ -3157,16 +4072,15 @@ ;; Determine where to split the line. (let* (after-prefix (fill-point - (let ((opoint (point))) - (save-excursion - (beginning-of-line) - (setq after-prefix (point)) - (and fill-prefix - (looking-at (regexp-quote fill-prefix)) - (setq after-prefix (match-end 0))) - (move-to-column (1+ fc)) - (fill-move-to-break-point after-prefix) - (point))))) + (save-excursion + (beginning-of-line) + (setq after-prefix (point)) + (and fill-prefix + (looking-at (regexp-quote fill-prefix)) + (setq after-prefix (match-end 0))) + (move-to-column (1+ fc)) + (fill-move-to-break-point after-prefix) + (point)))) ;; See whether the place we found is any good. (if (save-excursion @@ -3217,6 +4131,7 @@ "The function to use for `auto-fill-function' if Auto Fill mode is turned on. Some major modes set this.") +(put 'auto-fill-function :minor-mode-function 'auto-fill-mode) ;; FIXME: turn into a proper minor mode. ;; Add a global minor mode version of it. (defun auto-fill-mode (&optional arg) @@ -3340,7 +4255,7 @@ typing characters do. Note that binary overwrite mode is not its own minor mode; it is a -specialization of overwrite-mode, entered by setting the +specialization of overwrite mode, entered by setting the `overwrite-mode' variable to `overwrite-mode-binary'." (interactive "P") (setq overwrite-mode @@ -3359,14 +4274,21 @@ Line numbers do not appear for very large buffers and buffers with very long lines; see variables `line-number-display-limit' and `line-number-display-limit-width'." - :init-value t :global t :group 'editing-basics :require nil) + :init-value t :global t :group 'editing-basics) (define-minor-mode column-number-mode "Toggle Column Number mode. With arg, turn Column Number mode on iff arg is positive. When Column Number mode is enabled, the column number appears in the mode line." - :global t :group 'editing-basics :require nil) + :global t :group 'editing-basics) + +(define-minor-mode size-indication-mode + "Toggle Size Indication mode. +With arg, turn Size Indication mode on iff arg is positive. When +Size Indication mode is enabled, the size of the accessible part +of the buffer appears in the mode line." + :global t :group 'editing-basics) (defgroup paren-blinking nil "Blinking matching of parens and expressions." @@ -3381,13 +4303,18 @@ (defcustom blink-matching-paren-on-screen t "*Non-nil means show matching open-paren when it is on screen. If nil, means don't show it (but the open-paren can still be shown -when it is off screen)." +when it is off screen). + +This variable has no effect if `blink-matching-paren' is nil. +\(In that case, the open-paren is never shown.) +It is also ignored if `show-paren-mode' is enabled." :type 'boolean :group 'paren-blinking) (defcustom blink-matching-paren-distance (* 25 1024) - "*If non-nil, is maximum distance to search for matching open-paren." - :type 'integer + "*If non-nil, maximum distance to search backwards for matching open-paren. +If nil, search stops at the beginning of the accessible portion of the buffer." + :type '(choice (const nil) integer) :group 'paren-blinking) (defcustom blink-matching-delay 1 @@ -3403,82 +4330,93 @@ (defun blink-matching-open () "Move cursor momentarily to the beginning of the sexp before point." (interactive) - (and (> (point) (1+ (point-min))) - blink-matching-paren - ;; Verify an even number of quoting characters precede the close. - (= 1 (logand 1 (- (point) - (save-excursion - (forward-char -1) - (skip-syntax-backward "/\\") - (point))))) - (let* ((oldpos (point)) - (blinkpos) - (mismatch)) - (save-excursion - (save-restriction - (if blink-matching-paren-distance - (narrow-to-region (max (point-min) - (- (point) blink-matching-paren-distance)) - oldpos)) - (condition-case () - (let ((parse-sexp-ignore-comments - (and parse-sexp-ignore-comments - (not blink-matching-paren-dont-ignore-comments)))) - (setq blinkpos (scan-sexps oldpos -1))) - (error nil))) - (and blinkpos - (/= (char-syntax (char-after blinkpos)) - ?\$) - (setq mismatch - (or (null (matching-paren (char-after blinkpos))) - (/= (char-after (1- oldpos)) - (matching-paren (char-after blinkpos)))))) - (if mismatch (setq blinkpos nil)) - (if blinkpos - ;; Don't log messages about paren matching. - (let (message-log-max) - (goto-char blinkpos) - (if (pos-visible-in-window-p) - (and blink-matching-paren-on-screen - (sit-for blink-matching-delay)) - (goto-char blinkpos) - (message - "Matches %s" - ;; Show what precedes the open in its line, if anything. - (if (save-excursion - (skip-chars-backward " \t") - (not (bolp))) - (buffer-substring (progn (beginning-of-line) (point)) - (1+ blinkpos)) - ;; Show what follows the open in its line, if anything. - (if (save-excursion - (forward-char 1) - (skip-chars-forward " \t") - (not (eolp))) - (buffer-substring blinkpos - (progn (end-of-line) (point))) - ;; Otherwise show the previous nonblank line, - ;; if there is one. - (if (save-excursion - (skip-chars-backward "\n \t") - (not (bobp))) - (concat - (buffer-substring (progn + (when (and (> (point) (point-min)) + blink-matching-paren + ;; Verify an even number of quoting characters precede the close. + (= 1 (logand 1 (- (point) + (save-excursion + (forward-char -1) + (skip-syntax-backward "/\\") + (point)))))) + (let* ((oldpos (point)) + blinkpos + message-log-max ; Don't log messages about paren matching. + matching-paren + open-paren-line-string) + (save-excursion + (save-restriction + (if blink-matching-paren-distance + (narrow-to-region (max (point-min) + (- (point) blink-matching-paren-distance)) + oldpos)) + (condition-case () + (let ((parse-sexp-ignore-comments + (and parse-sexp-ignore-comments + (not blink-matching-paren-dont-ignore-comments)))) + (setq blinkpos (scan-sexps oldpos -1))) + (error nil))) + (and blinkpos + ;; Not syntax '$'. + (not (eq (syntax-class (syntax-after blinkpos)) 8)) + (setq matching-paren + (let ((syntax (syntax-after blinkpos))) + (and (consp syntax) + (eq (syntax-class syntax) 4) + (cdr syntax))))) + (cond + ((not (or (eq matching-paren (char-before oldpos)) + ;; The cdr might hold a new paren-class info rather than + ;; a matching-char info, in which case the two CDRs + ;; should match. + (eq matching-paren (cdr (syntax-after (1- oldpos)))))) + (message "Mismatched parentheses")) + ((not blinkpos) + (if (not blink-matching-paren-distance) + (message "Unmatched parenthesis"))) + ((pos-visible-in-window-p blinkpos) + ;; Matching open within window, temporarily move to blinkpos but only + ;; if `blink-matching-paren-on-screen' is non-nil. + (and blink-matching-paren-on-screen + (not show-paren-mode) + (save-excursion + (goto-char blinkpos) + (sit-for blink-matching-delay)))) + (t + (save-excursion + (goto-char blinkpos) + (setq open-paren-line-string + ;; Show what precedes the open in its line, if anything. + (if (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + (buffer-substring (line-beginning-position) + (1+ blinkpos)) + ;; Show what follows the open in its line, if anything. + (if (save-excursion + (forward-char 1) + (skip-chars-forward " \t") + (not (eolp))) + (buffer-substring blinkpos + (line-end-position)) + ;; Otherwise show the previous nonblank line, + ;; if there is one. + (if (save-excursion + (skip-chars-backward "\n \t") + (not (bobp))) + (concat + (buffer-substring (progn (skip-chars-backward "\n \t") - (beginning-of-line) - (point)) - (progn (end-of-line) - (skip-chars-backward " \t") - (point))) - ;; Replace the newline and other whitespace with `...'. - "..." - (buffer-substring blinkpos (1+ blinkpos))) - ;; There is nothing to show except the char itself. - (buffer-substring blinkpos (1+ blinkpos)))))))) - (cond (mismatch - (message "Mismatched parentheses")) - ((not blink-matching-paren-distance) - (message "Unmatched parenthesis")))))))) + (line-beginning-position)) + (progn (end-of-line) + (skip-chars-backward " \t") + (point))) + ;; Replace the newline and other whitespace with `...'. + "..." + (buffer-substring blinkpos (1+ blinkpos))) + ;; There is nothing to show except the char itself. + (buffer-substring blinkpos (1+ blinkpos))))))) + (message "Matches %s" + (substring-no-properties open-paren-line-string)))))))) ;Turned off because it makes dbx bomb out. (setq blink-paren-function 'blink-matching-open) @@ -3492,11 +4430,11 @@ At top-level, as an editor command, this simply beeps." (interactive) (deactivate-mark) + (if (fboundp 'kmacro-keyboard-quit) + (kmacro-keyboard-quit)) (setq defining-kbd-macro nil) (signal 'quit nil)) -(define-key global-map "\C-g" 'keyboard-quit) - (defvar buffer-quit-function nil "Function to call to \"quit\" the current buffer, or nil if none. \\[keyboard-escape-quit] calls this function when its more local actions @@ -3515,8 +4453,7 @@ (abort-recursive-edit)) (current-prefix-arg nil) - ((and transient-mark-mode - mark-active) + ((and transient-mark-mode mark-active) (deactivate-mark)) ((> (recursion-depth) 0) (exit-recursive-edit)) @@ -3540,8 +4477,7 @@ (push 'sound sound) (play-sound sound))) -(define-key global-map "\e\e\e" 'keyboard-escape-quit) - + (defcustom read-mail-command 'rmail "*Your preference for a mail reading package. This is used by some keybindings which support reading mail. @@ -3611,9 +4547,9 @@ (same-window-buffer-names nil) (same-window-regexps nil)) (funcall switch-function "*mail*"))) - (let ((cc (cdr (assoc-ignore-case "cc" other-headers))) - (in-reply-to (cdr (assoc-ignore-case "in-reply-to" other-headers))) - (body (cdr (assoc-ignore-case "body" other-headers)))) + (let ((cc (cdr (assoc-string "cc" other-headers t))) + (in-reply-to (cdr (assoc-string "in-reply-to" other-headers t))) + (body (cdr (assoc-string "body" other-headers t)))) (or (mail continue to subject in-reply-to cc yank-action send-actions) continue (error "Message aborted")) @@ -3623,17 +4559,14 @@ (unless (member-ignore-case (car (car other-headers)) '("in-reply-to" "cc" "body")) (insert (car (car other-headers)) ": " - (cdr (car other-headers)) "\n")) + (cdr (car other-headers)) + (if use-hard-newlines hard-newline "\n"))) (setq other-headers (cdr other-headers))) (when body (forward-line 1) (insert body)) t))) -(define-mail-user-agent 'mh-e-user-agent - 'mh-smail-batch 'mh-send-letter 'mh-fully-kill-draft - 'mh-before-send-letter-hook) - (defun compose-mail (&optional to subject other-headers continue switch-function yank-action send-actions) "Start composing a mail message to send. @@ -3683,14 +4616,15 @@ (list nil nil nil current-prefix-arg)) (compose-mail to subject other-headers continue 'switch-to-buffer-other-frame yank-action send-actions)) - + (defvar set-variable-value-history nil "History of values entered with `set-variable'.") -(defun set-variable (var val &optional make-local) +(defun set-variable (variable value &optional make-local) "Set VARIABLE to VALUE. VALUE is a Lisp object. -When using this interactively, enter a Lisp object for VALUE. -If you want VALUE to be a string, you must surround it with doublequotes. +VARIABLE should be a user option variable name, a Lisp variable +meant to be customized by users. You should enter VALUE in Lisp syntax, +so if you want VALUE to be a string, you must surround it with doublequotes. VALUE is used literally, not evaluated. If VARIABLE has a `variable-interactive' property, that is used as if @@ -3702,51 +4636,59 @@ With a prefix argument, set VARIABLE to VALUE buffer-locally." (interactive (let* ((default-var (variable-at-point)) - (var (if (symbolp default-var) - (read-variable (format "Set variable (default %s): " default-var) - default-var) - (read-variable "Set variable: "))) - (minibuffer-help-form '(describe-variable var)) - (prop (get var 'variable-interactive)) - (prompt (format "Set %s%s to value: " var - (cond ((local-variable-p var) - " (buffer-local)") - ((or current-prefix-arg - (local-variable-if-set-p var)) - " buffer-locally") - (t " globally")))) - (val (if prop - ;; Use VAR's `variable-interactive' property - ;; as an interactive spec for prompting. - (call-interactively `(lambda (arg) - (interactive ,prop) - arg)) - (read - (read-string prompt nil - 'set-variable-value-history))))) - (list var val current-prefix-arg))) - - (and (custom-variable-p var) - (not (get var 'custom-type)) - (custom-load-symbol var)) - (let ((type (get var 'custom-type))) + (var (if (user-variable-p default-var) + (read-variable (format "Set variable (default %s): " default-var) + default-var) + (read-variable "Set variable: "))) + (minibuffer-help-form '(describe-variable var)) + (prop (get var 'variable-interactive)) + (obsolete (car (get var 'byte-obsolete-variable))) + (prompt (format "Set %s %s to value: " var + (cond ((local-variable-p var) + "(buffer-local)") + ((or current-prefix-arg + (local-variable-if-set-p var)) + "buffer-locally") + (t "globally")))) + (val (progn + (when obsolete + (message (concat "`%S' is obsolete; " + (if (symbolp obsolete) "use `%S' instead" "%s")) + var obsolete) + (sit-for 3)) + (if prop + ;; Use VAR's `variable-interactive' property + ;; as an interactive spec for prompting. + (call-interactively `(lambda (arg) + (interactive ,prop) + arg)) + (read + (read-string prompt nil + 'set-variable-value-history + (format "%S" (symbol-value var)))))))) + (list var val current-prefix-arg))) + + (and (custom-variable-p variable) + (not (get variable 'custom-type)) + (custom-load-symbol variable)) + (let ((type (get variable 'custom-type))) (when type ;; Match with custom type. (require 'cus-edit) (setq type (widget-convert type)) - (unless (widget-apply type :match val) + (unless (widget-apply type :match value) (error "Value `%S' does not match type %S of %S" - val (car type) var)))) + value (car type) variable)))) (if make-local - (make-local-variable var)) - - (set var val) + (make-local-variable variable)) + + (set variable value) ;; Force a thorough redisplay for the case that the variable ;; has an effect on the display, like `tab-width' has. (force-mode-line-update)) - + ;; Define the major mode for lists of completions. (defvar completion-list-mode-map nil @@ -3754,6 +4696,7 @@ (or completion-list-mode-map (let ((map (make-sparse-keymap))) (define-key map [mouse-2] 'mouse-choose-completion) + (define-key map [follow-link] 'mouse-face) (define-key map [down-mouse-2] nil) (define-key map "\C-m" 'choose-completion) (define-key map "\e\e\e" 'delete-completion-window) @@ -3839,7 +4782,7 @@ (error "No completion here")) (setq beg (previous-single-property-change beg 'mouse-face)) (setq end (or (next-single-property-change end 'mouse-face) (point-max))) - (setq completion (buffer-substring beg end)) + (setq completion (buffer-substring-no-properties beg end)) (let ((owindow (selected-window))) (if (and (one-window-p t 'selected-frame) (window-dedicated-p (selected-window))) @@ -3898,9 +4841,8 @@ ;; unless it is reading a file name and CHOICE is a directory, ;; or completion-no-auto-exit is non-nil. - (let ((buffer (or buffer completion-reference-buffer)) - (mini-p (string-match "\\` \\*Minibuf-[0-9]+\\*\\'" - (buffer-name buffer)))) + (let* ((buffer (or buffer completion-reference-buffer)) + (mini-p (minibufferp buffer))) ;; If BUFFER is a minibuffer, barf unless it's the currently ;; active minibuffer. (if (and mini-p @@ -3908,11 +4850,12 @@ (not (equal buffer (window-buffer (active-minibuffer-window)))))) (error "Minibuffer is not active for completion") + ;; Set buffer so buffer-local choose-completion-string-functions works. + (set-buffer buffer) (unless (run-hook-with-args-until-success 'choose-completion-string-functions choice buffer mini-p base-size) ;; Insert the completion into the buffer where it was requested. - (set-buffer buffer) (if base-size (delete-region (+ base-size (if mini-p (minibuffer-prompt-end) @@ -3952,7 +4895,7 @@ (setq major-mode 'completion-list-mode) (make-local-variable 'completion-base-size) (setq completion-base-size nil) - (run-hooks 'completion-list-mode-hook)) + (run-mode-hooks 'completion-list-mode-hook)) (defun completion-list-mode-finish () "Finish setup of the completions buffer. @@ -3966,40 +4909,100 @@ "Normal hook run at the end of setting up a completion list buffer. When this hook is run, the current buffer is the one in which the command to display the completion list buffer was run. -The completion list buffer is available as the value of `standard-output'.") +The completion list buffer is available as the value of `standard-output'. +The common prefix substring for completion may be available as the +value of `completion-common-substring'. See also `display-completion-list'.") + + +;; Variables and faces used in `completion-setup-function'. + +(defface completions-first-difference + '((t (:inherit bold))) + "Face put on the first uncommon character in completions in *Completions* buffer." + :group 'completion) + +(defface completions-common-part + '((t (:inherit default))) + "Face put on the common prefix substring in completions in *Completions* buffer. +The idea of `completions-common-part' is that you can use it to +make the common parts less visible than normal, so that the rest +of the differing parts is, by contrast, slightly highlighted." + :group 'completion) + +;; This is for packages that need to bind it to a non-default regexp +;; in order to make the first-differing character highlight work +;; to their liking +(defvar completion-root-regexp "^/" + "Regexp to use in `completion-setup-function' to find the root directory.") + +(defvar completion-common-substring nil + "Common prefix substring to use in `completion-setup-function' to put faces. +The value is set by `display-completion-list' during running `completion-setup-hook'. + +To put faces `completions-first-difference' and `completions-common-part' +in the `*Completions*' buffer, the common prefix substring in completions +is needed as a hint. (The minibuffer is a special case. The content +of the minibuffer before point is always the common substring.)") ;; This function goes in completion-setup-hook, so that it is called ;; after the text of the completion list buffer is written. - (defun completion-setup-function () - (save-excursion - (let ((mainbuf (current-buffer)) - (mbuf-contents (minibuffer-contents))) - ;; When reading a file name in the minibuffer, - ;; set default-directory in the minibuffer - ;; so it will get copied into the completion list buffer. - (if minibuffer-completing-file-name - (with-current-buffer mainbuf - (setq default-directory (file-name-directory mbuf-contents)))) - (set-buffer standard-output) + (let* ((mainbuf (current-buffer)) + (mbuf-contents (minibuffer-completion-contents)) + common-string-length) + ;; When reading a file name in the minibuffer, + ;; set default-directory in the minibuffer + ;; so it will get copied into the completion list buffer. + (if minibuffer-completing-file-name + (with-current-buffer mainbuf + (setq default-directory (file-name-directory mbuf-contents)))) + (with-current-buffer standard-output (completion-list-mode) - (make-local-variable 'completion-reference-buffer) - (setq completion-reference-buffer mainbuf) - (if minibuffer-completing-file-name - ;; For file name completion, - ;; use the number of chars before the start of the - ;; last file name component. - (setq completion-base-size + (set (make-local-variable 'completion-reference-buffer) mainbuf) + (setq completion-base-size + (cond + ((and (symbolp minibuffer-completion-table) + (get minibuffer-completion-table 'completion-base-size-function)) + ;; To compute base size, a function can use the global value of + ;; completion-common-substring or minibuffer-completion-contents. + (with-current-buffer mainbuf + (funcall (get minibuffer-completion-table + 'completion-base-size-function)))) + (minibuffer-completing-file-name + ;; For file name completion, use the number of chars before + ;; the start of the file name component at point. + (with-current-buffer mainbuf (save-excursion - (set-buffer mainbuf) - (goto-char (point-max)) - (skip-chars-backward "^/") - (- (point) (minibuffer-prompt-end)))) - ;; Otherwise, in minibuffer, the whole input is being completed. - (save-match-data - (if (string-match "\\` \\*Minibuf-[0-9]+\\*\\'" - (buffer-name mainbuf)) - (setq completion-base-size 0)))) + (skip-chars-backward completion-root-regexp) + (- (point) (minibuffer-prompt-end))))) + ;; Otherwise, in minibuffer, the base size is 0. + ((minibufferp mainbuf) 0))) + (setq common-string-length + (cond + (completion-common-substring + (length completion-common-substring)) + (completion-base-size + (- (length mbuf-contents) completion-base-size)))) + ;; Put faces on first uncommon characters and common parts. + (when (and (integerp common-string-length) (>= common-string-length 0)) + (let ((element-start (point-min)) + (maxp (point-max)) + element-common-end) + (while (and (setq element-start + (next-single-property-change + element-start 'mouse-face)) + (< (setq element-common-end + (+ element-start common-string-length)) + maxp)) + (when (get-char-property element-start 'mouse-face) + (if (and (> common-string-length 0) + (get-char-property (1- element-common-end) 'mouse-face)) + (put-text-property element-start element-common-end + 'font-lock-face 'completions-common-part)) + (if (get-char-property element-common-end 'mouse-face) + (put-text-property element-common-end (1+ element-common-end) + 'font-lock-face 'completions-first-difference)))))) + ;; Insert help string. (goto-char (point-min)) (if (display-mouse-p) (insert (substitute-command-keys @@ -4010,14 +5013,8 @@ (add-hook 'completion-setup-hook 'completion-setup-function) -(define-key minibuffer-local-completion-map [prior] - 'switch-to-completions) -(define-key minibuffer-local-must-match-map [prior] - 'switch-to-completions) -(define-key minibuffer-local-completion-map "\M-v" - 'switch-to-completions) -(define-key minibuffer-local-must-match-map "\M-v" - 'switch-to-completions) +(define-key minibuffer-local-completion-map [prior] 'switch-to-completions) +(define-key minibuffer-local-completion-map "\M-v" 'switch-to-completions) (defun switch-to-completions () "Select the completion list window." @@ -4038,27 +5035,27 @@ ;; to the following event. (defun event-apply-alt-modifier (ignore-prompt) - "Add the Alt modifier to the following event. + "\\<function-key-map>Add the Alt modifier to the following event. For example, type \\[event-apply-alt-modifier] & to enter Alt-&." (vector (event-apply-modifier (read-event) 'alt 22 "A-"))) (defun event-apply-super-modifier (ignore-prompt) - "Add the Super modifier to the following event. + "\\<function-key-map>Add the Super modifier to the following event. For example, type \\[event-apply-super-modifier] & to enter Super-&." (vector (event-apply-modifier (read-event) 'super 23 "s-"))) (defun event-apply-hyper-modifier (ignore-prompt) - "Add the Hyper modifier to the following event. + "\\<function-key-map>Add the Hyper modifier to the following event. For example, type \\[event-apply-hyper-modifier] & to enter Hyper-&." (vector (event-apply-modifier (read-event) 'hyper 24 "H-"))) (defun event-apply-shift-modifier (ignore-prompt) - "Add the Shift modifier to the following event. + "\\<function-key-map>Add the Shift modifier to the following event. For example, type \\[event-apply-shift-modifier] & to enter Shift-&." (vector (event-apply-modifier (read-event) 'shift 25 "S-"))) (defun event-apply-control-modifier (ignore-prompt) - "Add the Ctrl modifier to the following event. + "\\<function-key-map>Add the Ctrl modifier to the following event. For example, type \\[event-apply-control-modifier] & to enter Ctrl-&." (vector (event-apply-modifier (read-event) 'control 26 "C-"))) (defun event-apply-meta-modifier (ignore-prompt) - "Add the Meta modifier to the following event. + "\\<function-key-map>Add the Meta modifier to the following event. For example, type \\[event-apply-meta-modifier] & to enter Meta-&." (vector (event-apply-modifier (read-event) 'meta 27 "M-"))) @@ -4114,7 +5111,7 @@ (define-key function-key-map (vector keypad) (vector normal)))) '((kp-0 ?0) (kp-1 ?1) (kp-2 ?2) (kp-3 ?3) (kp-4 ?4) (kp-5 ?5) (kp-6 ?6) (kp-7 ?7) (kp-8 ?8) (kp-9 ?9) - (kp-space ?\ ) + (kp-space ?\s) (kp-tab ?\t) (kp-enter ?\r) (kp-multiply ?*) @@ -4168,11 +5165,22 @@ ;; - syntax-table ;; - overlays (defun clone-buffer (&optional newname display-flag) - "Create a twin copy of the current buffer. -If NEWNAME is nil, it defaults to the current buffer's name; -NEWNAME is modified by adding or incrementing <N> at the end as necessary. - -If DISPLAY-FLAG is non-nil, the new buffer is shown with `pop-to-buffer'. + "Create and return a twin copy of the current buffer. +Unlike an indirect buffer, the new buffer can be edited +independently of the old one (if it is not read-only). +NEWNAME is the name of the new buffer. It may be modified by +adding or incrementing <N> at the end as necessary to create a +unique buffer name. If nil, it defaults to the name of the +current buffer, with the proper suffix. If DISPLAY-FLAG is +non-nil, the new buffer is shown with `pop-to-buffer'. Trying to +clone a file-visiting buffer, or a buffer whose major mode symbol +has a non-nil `no-clone' property, results in an error. + +Interactively, DISPLAY-FLAG is t and NEWNAME is the name of the +current buffer with appropriate suffix. However, if a prefix +argument is given, then the command prompts for NEWNAME in the +minibuffer. + This runs the normal hook `clone-buffer-hook' in the new buffer after it has been set up properly in other respects." (interactive @@ -4235,7 +5243,7 @@ (defun clone-indirect-buffer (newname display-flag &optional norecord) "Create an indirect buffer that is a twin copy of the current buffer. -Give the indirect buffer name NEWNAME. Interactively, read NEW-NAME +Give the indirect buffer name NEWNAME. Interactively, read NEWNAME from the minibuffer when invoked with a prefix arg. If NEWNAME is nil or if not called with a prefix arg, NEWNAME defaults to the current buffer's name. The name is modified by adding a `<N>' suffix to it @@ -4244,7 +5252,7 @@ DISPLAY-FLAG non-nil means show the new buffer with `pop-to-buffer'. This is always done when called interactively. -Optional last arg NORECORD non-nil means do not put this buffer at the +Optional third arg NORECORD non-nil means do not put this buffer at the front of the list of recently selected ones." (interactive (progn @@ -4275,11 +5283,21 @@ (set-buffer buffer) (clone-indirect-buffer nil t norecord))) -(define-key ctl-x-4-map "c" 'clone-indirect-buffer-other-window) ;;; Handling of Backspace and Delete keys. -(defcustom normal-erase-is-backspace nil +(defcustom normal-erase-is-backspace + (and (not noninteractive) + (or (memq system-type '(ms-dos windows-nt)) + (eq window-system 'mac) + (and (memq window-system '(x)) + (fboundp 'x-backspace-delete-keys-p) + (x-backspace-delete-keys-p)) + ;; If the terminal Emacs is running on has erase char + ;; set to ^H, use the Backspace key for deleting + ;; backward and, and the Delete key for deleting forward. + (and (null window-system) + (eq tty-erase-char ?\^H)))) "If non-nil, Delete key deletes forward and Backspace key deletes backward. On window systems, the default value of this option is chosen @@ -4387,8 +5405,27 @@ (if (interactive-p) (message "Delete key deletes %s" (if normal-erase-is-backspace "forward" "backward")))) - - + +(defvar vis-mode-saved-buffer-invisibility-spec nil + "Saved value of `buffer-invisibility-spec' when Visible mode is on.") + +(define-minor-mode visible-mode + "Toggle Visible mode. +With argument ARG turn Visible mode on iff ARG is positive. + +Enabling Visible mode makes all invisible text temporarily visible. +Disabling Visible mode turns off that effect. Visible mode +works by saving the value of `buffer-invisibility-spec' and setting it to nil." + :lighter " Vis" + :group 'editing-basics + (when (local-variable-p 'vis-mode-saved-buffer-invisibility-spec) + (setq buffer-invisibility-spec vis-mode-saved-buffer-invisibility-spec) + (kill-local-variable 'vis-mode-saved-buffer-invisibility-spec)) + (when visible-mode + (set (make-local-variable 'vis-mode-saved-buffer-invisibility-spec) + buffer-invisibility-spec) + (setq buffer-invisibility-spec nil))) + ;; Minibuffer prompt stuff. ;(defun minibuffer-prompt-modification (start end) @@ -4411,4 +5448,6 @@ ; (provide 'simple) + +;; arch-tag: 24af67c0-2a49-44f6-b3b1-312d8b570dfd ;;; simple.el ends here