commit 1778577cd71cc38d122376684360a0ce1520d402
parent 66828105d090f28900ccf2703d05d112c4f33abb
Author: Byron Torres <b@torresjrjr.com>
Date: Sun, 7 Jan 2024 01:07:17 +0000
add cmd_invglobal(), global.ha
Diffstat:
M | Makefile | | | 1 | + |
M | command.ha | | | 189 | ++++--------------------------------------------------------------------------- |
A | global.ha | | | 190 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 199 insertions(+), 181 deletions(-)
diff --git a/Makefile b/Makefile
@@ -7,6 +7,7 @@ source=\
buffer.ha \
command.ha \
execute.ha \
+ global.ha \
interaction.ha \
parse.ha \
util.ha \
diff --git a/command.ha b/command.ha
@@ -1,4 +1,3 @@
-use bufio;
use errors;
use fmt;
use fs;
@@ -8,7 +7,6 @@ use os;
use os::exec;
use regex;
use strings;
-use types;
type Command = struct{
addrs: []Address,
@@ -253,186 +251,11 @@ fn cmd_filename(s: *Session, cmd: *Command) (void | Error) = {
};
fn cmd_global(s: *Session, cmd: *Command) (void | Error) = {
- s.warned = false;
-
- const (a, b) = get_range(
- s,
- &cmd.linenums,
- addr_linenum(s.buf, 1)?,
- addr_lastline(s.buf),
- )?;
- assert_nonzero(s, a)?;
-
- 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.name=<{}>", subcmd.name);
-
- // TODO: write new parse_global() function instead
- // as to avoid reading multiple lines in the case of
- // 'a', 'c', 'i' ?
- switch (subcmd.name) {
- case 'g', 'G', 'v', 'V', '!' =>
- // TODO: implement?
- errormsg(s, subcmd.name: 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{ name = '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;
- };
+ global(s, cmd, true)?;
};
fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = {
- s.warned = false;
-
- const (a, b) = get_range(
- s,
- &cmd.linenums,
- addr_linenum(s.buf, 1)?,
- addr_lastline(s.buf),
- )?;
- assert_nonzero(s, a)?;
-
- 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 prevsubcmd: (void | Command) = void; // TODO: handle mem
-
- 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];
-
- fmt::println(line.text)!;
-
- // TODO: handle termination by SIGINT signal
-
- // TODO: handle mem
- // TODO: just use 'parse()?' when compiler allows
- //let subcmd = parse(s.input)?;
- let subcmd = match (parse(s.input)) {
- case let c: Command =>
- yield c;
- case let e: ParseError =>
- return e;
- case let e: InteractionError =>
- return e;
- };
-
- // TODO: write new parse_global_interactive() function instead
- // as to avoid reading multiple lines in the case of
- // 'a', 'c', 'i' ?
- switch (subcmd.name) {
- case 'a', 'c', 'i', 'g', 'G', 'v', 'V' =>
- errormsg(s, subcmd.name: InvalidGlobalSubCmd);
- continue;
- case NUL =>
- line.globalmark = false;
- continue;
- case '&' =>
- match (prevsubcmd) {
- case void =>
- return NoPrevGlobalSubCmd;
- case let prevsubcmd: Command =>
- subcmd = prevsubcmd;
- };
- case 'u' =>
- // TODO: undo behaviour
- continue;
- case =>
- prevsubcmd = subcmd;
- };
-
- execute(s, &subcmd)?;
-
- line.globalmark = false;
- };
+ global_interactive(s, cmd, true)?;
};
fn cmd_help(s: *Session, cmd: *Command) (void | Error) = {
@@ -771,9 +594,13 @@ fn cmd_copy(s: *Session, cmd: *Command) (void | Error) = {
fn cmd_undo(s: *Session, cmd: *Command) (void | Error) = void;
-fn cmd_invglobal(s: *Session, cmd: *Command) (void | Error) = void;
+fn cmd_invglobal(s: *Session, cmd: *Command) (void | Error) = {
+ global(s, cmd, false)?;
+};
-fn cmd_invglobal_interative(s: *Session, cmd: *Command) (void | Error) = void;
+fn cmd_invglobal_interative(s: *Session, cmd: *Command) (void | Error) = {
+ global_interactive(s, cmd, false)?;
+};
fn cmd_write(s: *Session, cmd: *Command) (void | Error) = {
s.warned = false;
diff --git a/global.ha b/global.ha
@@ -0,0 +1,190 @@
+use bufio;
+use fmt;
+use io;
+use memio;
+use regex;
+use strings;
+use types;
+
+fn global(s: *Session, cmd: *Command, matched: bool) (void | Error) = {
+ s.warned = false;
+
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ addr_linenum(s.buf, 1)?,
+ addr_lastline(s.buf),
+ )?;
+ assert_nonzero(s, a)?;
+
+ 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 (matched ^^ !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.name=<{}>", subcmd.name);
+
+ // TODO: write new parse_global() function instead
+ // as to avoid reading multiple lines in the case of
+ // 'a', 'c', 'i' ?
+ switch (subcmd.name) {
+ case 'g', 'G', 'v', 'V', '!' =>
+ // TODO: undefined specification. implement?
+ errormsg(s, subcmd.name: 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{ name = '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 global_interactive(s: *Session, cmd: *Command, matched: bool) (void | Error) = {
+ s.warned = false;
+
+ const (a, b) = get_range(
+ s,
+ &cmd.linenums,
+ addr_linenum(s.buf, 1)?,
+ addr_lastline(s.buf),
+ )?;
+ assert_nonzero(s, a)?;
+
+ 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 (matched ^^ !regex::test(®ex, line.text)) {
+ line.globalmark = true;
+ };
+ };
+
+ let prevsubcmd: (void | Command) = void; // TODO: handle mem
+
+ 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];
+
+ fmt::println(line.text)!;
+
+ // TODO: handle termination by SIGINT signal
+
+ // TODO: handle mem
+ // TODO: just use 'parse()?' when compiler allows
+ //let subcmd = parse(s.input)?;
+ let subcmd = match (parse(s.input)) {
+ case let c: Command =>
+ yield c;
+ case let e: ParseError =>
+ return e;
+ case let e: InteractionError =>
+ return e;
+ };
+
+ // TODO: write new parse_global_interactive() function instead
+ // as to avoid reading multiple lines in the case of
+ // 'a', 'c', 'i' ?
+ switch (subcmd.name) {
+ case 'a', 'c', 'i', 'g', 'G', 'v', 'V' =>
+ errormsg(s, subcmd.name: InvalidGlobalSubCmd);
+ continue;
+ case NUL =>
+ line.globalmark = false;
+ continue;
+ case '&' =>
+ match (prevsubcmd) {
+ case void =>
+ return NoPrevGlobalSubCmd;
+ case let prevsubcmd: Command =>
+ subcmd = prevsubcmd;
+ };
+ case 'u' =>
+ // TODO: undo behaviour
+ continue;
+ case =>
+ prevsubcmd = subcmd;
+ };
+
+ execute(s, &subcmd)?;
+
+ line.globalmark = false;
+ };
+};