Forráskód Böngészése

LibLine: Parse CSI parameters and immediates

No behavior change, but it makes it easy to handle
page up and page down if we wanted to make them do something
in libline.
Nico Weber 4 éve
szülő
commit
2fe127d96f
2 módosított fájl, 52 hozzáadás és 22 törlés
  1. 49 20
      Libraries/LibLine/Editor.cpp
  2. 3 2
      Libraries/LibLine/Editor.h

+ 49 - 20
Libraries/LibLine/Editor.cpp

@@ -631,6 +631,11 @@ void Editor::handle_read_event()
     Utf8View input_view { StringView { m_incomplete_data.data(), valid_bytes } };
     Utf8View input_view { StringView { m_incomplete_data.data(), valid_bytes } };
     size_t consumed_code_points = 0;
     size_t consumed_code_points = 0;
 
 
+    Vector<u8, 4> csi_parameter_bytes;
+    Vector<unsigned, 4> csi_parameters;
+    Vector<u8> csi_intermediate_bytes;
+    u8 csi_final;
+
     for (auto code_point : input_view) {
     for (auto code_point : input_view) {
         if (m_finish)
         if (m_finish)
             break;
             break;
@@ -644,7 +649,7 @@ void Editor::handle_read_event()
         case InputState::GotEscape:
         case InputState::GotEscape:
             switch (code_point) {
             switch (code_point) {
             case '[':
             case '[':
-                m_state = InputState::GotEscapeFollowedByLeftBracket;
+                m_state = InputState::CSIExpectParameter;
                 continue;
                 continue;
             default: {
             default: {
                 m_state = InputState::Free;
                 m_state = InputState::Free;
@@ -658,29 +663,55 @@ void Editor::handle_read_event()
                 continue;
                 continue;
             }
             }
             }
             }
-        case InputState::GotEscapeFollowedByLeftBracket:
-            if (code_point == 'O') {
+        case InputState::CSIExpectParameter:
+            if (code_point >= 0x30 && code_point <= 0x3f) { // '0123456789:;<=>?'
+                csi_parameter_bytes.append(code_point);
+                continue;
+            }
+            m_state = InputState::CSIExpectIntermediate;
+            [[fallthrough]];
+        case InputState::CSIExpectIntermediate:
+            if (code_point >= 0x20 && code_point <= 0x2f) { // ' !"#$%&\'()*+,-./'
+                csi_intermediate_bytes.append(code_point);
+                continue;
+            }
+            m_state = InputState::CSIExpectFinal;
+            [[fallthrough]];
+        case InputState::CSIExpectFinal:
+            m_state = InputState::Free;
+            if (!(code_point >= 0x40 && code_point <= 0x7f)) {
+                dbgprintf("LibLine: Invalid CSI: %02x (%c)\r\n", code_point, code_point);
+                ctrl_held = false;
+                continue;
+            }
+            csi_final = code_point;
+
+            for (auto& parameter : String::copy(csi_parameter_bytes).split(';')) {
+                if (auto value = parameter.to_uint(); value.has_value())
+                    csi_parameters.append(value.value());
+                else
+                    csi_parameters.append(0);
+            }
+
+            if (csi_final == 'O') {
                 // mod_ctrl
                 // mod_ctrl
                 ctrl_held = true;
                 ctrl_held = true;
                 continue;
                 continue;
             }
             }
-            if (code_point == 'Z') {
+            if (csi_final == 'Z') {
                 // 'reverse tab'
                 // 'reverse tab'
                 reverse_tab = true;
                 reverse_tab = true;
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 break;
                 break;
             }
             }
             cleanup_suggestions();
             cleanup_suggestions();
-            switch (code_point) {
+            switch (csi_final) {
             case 'A': // ^[[A: arrow up
             case 'A': // ^[[A: arrow up
                 search_backwards();
                 search_backwards();
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             case 'B': // ^[[B: arrow down
             case 'B': // ^[[B: arrow down
                 search_forwards();
                 search_forwards();
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             case 'D': // ^[[D: arrow left
             case 'D': // ^[[D: arrow left
@@ -688,7 +719,6 @@ void Editor::handle_read_event()
                     cursor_left_word();
                     cursor_left_word();
                 else
                 else
                     cursor_left_character();
                     cursor_left_character();
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             case 'C': // ^[[C: arrow right
             case 'C': // ^[[C: arrow right
@@ -696,35 +726,34 @@ void Editor::handle_read_event()
                     cursor_right_word();
                     cursor_right_word();
                 else
                 else
                     cursor_right_character();
                     cursor_right_character();
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             case 'H': // ^[[H: home
             case 'H': // ^[[H: home
                 go_home();
                 go_home();
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             case 'F': // ^[[F: end
             case 'F': // ^[[F: end
                 go_end();
                 go_end();
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
-            case '3': // ^[[3~: delete
-                erase_character_forwards();
-                m_search_offset = 0;
-                m_state = InputState::ExpectTerminator;
+            case '~':
+                if (csi_parameters.size() == 1 && csi_parameters[0] == 3) { // ^[[3~: delete
+                    erase_character_forwards();
+                    m_search_offset = 0;
+                    ctrl_held = false;
+                    continue;
+                }
+                // ^[[5~: page up
+                // ^[[6~: page down
+                dbgprintf("LibLine: Unhandled '~'\r\n");
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             default:
             default:
                 dbgprintf("LibLine: Unhandled final: %02x (%c)\r\n", code_point, code_point);
                 dbgprintf("LibLine: Unhandled final: %02x (%c)\r\n", code_point, code_point);
-                m_state = InputState::Free;
                 ctrl_held = false;
                 ctrl_held = false;
                 continue;
                 continue;
             }
             }
             break;
             break;
-        case InputState::ExpectTerminator:
-            m_state = InputState::Free;
-            continue;
         case InputState::Free:
         case InputState::Free:
             if (code_point == 27) {
             if (code_point == 27) {
                 m_state = InputState::GotEscape;
                 m_state = InputState::GotEscape;

+ 3 - 2
Libraries/LibLine/Editor.h

@@ -471,8 +471,9 @@ private:
     enum class InputState {
     enum class InputState {
         Free,
         Free,
         GotEscape,
         GotEscape,
-        GotEscapeFollowedByLeftBracket,
-        ExpectTerminator,
+        CSIExpectParameter,
+        CSIExpectIntermediate,
+        CSIExpectFinal,
     };
     };
     InputState m_state { InputState::Free };
     InputState m_state { InputState::Free };