1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:35:07 +00:00

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.
This commit is contained in:
Nico Weber 2020-09-13 20:33:04 -04:00 committed by Andreas Kling
parent 365fa05a82
commit 2fe127d96f
2 changed files with 52 additions and 22 deletions

View file

@ -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: case InputState::CSIExpectParameter:
if (code_point == 'O') { 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 case '~':
erase_character_forwards(); if (csi_parameters.size() == 1 && csi_parameters[0] == 3) { // ^[[3~: delete
m_search_offset = 0; erase_character_forwards();
m_state = InputState::ExpectTerminator; 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;

View file

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