commit 6143f14e22aa10e3bd446858b859c7f6eccf840a
parent 8071aefcd32dcb1d1e909021b30343cac097e255
Author: Byron Torres <b@torresjrjr.com>
Date: Tue, 13 Dec 2022 04:59:49 +0000
add cmd_move(); handle errors, invalid addresses
Diffstat:
5 files changed, 99 insertions(+), 58 deletions(-)
diff --git a/address.ha b/address.ha
@@ -12,7 +12,7 @@ type currentline = void;
type lastline = void;
-type badaddress = !void;
+type invalidaddress = !void;
fn addr_nextline(buf: *buffer, n: size) size = {
if (len(buf.lines) - 1 == n) {
@@ -28,9 +28,9 @@ fn addr_prevline(buf: *buffer, n: size) size = {
return n - 1;
};
-fn addr_linenum(buf: *buffer, n: size) (size | badaddress) = {
- if (n > len(buf.lines)) {
- return badaddress;
+fn addr_linenum(buf: *buffer, n: size) (size | invalidaddress) = {
+ if (n >= len(buf.lines)) {
+ return invalidaddress;
};
return n;
};
@@ -39,12 +39,12 @@ fn addr_lastline(buf: *buffer) size = {
return len(buf.lines) - 1z;
};
-fn addr_mark(buf: *buffer, mark: rune) (size | badaddress) = {
+fn addr_mark(buf: *buffer, mark: rune) (size | invalidaddress) = {
for (let n = 1z; n < len(buf.lines); n += 1) {
const l = buf.lines[n];
if (l.mark == mark) {
return n;
};
};
- return badaddress;
+ return invalidaddress;
};
diff --git a/buffer.ha b/buffer.ha
@@ -19,11 +19,14 @@ type line = struct {
fn buf_insert(buf: *buffer, n: size, ls: *line...) void = {
debug("buf_insert(n={}), len(ls)={}", n, len(ls));
+// for (let i = 0z; i < len(ls); i += 1) {
+// debug("buf_insert(): ls[{}].text='{}'", i, ls[i].text);
+// };
insert(buf.lines[n], ls...);
};
fn buf_deleteall(buf: *buffer) void = {
- buf_wipetrash(buf);
+ // buf_wipetrash(buf);
if (len(buf.lines) > 1) {
insert(buf.trash[0], buf.lines[1..]...);
@@ -33,7 +36,7 @@ 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);
+ // buf_wipetrash(buf);
insert(buf.trash[0], buf.lines[a..b+1]...);
delete(buf.lines[a..b+1]);
@@ -41,7 +44,7 @@ fn buf_delete(buf: *buffer, a: size, b: size) void = {
fn buf_read(buf: *buffer, src: io::handle, a: size) (size, size) = {
// TODO: don't call this here, call it at a higher level
- buf_wipetrash(buf);
+ // buf_wipetrash(buf);
let ls: []*line = [];
defer free(ls);
diff --git a/command.ha b/command.ha
@@ -25,10 +25,10 @@ type suffix = enum {
};
type error = !(
- badaddress
+ invalidaddress
+ | unexpectedaddress
| nofilename
| buffermodified
- | unexpectedaddress
| fs::error
);
@@ -41,25 +41,27 @@ type unexpectedaddress = !void;
// Executes the session's .cmd command.
fn execute(s: *session, cmd: *command) (void | error) = {
// TODO: move this into the cmd_* functions?
- exec_addrs(s, cmd)?;
- defer delete(cmd.linenums[..]); // TODO: write finish_cmd()
-
- cmd.cmdfn(s, cmd)?;
+ match (exec_addrs(s, cmd)) {
+ case void => void;
+ case let err: error =>
+ delete(cmd.linenums[..]);
+ return errormsg(s, err);
+ };
+ // TODO: write finish_cmd()
+ // TODO: finish the command at a higher level (main()) ?.
+ defer delete(cmd.linenums[..]);
+
+ match (cmd.cmdfn(s, cmd)) {
+ case void => void;
+ case let err: error =>
+ return errormsg(s, err);
+ };
};
fn exec_addrs(s: *session, cmd: *command) (void | error) = {
for (let i = 0z; i < len(cmd.addrs); i += 1) {
const addr = cmd.addrs[i];
- let n = match (addr.addrtype) {
- case let n: size =>
- yield addr_linenum(&s.buf, n)?;
- case currentline =>
- yield s.buf.cursor;
- case lastline =>
- yield addr_lastline(&s.buf);
- case let m: rune =>
- yield addr_mark(&s.buf, m)?;
- };
+ let n = exec_addr(s, addr)?;
n = n + addr.lineoffset: size; // beware of negatives
debug("exec_addrs(): n={}", n);
append(cmd.linenums, n);
@@ -70,8 +72,22 @@ fn exec_addrs(s: *session, cmd: *command) (void | error) = {
};
};
+fn exec_addr(s: *session, addr: address) (size | error) = {
+ match (addr.addrtype) {
+ case let n: size =>
+ return addr_linenum(&s.buf, n)?;
+ case currentline =>
+ return s.buf.cursor;
+ case lastline =>
+ return addr_lastline(&s.buf);
+ case let m: rune =>
+ return addr_mark(&s.buf, m)?;
+ };
+};
-fn get_range(s: *session, lns: *[]size, a: size, b: size) ((size, size) | badaddress) = {
+
+fn get_range(s: *session, lns: *[]size, a: size, b: size) ((size, size) | invalidaddress) = {
+ debug("get_range(): len(lns)={}", len(lns));
const (a, b) = if (len(lns) == 0) {
yield (a, b);
} else if (len(lns) == 1) {
@@ -80,9 +96,8 @@ fn get_range(s: *session, lns: *[]size, a: size, b: size) ((size, size) | badadd
yield (lns[len(lns)-2], lns[len(lns)-1]);
};
debug("get_range(): (a, b)=({}, {})", a, b);
- if (a > b) {
- errormsg(s, "Invalid address");
- return badaddress;
+ if (a < 0 || a > b || b >= len(s.buf.lines)) {
+ return invalidaddress;
};
return (a, b);
};
@@ -97,15 +112,13 @@ fn get_linenum(lns: []size, n: size) size = {
fn assert_noaddrs(s: *session, lns: []size) (void | unexpectedaddress) = {
if (len(lns) != 0) {
- errormsg(s, "Unexpected address");
return unexpectedaddress;
};
};
-fn assert_nonzero(s: *session, n: size) (void | badaddress) = {
+fn assert_nonzero(s: *session, n: size) (void | invalidaddress) = {
if (n < 1) {
- errormsg(s, "Invalid address");
- return badaddress;
+ return invalidaddress;
};
};
@@ -136,7 +149,6 @@ fn cmd_edit(s: *session, cmd: *command) (void | error) = {
assert_noaddrs(s, cmd.linenums)?;
if (s.buf.modified && !s.warned) {
- errormsg(s, "Warning: buffer modified");
s.warned = true;
return buffermodified;
};
@@ -148,14 +160,12 @@ fn cmd_edit(s: *session, cmd: *command) (void | error) = {
yield if (len(s.buf.filename) != 0) {
yield s.buf.filename;
} else {
- errormsg(s, "No current filename");
return nofilename;
};
};
const h = match (os::open(fname)) {
case let err: fs::error =>
- errormsg(s, fs::strerror(err));
return err;
case let h: io::file =>
yield h: io::handle;
@@ -178,7 +188,6 @@ fn cmd_filename(s: *session, cmd: *command) (void | error) = {
s.buf.filename = cmd.arg;
};
if (len(s.buf.filename) == 0) {
- errormsg(s, "No current filename");
return nofilename;
};
fmt::println(s.buf.filename)!;
@@ -275,7 +284,33 @@ fn cmd_mark(s: *session, cmd: *command) (void | error) = {
fn cmd_list(s: *session, cmd: *command) (void | error) = void;
-fn cmd_move(s: *session, cmd: *command) (void | error) = void;
+fn cmd_move(s: *session, cmd: *command) (void | error) = {
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ s.buf.cursor,
+ s.buf.cursor,
+ )?;
+ assert_nonzero(s, a)?;
+
+ // TODO: parse this properly in parse.ha?
+ const iter = strings::iter(cmd.arg);
+ const n = match (scan_addr(&iter)) {
+ case let addr: address =>
+ yield exec_addr(s, addr)? + 1;
+ case void =>
+ return invalidaddress;
+ };
+ debug("cmd_move(): n={}", n);
+
+ // TODO: write buf_get(&buf, a, b) ?
+ const ls = alloc(s.buf.lines[a..b+1]...); defer free(ls);
+// for (let i = 0z; i < len(ls); i += 1) {
+// debug("cmd_move(): ls[{}].text='{}'", i, ls[i].text);
+// };
+ buf_delete(&s.buf, a, b);
+ buf_insert(&s.buf, n, ls...);
+};
fn cmd_number(s: *session, cmd: *command) (void | error) = {
const (a, b) = get_range(
@@ -285,6 +320,7 @@ fn cmd_number(s: *session, cmd: *command) (void | error) = {
s.buf.cursor,
)?;
assert_nonzero(s, a)?;
+ debug("cmd_number(): (a, b)=({}, {})", a, b);
for (let n = a; n <= b; n += 1) {
fmt::printfln("{}\t{}", n, s.buf.lines[n].text)!;
@@ -300,6 +336,7 @@ fn cmd_print(s: *session, cmd: *command) (void | error) = {
s.buf.cursor,
)?;
assert_nonzero(s, a)?;
+
for (let n = a; n <= b; n += 1) {
fmt::println(s.buf.lines[n].text)!;
};
@@ -315,7 +352,7 @@ fn cmd_quit(s: *session, cmd: *command) (void | error) = void;
fn cmd_quit_forced(s: *session, cmd: *command) (void | error) = void;
-fn cmd_read(s: *session, cmd: *command) void = {
+fn cmd_read(s: *session, cmd: *command) (void | error) = {
const n = get_linenum(cmd.linenums, s.buf.cursor);
const fname = if (len(cmd.arg) != 0) {
s.buf.filename = cmd.arg;
@@ -324,17 +361,11 @@ fn cmd_read(s: *session, cmd: *command) void = {
yield if (len(s.buf.filename) != 0) {
yield s.buf.filename;
} else {
- errormsg(s, "No current filename");
- return;
+ return nofilename;
};
};
- const h = match (os::open(fname)) {
- case let err: fs::error =>
- return errormsg(s, fs::strerror(err));
- case let h: io::file =>
- yield h: io::handle;
- };
+ const h = os::open(fname)?: io::handle;
defer io::close(h)!;
const (sz, _) = buf_read(&s.buf, h, n);
@@ -370,7 +401,6 @@ fn cmd_write(s: *session, cmd: *command) (void | error) = {
yield if (len(s.buf.filename) != 0) {
yield s.buf.filename;
} else {
- errormsg(s, "No current filename");
return nofilename;
};
};
@@ -379,14 +409,8 @@ fn cmd_write(s: *session, cmd: *command) (void | error) = {
case let err: fs::error =>
yield match (err) {
case errors::noentry =>
- yield match (os::create(fname, 0o644)) {
- case let h: io::file =>
- yield h: io::handle;
- case let err: fs::error =>
- return errormsg(s, fs::strerror(err));
- };
+ yield os::create(fname, 0o644)?: io::handle;
case =>
- errormsg(s, fs::strerror(err));
return err;
};
case let h: io::file =>
diff --git a/main.ha b/main.ha
@@ -1,6 +1,7 @@
use bufio;
use encoding::utf8;
use fmt;
+use fs;
use getopt;
use io;
use os;
@@ -122,10 +123,23 @@ export fn main() void = {
os::exit(1);
};
-fn errormsg(s: *session, msg: str) void = {
+fn errormsg(s: *session, err: error) error = {
fmt::errorln('?')!;
+ const msg = match (err) {
+ case invalidaddress =>
+ yield "Invalid address";
+ case nofilename =>
+ yield "No filename";
+ case buffermodified =>
+ yield "Buffer modified";
+ case unexpectedaddress =>
+ yield "Unexpected address";
+ case let e: fs::error =>
+ yield fs::strerror(e);
+ };
s.lasterror = msg;
if (s.helpmode) {
fmt::errorfln(msg)!;
};
+ return err;
};
diff --git a/parse.ha b/parse.ha
@@ -15,7 +15,7 @@ fn parse(cmd: *command, input: str) bool = {
cmd.addrs = scan_addrs(&iter);
cmd.cmdfn = scan_cmdfn(&iter);
cmd.arg = scan_arg(&iter);
- debug("parse(): cmd.arg={}", cmd.arg);
+// debug("parse(): cmd.arg={}", cmd.arg);
return true;
};
@@ -222,7 +222,7 @@ fn scan_cmdfn(iter: *strings::iterator) commandfn = {
case 'j' => return &cmd_join;
case 'k' => return &cmd_mark;
// case 'l' => return &cmd_list;
-// case 'm' => return &cmd_move;
+ case 'm' => return &cmd_move;
case 'n' => return &cmd_number;
case 'p' => return &cmd_print;
// case 'q' => return &cmd_quit;