From cb228d8c8b58e3c583d7f84d3c5b2218e51fe3bf Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 1 Nov 2020 14:22:57 +0100 Subject: [PATCH] shell line edit: cursor, pos1, end, del, F1.. --- CHANGELOG_LATEST.md | 1 + lib/uuid-console/src/shell.cpp | 177 +++++++++++++++++----------- lib/uuid-console/src/uuid/console.h | 4 +- 3 files changed, 111 insertions(+), 71 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 14fab2652..77d09e2a2 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -1,6 +1,7 @@ # Changelog ### Added +- function keys in editor: cursor, del, pos1, end. F1=help, F2=show, F10=report ### Fixed diff --git a/lib/uuid-console/src/shell.cpp b/lib/uuid-console/src/shell.cpp index ddc03d82a..e68af84c8 100644 --- a/lib/uuid-console/src/shell.cpp +++ b/lib/uuid-console/src/shell.cpp @@ -65,8 +65,8 @@ void Shell::start() { #endif line_buffer_.reserve(maximum_command_line_length_); - oldline_.reserve(maximum_command_line_length_); - oldline_.clear(); + line_old_.reserve(maximum_command_line_length_); + line_old_.clear(); display_banner(); display_prompt(); shells_.insert(shared_from_this()); @@ -148,8 +148,7 @@ void Shell::loop_normal() { // Interrupt (^C) line_buffer_.clear(); println(); - prompt_displayed_ = false; - display_prompt(); + cursor_ = 0; break; case '\x04': @@ -160,51 +159,38 @@ void Shell::loop_normal() { break; case '\x08': - case '\x7F': // Backspace (^H) - // Delete (^?) - if (!line_buffer_.empty()) { - erase_characters(1); - line_buffer_.pop_back(); + case '\x7F': + // Del/Backspace (^?) + if (line_buffer_.length() > cursor_) { + line_buffer_.erase(line_buffer_.length() - cursor_ - 1, 1); } break; case '\x09': // Tab (^I) process_completion(); + cursor_ = 0; break; case '\x0A': // Line feed (^J) if (previous_ != '\x0D') { - if (!line_buffer_.empty()) { - oldline_ = line_buffer_; - } process_command(); } break; - case '\x0C': - // New page (^L) - erase_current_line(); - prompt_displayed_ = false; - display_prompt(); - break; - case '\x0D': - if (!line_buffer_.empty()) { - oldline_ = line_buffer_; - } // Carriage return (^M) process_command(); break; + case '\x0C': + // New page (^L) case '\x15': // Delete line (^U) - erase_current_line(); - prompt_displayed_ = false; line_buffer_.clear(); - display_prompt(); + cursor_ = 0; break; case '\x17': @@ -212,51 +198,91 @@ void Shell::loop_normal() { delete_buffer_word(true); break; + case '\033': + // esc + esc_ = 0x80; + break; + default: - if (c >= '\x20' && c <= '\x7E') { + if (esc_) { + if (c == '[') { + // start of sequence + } else if (c >= '0' && (c <= '9')) { + // numbers + esc_ = (esc_ & 0x7F) * 10 + c - '0'; + } else if (c == 'A') { + // cursor up + line_buffer_ = line_old_; + cursor_ = 0; + esc_ = 0; + } else if (c == 'B') { + // cursor down + line_buffer_.clear(); + cursor_ = 0; + esc_ = 0; + } else if (c == 'C') { + // cursor right + if (cursor_) { + cursor_--; + } + esc_ = 0; + } else if (c == 'D') { + // cursor left + if (cursor_ < line_buffer_.length()) { + cursor_++; + } + esc_ = 0; + } else if (c == '~') { + // function keys with number + if ((esc_ == 3) && cursor_) { + // del + cursor_--; + line_buffer_.erase(line_buffer_.length() - cursor_ - 1, 1); + } else if (esc_ == 4) { + // end + cursor_ = 0; + } else if (esc_ == 1) { + // pos1 + cursor_ = line_buffer_.length(); + } else if (esc_ == 11) { + // F1 and F10 + line_buffer_ = "help"; + process_command(); + } else if (esc_ == 12) { + // F2 + line_buffer_ = "show"; + process_command(); + } else if (esc_ == 20) { + // F9 + line_buffer_ = "send telegram \"0B \""; + cursor_ = 1; + } else if (esc_ == 21) { + // F10 + line_buffer_ = "call system report"; + process_command(); + } + esc_ = 0; + } else { + // all other chars end sequence + esc_ = 0; + } + } else if (c >= '\x20' && c <= '\x7E') { // ASCII text if (line_buffer_.length() < maximum_command_line_length_) { - line_buffer_.push_back(c); - write((uint8_t)c); - } - // cursor up, get last command - if ((c == 'A') && (previous_ == '[')) { - erase_current_line(); - prompt_displayed_ = false; - line_buffer_ = oldline_; - display_prompt(); - } - // cursor back, delete cursor chars - if ((c == 'D') && (previous_ == '[')) { - line_buffer_.pop_back(); - line_buffer_.pop_back(); - // alternative work as backspace - // if (line_buffer_.length() > 0) { - // line_buffer_.pop_back(); - // } - erase_current_line(); - prompt_displayed_ = false; - display_prompt(); - } - // cursor forward, only delete cursor chars - if ((c == 'C') && (previous_ == '[')) { - line_buffer_.pop_back(); - line_buffer_.pop_back(); - erase_current_line(); - prompt_displayed_ = false; - display_prompt(); - } - // cursor down(B): Delete line - if ((c == 'B') && (previous_ == '[')) { - erase_current_line(); - prompt_displayed_ = false; - line_buffer_.clear(); - display_prompt(); + line_buffer_.insert(line_buffer_.length() - cursor_, 1, c); } } break; } + // common for all, display the complete line + erase_current_line(); + prompt_displayed_ = false; + display_prompt(); + if (cursor_) { + printf(F("\033[%dD"), cursor_); + } + previous_ = c; // This is a hack to let TelnetStream know that command @@ -428,16 +454,24 @@ void Shell::delete_buffer_word(bool display) { if (pos == std::string::npos) { line_buffer_.clear(); - if (display) { - erase_current_line(); - prompt_displayed_ = false; - display_prompt(); - } + cursor_ = 0; } else { if (display) { - erase_characters(line_buffer_.length() - pos); + size_t pos1 = 0; + pos = 0; + while (pos1 < line_buffer_.length() - cursor_) { + pos = pos1; + pos1 = line_buffer_.find(' ', pos + 1); + } + line_buffer_.erase(pos, pos1 - pos); + if (line_buffer_.find(' ') == 0) { + line_buffer_.erase(0, 1); + } + cursor_ = line_buffer_.length() - pos; + } else { + line_buffer_.resize(pos); + cursor_ = 0; } - line_buffer_.resize(pos); } } @@ -453,7 +487,6 @@ void Shell::maximum_command_line_length(size_t length) { void Shell::process_command() { CommandLine command_line{line_buffer_}; - line_buffer_.clear(); println(); prompt_displayed_ = false; @@ -467,8 +500,12 @@ void Shell::process_command() { } else { println(F("No commands configured")); } + line_old_ = line_buffer_; } + cursor_ = 0; + line_buffer_.clear(); + if (running()) { display_prompt(); } diff --git a/lib/uuid-console/src/uuid/console.h b/lib/uuid-console/src/uuid/console.h index 5b65acb5f..6918020cb 100644 --- a/lib/uuid-console/src/uuid/console.h +++ b/lib/uuid-console/src/uuid/console.h @@ -903,9 +903,11 @@ class Shell : public std::enable_shared_from_this, public uuid::log::Hand std::list log_messages_; /*!< Queued log messages, in the order they were received. @since 0.1.0 */ size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum command line length in bytes. @since 0.6.0 */ std::string line_buffer_; /*!< Command line buffer. Limited to maximum_command_line_length() bytes. @since 0.1.0 */ + std::string line_old_; /*!< old Command line buffer.*/ size_t maximum_command_line_length_ = MAX_COMMAND_LINE_LENGTH; /*!< Maximum command line length in bytes. @since 0.6.0 */ unsigned char previous_ = 0; /*!< Previous character that was entered on the command line. Used to detect CRLF line endings. @since 0.1.0 */ - std::string oldline_; /*!< old Command line buffer.*/ + uint8_t cursor_ = 0; /*!< cursor position from end of line */ + uint8_t esc_ = 0; /*!< esc sequence running */ Mode mode_ = Mode::NORMAL; /*!< Current execution mode. @since 0.1.0 */ std::unique_ptr mode_data_ = nullptr; /*!< Data associated with the current execution mode. @since 0.1.0 */ bool stopped_ = false; /*!< Indicates that the shell has been stopped. @since 0.1.0 */