Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
stratact
liner
Commits
ff8ab197
Commit
ff8ab197
authored
Feb 01, 2017
by
Matthew Nicholson
Browse files
support undoing commands in groups
This is necessary to support proper undoing in insert mode.
parent
688dca65
Changes
1
Hide whitespace changes
Inline
Side-by-side
src/buffer.rs
View file @
ff8ab197
...
...
@@ -7,6 +7,8 @@ use std::fmt::{self, Write as FmtWrite};
pub
enum
Action
{
Insert
{
start
:
usize
,
text
:
Vec
<
char
>
},
Remove
{
start
:
usize
,
text
:
Vec
<
char
>
},
StartGroup
,
EndGroup
,
}
impl
Action
{
...
...
@@ -16,6 +18,7 @@ impl Action {
Action
::
Remove
{
start
,
ref
text
}
=>
{
buf
.remove_raw
(
start
,
start
+
text
.len
());
}
Action
::
StartGroup
|
Action
::
EndGroup
=>
{}
}
}
...
...
@@ -25,6 +28,7 @@ impl Action {
buf
.remove_raw
(
start
,
start
+
text
.len
());
}
Action
::
Remove
{
start
,
ref
text
}
=>
buf
.insert_raw
(
start
,
&
text
[
..
]),
Action
::
StartGroup
|
Action
::
EndGroup
=>
{}
}
}
}
...
...
@@ -87,26 +91,66 @@ impl Buffer {
self
.undone_actions
.clear
();
}
pub
fn
start_undo_group
(
&
mut
self
)
{
self
.actions
.push
(
Action
::
StartGroup
);
}
pub
fn
end_undo_group
(
&
mut
self
)
{
self
.actions
.push
(
Action
::
EndGroup
);
}
pub
fn
undo
(
&
mut
self
)
->
bool
{
match
self
.actions
.pop
()
{
None
=>
false
,
Some
(
act
)
=>
{
act
.undo
(
self
);
self
.undone_actions
.push
(
act
);
true
use
Action
::
*
;
let
did
=
!
self
.actions
.is_empty
();
let
mut
group_nest
=
0
;
let
mut
group_count
=
0
;
while
let
Some
(
act
)
=
self
.actions
.pop
()
{
act
.undo
(
self
);
self
.undone_actions
.push
(
act
.clone
());
match
act
{
EndGroup
=>
{
group_nest
+=
1
;
group_count
=
0
;
}
StartGroup
=>
group_nest
-=
1
,
// count the actions in this group so we can ignore empty groups below
_
=>
group_count
+=
1
,
}
// if we aren't in a group, and the last group wasn't empty
if
group_nest
==
0
&&
group_count
>
0
{
break
;
}
}
did
}
pub
fn
redo
(
&
mut
self
)
->
bool
{
match
self
.undone_actions
.pop
()
{
None
=>
false
,
Some
(
act
)
=>
{
act
.do_on
(
self
);
self
.actions
.push
(
act
);
true
use
Action
::
*
;
let
did
=
!
self
.undone_actions
.is_empty
();
let
mut
group_nest
=
0
;
let
mut
group_count
=
0
;
while
let
Some
(
act
)
=
self
.undone_actions
.pop
()
{
act
.do_on
(
self
);
self
.actions
.push
(
act
.clone
());
match
act
{
StartGroup
=>
{
group_nest
+=
1
;
group_count
=
0
;
}
EndGroup
=>
group_nest
-=
1
,
// count the actions in this group so we can ignore empty groups below
_
=>
group_count
+=
1
,
}
// if we aren't in a group, and the last group wasn't empty
if
group_nest
==
0
&&
group_count
>
0
{
break
;
}
}
did
}
pub
fn
revert
(
&
mut
self
)
->
bool
{
...
...
@@ -288,4 +332,62 @@ mod tests {
buf
.undo
();
assert_eq!
(
String
::
from
(
buf
),
"abcdefg"
);
}
#[test]
fn
test_undo_group
()
{
let
mut
buf
=
Buffer
::
new
();
buf
.insert
(
0
,
&
[
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
]);
buf
.start_undo_group
();
buf
.remove
(
0
,
1
);
buf
.remove
(
0
,
1
);
buf
.remove
(
0
,
1
);
buf
.end_undo_group
();
assert_eq!
(
buf
.undo
(),
true
);
assert_eq!
(
String
::
from
(
buf
),
"abcdefg"
);
}
#[test]
fn
test_redo_group
()
{
let
mut
buf
=
Buffer
::
new
();
buf
.insert
(
0
,
&
[
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
]);
buf
.start_undo_group
();
buf
.remove
(
0
,
1
);
buf
.remove
(
0
,
1
);
buf
.remove
(
0
,
1
);
buf
.end_undo_group
();
assert_eq!
(
buf
.undo
(),
true
);
assert_eq!
(
buf
.redo
(),
true
);
assert_eq!
(
String
::
from
(
buf
),
"defg"
);
}
#[test]
fn
test_nested_undo_group
()
{
let
mut
buf
=
Buffer
::
new
();
buf
.insert
(
0
,
&
[
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
]);
buf
.start_undo_group
();
buf
.remove
(
0
,
1
);
buf
.start_undo_group
();
buf
.remove
(
0
,
1
);
buf
.end_undo_group
();
buf
.remove
(
0
,
1
);
buf
.end_undo_group
();
assert_eq!
(
buf
.undo
(),
true
);
assert_eq!
(
String
::
from
(
buf
),
"abcdefg"
);
}
#[test]
fn
test_nested_redo_group
()
{
let
mut
buf
=
Buffer
::
new
();
buf
.insert
(
0
,
&
[
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
]);
buf
.start_undo_group
();
buf
.remove
(
0
,
1
);
buf
.start_undo_group
();
buf
.remove
(
0
,
1
);
buf
.end_undo_group
();
buf
.remove
(
0
,
1
);
buf
.end_undo_group
();
assert_eq!
(
buf
.undo
(),
true
);
assert_eq!
(
buf
.redo
(),
true
);
assert_eq!
(
String
::
from
(
buf
),
"defg"
);
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment