commit 14d833400a367b05161b371ca1e1235faae065d0
parent 85c2713c7dbb77a98d847f1e067578e239c92d12
Author: Byron Torres <b@torresjrjr.com>
Date: Sun, 7 Jan 2024 00:17:45 +0000
add cmd_global
Diffstat:
4 files changed, 121 insertions(+), 15 deletions(-)
diff --git a/command.ha b/command.ha
@@ -3,11 +3,12 @@ use errors;
use fmt;
use fs;
use io;
+use memio;
use os;
use os::exec;
use regex;
use strings;
-use memio;
+use types;
type Command = struct{
addrs: []Address,
@@ -117,7 +118,7 @@ fn cmd_append(s: *Session, cmd: *Command) (void | Error) = {
for (let i = 0z; i < len(cmd.textinput); i += 1) {
const l = alloc(Line{ text = cmd.textinput[i], ... });
- debug("cmd_append(): l.text={}", l.text);
+ //debug("cmd_append(): l.text=<{}>", l.text);
buf_insert(s.buf, n + 1 + i, l);
};
@@ -144,7 +145,7 @@ fn cmd_change(s: *Session, cmd: *Command) (void | Error) = {
for (let i = 0z; i < len(cmd.textinput); i += 1) {
const l = alloc(Line{ text = cmd.textinput[i], ... });
- debug("cmd_append(): l.text={}", l.text);
+ //debug("cmd_append(): l.text=<{}>", l.text);
buf_insert(s.buf, a + i, l);
};
@@ -262,7 +263,93 @@ fn cmd_global(s: *Session, cmd: *Command) (void | Error) = {
)?;
assert_nonzero(s, a)?;
- void;
+ const regex = regex::compile(cmd.arg1)?; defer regex::finish(®ex);
+
+ for (let i = a; i <= b; i += 1) {
+ const line = s.buf.lines[i];
+ line.globalmark = false; // TODO: is this necessary?
+ if (regex::test(®ex, line.text)) {
+ line.globalmark = true;
+ };
+ };
+
+ let subcmds: []Command = [];
+
+ let inputtext = strings::join("\n", cmd.textinput...);
+ let inputbytes = strings::toutf8(inputtext);
+ let inputstream = memio::dynamic_from(inputbytes);
+ defer io::close(&inputstream)!;
+ let input = bufio::newscanner(&inputstream, types::SIZE_MAX);
+ defer bufio::finish(&input);
+ // TODO: could be less than types::SIZE_MAX ^ ?
+
+ for (true) {
+ // TODO: handle mem
+ // TODO: just use 'parse()?' when compiler allows
+ //let subcmd = parse(s.input)?;
+ let subcmd = match (parse(&input)) {
+ case let c: Command =>
+ yield c;
+ case io::EOF =>
+ break;
+ case let e: ParseError =>
+ return e;
+ case let e: InteractionError =>
+ return e;
+ };
+
+ debug("cmd_global() for subcmd.cmdname=<{}>", subcmd.cmdname);
+
+ // TODO: write new parse_global() function instead
+ // as to avoid reading multiple lines in the case of
+ // 'a', 'c', 'i' ?
+ switch (subcmd.cmdname) {
+ case 'g', 'G', 'v', 'V', '!' =>
+ // TODO: implement?
+ errormsg(s, subcmd.cmdname: InvalidGlobalSubCmd);
+ continue;
+ case '&' =>
+ errormsg(s, '&': UnknownCommand);
+ continue;
+ case 'u' =>
+ // TODO: undo behaviour
+ continue;
+ case =>
+ void;
+ };
+
+ append(subcmds, subcmd);
+ };
+
+ debug("cmd_global() len(subcmds)={}", len(subcmds));
+
+ if (len(subcmds) == 0)
+ append(subcmds, Command{ cmdname = 'p', ... });
+
+ for :marks (true) {
+ // find next global-marked line
+ let n = 1z;
+ for :lines (true; n += 1) {
+ if (n >= len(s.buf.lines)) {
+ break :marks;
+ };
+ if (s.buf.lines[n].globalmark) {
+ break :lines;
+ };
+ };
+ s.buf.cursor = n;
+ let line = s.buf.lines[n];
+
+ // TODO: handle termination by SIGINT signal
+
+ for (let i = 0z; i < len(subcmds); i += 1) {
+ let subcmd = subcmds[i];
+ //debug("cmd_global() for :marks execute()ing");
+ execute(s, &subcmd)?;
+ };
+
+ line.globalmark = false;
+ };
};
fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = {
@@ -318,7 +405,7 @@ fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = {
return e;
};
- // write new parse_global_interactive() function instead
+ // TODO: write new parse_global_interactive() function instead
// as to avoid reading multiple lines in the case of
// 'a', 'c', 'i' ?
switch (subcmd.cmdname) {
@@ -375,7 +462,7 @@ fn cmd_insert(s: *Session, cmd: *Command) (void | Error) = {
for (let i = 0z; i < len(cmd.textinput); i += 1) {
const l = alloc(Line{ text = cmd.textinput[i], ... });
- debug("cmd_insert(): l.text={}", l.text);
+ //debug("cmd_insert(): l.text=<{}>", l.text);
buf_insert(s.buf, n + i, l);
};
@@ -471,7 +558,7 @@ fn cmd_list(s: *Session, cmd: *Command) (void | Error) = {
s.buf.cursor,
)?;
assert_nonzero(s, a)?;
- debug("cmd_list(): (a, b)=({}, {})", a, b);
+ //debug("cmd_list(): (a, b)=({}, {})", a, b);
printlistlns(s.buf, a, b)?;
s.buf.cursor = b;
diff --git a/interaction.ha b/interaction.ha
@@ -7,6 +7,7 @@ use types;
type InteractionError = !(
Quit
+ | io::EOF
| UnexpectedEOF
| utf8::invalid
| io::error
diff --git a/main.ha b/main.ha
@@ -92,6 +92,8 @@ export fn main() void = {
const cmd = match (parse(&input)) {
case let cmd: Command =>
yield cmd;
+ case io::EOF =>
+ yield Command{ cmdname = 'q', ... };
case let err: ParseError =>
errormsg(&s, strerror(err));
continue;
diff --git a/parse.ha b/parse.ha
@@ -42,7 +42,7 @@ fn parse(input: *bufio::scanner) (Command | ParseError | InteractionError) = {
case let s: const str =>
yield s;
case io::EOF =>
- return Command{ cmdname = 'q', ... };
+ return io::EOF;
};
let iter = strings::iter(inputline);
@@ -52,7 +52,7 @@ fn parse(input: *bufio::scanner) (Command | ParseError | InteractionError) = {
cmd.cmdname = scan_cmdname(&iter)?;
parse_cmdargs(&cmd, &iter)?;
- switch (cmd.cmdname) {
+ switch :input (cmd.cmdname) {
case => void;
case 'a', 'c', 'i' =>
for (true) {
@@ -68,9 +68,13 @@ fn parse(input: *bufio::scanner) (Command | ParseError | InteractionError) = {
append(cmd.textinput, strings::dup(inputline));
};
- case 'q', 'v' =>
- if (!strings::hassuffix(cmd.arg2, '\\'))
- yield;
+ case 'g', 'v' =>
+ if (!strings::hassuffix(cmd.arg2, '\\')) {
+ append(cmd.textinput, strings::dup(cmd.arg2));
+ yield :input;
+ };
+ append(cmd.textinput,
+ strings::dup(strings::rtrim(cmd.arg2, '\\')));
for (true) {
let inputline = match (bufio::scan_line(input)?) {
@@ -79,12 +83,24 @@ fn parse(input: *bufio::scanner) (Command | ParseError | InteractionError) = {
case io::EOF =>
break;
};
-
- // TODO: parse and append to .subcmds ?
- append(cmd.textinput, strings::dup(inputline));
+ // workaround scan_line undelimited last line.
+ // note, GNU ed would use "p\n" instead.
+ if (inputline == "") {
+ append(cmd.textinput, strings::dup("\n"));
+ break;
+ };
+ if (!strings::hassuffix(inputline, '\\')) {
+ append(cmd.textinput, strings::dup(inputline));
+ break;
+ };
+ append(cmd.textinput,
+ strings::dup(strings::rtrim(inputline, '\\')));
};
};
+ for (let i = 0z; i < len(cmd.textinput); i += 1)
+ debug("parse() cmd.textinput[{}]=<{}>", i, cmd.textinput[i]);
+
return cmd;
};