ed

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

commit eddd47458d41cb267c74ea07b26dce189f9c844b
parent b9d8945d34c6e559a87400a99c7c4f6fadabcd2b
Author: Byron Torres <b@torresjrjr.com>
Date:   Sun, 11 Dec 2022 03:18:36 +0000

reorganise command code, create stubs

Diffstat:
Mcommand.ha | 253+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mparse.ha | 25+++----------------------
2 files changed, 160 insertions(+), 118 deletions(-)

diff --git a/command.ha b/command.ha @@ -4,6 +4,25 @@ use fs; use io; use os; +type command = struct { + addrs: []address, + linenums: []size, + cmdfn: commandfn, + suffix: suffix, + arg: str, + input: []str, + subcmds: []command, +}; + +type commandfn = *fn(_: *session, _: *command) (void | error); + +type suffix = enum { + NONE, + LIST, + NUMBER, + PRINT, +}; + type error = !( badaddress | nofilename @@ -18,6 +37,15 @@ type buffermodified = !void; 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)?; +}; + fn exec_addrs(s: *session, cmd: *command) (void | error) = { for (let i = 0z; i < len(cmd.addrs); i += 1) { const addr = cmd.addrs[i]; @@ -42,14 +70,6 @@ fn exec_addrs(s: *session, cmd: *command) (void | error) = { }; }; -// 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)?; -}; fn get_range(s: *session, lns: *[]size, a: size, b: size) ((size, size) | badaddress) = { const (a, b) = if (len(lns) == 0) { @@ -82,16 +102,85 @@ fn assert_noaddrs(s: *session, lns: []size) (void | unexpectedaddress) = { }; }; -fn cmd_prompt(s: *session, cmd: *command) (void | error) = { +fn cmd_append(s: *session, cmd: *command) (void | error) = void; + +fn cmd_change(s: *session, cmd: *command) (void | error) = void; + +fn cmd_delete(s: *session, cmd: *command) (void | error) = { + const (a, b) = get_range( + s, + &cmd.linenums, + s.buf.cursor, + s.buf.cursor, + )?; + if (a < 1) return badaddress; + + buf_delete(&s.buf, a, b); + s.buf.cursor = if (len(s.buf.lines) == 1) { + yield 0; + } else if (len(s.buf.lines) == a) { + yield a - 1; + } else { + yield a; + }; +}; + +fn cmd_edit(s: *session, cmd: *command) (void | error) = { assert_noaddrs(s, cmd.linenums)?; - s.promptmode = !s.promptmode; + + if (s.buf.modified && !s.warned) { + errormsg(s, "Warning: buffer modified"); + s.warned = true; + return buffermodified; + }; + + 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 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; + }; + defer io::close(h)!; + + buf_deleteall(&s.buf); + const (sz, _) = buf_read(&s.buf, h, 0); + if (!s.suppressmode) { + fmt::println(sz)!; + }; + s.buf.cursor = len(s.buf.lines) - 1; }; -fn cmd_linenumber(s: *session, cmd: *command) (void | error) = { - const n = get_linenum(cmd.linenums, addr_lastline(&s.buf)); - fmt::println(n)!; +fn cmd_edit_forced(s: *session, cmd: *command) (void | error) = void; + +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) { + errormsg(s, "No current filename"); + return nofilename; + }; + fmt::println(s.buf.filename)!; }; +fn cmd_global(s: *session, cmd: *command) (void | error) = void; + +fn cmd_global_manual(s: *session, cmd: *command) (void | error) = void; + fn cmd_help(s: *session, cmd: *command) (void | error) = { assert_noaddrs(s, cmd.linenums)?; if (s.lasterror != "") { @@ -107,89 +196,52 @@ fn cmd_helpmode(s: *session, cmd: *command) (void | error) = { }; }; -fn cmd_print(s: *session, cmd: *command) (void | error) = { +fn cmd_insert(s: *session, cmd: *command) (void | error) = void; + +fn cmd_join(s: *session, cmd: *command) (void | error) = void; + +fn cmd_mark(s: *session, cmd: *command) (void | error) = void; + +fn cmd_list(s: *session, cmd: *command) (void | error) = void; + +fn cmd_move(s: *session, cmd: *command) (void | error) = void; + +fn cmd_number(s: *session, cmd: *command) (void | error) = { const (a, b) = get_range( s, &cmd.linenums, s.buf.cursor, s.buf.cursor, )?; + if (a < 1) return badaddress; + for (let n = a; n <= b; n += 1) { - fmt::println(s.buf.lines[n].text)!; + fmt::printfln("{}\t{}", n, s.buf.lines[n].text)!; }; s.buf.cursor = b; }; -fn cmd_number(s: *session, cmd: *command) (void | error) = { +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::printfln("{}\t{}", n, s.buf.lines[n].text)!; + fmt::println(s.buf.lines[n].text)!; }; s.buf.cursor = b; }; -fn cmd_filename(s: *session, cmd: *command) (void | error) = { +fn cmd_prompt(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) { - errormsg(s, "No current filename"); - return nofilename; - }; - fmt::println(s.buf.filename)!; + s.promptmode = !s.promptmode; }; -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), - )?; +fn cmd_quit(s: *session, cmd: *command) (void | error) = void; - 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 nofilename; - }; - }; - - const h = match (os::open(fname)) { - 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)); - }; - case => - errormsg(s, fs::strerror(err)); - return err; - }; - case let h: io::file => - yield h: io::handle; - }; - defer io::close(h)!; - - const sz = buf_write(&s.buf, h, a, b); - if (!s.suppressmode) { - fmt::println(sz)!; - }; -}; +fn cmd_quit_forced(s: *session, cmd: *command) (void | error) = void; fn cmd_read(s: *session, cmd: *command) void = { const n = get_linenum(cmd.linenums, s.buf.cursor); @@ -220,12 +272,23 @@ fn cmd_read(s: *session, cmd: *command) void = { s.buf.cursor = len(s.buf.lines) - 1; }; -fn cmd_edit(s: *session, cmd: *command) (void | error) = { - if (s.buf.modified && !s.warned) { - errormsg(s, "Warning: buffer modified"); - s.warned = true; - return buffermodified; - }; +fn cmd_substitute(s: *session, cmd: *command) (void | error) = void; + +fn cmd_copy(s: *session, cmd: *command) (void | error) = void; + +fn cmd_undo(s: *session, cmd: *command) (void | error) = void; + +fn cmd_invglobal(s: *session, cmd: *command) (void | error) = void; + +fn cmd_invglobal_manual(s: *session, cmd: *command) (void | error) = void; + +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; @@ -241,38 +304,36 @@ fn cmd_edit(s: *session, cmd: *command) (void | error) = { const h = match (os::open(fname)) { case let err: fs::error => - errormsg(s, fs::strerror(err)); - return err; + 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)); + }; + case => + errormsg(s, fs::strerror(err)); + return err; + }; case let h: io::file => yield h: io::handle; }; defer io::close(h)!; - buf_deleteall(&s.buf); - const (sz, _) = buf_read(&s.buf, h, 0); + const sz = buf_write(&s.buf, h, a, b); if (!s.suppressmode) { fmt::println(sz)!; }; - s.buf.cursor = len(s.buf.lines) - 1; }; -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; - } else if (len(s.buf.lines) == a) { - yield a - 1; - } else { - yield a; - }; +fn cmd_linenumber(s: *session, cmd: *command) (void | error) = { + const n = get_linenum(cmd.linenums, addr_lastline(&s.buf)); + fmt::println(n)!; }; +fn cmd_shellescape(s: *session, cmd: *command) (void | error) = void; + fn cmd_null(s: *session, cmd: *command) (void | error) = { const n = get_linenum( cmd.linenums, diff --git a/parse.ha b/parse.ha @@ -4,25 +4,6 @@ use ascii; use strconv; use strings; -type command = struct { - addrs: []address, - linenums: []size, - cmdfn: commandfn, - suffix: suffix, - arg: str, - input: []str, - subcmds: []command, -}; - -type commandfn = *fn(_: *session, _: *command) (void | error); - -type suffix = enum { - NONE, - LIST, - NUMBER, - PRINT, -}; - // Parses inputted commands. Returns true on terminal input. fn parse(cmd: *command, input: str) bool = { if (len(input) != 1) { @@ -224,11 +205,11 @@ fn scan_cmdfn(iter: *strings::iterator) commandfn = { switch (r) { case '=' => return &cmd_linenumber; // case 'E' => return &cmd_edit_forced; -// case 'G' => return &cmd_global_interactive; +// case 'G' => return &cmd_global_manual; case 'H' => return &cmd_helpmode; case 'P' => return &cmd_prompt; // case 'Q' => return &cmd_quit_forced; -// case 'V' => return &cmd_global_inverse_interactive; +// case 'V' => return &cmd_invglobal_manual; // case 'a' => return &cmd_append; // case 'c' => return &cmd_change; case 'd' => return &cmd_delete; @@ -248,7 +229,7 @@ fn scan_cmdfn(iter: *strings::iterator) commandfn = { // case 's' => return &cmd_substitute; // case 't' => return &cmd_copy; // case 'u' => return &cmd_undo; -// case 'v' => return &cmd_global_inverse; +// case 'v' => return &cmd_invglobal; case 'w' => return &cmd_write; case 'b' => return &cmd_dumpbuffer;