summaryrefslogtreecommitdiff
path: root/Libraries/LibLine
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2020-09-13 20:33:04 -0400
committerAndreas Kling <kling@serenityos.org>2020-09-15 09:45:13 +0200
commit2fe127d96ff9991d13d73e4c26c85cb44efeac99 (patch)
treeb89375eae56ad18525a098e0f94aee4f779f7930 /Libraries/LibLine
parent365fa05a8256d1ba44cff5d05c44dda5021571e9 (diff)
downloadserenity-2fe127d96ff9991d13d73e4c26c85cb44efeac99.zip
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.
Diffstat (limited to 'Libraries/LibLine')
-rw-r--r--Libraries/LibLine/Editor.cpp69
-rw-r--r--Libraries/LibLine/Editor.h5
2 files changed, 52 insertions, 22 deletions
diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp
index 08bef585fa..9a2e271224 100644
--- a/Libraries/LibLine/Editor.cpp
+++ b/Libraries/LibLine/Editor.cpp
@@ -631,6 +631,11 @@ void Editor::handle_read_event()
Utf8View input_view { StringView { m_incomplete_data.data(), valid_bytes } };
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) {
if (m_finish)
break;
@@ -644,7 +649,7 @@ void Editor::handle_read_event()
case InputState::GotEscape:
switch (code_point) {
case '[':
- m_state = InputState::GotEscapeFollowedByLeftBracket;
+ m_state = InputState::CSIExpectParameter;
continue;
default: {
m_state = InputState::Free;
@@ -658,29 +663,55 @@ void Editor::handle_read_event()
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
ctrl_held = true;
continue;
}
- if (code_point == 'Z') {
+ if (csi_final == 'Z') {
// 'reverse tab'
reverse_tab = true;
- m_state = InputState::Free;
ctrl_held = false;
break;
}
cleanup_suggestions();
- switch (code_point) {
+ switch (csi_final) {
case 'A': // ^[[A: arrow up
search_backwards();
- m_state = InputState::Free;
ctrl_held = false;
continue;
case 'B': // ^[[B: arrow down
search_forwards();
- m_state = InputState::Free;
ctrl_held = false;
continue;
case 'D': // ^[[D: arrow left
@@ -688,7 +719,6 @@ void Editor::handle_read_event()
cursor_left_word();
else
cursor_left_character();
- m_state = InputState::Free;
ctrl_held = false;
continue;
case 'C': // ^[[C: arrow right
@@ -696,35 +726,34 @@ void Editor::handle_read_event()
cursor_right_word();
else
cursor_right_character();
- m_state = InputState::Free;
ctrl_held = false;
continue;
case 'H': // ^[[H: home
go_home();
- m_state = InputState::Free;
ctrl_held = false;
continue;
case 'F': // ^[[F: end
go_end();
- m_state = InputState::Free;
ctrl_held = false;
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;
continue;
default:
dbgprintf("LibLine: Unhandled final: %02x (%c)\r\n", code_point, code_point);
- m_state = InputState::Free;
ctrl_held = false;
continue;
}
break;
- case InputState::ExpectTerminator:
- m_state = InputState::Free;
- continue;
case InputState::Free:
if (code_point == 27) {
m_state = InputState::GotEscape;
diff --git a/Libraries/LibLine/Editor.h b/Libraries/LibLine/Editor.h
index bf026b62b7..fe32d5bfba 100644
--- a/Libraries/LibLine/Editor.h
+++ b/Libraries/LibLine/Editor.h
@@ -471,8 +471,9 @@ private:
enum class InputState {
Free,
GotEscape,
- GotEscapeFollowedByLeftBracket,
- ExpectTerminator,
+ CSIExpectParameter,
+ CSIExpectIntermediate,
+ CSIExpectFinal,
};
InputState m_state { InputState::Free };