From 30aa9b837cc9d0bc5bb434465c461e7f6c2c1806 Mon Sep 17 00:00:00 2001 From: Peter Elliott Date: Mon, 5 Jul 2021 23:55:10 -0600 Subject: [PATCH] Userland: Add minimal prompt support to less GNU less has a pretty cool prompt format language. This patch adds support for the language and specifiers for filename, linenumber, and ending. --- Userland/Utilities/less.cpp | 77 ++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/Userland/Utilities/less.cpp b/Userland/Utilities/less.cpp index 7d3524176e..59c923f361 100644 --- a/Userland/Utilities/less.cpp +++ b/Userland/Utilities/less.cpp @@ -174,7 +174,19 @@ public: void status_line() { - out(m_tty, "\e[7m -- less -- (line {})\e[27m", m_line + 1); + out(m_tty, "\e[7m "); + render_status_line(m_prompt); + out(m_tty, " \e[27m"); + } + + void set_filename(StringView const& filename) + { + m_filename = filename; + } + + void set_prompt(StringView const& prompt) + { + m_prompt = prompt; } bool read_line() @@ -191,7 +203,63 @@ public: return true; } + bool at_end() + { + return (m_line + m_height - 1) >= m_lines.size() && feof(m_file); + } + private: + size_t render_status_line(StringView const& prompt, size_t off = 0, char end = '\0', bool ignored = false) + { + for (; prompt[off] != end && off < prompt.length(); ++off) { + if (ignored) + continue; + + if (off + 1 >= prompt.length()) { + // Don't parse any multi-character sequences if we are at the end of input. + out(m_tty, "{}", prompt[off]); + continue; + } + + switch (prompt[off]) { + case '?': + switch (prompt[++off]) { + case 'f': + off = render_status_line(prompt, off + 1, ':', m_file == stdin); + off = render_status_line(prompt, off + 1, '.', m_file != stdin); + break; + case 'e': + off = render_status_line(prompt, off + 1, ':', !at_end()); + off = render_status_line(prompt, off + 1, '.', at_end()); + break; + default: + // Unknown flags are never true. + off = render_status_line(prompt, off + 1, ':', true); + off = render_status_line(prompt, off + 1, '.', false); + } + break; + case '%': + switch (prompt[++off]) { + case 'f': + out(m_tty, "{}", m_filename); + break; + case 'l': + out(m_tty, "{}", m_line); + break; + default: + out(m_tty, "?"); + } + break; + case '\\': + ++off; + [[fallthrough]]; + default: + out(m_tty, "{}", prompt[off]); + } + } + return off; + } + Vector m_lines; size_t m_line { 0 }; FILE* m_file; @@ -214,9 +282,12 @@ static String get_key_sequence() int main(int argc, char** argv) { - const char* filename = "-"; + char const* filename = "-"; + char const* prompt = "?f%f :.(line %l)?e (END):."; + Core::ArgsParser args_parser; args_parser.add_positional_argument(filename, "The paged file", "file", Core::ArgsParser::Required::No); + args_parser.add_option(prompt, "Prompt line", "prompt", 'P', "Prompt"); args_parser.parse(argc, argv); FILE* file; @@ -229,6 +300,8 @@ int main(int argc, char** argv) setup_tty(); Pager pager(file, stdout, g_wsize.ws_col, g_wsize.ws_row); + pager.set_filename(filename); + pager.set_prompt(prompt); pager.init();