ed

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

commit e741b8bd1d5c4129c3ece8a86789d551479a6f20
parent 905650984a0a7221922e40d5dd2702ad8aab4a5e
Author: Byron Torres <b@torresjrjr.com>
Date:   Tue, 22 Nov 2022 20:46:50 +0000

add command.ha, util.ha, cmd_edit()

Diffstat:
MMakefile | 2++
Mbuffer.ha | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Acommand.ha | 29+++++++++++++++++++++++++++++
Mmain.ha | 37+++++++++++++++++++++++++++++--------
Autil.ha | 7+++++++
5 files changed, 121 insertions(+), 10 deletions(-)

diff --git a/Makefile b/Makefile @@ -4,6 +4,8 @@ HAREFLAGS= source=\ main.ha \ buffer.ha \ + command.ha \ + util.ha \ all: ed diff --git a/buffer.ha b/buffer.ha @@ -1,7 +1,12 @@ +use bufio; +use fmt; +use io; +use strings; + type buffer = struct { filename: (void | str), - lines: []line, - trash: []line, + lines: []*line, + trash: []*line, cursor: size, }; @@ -10,3 +15,50 @@ type line = struct { mark: rune, globalmark: bool, }; + +fn buf_deleteall(buf: *buffer) void = { + buf_wipetrash(buf); + + for (len(buf.lines) > 1) { + insert(buf.trash[0], buf.lines[1]); + delete(buf.lines[1]); + }; +}; + +fn buf_read(buf: *buffer, src: io::handle, a: size) size = { + buf_wipetrash(buf); + + let newlines: []*line = []; + let sz = 0z; + for (true) { + const bytes = match (bufio::scanline(src)) { + case let bs: []u8 => + yield bs; + case io::EOF => + break; + case => + abort(); + }; + + sz += len(bytes); + const text = strings::fromutf8(bytes)!; + + append(newlines, alloc(line { text = text, ... })); + }; + + insert(buf.lines[a + 1], newlines...); + return sz; +}; + +fn buf_write(buf: *buffer, dest: io::handle, a: size, b: size) void = { + for (let n = a; n <= b; n += 1) { + fmt::fprintln(dest, buf.lines[n].text)!; + }; +}; + +fn buf_wipetrash(buf: *buffer) void = { + for (len(buf.trash) > 0) { + free(buf.trash[0].text); + delete(buf.trash[0]); + }; +}; diff --git a/command.ha b/command.ha @@ -0,0 +1,29 @@ +use fmt; +use fs; +use io; +use os; + +fn cmd_edit(s: *session, file: (void | str)) void = { + if (file is void) { + if (s.buffer.filename is void) { + return errormsg(s, "No current filename"); + }; + } else { + s.buffer.filename = file; + }; + const file = s.buffer.filename as str; + + const h = match (os::open(file)) { + case let err: fs::error => + return errormsg(s, fs::strerror(err)); + case let h: io::file => + yield h: io::handle; + }; + defer io::close(h)!; + + buf_deleteall(&s.buffer); + const sz = buf_read(&s.buffer, h, 0); + if (!s.suppressmode) { + fmt::println(sz)!; + }; +}; diff --git a/main.ha b/main.ha @@ -22,16 +22,24 @@ export fn main() void = { const cmd = getopt::parse(os::args, help...); defer getopt::finish(&cmd); - const sesh = session{ ... }; + const s = session{ + buffer = buffer{ + filename = void, + lines = [ alloc(line{ ... }) ], + trash = [], + ... + }, + ... + }; for (let i = 0z; i < len(cmd.opts); i += 1) { const opt = cmd.opts[i]; switch (opt.0) { case 'p' => - sesh.prompt = opt.1; - sesh.promptmode = true; + s.prompt = opt.1; + s.promptmode = true; case 's' => - sesh.suppressmode = true; + s.suppressmode = true; }; }; @@ -39,24 +47,29 @@ export fn main() void = { exit_usage(help); }; - sesh.buffer.filename = if (len(cmd.args) == 1) { - yield switch (cmd.args[0]) { + if (len(cmd.args) == 1) { + switch (cmd.args[0]) { case "-" => fmt::fatal("Invalid filename '-'"); case "" => fmt::fatal("Invalid filename ''"); case => - yield cmd.args[0]; + s.buffer.filename = cmd.args[0]; }; }; + if (s.buffer.filename is str) { + cmd_edit(&s, s.buffer.filename as str); + }; + for (true) :repl { - fmt::error(sesh.prompt)!; + fmt::error(s.prompt)!; const rawline = match (bufio::scanline(os::stdin)) { case let rawline: []u8 => yield rawline; case io::EOF => + fmt::println()!; break; case => abort(); @@ -65,6 +78,8 @@ export fn main() void = { const input = fmt::bsprint(rawline); }; + + dumpbuffer(&s.buffer); }; @noreturn fn exit_usage(help: []getopt::help) void = { @@ -72,3 +87,9 @@ export fn main() void = { os::exit(1); }; +fn errormsg(s: *session, msgfmt: str, args: fmt::field...) void = { + fmt::errorln('?')!; + if (s.helpmode) { + fmt::errorfln(msgfmt)!; + }; +}; diff --git a/util.ha b/util.ha @@ -0,0 +1,7 @@ +use fmt; + +fn dumpbuffer(buf: *buffer) void = { + for (let n = 1z; n < len(buf.lines); n += 1) { + fmt::printfln("{}\t{}", n, buf.lines[n].text)!; + }; +};