]> code.delx.au - gnu-emacs-elpa/blob - packages/undo-tree/undo-tree.el
Add ENWC from bzr://bzr.savannah.nongnu.org/enwc/trunk
[gnu-emacs-elpa] / packages / undo-tree / undo-tree.el
1 ;;; undo-tree.el --- Treat undo history as a tree -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2009-2012 Free Software Foundation, Inc
4
5 ;; Author: Toby Cubitt <toby-undo-tree@dr-qubit.org>
6 ;; Version: 0.6.3
7 ;; Keywords: convenience, files, undo, redo, history, tree
8 ;; URL: http://www.dr-qubit.org/emacs.php
9 ;; Repository: http://www.dr-qubit.org/git/undo-tree.git
10
11 ;; This file is part of Emacs.
12 ;;
13 ;; This file is free software: you can redistribute it and/or modify it under
14 ;; the terms of the GNU General Public License as published by the Free
15 ;; Software Foundation, either version 3 of the License, or (at your option)
16 ;; any later version.
17 ;;
18 ;; This program is distributed in the hope that it will be useful, but WITHOUT
19 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21 ;; more details.
22 ;;
23 ;; You should have received a copy of the GNU General Public License along
24 ;; with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25
26
27 ;;; Commentary:
28 ;;
29 ;; Emacs has a powerful undo system. Unlike the standard undo/redo system in
30 ;; most software, it allows you to recover *any* past state of a buffer
31 ;; (whereas the standard undo/redo system can lose past states as soon as you
32 ;; redo). However, this power comes at a price: many people find Emacs' undo
33 ;; system confusing and difficult to use, spawning a number of packages that
34 ;; replace it with the less powerful but more intuitive undo/redo system.
35 ;;
36 ;; Both the loss of data with standard undo/redo, and the confusion of Emacs'
37 ;; undo, stem from trying to treat undo history as a linear sequence of
38 ;; changes. It's not. The `undo-tree-mode' provided by this package replaces
39 ;; Emacs' undo system with a system that treats undo history as what it is: a
40 ;; branching tree of changes. This simple idea allows the more intuitive
41 ;; behaviour of the standard undo/redo system to be combined with the power of
42 ;; never losing any history. An added side bonus is that undo history can in
43 ;; some cases be stored more efficiently, allowing more changes to accumulate
44 ;; before Emacs starts discarding history.
45 ;;
46 ;; The only downside to this more advanced yet simpler undo system is that it
47 ;; was inspired by Vim. But, after all, most successful religions steal the
48 ;; best ideas from their competitors!
49 ;;
50 ;;
51 ;; Installation
52 ;; ============
53 ;;
54 ;; This package has only been tested with Emacs versions 24 and CVS. It should
55 ;; work in Emacs versions 22 and 23 too, but will not work without
56 ;; modifications in earlier versions of Emacs.
57 ;;
58 ;; To install `undo-tree-mode', make sure this file is saved in a directory in
59 ;; your `load-path', and add the line:
60 ;;
61 ;; (require 'undo-tree)
62 ;;
63 ;; to your .emacs file. Byte-compiling undo-tree.el is recommended (e.g. using
64 ;; "M-x byte-compile-file" from within emacs).
65 ;;
66 ;; If you want to replace the standard Emacs' undo system with the
67 ;; `undo-tree-mode' system in all buffers, you can enable it globally by
68 ;; adding:
69 ;;
70 ;; (global-undo-tree-mode)
71 ;;
72 ;; to your .emacs file.
73 ;;
74 ;;
75 ;; Quick-Start
76 ;; ===========
77 ;;
78 ;; If you're the kind of person who likes to jump in the car and drive,
79 ;; without bothering to first figure out whether the button on the left dips
80 ;; the headlights or operates the ejector seat (after all, you'll soon figure
81 ;; it out when you push it), then here's the minimum you need to know:
82 ;;
83 ;; `undo-tree-mode' and `global-undo-tree-mode'
84 ;; Enable undo-tree mode (either in the current buffer or globally).
85 ;;
86 ;; C-_ C-/ (`undo-tree-undo')
87 ;; Undo changes.
88 ;;
89 ;; M-_ C-? (`undo-tree-redo')
90 ;; Redo changes.
91 ;;
92 ;; `undo-tree-switch-branch'
93 ;; Switch undo-tree branch.
94 ;; (What does this mean? Better press the button and see!)
95 ;;
96 ;; C-x u (`undo-tree-visualize')
97 ;; Visualize the undo tree.
98 ;; (Better try pressing this button too!)
99 ;;
100 ;; C-x r u (`undo-tree-save-state-to-register')
101 ;; Save current buffer state to register.
102 ;;
103 ;; C-x r U (`undo-tree-restore-state-from-register')
104 ;; Restore buffer state from register.
105 ;;
106 ;;
107 ;;
108 ;; In the undo-tree visualizer:
109 ;;
110 ;; <up> p C-p (`undo-tree-visualize-undo')
111 ;; Undo changes.
112 ;;
113 ;; <down> n C-n (`undo-tree-visualize-redo')
114 ;; Redo changes.
115 ;;
116 ;; <left> b C-b (`undo-tree-visualize-switch-branch-left')
117 ;; Switch to previous undo-tree branch.
118 ;;
119 ;; <right> f C-f (`undo-tree-visualize-switch-branch-right')
120 ;; Switch to next undo-tree branch.
121 ;;
122 ;; C-<up> M-{ (`undo-tree-visualize-undo-to-x')
123 ;; Undo changes up to last branch point.
124 ;;
125 ;; C-<down> M-} (`undo-tree-visualize-redo-to-x')
126 ;; Redo changes down to next branch point.
127 ;;
128 ;; <down> n C-n (`undo-tree-visualize-redo')
129 ;; Redo changes.
130 ;;
131 ;; <mouse-1> (`undo-tree-visualizer-mouse-set')
132 ;; Set state to node at mouse click.
133 ;;
134 ;; t (`undo-tree-visualizer-toggle-timestamps')
135 ;; Toggle display of time-stamps.
136 ;;
137 ;; d (`undo-tree-visualizer-toggle-diff')
138 ;; Toggle diff display.
139 ;;
140 ;; s (`undo-tree-visualizer-selection-mode')
141 ;; Toggle keyboard selection mode.
142 ;;
143 ;; q (`undo-tree-visualizer-quit')
144 ;; Quit undo-tree-visualizer.
145 ;;
146 ;; C-q (`undo-tree-visualizer-abort')
147 ;; Abort undo-tree-visualizer.
148 ;;
149 ;; , <
150 ;; Scroll left.
151 ;;
152 ;; . >
153 ;; Scroll right.
154 ;;
155 ;; <pgup> M-v
156 ;; Scroll up.
157 ;;
158 ;; <pgdown> C-v
159 ;; Scroll down.
160 ;;
161 ;;
162 ;;
163 ;; In visualizer selection mode:
164 ;;
165 ;; <up> p C-p (`undo-tree-visualizer-select-previous')
166 ;; Select previous node.
167 ;;
168 ;; <down> n C-n (`undo-tree-visualizer-select-next')
169 ;; Select next node.
170 ;;
171 ;; <left> b C-b (`undo-tree-visualizer-select-left')
172 ;; Select left sibling node.
173 ;;
174 ;; <right> f C-f (`undo-tree-visualizer-select-right')
175 ;; Select right sibling node.
176 ;;
177 ;; <pgup> M-v
178 ;; Select node 10 above.
179 ;;
180 ;; <pgdown> C-v
181 ;; Select node 10 below.
182 ;;
183 ;; <enter> (`undo-tree-visualizer-set')
184 ;; Set state to selected node and exit selection mode.
185 ;;
186 ;; s (`undo-tree-visualizer-mode')
187 ;; Exit selection mode.
188 ;;
189 ;; t (`undo-tree-visualizer-toggle-timestamps')
190 ;; Toggle display of time-stamps.
191 ;;
192 ;; d (`undo-tree-visualizer-toggle-diff')
193 ;; Toggle diff display.
194 ;;
195 ;; q (`undo-tree-visualizer-quit')
196 ;; Quit undo-tree-visualizer.
197 ;;
198 ;; C-q (`undo-tree-visualizer-abort')
199 ;; Abort undo-tree-visualizer.
200 ;;
201 ;; , <
202 ;; Scroll left.
203 ;;
204 ;; . >
205 ;; Scroll right.
206 ;;
207 ;;
208 ;;
209 ;; Persistent undo history:
210 ;;
211 ;; Note: Requires a recent development version of Emacs checked out out from
212 ;; the Emacs bzr repository. All stable versions of Emacs currently
213 ;; break this feature.
214 ;;
215 ;; `undo-tree-auto-save-history' (variable)
216 ;; automatically save and restore undo-tree history along with buffer
217 ;; (disabled by default)
218 ;;
219 ;; `undo-tree-save-history' (command)
220 ;; manually save undo history to file
221 ;;
222 ;; `undo-tree-load-history' (command)
223 ;; manually load undo history from file
224 ;;
225 ;;
226 ;;
227 ;; Compressing undo history:
228 ;;
229 ;; Undo history files cannot grow beyond the maximum undo tree size, which
230 ;; is limited by `undo-limit', `undo-strong-limit' and
231 ;; `undo-outer-limit'. Nevertheless, undo history files can grow quite
232 ;; large. If you want to automatically compress undo history, add the
233 ;; following advice to your .emacs file (replacing ".gz" with the filename
234 ;; extension of your favourite compression algorithm):
235 ;;
236 ;; (defadvice undo-tree-make-history-save-file-name
237 ;; (after undo-tree activate)
238 ;; (setq concat ad-return-value ".gz"))
239 ;;
240 ;;
241 ;;
242 ;;
243 ;; Undo Systems
244 ;; ============
245 ;;
246 ;; To understand the different undo systems, it's easiest to consider an
247 ;; example. Imagine you make a few edits in a buffer. As you edit, you
248 ;; accumulate a history of changes, which we might visualize as a string of
249 ;; past buffer states, growing downwards:
250 ;;
251 ;; o (initial buffer state)
252 ;; |
253 ;; |
254 ;; o (first edit)
255 ;; |
256 ;; |
257 ;; o (second edit)
258 ;; |
259 ;; |
260 ;; x (current buffer state)
261 ;;
262 ;;
263 ;; Now imagine that you undo the last two changes. We can visualize this as
264 ;; rewinding the current state back two steps:
265 ;;
266 ;; o (initial buffer state)
267 ;; |
268 ;; |
269 ;; x (current buffer state)
270 ;; |
271 ;; |
272 ;; o
273 ;; |
274 ;; |
275 ;; o
276 ;;
277 ;;
278 ;; However, this isn't a good representation of what Emacs' undo system
279 ;; does. Instead, it treats the undos as *new* changes to the buffer, and adds
280 ;; them to the history:
281 ;;
282 ;; o (initial buffer state)
283 ;; |
284 ;; |
285 ;; o (first edit)
286 ;; |
287 ;; |
288 ;; o (second edit)
289 ;; |
290 ;; |
291 ;; x (buffer state before undo)
292 ;; |
293 ;; |
294 ;; o (first undo)
295 ;; |
296 ;; |
297 ;; x (second undo)
298 ;;
299 ;;
300 ;; Actually, since the buffer returns to a previous state after an undo,
301 ;; perhaps a better way to visualize it is to imagine the string of changes
302 ;; turning back on itself:
303 ;;
304 ;; (initial buffer state) o
305 ;; |
306 ;; |
307 ;; (first edit) o x (second undo)
308 ;; | |
309 ;; | |
310 ;; (second edit) o o (first undo)
311 ;; | /
312 ;; |/
313 ;; o (buffer state before undo)
314 ;;
315 ;; Treating undos as new changes might seem a strange thing to do. But the
316 ;; advantage becomes clear as soon as we imagine what happens when you edit
317 ;; the buffer again. Since you've undone a couple of changes, new edits will
318 ;; branch off from the buffer state that you've rewound to. Conceptually, it
319 ;; looks like this:
320 ;;
321 ;; o (initial buffer state)
322 ;; |
323 ;; |
324 ;; o
325 ;; |\
326 ;; | \
327 ;; o x (new edit)
328 ;; |
329 ;; |
330 ;; o
331 ;;
332 ;; The standard undo/redo system only lets you go backwards and forwards
333 ;; linearly. So as soon as you make that new edit, it discards the old
334 ;; branch. Emacs' undo just keeps adding changes to the end of the string. So
335 ;; the undo history in the two systems now looks like this:
336 ;;
337 ;; Undo/Redo: Emacs' undo
338 ;;
339 ;; o o
340 ;; | |
341 ;; | |
342 ;; o o o
343 ;; .\ | |\
344 ;; . \ | | \
345 ;; . x (new edit) o o |
346 ;; (discarded . | / |
347 ;; branch) . |/ |
348 ;; . o |
349 ;; |
350 ;; |
351 ;; x (new edit)
352 ;;
353 ;; Now, what if you change your mind about those undos, and decide you did
354 ;; like those other changes you'd made after all? With the standard undo/redo
355 ;; system, you're lost. There's no way to recover them, because that branch
356 ;; was discarded when you made the new edit.
357 ;;
358 ;; However, in Emacs' undo system, those old buffer states are still there in
359 ;; the undo history. You just have to rewind back through the new edit, and
360 ;; back through the changes made by the undos, until you reach them. Of
361 ;; course, since Emacs treats undos (even undos of undos!) as new changes,
362 ;; you're really weaving backwards and forwards through the history, all the
363 ;; time adding new changes to the end of the string as you go:
364 ;;
365 ;; o
366 ;; |
367 ;; |
368 ;; o o o (undo new edit)
369 ;; | |\ |\
370 ;; | | \ | \
371 ;; o o | | o (undo the undo)
372 ;; | / | | |
373 ;; |/ | | |
374 ;; (trying to get o | | x (undo the undo)
375 ;; to this state) | /
376 ;; |/
377 ;; o
378 ;;
379 ;; So far, this is still reasonably intuitive to use. It doesn't behave so
380 ;; differently to standard undo/redo, except that by going back far enough you
381 ;; can access changes that would be lost in standard undo/redo.
382 ;;
383 ;; However, imagine that after undoing as just described, you decide you
384 ;; actually want to rewind right back to the initial state. If you're lucky,
385 ;; and haven't invoked any command since the last undo, you can just keep on
386 ;; undoing until you get back to the start:
387 ;;
388 ;; (trying to get o x (got there!)
389 ;; to this state) | |
390 ;; | |
391 ;; o o o o (keep undoing)
392 ;; | |\ |\ |
393 ;; | | \ | \ |
394 ;; o o | | o o (keep undoing)
395 ;; | / | | | /
396 ;; |/ | | |/
397 ;; (already undid o | | o (got this far)
398 ;; to this state) | /
399 ;; |/
400 ;; o
401 ;;
402 ;; But if you're unlucky, and you happen to have moved the point (say) after
403 ;; getting to the state labelled "got this far", then you've "broken the undo
404 ;; chain". Hold on to something solid, because things are about to get
405 ;; hairy. If you try to undo now, Emacs thinks you're trying to undo the
406 ;; undos! So to get back to the initial state you now have to rewind through
407 ;; *all* the changes, including the undos you just did:
408 ;;
409 ;; (trying to get o x (finally got there!)
410 ;; to this state) | |
411 ;; | |
412 ;; o o o o o o
413 ;; | |\ |\ |\ |\ |
414 ;; | | \ | \ | \ | \ |
415 ;; o o | | o o o | o o
416 ;; | / | | | / | | | /
417 ;; |/ | | |/ | | |/
418 ;; (already undid o | | o<. | | o
419 ;; to this state) | / : | /
420 ;; |/ : |/
421 ;; o : o
422 ;; :
423 ;; (got this far, but
424 ;; broke the undo chain)
425 ;;
426 ;; Confused?
427 ;;
428 ;; In practice you can just hold down the undo key until you reach the buffer
429 ;; state that you want. But whatever you do, don't move around in the buffer
430 ;; to *check* that you've got back to where you want! Because you'll break the
431 ;; undo chain, and then you'll have to traverse the entire string of undos
432 ;; again, just to get back to the point at which you broke the
433 ;; chain. Undo-in-region and commands such as `undo-only' help to make using
434 ;; Emacs' undo a little easier, but nonetheless it remains confusing for many
435 ;; people.
436 ;;
437 ;;
438 ;; So what does `undo-tree-mode' do? Remember the diagram we drew to represent
439 ;; the history we've been discussing (make a few edits, undo a couple of them,
440 ;; and edit again)? The diagram that conceptually represented our undo
441 ;; history, before we started discussing specific undo systems? It looked like
442 ;; this:
443 ;;
444 ;; o (initial buffer state)
445 ;; |
446 ;; |
447 ;; o
448 ;; |\
449 ;; | \
450 ;; o x (current state)
451 ;; |
452 ;; |
453 ;; o
454 ;;
455 ;; Well, that's *exactly* what the undo history looks like to
456 ;; `undo-tree-mode'. It doesn't discard the old branch (as standard undo/redo
457 ;; does), nor does it treat undos as new changes to be added to the end of a
458 ;; linear string of buffer states (as Emacs' undo does). It just keeps track
459 ;; of the tree of branching changes that make up the entire undo history.
460 ;;
461 ;; If you undo from this point, you'll rewind back up the tree to the previous
462 ;; state:
463 ;;
464 ;; o
465 ;; |
466 ;; |
467 ;; x (undo)
468 ;; |\
469 ;; | \
470 ;; o o
471 ;; |
472 ;; |
473 ;; o
474 ;;
475 ;; If you were to undo again, you'd rewind back to the initial state. If on
476 ;; the other hand you redo the change, you'll end up back at the bottom of the
477 ;; most recent branch:
478 ;;
479 ;; o (undo takes you here)
480 ;; |
481 ;; |
482 ;; o (start here)
483 ;; |\
484 ;; | \
485 ;; o x (redo takes you here)
486 ;; |
487 ;; |
488 ;; o
489 ;;
490 ;; So far, this is just like the standard undo/redo system. But what if you
491 ;; want to return to a buffer state located on a previous branch of the
492 ;; history? Since `undo-tree-mode' keeps the entire history, you simply need
493 ;; to tell it to switch to a different branch, and then redo the changes you
494 ;; want:
495 ;;
496 ;; o
497 ;; |
498 ;; |
499 ;; o (start here, but switch
500 ;; |\ to the other branch)
501 ;; | \
502 ;; (redo) o o
503 ;; |
504 ;; |
505 ;; (redo) x
506 ;;
507 ;; Now you're on the other branch, if you undo and redo changes you'll stay on
508 ;; that branch, moving up and down through the buffer states located on that
509 ;; branch. Until you decide to switch branches again, of course.
510 ;;
511 ;; Real undo trees might have multiple branches and sub-branches:
512 ;;
513 ;; o
514 ;; ____|______
515 ;; / \
516 ;; o o
517 ;; ____|__ __|
518 ;; / | \ / \
519 ;; o o o o x
520 ;; | |
521 ;; / \ / \
522 ;; o o o o
523 ;;
524 ;; Trying to imagine what Emacs' undo would do as you move about such a tree
525 ;; will likely frazzle your brain circuits! But in `undo-tree-mode', you're
526 ;; just moving around this undo history tree. Most of the time, you'll
527 ;; probably only need to stay on the most recent branch, in which case it
528 ;; behaves like standard undo/redo, and is just as simple to understand. But
529 ;; if you ever need to recover a buffer state on a different branch, the
530 ;; possibility of switching between branches and accessing the full undo
531 ;; history is still there.
532 ;;
533 ;;
534 ;;
535 ;; The Undo-Tree Visualizer
536 ;; ========================
537 ;;
538 ;; Actually, it gets better. You don't have to imagine all these tree
539 ;; diagrams, because `undo-tree-mode' includes an undo-tree visualizer which
540 ;; draws them for you! In fact, it draws even better diagrams: it highlights
541 ;; the node representing the current buffer state, it highlights the current
542 ;; branch, and you can toggle the display of time-stamps (by hitting "t") and
543 ;; a diff of the undo changes (by hitting "d"). (There's one other tiny
544 ;; difference: the visualizer puts the most recent branch on the left rather
545 ;; than the right.)
546 ;;
547 ;; Bring up the undo tree visualizer whenever you want by hitting "C-x u".
548 ;;
549 ;; In the visualizer, the usual keys for moving up and down a buffer instead
550 ;; move up and down the undo history tree (e.g. the up and down arrow keys, or
551 ;; "C-n" and "C-p"). The state of the "parent" buffer (the buffer whose undo
552 ;; history you are visualizing) is updated as you move around the undo tree in
553 ;; the visualizer. If you reach a branch point in the visualizer, the usual
554 ;; keys for moving forward and backward in a buffer instead switch branch
555 ;; (e.g. the left and right arrow keys, or "C-f" and "C-b").
556 ;;
557 ;; Clicking with the mouse on any node in the visualizer will take you
558 ;; directly to that node, resetting the state of the parent buffer to the
559 ;; state represented by that node.
560 ;;
561 ;; You can also select nodes directly using the keyboard, by hitting "s" to
562 ;; toggle selection mode. The usual motion keys now allow you to move around
563 ;; the tree without changing the parent buffer. Hitting <enter> will reset the
564 ;; state of the parent buffer to the state represented by the currently
565 ;; selected node.
566 ;;
567 ;; It can be useful to see how long ago the parent buffer was in the state
568 ;; represented by a particular node in the visualizer. Hitting "t" in the
569 ;; visualizer toggles the display of time-stamps for all the nodes. (Note
570 ;; that, because of the way `undo-tree-mode' works, these time-stamps may be
571 ;; somewhat later than the true times, especially if it's been a long time
572 ;; since you last undid any changes.)
573 ;;
574 ;; To get some idea of what changes are represented by a given node in the
575 ;; tree, it can be useful to see a diff of the changes. Hit "d" in the
576 ;; visualizer to toggle a diff display. This normally displays a diff between
577 ;; the current state and the previous one, i.e. it shows you the changes that
578 ;; will be applied if you undo (move up the tree). However, the diff display
579 ;; really comes into its own in the visualizer's selection mode (see above),
580 ;; where it instead shows a diff between the current state and the currently
581 ;; selected state, i.e. it shows you the changes that will be applied if you
582 ;; reset to the selected state.
583 ;;
584 ;; (Note that the diff is generated by the Emacs `diff' command, and is
585 ;; displayed using `diff-mode'. See the corresponding customization groups if
586 ;; you want to customize the diff display.)
587 ;;
588 ;; Finally, hitting "q" will quit the visualizer, leaving the parent buffer in
589 ;; whatever state you ended at. Hitting "C-q" will abort the visualizer,
590 ;; returning the parent buffer to whatever state it was originally in when the
591 ;; visualizer was .
592 ;;
593 ;;
594 ;;
595 ;; Undo-in-Region
596 ;; ==============
597 ;;
598 ;; Emacs allows a very useful and powerful method of undoing only selected
599 ;; changes: when a region is active, only changes that affect the text within
600 ;; that region will be undone. With the standard Emacs undo system, changes
601 ;; produced by undoing-in-region naturally get added onto the end of the
602 ;; linear undo history:
603 ;;
604 ;; o
605 ;; |
606 ;; | x (second undo-in-region)
607 ;; o |
608 ;; | |
609 ;; | o (first undo-in-region)
610 ;; o |
611 ;; | /
612 ;; |/
613 ;; o
614 ;;
615 ;; You can of course redo these undos-in-region as usual, by undoing the
616 ;; undos:
617 ;;
618 ;; o
619 ;; |
620 ;; | o_
621 ;; o | \
622 ;; | | |
623 ;; | o o (undo the undo-in-region)
624 ;; o | |
625 ;; | / |
626 ;; |/ |
627 ;; o x (undo the undo-in-region)
628 ;;
629 ;;
630 ;; In `undo-tree-mode', undo-in-region works similarly: when there's an active
631 ;; region, undoing only undoes changes that affect that region. However, the
632 ;; way these undos-in-region are recorded in the undo history is quite
633 ;; different. In `undo-tree-mode', undo-in-region creates a new branch in the
634 ;; undo history. The new branch consists of an undo step that undoes some of
635 ;; the changes that affect the current region, and another step that undoes
636 ;; the remaining changes needed to rejoin the previous undo history.
637 ;;
638 ;; Previous undo history Undo-in-region
639 ;;
640 ;; o o
641 ;; | |
642 ;; | |
643 ;; o o
644 ;; | |\
645 ;; | | \
646 ;; o o x (undo-in-region)
647 ;; | | |
648 ;; | | |
649 ;; x o o
650 ;;
651 ;; As long as you don't change the active region after undoing-in-region,
652 ;; continuing to undo-in-region extends the new branch, pulling more changes
653 ;; that affect the current region into an undo step immediately above your
654 ;; current location in the undo tree, and pushing the point at which the new
655 ;; branch is attached further up the tree:
656 ;;
657 ;; First undo-in-region Second undo-in-region
658 ;;
659 ;; o o
660 ;; | |\
661 ;; | | \
662 ;; o o x (undo-in-region)
663 ;; |\ | |
664 ;; | \ | |
665 ;; o x o o
666 ;; | | | |
667 ;; | | | |
668 ;; o o o o
669 ;;
670 ;; Redoing takes you back down the undo tree, as usual (as long as you haven't
671 ;; changed the active region after undoing-in-region, it doesn't matter if it
672 ;; is still active):
673 ;;
674 ;; o
675 ;; |\
676 ;; | \
677 ;; o o
678 ;; | |
679 ;; | |
680 ;; o o (redo)
681 ;; | |
682 ;; | |
683 ;; o x (redo)
684 ;;
685 ;;
686 ;; What about redo-in-region? Obviously, this only makes sense if you have
687 ;; already undone some changes, so that there are some changes to redo!
688 ;; Redoing-in-region splits off a new branch of the undo history below your
689 ;; current location in the undo tree. This time, the new branch consists of a
690 ;; redo step that redoes some of the redo changes that affect the current
691 ;; region, followed by all the remaining redo changes.
692 ;;
693 ;; Previous undo history Redo-in-region
694 ;;
695 ;; o o
696 ;; | |
697 ;; | |
698 ;; x o
699 ;; | |\
700 ;; | | \
701 ;; o o x (redo-in-region)
702 ;; | | |
703 ;; | | |
704 ;; o o o
705 ;;
706 ;; As long as you don't change the active region after redoing-in-region,
707 ;; continuing to redo-in-region extends the new branch, pulling more redo
708 ;; changes into a redo step immediately below your current location in the
709 ;; undo tree.
710 ;;
711 ;; First redo-in-region Second redo-in-region
712 ;;
713 ;; o o
714 ;; | |
715 ;; | |
716 ;; o o
717 ;; |\ |\
718 ;; | \ | \
719 ;; o x (redo-in-region) o o
720 ;; | | | |
721 ;; | | | |
722 ;; o o o x (redo-in-region)
723 ;; |
724 ;; |
725 ;; o
726 ;;
727 ;; Note that undo-in-region and redo-in-region only ever add new changes to
728 ;; the undo tree, they *never* modify existing undo history. So you can always
729 ;; return to previous buffer states by switching to a previous branch of the
730 ;; tree.
731
732
733
734 ;;; Code:
735
736 (eval-when-compile (require 'cl))
737 (require 'diff)
738
739
740 \f
741 ;;; =====================================================================
742 ;;; Compatibility hacks for older Emacsen
743
744 ;; `characterp' isn't defined in Emacs versions < 23
745 (unless (fboundp 'characterp)
746 (defalias 'characterp 'char-valid-p))
747
748 ;; `region-active-p' isn't defined in Emacs versions < 23
749 (unless (fboundp 'region-active-p)
750 (defun region-active-p () (and transient-mark-mode mark-active)))
751
752
753 ;; `registerv' defstruct isn't defined in Emacs versions < 24
754 (unless (fboundp 'registerv-make)
755 (defmacro registerv-make (data &rest _dummy) data))
756
757 (unless (fboundp 'registerv-data)
758 (defmacro registerv-data (data) data))
759
760
761 ;; `diff-no-select' and `diff-file-local-copy' aren't defined in Emacs
762 ;; versions < 24 (copied and adapted from Emacs 24)
763 (unless (fboundp 'diff-no-select)
764 (defun diff-no-select (old new &optional switches no-async buf)
765 ;; Noninteractive helper for creating and reverting diff buffers
766 (unless (bufferp new) (setq new (expand-file-name new)))
767 (unless (bufferp old) (setq old (expand-file-name old)))
768 (or switches (setq switches diff-switches)) ; If not specified, use default.
769 (unless (listp switches) (setq switches (list switches)))
770 (or buf (setq buf (get-buffer-create "*Diff*")))
771 (let* ((old-alt (diff-file-local-copy old))
772 (new-alt (diff-file-local-copy new))
773 (command
774 (mapconcat 'identity
775 `(,diff-command
776 ;; Use explicitly specified switches
777 ,@switches
778 ,@(mapcar #'shell-quote-argument
779 (nconc
780 (when (or old-alt new-alt)
781 (list "-L" (if (stringp old)
782 old (prin1-to-string old))
783 "-L" (if (stringp new)
784 new (prin1-to-string new))))
785 (list (or old-alt old)
786 (or new-alt new)))))
787 " "))
788 (thisdir default-directory))
789 (with-current-buffer buf
790 (setq buffer-read-only t)
791 (buffer-disable-undo (current-buffer))
792 (let ((inhibit-read-only t))
793 (erase-buffer))
794 (buffer-enable-undo (current-buffer))
795 (diff-mode)
796 (set (make-local-variable 'revert-buffer-function)
797 (lambda (_ignore-auto _noconfirm)
798 (diff-no-select old new switches no-async (current-buffer))))
799 (setq default-directory thisdir)
800 (let ((inhibit-read-only t))
801 (insert command "\n"))
802 (if (and (not no-async) (fboundp 'start-process))
803 (let ((proc (start-process "Diff" buf shell-file-name
804 shell-command-switch command)))
805 (set-process-filter proc 'diff-process-filter)
806 (set-process-sentinel
807 proc (lambda (proc _msg)
808 (with-current-buffer (process-buffer proc)
809 (diff-sentinel (process-exit-status proc))
810 (if old-alt (delete-file old-alt))
811 (if new-alt (delete-file new-alt))))))
812 ;; Async processes aren't available.
813 (let ((inhibit-read-only t))
814 (diff-sentinel
815 (call-process shell-file-name nil buf nil
816 shell-command-switch command))
817 (if old-alt (delete-file old-alt))
818 (if new-alt (delete-file new-alt)))))
819 buf)))
820
821 (unless (fboundp 'diff-file-local-copy)
822 (defun diff-file-local-copy (file-or-buf)
823 (if (bufferp file-or-buf)
824 (with-current-buffer file-or-buf
825 (let ((tempfile (make-temp-file "buffer-content-")))
826 (write-region nil nil tempfile nil 'nomessage)
827 tempfile))
828 (file-local-copy file-or-buf))))
829
830
831
832 \f
833 ;;; =====================================================================
834 ;;; Global variables and customization options
835
836 (defvar buffer-undo-tree nil
837 "Tree of undo entries in current buffer.")
838 (make-variable-buffer-local 'buffer-undo-tree)
839 (put 'buffer-undo-tree 'permanent-local t)
840
841
842 (defgroup undo-tree nil
843 "Tree undo/redo."
844 :group 'undo)
845
846 (defcustom undo-tree-mode-lighter " Undo-Tree"
847 "Lighter displayed in mode line
848 when `undo-tree-mode' is enabled."
849 :group 'undo-tree
850 :type 'string)
851
852
853 (defcustom undo-tree-incompatible-major-modes '(term-mode)
854 "List of major-modes in which `undo-tree-mode' should not be enabled.
855 \(See `turn-on-undo-tree-mode'.\)"
856 :group 'undo-tree
857 :type '(repeat symbol))
858
859
860 (defcustom undo-tree-enable-undo-in-region t
861 "When non-nil, enable undo-in-region.
862
863 When undo-in-region is enabled, undoing or redoing when the
864 region is active (in `transient-mark-mode') or with a prefix
865 argument (not in `transient-mark-mode') only undoes changes
866 within the current region."
867 :group 'undo-tree
868 :type 'boolean)
869
870
871 (defcustom undo-tree-auto-save-history nil
872 "When non-nil, `undo-tree-mode' will save undo history to file
873 when a buffer is saved to file.
874
875 It will automatically load undo history when a buffer is loaded
876 from file, if an undo save file exists.
877
878 Undo-tree history is saved to a file called
879 \".<buffer-file-name>.~undo-tree\" in the same directory as the
880 file itself.
881
882 WARNING! `undo-tree-auto-save-history' will not work properly in
883 Emacs versions prior to 24.3, so it cannot be enabled via
884 the customization interface in versions earlier than that one. To
885 ignore this warning and enable it regardless, set
886 `undo-tree-auto-save-history' to a non-nil value outside of
887 customize."
888 :group 'undo-tree
889 :type (if (version-list-< (version-to-list emacs-version) '(24 3))
890 '(choice (const :tag "<disabled>" nil))
891 'boolean))
892
893
894 (defcustom undo-tree-history-directory-alist nil
895 "Alist of filename patterns and undo history directory names.
896 Each element looks like (REGEXP . DIRECTORY). Undo history for
897 files with names matching REGEXP will be saved in DIRECTORY.
898 DIRECTORY may be relative or absolute. If it is absolute, so
899 that all matching files are backed up into the same directory,
900 the file names in this directory will be the full name of the
901 file backed up with all directory separators changed to `!' to
902 prevent clashes. This will not work correctly if your filesystem
903 truncates the resulting name.
904
905 For the common case of all backups going into one directory, the
906 alist should contain a single element pairing \".\" with the
907 appropriate directory name.
908
909 If this variable is nil, or it fails to match a filename, the
910 backup is made in the original file's directory.
911
912 On MS-DOS filesystems without long names this variable is always
913 ignored."
914 :group 'undo-tree
915 :type '(repeat (cons (regexp :tag "Regexp matching filename")
916 (directory :tag "Undo history directory name"))))
917
918
919
920 (defcustom undo-tree-visualizer-relative-timestamps t
921 "When non-nil, display times relative to current time
922 when displaying time stamps in visualizer.
923
924 Otherwise, display absolute times."
925 :group 'undo-tree
926 :type 'boolean)
927
928
929 (defcustom undo-tree-visualizer-timestamps nil
930 "When non-nil, display time-stamps by default
931 in undo-tree visualizer.
932
933 \\<undo-tree-visualizer-map>You can always toggle time-stamps on and off \
934 using \\[undo-tree-visualizer-toggle-timestamps], regardless of the
935 setting of this variable."
936 :group 'undo-tree
937 :type 'boolean)
938
939
940 (defcustom undo-tree-visualizer-diff nil
941 "When non-nil, display diff by default in undo-tree visualizer.
942
943 \\<undo-tree-visualizer-map>You can always toggle the diff display \
944 using \\[undo-tree-visualizer-toggle-diff], regardless of the
945 setting of this variable."
946 :group 'undo-tree
947 :type 'boolean)
948
949
950 (defcustom undo-tree-visualizer-lazy-drawing 100
951 "When non-nil, use lazy undo-tree drawing in visualizer.
952
953 Setting this to a number causes the visualizer to switch to lazy
954 drawing when the number of nodes in the tree is larger than this
955 value.
956
957 Lazy drawing means that only the visible portion of the tree will
958 be drawn initially , and the tree will be extended later as
959 needed. For the most part, the only visible effect of this is to
960 significantly speed up displaying the visualizer for very large
961 trees.
962
963 There is one potential negative effect of lazy drawing. Other
964 branches of the tree will only be drawn once the node from which
965 they branch off becomes visible. So it can happen that certain
966 portions of the tree that would be shown with lazy drawing
967 disabled, will not be drawn immediately when it is
968 enabled. However, this effect is quite rare in practice."
969 :group 'undo-tree
970 :type '(choice (const :tag "never" nil)
971 (const :tag "always" t)
972 (integer :tag "> size")))
973
974
975 (defface undo-tree-visualizer-default-face
976 '((((class color)) :foreground "gray"))
977 "Face used to draw undo-tree in visualizer."
978 :group 'undo-tree)
979
980 (defface undo-tree-visualizer-current-face
981 '((((class color)) :foreground "red"))
982 "Face used to highlight current undo-tree node in visualizer."
983 :group 'undo-tree)
984
985 (defface undo-tree-visualizer-active-branch-face
986 '((((class color) (background dark))
987 (:foreground "white" :weight bold))
988 (((class color) (background light))
989 (:foreground "black" :weight bold)))
990 "Face used to highlight active undo-tree branch in visualizer."
991 :group 'undo-tree)
992
993 (defface undo-tree-visualizer-register-face
994 '((((class color)) :foreground "yellow"))
995 "Face used to highlight undo-tree nodes saved to a register
996 in visualizer."
997 :group 'undo-tree)
998
999 (defface undo-tree-visualizer-unmodified-face
1000 '((((class color)) :foreground "cyan"))
1001 "Face used to highlight nodes corresponding to unmodified buffers
1002 in visualizer."
1003 :group 'undo-tree)
1004
1005
1006 (defvar undo-tree-visualizer-parent-buffer nil
1007 "Parent buffer in visualizer.")
1008 (make-variable-buffer-local 'undo-tree-visualizer-parent-buffer)
1009
1010 ;; stores modification time of parent buffer's file, if any
1011 (defvar undo-tree-visualizer-parent-mtime nil)
1012 (make-variable-buffer-local 'undo-tree-visualizer-parent-mtime)
1013
1014 ;; stores current horizontal spacing needed for drawing undo-tree
1015 (defvar undo-tree-visualizer-spacing nil)
1016 (make-variable-buffer-local 'undo-tree-visualizer-spacing)
1017
1018 ;; calculate horizontal spacing required for drawing tree with current
1019 ;; settings
1020 (defsubst undo-tree-visualizer-calculate-spacing ()
1021 (if undo-tree-visualizer-timestamps
1022 (if undo-tree-visualizer-relative-timestamps 9 13)
1023 3))
1024
1025 ;; holds node that was current when visualizer was invoked
1026 (defvar undo-tree-visualizer-initial-node nil)
1027 (make-variable-buffer-local 'undo-tree-visualizer-initial-node)
1028
1029 ;; holds currently selected node in visualizer selection mode
1030 (defvar undo-tree-visualizer-selected-node nil)
1031 (make-variable-buffer-local 'undo-tree-visualizer-selected)
1032
1033 ;; used to store nodes at edge of currently drawn portion of tree
1034 (defvar undo-tree-visualizer-needs-extending-down nil)
1035 (make-variable-buffer-local 'undo-tree-visualizer-needs-extending-down)
1036 (defvar undo-tree-visualizer-needs-extending-up nil)
1037 (make-variable-buffer-local 'undo-tree-visualizer-needs-extending-up)
1038
1039 ;; dynamically bound to t when undoing from visualizer, to inhibit
1040 ;; `undo-tree-kill-visualizer' hook function in parent buffer
1041 (defvar undo-tree-inhibit-kill-visualizer nil)
1042
1043 ;; can be let-bound to a face name, used in drawing functions
1044 (defvar undo-tree-insert-face nil)
1045
1046 ;; visualizer buffer names
1047 (defconst undo-tree-visualizer-buffer-name " *undo-tree*")
1048 (defconst undo-tree-diff-buffer-name "*undo-tree Diff*")
1049
1050 ;; prevent debugger being called on "No further redo information"
1051 (add-to-list 'debug-ignored-errors "^No further redo information")
1052 (add-to-list 'debug-ignored-errors "^No further redo information for region")
1053
1054 ;; install history-auto-save hooks
1055 (add-hook 'write-file-functions 'undo-tree-save-history-hook)
1056 (add-hook 'find-file-hook 'undo-tree-load-history-hook)
1057
1058
1059
1060 \f
1061 ;;; =================================================================
1062 ;;; Default keymaps
1063
1064 (defvar undo-tree-map nil
1065 "Keymap used in undo-tree-mode.")
1066
1067 (unless undo-tree-map
1068 (let ((map (make-sparse-keymap)))
1069 ;; remap `undo' and `undo-only' to `undo-tree-undo'
1070 (define-key map [remap undo] 'undo-tree-undo)
1071 (define-key map [remap undo-only] 'undo-tree-undo)
1072 ;; bind standard undo bindings (since these match redo counterparts)
1073 (define-key map (kbd "C-/") 'undo-tree-undo)
1074 (define-key map "\C-_" 'undo-tree-undo)
1075 ;; redo doesn't exist normally, so define our own keybindings
1076 (define-key map (kbd "C-?") 'undo-tree-redo)
1077 (define-key map (kbd "M-_") 'undo-tree-redo)
1078 ;; just in case something has defined `redo'...
1079 (define-key map [remap redo] 'undo-tree-redo)
1080 ;; we use "C-x u" for the undo-tree visualizer
1081 (define-key map (kbd "\C-x u") 'undo-tree-visualize)
1082 ;; bind register commands
1083 (define-key map (kbd "C-x r u") 'undo-tree-save-state-to-register)
1084 (define-key map (kbd "C-x r U") 'undo-tree-restore-state-from-register)
1085 ;; set keymap
1086 (setq undo-tree-map map)))
1087
1088
1089 (defvar undo-tree-visualizer-map nil
1090 "Keymap used in undo-tree visualizer.")
1091
1092 (unless undo-tree-visualizer-map
1093 (let ((map (make-sparse-keymap)))
1094 ;; vertical motion keys undo/redo
1095 (define-key map [remap previous-line] 'undo-tree-visualize-undo)
1096 (define-key map [remap next-line] 'undo-tree-visualize-redo)
1097 (define-key map [up] 'undo-tree-visualize-undo)
1098 (define-key map "p" 'undo-tree-visualize-undo)
1099 (define-key map "\C-p" 'undo-tree-visualize-undo)
1100 (define-key map [down] 'undo-tree-visualize-redo)
1101 (define-key map "n" 'undo-tree-visualize-redo)
1102 (define-key map "\C-n" 'undo-tree-visualize-redo)
1103 ;; horizontal motion keys switch branch
1104 (define-key map [remap forward-char]
1105 'undo-tree-visualize-switch-branch-right)
1106 (define-key map [remap backward-char]
1107 'undo-tree-visualize-switch-branch-left)
1108 (define-key map [right] 'undo-tree-visualize-switch-branch-right)
1109 (define-key map "f" 'undo-tree-visualize-switch-branch-right)
1110 (define-key map "\C-f" 'undo-tree-visualize-switch-branch-right)
1111 (define-key map [left] 'undo-tree-visualize-switch-branch-left)
1112 (define-key map "b" 'undo-tree-visualize-switch-branch-left)
1113 (define-key map "\C-b" 'undo-tree-visualize-switch-branch-left)
1114 ;; paragraph motion keys undo/redo to significant points in tree
1115 (define-key map [remap backward-paragraph] 'undo-tree-visualize-undo-to-x)
1116 (define-key map [remap forward-paragraph] 'undo-tree-visualize-redo-to-x)
1117 (define-key map "\M-{" 'undo-tree-visualize-undo-to-x)
1118 (define-key map "\M-}" 'undo-tree-visualize-redo-to-x)
1119 (define-key map [C-down] 'undo-tree-visualize-undo-to-x)
1120 (define-key map [C-up] 'undo-tree-visualize-redo-to-x)
1121 ;; mouse sets buffer state to node at click
1122 (define-key map [mouse-1] 'undo-tree-visualizer-mouse-set)
1123 ;; toggle timestamps
1124 (define-key map "t" 'undo-tree-visualizer-toggle-timestamps)
1125 ;; toggle diff
1126 (define-key map "d" 'undo-tree-visualizer-toggle-diff)
1127 ;; selection mode
1128 (define-key map "s" 'undo-tree-visualizer-selection-mode)
1129 ;; horizontal scrolling may be needed if the tree is very wide
1130 (define-key map "," 'undo-tree-visualizer-scroll-left)
1131 (define-key map "." 'undo-tree-visualizer-scroll-right)
1132 (define-key map "<" 'undo-tree-visualizer-scroll-left)
1133 (define-key map ">" 'undo-tree-visualizer-scroll-right)
1134 ;; vertical scrolling may be needed if the tree is very tall
1135 (define-key map [next] 'undo-tree-visualizer-scroll-up)
1136 (define-key map [prior] 'undo-tree-visualizer-scroll-down)
1137 ;; quit/abort visualizer
1138 (define-key map "q" 'undo-tree-visualizer-quit)
1139 (define-key map "\C-q" 'undo-tree-visualizer-abort)
1140 ;; set keymap
1141 (setq undo-tree-visualizer-map map)))
1142
1143
1144 (defvar undo-tree-visualizer-selection-map nil
1145 "Keymap used in undo-tree visualizer selection mode.")
1146
1147 (unless undo-tree-visualizer-selection-map
1148 (let ((map (make-sparse-keymap)))
1149 ;; vertical motion keys move up and down tree
1150 (define-key map [remap previous-line]
1151 'undo-tree-visualizer-select-previous)
1152 (define-key map [remap next-line]
1153 'undo-tree-visualizer-select-next)
1154 (define-key map [up] 'undo-tree-visualizer-select-previous)
1155 (define-key map "p" 'undo-tree-visualizer-select-previous)
1156 (define-key map "\C-p" 'undo-tree-visualizer-select-previous)
1157 (define-key map [down] 'undo-tree-visualizer-select-next)
1158 (define-key map "n" 'undo-tree-visualizer-select-next)
1159 (define-key map "\C-n" 'undo-tree-visualizer-select-next)
1160 ;; vertical scroll keys move up and down quickly
1161 (define-key map [next]
1162 (lambda () (interactive) (undo-tree-visualizer-select-next 10)))
1163 (define-key map [prior]
1164 (lambda () (interactive) (undo-tree-visualizer-select-previous 10)))
1165 ;; horizontal motion keys move to left and right siblings
1166 (define-key map [remap forward-char] 'undo-tree-visualizer-select-right)
1167 (define-key map [remap backward-char] 'undo-tree-visualizer-select-left)
1168 (define-key map [right] 'undo-tree-visualizer-select-right)
1169 (define-key map "f" 'undo-tree-visualizer-select-right)
1170 (define-key map "\C-f" 'undo-tree-visualizer-select-right)
1171 (define-key map [left] 'undo-tree-visualizer-select-left)
1172 (define-key map "b" 'undo-tree-visualizer-select-left)
1173 (define-key map "\C-b" 'undo-tree-visualizer-select-left)
1174 ;; horizontal scroll keys move left or right quickly
1175 (define-key map ","
1176 (lambda () (interactive) (undo-tree-visualizer-select-left 10)))
1177 (define-key map "."
1178 (lambda () (interactive) (undo-tree-visualizer-select-right 10)))
1179 (define-key map "<"
1180 (lambda () (interactive) (undo-tree-visualizer-select-left 10)))
1181 (define-key map ">"
1182 (lambda () (interactive) (undo-tree-visualizer-select-right 10)))
1183 ;; mouse or <enter> sets buffer state to node at point/click
1184 (define-key map "\r" 'undo-tree-visualizer-set)
1185 (define-key map [mouse-1] 'undo-tree-visualizer-mouse-set)
1186 ;; toggle timestamps
1187 (define-key map "t" 'undo-tree-visualizer-toggle-timestamps)
1188 ;; toggle diff
1189 (define-key map "d" 'undo-tree-visualizer-selection-toggle-diff)
1190 ;; quit visualizer selection mode
1191 (define-key map "s" 'undo-tree-visualizer-mode)
1192 ;; quit visualizer
1193 (define-key map "q" 'undo-tree-visualizer-quit)
1194 (define-key map "\C-q" 'undo-tree-visualizer-abort)
1195 ;; set keymap
1196 (setq undo-tree-visualizer-selection-map map)))
1197
1198
1199
1200 \f
1201 ;;; =====================================================================
1202 ;;; Undo-tree data structure
1203
1204 (defstruct
1205 (undo-tree
1206 :named
1207 (:constructor nil)
1208 (:constructor make-undo-tree
1209 (&aux
1210 (root (undo-tree-make-node nil nil))
1211 (current root)
1212 (size 0)
1213 (count 0)
1214 (object-pool (make-hash-table :test 'eq :weakness 'value))))
1215 ;;(:copier nil)
1216 )
1217 root current size count object-pool)
1218
1219
1220
1221 (defstruct
1222 (undo-tree-node
1223 (:type vector) ; create unnamed struct
1224 (:constructor nil)
1225 (:constructor undo-tree-make-node
1226 (previous undo
1227 &optional redo
1228 &aux
1229 (timestamp (current-time))
1230 (branch 0)))
1231 (:constructor undo-tree-make-node-backwards
1232 (next-node undo
1233 &optional redo
1234 &aux
1235 (next (list next-node))
1236 (timestamp (current-time))
1237 (branch 0)))
1238 (:copier nil))
1239 previous next undo redo timestamp branch meta-data)
1240
1241
1242 (defmacro undo-tree-node-p (n)
1243 (let ((len (length (undo-tree-make-node nil nil))))
1244 `(and (vectorp ,n) (= (length ,n) ,len))))
1245
1246
1247
1248 (defstruct
1249 (undo-tree-region-data
1250 (:type vector) ; create unnamed struct
1251 (:constructor nil)
1252 (:constructor undo-tree-make-region-data
1253 (&optional undo-beginning undo-end
1254 redo-beginning redo-end))
1255 (:constructor undo-tree-make-undo-region-data
1256 (undo-beginning undo-end))
1257 (:constructor undo-tree-make-redo-region-data
1258 (redo-beginning redo-end))
1259 (:copier nil))
1260 undo-beginning undo-end redo-beginning redo-end)
1261
1262
1263 (defmacro undo-tree-region-data-p (r)
1264 (let ((len (length (undo-tree-make-region-data))))
1265 `(and (vectorp ,r) (= (length ,r) ,len))))
1266
1267 (defmacro undo-tree-node-clear-region-data (node)
1268 `(setf (undo-tree-node-meta-data ,node)
1269 (delq nil
1270 (delq :region
1271 (plist-put (undo-tree-node-meta-data ,node)
1272 :region nil)))))
1273
1274
1275 (defmacro undo-tree-node-undo-beginning (node)
1276 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1277 (when (undo-tree-region-data-p r)
1278 (undo-tree-region-data-undo-beginning r))))
1279
1280 (defmacro undo-tree-node-undo-end (node)
1281 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1282 (when (undo-tree-region-data-p r)
1283 (undo-tree-region-data-undo-end r))))
1284
1285 (defmacro undo-tree-node-redo-beginning (node)
1286 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1287 (when (undo-tree-region-data-p r)
1288 (undo-tree-region-data-redo-beginning r))))
1289
1290 (defmacro undo-tree-node-redo-end (node)
1291 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1292 (when (undo-tree-region-data-p r)
1293 (undo-tree-region-data-redo-end r))))
1294
1295
1296 (defsetf undo-tree-node-undo-beginning (node) (val)
1297 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1298 (unless (undo-tree-region-data-p r)
1299 (setf (undo-tree-node-meta-data ,node)
1300 (plist-put (undo-tree-node-meta-data ,node) :region
1301 (setq r (undo-tree-make-region-data)))))
1302 (setf (undo-tree-region-data-undo-beginning r) ,val)))
1303
1304 (defsetf undo-tree-node-undo-end (node) (val)
1305 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1306 (unless (undo-tree-region-data-p r)
1307 (setf (undo-tree-node-meta-data ,node)
1308 (plist-put (undo-tree-node-meta-data ,node) :region
1309 (setq r (undo-tree-make-region-data)))))
1310 (setf (undo-tree-region-data-undo-end r) ,val)))
1311
1312 (defsetf undo-tree-node-redo-beginning (node) (val)
1313 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1314 (unless (undo-tree-region-data-p r)
1315 (setf (undo-tree-node-meta-data ,node)
1316 (plist-put (undo-tree-node-meta-data ,node) :region
1317 (setq r (undo-tree-make-region-data)))))
1318 (setf (undo-tree-region-data-redo-beginning r) ,val)))
1319
1320 (defsetf undo-tree-node-redo-end (node) (val)
1321 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1322 (unless (undo-tree-region-data-p r)
1323 (setf (undo-tree-node-meta-data ,node)
1324 (plist-put (undo-tree-node-meta-data ,node) :region
1325 (setq r (undo-tree-make-region-data)))))
1326 (setf (undo-tree-region-data-redo-end r) ,val)))
1327
1328
1329
1330 (defstruct
1331 (undo-tree-visualizer-data
1332 (:type vector) ; create unnamed struct
1333 (:constructor nil)
1334 (:constructor undo-tree-make-visualizer-data
1335 (&optional lwidth cwidth rwidth marker))
1336 (:copier nil))
1337 lwidth cwidth rwidth marker)
1338
1339
1340 (defmacro undo-tree-visualizer-data-p (v)
1341 (let ((len (length (undo-tree-make-visualizer-data))))
1342 `(and (vectorp ,v) (= (length ,v) ,len))))
1343
1344 (defun undo-tree-node-clear-visualizer-data (node)
1345 (let ((plist (undo-tree-node-meta-data node)))
1346 (if (eq (car plist) :visualizer)
1347 (setf (undo-tree-node-meta-data node) (nthcdr 2 plist))
1348 (while (and plist (not (eq (cadr plist) :visualizer)))
1349 (setq plist (cdr plist)))
1350 (if plist (setcdr plist (nthcdr 3 plist))))))
1351
1352 (defmacro undo-tree-node-lwidth (node)
1353 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1354 (when (undo-tree-visualizer-data-p v)
1355 (undo-tree-visualizer-data-lwidth v))))
1356
1357 (defmacro undo-tree-node-cwidth (node)
1358 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1359 (when (undo-tree-visualizer-data-p v)
1360 (undo-tree-visualizer-data-cwidth v))))
1361
1362 (defmacro undo-tree-node-rwidth (node)
1363 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1364 (when (undo-tree-visualizer-data-p v)
1365 (undo-tree-visualizer-data-rwidth v))))
1366
1367 (defmacro undo-tree-node-marker (node)
1368 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1369 (when (undo-tree-visualizer-data-p v)
1370 (undo-tree-visualizer-data-marker v))))
1371
1372
1373 (defsetf undo-tree-node-lwidth (node) (val)
1374 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1375 (unless (undo-tree-visualizer-data-p v)
1376 (setf (undo-tree-node-meta-data ,node)
1377 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1378 (setq v (undo-tree-make-visualizer-data)))))
1379 (setf (undo-tree-visualizer-data-lwidth v) ,val)))
1380
1381 (defsetf undo-tree-node-cwidth (node) (val)
1382 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1383 (unless (undo-tree-visualizer-data-p v)
1384 (setf (undo-tree-node-meta-data ,node)
1385 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1386 (setq v (undo-tree-make-visualizer-data)))))
1387 (setf (undo-tree-visualizer-data-cwidth v) ,val)))
1388
1389 (defsetf undo-tree-node-rwidth (node) (val)
1390 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1391 (unless (undo-tree-visualizer-data-p v)
1392 (setf (undo-tree-node-meta-data ,node)
1393 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1394 (setq v (undo-tree-make-visualizer-data)))))
1395 (setf (undo-tree-visualizer-data-rwidth v) ,val)))
1396
1397 (defsetf undo-tree-node-marker (node) (val)
1398 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1399 (unless (undo-tree-visualizer-data-p v)
1400 (setf (undo-tree-node-meta-data ,node)
1401 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1402 (setq v (undo-tree-make-visualizer-data)))))
1403 (setf (undo-tree-visualizer-data-marker v) ,val)))
1404
1405
1406
1407 (defstruct
1408 (undo-tree-register-data
1409 (:type vector)
1410 (:constructor nil)
1411 (:constructor undo-tree-make-register-data (buffer node)))
1412 buffer node)
1413
1414 (defun undo-tree-register-data-p (data)
1415 (and (vectorp data)
1416 (= (length data) 2)
1417 (undo-tree-node-p (undo-tree-register-data-node data))))
1418
1419 (defun undo-tree-register-data-print-func (data)
1420 (princ (format "an undo-tree state for buffer %s"
1421 (undo-tree-register-data-buffer data))))
1422
1423 (defmacro undo-tree-node-register (node)
1424 `(plist-get (undo-tree-node-meta-data ,node) :register))
1425
1426 (defsetf undo-tree-node-register (node) (val)
1427 `(setf (undo-tree-node-meta-data ,node)
1428 (plist-put (undo-tree-node-meta-data ,node) :register ,val)))
1429
1430
1431
1432 \f
1433 ;;; =====================================================================
1434 ;;; Basic undo-tree data structure functions
1435
1436 (defun undo-tree-grow (undo)
1437 "Add an UNDO node to current branch of `buffer-undo-tree'."
1438 (let* ((current (undo-tree-current buffer-undo-tree))
1439 (new (undo-tree-make-node current undo)))
1440 (push new (undo-tree-node-next current))
1441 (setf (undo-tree-current buffer-undo-tree) new)))
1442
1443
1444 (defun undo-tree-grow-backwards (node undo &optional redo)
1445 "Add new node *above* undo-tree NODE, and return new node.
1446 Note that this will overwrite NODE's \"previous\" link, so should
1447 only be used on a detached NODE, never on nodes that are already
1448 part of `buffer-undo-tree'."
1449 (let ((new (undo-tree-make-node-backwards node undo redo)))
1450 (setf (undo-tree-node-previous node) new)
1451 new))
1452
1453
1454 (defun undo-tree-splice-node (node splice)
1455 "Splice NODE into undo tree, below node SPLICE.
1456 Note that this will overwrite NODE's \"next\" and \"previous\"
1457 links, so should only be used on a detached NODE, never on nodes
1458 that are already part of `buffer-undo-tree'."
1459 (setf (undo-tree-node-next node) (undo-tree-node-next splice)
1460 (undo-tree-node-branch node) (undo-tree-node-branch splice)
1461 (undo-tree-node-previous node) splice
1462 (undo-tree-node-next splice) (list node)
1463 (undo-tree-node-branch splice) 0)
1464 (dolist (n (undo-tree-node-next node))
1465 (setf (undo-tree-node-previous n) node)))
1466
1467
1468 (defun undo-tree-snip-node (node)
1469 "Snip NODE out of undo tree."
1470 (let* ((parent (undo-tree-node-previous node))
1471 position p)
1472 ;; if NODE is only child, replace parent's next links with NODE's
1473 (if (= (length (undo-tree-node-next parent)) 0)
1474 (setf (undo-tree-node-next parent) (undo-tree-node-next node)
1475 (undo-tree-node-branch parent) (undo-tree-node-branch node))
1476 ;; otherwise...
1477 (setq position (undo-tree-position node (undo-tree-node-next parent)))
1478 (cond
1479 ;; if active branch used do go via NODE, set parent's branch to active
1480 ;; branch of NODE
1481 ((= (undo-tree-node-branch parent) position)
1482 (setf (undo-tree-node-branch parent)
1483 (+ position (undo-tree-node-branch node))))
1484 ;; if active branch didn't go via NODE, update parent's branch to point
1485 ;; to same node as before
1486 ((> (undo-tree-node-branch parent) position)
1487 (incf (undo-tree-node-branch parent)
1488 (1- (length (undo-tree-node-next node))))))
1489 ;; replace NODE in parent's next list with NODE's entire next list
1490 (if (= position 0)
1491 (setf (undo-tree-node-next parent)
1492 (nconc (undo-tree-node-next node)
1493 (cdr (undo-tree-node-next parent))))
1494 (setq p (nthcdr (1- position) (undo-tree-node-next parent)))
1495 (setcdr p (nconc (undo-tree-node-next node) (cddr p)))))
1496 ;; update previous links of NODE's children
1497 (dolist (n (undo-tree-node-next node))
1498 (setf (undo-tree-node-previous n) parent))))
1499
1500
1501 (defun undo-tree-mapc (--undo-tree-mapc-function-- node)
1502 ;; Apply FUNCTION to NODE and to each node below it.
1503 (let ((stack (list node))
1504 n)
1505 (while stack
1506 (setq n (pop stack))
1507 (funcall --undo-tree-mapc-function-- n)
1508 (setq stack (append (undo-tree-node-next n) stack)))))
1509
1510
1511 (defmacro undo-tree-num-branches ()
1512 "Return number of branches at current undo tree node."
1513 '(length (undo-tree-node-next (undo-tree-current buffer-undo-tree))))
1514
1515
1516 (defun undo-tree-position (node list)
1517 "Find the first occurrence of NODE in LIST.
1518 Return the index of the matching item, or nil of not found.
1519 Comparison is done with `eq'."
1520 (let ((i 0))
1521 (catch 'found
1522 (while (progn
1523 (when (eq node (car list)) (throw 'found i))
1524 (incf i)
1525 (setq list (cdr list))))
1526 nil)))
1527
1528
1529 (defvar *undo-tree-id-counter* 0)
1530 (make-variable-buffer-local '*undo-tree-id-counter*)
1531
1532 (defmacro undo-tree-generate-id ()
1533 ;; Generate a new, unique id (uninterned symbol).
1534 ;; The name is made by appending a number to "undo-tree-id".
1535 ;; (Copied from CL package `gensym'.)
1536 `(let ((num (prog1 *undo-tree-id-counter* (incf *undo-tree-id-counter*))))
1537 (make-symbol (format "undo-tree-id%d" num))))
1538
1539
1540 (defun undo-tree-decircle (undo-tree)
1541 ;; Nullify PREVIOUS links of UNDO-TREE nodes, to make UNDO-TREE data
1542 ;; structure non-circular.
1543 (undo-tree-mapc
1544 (lambda (node)
1545 (dolist (n (undo-tree-node-next node))
1546 (setf (undo-tree-node-previous n) nil)))
1547 (undo-tree-root undo-tree)))
1548
1549
1550 (defun undo-tree-recircle (undo-tree)
1551 ;; Recreate PREVIOUS links of UNDO-TREE nodes, to restore circular UNDO-TREE
1552 ;; data structure.
1553 (undo-tree-mapc
1554 (lambda (node)
1555 (dolist (n (undo-tree-node-next node))
1556 (setf (undo-tree-node-previous n) node)))
1557 (undo-tree-root undo-tree)))
1558
1559
1560
1561 \f
1562 ;;; =====================================================================
1563 ;;; Undo list and undo changeset utility functions
1564
1565 (defmacro undo-list-marker-elt-p (elt)
1566 `(markerp (car-safe ,elt)))
1567
1568 (defmacro undo-list-GCd-marker-elt-p (elt)
1569 ;; Return t if ELT is a marker element whose marker has been moved to the
1570 ;; object-pool, so may potentially have been garbage-collected.
1571 ;; Note: Valid marker undo elements should be uniquely identified as cons
1572 ;; cells with a symbol in the car (replacing the marker), and a number in
1573 ;; the cdr. However, to guard against future changes to undo element
1574 ;; formats, we perform an additional redundant check on the symbol name.
1575 `(and (car-safe ,elt)
1576 (symbolp (car ,elt))
1577 (let ((str (symbol-name (car ,elt))))
1578 (and (> (length str) 12)
1579 (string= (substring str 0 12) "undo-tree-id")))
1580 (numberp (cdr-safe ,elt))))
1581
1582
1583 (defun undo-tree-move-GC-elts-to-pool (elt)
1584 ;; Move elements that can be garbage-collected into `buffer-undo-tree'
1585 ;; object pool, substituting a unique id that can be used to retrieve them
1586 ;; later. (Only markers require this treatment currently.)
1587 (when (undo-list-marker-elt-p elt)
1588 (let ((id (undo-tree-generate-id)))
1589 (puthash id (car elt) (undo-tree-object-pool buffer-undo-tree))
1590 (setcar elt id))))
1591
1592
1593 (defun undo-tree-restore-GC-elts-from-pool (elt)
1594 ;; Replace object id's in ELT with corresponding objects from
1595 ;; `buffer-undo-tree' object pool and return modified ELT, or return nil if
1596 ;; any object in ELT has been garbage-collected.
1597 (if (undo-list-GCd-marker-elt-p elt)
1598 (when (setcar elt (gethash (car elt)
1599 (undo-tree-object-pool buffer-undo-tree)))
1600 elt)
1601 elt))
1602
1603
1604 (defun undo-list-clean-GCd-elts (undo-list)
1605 ;; Remove object id's from UNDO-LIST that refer to elements that have been
1606 ;; garbage-collected. UNDO-LIST is modified by side-effect.
1607 (while (undo-list-GCd-marker-elt-p (car undo-list))
1608 (unless (gethash (caar undo-list)
1609 (undo-tree-object-pool buffer-undo-tree))
1610 (setq undo-list (cdr undo-list))))
1611 (let ((p undo-list))
1612 (while (cdr p)
1613 (when (and (undo-list-GCd-marker-elt-p (cadr p))
1614 (null (gethash (car (cadr p))
1615 (undo-tree-object-pool buffer-undo-tree))))
1616 (setcdr p (cddr p)))
1617 (setq p (cdr p))))
1618 undo-list)
1619
1620
1621 (defun undo-list-pop-changeset (&optional discard-pos)
1622 ;; Pop changeset from `buffer-undo-list'. If DISCARD-POS is non-nil, discard
1623 ;; any position entries from changeset.
1624
1625 ;; discard undo boundaries and (if DISCARD-POS is non-nil) position entries
1626 ;; at head of undo list
1627 (while (or (null (car buffer-undo-list))
1628 (and discard-pos (integerp (car buffer-undo-list))))
1629 (setq buffer-undo-list (cdr buffer-undo-list)))
1630 ;; pop elements up to next undo boundary, discarding position entries if
1631 ;; DISCARD-POS is non-nil
1632 (if (eq (car buffer-undo-list) 'undo-tree-canary)
1633 (push nil buffer-undo-list)
1634 (let* ((changeset (list (pop buffer-undo-list)))
1635 (p changeset))
1636 (while (progn
1637 (undo-tree-move-GC-elts-to-pool (car p))
1638 (while (and discard-pos (integerp (car buffer-undo-list)))
1639 (setq buffer-undo-list (cdr buffer-undo-list)))
1640 (and (car buffer-undo-list)
1641 (not (eq (car buffer-undo-list) 'undo-tree-canary))))
1642 (setcdr p (list (pop buffer-undo-list)))
1643 (setq p (cdr p)))
1644 changeset)))
1645
1646
1647 (defun undo-tree-copy-list (undo-list)
1648 ;; Return a deep copy of first changeset in `undo-list'. Object id's are
1649 ;; replaced by corresponding objects from `buffer-undo-tree' object-pool.
1650 (when undo-list
1651 (let (copy p)
1652 ;; if first element contains an object id, replace it with object from
1653 ;; pool, discarding element entirely if it's been GC'd
1654 (while (null copy)
1655 (setq copy
1656 (undo-tree-restore-GC-elts-from-pool (pop undo-list))))
1657 (setq copy (list copy)
1658 p copy)
1659 ;; copy remaining elements, replacing object id's with objects from
1660 ;; pool, or discarding them entirely if they've been GC'd
1661 (while undo-list
1662 (when (setcdr p (undo-tree-restore-GC-elts-from-pool
1663 (undo-copy-list-1 (pop undo-list))))
1664 (setcdr p (list (cdr p)))
1665 (setq p (cdr p))))
1666 copy)))
1667
1668
1669
1670 (defun undo-list-transfer-to-tree ()
1671 ;; Transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'.
1672
1673 ;; `undo-list-transfer-to-tree' should never be called when undo is disabled
1674 ;; (i.e. `buffer-undo-tree' is t)
1675 (assert (not (eq buffer-undo-tree t)))
1676
1677 ;; if `buffer-undo-tree' is empty, create initial undo-tree
1678 (when (null buffer-undo-tree) (setq buffer-undo-tree (make-undo-tree)))
1679 ;; make sure there's a canary at end of `buffer-undo-list'
1680 (when (null buffer-undo-list)
1681 (setq buffer-undo-list '(nil undo-tree-canary)))
1682
1683 (unless (or (eq (cadr buffer-undo-list) 'undo-tree-canary)
1684 (eq (car buffer-undo-list) 'undo-tree-canary))
1685 ;; create new node from first changeset in `buffer-undo-list', save old
1686 ;; `buffer-undo-tree' current node, and make new node the current node
1687 (let* ((node (undo-tree-make-node nil (undo-list-pop-changeset)))
1688 (splice (undo-tree-current buffer-undo-tree))
1689 (size (undo-list-byte-size (undo-tree-node-undo node)))
1690 (count 1))
1691 (setf (undo-tree-current buffer-undo-tree) node)
1692 ;; grow tree fragment backwards using `buffer-undo-list' changesets
1693 (while (and buffer-undo-list
1694 (not (eq (cadr buffer-undo-list) 'undo-tree-canary)))
1695 (setq node
1696 (undo-tree-grow-backwards node (undo-list-pop-changeset)))
1697 (incf size (undo-list-byte-size (undo-tree-node-undo node)))
1698 (incf count))
1699 ;; if no undo history has been discarded from `buffer-undo-list' since
1700 ;; last transfer, splice new tree fragment onto end of old
1701 ;; `buffer-undo-tree' current node
1702 (if (or (eq (cadr buffer-undo-list) 'undo-tree-canary)
1703 (eq (car buffer-undo-list) 'undo-tree-canary))
1704 (progn
1705 (setf (undo-tree-node-previous node) splice)
1706 (push node (undo-tree-node-next splice))
1707 (setf (undo-tree-node-branch splice) 0)
1708 (incf (undo-tree-size buffer-undo-tree) size)
1709 (incf (undo-tree-count buffer-undo-tree) count))
1710 ;; if undo history has been discarded, replace entire
1711 ;; `buffer-undo-tree' with new tree fragment
1712 (setq node (undo-tree-grow-backwards node nil))
1713 (setf (undo-tree-root buffer-undo-tree) node)
1714 (setq buffer-undo-list '(nil undo-tree-canary))
1715 (setf (undo-tree-size buffer-undo-tree) size)
1716 (setf (undo-tree-count buffer-undo-tree) count)
1717 (setq buffer-undo-list '(nil undo-tree-canary))))
1718 ;; discard undo history if necessary
1719 (undo-tree-discard-history)))
1720
1721
1722 (defun undo-list-byte-size (undo-list)
1723 ;; Return size (in bytes) of UNDO-LIST
1724 (let ((size 0) (p undo-list))
1725 (while p
1726 (incf size 8) ; cons cells use up 8 bytes
1727 (when (and (consp (car p)) (stringp (caar p)))
1728 (incf size (string-bytes (caar p))))
1729 (setq p (cdr p)))
1730 size))
1731
1732
1733
1734 (defun undo-list-rebuild-from-tree ()
1735 "Rebuild `buffer-undo-list' from information in `buffer-undo-tree'."
1736 (unless (eq buffer-undo-list t)
1737 (undo-list-transfer-to-tree)
1738 (setq buffer-undo-list nil)
1739 (when buffer-undo-tree
1740 (let ((stack (list (list (undo-tree-root buffer-undo-tree)))))
1741 (push (sort (mapcar 'identity (undo-tree-node-next (caar stack)))
1742 (lambda (a b)
1743 (time-less-p (undo-tree-node-timestamp a)
1744 (undo-tree-node-timestamp b))))
1745 stack)
1746 ;; Traverse tree in depth-and-oldest-first order, but add undo records
1747 ;; on the way down, and redo records on the way up.
1748 (while (or (car stack)
1749 (not (eq (car (nth 1 stack))
1750 (undo-tree-current buffer-undo-tree))))
1751 (if (car stack)
1752 (progn
1753 (setq buffer-undo-list
1754 (append (undo-tree-node-undo (caar stack))
1755 buffer-undo-list))
1756 (undo-boundary)
1757 (push (sort (mapcar 'identity
1758 (undo-tree-node-next (caar stack)))
1759 (lambda (a b)
1760 (time-less-p (undo-tree-node-timestamp a)
1761 (undo-tree-node-timestamp b))))
1762 stack))
1763 (pop stack)
1764 (setq buffer-undo-list
1765 (append (undo-tree-node-redo (caar stack))
1766 buffer-undo-list))
1767 (undo-boundary)
1768 (pop (car stack))))))))
1769
1770
1771
1772 \f
1773 ;;; =====================================================================
1774 ;;; History discarding utility functions
1775
1776 (defun undo-tree-oldest-leaf (node)
1777 ;; Return oldest leaf node below NODE.
1778 (while (undo-tree-node-next node)
1779 (setq node
1780 (car (sort (mapcar 'identity (undo-tree-node-next node))
1781 (lambda (a b)
1782 (time-less-p (undo-tree-node-timestamp a)
1783 (undo-tree-node-timestamp b)))))))
1784 node)
1785
1786
1787 (defun undo-tree-discard-node (node)
1788 ;; Discard NODE from `buffer-undo-tree', and return next in line for
1789 ;; discarding.
1790
1791 ;; don't discard current node
1792 (unless (eq node (undo-tree-current buffer-undo-tree))
1793
1794 ;; discarding root node...
1795 (if (eq node (undo-tree-root buffer-undo-tree))
1796 (cond
1797 ;; should always discard branches before root
1798 ((> (length (undo-tree-node-next node)) 1)
1799 (error "Trying to discard undo-tree root which still\
1800 has multiple branches"))
1801 ;; don't discard root if current node is only child
1802 ((eq (car (undo-tree-node-next node))
1803 (undo-tree-current buffer-undo-tree))
1804 nil)
1805 ;; discard root
1806 (t
1807 ;; clear any register referring to root
1808 (let ((r (undo-tree-node-register node)))
1809 (when (and r (eq (get-register r) node))
1810 (set-register r nil)))
1811 ;; make child of root into new root
1812 (setq node (setf (undo-tree-root buffer-undo-tree)
1813 (car (undo-tree-node-next node))))
1814 ;; update undo-tree size
1815 (decf (undo-tree-size buffer-undo-tree)
1816 (+ (undo-list-byte-size (undo-tree-node-undo node))
1817 (undo-list-byte-size (undo-tree-node-redo node))))
1818 (decf (undo-tree-count buffer-undo-tree))
1819 ;; discard new root's undo data and PREVIOUS link
1820 (setf (undo-tree-node-undo node) nil
1821 (undo-tree-node-redo node) nil
1822 (undo-tree-node-previous node) nil)
1823 ;; if new root has branches, or new root is current node, next node
1824 ;; to discard is oldest leaf, otherwise it's new root
1825 (if (or (> (length (undo-tree-node-next node)) 1)
1826 (eq (car (undo-tree-node-next node))
1827 (undo-tree-current buffer-undo-tree)))
1828 (undo-tree-oldest-leaf node)
1829 node)))
1830
1831 ;; discarding leaf node...
1832 (let* ((parent (undo-tree-node-previous node))
1833 (current (nth (undo-tree-node-branch parent)
1834 (undo-tree-node-next parent))))
1835 ;; clear any register referring to the discarded node
1836 (let ((r (undo-tree-node-register node)))
1837 (when (and r (eq (get-register r) node))
1838 (set-register r nil)))
1839 ;; update undo-tree size
1840 (decf (undo-tree-size buffer-undo-tree)
1841 (+ (undo-list-byte-size (undo-tree-node-undo node))
1842 (undo-list-byte-size (undo-tree-node-redo node))))
1843 (decf (undo-tree-count buffer-undo-tree))
1844 ;; discard leaf
1845 (setf (undo-tree-node-next parent)
1846 (delq node (undo-tree-node-next parent))
1847 (undo-tree-node-branch parent)
1848 (undo-tree-position current (undo-tree-node-next parent)))
1849 ;; if parent has branches, or parent is current node, next node to
1850 ;; discard is oldest leaf, otherwise it's the parent itself
1851 (if (or (eq parent (undo-tree-current buffer-undo-tree))
1852 (and (undo-tree-node-next parent)
1853 (or (not (eq parent (undo-tree-root buffer-undo-tree)))
1854 (> (length (undo-tree-node-next parent)) 1))))
1855 (undo-tree-oldest-leaf parent)
1856 parent)))))
1857
1858
1859
1860 (defun undo-tree-discard-history ()
1861 "Discard undo history until we're within memory usage limits
1862 set by `undo-limit', `undo-strong-limit' and `undo-outer-limit'."
1863
1864 (when (> (undo-tree-size buffer-undo-tree) undo-limit)
1865 ;; if there are no branches off root, first node to discard is root;
1866 ;; otherwise it's leaf node at botom of oldest branch
1867 (let ((node (if (> (length (undo-tree-node-next
1868 (undo-tree-root buffer-undo-tree))) 1)
1869 (undo-tree-oldest-leaf (undo-tree-root buffer-undo-tree))
1870 (undo-tree-root buffer-undo-tree))))
1871
1872 ;; discard nodes until memory use is within `undo-strong-limit'
1873 (while (and node
1874 (> (undo-tree-size buffer-undo-tree) undo-strong-limit))
1875 (setq node (undo-tree-discard-node node)))
1876
1877 ;; discard nodes until next node to discard would bring memory use
1878 ;; within `undo-limit'
1879 (while (and node
1880 ;; check first if last discard has brought us within
1881 ;; `undo-limit', in case we can avoid more expensive
1882 ;; `undo-strong-limit' calculation
1883 ;; Note: this assumes undo-strong-limit > undo-limit;
1884 ;; if not, effectively undo-strong-limit = undo-limit
1885 (> (undo-tree-size buffer-undo-tree) undo-limit)
1886 (> (- (undo-tree-size buffer-undo-tree)
1887 ;; if next node to discard is root, the memory we
1888 ;; free-up comes from discarding changesets from its
1889 ;; only child...
1890 (if (eq node (undo-tree-root buffer-undo-tree))
1891 (+ (undo-list-byte-size
1892 (undo-tree-node-undo
1893 (car (undo-tree-node-next node))))
1894 (undo-list-byte-size
1895 (undo-tree-node-redo
1896 (car (undo-tree-node-next node)))))
1897 ;; ...otherwise, it comes from discarding changesets
1898 ;; from along with the node itself
1899 (+ (undo-list-byte-size (undo-tree-node-undo node))
1900 (undo-list-byte-size (undo-tree-node-redo node)))
1901 ))
1902 undo-limit))
1903 (setq node (undo-tree-discard-node node)))
1904
1905 ;; if we're still over the `undo-outer-limit', discard entire history
1906 (when (> (undo-tree-size buffer-undo-tree) undo-outer-limit)
1907 ;; query first if `undo-ask-before-discard' is set
1908 (if undo-ask-before-discard
1909 (when (yes-or-no-p
1910 (format
1911 "Buffer `%s' undo info is %d bytes long; discard it? "
1912 (buffer-name) (undo-tree-size buffer-undo-tree)))
1913 (setq buffer-undo-tree nil))
1914 ;; otherwise, discard and display warning
1915 (display-warning
1916 '(undo discard-info)
1917 (concat
1918 (format "Buffer `%s' undo info was %d bytes long.\n"
1919 (buffer-name) (undo-tree-size buffer-undo-tree))
1920 "The undo info was discarded because it exceeded\
1921 `undo-outer-limit'.
1922
1923 This is normal if you executed a command that made a huge change
1924 to the buffer. In that case, to prevent similar problems in the
1925 future, set `undo-outer-limit' to a value that is large enough to
1926 cover the maximum size of normal changes you expect a single
1927 command to make, but not so large that it might exceed the
1928 maximum memory allotted to Emacs.
1929
1930 If you did not execute any such command, the situation is
1931 probably due to a bug and you should report it.
1932
1933 You can disable the popping up of this buffer by adding the entry
1934 \(undo discard-info) to the user option `warning-suppress-types',
1935 which is defined in the `warnings' library.\n")
1936 :warning)
1937 (setq buffer-undo-tree nil)))
1938 )))
1939
1940
1941
1942 \f
1943 ;;; =====================================================================
1944 ;;; Visualizer utility functions
1945
1946 (defun undo-tree-compute-widths (node)
1947 "Recursively compute widths for nodes below NODE."
1948 (let ((stack (list node))
1949 res)
1950 (while stack
1951 ;; try to compute widths for node at top of stack
1952 (if (undo-tree-node-p
1953 (setq res (undo-tree-node-compute-widths (car stack))))
1954 ;; if computation fails, it returns a node whose widths still need
1955 ;; computing, which we push onto the stack
1956 (push res stack)
1957 ;; otherwise, store widths and remove it from stack
1958 (setf (undo-tree-node-lwidth (car stack)) (aref res 0)
1959 (undo-tree-node-cwidth (car stack)) (aref res 1)
1960 (undo-tree-node-rwidth (car stack)) (aref res 2))
1961 (pop stack)))))
1962
1963
1964 (defun undo-tree-node-compute-widths (node)
1965 ;; Compute NODE's left-, centre-, and right-subtree widths. Returns widths
1966 ;; (in a vector) if successful. Otherwise, returns a node whose widths need
1967 ;; calculating before NODE's can be calculated.
1968 (let ((num-children (length (undo-tree-node-next node)))
1969 (lwidth 0) (cwidth 0) (rwidth 0) p)
1970 (catch 'need-widths
1971 (cond
1972 ;; leaf nodes have 0 width
1973 ((= 0 num-children)
1974 (setf cwidth 1
1975 (undo-tree-node-lwidth node) 0
1976 (undo-tree-node-cwidth node) 1
1977 (undo-tree-node-rwidth node) 0))
1978
1979 ;; odd number of children
1980 ((= (mod num-children 2) 1)
1981 (setq p (undo-tree-node-next node))
1982 ;; compute left-width
1983 (dotimes (i (/ num-children 2))
1984 (if (undo-tree-node-lwidth (car p))
1985 (incf lwidth (+ (undo-tree-node-lwidth (car p))
1986 (undo-tree-node-cwidth (car p))
1987 (undo-tree-node-rwidth (car p))))
1988 ;; if child's widths haven't been computed, return that child
1989 (throw 'need-widths (car p)))
1990 (setq p (cdr p)))
1991 (if (undo-tree-node-lwidth (car p))
1992 (incf lwidth (undo-tree-node-lwidth (car p)))
1993 (throw 'need-widths (car p)))
1994 ;; centre-width is inherited from middle child
1995 (setf cwidth (undo-tree-node-cwidth (car p)))
1996 ;; compute right-width
1997 (incf rwidth (undo-tree-node-rwidth (car p)))
1998 (setq p (cdr p))
1999 (dotimes (i (/ num-children 2))
2000 (if (undo-tree-node-lwidth (car p))
2001 (incf rwidth (+ (undo-tree-node-lwidth (car p))
2002 (undo-tree-node-cwidth (car p))
2003 (undo-tree-node-rwidth (car p))))
2004 (throw 'need-widths (car p)))
2005 (setq p (cdr p))))
2006
2007 ;; even number of children
2008 (t
2009 (setq p (undo-tree-node-next node))
2010 ;; compute left-width
2011 (dotimes (i (/ num-children 2))
2012 (if (undo-tree-node-lwidth (car p))
2013 (incf lwidth (+ (undo-tree-node-lwidth (car p))
2014 (undo-tree-node-cwidth (car p))
2015 (undo-tree-node-rwidth (car p))))
2016 (throw 'need-widths (car p)))
2017 (setq p (cdr p)))
2018 ;; centre-width is 0 when number of children is even
2019 (setq cwidth 0)
2020 ;; compute right-width
2021 (dotimes (i (/ num-children 2))
2022 (if (undo-tree-node-lwidth (car p))
2023 (incf rwidth (+ (undo-tree-node-lwidth (car p))
2024 (undo-tree-node-cwidth (car p))
2025 (undo-tree-node-rwidth (car p))))
2026 (throw 'need-widths (car p)))
2027 (setq p (cdr p)))))
2028
2029 ;; return left-, centre- and right-widths
2030 (vector lwidth cwidth rwidth))))
2031
2032
2033 (defun undo-tree-clear-visualizer-data (tree)
2034 ;; Clear visualizer data below NODE.
2035 (undo-tree-mapc
2036 (lambda (n) (undo-tree-node-clear-visualizer-data n))
2037 (undo-tree-root tree)))
2038
2039
2040 (defun undo-tree-node-unmodified-p (node &optional mtime)
2041 ;; Return non-nil if NODE corresponds to a buffer state that once upon a
2042 ;; time was unmodified. If a file modification time MTIME is specified,
2043 ;; return non-nil if the corresponding buffer state really is unmodified.
2044 (let (changeset ntime)
2045 (setq changeset
2046 (or (undo-tree-node-redo node)
2047 (and (setq changeset (car (undo-tree-node-next node)))
2048 (undo-tree-node-undo changeset)))
2049 ntime
2050 (catch 'found
2051 (dolist (elt changeset)
2052 (when (and (consp elt) (eq (car elt) t) (consp (cdr elt))
2053 (throw 'found (cdr elt)))))))
2054 (and ntime
2055 (or (null mtime)
2056 ;; high-precision timestamps
2057 (if (listp (cdr ntime))
2058 (equal ntime mtime)
2059 ;; old-style timestamps
2060 (and (= (car ntime) (car mtime))
2061 (= (cdr ntime) (cadr mtime))))))))
2062
2063
2064
2065 \f
2066 ;;; =====================================================================
2067 ;;; Undo-in-region utility functions
2068
2069 ;; `undo-elt-in-region' uses this as a dynamically-scoped variable
2070 (defvar undo-adjusted-markers nil)
2071
2072
2073 (defun undo-tree-pull-undo-in-region-branch (start end)
2074 ;; Pull out entries from undo changesets to create a new undo-in-region
2075 ;; branch, which undoes changeset entries lying between START and END first,
2076 ;; followed by remaining entries from the changesets, before rejoining the
2077 ;; existing undo tree history. Repeated calls will, if appropriate, extend
2078 ;; the current undo-in-region branch rather than creating a new one.
2079
2080 ;; if we're just reverting the last redo-in-region, we don't need to
2081 ;; manipulate the undo tree at all
2082 (if (undo-tree-reverting-redo-in-region-p start end)
2083 t ; return t to indicate success
2084
2085 ;; We build the `region-changeset' and `delta-list' lists forwards, using
2086 ;; pointers `r' and `d' to the penultimate element of the list. So that we
2087 ;; don't have to treat the first element differently, we prepend a dummy
2088 ;; leading nil to the lists, and have the pointers point to that
2089 ;; initially.
2090 ;; Note: using '(nil) instead of (list nil) in the `let*' results in
2091 ;; bizarre errors when the code is byte-compiled, where parts of the
2092 ;; lists appear to survive across different calls to this function.
2093 ;; An obscure byte-compiler bug, perhaps?
2094 (let* ((region-changeset (list nil))
2095 (r region-changeset)
2096 (delta-list (list nil))
2097 (d delta-list)
2098 (node (undo-tree-current buffer-undo-tree))
2099 (repeated-undo-in-region
2100 (undo-tree-repeated-undo-in-region-p start end))
2101 undo-adjusted-markers ; `undo-elt-in-region' expects this
2102 fragment splice original-fragment original-splice original-current
2103 got-visible-elt undo-list elt)
2104
2105 ;; --- initialisation ---
2106 (cond
2107 ;; if this is a repeated undo in the same region, start pulling changes
2108 ;; from NODE at which undo-in-region branch iss attached, and detatch
2109 ;; the branch, using it as initial FRAGMENT of branch being constructed
2110 (repeated-undo-in-region
2111 (setq original-current node
2112 fragment (car (undo-tree-node-next node))
2113 splice node)
2114 ;; undo up to node at which undo-in-region branch is attached
2115 ;; (recognizable as first node with more than one branch)
2116 (let ((mark-active nil))
2117 (while (= (length (undo-tree-node-next node)) 1)
2118 (undo-tree-undo-1)
2119 (setq fragment node
2120 node (undo-tree-current buffer-undo-tree))))
2121 (when (eq splice node) (setq splice nil))
2122 ;; detatch undo-in-region branch
2123 (setf (undo-tree-node-next node)
2124 (delq fragment (undo-tree-node-next node))
2125 (undo-tree-node-previous fragment) nil
2126 original-fragment fragment
2127 original-splice node))
2128
2129 ;; if this is a new undo-in-region, initial FRAGMENT is a copy of all
2130 ;; nodes below the current one in the active branch
2131 ((undo-tree-node-next node)
2132 (setq fragment (undo-tree-make-node nil nil)
2133 splice fragment)
2134 (while (setq node (nth (undo-tree-node-branch node)
2135 (undo-tree-node-next node)))
2136 (push (undo-tree-make-node
2137 splice
2138 (undo-copy-list (undo-tree-node-undo node))
2139 (undo-copy-list (undo-tree-node-redo node)))
2140 (undo-tree-node-next splice))
2141 (setq splice (car (undo-tree-node-next splice))))
2142 (setq fragment (car (undo-tree-node-next fragment))
2143 splice nil
2144 node (undo-tree-current buffer-undo-tree))))
2145
2146
2147 ;; --- pull undo-in-region elements into branch ---
2148 ;; work backwards up tree, pulling out undo elements within region until
2149 ;; we've got one that undoes a visible change (insertion or deletion)
2150 (catch 'abort
2151 (while (and (not got-visible-elt) node (undo-tree-node-undo node))
2152 ;; we cons a dummy nil element on the front of the changeset so that
2153 ;; we can conveniently remove the first (real) element from the
2154 ;; changeset if we need to; the leading nil is removed once we're
2155 ;; done with this changeset
2156 (setq undo-list (cons nil (undo-copy-list (undo-tree-node-undo node)))
2157 elt (cadr undo-list))
2158 (if fragment
2159 (progn
2160 (setq fragment (undo-tree-grow-backwards fragment undo-list))
2161 (unless splice (setq splice fragment)))
2162 (setq fragment (undo-tree-make-node nil undo-list))
2163 (setq splice fragment))
2164
2165 (while elt
2166 (cond
2167 ;; keep elements within region
2168 ((undo-elt-in-region elt start end)
2169 ;; set flag if kept element is visible (insertion or deletion)
2170 (when (and (consp elt)
2171 (or (stringp (car elt)) (integerp (car elt))))
2172 (setq got-visible-elt t))
2173 ;; adjust buffer positions in elements previously undone before
2174 ;; kept element, as kept element will now be undone first
2175 (undo-tree-adjust-elements-to-elt splice elt)
2176 ;; move kept element to undo-in-region changeset, adjusting its
2177 ;; buffer position as it will now be undone first
2178 (setcdr r (list (undo-tree-apply-deltas elt (cdr delta-list))))
2179 (setq r (cdr r))
2180 (setcdr undo-list (cddr undo-list)))
2181
2182 ;; discard "was unmodified" elements
2183 ;; FIXME: deal properly with these
2184 ((and (consp elt) (eq (car elt) t))
2185 (setcdr undo-list (cddr undo-list)))
2186
2187 ;; if element crosses region, we can't pull any more elements
2188 ((undo-elt-crosses-region elt start end)
2189 ;; if we've found a visible element, it must be earlier in
2190 ;; current node's changeset; stop pulling elements (null
2191 ;; `undo-list' and non-nil `got-visible-elt' cause loop to exit)
2192 (if got-visible-elt
2193 (setq undo-list nil)
2194 ;; if we haven't found a visible element yet, pulling
2195 ;; undo-in-region branch has failed
2196 (setq region-changeset nil)
2197 (throw 'abort t)))
2198
2199 ;; if rejecting element, add its delta (if any) to the list
2200 (t
2201 (let ((delta (undo-delta elt)))
2202 (when (/= 0 (cdr delta))
2203 (setcdr d (list delta))
2204 (setq d (cdr d))))
2205 (setq undo-list (cdr undo-list))))
2206
2207 ;; process next element of current changeset
2208 (setq elt (cadr undo-list)))
2209
2210 ;; if there are remaining elements in changeset, remove dummy nil
2211 ;; from front
2212 (if (cadr (undo-tree-node-undo fragment))
2213 (pop (undo-tree-node-undo fragment))
2214 ;; otherwise, if we've kept all elements in changeset, discard
2215 ;; empty changeset
2216 (when (eq splice fragment) (setq splice nil))
2217 (setq fragment (car (undo-tree-node-next fragment))))
2218 ;; process changeset from next node up the tree
2219 (setq node (undo-tree-node-previous node))))
2220
2221 ;; pop dummy nil from front of `region-changeset'
2222 (setq region-changeset (cdr region-changeset))
2223
2224
2225 ;; --- integrate branch into tree ---
2226 ;; if no undo-in-region elements were found, restore undo tree
2227 (if (null region-changeset)
2228 (when original-current
2229 (push original-fragment (undo-tree-node-next original-splice))
2230 (setf (undo-tree-node-branch original-splice) 0
2231 (undo-tree-node-previous original-fragment) original-splice)
2232 (let ((mark-active nil))
2233 (while (not (eq (undo-tree-current buffer-undo-tree)
2234 original-current))
2235 (undo-tree-redo-1)))
2236 nil) ; return nil to indicate failure
2237
2238 ;; otherwise...
2239 ;; need to undo up to node where new branch will be attached, to
2240 ;; ensure redo entries are populated, and then redo back to where we
2241 ;; started
2242 (let ((mark-active nil)
2243 (current (undo-tree-current buffer-undo-tree)))
2244 (while (not (eq (undo-tree-current buffer-undo-tree) node))
2245 (undo-tree-undo-1))
2246 (while (not (eq (undo-tree-current buffer-undo-tree) current))
2247 (undo-tree-redo-1)))
2248
2249 (cond
2250 ;; if there's no remaining fragment, just create undo-in-region node
2251 ;; and attach it to parent of last node from which elements were
2252 ;; pulled
2253 ((null fragment)
2254 (setq fragment (undo-tree-make-node node region-changeset))
2255 (push fragment (undo-tree-node-next node))
2256 (setf (undo-tree-node-branch node) 0)
2257 ;; set current node to undo-in-region node
2258 (setf (undo-tree-current buffer-undo-tree) fragment))
2259
2260 ;; if no splice point has been set, add undo-in-region node to top of
2261 ;; fragment and attach it to parent of last node from which elements
2262 ;; were pulled
2263 ((null splice)
2264 (setq fragment (undo-tree-grow-backwards fragment region-changeset))
2265 (push fragment (undo-tree-node-next node))
2266 (setf (undo-tree-node-branch node) 0
2267 (undo-tree-node-previous fragment) node)
2268 ;; set current node to undo-in-region node
2269 (setf (undo-tree-current buffer-undo-tree) fragment))
2270
2271 ;; if fragment contains nodes, attach fragment to parent of last node
2272 ;; from which elements were pulled, and splice in undo-in-region node
2273 (t
2274 (setf (undo-tree-node-previous fragment) node)
2275 (push fragment (undo-tree-node-next node))
2276 (setf (undo-tree-node-branch node) 0)
2277 ;; if this is a repeated undo-in-region, then we've left the current
2278 ;; node at the original splice-point; we need to set the current
2279 ;; node to the equivalent node on the undo-in-region branch and redo
2280 ;; back to where we started
2281 (when repeated-undo-in-region
2282 (setf (undo-tree-current buffer-undo-tree)
2283 (undo-tree-node-previous original-fragment))
2284 (let ((mark-active nil))
2285 (while (not (eq (undo-tree-current buffer-undo-tree) splice))
2286 (undo-tree-redo-1 nil 'preserve-undo))))
2287 ;; splice new undo-in-region node into fragment
2288 (setq node (undo-tree-make-node nil region-changeset))
2289 (undo-tree-splice-node node splice)
2290 ;; set current node to undo-in-region node
2291 (setf (undo-tree-current buffer-undo-tree) node)))
2292
2293 ;; update undo-tree size
2294 (setq node (undo-tree-node-previous fragment))
2295 (while (progn
2296 (and (setq node (car (undo-tree-node-next node)))
2297 (not (eq node original-fragment))
2298 (incf (undo-tree-count buffer-undo-tree))
2299 (incf (undo-tree-size buffer-undo-tree)
2300 (+ (undo-list-byte-size (undo-tree-node-undo node))
2301 (undo-list-byte-size (undo-tree-node-redo node)))))))
2302 t) ; indicate undo-in-region branch was successfully pulled
2303 )))
2304
2305
2306
2307 (defun undo-tree-pull-redo-in-region-branch (start end)
2308 ;; Pull out entries from redo changesets to create a new redo-in-region
2309 ;; branch, which redoes changeset entries lying between START and END first,
2310 ;; followed by remaining entries from the changesets. Repeated calls will,
2311 ;; if appropriate, extend the current redo-in-region branch rather than
2312 ;; creating a new one.
2313
2314 ;; if we're just reverting the last undo-in-region, we don't need to
2315 ;; manipulate the undo tree at all
2316 (if (undo-tree-reverting-undo-in-region-p start end)
2317 t ; return t to indicate success
2318
2319 ;; We build the `region-changeset' and `delta-list' lists forwards, using
2320 ;; pointers `r' and `d' to the penultimate element of the list. So that we
2321 ;; don't have to treat the first element differently, we prepend a dummy
2322 ;; leading nil to the lists, and have the pointers point to that
2323 ;; initially.
2324 ;; Note: using '(nil) instead of (list nil) in the `let*' causes bizarre
2325 ;; errors when the code is byte-compiled, where parts of the lists
2326 ;; appear to survive across different calls to this function. An
2327 ;; obscure byte-compiler bug, perhaps?
2328 (let* ((region-changeset (list nil))
2329 (r region-changeset)
2330 (delta-list (list nil))
2331 (d delta-list)
2332 (node (undo-tree-current buffer-undo-tree))
2333 (repeated-redo-in-region
2334 (undo-tree-repeated-redo-in-region-p start end))
2335 undo-adjusted-markers ; `undo-elt-in-region' expects this
2336 fragment splice got-visible-elt redo-list elt)
2337
2338 ;; --- inisitalisation ---
2339 (cond
2340 ;; if this is a repeated redo-in-region, detach fragment below current
2341 ;; node
2342 (repeated-redo-in-region
2343 (when (setq fragment (car (undo-tree-node-next node)))
2344 (setf (undo-tree-node-previous fragment) nil
2345 (undo-tree-node-next node)
2346 (delq fragment (undo-tree-node-next node)))))
2347 ;; if this is a new redo-in-region, initial fragment is a copy of all
2348 ;; nodes below the current one in the active branch
2349 ((undo-tree-node-next node)
2350 (setq fragment (undo-tree-make-node nil nil)
2351 splice fragment)
2352 (while (setq node (nth (undo-tree-node-branch node)
2353 (undo-tree-node-next node)))
2354 (push (undo-tree-make-node
2355 splice nil
2356 (undo-copy-list (undo-tree-node-redo node)))
2357 (undo-tree-node-next splice))
2358 (setq splice (car (undo-tree-node-next splice))))
2359 (setq fragment (car (undo-tree-node-next fragment)))))
2360
2361
2362 ;; --- pull redo-in-region elements into branch ---
2363 ;; work down fragment, pulling out redo elements within region until
2364 ;; we've got one that redoes a visible change (insertion or deletion)
2365 (setq node fragment)
2366 (catch 'abort
2367 (while (and (not got-visible-elt) node (undo-tree-node-redo node))
2368 ;; we cons a dummy nil element on the front of the changeset so that
2369 ;; we can conveniently remove the first (real) element from the
2370 ;; changeset if we need to; the leading nil is removed once we're
2371 ;; done with this changeset
2372 (setq redo-list (push nil (undo-tree-node-redo node))
2373 elt (cadr redo-list))
2374 (while elt
2375 (cond
2376 ;; keep elements within region
2377 ((undo-elt-in-region elt start end)
2378 ;; set flag if kept element is visible (insertion or deletion)
2379 (when (and (consp elt)
2380 (or (stringp (car elt)) (integerp (car elt))))
2381 (setq got-visible-elt t))
2382 ;; adjust buffer positions in elements previously redone before
2383 ;; kept element, as kept element will now be redone first
2384 (undo-tree-adjust-elements-to-elt fragment elt t)
2385 ;; move kept element to redo-in-region changeset, adjusting its
2386 ;; buffer position as it will now be redone first
2387 (setcdr r (list (undo-tree-apply-deltas elt (cdr delta-list) -1)))
2388 (setq r (cdr r))
2389 (setcdr redo-list (cddr redo-list)))
2390
2391 ;; discard "was unmodified" elements
2392 ;; FIXME: deal properly with these
2393 ((and (consp elt) (eq (car elt) t))
2394 (setcdr redo-list (cddr redo-list)))
2395
2396 ;; if element crosses region, we can't pull any more elements
2397 ((undo-elt-crosses-region elt start end)
2398 ;; if we've found a visible element, it must be earlier in
2399 ;; current node's changeset; stop pulling elements (null
2400 ;; `redo-list' and non-nil `got-visible-elt' cause loop to exit)
2401 (if got-visible-elt
2402 (setq redo-list nil)
2403 ;; if we haven't found a visible element yet, pulling
2404 ;; redo-in-region branch has failed
2405 (setq region-changeset nil)
2406 (throw 'abort t)))
2407
2408 ;; if rejecting element, add its delta (if any) to the list
2409 (t
2410 (let ((delta (undo-delta elt)))
2411 (when (/= 0 (cdr delta))
2412 (setcdr d (list delta))
2413 (setq d (cdr d))))
2414 (setq redo-list (cdr redo-list))))
2415
2416 ;; process next element of current changeset
2417 (setq elt (cadr redo-list)))
2418
2419 ;; if there are remaining elements in changeset, remove dummy nil
2420 ;; from front
2421 (if (cadr (undo-tree-node-redo node))
2422 (pop (undo-tree-node-undo node))
2423 ;; otherwise, if we've kept all elements in changeset, discard
2424 ;; empty changeset
2425 (if (eq fragment node)
2426 (setq fragment (car (undo-tree-node-next fragment)))
2427 (undo-tree-snip-node node)))
2428 ;; process changeset from next node in fragment
2429 (setq node (car (undo-tree-node-next node)))))
2430
2431 ;; pop dummy nil from front of `region-changeset'
2432 (setq region-changeset (cdr region-changeset))
2433
2434
2435 ;; --- integrate branch into tree ---
2436 (setq node (undo-tree-current buffer-undo-tree))
2437 ;; if no redo-in-region elements were found, restore undo tree
2438 (if (null (car region-changeset))
2439 (when (and repeated-redo-in-region fragment)
2440 (push fragment (undo-tree-node-next node))
2441 (setf (undo-tree-node-branch node) 0
2442 (undo-tree-node-previous fragment) node)
2443 nil) ; return nil to indicate failure
2444
2445 ;; otherwise, add redo-in-region node to top of fragment, and attach
2446 ;; it below current node
2447 (setq fragment
2448 (if fragment
2449 (undo-tree-grow-backwards fragment nil region-changeset)
2450 (undo-tree-make-node nil nil region-changeset)))
2451 (push fragment (undo-tree-node-next node))
2452 (setf (undo-tree-node-branch node) 0
2453 (undo-tree-node-previous fragment) node)
2454 ;; update undo-tree size
2455 (unless repeated-redo-in-region
2456 (setq node fragment)
2457 (while (and (setq node (car (undo-tree-node-next node)))
2458 (incf (undo-tree-count buffer-undo-tree))
2459 (incf (undo-tree-size buffer-undo-tree)
2460 (undo-list-byte-size
2461 (undo-tree-node-redo node))))))
2462 (incf (undo-tree-size buffer-undo-tree)
2463 (undo-list-byte-size (undo-tree-node-redo fragment)))
2464 t) ; indicate redo-in-region branch was successfully pulled
2465 )))
2466
2467
2468
2469 (defun undo-tree-adjust-elements-to-elt (node undo-elt &optional below)
2470 "Adjust buffer positions of undo elements, starting at NODE's
2471 and going up the tree (or down the active branch if BELOW is
2472 non-nil) and through the nodes' undo elements until we reach
2473 UNDO-ELT. UNDO-ELT must appear somewhere in the undo changeset
2474 of either NODE itself or some node above it in the tree."
2475 (let ((delta (list (undo-delta undo-elt)))
2476 (undo-list (undo-tree-node-undo node)))
2477 ;; adjust elements until we reach UNDO-ELT
2478 (while (and (car undo-list)
2479 (not (eq (car undo-list) undo-elt)))
2480 (setcar undo-list
2481 (undo-tree-apply-deltas (car undo-list) delta -1))
2482 ;; move to next undo element in list, or to next node if we've run out
2483 ;; of elements
2484 (unless (car (setq undo-list (cdr undo-list)))
2485 (if below
2486 (setq node (nth (undo-tree-node-branch node)
2487 (undo-tree-node-next node)))
2488 (setq node (undo-tree-node-previous node)))
2489 (setq undo-list (undo-tree-node-undo node))))))
2490
2491
2492
2493 (defun undo-tree-apply-deltas (undo-elt deltas &optional sgn)
2494 ;; Apply DELTAS in order to UNDO-ELT, multiplying deltas by SGN
2495 ;; (only useful value for SGN is -1).
2496 (let (position offset)
2497 (dolist (delta deltas)
2498 (setq position (car delta)
2499 offset (* (cdr delta) (or sgn 1)))
2500 (cond
2501 ;; POSITION
2502 ((integerp undo-elt)
2503 (when (>= undo-elt position)
2504 (setq undo-elt (- undo-elt offset))))
2505 ;; nil (or any other atom)
2506 ((atom undo-elt))
2507 ;; (TEXT . POSITION)
2508 ((stringp (car undo-elt))
2509 (let ((text-pos (abs (cdr undo-elt)))
2510 (point-at-end (< (cdr undo-elt) 0)))
2511 (if (>= text-pos position)
2512 (setcdr undo-elt (* (if point-at-end -1 1)
2513 (- text-pos offset))))))
2514 ;; (BEGIN . END)
2515 ((integerp (car undo-elt))
2516 (when (>= (car undo-elt) position)
2517 (setcar undo-elt (- (car undo-elt) offset))
2518 (setcdr undo-elt (- (cdr undo-elt) offset))))
2519 ;; (nil PROPERTY VALUE BEG . END)
2520 ((null (car undo-elt))
2521 (let ((tail (nthcdr 3 undo-elt)))
2522 (when (>= (car tail) position)
2523 (setcar tail (- (car tail) offset))
2524 (setcdr tail (- (cdr tail) offset)))))
2525 ))
2526 undo-elt))
2527
2528
2529
2530 (defun undo-tree-repeated-undo-in-region-p (start end)
2531 ;; Return non-nil if undo-in-region between START and END is a repeated
2532 ;; undo-in-region
2533 (let ((node (undo-tree-current buffer-undo-tree)))
2534 (and (setq node
2535 (nth (undo-tree-node-branch node) (undo-tree-node-next node)))
2536 (eq (undo-tree-node-undo-beginning node) start)
2537 (eq (undo-tree-node-undo-end node) end))))
2538
2539
2540 (defun undo-tree-repeated-redo-in-region-p (start end)
2541 ;; Return non-nil if undo-in-region between START and END is a repeated
2542 ;; undo-in-region
2543 (let ((node (undo-tree-current buffer-undo-tree)))
2544 (and (eq (undo-tree-node-redo-beginning node) start)
2545 (eq (undo-tree-node-redo-end node) end))))
2546
2547
2548 ;; Return non-nil if undo-in-region between START and END is simply
2549 ;; reverting the last redo-in-region
2550 (defalias 'undo-tree-reverting-undo-in-region-p
2551 'undo-tree-repeated-undo-in-region-p)
2552
2553
2554 ;; Return non-nil if redo-in-region between START and END is simply
2555 ;; reverting the last undo-in-region
2556 (defalias 'undo-tree-reverting-redo-in-region-p
2557 'undo-tree-repeated-redo-in-region-p)
2558
2559
2560
2561 \f
2562 ;;; =====================================================================
2563 ;;; Undo-tree commands
2564
2565 ;;;###autoload
2566 (define-minor-mode undo-tree-mode
2567 "Toggle undo-tree mode.
2568 With no argument, this command toggles the mode.
2569 A positive prefix argument turns the mode on.
2570 A negative prefix argument turns it off.
2571
2572 Undo-tree-mode replaces Emacs' standard undo feature with a more
2573 powerful yet easier to use version, that treats the undo history
2574 as what it is: a tree.
2575
2576 The following keys are available in `undo-tree-mode':
2577
2578 \\{undo-tree-map}
2579
2580 Within the undo-tree visualizer, the following keys are available:
2581
2582 \\{undo-tree-visualizer-map}"
2583
2584 nil ; init value
2585 undo-tree-mode-lighter ; lighter
2586 undo-tree-map ; keymap
2587
2588 ;; if disabling `undo-tree-mode', rebuild `buffer-undo-list' from tree so
2589 ;; Emacs undo can work
2590 (if (not undo-tree-mode)
2591 (undo-list-rebuild-from-tree)
2592 (setq buffer-undo-tree nil)))
2593
2594
2595 (defun turn-on-undo-tree-mode (&optional print-message)
2596 "Enable `undo-tree-mode' in the current buffer, when appropriate.
2597 Some major modes implement their own undo system, which should
2598 not normally be overridden by `undo-tree-mode'. This command does
2599 not enable `undo-tree-mode' in such buffers. If you want to force
2600 `undo-tree-mode' to be enabled regardless, use (undo-tree-mode 1)
2601 instead.
2602
2603 The heuristic used to detect major modes in which
2604 `undo-tree-mode' should not be used is to check whether either
2605 the `undo' command has been remapped, or the default undo
2606 keybindings (C-/ and C-_) have been overridden somewhere other
2607 than in the global map. In addition, `undo-tree-mode' will not be
2608 enabled if the buffer's `major-mode' appears in
2609 `undo-tree-incompatible-major-modes'."
2610 (interactive "p")
2611 (if (or (key-binding [remap undo])
2612 (undo-tree-overridden-undo-bindings-p)
2613 (memq major-mode undo-tree-incompatible-major-modes))
2614 (when print-message
2615 (message "Buffer does not support undo-tree-mode;\
2616 undo-tree-mode NOT enabled"))
2617 (undo-tree-mode 1)))
2618
2619
2620 (defun undo-tree-overridden-undo-bindings-p ()
2621 "Returns t if default undo bindings are overridden, nil otherwise.
2622 Checks if either of the default undo key bindings (\"C-/\" or
2623 \"C-_\") are overridden in the current buffer by any keymap other
2624 than the global one. (So global redefinitions of the default undo
2625 key bindings do not count.)"
2626 (let ((binding1 (lookup-key (current-global-map) [?\C-/]))
2627 (binding2 (lookup-key (current-global-map) [?\C-_])))
2628 (global-set-key [?\C-/] 'undo)
2629 (global-set-key [?\C-_] 'undo)
2630 (unwind-protect
2631 (or (and (key-binding [?\C-/])
2632 (not (eq (key-binding [?\C-/]) 'undo)))
2633 (and (key-binding [?\C-_])
2634 (not (eq (key-binding [?\C-_]) 'undo))))
2635 (global-set-key [?\C-/] binding1)
2636 (global-set-key [?\C-_] binding2))))
2637
2638
2639 ;;;###autoload
2640 (define-globalized-minor-mode global-undo-tree-mode
2641 undo-tree-mode turn-on-undo-tree-mode)
2642
2643
2644
2645 (defun undo-tree-undo (&optional arg)
2646 "Undo changes.
2647 Repeat this command to undo more changes.
2648 A numeric ARG serves as a repeat count.
2649
2650 In Transient Mark mode when the mark is active, only undo changes
2651 within the current region. Similarly, when not in Transient Mark
2652 mode, just \\[universal-argument] as an argument limits undo to
2653 changes within the current region."
2654 (interactive "*P")
2655 ;; throw error if undo is disabled in buffer
2656 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2657 (undo-tree-undo-1 arg)
2658 ;; inform user if at branch point
2659 (when (> (undo-tree-num-branches) 1) (message "Undo branch point!")))
2660
2661
2662 (defun undo-tree-undo-1 (&optional arg preserve-redo preserve-timestamps)
2663 ;; Internal undo function. An active mark in `transient-mark-mode', or
2664 ;; non-nil ARG otherwise, enables undo-in-region. Non-nil PRESERVE-REDO
2665 ;; causes the existing redo record to be preserved, rather than replacing it
2666 ;; with the new one generated by undoing. Non-nil PRESERVE-TIMESTAMPS
2667 ;; disables updating of timestamps in visited undo-tree nodes. (This latter
2668 ;; should *only* be used when temporarily visiting another undo state and
2669 ;; immediately returning to the original state afterwards. Otherwise, it
2670 ;; could cause history-discarding errors.)
2671 (let ((undo-in-progress t)
2672 (undo-in-region (and undo-tree-enable-undo-in-region
2673 (or (region-active-p)
2674 (and arg (not (numberp arg))))))
2675 pos current)
2676 ;; transfer entries accumulated in `buffer-undo-list' to
2677 ;; `buffer-undo-tree'
2678 (undo-list-transfer-to-tree)
2679
2680 (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1))
2681 ;; check if at top of undo tree
2682 (unless (undo-tree-node-previous (undo-tree-current buffer-undo-tree))
2683 (error "No further undo information"))
2684
2685 ;; if region is active, or a non-numeric prefix argument was supplied,
2686 ;; try to pull out a new branch of changes affecting the region
2687 (when (and undo-in-region
2688 (not (undo-tree-pull-undo-in-region-branch
2689 (region-beginning) (region-end))))
2690 (error "No further undo information for region"))
2691
2692 ;; remove any GC'd elements from node's undo list
2693 (setq current (undo-tree-current buffer-undo-tree))
2694 (decf (undo-tree-size buffer-undo-tree)
2695 (undo-list-byte-size (undo-tree-node-undo current)))
2696 (setf (undo-tree-node-undo current)
2697 (undo-list-clean-GCd-elts (undo-tree-node-undo current)))
2698 (incf (undo-tree-size buffer-undo-tree)
2699 (undo-list-byte-size (undo-tree-node-undo current)))
2700 ;; undo one record from undo tree
2701 (when undo-in-region
2702 (setq pos (set-marker (make-marker) (point)))
2703 (set-marker-insertion-type pos t))
2704 (primitive-undo 1 (undo-tree-copy-list (undo-tree-node-undo current)))
2705 (undo-boundary)
2706
2707 ;; if preserving old redo record, discard new redo entries that
2708 ;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd
2709 ;; elements from node's redo list
2710 (if preserve-redo
2711 (progn
2712 (undo-list-pop-changeset)
2713 (decf (undo-tree-size buffer-undo-tree)
2714 (undo-list-byte-size (undo-tree-node-redo current)))
2715 (setf (undo-tree-node-redo current)
2716 (undo-list-clean-GCd-elts (undo-tree-node-redo current)))
2717 (incf (undo-tree-size buffer-undo-tree)
2718 (undo-list-byte-size (undo-tree-node-redo current))))
2719 ;; otherwise, record redo entries that `primitive-undo' has added to
2720 ;; `buffer-undo-list' in current node's redo record, replacing
2721 ;; existing entry if one already exists
2722 (decf (undo-tree-size buffer-undo-tree)
2723 (undo-list-byte-size (undo-tree-node-redo current)))
2724 (setf (undo-tree-node-redo current)
2725 (undo-list-pop-changeset 'discard-pos))
2726 (incf (undo-tree-size buffer-undo-tree)
2727 (undo-list-byte-size (undo-tree-node-redo current))))
2728
2729 ;; rewind current node and update timestamp
2730 (setf (undo-tree-current buffer-undo-tree)
2731 (undo-tree-node-previous (undo-tree-current buffer-undo-tree)))
2732 (unless preserve-timestamps
2733 (setf (undo-tree-node-timestamp (undo-tree-current buffer-undo-tree))
2734 (current-time)))
2735
2736 ;; if undoing-in-region, record current node, region and direction so we
2737 ;; can tell if undo-in-region is repeated, and re-activate mark if in
2738 ;; `transient-mark-mode'; if not, erase any leftover data
2739 (if (not undo-in-region)
2740 (undo-tree-node-clear-region-data current)
2741 (goto-char pos)
2742 ;; note: we deliberately want to store the region information in the
2743 ;; node *below* the now current one
2744 (setf (undo-tree-node-undo-beginning current) (region-beginning)
2745 (undo-tree-node-undo-end current) (region-end))
2746 (set-marker pos nil)))
2747
2748 ;; undo deactivates mark unless undoing-in-region
2749 (setq deactivate-mark (not undo-in-region))))
2750
2751
2752
2753 (defun undo-tree-redo (&optional arg)
2754 "Redo changes. A numeric ARG serves as a repeat count.
2755
2756 In Transient Mark mode when the mark is active, only redo changes
2757 within the current region. Similarly, when not in Transient Mark
2758 mode, just \\[universal-argument] as an argument limits redo to
2759 changes within the current region."
2760 (interactive "*P")
2761 ;; throw error if undo is disabled in buffer
2762 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2763 (undo-tree-redo-1 arg)
2764 ;; inform user if at branch point
2765 (when (> (undo-tree-num-branches) 1) (message "Undo branch point!")))
2766
2767
2768 (defun undo-tree-redo-1 (&optional arg preserve-undo preserve-timestamps)
2769 ;; Internal redo function. An active mark in `transient-mark-mode', or
2770 ;; non-nil ARG otherwise, enables undo-in-region. Non-nil PRESERVE-UNDO
2771 ;; causes the existing redo record to be preserved, rather than replacing it
2772 ;; with the new one generated by undoing. Non-nil PRESERVE-TIMESTAMPS
2773 ;; disables updating of timestamps in visited undo-tree nodes. (This latter
2774 ;; should *only* be used when temporarily visiting another undo state and
2775 ;; immediately returning to the original state afterwards. Otherwise, it
2776 ;; could cause history-discarding errors.)
2777 (let ((undo-in-progress t)
2778 (redo-in-region (and undo-tree-enable-undo-in-region
2779 (or (region-active-p)
2780 (and arg (not (numberp arg))))))
2781 pos current)
2782 ;; transfer entries accumulated in `buffer-undo-list' to
2783 ;; `buffer-undo-tree'
2784 (undo-list-transfer-to-tree)
2785
2786 (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1))
2787 ;; check if at bottom of undo tree
2788 (when (null (undo-tree-node-next (undo-tree-current buffer-undo-tree)))
2789 (error "No further redo information"))
2790
2791 ;; if region is active, or a non-numeric prefix argument was supplied,
2792 ;; try to pull out a new branch of changes affecting the region
2793 (when (and redo-in-region
2794 (not (undo-tree-pull-redo-in-region-branch
2795 (region-beginning) (region-end))))
2796 (error "No further redo information for region"))
2797
2798 ;; get next node (but DON'T advance current node in tree yet, in case
2799 ;; redoing fails)
2800 (setq current (undo-tree-current buffer-undo-tree)
2801 current (nth (undo-tree-node-branch current)
2802 (undo-tree-node-next current)))
2803 ;; remove any GC'd elements from node's redo list
2804 (decf (undo-tree-size buffer-undo-tree)
2805 (undo-list-byte-size (undo-tree-node-redo current)))
2806 (setf (undo-tree-node-redo current)
2807 (undo-list-clean-GCd-elts (undo-tree-node-redo current)))
2808 (incf (undo-tree-size buffer-undo-tree)
2809 (undo-list-byte-size (undo-tree-node-redo current)))
2810 ;; redo one record from undo tree
2811 (when redo-in-region
2812 (setq pos (set-marker (make-marker) (point)))
2813 (set-marker-insertion-type pos t))
2814 (primitive-undo 1 (undo-tree-copy-list (undo-tree-node-redo current)))
2815 (undo-boundary)
2816 ;; advance current node in tree
2817 (setf (undo-tree-current buffer-undo-tree) current)
2818
2819 ;; if preserving old undo record, discard new undo entries that
2820 ;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd
2821 ;; elements from node's redo list
2822 (if preserve-undo
2823 (progn
2824 (undo-list-pop-changeset)
2825 (decf (undo-tree-size buffer-undo-tree)
2826 (undo-list-byte-size (undo-tree-node-undo current)))
2827 (setf (undo-tree-node-undo current)
2828 (undo-list-clean-GCd-elts (undo-tree-node-undo current)))
2829 (incf (undo-tree-size buffer-undo-tree)
2830 (undo-list-byte-size (undo-tree-node-undo current))))
2831 ;; otherwise, record undo entries that `primitive-undo' has added to
2832 ;; `buffer-undo-list' in current node's undo record, replacing
2833 ;; existing entry if one already exists
2834 (decf (undo-tree-size buffer-undo-tree)
2835 (undo-list-byte-size (undo-tree-node-undo current)))
2836 (setf (undo-tree-node-undo current)
2837 (undo-list-pop-changeset 'discard-pos))
2838 (incf (undo-tree-size buffer-undo-tree)
2839 (undo-list-byte-size (undo-tree-node-undo current))))
2840
2841 ;; update timestamp
2842 (unless preserve-timestamps
2843 (setf (undo-tree-node-timestamp current) (current-time)))
2844
2845 ;; if redoing-in-region, record current node, region and direction so we
2846 ;; can tell if redo-in-region is repeated, and re-activate mark if in
2847 ;; `transient-mark-mode'
2848 (if (not redo-in-region)
2849 (undo-tree-node-clear-region-data current)
2850 (goto-char pos)
2851 (setf (undo-tree-node-redo-beginning current) (region-beginning)
2852 (undo-tree-node-redo-end current) (region-end))
2853 (set-marker pos nil)))
2854
2855 ;; redo deactivates the mark unless redoing-in-region
2856 (setq deactivate-mark (not redo-in-region))))
2857
2858
2859
2860 (defun undo-tree-switch-branch (branch)
2861 "Switch to a different BRANCH of the undo tree.
2862 This will affect which branch to descend when *redoing* changes
2863 using `undo-tree-redo'."
2864 (interactive (list (or (and prefix-arg (prefix-numeric-value prefix-arg))
2865 (and (not (eq buffer-undo-list t))
2866 (or (undo-list-transfer-to-tree) t)
2867 (let ((b (undo-tree-node-branch
2868 (undo-tree-current
2869 buffer-undo-tree))))
2870 (cond
2871 ;; switch to other branch if only 2
2872 ((= (undo-tree-num-branches) 2) (- 1 b))
2873 ;; prompt if more than 2
2874 ((> (undo-tree-num-branches) 2)
2875 (read-number
2876 (format "Branch (0-%d, on %d): "
2877 (1- (undo-tree-num-branches)) b)))
2878 ))))))
2879 ;; throw error if undo is disabled in buffer
2880 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2881 ;; sanity check branch number
2882 (when (<= (undo-tree-num-branches) 1) (error "Not at undo branch point"))
2883 (when (or (< branch 0) (> branch (1- (undo-tree-num-branches))))
2884 (error "Invalid branch number"))
2885 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
2886 (undo-list-transfer-to-tree)
2887 ;; switch branch
2888 (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
2889 branch)
2890 (message "Switched to branch %d" branch))
2891
2892
2893 (defun undo-tree-set (node &optional preserve-timestamps)
2894 ;; Set buffer to state corresponding to NODE. Returns intersection point
2895 ;; between path back from current node and path back from selected NODE.
2896 ;; Non-nil PRESERVE-TIMESTAMPS disables updating of timestamps in visited
2897 ;; undo-tree nodes. (This should *only* be used when temporarily visiting
2898 ;; another undo state and immediately returning to the original state
2899 ;; afterwards. Otherwise, it could cause history-discarding errors.)
2900 (let ((path (make-hash-table :test 'eq))
2901 (n node))
2902 (puthash (undo-tree-root buffer-undo-tree) t path)
2903 ;; build list of nodes leading back from selected node to root, updating
2904 ;; branches as we go to point down to selected node
2905 (while (progn
2906 (puthash n t path)
2907 (when (undo-tree-node-previous n)
2908 (setf (undo-tree-node-branch (undo-tree-node-previous n))
2909 (undo-tree-position
2910 n (undo-tree-node-next (undo-tree-node-previous n))))
2911 (setq n (undo-tree-node-previous n)))))
2912 ;; work backwards from current node until we intersect path back from
2913 ;; selected node
2914 (setq n (undo-tree-current buffer-undo-tree))
2915 (while (not (gethash n path))
2916 (setq n (undo-tree-node-previous n)))
2917 ;; ascend tree until intersection node
2918 (while (not (eq (undo-tree-current buffer-undo-tree) n))
2919 (undo-tree-undo-1 nil nil preserve-timestamps))
2920 ;; descend tree until selected node
2921 (while (not (eq (undo-tree-current buffer-undo-tree) node))
2922 (undo-tree-redo-1 nil nil preserve-timestamps))
2923 n)) ; return intersection node
2924
2925
2926
2927 (defun undo-tree-save-state-to-register (register)
2928 "Store current undo-tree state to REGISTER.
2929 The saved state can be restored using
2930 `undo-tree-restore-state-from-register'.
2931 Argument is a character, naming the register."
2932 (interactive "cUndo-tree state to register: ")
2933 ;; throw error if undo is disabled in buffer
2934 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2935 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
2936 (undo-list-transfer-to-tree)
2937 ;; save current node to REGISTER
2938 (set-register
2939 register (registerv-make
2940 (undo-tree-make-register-data
2941 (current-buffer) (undo-tree-current buffer-undo-tree))
2942 :print-func 'undo-tree-register-data-print-func))
2943 ;; record REGISTER in current node, for visualizer
2944 (setf (undo-tree-node-register (undo-tree-current buffer-undo-tree))
2945 register))
2946
2947
2948
2949 (defun undo-tree-restore-state-from-register (register)
2950 "Restore undo-tree state from REGISTER.
2951 The state must be saved using `undo-tree-save-state-to-register'.
2952 Argument is a character, naming the register."
2953 (interactive "*cRestore undo-tree state from register: ")
2954 ;; throw error if undo is disabled in buffer, or if register doesn't contain
2955 ;; an undo-tree node
2956 (let ((data (registerv-data (get-register register))))
2957 (cond
2958 ((eq buffer-undo-list t)
2959 (error "No undo information in this buffer"))
2960 ((not (undo-tree-register-data-p data))
2961 (error "Register doesn't contain undo-tree state"))
2962 ((not (eq (current-buffer) (undo-tree-register-data-buffer data)))
2963 (error "Register contains undo-tree state for a different buffer")))
2964 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
2965 (undo-list-transfer-to-tree)
2966 ;; restore buffer state corresponding to saved node
2967 (undo-tree-set (undo-tree-register-data-node data))))
2968
2969
2970
2971 \f
2972 ;;; =====================================================================
2973 ;;; Persistent storage commands
2974
2975 (defun undo-tree-make-history-save-file-name (file)
2976 "Create the undo history file name for FILE.
2977 Normally this is the file's name with `.' prepended and
2978 `~undo-tree~' appended.
2979
2980 A match for FILE is sought in `undo-tree-history-directory-alist';
2981 see the documentation of that variable. If the directory for the
2982 backup doesn't exist, it is created."
2983 (let* ((backup-directory-alist undo-tree-history-directory-alist)
2984 (name (make-backup-file-name-1 file)))
2985 (concat (file-name-directory name) "." (file-name-nondirectory name)
2986 "~undo-tree~")))
2987
2988
2989 (defun undo-tree-save-history (&optional filename overwrite)
2990 "Store undo-tree history to file.
2991
2992 If optional argument FILENAME is omitted, default save file is
2993 \".<buffer-file-name>.~undo-tree\" if buffer is visiting a file.
2994 Otherwise, prompt for one.
2995
2996 If OVERWRITE is non-nil, any existing file will be overwritten
2997 without asking for confirmation."
2998 (interactive)
2999 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
3000 (undo-list-transfer-to-tree)
3001 (when (and buffer-undo-tree (not (eq buffer-undo-tree t)))
3002 (condition-case nil
3003 (undo-tree-kill-visualizer)
3004 (error (undo-tree-clear-visualizer-data buffer-undo-tree)))
3005 (let ((buff (current-buffer))
3006 tree)
3007 ;; get filename
3008 (unless filename
3009 (setq filename
3010 (if buffer-file-name
3011 (undo-tree-make-history-save-file-name buffer-file-name)
3012 (expand-file-name (read-file-name "File to save in: ") nil))))
3013 (when (or (not (file-exists-p filename))
3014 overwrite
3015 (yes-or-no-p (format "Overwrite \"%s\"? " filename)))
3016 (unwind-protect
3017 (progn
3018 ;; transform undo-tree into non-circular structure, and make
3019 ;; temporary copy
3020 (undo-tree-decircle buffer-undo-tree)
3021 (setq tree (copy-undo-tree buffer-undo-tree))
3022 ;; discard undo-tree object pool before saving
3023 (setf (undo-tree-object-pool tree) nil)
3024 ;; print undo-tree to file
3025 ;; NOTE: We use `with-temp-buffer' instead of `with-temp-file'
3026 ;; to allow `auto-compression-mode' to take effect, in
3027 ;; case user has overridden or advised the default
3028 ;; `undo-tree-make-history-save-file-name' to add a
3029 ;; compressed file extension.
3030 (with-auto-compression-mode
3031 (with-temp-buffer
3032 (prin1 (sha1 buff) (current-buffer))
3033 (terpri (current-buffer))
3034 (let ((print-circle t)) (prin1 tree (current-buffer)))
3035 (write-region nil nil filename))))
3036 ;; restore circular undo-tree data structure
3037 (undo-tree-recircle buffer-undo-tree))
3038 ))))
3039
3040
3041
3042 (defun undo-tree-load-history (&optional filename noerror)
3043 "Load undo-tree history from file.
3044
3045 If optional argument FILENAME is null, default load file is
3046 \".<buffer-file-name>.~undo-tree\" if buffer is visiting a file.
3047 Otherwise, prompt for one.
3048
3049 If optional argument NOERROR is non-nil, return nil instead of
3050 signaling an error if file is not found."
3051 (interactive)
3052 ;; get filename
3053 (unless filename
3054 (setq filename
3055 (if buffer-file-name
3056 (undo-tree-make-history-save-file-name buffer-file-name)
3057 (expand-file-name (read-file-name "File to load from: ") nil))))
3058
3059 ;; attempt to read undo-tree from FILENAME
3060 (catch 'load-error
3061 (unless (file-exists-p filename)
3062 (if noerror
3063 (throw 'load-error nil)
3064 (error "File \"%s\" does not exist; could not load undo-tree history"
3065 filename)))
3066 (let (buff hash tree)
3067 (setq buff (current-buffer))
3068 (with-auto-compression-mode
3069 (with-temp-buffer
3070 (insert-file-contents filename)
3071 (goto-char (point-min))
3072 (condition-case nil
3073 (setq hash (read (current-buffer)))
3074 (error
3075 (kill-buffer nil)
3076 (funcall (if noerror 'message 'error)
3077 "Error reading undo-tree history from \"%s\"" filename)
3078 (throw 'load-error nil)))
3079 (unless (string= (sha1 buff) hash)
3080 (kill-buffer nil)
3081 (funcall (if noerror 'message 'error)
3082 "Buffer has been modified; could not load undo-tree history")
3083 (throw 'load-error nil))
3084 (condition-case nil
3085 (setq tree (read (current-buffer)))
3086 (error
3087 (kill-buffer nil)
3088 (funcall (if noerror 'message 'error)
3089 "Error reading undo-tree history from \"%s\"" filename)
3090 (throw 'load-error nil)))
3091 (kill-buffer nil)))
3092 ;; initialise empty undo-tree object pool
3093 (setf (undo-tree-object-pool tree)
3094 (make-hash-table :test 'eq :weakness 'value))
3095 ;; restore circular undo-tree data structure
3096 (undo-tree-recircle tree)
3097 (setq buffer-undo-tree tree))))
3098
3099
3100
3101 ;; Versions of save/load functions for use in hooks
3102 (defun undo-tree-save-history-hook ()
3103 (when (and undo-tree-mode undo-tree-auto-save-history
3104 (not (eq buffer-undo-list t)))
3105 (undo-tree-save-history nil t) nil))
3106
3107 (defun undo-tree-load-history-hook ()
3108 (when (and undo-tree-mode undo-tree-auto-save-history
3109 (not (eq buffer-undo-list t)))
3110 (undo-tree-load-history nil t)))
3111
3112
3113
3114 \f
3115 ;;; =====================================================================
3116 ;;; Visualizer drawing functions
3117
3118 (defun undo-tree-visualize ()
3119 "Visualize the current buffer's undo tree."
3120 (interactive "*")
3121 (deactivate-mark)
3122 ;; throw error if undo is disabled in buffer
3123 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
3124 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
3125 (undo-list-transfer-to-tree)
3126 ;; add hook to kill visualizer buffer if original buffer is changed
3127 (add-hook 'before-change-functions 'undo-tree-kill-visualizer nil t)
3128 ;; prepare *undo-tree* buffer, then draw tree in it
3129 (let ((undo-tree buffer-undo-tree)
3130 (buff (current-buffer))
3131 (display-buffer-mark-dedicated 'soft))
3132 (switch-to-buffer-other-window
3133 (get-buffer-create undo-tree-visualizer-buffer-name))
3134 (setq undo-tree-visualizer-parent-buffer buff)
3135 (setq undo-tree-visualizer-parent-mtime
3136 (and (buffer-file-name buff)
3137 (nth 5 (file-attributes (buffer-file-name buff)))))
3138 (setq buffer-undo-tree undo-tree)
3139 (setq undo-tree-visualizer-initial-node (undo-tree-current undo-tree))
3140 (setq undo-tree-visualizer-spacing
3141 (undo-tree-visualizer-calculate-spacing))
3142 (make-local-variable 'undo-tree-visualizer-timestamps)
3143 (make-local-variable 'undo-tree-visualizer-diff)
3144 (set (make-local-variable 'undo-tree-visualizer-lazy-drawing)
3145 (or (eq undo-tree-visualizer-lazy-drawing t)
3146 (and (numberp undo-tree-visualizer-lazy-drawing)
3147 (>= (undo-tree-count undo-tree)
3148 undo-tree-visualizer-lazy-drawing))))
3149 (when undo-tree-visualizer-diff (undo-tree-visualizer-show-diff))
3150 (undo-tree-visualizer-mode)
3151 (let ((inhibit-read-only t)) (undo-tree-draw-tree undo-tree))))
3152
3153
3154 (defun undo-tree-kill-visualizer (&rest _dummy)
3155 ;; Kill visualizer. Added to `before-change-functions' hook of original
3156 ;; buffer when visualizer is invoked.
3157 (unless undo-tree-inhibit-kill-visualizer
3158 (unwind-protect
3159 (with-current-buffer undo-tree-visualizer-buffer-name
3160 (undo-tree-visualizer-quit)))))
3161
3162
3163
3164 (defun undo-tree-draw-tree (undo-tree)
3165 ;; Draw undo-tree in current buffer starting from NODE (or root if nil).
3166 (let ((node (if undo-tree-visualizer-lazy-drawing
3167 (undo-tree-current undo-tree)
3168 (undo-tree-root undo-tree))))
3169 (erase-buffer)
3170 (undo-tree-clear-visualizer-data undo-tree)
3171 (undo-tree-compute-widths node)
3172 ;; lazy drawing starts vertically centred and displaced horizontally to
3173 ;; the left (window-width/4), since trees will typically grow right
3174 (if undo-tree-visualizer-lazy-drawing
3175 (progn
3176 (undo-tree-move-down (/ (window-height) 2))
3177 (undo-tree-move-forward (max 2 (/ (window-width) 4)))) ; left margin
3178 ;; non-lazy drawing starts in centre at top of buffer
3179 (undo-tree-move-down 1) ; top margin
3180 (undo-tree-move-forward
3181 (max (/ (window-width) 2)
3182 (+ (undo-tree-node-char-lwidth node)
3183 ;; add space for left part of left-most time-stamp
3184 (if undo-tree-visualizer-timestamps
3185 (/ (- undo-tree-visualizer-spacing 4) 2)
3186 0)
3187 2)))) ; left margin
3188 ;; link starting node to its representation in visualizer
3189 (setf (undo-tree-node-marker node) (make-marker))
3190 (set-marker-insertion-type (undo-tree-node-marker node) nil)
3191 (move-marker (undo-tree-node-marker node) (point))
3192 ;; draw undo-tree
3193 (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
3194 node-list)
3195 (if (not undo-tree-visualizer-lazy-drawing)
3196 (undo-tree-extend-down node t)
3197 (undo-tree-extend-down node)
3198 (undo-tree-extend-up node)
3199 (setq node-list undo-tree-visualizer-needs-extending-down
3200 undo-tree-visualizer-needs-extending-down nil)
3201 (while node-list (undo-tree-extend-down (pop node-list)))))
3202 ;; highlight active branch
3203 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face))
3204 (undo-tree-highlight-active-branch
3205 (or undo-tree-visualizer-needs-extending-up
3206 (undo-tree-root undo-tree))))
3207 ;; highlight current node
3208 (undo-tree-draw-node (undo-tree-current undo-tree) 'current)))
3209
3210
3211 (defun undo-tree-extend-down (node &optional bottom)
3212 ;; Extend tree downwards starting from NODE and point. If BOTTOM is t,
3213 ;; extend all the way down to the leaves. If BOTTOM is a node, extend down
3214 ;; as far as that node. If BOTTOM is an integer, extend down as far as that
3215 ;; line. Otherwise, only extend visible portion of tree. NODE is assumed to
3216 ;; already have a node marker. Returns non-nil if anything was actually
3217 ;; extended.
3218 (let ((extended nil)
3219 (cur-stack (list node))
3220 next-stack)
3221 ;; don't bother extending if BOTTOM specifies an already-drawn node
3222 (unless (and (undo-tree-node-p bottom) (undo-tree-node-marker bottom))
3223 ;; draw nodes layer by layer
3224 (while (or cur-stack
3225 (prog1 (setq cur-stack next-stack)
3226 (setq next-stack nil)))
3227 (setq node (pop cur-stack))
3228 ;; if node is within range being drawn...
3229 (if (or (eq bottom t)
3230 (and (undo-tree-node-p bottom)
3231 (not (eq (undo-tree-node-previous node) bottom)))
3232 (and (integerp bottom)
3233 (>= bottom (line-number-at-pos
3234 (undo-tree-node-marker node))))
3235 (and (null bottom)
3236 (pos-visible-in-window-p (undo-tree-node-marker node)
3237 nil t)))
3238 ;; ...draw one layer of node's subtree (if not already drawn)
3239 (progn
3240 (unless (and (undo-tree-node-next node)
3241 (undo-tree-node-marker
3242 (nth (undo-tree-node-branch node)
3243 (undo-tree-node-next node))))
3244 (goto-char (undo-tree-node-marker node))
3245 (undo-tree-draw-subtree node)
3246 (setq extended t))
3247 (setq next-stack
3248 (append (undo-tree-node-next node) next-stack)))
3249 ;; ...otherwise, postpone drawing until later
3250 (push node undo-tree-visualizer-needs-extending-down))))
3251 extended))
3252
3253
3254 (defun undo-tree-extend-up (node &optional top)
3255 ;; Extend tree upwards starting from NODE. If TOP is t, extend all the way
3256 ;; to root. If TOP is a node, extend up as far as that node. If TOP is an
3257 ;; integer, extend up as far as that line. Otherwise, only extend visible
3258 ;; portion of tree. NODE is assumed to already have a node marker. Returns
3259 ;; non-nil if anything was actually extended.
3260 (let ((extended nil) parent n)
3261 ;; don't bother extending if TOP specifies an already-drawn node
3262 (unless (and (undo-tree-node-p top) (undo-tree-node-marker top))
3263 (while node
3264 (setq parent (undo-tree-node-previous node))
3265 ;; if we haven't reached root...
3266 (if parent
3267 ;; ...and node is within range being drawn...
3268 (if (or (eq top t)
3269 (and (undo-tree-node-p top) (not (eq node top)))
3270 (and (integerp top)
3271 (< top (line-number-at-pos
3272 (undo-tree-node-marker node))))
3273 (and (null top)
3274 ;; NOTE: check point in case window-start is outdated
3275 (< (min (line-number-at-pos (point))
3276 (line-number-at-pos (window-start)))
3277 (line-number-at-pos
3278 (undo-tree-node-marker node)))))
3279 ;; ...and it hasn't already been drawn
3280 (when (not (undo-tree-node-marker parent))
3281 ;; link parent node to its representation in visualizer
3282 (undo-tree-compute-widths parent)
3283 (undo-tree-move-to-parent node)
3284 (setf (undo-tree-node-marker parent) (make-marker))
3285 (set-marker-insertion-type
3286 (undo-tree-node-marker parent) nil)
3287 (move-marker (undo-tree-node-marker parent) (point))
3288 ;; draw subtree beneath parent
3289 (setq undo-tree-visualizer-needs-extending-down
3290 (nconc (delq node (undo-tree-draw-subtree parent))
3291 undo-tree-visualizer-needs-extending-down))
3292 (setq extended t))
3293 ;; ...otherwise, postpone drawing for later and exit
3294 (setq undo-tree-visualizer-needs-extending-up (when parent node)
3295 parent nil))
3296
3297 ;; if we've reached root, stop extending and add top margin
3298 (setq undo-tree-visualizer-needs-extending-up nil)
3299 (goto-char (undo-tree-node-marker node))
3300 (undo-tree-move-up 1) ; top margin
3301 (delete-region (point-min) (line-beginning-position)))
3302 ;; next iteration
3303 (setq node parent)))
3304 extended))
3305
3306
3307 (defun undo-tree-expand-down (from &optional to)
3308 ;; Expand tree downwards. FROM is the node to start expanding from. Stop
3309 ;; expanding at TO if specified. Otherwise, just expand visible portion of
3310 ;; tree and highlight active branch from FROM.
3311 (when undo-tree-visualizer-needs-extending-down
3312 (let ((inhibit-read-only t)
3313 node-list extended)
3314 ;; extend down as far as TO node
3315 (when to
3316 (setq extended (undo-tree-extend-down from to))
3317 (goto-char (undo-tree-node-marker to))
3318 (redisplay t)) ; force redisplay to scroll buffer if necessary
3319 ;; extend visible portion of tree downwards
3320 (setq node-list undo-tree-visualizer-needs-extending-down
3321 undo-tree-visualizer-needs-extending-down nil)
3322 (when node-list
3323 (dolist (n node-list)
3324 (when (undo-tree-extend-down n) (setq extended t)))
3325 ;; highlight active branch in newly-extended-down portion, if any
3326 (when extended
3327 (let ((undo-tree-insert-face
3328 'undo-tree-visualizer-active-branch-face))
3329 (undo-tree-highlight-active-branch from)))))))
3330
3331
3332 (defun undo-tree-expand-up (from &optional to)
3333 ;; Expand tree upwards. FROM is the node to start expanding from, TO is the
3334 ;; node to stop expanding at. If TO node isn't specified, just expand visible
3335 ;; portion of tree and highlight active branch down to FROM.
3336 (when undo-tree-visualizer-needs-extending-up
3337 (let ((inhibit-read-only t)
3338 extended node-list)
3339 ;; extend up as far as TO node
3340 (when to
3341 (setq extended (undo-tree-extend-up from to))
3342 (goto-char (undo-tree-node-marker to))
3343 ;; simulate auto-scrolling if close to top of buffer
3344 (when (<= (line-number-at-pos (point)) scroll-margin)
3345 (undo-tree-move-up (if (= scroll-conservatively 0)
3346 (/ (window-height) 2) 3))
3347 (when (undo-tree-extend-up to) (setq extended t))
3348 (goto-char (undo-tree-node-marker to))
3349 (unless (= scroll-conservatively 0) (recenter scroll-margin))))
3350 ;; extend visible portion of tree upwards
3351 (and undo-tree-visualizer-needs-extending-up
3352 (undo-tree-extend-up undo-tree-visualizer-needs-extending-up)
3353 (setq extended t))
3354 ;; extend visible portion of tree downwards
3355 (setq node-list undo-tree-visualizer-needs-extending-down
3356 undo-tree-visualizer-needs-extending-down nil)
3357 (dolist (n node-list) (undo-tree-extend-down n))
3358 ;; highlight active branch in newly-extended-up portion, if any
3359 (when extended
3360 (let ((undo-tree-insert-face
3361 'undo-tree-visualizer-active-branch-face))
3362 (undo-tree-highlight-active-branch
3363 (or undo-tree-visualizer-needs-extending-up
3364 (undo-tree-root buffer-undo-tree))
3365 from))))))
3366
3367
3368
3369 (defun undo-tree-highlight-active-branch (node &optional end)
3370 ;; Draw highlighted active branch below NODE in current buffer. Stop
3371 ;; highlighting at END node if specified.
3372 (let ((stack (list node)))
3373 ;; draw active branch
3374 (while stack
3375 (setq node (pop stack))
3376 (unless (or (eq node end)
3377 (memq node undo-tree-visualizer-needs-extending-down))
3378 (goto-char (undo-tree-node-marker node))
3379 (setq node (undo-tree-draw-subtree node 'active)
3380 stack (nconc stack node))))))
3381
3382
3383 (defun undo-tree-draw-node (node &optional current)
3384 ;; Draw symbol representing NODE in visualizer. If CURRENT is non-nil, node
3385 ;; is current node.
3386 (goto-char (undo-tree-node-marker node))
3387 (when undo-tree-visualizer-timestamps
3388 (undo-tree-move-backward (/ undo-tree-visualizer-spacing 2)))
3389
3390 (let* ((undo-tree-insert-face (and undo-tree-insert-face
3391 (or (and (consp undo-tree-insert-face)
3392 undo-tree-insert-face)
3393 (list undo-tree-insert-face))))
3394 (register (undo-tree-node-register node))
3395 (unmodified (if undo-tree-visualizer-parent-mtime
3396 (undo-tree-node-unmodified-p
3397 node undo-tree-visualizer-parent-mtime)
3398 (undo-tree-node-unmodified-p node)))
3399 node-string)
3400 ;; check node's register (if any) still stores appropriate undo-tree state
3401 (unless (and register
3402 (undo-tree-register-data-p
3403 (registerv-data (get-register register)))
3404 (eq node (undo-tree-register-data-node
3405 (registerv-data (get-register register)))))
3406 (setq register nil))
3407 ;; represent node by different symbols, depending on whether it's the
3408 ;; current node, is saved in a register, or corresponds to an unmodified
3409 ;; buffer
3410 (setq node-string
3411 (cond
3412 (undo-tree-visualizer-timestamps
3413 (undo-tree-timestamp-to-string
3414 (undo-tree-node-timestamp node)
3415 undo-tree-visualizer-relative-timestamps
3416 current register))
3417 (register (char-to-string register))
3418 (unmodified "s")
3419 (current "x")
3420 (t "o"))
3421 undo-tree-insert-face
3422 (nconc
3423 (cond
3424 (current '(undo-tree-visualizer-current-face))
3425 (unmodified '(undo-tree-visualizer-unmodified-face))
3426 (register '(undo-tree-visualizer-register-face)))
3427 undo-tree-insert-face))
3428 ;; draw node and link it to its representation in visualizer
3429 (undo-tree-insert node-string)
3430 (undo-tree-move-backward (if undo-tree-visualizer-timestamps
3431 (1+ (/ undo-tree-visualizer-spacing 2))
3432 1))
3433 (move-marker (undo-tree-node-marker node) (point))
3434 (put-text-property (point) (1+ (point)) 'undo-tree-node node)))
3435
3436
3437 (defun undo-tree-draw-subtree (node &optional active-branch)
3438 ;; Draw subtree rooted at NODE. The subtree will start from point.
3439 ;; If ACTIVE-BRANCH is non-nil, just draw active branch below NODE. Returns
3440 ;; list of nodes below NODE.
3441 (let ((num-children (length (undo-tree-node-next node)))
3442 node-list pos trunk-pos n)
3443 ;; draw node itself
3444 (undo-tree-draw-node node)
3445
3446 (cond
3447 ;; if we're at a leaf node, we're done
3448 ((= num-children 0))
3449
3450 ;; if node has only one child, draw it (not strictly necessary to deal
3451 ;; with this case separately, but as it's by far the most common case
3452 ;; this makes the code clearer and more efficient)
3453 ((= num-children 1)
3454 (undo-tree-move-down 1)
3455 (undo-tree-insert ?|)
3456 (undo-tree-move-backward 1)
3457 (undo-tree-move-down 1)
3458 (undo-tree-insert ?|)
3459 (undo-tree-move-backward 1)
3460 (undo-tree-move-down 1)
3461 (setq n (car (undo-tree-node-next node)))
3462 ;; link next node to its representation in visualizer
3463 (unless (markerp (undo-tree-node-marker n))
3464 (setf (undo-tree-node-marker n) (make-marker))
3465 (set-marker-insertion-type (undo-tree-node-marker n) nil))
3466 (move-marker (undo-tree-node-marker n) (point))
3467 ;; add next node to list of nodes to draw next
3468 (push n node-list))
3469
3470 ;; if node has multiple children, draw branches
3471 (t
3472 (undo-tree-move-down 1)
3473 (undo-tree-insert ?|)
3474 (undo-tree-move-backward 1)
3475 (move-marker (setq trunk-pos (make-marker)) (point))
3476 ;; left subtrees
3477 (undo-tree-move-backward
3478 (- (undo-tree-node-char-lwidth node)
3479 (undo-tree-node-char-lwidth
3480 (car (undo-tree-node-next node)))))
3481 (move-marker (setq pos (make-marker)) (point))
3482 (setq n (cons nil (undo-tree-node-next node)))
3483 (dotimes (i (/ num-children 2))
3484 (setq n (cdr n))
3485 (when (or (null active-branch)
3486 (eq (car n)
3487 (nth (undo-tree-node-branch node)
3488 (undo-tree-node-next node))))
3489 (undo-tree-move-forward 2)
3490 (undo-tree-insert ?_ (- trunk-pos pos 2))
3491 (goto-char pos)
3492 (undo-tree-move-forward 1)
3493 (undo-tree-move-down 1)
3494 (undo-tree-insert ?/)
3495 (undo-tree-move-backward 2)
3496 (undo-tree-move-down 1)
3497 ;; link node to its representation in visualizer
3498 (unless (markerp (undo-tree-node-marker (car n)))
3499 (setf (undo-tree-node-marker (car n)) (make-marker))
3500 (set-marker-insertion-type (undo-tree-node-marker (car n)) nil))
3501 (move-marker (undo-tree-node-marker (car n)) (point))
3502 ;; add node to list of nodes to draw next
3503 (push (car n) node-list))
3504 (goto-char pos)
3505 (undo-tree-move-forward
3506 (+ (undo-tree-node-char-rwidth (car n))
3507 (undo-tree-node-char-lwidth (cadr n))
3508 undo-tree-visualizer-spacing 1))
3509 (move-marker pos (point)))
3510 ;; middle subtree (only when number of children is odd)
3511 (when (= (mod num-children 2) 1)
3512 (setq n (cdr n))
3513 (when (or (null active-branch)
3514 (eq (car n)
3515 (nth (undo-tree-node-branch node)
3516 (undo-tree-node-next node))))
3517 (undo-tree-move-down 1)
3518 (undo-tree-insert ?|)
3519 (undo-tree-move-backward 1)
3520 (undo-tree-move-down 1)
3521 ;; link node to its representation in visualizer
3522 (unless (markerp (undo-tree-node-marker (car n)))
3523 (setf (undo-tree-node-marker (car n)) (make-marker))
3524 (set-marker-insertion-type (undo-tree-node-marker (car n)) nil))
3525 (move-marker (undo-tree-node-marker (car n)) (point))
3526 ;; add node to list of nodes to draw next
3527 (push (car n) node-list))
3528 (goto-char pos)
3529 (undo-tree-move-forward
3530 (+ (undo-tree-node-char-rwidth (car n))
3531 (if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0)
3532 undo-tree-visualizer-spacing 1))
3533 (move-marker pos (point)))
3534 ;; right subtrees
3535 (move-marker trunk-pos (1+ trunk-pos))
3536 (dotimes (i (/ num-children 2))
3537 (setq n (cdr n))
3538 (when (or (null active-branch)
3539 (eq (car n)
3540 (nth (undo-tree-node-branch node)
3541 (undo-tree-node-next node))))
3542 (goto-char trunk-pos)
3543 (undo-tree-insert ?_ (- pos trunk-pos 1))
3544 (goto-char pos)
3545 (undo-tree-move-backward 1)
3546 (undo-tree-move-down 1)
3547 (undo-tree-insert ?\\)
3548 (undo-tree-move-down 1)
3549 ;; link node to its representation in visualizer
3550 (unless (markerp (undo-tree-node-marker (car n)))
3551 (setf (undo-tree-node-marker (car n)) (make-marker))
3552 (set-marker-insertion-type (undo-tree-node-marker (car n)) nil))
3553 (move-marker (undo-tree-node-marker (car n)) (point))
3554 ;; add node to list of nodes to draw next
3555 (push (car n) node-list))
3556 (when (cdr n)
3557 (goto-char pos)
3558 (undo-tree-move-forward
3559 (+ (undo-tree-node-char-rwidth (car n))
3560 (if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0)
3561 undo-tree-visualizer-spacing 1))
3562 (move-marker pos (point))))
3563 ))
3564 ;; return list of nodes to draw next
3565 (nreverse node-list)))
3566
3567
3568 (defun undo-tree-node-char-lwidth (node)
3569 ;; Return left-width of NODE measured in characters.
3570 (if (= (length (undo-tree-node-next node)) 0) 0
3571 (- (* (+ undo-tree-visualizer-spacing 1) (undo-tree-node-lwidth node))
3572 (if (= (undo-tree-node-cwidth node) 0)
3573 (1+ (/ undo-tree-visualizer-spacing 2)) 0))))
3574
3575
3576 (defun undo-tree-node-char-rwidth (node)
3577 ;; Return right-width of NODE measured in characters.
3578 (if (= (length (undo-tree-node-next node)) 0) 0
3579 (- (* (+ undo-tree-visualizer-spacing 1) (undo-tree-node-rwidth node))
3580 (if (= (undo-tree-node-cwidth node) 0)
3581 (1+ (/ undo-tree-visualizer-spacing 2)) 0))))
3582
3583
3584 (defun undo-tree-insert (str &optional arg)
3585 ;; Insert character or string STR ARG times, overwriting, and using
3586 ;; `undo-tree-insert-face'.
3587 (unless arg (setq arg 1))
3588 (when (characterp str)
3589 (setq str (make-string arg str))
3590 (setq arg 1))
3591 (dotimes (i arg) (insert str))
3592 (setq arg (* arg (length str)))
3593 (undo-tree-move-forward arg)
3594 ;; make sure mark isn't active, otherwise `backward-delete-char' might
3595 ;; delete region instead of single char if transient-mark-mode is enabled
3596 (setq mark-active nil)
3597 (backward-delete-char arg)
3598 (when undo-tree-insert-face
3599 (put-text-property (- (point) arg) (point) 'face undo-tree-insert-face)))
3600
3601
3602 (defun undo-tree-move-down (&optional arg)
3603 ;; Move down, extending buffer if necessary.
3604 (let ((row (line-number-at-pos))
3605 (col (current-column))
3606 line)
3607 (unless arg (setq arg 1))
3608 (forward-line arg)
3609 (setq line (line-number-at-pos))
3610 ;; if buffer doesn't have enough lines, add some
3611 (when (/= line (+ row arg))
3612 (cond
3613 ((< arg 0)
3614 (insert (make-string (- line row arg) ?\n))
3615 (forward-line (+ arg (- row line))))
3616 (t (insert (make-string (- arg (- line row)) ?\n)))))
3617 (undo-tree-move-forward col)))
3618
3619
3620 (defun undo-tree-move-up (&optional arg)
3621 ;; Move up, extending buffer if necessary.
3622 (unless arg (setq arg 1))
3623 (undo-tree-move-down (- arg)))
3624
3625
3626 (defun undo-tree-move-forward (&optional arg)
3627 ;; Move forward, extending buffer if necessary.
3628 (unless arg (setq arg 1))
3629 (let (n)
3630 (cond
3631 ((>= arg 0)
3632 (setq n (- (line-end-position) (point)))
3633 (if (> n arg)
3634 (forward-char arg)
3635 (end-of-line)
3636 (insert (make-string (- arg n) ? ))))
3637 ((< arg 0)
3638 (setq arg (- arg))
3639 (setq n (- (point) (line-beginning-position)))
3640 (when (< (- n 2) arg) ; -2 to create left-margin
3641 ;; no space left - shift entire buffer contents right!
3642 (let ((pos (move-marker (make-marker) (point))))
3643 (set-marker-insertion-type pos t)
3644 (goto-char (point-min))
3645 (while (not (eobp))
3646 (insert-before-markers (make-string (- arg -2 n) ? ))
3647 (forward-line 1))
3648 (goto-char pos)))
3649 (backward-char arg)))))
3650
3651
3652 (defun undo-tree-move-backward (&optional arg)
3653 ;; Move backward, extending buffer if necessary.
3654 (unless arg (setq arg 1))
3655 (undo-tree-move-forward (- arg)))
3656
3657
3658 (defun undo-tree-move-to-parent (node)
3659 ;; Move to position of parent of NODE, extending buffer if necessary.
3660 (let* ((parent (undo-tree-node-previous node))
3661 (n (undo-tree-node-next parent))
3662 (l (length n)) p)
3663 (goto-char (undo-tree-node-marker node))
3664 (unless (= l 1)
3665 ;; move horizontally
3666 (setq p (undo-tree-position node n))
3667 (cond
3668 ;; node in centre subtree: no horizontal movement
3669 ((and (= (mod l 2) 1) (= p (/ l 2))))
3670 ;; node in left subtree: move right
3671 ((< p (/ l 2))
3672 (setq n (nthcdr p n))
3673 (undo-tree-move-forward
3674 (+ (undo-tree-node-char-rwidth (car n))
3675 (/ undo-tree-visualizer-spacing 2) 1))
3676 (dotimes (i (- (/ l 2) p 1))
3677 (setq n (cdr n))
3678 (undo-tree-move-forward
3679 (+ (undo-tree-node-char-lwidth (car n))
3680 (undo-tree-node-char-rwidth (car n))
3681 undo-tree-visualizer-spacing 1)))
3682 (when (= (mod l 2) 1)
3683 (setq n (cdr n))
3684 (undo-tree-move-forward
3685 (+ (undo-tree-node-char-lwidth (car n))
3686 (/ undo-tree-visualizer-spacing 2) 1))))
3687 (t ;; node in right subtree: move left
3688 (setq n (nthcdr (/ l 2) n))
3689 (when (= (mod l 2) 1)
3690 (undo-tree-move-backward
3691 (+ (undo-tree-node-char-rwidth (car n))
3692 (/ undo-tree-visualizer-spacing 2) 1))
3693 (setq n (cdr n)))
3694 (dotimes (i (- p (/ l 2) (mod l 2)))
3695 (undo-tree-move-backward
3696 (+ (undo-tree-node-char-lwidth (car n))
3697 (undo-tree-node-char-rwidth (car n))
3698 undo-tree-visualizer-spacing 1))
3699 (setq n (cdr n)))
3700 (undo-tree-move-backward
3701 (+ (undo-tree-node-char-lwidth (car n))
3702 (/ undo-tree-visualizer-spacing 2) 1)))))
3703 ;; move vertically
3704 (undo-tree-move-up 3)))
3705
3706
3707 (defun undo-tree-timestamp-to-string
3708 (timestamp &optional relative current register)
3709 ;; Convert TIMESTAMP to string (either absolute or RELATVE time), indicating
3710 ;; if it's the CURRENT node and/or has an associated REGISTER.
3711 (if relative
3712 ;; relative time
3713 (let ((time (floor (float-time
3714 (subtract-time (current-time) timestamp))))
3715 n)
3716 (setq time
3717 ;; years
3718 (if (> (setq n (/ time 315360000)) 0)
3719 (if (> n 999) "-ages" (format "-%dy" n))
3720 (setq time (% time 315360000))
3721 ;; days
3722 (if (> (setq n (/ time 86400)) 0)
3723 (format "-%dd" n)
3724 (setq time (% time 86400))
3725 ;; hours
3726 (if (> (setq n (/ time 3600)) 0)
3727 (format "-%dh" n)
3728 (setq time (% time 3600))
3729 ;; mins
3730 (if (> (setq n (/ time 60)) 0)
3731 (format "-%dm" n)
3732 ;; secs
3733 (format "-%ds" (% time 60)))))))
3734 (setq time (concat
3735 (if current "*" " ")
3736 time
3737 (if register (concat "[" (char-to-string register) "]")
3738 " ")))
3739 (setq n (length time))
3740 (if (< n 9)
3741 (concat (make-string (- 9 n) ? ) time)
3742 time))
3743 ;; absolute time
3744 (concat (if current "*" " ")
3745 (format-time-string "%H:%M:%S" timestamp)
3746 (if register
3747 (concat "[" (char-to-string register) "]")
3748 " "))))
3749
3750
3751
3752 \f
3753 ;;; =====================================================================
3754 ;;; Visualizer commands
3755
3756 (defun undo-tree-visualizer-mode ()
3757 "Major mode used in undo-tree visualizer.
3758
3759 The undo-tree visualizer can only be invoked from a buffer in
3760 which `undo-tree-mode' is enabled. The visualizer displays the
3761 undo history tree graphically, and allows you to browse around
3762 the undo history, undoing or redoing the corresponding changes in
3763 the parent buffer.
3764
3765 Within the undo-tree visualizer, the following keys are available:
3766
3767 \\{undo-tree-visualizer-map}"
3768 (interactive)
3769 (setq major-mode 'undo-tree-visualizer-mode)
3770 (setq mode-name "undo-tree-visualizer-mode")
3771 (use-local-map undo-tree-visualizer-map)
3772 (setq truncate-lines t)
3773 (setq cursor-type nil)
3774 (setq buffer-read-only t)
3775 (setq undo-tree-visualizer-selected-node nil)
3776 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))
3777
3778
3779
3780 (defun undo-tree-visualize-undo (&optional arg)
3781 "Undo changes. A numeric ARG serves as a repeat count."
3782 (interactive "p")
3783 (let ((old (undo-tree-current buffer-undo-tree))
3784 current)
3785 ;; unhighlight old current node
3786 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
3787 (inhibit-read-only t))
3788 (undo-tree-draw-node old))
3789 ;; undo in parent buffer
3790 (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
3791 (deactivate-mark)
3792 (unwind-protect
3793 (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-undo-1 arg))
3794 (setq current (undo-tree-current buffer-undo-tree))
3795 (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
3796 ;; when using lazy drawing, extend tree upwards as required
3797 (when undo-tree-visualizer-lazy-drawing
3798 (undo-tree-expand-up old current))
3799 ;; highlight new current node
3800 (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current))
3801 ;; update diff display, if any
3802 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
3803
3804
3805 (defun undo-tree-visualize-redo (&optional arg)
3806 "Redo changes. A numeric ARG serves as a repeat count."
3807 (interactive "p")
3808 (let ((old (undo-tree-current buffer-undo-tree))
3809 current)
3810 ;; unhighlight old current node
3811 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
3812 (inhibit-read-only t))
3813 (undo-tree-draw-node (undo-tree-current buffer-undo-tree)))
3814 ;; redo in parent buffer
3815 (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
3816 (deactivate-mark)
3817 (unwind-protect
3818 (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-redo-1 arg))
3819 (setq current (undo-tree-current buffer-undo-tree))
3820 (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
3821 ;; when using lazy drawing, extend tree downwards as required
3822 (when undo-tree-visualizer-lazy-drawing
3823 (undo-tree-expand-down old current))
3824 ;; highlight new current node
3825 (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current))
3826 ;; update diff display, if any
3827 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
3828
3829
3830 (defun undo-tree-visualize-switch-branch-right (arg)
3831 "Switch to next branch of the undo tree.
3832 This will affect which branch to descend when *redoing* changes
3833 using `undo-tree-redo' or `undo-tree-visualizer-redo'."
3834 (interactive "p")
3835 ;; un-highlight old active branch below current node
3836 (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree)))
3837 (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
3838 (inhibit-read-only t))
3839 (undo-tree-highlight-active-branch (undo-tree-current buffer-undo-tree)))
3840 ;; increment branch
3841 (let ((branch (undo-tree-node-branch (undo-tree-current buffer-undo-tree))))
3842 (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
3843 (cond
3844 ((>= (+ branch arg) (undo-tree-num-branches))
3845 (1- (undo-tree-num-branches)))
3846 ((<= (+ branch arg) 0) 0)
3847 (t (+ branch arg))))
3848 (let ((inhibit-read-only t))
3849 ;; highlight new active branch below current node
3850 (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree)))
3851 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face))
3852 (undo-tree-highlight-active-branch (undo-tree-current buffer-undo-tree)))
3853 ;; re-highlight current node
3854 (undo-tree-draw-node (undo-tree-current buffer-undo-tree) 'current))))
3855
3856
3857 (defun undo-tree-visualize-switch-branch-left (arg)
3858 "Switch to previous branch of the undo tree.
3859 This will affect which branch to descend when *redoing* changes
3860 using `undo-tree-redo' or `undo-tree-visualizer-redo'."
3861 (interactive "p")
3862 (undo-tree-visualize-switch-branch-right (- arg)))
3863
3864
3865 (defun undo-tree-visualizer-quit ()
3866 "Quit the undo-tree visualizer."
3867 (interactive)
3868 (undo-tree-clear-visualizer-data buffer-undo-tree)
3869 ;; remove kill visualizer hook from parent buffer
3870 (unwind-protect
3871 (with-current-buffer undo-tree-visualizer-parent-buffer
3872 (remove-hook 'before-change-functions 'undo-tree-kill-visualizer t))
3873 ;; kill diff buffer, if any
3874 (when undo-tree-visualizer-diff (undo-tree-visualizer-hide-diff))
3875 (let ((parent undo-tree-visualizer-parent-buffer)
3876 window)
3877 ;; kill visualizer buffer
3878 (kill-buffer nil)
3879 ;; switch back to parent buffer
3880 (unwind-protect
3881 (if (setq window (get-buffer-window parent))
3882 (select-window window)
3883 (switch-to-buffer parent))))))
3884
3885
3886 (defun undo-tree-visualizer-abort ()
3887 "Quit the undo-tree visualizer and return buffer to original state."
3888 (interactive)
3889 (let ((node undo-tree-visualizer-initial-node))
3890 (undo-tree-visualizer-quit)
3891 (undo-tree-set node)))
3892
3893
3894 (defun undo-tree-visualizer-set (&optional pos)
3895 "Set buffer to state corresponding to undo tree node
3896 at POS, or point if POS is nil."
3897 (interactive)
3898 (unless pos (setq pos (point)))
3899 (let ((node (get-text-property pos 'undo-tree-node)))
3900 (when node
3901 ;; set parent buffer to state corresponding to node at POS
3902 (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
3903 (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-set node))
3904 (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
3905 ;; re-draw undo tree
3906 (let ((inhibit-read-only t)) (undo-tree-draw-tree buffer-undo-tree))
3907 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
3908
3909
3910 (defun undo-tree-visualizer-mouse-set (pos)
3911 "Set buffer to state corresponding to undo tree node
3912 at mouse event POS."
3913 (interactive "@e")
3914 (undo-tree-visualizer-set (event-start (nth 1 pos))))
3915
3916
3917 (defun undo-tree-visualize-undo-to-x (&optional x)
3918 "Undo to last branch point, register, or saved state.
3919 If X is 'branch, undo to last branch point. If X is 'register,
3920 undo to last register. If X is 'saved, undo to last saved state.
3921
3922 Interactively, a single \\[universal-argument] specifies
3923 `branch', a double \\[universal-argument] \[universal-argument]
3924 spcified `saved', and a negative prefix argument specifies
3925 `register'."
3926 (interactive "P")
3927 (when (and (called-interactively-p 'any) x)
3928 (setq x (prefix-numeric-value x)
3929 x (cond
3930 ((< x 0) 'register)
3931 ((<= x 4) 'branch)
3932 (t 'saved))))
3933 (let ((current (undo-tree-current buffer-undo-tree))
3934 r)
3935 (while (and (undo-tree-node-previous current)
3936 (or (undo-tree-visualize-undo) t)
3937 (setq current (undo-tree-current buffer-undo-tree))
3938 ;; branch point
3939 (not (or (and (or (null x) (eq x 'branch))
3940 (> (undo-tree-num-branches) 1))
3941 ;; register
3942 (and (or (null x) (eq x 'register))
3943 (setq r (undo-tree-node-register current))
3944 (undo-tree-register-data-p
3945 (setq r (registerv-data (get-register r))))
3946 (eq current (undo-tree-register-data-node r)))
3947 ;; saved state
3948 (and (or (null x) (eq x 'saved))
3949 (undo-tree-node-unmodified-p current))
3950 ))))))
3951
3952
3953 (defun undo-tree-visualize-redo-to-x (&optional x)
3954 "Redo to next branch point or register.
3955 If X is the symbol `branch', redo to next branch point ignoring
3956 registers. If X is the symbol 'register', redo to next register,
3957 ignoring branch points.
3958
3959 Interactively, a positive prefix argument specifies `branch', and
3960 a negative prefix argument specifies `register'."
3961 (interactive "P")
3962 (when (and (called-interactively-p 'any) x)
3963 (setq x (prefix-numeric-value x)
3964 x (cond
3965 ((< x 0) 'register)
3966 ((<= x 4) 'branch)
3967 (t 'saved))))
3968 (let ((current (undo-tree-current buffer-undo-tree))
3969 r)
3970 (while (and (undo-tree-node-next current)
3971 (or (undo-tree-visualize-redo) t)
3972 (setq current (undo-tree-current buffer-undo-tree))
3973 ;; branch point
3974 (not (or (and (or (null x) (eq x 'branch))
3975 (> (undo-tree-num-branches) 1))
3976 ;; register
3977 (and (or (null x) (eq x 'register))
3978 (setq r (undo-tree-node-register current))
3979 (undo-tree-register-data-p
3980 (setq r (registerv-data (get-register r))))
3981 (eq current (undo-tree-register-data-node r)))
3982 ;; saved state
3983 (and (or (null x) (eq x 'saved))
3984 (undo-tree-node-unmodified-p current))
3985 ))))))
3986
3987
3988 (defun undo-tree-visualizer-toggle-timestamps ()
3989 "Toggle display of time-stamps."
3990 (interactive)
3991 (setq undo-tree-visualizer-timestamps (not undo-tree-visualizer-timestamps))
3992 (setq undo-tree-visualizer-spacing (undo-tree-visualizer-calculate-spacing))
3993 ;; redraw tree
3994 (let ((inhibit-read-only t)) (undo-tree-draw-tree buffer-undo-tree)))
3995
3996
3997 (defun undo-tree-visualizer-scroll-left (&optional arg)
3998 (interactive "p")
3999 (scroll-left (or arg 1) t))
4000
4001
4002 (defun undo-tree-visualizer-scroll-right (&optional arg)
4003 (interactive "p")
4004 (scroll-right (or arg 1) t))
4005
4006
4007 (defun undo-tree-visualizer-scroll-up (&optional arg)
4008 (interactive "P")
4009 (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
4010 (undo-tree-visualizer-scroll-down arg)
4011 ;; scroll up and expand newly-visible portion of tree
4012 (unwind-protect
4013 (scroll-up-command arg)
4014 (undo-tree-expand-down
4015 (nth (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
4016 (undo-tree-node-next (undo-tree-current buffer-undo-tree)))))
4017 ;; signal error if at eob
4018 (when (and (not undo-tree-visualizer-needs-extending-down) (eobp))
4019 (scroll-up))))
4020
4021
4022 (defun undo-tree-visualizer-scroll-down (&optional arg)
4023 (interactive "P")
4024 (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
4025 (undo-tree-visualizer-scroll-up arg)
4026 ;; ensure there's enough room at top of buffer to scroll
4027 (let ((scroll-lines
4028 (or arg (- (window-height) next-screen-context-lines)))
4029 (window-line (1- (line-number-at-pos (window-start)))))
4030 (when (and undo-tree-visualizer-needs-extending-up
4031 (< window-line scroll-lines))
4032 (let ((inhibit-read-only t))
4033 (goto-char (point-min))
4034 (undo-tree-move-up (- scroll-lines window-line)))))
4035 ;; scroll down and expand newly-visible portion of tree
4036 (unwind-protect
4037 (scroll-down-command arg)
4038 (undo-tree-expand-up
4039 (undo-tree-node-previous (undo-tree-current buffer-undo-tree))))
4040 ;; signal error if at bob
4041 (when (and (not undo-tree-visualizer-needs-extending-down) (bobp))
4042 (scroll-down))))
4043
4044
4045
4046 \f
4047 ;;; =====================================================================
4048 ;;; Visualizer selection mode
4049
4050 (defun undo-tree-visualizer-selection-mode ()
4051 "Major mode used to select nodes in undo-tree visualizer."
4052 (interactive)
4053 (setq major-mode 'undo-tree-visualizer-selection-mode)
4054 (setq mode-name "undo-tree-visualizer-selection-mode")
4055 (use-local-map undo-tree-visualizer-selection-map)
4056 (setq cursor-type 'box)
4057 (setq undo-tree-visualizer-selected-node
4058 (undo-tree-current buffer-undo-tree))
4059 ;; erase diff (if any), as initially selected node is identical to current
4060 (when undo-tree-visualizer-diff
4061 (let ((buff (get-buffer undo-tree-diff-buffer-name))
4062 (inhibit-read-only t))
4063 (when buff (with-current-buffer buff (erase-buffer))))))
4064
4065
4066 (defun undo-tree-visualizer-select-previous (&optional arg)
4067 "Move to previous node."
4068 (interactive "p")
4069 (let ((node undo-tree-visualizer-selected-node))
4070 (catch 'top
4071 (dotimes (i arg)
4072 (unless (undo-tree-node-previous node) (throw 'top t))
4073 (setq node (undo-tree-node-previous node))))
4074 ;; when using lazy drawing, extend tree upwards as required
4075 (when undo-tree-visualizer-lazy-drawing
4076 (undo-tree-expand-up undo-tree-visualizer-selected-node node))
4077 ;; update diff display, if any
4078 (when (and undo-tree-visualizer-diff
4079 (not (eq node undo-tree-visualizer-selected-node)))
4080 (undo-tree-visualizer-update-diff node))
4081 ;; move to selected node
4082 (goto-char (undo-tree-node-marker node))
4083 (setq undo-tree-visualizer-selected-node node)))
4084
4085
4086 (defun undo-tree-visualizer-select-next (&optional arg)
4087 "Move to next node."
4088 (interactive "p")
4089 (let ((node undo-tree-visualizer-selected-node))
4090 (catch 'bottom
4091 (dotimes (i arg)
4092 (unless (nth (undo-tree-node-branch node) (undo-tree-node-next node))
4093 (throw 'bottom t))
4094 (setq node
4095 (nth (undo-tree-node-branch node) (undo-tree-node-next node)))))
4096 ;; when using lazy drawing, extend tree upwards as required
4097 (when undo-tree-visualizer-lazy-drawing
4098 (undo-tree-expand-down undo-tree-visualizer-selected-node node))
4099 ;; update diff display, if any
4100 (when (and undo-tree-visualizer-diff
4101 (not (eq node undo-tree-visualizer-selected-node)))
4102 (undo-tree-visualizer-update-diff node))
4103 ;; move to selected node
4104 (goto-char (undo-tree-node-marker node))
4105 (setq undo-tree-visualizer-selected-node node)))
4106
4107
4108 (defun undo-tree-visualizer-select-right (&optional arg)
4109 "Move right to a sibling node."
4110 (interactive "p")
4111 (let ((node undo-tree-visualizer-selected-node)
4112 end)
4113 (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node))
4114 (setq end (line-end-position))
4115 (catch 'end
4116 (dotimes (i arg)
4117 (while (or (null node) (eq node undo-tree-visualizer-selected-node))
4118 (forward-char)
4119 (setq node (get-text-property (point) 'undo-tree-node))
4120 (when (= (point) end) (throw 'end t)))))
4121 (goto-char (undo-tree-node-marker
4122 (or node undo-tree-visualizer-selected-node)))
4123 (when (and undo-tree-visualizer-diff node
4124 (not (eq node undo-tree-visualizer-selected-node)))
4125 (undo-tree-visualizer-update-diff node))
4126 (when node (setq undo-tree-visualizer-selected-node node))))
4127
4128
4129 (defun undo-tree-visualizer-select-left (&optional arg)
4130 "Move left to a sibling node."
4131 (interactive "p")
4132 (let ((node (get-text-property (point) 'undo-tree-node))
4133 beg)
4134 (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node))
4135 (setq beg (line-beginning-position))
4136 (catch 'beg
4137 (dotimes (i arg)
4138 (while (or (null node) (eq node undo-tree-visualizer-selected-node))
4139 (backward-char)
4140 (setq node (get-text-property (point) 'undo-tree-node))
4141 (when (= (point) beg) (throw 'beg t)))))
4142 (goto-char (undo-tree-node-marker
4143 (or node undo-tree-visualizer-selected-node)))
4144 (when (and undo-tree-visualizer-diff node
4145 (not (eq node undo-tree-visualizer-selected-node)))
4146 (undo-tree-visualizer-update-diff node))
4147 (when node (setq undo-tree-visualizer-selected-node node))))
4148
4149
4150 \f
4151 ;;; =====================================================================
4152 ;;; Visualizer diff display
4153
4154 (defun undo-tree-visualizer-toggle-diff ()
4155 "Toggle diff display in undo-tree visualizer."
4156 (interactive)
4157 (if undo-tree-visualizer-diff
4158 (undo-tree-visualizer-hide-diff)
4159 (undo-tree-visualizer-show-diff)))
4160
4161
4162 (defun undo-tree-visualizer-selection-toggle-diff ()
4163 "Toggle diff display in undo-tree visualizer selection mode."
4164 (interactive)
4165 (if undo-tree-visualizer-diff
4166 (undo-tree-visualizer-hide-diff)
4167 (let ((node (get-text-property (point) 'undo-tree-node)))
4168 (when node (undo-tree-visualizer-show-diff node)))))
4169
4170
4171 (defun undo-tree-visualizer-show-diff (&optional node)
4172 ;; show visualizer diff display
4173 (setq undo-tree-visualizer-diff t)
4174 (let ((buff (with-current-buffer undo-tree-visualizer-parent-buffer
4175 (undo-tree-diff node)))
4176 (display-buffer-mark-dedicated 'soft)
4177 win)
4178 (setq win (split-window))
4179 (set-window-buffer win buff)
4180 (shrink-window-if-larger-than-buffer win)))
4181
4182
4183 (defun undo-tree-visualizer-hide-diff ()
4184 ;; hide visualizer diff display
4185 (setq undo-tree-visualizer-diff nil)
4186 (let ((win (get-buffer-window undo-tree-diff-buffer-name)))
4187 (when win (with-selected-window win (kill-buffer-and-window)))))
4188
4189
4190 (defun undo-tree-diff (&optional node)
4191 ;; Create diff between current state and NODE (or previous state, if NODE is
4192 ;; null). Returns buffer containing diff.
4193 (let (tmpfile buff)
4194 ;; generate diff
4195 (let ((undo-tree-inhibit-kill-visualizer t)
4196 (current (undo-tree-current buffer-undo-tree)))
4197 (undo-tree-set (or node (undo-tree-node-previous current) current)
4198 'preserve-timestamps)
4199 (setq tmpfile (diff-file-local-copy (current-buffer)))
4200 (undo-tree-set current 'preserve-timestamps))
4201 (setq buff (diff-no-select
4202 (current-buffer) tmpfile nil 'noasync
4203 (get-buffer-create undo-tree-diff-buffer-name)))
4204 ;; delete process messages and useless headers from diff buffer
4205 (with-current-buffer buff
4206 (goto-char (point-min))
4207 (delete-region (point) (1+ (line-end-position 3)))
4208 (goto-char (point-max))
4209 (forward-line -2)
4210 (delete-region (point) (point-max))
4211 (setq cursor-type nil)
4212 (setq buffer-read-only t))
4213 buff))
4214
4215
4216 (defun undo-tree-visualizer-update-diff (&optional node)
4217 ;; update visualizer diff display to show diff between current state and
4218 ;; NODE (or previous state, if NODE is null)
4219 (with-current-buffer undo-tree-visualizer-parent-buffer
4220 (undo-tree-diff node))
4221 (let ((win (get-buffer-window undo-tree-diff-buffer-name)))
4222 (when win
4223 (balance-windows)
4224 (shrink-window-if-larger-than-buffer win))))
4225
4226
4227
4228 (provide 'undo-tree)
4229
4230 ;;; undo-tree.el ends here