⍝ Derive undo/redo function: commit←(⎕ns'')UndoRedo ⍝ derive a commit function '!'commit 0 ⍝ initialise history stacks. '?'commit 0 ⍝ both stacks empty. 0 0 A B C D←'now' 'is' 'the' 'time' ⍝ initial application state. commit A B C D ⍝ commit application state. A B←'then' 'was' ⍝ change state, commit A B C D ⍝ commit changes. A C←'that' 'a' ⍝ change state, commit A B C D ⍝ commit changes. B D←'took' 'while' ⍝ change state, ⍕A B C D ⍝ show current state that took a while '?'commit 0 ⍝ undo stack present. 0 3 A B C D←'<'commit A B C D ⍝ Undo last change, ⍕A B C D ⍝ show current state that was a time '?'commit 0 ⍝ items on both stacks. 1 2 A B C D←'<'commit A B C D ⍝ and previous change, ⍕A B C D ⍝ show current state then was the time A B C D←'<'commit A B C D ⍝ and change before that. ⍕A B C D ⍝ show current state. now is the time '?'commit 0 ⍝ undo stack empty. 3 0 A B C D← '>'commit A B C D ⍝ Redo last undo. ⍕A B C D ⍝ show current state. then was the time A B C D← '>'commit A B C D ⍝ Redo previous undo. ⍕A B C D ⍝ show current state. that was a time A B C D← '>'commit A B C D ⍝ Redo undo before that. ⍕A B C D ⍝ show current state. that took a while A B C D←'<'commit A B C D ⍝ Undo last Redo. ⍕A B C D ⍝ show current state. that was a time A B C D←'<'commit A B C D ⍝ Undo previous redo. ⍕A B C D ⍝ show current state. then was the time A B C D←'<'commit A B C D ⍝ Undo redo before that. ⍕A B C D ⍝ show current state. now is the time commit¨⍳10 ⍝ commit 10 transactions. '?'commit 0 ⍝ 10 items in undo stack. 0 10 '↑'commit 4 ⍝ cut to ... '?'commit 0 ⍝ ... 4 items. 0 4 '!'commit 0 ⍝ clear history commit¨ 1 2 3 ⍝ commits ⍕'⊃'commit '∘' ⍝ most recent undo/redo (Kai) 3 ∘ '<'commit 4 ⍝ undo 3 '⊃'commit '∘' ⍝ most recent undo/redo 2 4 '!'commit 0 ⍝ clear history '≠'commit¨ 1 2 2 3 3 3 4 ⍝ avoid duplicates '?'commit 0 ⍝ only 4 commits 0 4 ⍝ The following example shows that the space overhead of history is small. rand←{1e4?1e4} a b c d e f g h i j←rand¨⍳10 ⍝ ten large variables. '!'commit 0 ⍝ initialise history. wsused←{ ⍝ WS bytes used. wa←⎕wa 6::wa-⎕wa _←⍺⍺ ⍵ } commit a b c d e f g h i j ⍝ commit vars. 2000>|commit wsused a b c d e f g h i j ⍝ committing unchanged vars ... 1 2000>|commit wsused a b c d e f g h i j ⍝ ... consumes little workspace 1 2000>|commit wsused a b c d e f g h i j ⍝ ... consumes little workspace 1 ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝ This version uses a limited size vector for history ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝ UndoRedoV←{⎕ml←0 ⍝ Derive undo/redo fn (vector history) ⍺←⊢ ⍝ default: commit values. pop←{(⊃⍵)(1↓⍵)} ⍝ pop top vector item. psh←{(⊂⍺),⍵} ⍝ push ⍺ to vector ⍵. 1≡⍺ 1:⍺⍺{ ⍝ monadic commit: push new hist record. size←⍺.(max⌊1+⍴undo) ⍝ max size of undo vector. ⍺.undo←size↑⍵ psh ⍺.undo ⍝ push new undo record. 1:⍺.redo←⍬ ⍝ discard redo history. }⍵ '!'≡⍺:⍺⍺.(redo undo max←⍬ ⍬ ⍵) ⍝ initialize history vectors. '?'≡⍺:,↑⍴¨⍺⍺.(redo undo) ⍝ query history vectors. '<'≡⍺:⍺⍺{ ⍝ undo: 0=⍴⍺.undo:⍵ ⍝ no more undo: state unchanged. ⍺.redo←⍵ psh ⍺.redo ⍝ push current state on redo vector. ⊃last ⍺.undo←pop ⍺.undo ⍝ pop last state. }⍵ '>'≡⍺:⍺⍺{ ⍝ redo: 0=⍴⍺.redo:⍵ ⍝ no more redo: state unchanged. ⍺.undo←⍵ psh ⍺.undo ⍝ push current state on undo vector. ⊃next ⍺.redo←pop ⍺.redo ⍝ pop last state. }⍵ '↑'≡⍺:⍺⍺{ ⍝ resize undo vector. ⍺.max←⍵ ⍝ set new undo vector size limit. ⍺.(undo←(⍵⌊⍴undo)↑undo) ⍝ truncate undo vector. 1:⍺.redo←⍬ ⍝ remove redo records. }⍵ } commitV←(⎕ns'')UndoRedoV '!'commitV 4 ⍝ history limited to 4 records. ⍕commitV¨⍳10 ⍝ commit 10 transactions. '?'commitV 0 ⍝ last 4 items in undo vector. 0 4 '<'commitV ¨10+⍳2 ⍝ undo last two changes. 10 9 '?'commitV 0 ⍝ lengths of redo and undo vectors. 2 2 '<'commitV ¨12+⍳4 ⍝ only first 2 undos take effect. 8 7 15 16 '?'commitV 0 ⍝ sizes of redo and undo vectors. 4 0 '>'commitV ¨16+⍳3 ⍝ redo 3 transactions. 14 13 12 '?'commitV 0 ⍝ sizes of redo and undo vectors. 1 3 '↑'commitV 2 ⍝ reduce history size. '?'commitV 0 ⍝ sizes of redo and undo vectors. 0 2 ⍝∇ UndoRedo Back to: code Back to: Workspaces