Ver código fonte

Shell: Allow browsing history with up/down arrow keys.

Andreas Kling 6 anos atrás
pai
commit
ad1c3c748f
2 arquivos alterados com 78 adições e 4 exclusões
  1. 67 4
      Shell/LineEditor.cpp
  2. 11 0
      Shell/LineEditor.h

+ 67 - 4
Shell/LineEditor.cpp

@@ -19,8 +19,24 @@ void LineEditor::add_to_history(const String& line)
     m_history.append(line);
     m_history.append(line);
 }
 }
 
 
+void LineEditor::clear_line()
+{
+    for (int i = 0; i < m_buffer.size(); ++i)
+        fputc(0x8, stdout);
+    fflush(stdout);
+    m_buffer.clear();
+}
+
+void LineEditor::append(const String& string)
+{
+    m_buffer.append(string.characters(), string.length());
+    fputs(string.characters(), stdout);
+    fflush(stdout);
+}
+
 String LineEditor::get_line()
 String LineEditor::get_line()
 {
 {
+    m_history_cursor = m_history.size();
     for (;;) {
     for (;;) {
         char keybuf[16];
         char keybuf[16];
         ssize_t nread = read(0, keybuf, sizeof(keybuf));
         ssize_t nread = read(0, keybuf, sizeof(keybuf));
@@ -37,17 +53,64 @@ String LineEditor::get_line()
                 m_buffer.clear();
                 m_buffer.clear();
                 putchar('\n');
                 putchar('\n');
                 return String::empty();
                 return String::empty();
-            } else {
-                perror("read failed");
-                // FIXME: exit()ing here is a bit off. Should communicate failure to caller somehow instead.
-                exit(2);
             }
             }
+            perror("read failed");
+            // FIXME: exit()ing here is a bit off. Should communicate failure to caller somehow instead.
+            exit(2);
         }
         }
 
 
         for (ssize_t i = 0; i < nread; ++i) {
         for (ssize_t i = 0; i < nread; ++i) {
             char ch = keybuf[i];
             char ch = keybuf[i];
             if (ch == 0)
             if (ch == 0)
                 continue;
                 continue;
+
+            switch (m_state) {
+            case InputState::ExpectBracket:
+                if (ch == '[') {
+                    m_state = InputState::ExpectFinal;
+                    continue;
+                } else {
+                    m_state = InputState::Free;
+                    break;
+                }
+            case InputState::ExpectFinal:
+                switch (ch) {
+                case 'A': // up
+                    if (m_history_cursor > 0)
+                        --m_history_cursor;
+                    clear_line();
+                    if (m_history_cursor < m_history.size())
+                        append(m_history[m_history_cursor]);
+                    m_state = InputState::Free;
+                    continue;
+                case 'B': // down
+                    if (m_history_cursor < m_history.size())
+                        ++m_history_cursor;
+                    clear_line();
+                    if (m_history_cursor < m_history.size())
+                        append(m_history[m_history_cursor]);
+                    m_state = InputState::Free;
+                    continue;
+                case 'D': // left
+                    m_state = InputState::Free;
+                    continue;
+                case 'C': // right
+                    m_state = InputState::Free;
+                    continue;
+                default:
+                    dbgprintf("Shell: Unhandled final: %b (%c)\n", ch, ch);
+                    m_state = InputState::Free;
+                    continue;
+                }
+                break;
+            case InputState::Free:
+                if (ch == 27) {
+                    m_state = InputState::ExpectBracket;
+                    continue;
+                }
+                break;
+            }
+
             if (ch == 8 || ch == g.termios.c_cc[VERASE]) {
             if (ch == 8 || ch == g.termios.c_cc[VERASE]) {
                 if (m_buffer.is_empty())
                 if (m_buffer.is_empty())
                     continue;
                     continue;

+ 11 - 0
Shell/LineEditor.h

@@ -14,10 +14,21 @@ public:
     const Vector<String>& history() const { return m_history; }
     const Vector<String>& history() const { return m_history; }
 
 
 private:
 private:
+    void clear_line();
+    void append(const String&);
+
     Vector<char, 1024> m_buffer;
     Vector<char, 1024> m_buffer;
     int m_cursor { 0 };
     int m_cursor { 0 };
 
 
     // FIXME: This should be something more take_first()-friendly.
     // FIXME: This should be something more take_first()-friendly.
     Vector<String> m_history;
     Vector<String> m_history;
+    int m_history_cursor { 0 };
     int m_history_capacity { 100 };
     int m_history_capacity { 100 };
+
+    enum class InputState {
+        Free,
+        ExpectBracket,
+        ExpectFinal,
+    };
+    InputState m_state { InputState::Free };
 };
 };