| 5039 |      1 | (*  Title:      Pure/General/history.ML
 | 
|  |      2 |     ID:         $Id$
 | 
|  |      3 |     Author:     Markus Wenzel, TU Muenchen
 | 
|  |      4 | 
 | 
| 6680 |      5 | Histories of values, with undo and redo, and optional limit.
 | 
| 5039 |      6 | *)
 | 
|  |      7 | 
 | 
|  |      8 | signature HISTORY =
 | 
|  |      9 | sig
 | 
|  |     10 |   type 'a T
 | 
| 6680 |     11 |   val init: int option -> 'a -> 'a T
 | 
|  |     12 |   val is_initial: 'a T -> bool
 | 
| 5039 |     13 |   val current: 'a T -> 'a
 | 
| 16496 |     14 |   val previous: 'a T -> 'a option
 | 
| 7715 |     15 |   val clear: int -> 'a T -> 'a T
 | 
| 5039 |     16 |   val undo: 'a T -> 'a T
 | 
|  |     17 |   val redo: 'a T -> 'a T
 | 
| 21175 |     18 |   val apply': 'a -> ('a -> 'a) -> 'a T -> 'a T
 | 
| 5039 |     19 |   val apply: ('a -> 'a) -> 'a T -> 'a T
 | 
| 23359 |     20 |   val map_current: ('a -> 'a) -> 'a T -> 'a T
 | 
| 5039 |     21 | end;
 | 
|  |     22 | 
 | 
|  |     23 | structure History: HISTORY =
 | 
|  |     24 | struct
 | 
|  |     25 | 
 | 
|  |     26 | datatype 'a T =
 | 
| 6680 |     27 |   History of 'a * (int option * int * 'a list * 'a list);
 | 
| 5039 |     28 | 
 | 
| 6680 |     29 | fun init lim x = History (x, (lim, 0, [], []));
 | 
|  |     30 | 
 | 
|  |     31 | fun is_initial (History (_, (_, len, _, _))) = len = 0;
 | 
| 5039 |     32 | 
 | 
| 6680 |     33 | fun current (History (x, _)) = x;
 | 
|  |     34 | 
 | 
| 16496 |     35 | fun previous (History (_, (_, _, x :: _, _))) = SOME x
 | 
|  |     36 |   | previous _ = NONE;
 | 
|  |     37 | 
 | 
| 7715 |     38 | fun clear n (History (x, (lim, len, undo_list, redo_list))) =
 | 
| 15570 |     39 |   History (x, (lim, Int.max (0, len - n), Library.drop (n, undo_list), redo_list));
 | 
| 5039 |     40 | 
 | 
| 6680 |     41 | fun undo (History (_, (_, _, [], _))) = error "No further undo information"
 | 
|  |     42 |   | undo (History (x, (lim, len, u :: undo_list, redo_list))) =
 | 
|  |     43 |       History (u, (lim, len - 1, undo_list, x :: redo_list));
 | 
| 5039 |     44 | 
 | 
| 6680 |     45 | fun redo (History (_, (_, _, _, []))) = error "No further redo information"
 | 
|  |     46 |   | redo (History (x, (lim, len, undo_list, r :: redo_list))) =
 | 
|  |     47 |       History (r, (lim, len + 1, x :: undo_list, redo_list));
 | 
|  |     48 | 
 | 
| 15531 |     49 | fun push NONE _ x xs = x :: xs
 | 
|  |     50 |   | push (SOME 0) _ _ _ = []
 | 
| 15570 |     51 |   | push (SOME n) len x xs = if len < n then x :: xs else Library.take (n, x :: xs);
 | 
| 5039 |     52 | 
 | 
| 21175 |     53 | fun apply' x' f (History (x, (lim, len, undo_list, _))) =
 | 
|  |     54 |   History (f x, (lim, len + 1, push lim len x' undo_list, []));
 | 
| 5039 |     55 | 
 | 
| 21175 |     56 | fun apply f hist = apply' (current hist) f hist;
 | 
| 6680 |     57 | 
 | 
| 23359 |     58 | fun map_current f (History (x, hist)) = History (f x, hist);
 | 
| 5039 |     59 | 
 | 
|  |     60 | end;
 |