commit 88cd4e19d8f90212946de3caa7f172e9625c8d31
parent a8daa8d62cc7693f30ce906db8c523c789ab392f
Author: Byron Torres <b@torresjrjr.com>
Date: Sun, 21 Jan 2024 01:08:40 +0000
impl POSIX undo behaivour
Diffstat:
4 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/command.ha b/command.ha
@@ -121,8 +121,10 @@ fn cmd_append(s: *Session, cmd: *Command) (void | Error) = {
const n = get_linenum(cmd.linenums, s.buf.cursor);
- if (len(cmd.textinput) > 0)
+ if (len(cmd.textinput) > 0) {
hist_newseq(s.buf);
+ s.redolastchange = false;
+ };
for (let i = 0z; i < len(cmd.textinput); i += 1) {
const line = alloc(Line{ text = cmd.textinput[i], ... });
@@ -149,7 +151,7 @@ fn cmd_change(s: *Session, cmd: *Command) (void | Error) = {
};
};
- hist_newseq(s.buf);
+ hist_newseq(s.buf); s.redolastchange = false;
buf_delete(s.buf, a, b);
for (let i = 0z; i < len(cmd.textinput); i += 1) {
@@ -179,7 +181,7 @@ fn cmd_delete(s: *Session, cmd: *Command) (void | Error) = {
)?;
assert_nonzero(s, a)?;
- hist_newseq(s.buf);
+ hist_newseq(s.buf); s.redolastchange = false;
buf_delete(s.buf, a, b);
s.buf.cursor =
@@ -246,8 +248,10 @@ fn cmd_insert(s: *Session, cmd: *Command) (void | Error) = {
const n = get_linenum(cmd.linenums, s.buf.cursor);
const n = if (n == 0) 1z else n;
- if (len(cmd.textinput) > 0)
+ if (len(cmd.textinput) > 0) {
hist_newseq(s.buf);
+ s.redolastchange = false;
+ };
for (let i = 0z; i < len(cmd.textinput); i += 1) {
const line = alloc(Line{ text = cmd.textinput[i], ... });
@@ -291,7 +295,7 @@ fn cmd_join(s: *Session, cmd: *Command) (void | Error) = {
...
});
- hist_newseq(s.buf);
+ hist_newseq(s.buf); s.redolastchange = false;
buf_delete(s.buf, a, b);
buf_insert(s.buf, a, newline);
@@ -383,7 +387,7 @@ fn cmd_move(s: *Session, cmd: *Command) (void | Error) = {
const lines = alloc(s.buf.lines[a..b+1]...); defer free(lines); // TODO: mem?
- hist_newseq(s.buf);
+ hist_newseq(s.buf); s.redolastchange = false;
buf_delete(s.buf, a, b);
buf_insert(s.buf, dest, lines...);
@@ -471,7 +475,9 @@ fn cmd_read(s: *Session, cmd: *Command) (void | Error) = {
const (sz, _) = buf_read(s.buf, rd, n)?;
if (sz == 0)
- hist_discardseq(s.buf);
+ hist_discardseq(s.buf)
+ else
+ s.redolastchange = false;
if (!s.suppressmode)
fmt::println(sz)!;
@@ -549,6 +555,8 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = {
if (changes == 0) {
hist_discardseq(s.buf);
return NoMatch;
+ } else {
+ s.redolastchange = false;
};
printmode(s, cmd)?;
@@ -582,7 +590,7 @@ fn cmd_copy(s: *Session, cmd: *Command) (void | Error) = {
const lines = alloc(s.buf.lines[a..b+1]...); defer free(lines); // TODO: ?
- hist_newseq(s.buf);
+ hist_newseq(s.buf); s.redolastchange = false;
buf_insert(s.buf, dest, lines...);
s.buf.cursor = dest - 1 + len(lines);
@@ -594,7 +602,19 @@ fn cmd_undo(s: *Session, cmd: *Command) (void | Error) = {
assert_noaddrs(s, cmd.linenums)?;
- hist_undo(s.buf)?; // TODO: redo last undo too
+ switch (s.undomode) {
+ case UndoMode::POSIX =>
+ if (s.redolastchange) {
+ hist_redo(s.buf)?;
+ s.redolastchange = false;
+ } else {
+ hist_undo(s.buf)?;
+ s.redolastchange = true;
+ };
+ case UndoMode::FULL =>
+ hist_undo(s.buf)?;
+ hist_discardseq(s.buf);
+ };
};
fn cmd_vglobal(s: *Session, cmd: *Command) (void | Error) = {
diff --git a/execute.ha b/execute.ha
@@ -12,6 +12,9 @@ fn execute(s: *Session, cmd: *Command) (void | Error) = {
errormsg(s, e); // TODO: move up into caller?
return e;
};
+
+ for (let i = 0z; i < len(s.buf.trash); i += 1)
+ debug("trash[{}]={}", i, s.buf.trash[i].text);
};
fn exec_addrs(s: *Session, cmd: *Command) (void | CmdError) = {
diff --git a/history.ha b/history.ha
@@ -13,6 +13,12 @@ type Addition = (size, size);
// The deletion of a buffer chunk (start position, chunk size).
type Deletion = (size, size);
+// The effect of the undo command.
+type UndoMode = enum{
+ POSIX, // undoes the last buffer change, including that of 'u'
+ FULL, // undoes the last buffer change, exlucding that of 'u'
+};
+
// There is no history to undo.
type NoHistory = !void;
@@ -34,6 +40,7 @@ fn hist_append(buf: *Buffer, change: Change) void = {
};
fn hist_undo(buf: *Buffer) (void | NoHistory) = {
+ debug("hist_undo()");
if (len(buf.hist) == 0)
return NoHistory;
@@ -53,6 +60,27 @@ fn hist_undo(buf: *Buffer) (void | NoHistory) = {
insert(buf.trash[0], lines...);
delete(buf.lines[n..(n + m)]);
};
+};
+
+fn hist_redo(buf: *Buffer) (void | NoHistory) = {
+ debug("hist_redo()");
+ if (len(buf.hist) == 0)
+ return NoHistory;
- delete(buf.hist[ len(buf.hist) - 1 ]);
+ let seq = buf.hist[ len(buf.hist) - 1 ];
+
+ for (let j = len(seq) - 1; j < len(seq); j -= 1)
+ match (seq[j]) {
+ case let addn: Addition =>
+ let (n, m) = addn;
+ let lentrash = len(buf.trash);
+ let lines = buf.trash[(lentrash - m)..];
+ insert(buf.lines[n], lines...);
+ delete(buf.trash[(lentrash - m)..]);
+ case let deln: Deletion =>
+ let (n, m) = deln;
+ let lines = buf.lines[n..(n + m)];
+ append(buf.trash, lines...);
+ delete(buf.lines[n..(n + m)]);
+ };
};
diff --git a/main.ha b/main.ha
@@ -14,11 +14,13 @@ type Session = struct{
promptmode: bool,
suppressmode: bool,
helpmode: bool,
+ undomode: UndoMode,
warned: bool,
lasterror: (void | Error),
lastregex: (void | str),
lastshcmd: (void | str),
+ redolastchange: bool,
};
def proghelp: [_]getopt::help = [