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:
parent
365fa05a82
commit
2fe127d96f
2 changed files with 52 additions and 22 deletions
|
@ -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;
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue