ed

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

commit 18bb4f889430b5f59936ce12aa199e8bc37df527
parent 3354f41adc477539f2763576bb3140071dd9b7d6
Author: Byron Torres <b@torresjrjr.com>
Date:   Tue,  9 Jan 2024 00:41:52 +0000

cmd_write(): impl ! shell commands

Diffstat:
MMakefile | 1+
Mcommand.ha | 96++++++++++++++++++++++++++++++-------------------------------------------------
Afile.ha | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.ha | 12------------
4 files changed, 89 insertions(+), 72 deletions(-)

diff --git a/Makefile b/Makefile @@ -7,6 +7,7 @@ source=\ buffer.ha \ command.ha \ execute.ha \ + file.ha \ global.ha \ interaction.ha \ parse.ha \ diff --git a/command.ha b/command.ha @@ -179,38 +179,11 @@ fn cmd_delete(s: *Session, cmd: *Command) (void | Error) = { }; fn cmd_edit(s: *Session, cmd: *Command) (void | Error) = { - assert_noaddrs(s, cmd.linenums)?; - - if (s.buf.modified && !s.warned) { - s.warned = true; - return WarnBufferModified; - }; - - const fname = filename(s, cmd, true)?; - const h = os::open(fname)?; 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; + edit(s, cmd, false)?; }; fn cmd_edit_forced(s: *Session, cmd: *Command) (void | Error) = { - assert_noaddrs(s, cmd.linenums)?; - - const fname = filename(s, cmd, true)?; - const h = os::open(fname)?; 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; + edit(s, cmd, true)?; }; fn cmd_filename(s: *Session, cmd: *Command) (void | Error) = { @@ -448,15 +421,13 @@ fn cmd_read(s: *Session, cmd: *Command) (void | Error) = { const n = get_linenum(cmd.linenums, addr_lastline(s.buf)); - const h: io::handle = + const rd: io::handle = if (!strings::hasprefix(cmd.arg1, "!")) { const fname = filename(s, cmd, false)?; yield os::open(fname)?; } else { - // TODO: handle '!'s - let shcmd = exec::cmd( - "sh", "-c", strings::cut(cmd.arg1, "!").1 - )?; + let shcmdline = strings::cut(cmd.arg1, "!").1; + let shcmd = exec::cmd("sh", "-c", shcmdline)?; let pipe = exec::pipe(); exec::addfile(&shcmd, os::stdout_file, pipe.1); let proc = exec::start(&shcmd)?; @@ -464,9 +435,9 @@ fn cmd_read(s: *Session, cmd: *Command) (void | Error) = { exec::wait(&proc)?; yield pipe.0; }; - defer io::close(h)!; + defer io::close(rd)!; - const (sz, _) = buf_read(s.buf, h, n)?; + const (sz, _) = buf_read(s.buf, rd, n)?; if (!s.suppressmode) fmt::println(sz)!; @@ -578,21 +549,25 @@ fn cmd_write(s: *Session, cmd: *Command) (void | Error) = { )?; assert_nonzero(s, a)?; - const fname = filename(s, cmd, false)?; - const h = match (os::open(fname, fs::flag::WRONLY)) { - case let err: fs::error => - yield match (err) { - case errors::noentry => - yield os::create(fname, 0o644)?: io::handle; - case => - return err; + let proc: (void | exec::process) = void; + const wr: io::handle = + if (!strings::hasprefix(cmd.arg1, "!")) { + yield openwritefile(filename(s, cmd, false)?)?; + } else { + let shcmdline = strings::cut(cmd.arg1, "!").1; + let shcmd = exec::cmd("sh", "-c", shcmdline)?; + let pipe = exec::pipe(); + exec::addfile(&shcmd, os::stdin_file, pipe.0); + proc = exec::start(&shcmd)?; + yield pipe.1; }; - case let h: io::file => - yield h: io::handle; - }; - defer io::close(h)!; - const sz = buf_write(s.buf, h, a, b)?; + const sz = buf_write(s.buf, wr, a, b)?; + io::close(wr)!; + + // XXX: create a stdout pipe and copy it out here instead? + if (proc is exec::process) + exec::wait(&(proc as exec::process))?; if (!s.suppressmode) fmt::println(sz)!; @@ -657,20 +632,21 @@ fn cmd_shellescape(s: *Session, cmd: *Command) (void | Error) = { }; let shcmdline = memio::string(&new)!; - - let shcmd = exec::cmd("sh", "-c", shcmdline)?; - let pipe = exec::pipe(); - exec::addfile(&shcmd, os::stdout_file, pipe.1); - let proc = exec::start(&shcmd)?; - io::close(pipe.1)!; - - exec::wait(&proc)?; - if (preview) fmt::println(shcmdline)!; - io::copy(os::stdout, pipe.0)!; - io::close(pipe.0)!; + let rd: io::handle = { + let shcmd = exec::cmd("sh", "-c", shcmdline)?; + let pipe = exec::pipe(); + exec::addfile(&shcmd, os::stdout_file, pipe.1); + let proc = exec::start(&shcmd)?; + io::close(pipe.1)!; + exec::wait(&proc)?; + yield pipe.0; + }; + defer io::close(rd)!; + + io::copy(os::stdout, rd)!; if (!s.suppressmode) fmt::println("!")!; diff --git a/file.ha b/file.ha @@ -0,0 +1,52 @@ +use errors; +use fmt; +use fs; +use io; +use os; +use strings; + +fn edit(s: *Session, cmd: *Command, forced: bool) (void | Error) = { + assert_noaddrs(s, cmd.linenums)?; + + if (!forced && s.buf.modified && !s.warned) { + s.warned = true; + return WarnBufferModified; + }; + + const fname = filename(s, cmd, true)?; + const rd = os::open(fname)?; defer io::close(rd)!; + + buf_deleteall(s.buf); + const (sz, _) = buf_read(s.buf, rd, 0)?; + + if (!s.suppressmode) + fmt::println(sz)!; + + s.buf.cursor = len(s.buf.lines) - 1; +}; + +fn filename(s: *Session, cmd: *Command, remember: bool) (str | NoFilename) = { + if (cmd.arg1 != "") { + if (remember || s.buf.filename == "") + s.buf.filename = strings::dup(cmd.arg1); + return cmd.arg1; + }; + if (s.buf.filename != "") + return s.buf.filename; + + return NoFilename; +}; + +fn openwritefile(fname: str) (io::file | fs::error) = { + match (os::open(fname, fs::flag::WRONLY)) { + case let h: io::file => + return h; + case let e: fs::error => + match (e) { + case errors::noentry => + return os::create(fname, 0o644)?; + case => + return e; + }; + }; +}; diff --git a/util.ha b/util.ha @@ -82,15 +82,3 @@ fn printlistln(text: str) (size | io::error) = { sz += fmt::println('$')?; return sz; }; - -fn filename(s: *Session, cmd: *Command, remember: bool) (str | NoFilename) = { - if (cmd.arg1 != "") { - if (remember || s.buf.filename == "") - s.buf.filename = strings::dup(cmd.arg1); - return cmd.arg1; - }; - if (s.buf.filename != "") - return s.buf.filename; - - return NoFilename; -};