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