From ab84cdb790b6cf6698dd1326ec04940bf2affe11 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 28 Apr 2024 17:24:15 -0700 Subject: [PATCH] [edit] Change libedit API The edit::line API now takes a source object for I/O, qnd allows getting a single command from the editor. --- src/libraries/edit/include/edit/line.h | 32 +++---- src/libraries/edit/line.cpp | 122 ++++++++++--------------- src/user/6s/main.cpp | 93 ++++++------------- 3 files changed, 88 insertions(+), 159 deletions(-) diff --git a/src/libraries/edit/include/edit/line.h b/src/libraries/edit/include/edit/line.h index 5ad9aba..2437bc2 100644 --- a/src/libraries/edit/include/edit/line.h +++ b/src/libraries/edit/include/edit/line.h @@ -7,34 +7,28 @@ namespace edit { +class API source +{ +public: + virtual size_t read(char const **data) = 0; + virtual void consume(size_t size) = 0; + virtual void write(char const *data, size_t len) = 0; +}; + + class API line { public: - line(const char *prompt = nullptr, size_t propmt_len = 0); + line(source &s); ~line(); - /// Feed input from the terminal keyboard in. - /// \arg data Data from the keyboard - /// \arg len Length of data in bytes - /// \retruns Number of bytes consumed - size_t input(char const *data, size_t len); - - /// Get output to be sent to the terminal screen. - /// \arg data [out] Data to be written to the screen - /// \returns Number of bytes from data to be written - size_t output(char const **data); + /// Get a finished line from the editor. + size_t read(char *buffer, size_t size, char const *prompt = nullptr, size_t prompt_len = 0); private: size_t parse_command(char const *data, size_t len); - char *m_buf; - - size_t m_in; - size_t m_out; - size_t m_prefix; - - char const *m_tmp_out; - size_t m_tmp_out_len; + source &m_source; }; } // namespace edit diff --git a/src/libraries/edit/line.cpp b/src/libraries/edit/line.cpp index 2d44b25..a2b5b5e 100644 --- a/src/libraries/edit/line.cpp +++ b/src/libraries/edit/line.cpp @@ -2,6 +2,8 @@ #include #include +static inline size_t min(size_t a, size_t b) { return a > b ? a : b; } + namespace edit { static constexpr char ESC = '\x1b'; @@ -17,96 +19,68 @@ static const size_t get_pos_len = sizeof(get_pos) - 1; static const char backspace[] = "\x1b[D\x1b[K"; static const size_t backspace_len = sizeof(backspace) - 1; -line::line(const char *prompt, size_t prompt_len) : - m_out {0} +line::line(source &s) : + m_source {s} { - m_buf = new char [1024]; - memcpy(m_buf, init_line, init_line_len); - m_in = init_line_len; - - if (prompt && prompt_len) { - memcpy(m_buf + m_in, prompt, prompt_len); - m_in += prompt_len; - } - - m_prefix = m_in; - - m_tmp_out = get_pos; - m_tmp_out_len = get_pos_len; } line::~line() { - delete [] m_buf; } size_t -line::input(char const *data, size_t len) +line::read(char *buffer, size_t size, char const *prompt, size_t prompt_len) { - j6::syslog(j6::logs::app, j6::log_level::spam, "Line edit got %d bytes input", len); - size_t i = 0; - size_t sub_len = 0; - while (i < len) { - switch (data[i]) { - case ESC: - sub_len = parse_command(data + i, len - i); - if (!sub_len) - return i; // Not yet enough data - i += sub_len; - break; + m_source.write(init_line, init_line_len); + if (prompt && prompt_len) + m_source.write(prompt, prompt_len); - case BACKSPACE: - case DEL: - if (m_in > m_prefix) { - --m_in; - if (m_out > m_in) - m_out = m_in; - m_tmp_out = backspace; - m_tmp_out_len = backspace_len; + size_t in = 0; + + while (in < size) { + char const *input = nullptr; + size_t inlen = m_source.read(&input); + + size_t i = 0; + size_t sub_len = 0; + while (i < inlen) { + switch (input[i]) { + case ESC: + sub_len = parse_command(input + i, inlen - i); + if (!sub_len) + goto reread; + i += sub_len; + break; + + case BACKSPACE: + case DEL: + if (in > 0) { + --in; + m_source.write(backspace, backspace_len); + } + ++i; + break; + + case '\r': + m_source.consume(++i); + m_source.write("\n", 1); + buffer[in] = 0; + return in; + + default: + m_source.write(input + i, 1); + buffer[in++] = input[i++]; + break; } - ++i; - break; - - case '\r': - m_out = 0; - m_in = m_prefix; - m_tmp_out = "\n"; - m_tmp_out_len = 1; - ++i; - break; - - default: - m_buf[m_in++] = data[i++]; - break; } + +reread: + m_source.consume(i); } - return i; -} - - -size_t -line::output(char const **data) -{ - if (m_tmp_out) { - char const *out = m_tmp_out; - m_tmp_out = nullptr; - - size_t len = m_tmp_out_len; - m_tmp_out_len = 0; - - *data = out; - j6::syslog(j6::logs::app, j6::log_level::spam, "Line edit sending %d bytes alt output", len); - return len; - } - - *data = (m_buf + m_out); - size_t len = m_in - m_out; - m_out = m_in; - j6::syslog(j6::logs::app, j6::log_level::spam, "Line edit sending %d bytes output", len); - return len; + return 0; } diff --git a/src/user/6s/main.cpp b/src/user/6s/main.cpp index b52bbc1..db24640 100644 --- a/src/user/6s/main.cpp +++ b/src/user/6s/main.cpp @@ -18,57 +18,29 @@ j6_handle_t g_handle_sys = j6_handle_invalid; const char prompt[] = "\x1b[1;32mj6> \x1b[0m"; static constexpr size_t prompt_len = sizeof(prompt) - 1; -const char query[] = "\x1b[6n"; -static constexpr size_t query_len = sizeof(prompt) - 1; - -size_t -gather_command(j6::channel &cout, j6::ring_buffer &buf) +class channel_source : + public edit::source { - size_t total_len = buf.used(); +public: + channel_source(j6::channel &chan) : m_chan {chan} {} - while (true) { - size_t size = buf.free(); - char *start = buf.write_ptr(); - - uint8_t const *input = nullptr; - size_t n = cout.get_block(&input); - if (n > size) n = size; - - uint8_t *outp = nullptr; - cout.reserve(n, &outp, true); - - size_t i = 0; - bool newline = false; - bool eof = false; - while (i < n) { - start[i] = input[i]; - outp[i] = input[i]; - if (start[i] == 0x1b) - outp[i] = 'E'; - if (start[i] == 4) - eof = true; - - if (start[i++] == '\r') { - newline = true; - break; - } - } - - cout.commit(i); - cout.consume(i); - - if (eof) { - cout.reserve(query_len, &outp, true); - memcpy(outp, query, query_len); - cout.commit(query_len); - } - - if (newline) - return total_len + i; - - total_len += size; + size_t read(char const **data) override { + return m_chan.get_block(reinterpret_cast(data)); } -} + + void consume(size_t size) override { return m_chan.consume(size); } + + void write(char const *data, size_t len) override { + uint8_t *outp; + m_chan.reserve(len, &outp); + memcpy(outp, data, len); + m_chan.commit(len); + } + +private: + j6::channel &m_chan; +}; + int main(int argc, const char **argv) @@ -112,25 +84,14 @@ main(int argc, const char **argv) if (!cout) return 5; - edit::line editor {prompt, prompt_len}; + channel_source source {*cout}; + edit::line editor {source}; + + static constexpr size_t bufsize = 256; + char buffer [bufsize]; while (true) { - uint8_t *outb = nullptr; - char const *inc = nullptr; - size_t len = editor.output(&inc); - while (len) { - cout->reserve(len, &outb, true); - memcpy(outb, inc, len); - cout->commit(len); - len = editor.output(&inc); - } - - char *outc = nullptr; - uint8_t const *inb = nullptr; - len = cout->get_block(&inb); - if (len) { - len = editor.input(reinterpret_cast(inb), len); - cout->consume(len); - } + size_t len = editor.read(buffer, bufsize, prompt, prompt_len); + j6::syslog(j6::logs::app, j6::log_level::info, "Command: %s", buffer); } }