Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4761 lines
182 KiB

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