Mercurial > hg > xemacs-beta
comparison lisp/utils/redo.el @ 98:0d2f883870bc r20-1b1
Import from CVS: tag r20-1b1
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:13:56 +0200 |
parents | 8fc7fe29b841 |
children | 4103f0995bd7 |
comparison
equal
deleted
inserted
replaced
97:498bf5da1c90 | 98:0d2f883870bc |
---|---|
1 ;;; redo.el -- Redo/undo system for XEmacs | |
2 | |
3 ;; Copyright (C) 1985, 1986, 1987, 1993-1995 Free Software Foundation, Inc. | |
4 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | |
5 ;; Copyright (C) 1997 Kyle E. Jones | |
6 | |
7 ;; Author: Kyle E. Jones, February 1997 | |
8 ;; Keywords: lisp, extensions | |
9 | |
10 ;; This file is part of XEmacs. | |
11 | |
12 ;; XEmacs is free software; you can redistribute it and/or modify it | |
13 ;; under the terms of the GNU General Public License as published by | |
14 ;; the Free Software Foundation; either version 2, or (at your option) | |
15 ;; any later version. | |
16 | |
17 ;; XEmacs is distributed in the hope that it will be useful, but | |
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 ;; General Public License for more details. | |
21 | |
22 ;; You should have received a copy of the GNU General Public License | |
23 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
24 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
25 ;; 02111-1307, USA. | |
26 | |
27 ;;; Synched up with: Not in FSF. | |
28 | |
29 ;;; Commentary: | |
30 | |
31 ;; Derived partly from lisp/prim/simple.el in XEmacs. | |
32 | |
33 ;; Emacs' normal undo system allows you to undo an arbitrary | |
34 ;; number of buffer changes. These undos are recorded as ordinary | |
35 ;; buffer changes themselves. So when you break the chain of | |
36 ;; undos by issuing some other command, you can then undo all | |
37 ;; the undos. The chain of recorded buffer modifications | |
38 ;; therefore grows without bound, truncated only at garbage | |
39 ;; collection time. | |
40 ;; | |
41 ;; The redo/undo system is different in two ways: | |
42 ;; 1. The undo/redo command chain is only broken by a buffer | |
43 ;; modification. You can move around the buffer or switch | |
44 ;; buffers and still come back and do more undos or redos. | |
45 ;; 2. The `redo' command rescinds the most recent undo without | |
46 ;; recording the change as a _new_ buffer change. It | |
47 ;; completely reverses the effect of the undo, which | |
48 ;; includes making the chain of buffer modification records | |
49 ;; shorter by one, to counteract the effect of the undo | |
50 ;; command making the record list longer by one. | |
51 ;; | |
52 ;; Installation: | |
53 ;; | |
54 ;; Save this file as redo.el, byte compile it and put the | |
55 ;; resulting redo.elc file in a directory that is listed in | |
56 ;; load-path. | |
57 ;; | |
58 ;; In your .emacs file, add | |
59 ;; (require 'redo) | |
60 ;; and the system will be enabled. | |
61 | |
62 ;;; Code: | |
63 | |
64 (provide 'redo) | |
65 | |
66 (defvar redo-version "1.00" | |
67 "Version number for the Redo package.") | |
68 | |
69 (defvar last-buffer-undo-list nil | |
70 "The head of buffer-undo-list at the last time an undo or redo was done.") | |
71 (make-variable-buffer-local 'last-buffer-undo-list) | |
72 | |
73 (defun redo (&optional count) | |
74 "Redo the the most recent undo. | |
75 Prefix arg COUNT means redo the COUNT most recent undos. | |
76 If you have modified the buffer since the last redo or undo, | |
77 then you cannot redo any undos before then." | |
78 (interactive "*p") | |
79 (if (eq buffer-undo-list t) | |
80 (error "No undo information in this buffer")) | |
81 (if (eq last-buffer-undo-list nil) | |
82 (error "No undos to redo")) | |
83 (or (eq last-buffer-undo-list buffer-undo-list) | |
84 (and (null (car-safe buffer-undo-list)) | |
85 (eq last-buffer-undo-list (cdr-safe buffer-undo-list))) | |
86 (error "Buffer modified since last undo/redo, cannot redo")) | |
87 (and (or (eq buffer-undo-list pending-undo-list) | |
88 (eq (cdr buffer-undo-list) pending-undo-list)) | |
89 (error "No further undos to redo in this buffer")) | |
90 (or (eq (selected-window) (minibuffer-window)) | |
91 (message "Redo...")) | |
92 (let ((modified (buffer-modified-p)) | |
93 (recent-save (recent-auto-save-p)) | |
94 (old-undo-list buffer-undo-list) | |
95 (p (cdr buffer-undo-list)) | |
96 (records-between 0)) | |
97 ;; count the number of undo records between the head of teh | |
98 ;; undo chain and the pointer to the next change. Note that | |
99 ;; by `record' we mean clumps of change records, not the | |
100 ;; boundary records. The number of records will always be a | |
101 ;; multiple of 2, because an undo moves the pending pointer | |
102 ;; forward one record and prepend a record to the head of the | |
103 ;; chain. Thus the separation always increases by two. WHen | |
104 ;; we decrease it we will decrease it by a multiple of 2 | |
105 ;; also. | |
106 (while p | |
107 (cond ((eq p pending-undo-list) | |
108 (setq p nil)) | |
109 ((null (car p)) | |
110 (setq records-between (1+ records-between)) | |
111 (setq p (cdr p))) | |
112 (t | |
113 (setq p (cdr p))))) | |
114 ;; we're off by one if pending pointer is nil, because there | |
115 ;; was no boundary record in front of it to count. | |
116 (and (null pending-undo-list) | |
117 (setq records-between (1+ records-between))) | |
118 ;; don't allow the user to redo more undos than exist. | |
119 ;; only half the records between the list head and the pending | |
120 ;; pointer are undos that are a part of this command chain. | |
121 (setq count (min (/ records-between 2) count) | |
122 p (primitive-undo (1+ count) buffer-undo-list)) | |
123 (if (eq p old-undo-list) | |
124 nil ;; nothing happened | |
125 ;; set buffer-undo-list to the new undo list. if has been | |
126 ;; shortened by `count' records. | |
127 (setq buffer-undo-list p) | |
128 ;; primitive-undo returns a list without a leading undo | |
129 ;; boundary. add one. | |
130 (undo-boundary) | |
131 ;; now move the pending pointer backward in the undo list | |
132 ;; to reflect the redo. sure would be nice if this list | |
133 ;; were doubly linked, but no... so we have to run down the | |
134 ;; list from the head and stop at the right place. | |
135 (let ((n (- records-between count))) | |
136 (setq p (cdr old-undo-list)) | |
137 (while (and p (> n 0)) | |
138 (if (null (car p)) | |
139 (setq n (1- n))) | |
140 (setq p (cdr p))) | |
141 (setq pending-undo-list p))) | |
142 (and modified (not (buffer-modified-p)) | |
143 (delete-auto-save-file-if-necessary recent-save)) | |
144 (or (eq (selected-window) (minibuffer-window)) | |
145 (message "Redo!")) | |
146 (setq last-buffer-undo-list buffer-undo-list))) | |
147 | |
148 (defun undo (&optional arg) | |
149 "Undo some previous changes. | |
150 Repeat this command to undo more changes. | |
151 A numeric argument serves as a repeat count." | |
152 (interactive "*p") | |
153 (let ((modified (buffer-modified-p)) | |
154 (recent-save (recent-auto-save-p))) | |
155 (or (eq (selected-window) (minibuffer-window)) | |
156 (message "Undo...")) | |
157 (or (eq last-buffer-undo-list buffer-undo-list) | |
158 (and (null (car-safe buffer-undo-list)) | |
159 (eq last-buffer-undo-list (cdr-safe buffer-undo-list))) | |
160 (progn (undo-start) | |
161 (undo-more 1))) | |
162 (undo-more (or arg 1)) | |
163 ;; Don't specify a position in the undo record for the undo command. | |
164 ;; Instead, undoing this should move point to where the change is. | |
165 ;; | |
166 ;;;; The old code for this was mad! It deleted all set-point | |
167 ;;;; references to the position from the whole undo list, | |
168 ;;;; instead of just the cells from the beginning to the next | |
169 ;;;; undo boundary. This does what I think the other code | |
170 ;;;; meant to do. | |
171 (let ((list buffer-undo-list) | |
172 (prev nil)) | |
173 (while (and list (not (null (car list)))) | |
174 (if (integerp (car list)) | |
175 (if prev | |
176 (setcdr prev (cdr list)) | |
177 ;; impossible now, but maybe not in the future | |
178 (setq buffer-undo-list (cdr list)))) | |
179 (setq prev list | |
180 list (cdr list)))) | |
181 (and modified (not (buffer-modified-p)) | |
182 (delete-auto-save-file-if-necessary recent-save))) | |
183 (or (eq (selected-window) (minibuffer-window)) | |
184 (message "Undo!")) | |
185 (setq last-buffer-undo-list buffer-undo-list)) | |
186 | |
187 ;;; redo.el ends here |