commit 596f6d1fa4c51ecce0dd6c73fe185fcf1bdbcfa0
parent 1ed775fdc4cf5c7abaecb5cac5fa8fe36dae1b38
Author: Byron Torres <b@torresjrjr.com>
Date: Sat, 10 Dec 2022 01:16:11 +0000
progress
Diffstat:
M | address.ha | | | 21 | +++++++++++---------- |
M | buffer.ha | | | 1 | + |
M | command.ha | | | 226 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
M | main.ha | | | 6 | ++++-- |
M | parse.ha | | | 76 | +++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
5 files changed, 194 insertions(+), 136 deletions(-)
diff --git a/address.ha b/address.ha
@@ -3,6 +3,7 @@ use regex;
type address = struct {
addrtype: addresstype,
lineoffset: int,
+ setcurrentline: bool,
};
type addresstype = (size | currentline | lastline | rune);
@@ -13,34 +14,34 @@ type lastline = void;
type badaddress = !void;
-fn addr_nextline(s: *session, n: size) size = {
- if (len(s.buf.lines) - 1 == n) {
+fn addr_nextline(buf: *buffer, n: size) size = {
+ if (len(buf.lines) - 1 == n) {
return n;
};
return n + 1;
};
-fn addr_prevline(s: *session, n: size) size = {
+fn addr_prevline(buf: *buffer, n: size) size = {
if (n == 0 || n == 1) {
return n;
};
return n - 1;
};
-fn addr_linenum(s: *session, n: size) (size | badaddress) = {
- if (n > len(s.buf.lines)) {
+fn addr_linenum(buf: *buffer, n: size) (size | badaddress) = {
+ if (n > len(buf.lines)) {
return badaddress;
};
return n;
};
-fn addr_lastline(s: *session) size = {
- return len(s.buf.lines) - 1z;
+fn addr_lastline(buf: *buffer) size = {
+ return len(buf.lines) - 1z;
};
-fn addr_mark(s: *session, mark: rune) (size | badaddress) = {
- for (let n = 1z; n < len(s.buf.lines); n += 1) {
- const l = s.buf.lines[n];
+fn addr_mark(buf: *buffer, mark: rune) (size | badaddress) = {
+ for (let n = 1z; n < len(buf.lines); n += 1) {
+ const l = buf.lines[n];
if (l.mark == mark) {
return n;
};
diff --git a/buffer.ha b/buffer.ha
@@ -35,6 +35,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);
let ls: []*line = [];
diff --git a/command.ha b/command.ha
@@ -4,54 +4,71 @@ use fs;
use io;
use os;
-// Executes the session's .cmd command.
-fn execute(s: *session) void = {
- // first, execute the addresses
- let cursor = s.buf.cursor;
- let lns: []size = [];
- // defer free(lns);
- for (let i = 0z; i < len(s.cmd.addrs); i += 1) {
- const addr = s.cmd.addrs[i];
+type error = !(
+ badaddress
+ | nofilename
+ | buffermodified
+ | unexpectedaddress
+ | fs::error
+);
+
+type nofilename = !void;
+
+type buffermodified = !void;
+
+type unexpectedaddress = !void;
+
+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, n)!;
+ yield addr_linenum(&s.buf, n)?;
case currentline =>
- yield cursor;
+ yield s.buf.cursor;
case lastline =>
- yield addr_lastline(s);
+ yield addr_lastline(&s.buf);
case let m: rune =>
- yield addr_mark(s, m)!;
+ yield addr_mark(&s.buf, m)?;
};
n = (n: int + addr.lineoffset): size;
- append(lns, n);
+ fmt::errorfln("DEBUG: exec_addrs() n={}", n)!;
+ append(cmd.linenums, n);
+ // fmt::errorfln("DEBUG: exec_addrs() ...[i]={}", cmd.linenums[i])!;
+
+ if (addr.setcurrentline) {
+ s.buf.cursor = n;
+ };
};
+};
+
+// Executes the session's .cmd command.
+fn execute(s: *session) (void | error) = {
+ // TODO: move this into the cmd_* functions?
+ exec_addrs(s, &s.cmd)?;
+ defer delete(s.cmd.linenums[..]); // TODO: write finish_cmd()
- // then, execute the full command
switch (s.cmd.cmdtype) {
case commandtype::APPEND =>
fmt::errorfln("TODO: append")!;
case commandtype::CHANGE =>
fmt::errorfln("TODO: change")!;
case commandtype::DELETE =>
- const (a, b) = get_range(lns, cursor, cursor);
- cmd_delete(s, s.cmd.arg, a, b);
+ cmd_delete(s, &s.cmd): void;
case commandtype::EDIT =>
- cmd_edit(s, s.cmd.arg);
+ cmd_edit(s, &s.cmd): void;
case commandtype::EDIT_FORCED =>
fmt::errorfln("TODO: edit_forced")!;
case commandtype::FILENAME =>
- if (!assert_noaddrs(s, lns)) return;
- cmd_filename(s, s.cmd.arg);
+ cmd_filename(s, &s.cmd): void;
case commandtype::GLOBAL =>
fmt::errorfln("TODO: global")!;
case commandtype::GLOBAL_INTERACTIVE =>
fmt::errorfln("TODO: global_interactive")!;
case commandtype::HELP =>
- if (!assert_noaddrs(s, lns)) return;
- cmd_help(s);
+ cmd_help(s, &s.cmd): void;
case commandtype::HELPMODE =>
- if (!assert_noaddrs(s, lns)) return;
- cmd_helpmode(s);
+ cmd_helpmode(s, &s.cmd): void;
case commandtype::INSERT =>
fmt::errorfln("TODO: insert")!;
case commandtype::JOIN =>
@@ -63,24 +80,15 @@ fn execute(s: *session) void = {
case commandtype::MOVE =>
fmt::errorfln("TODO: move")!;
case commandtype::NUMBER =>
- const (a, b) = get_range(lns, cursor, cursor);
- if (a > b) {
- //return badaddress;
- errormsg(s, "Invalid address");
- return;
- };
- cmd_number(s, a, b);
+ cmd_number(s, &s.cmd): void;
case commandtype::PRINT =>
- const (a, b) = get_range(lns, cursor, cursor);
- cmd_print(s, a, b);
+ cmd_print(s, &s.cmd): void;
case commandtype::PROMPT=>
- if (!assert_noaddrs(s, lns)) return;
- cmd_prompt(s);
+ cmd_prompt(s, &s.cmd): void;
case commandtype::QUIT =>
fmt::errorfln("TODO: quit")!;
case commandtype::READ =>
- const n = get_linenum(lns, cursor);
- cmd_read(s, s.cmd.arg, n);
+ cmd_read(s, &s.cmd);
case commandtype::SUBSTITUTE =>
fmt::errorfln("TODO: substitute")!;
case commandtype::COPY =>
@@ -92,24 +100,13 @@ fn execute(s: *session) void = {
case commandtype::GLOBAL_INVERSE_INTERACTIVE =>
fmt::errorfln("TODO: global_inverse_interactive")!;
case commandtype::WRITE =>
- const (a, b) = get_range(
- lns,
- addr_linenum(s, 1)!,
- addr_lastline(s),
- );
- cmd_write(s, s.cmd.arg, a, b);
+ cmd_write(s, &s.cmd): void;
case commandtype::LINE_NUMBER =>
- const n = get_linenum(lns, addr_lastline(s));
- cmd_linenumber(s, n);
+ cmd_linenumber(s, &s.cmd);
case commandtype::SHELL_ESCAPE =>
fmt::errorfln("TODO: shell_escape")!;
case commandtype::NULL =>
- const n = get_linenum(lns, if (len(lns) == 0) {
- yield addr_nextline(s, cursor);
- } else {
- yield cursor;
- });
- cmd_print(s, n, n);
+ cmd_null(s, &s.cmd): void;
case commandtype::DEBUG_NUMBER =>
dumpbuffer(&s.buf);
@@ -118,16 +115,20 @@ fn execute(s: *session) void = {
};
};
-fn get_range(lns: []size, a: size, b: size) (size, size) = {
- if (len(lns) == 0) {
- return (a, b);
+fn get_range(s: *session, lns: *[]size, a: size, b: size) ((size, size) | badaddress) = {
+ const (a, b) = if (len(lns) == 0) {
+ yield (a, b);
} else if (len(lns) == 1) {
- return (lns[0], lns[0]);
+ yield (lns[0], lns[0]);
} else {
- // fmt::errorfln("DEBUG: ({}, {})", lns[len(lns)-2], lns[len(lns)-1])!;
- const (a, b) = (lns[len(lns)-2], lns[len(lns)-1]);
- return (a, b);
+ yield (lns[len(lns)-2], lns[len(lns)-1]);
+ };
+ fmt::errorfln("DEBUG: get_range() (a, b)=({}, {})", a, b)!;
+ if (a > b) {
+ errormsg(s, "Invalid address");
+ return badaddress;
};
+ return (a, b);
};
fn get_linenum(lns: []size, n: size) size = {
@@ -138,69 +139,94 @@ fn get_linenum(lns: []size, n: size) size = {
};
};
-fn assert_noaddrs(s: *session, lns: []size) bool = {
+fn assert_noaddrs(s: *session, lns: []size) (void | unexpectedaddress) = {
if (len(lns) != 0) {
errormsg(s, "Unexpected address");
- return false;
+ return unexpectedaddress;
};
- return true;
};
-fn cmd_prompt(s: *session) void = {
+fn cmd_prompt(s: *session, cmd: *command) (void | error) = {
+ assert_noaddrs(s, cmd.linenums)?;
s.promptmode = !s.promptmode;
};
-fn cmd_linenumber(s: *session, n: size) void = {
+fn cmd_linenumber(s: *session, cmd: *command) void = {
+ const n = get_linenum(cmd.linenums, addr_lastline(&s.buf));
fmt::println(n)!;
};
-fn cmd_help(s: *session) void = {
+fn cmd_help(s: *session, cmd: *command) (void | error) = {
+ assert_noaddrs(s, cmd.linenums)?;
if (s.lasterror != "") {
fmt::println(s.lasterror)!;
};
};
-fn cmd_helpmode(s: *session) void = {
+fn cmd_helpmode(s: *session, cmd: *command) (void | error) = {
+ assert_noaddrs(s, cmd.linenums)?;
s.helpmode = !s.helpmode;
- if (s.helpmode) {
- cmd_help(s);
+ if (s.helpmode && s.lasterror != "") {
+ fmt::println(s.lasterror)!;
};
};
-fn cmd_print(s: *session, a: size, b: size) void = {
+fn cmd_print(s: *session, cmd: *command) (void | error) = {
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ s.buf.cursor,
+ s.buf.cursor,
+ )?;
for (let n = a; n <= b; n += 1) {
fmt::println(s.buf.lines[n].text)!;
};
s.buf.cursor = b;
};
-fn cmd_number(s: *session, a: size, b: size) void = {
+fn cmd_number(s: *session, cmd: *command) (void | error) = {
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ s.buf.cursor,
+ s.buf.cursor,
+ )?;
+
for (let n = a; n <= b; n += 1) {
fmt::printfln("{}\t{}", n, s.buf.lines[n].text)!;
};
s.buf.cursor = b;
};
-fn cmd_filename(s: *session, filename: str) void = {
- if (len(filename) != 0) {
- s.buf.filename = filename;
+fn cmd_filename(s: *session, cmd: *command) (void | error) = {
+ assert_noaddrs(s, cmd.linenums)?;
+ if (len(cmd.arg) != 0) {
+ s.buf.filename = cmd.arg;
};
if (len(s.buf.filename) == 0) {
- return errormsg(s, "No current filename");
+ errormsg(s, "No current filename");
+ return nofilename;
};
fmt::println(s.buf.filename)!;
};
-fn cmd_write(s: *session, filename: str, a: size, b: size) void = {
- const fname = if (len(filename) != 0) {
- s.buf.filename = filename;
- yield filename;
+fn cmd_write(s: *session, cmd: *command) (void | error) = {
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ addr_linenum(&s.buf, 1)!,
+ addr_lastline(&s.buf),
+ )?;
+
+ const fname = if (len(cmd.arg) != 0) {
+ s.buf.filename = cmd.arg;
+ yield cmd.arg;
} else {
yield if (len(s.buf.filename) != 0) {
yield s.buf.filename;
} else {
errormsg(s, "No current filename");
- return;
+ return nofilename;
};
};
@@ -215,7 +241,8 @@ fn cmd_write(s: *session, filename: str, a: size, b: size) void = {
return errormsg(s, fs::strerror(err));
};
case =>
- return errormsg(s, fs::strerror(err));
+ errormsg(s, fs::strerror(err));
+ return err;
};
case let h: io::file =>
yield h: io::handle;
@@ -228,10 +255,11 @@ fn cmd_write(s: *session, filename: str, a: size, b: size) void = {
};
};
-fn cmd_read(s: *session, filename: str, a: size) void = {
- const fname = if (len(filename) != 0) {
- s.buf.filename = filename;
- yield filename;
+fn cmd_read(s: *session, cmd: *command) void = {
+ const n = get_linenum(cmd.linenums, s.buf.cursor);
+ const fname = if (len(cmd.arg) != 0) {
+ s.buf.filename = cmd.arg;
+ yield cmd.arg;
} else {
yield if (len(s.buf.filename) != 0) {
yield s.buf.filename;
@@ -249,35 +277,36 @@ fn cmd_read(s: *session, filename: str, a: size) void = {
};
defer io::close(h)!;
- const (sz, _) = buf_read(&s.buf, h, a);
+ const (sz, _) = buf_read(&s.buf, h, n);
if (!s.suppressmode) {
fmt::println(sz)!;
};
s.buf.cursor = len(s.buf.lines) - 1;
};
-fn cmd_edit(s: *session, filename: str) void = {
+fn cmd_edit(s: *session, cmd: *command) (void | error) = {
if (s.buf.modified && !s.warned) {
errormsg(s, "Warning: buffer modified");
s.warned = true;
- return;
+ return buffermodified;
};
- const fname = if (len(filename) != 0) {
- s.buf.filename = filename;
- yield filename;
+ const fname = if (len(cmd.arg) != 0) {
+ s.buf.filename = cmd.arg;
+ yield cmd.arg;
} else {
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));
+ errormsg(s, fs::strerror(err));
+ return err;
case let h: io::file =>
yield h: io::handle;
};
@@ -291,7 +320,13 @@ fn cmd_edit(s: *session, filename: str) void = {
s.buf.cursor = len(s.buf.lines) - 1;
};
-fn cmd_delete(s: *session, filename: str, a: size, b: size) void = {
+fn cmd_delete(s: *session, cmd: *command) (void | error) = {
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ s.buf.cursor,
+ s.buf.cursor,
+ )?;
buf_delete(&s.buf, a, b);
s.buf.cursor = if (len(s.buf.lines) == 1) {
yield 0;
@@ -301,3 +336,12 @@ fn cmd_delete(s: *session, filename: str, a: size, b: size) void = {
yield a;
};
};
+
+fn cmd_null(s: *session, cmd: *command) (void | error) = {
+ const n = get_linenum(
+ cmd.linenums,
+ addr_nextline(&s.buf, s.buf.cursor),
+ );
+ fmt::println(s.buf.lines[n].text)!;
+ s.buf.cursor = n;
+};
diff --git a/main.ha b/main.ha
@@ -71,7 +71,8 @@ export fn main() void = {
};
if (len(s.buf.filename) != 0) {
- cmd_edit(&s, s.buf.filename);
+ s.cmd.arg = s.buf.filename;
+ cmd_edit(&s, &s.cmd): void;
};
for (true) :repl {
@@ -101,7 +102,8 @@ export fn main() void = {
switch (s.mode) {
case mode::COMMAND =>
if (parse(&s.cmd, input)) {
- execute(&s);
+ // TODO: handle all ": void"s
+ execute(&s): void;
};
case mode::INPUT =>
if (input == ".") {
diff --git a/parse.ha b/parse.ha
@@ -6,6 +6,7 @@ use strings;
type command = struct {
addrs: []address,
+ linenums: []size,
cmdtype: commandtype,
suffix: suffix,
arg: str,
@@ -81,38 +82,40 @@ fn scan_addrs(iter: *strings::iterator) []address = {
case let r: rune =>
switch (r) {
case ',' =>
+ specialfirst = true;
append(addrs, address {
addrtype = 1z,
lineoffset = 0,
+ setcurrentline = false,
});
- specialfirst = true;
case ';' =>
+ specialfirst = true;
append(addrs, address {
addrtype = currentline,
lineoffset = 0,
+ setcurrentline = true,
});
- specialfirst = true;
case =>
strings::prev(iter);
};
};
for (true) {
- match (scan_addr(iter)) {
+ let addr = match (scan_addr(iter)) {
case void =>
- if (specialfirst) {
- append(addrs, address {
+ yield if (specialfirst) {
+ yield address {
addrtype = lastline,
lineoffset = 0,
- });
+ ...
+ };
} else if (len(addrs) > 0) {
- const prevaddr = addrs[len(addrs)-1];
- append(addrs, prevaddr);
+ yield addrs[len(addrs)-1];
} else {
break;
};
- case let addr: address =>
- append(addrs, addr);
+ case let a: address =>
+ yield a;
};
specialfirst = false;
@@ -120,12 +123,17 @@ fn scan_addrs(iter: *strings::iterator) []address = {
scan_blanks(iter);
match (strings::next(iter)) {
case void =>
+ append(addrs, addr);
break;
case let r: rune =>
switch (r) {
- case ',', ';' =>
- void;
+ case ',' =>
+ append(addrs, addr);
+ case ';' =>
+ addr.setcurrentline = true;
+ append(addrs, addr);
case =>
+ append(addrs, addr);
strings::prev(iter);
break;
};
@@ -148,27 +156,28 @@ fn scan_addr(iter: *strings::iterator) (address | void) = {
// fmt::errorfln("DEBUG: scan_addr() r={}", r)!;
- const addrtype: (addresstype | void) = if (r == '.') {
- yield currentline;
- } else if (r == '$') {
- yield lastline;
- } else if (ascii::isdigit(r)) {
- strings::prev(iter);
- yield scan_uint(iter): size;
- } else if (r == '\'') {
- yield scan_mark(iter);
- } else if (r == '/') {
- // const re = scan_regex(iter, r);j
- // ...
- abort("TODO: /regex/");
- } else if (r == '?') {
- // const re = scan_regex(iter, r);j
- // ...
- abort("TODO: ?regex?");
- } else {
- strings::prev(iter);
- yield void;
- };
+ const addrtype: (addresstype | void) =
+ if (r == '.') {
+ yield currentline;
+ } else if (r == '$') {
+ yield lastline;
+ } else if (ascii::isdigit(r)) {
+ strings::prev(iter);
+ yield scan_uint(iter): size;
+ } else if (r == '\'') {
+ yield scan_mark(iter);
+ } else if (r == '/') {
+ // const re = scan_regex(iter, r);j
+ // ...
+ abort("TODO: /regex/");
+ } else if (r == '?') {
+ // const re = scan_regex(iter, r);j
+ // ...
+ abort("TODO: ?regex?");
+ } else {
+ strings::prev(iter);
+ yield void;
+ };
const offs = scan_offsets(iter);
@@ -186,6 +195,7 @@ fn scan_addr(iter: *strings::iterator) (address | void) = {
let addr = address {
addrtype = addrtype,
lineoffset = 0,
+ ...
};
for (let i = 0z; i < len(offs); i += 1) {