ed

[hare] The standard editor
Log | Files | Refs | README | LICENSE

commit 3257635eedc132400da16934708d94f7bf966f32
parent 2cd2cb220b526a5b35743ff8e505fd5d06c309eb
Author: Byron Torres <b@torresjrjr.com>
Date:   Wed, 17 Jan 2024 21:23:26 +0000

undo progress

Diffstat:
Mbuffer.ha | 24+++---------------------
Mcommand.ha | 15++++++++++++---
Mhistory.ha | 33++++++++++++++-------------------
3 files changed, 29 insertions(+), 43 deletions(-)

diff --git a/buffer.ha b/buffer.ha @@ -8,7 +8,7 @@ type Buffer = struct{ filename: str, lines: []*Line, trash: []*Line, - hist: []ChangeSet, + hist: []ChangeSeq, cursor: size, modified: bool, written: bool, @@ -38,16 +38,10 @@ fn buf_insert(buf: *Buffer, n: size, ls: *Line...) void = { hist_append(buf, (n, len(ls)): Addition); - debug("buf_insert(): len('last changeset')={}", len(buf.hist[len(buf.hist) - 1])); - -// let change = Change{ kind = true, n = n, z = len(ls) }; -// let activeset = buf.hist[buf.activehist]; -// append(activeset, change); + debug("buf_insert(): len('last changeseq')={}", len(buf.hist[len(buf.hist) - 1])); }; fn buf_deleteall(buf: *Buffer) void = { - // buf_wipetrash(buf); - if (len(buf.lines) > 1) { append(buf.trash, buf.lines[1..]...); delete(buf.lines[1..]); @@ -58,15 +52,6 @@ fn buf_deleteall(buf: *Buffer) void = { fn buf_delete(buf: *Buffer, a: size, b: size) void = { debug("buf_delete(a={}, b={})", a, b); - // buf_wipetrash(buf); - - // The G command requires changed lines to be unmarked. - // Command functions "change" lines using buf_delete() first. - // If a line is trashed, it is effectively unmarked. - // The G command function unmarks all lines first anyway. - //for (let i = 0z; i < len(buf.lines); i += 1) { - // buf.lines[i].globalmark = false; - //}; append(buf.trash, buf.lines[a..b+1]...); delete(buf.lines[a..b+1]); @@ -76,13 +61,10 @@ fn buf_delete(buf: *Buffer, a: size, b: size) void = { hist_append(buf, (a, (b + 1 - a)): Deletion); - debug("buf_delete(): len('last changeset')={}", len(buf.hist[len(buf.hist) - 1])); + debug("buf_delete(): len('last changeseq')={}", len(buf.hist[len(buf.hist) - 1])); }; fn buf_read(buf: *Buffer, src: io::handle, a: size) ((size, size) | io::error | encoding::utf8::invalid) = { - // TODO: don't call this here, call it at a higher level - // buf_wipetrash(buf); - let ls: []*Line = []; let sz = 0z; for (true) { diff --git a/command.ha b/command.ha @@ -121,7 +121,7 @@ fn cmd_append(s: *Session, cmd: *Command) (void | Error) = { const n = get_linenum(cmd.linenums, s.buf.cursor); - hist_newset(s.buf); + hist_newseq(s.buf); // TODO: special case, len(cmd.textinput) == 0 for (let i = 0z; i < len(cmd.textinput); i += 1) { const line = alloc(Line{ text = cmd.textinput[i], ... }); buf_insert(s.buf, n + 1 + i, line); @@ -147,6 +147,7 @@ fn cmd_change(s: *Session, cmd: *Command) (void | Error) = { }; }; + hist_newseq(s.buf); buf_delete(s.buf, a, b); for (let i = 0z; i < len(cmd.textinput); i += 1) { @@ -176,7 +177,7 @@ fn cmd_delete(s: *Session, cmd: *Command) (void | Error) = { )?; assert_nonzero(s, a)?; - hist_newset(s.buf); + hist_newseq(s.buf); buf_delete(s.buf, a, b); s.buf.cursor = @@ -243,6 +244,7 @@ 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; + hist_newseq(s.buf); // TODO special case, zeros lines for (let i = 0z; i < len(cmd.textinput); i += 1) { const line = alloc(Line{ text = cmd.textinput[i], ... }); buf_insert(s.buf, n + i, line); @@ -285,6 +287,7 @@ fn cmd_join(s: *Session, cmd: *Command) (void | Error) = { ... }); + hist_newseq(s.buf); buf_delete(s.buf, a, b); buf_insert(s.buf, a, newline); @@ -375,6 +378,8 @@ fn cmd_move(s: *Session, cmd: *Command) (void | Error) = { n; const lines = alloc(s.buf.lines[a..b+1]...); defer free(lines); // TODO: mem? + + hist_newseq(s.buf); buf_delete(s.buf, a, b); buf_insert(s.buf, dest, lines...); @@ -457,6 +462,7 @@ fn cmd_read(s: *Session, cmd: *Command) (void | Error) = { }; defer io::close(rd)!; + hist_newseq(s.buf); // TODO: special case, zero input const (sz, _) = buf_read(s.buf, rd, n)?; if (!s.suppressmode) @@ -486,6 +492,7 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = { let changes = 0z; + hist_newseq(s.buf); // TODO: special case, no match or changes for (let n = a; n <= b; n += 1) { const old = s.buf.lines[n].text; const results = regex::findall(&re, old); @@ -563,6 +570,8 @@ 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); buf_insert(s.buf, dest, lines...); s.buf.cursor = dest - 1 + len(lines); @@ -574,7 +583,7 @@ fn cmd_undo(s: *Session, cmd: *Command) (void | Error) = { assert_noaddrs(s, cmd.linenums)?; - hist_undo(s.buf)?; + hist_undo(s.buf)?; // TODO: redo last undo too }; fn cmd_vglobal(s: *Session, cmd: *Command) (void | Error) = { diff --git a/history.ha b/history.ha @@ -1,19 +1,23 @@ -type History = []ChangeSet; +type History = []ChangeSeq; -type ChangeSet = []Change; +type ChangeSeq = []Change; type Change = (Addition | Deletion); +// chunk (position, size) type Addition = (size, size); +// chunk (position, size) type Deletion = (size, size); type NoHistory = !void; -fn hist_newset(buf: *Buffer) void = { -debug("hist_newset(): begin"); - append(buf.hist, []: ChangeSet); -debug("hist_newset(): end"); +fn hist_newseq(buf: *Buffer) void = { + append(buf.hist, []: ChangeSeq); +}; + +fn hist_discardseq(buf: *Buffer) void = { + delete(buf.hist[len(buf.hist) - 1]); }; fn hist_append(buf: *Buffer, change: Change) void = { @@ -21,34 +25,25 @@ fn hist_append(buf: *Buffer, change: Change) void = { }; fn hist_undo(buf: *Buffer) (void | NoHistory) = { -debug("hist_undo(): len(buf.hist)={}", len(buf.hist)); if (len(buf.hist) == 0) return NoHistory; - let lastset = buf.hist[ len(buf.hist) - 1 ]; -debug("hist_undo(): len(lastset)={}", len(lastset)); + let seq = buf.hist[ len(buf.hist) - 1 ]; - for (let i = len(lastset) - 1; i < len(lastset); i -= 1) { - let change = lastset[i]; - match (change) { + for (let i = len(seq) - 1; i < len(seq); i -= 1) + match (seq[i]) { case let deln: Deletion => let (n, m) = deln; -debug("hist_undo(): deln=({}, {})", n, m); let lentrash = len(buf.trash); -debug("hist_undo(): lentrash={}", lentrash); let lines = buf.trash[(lentrash - m)..]; -debug("hist_undo(): len(lines)={}", len(lines)); insert(buf.lines[n], lines...); delete(buf.trash[(lentrash - m)..]); case let addn: Addition => let (n, m) = addn; -debug("hist_undo(): addn=({}, {})", n, m); let lines = buf.lines[n..(n + m)]; -debug("hist_undo(): len(lines)={}", len(lines)); - append(buf.trash, lines...); + insert(buf.trash[0], lines...); delete(buf.lines[n..(n + m)]); }; - }; delete(buf.hist[ len(buf.hist) - 1 ]); };