diff options
Diffstat (limited to 'ttwhy/scanner.cppm')
| -rw-r--r-- | ttwhy/scanner.cppm | 195 |
1 files changed, 165 insertions, 30 deletions
diff --git a/ttwhy/scanner.cppm b/ttwhy/scanner.cppm index 86a8493..2257f5f 100644 --- a/ttwhy/scanner.cppm +++ b/ttwhy/scanner.cppm @@ -3,8 +3,8 @@ module; #include <algorithm> #include <boost/sml.hpp> -#include <cctype> #include <span> +#include <string> #include <vector> export module ttwhy:scanner; @@ -21,27 +21,41 @@ namespace ttwhy::detail char value; }; + struct timeout_expired + { + }; + /// States - auto const idle = boost::sml::state<class idle>; - auto const escape_sequence = boost::sml::state<class escape_sequence>; - auto const csi_sequence = boost::sml::state<class csi_sequence>; + constexpr auto idle = boost::sml::state<class idle>; + constexpr auto escape_sequence = boost::sml::state<class escape_sequence>; + constexpr auto csi_sequence = boost::sml::state<class csi_sequence>; + constexpr auto ss3_sequence = boost::sml::state<class ss3_sequence>; /// Actions - auto push_character = [](byte_received const & event, std::vector<input_event> & queue) { + constexpr auto push_character = [](byte_received const & event, std::vector<input_event> & queue) { queue.push_back(character_event{event.value}); }; - auto push_backspace = [](std::vector<input_event> & queue) { + constexpr auto push_backspace = [](std::vector<input_event> & queue) { queue.push_back(control_event{control_key::backspace}); }; - auto push_delete = [](std::vector<input_event> & queue) { - queue.push_back(navigation_event{navigation_key::delete_key}); + constexpr auto push_tab = [](std::vector<input_event> & queue) { + queue.push_back(control_event(control_key::tab)); + }; + + constexpr auto push_enter = [](std::vector<input_event> & queue) { + queue.push_back(control_event(control_key::enter)); }; - auto fallback_escape = [](byte_received const & event, std::vector<input_event> & queue) { + constexpr auto emit_timeout_escape = [](std::vector<input_event> & queue, std::string & buffer) { + queue.push_back(control_event{control_key::escape}); + buffer.clear(); + }; + + constexpr auto fallback_escape = [](byte_received const & event, std::vector<input_event> & queue) { queue.push_back(control_event{control_key::escape}); if (event.value >= 0x20 && event.value <= 0x7e) { @@ -49,34 +63,135 @@ namespace ttwhy::detail } }; + constexpr auto clear_csi = [](std::string & buffer) { + buffer.clear(); + }; + + constexpr auto push_csi_parameter = [](byte_received const & event, std::string & buffer) { + buffer.push_back(event.value); + }; + + constexpr auto resolve_csi = [](byte_received const & event, std::string & buffer, std::vector<input_event> & queue) { + if (event.value == '~') + { + switch (buffer.at(0)) + { + case '1': + case '7': + queue.push_back(navigation_event{navigation_key::home}); + break; + case '2': + queue.push_back(navigation_event{navigation_key::insert_key}); + break; + case '3': + queue.push_back(navigation_event{navigation_key::delete_key}); + break; + case '4': + case '8': + queue.push_back(navigation_event{navigation_key::end}); + break; + case '5': + queue.push_back(navigation_event{navigation_key::page_up}); + break; + case '6': + queue.push_back(navigation_event{navigation_key::page_down}); + break; + default: + } + } + else + { + switch (event.value) + { + case 'A': + queue.push_back(navigation_event{navigation_key::up}); + break; + case 'B': + queue.push_back(navigation_event{navigation_key::down}); + break; + case 'C': + queue.push_back(navigation_event{navigation_key::right}); + break; + case 'D': + queue.push_back(navigation_event{navigation_key::left}); + break; + case 'H': + queue.push_back(navigation_event{navigation_key::home}); + break; + case 'F': + queue.push_back(navigation_event{navigation_key::end}); + break; + default: + } + } + buffer.clear(); + }; + + constexpr auto resolve_ss3 = [](byte_received const & event, std::vector<input_event> & queue) { + switch (event.value) + { + case 'A': + queue.push_back(navigation_event{navigation_key::up}); + break; + case 'B': + queue.push_back(navigation_event{navigation_key::down}); + break; + case 'C': + queue.push_back(navigation_event{navigation_key::right}); + break; + case 'D': + queue.push_back(navigation_event{navigation_key::left}); + break; + case 'H': + queue.push_back(navigation_event{navigation_key::home}); + break; + case 'F': + queue.push_back(navigation_event{navigation_key::end}); + break; + default: + } + }; + /// Guards - auto is_backspace = [](byte_received e) { + constexpr auto is_backspace = [](byte_received e) { return e.value == '\x08' || e.value == '\x7f'; }; - auto is_escape = [](byte_received e) { + constexpr auto is_tab = [](byte_received e) { + return e.value == '\x09'; + }; + + constexpr auto is_enter = [](byte_received e) { + return e.value == '\x0a' || e.value == '\x0d'; + }; + + constexpr auto is_escape = [](byte_received e) { return e.value == '\x1b'; }; - auto is_printable = [](byte_received e) { + constexpr auto is_printable = [](byte_received e) { return e.value >= 0x20 && e.value <= 0x7e; }; - auto is_csi_introducer = [](byte_received e) { + constexpr auto is_csi_introducer = [](byte_received e) { return e.value == '['; }; - auto is_csi_param = [](byte_received e) { - return e.value >= 0x20 && e.value <= 0x3f; + constexpr auto is_ss3_introducer = [](byte_received e) { + return e.value == 'O'; }; - auto is_csi_terminator = [](byte_received e) { - return e.value >= 0x40 && e.value <= 0x7e; + constexpr auto is_invalid_introducer = [](byte_received e) { + return !(is_ss3_introducer(e) || is_csi_introducer(e)); + }; + + constexpr auto is_csi_param = [](byte_received e) { + return e.value >= 0x20 && e.value <= 0x3f; }; - auto is_tilde = [](byte_received e) { - return e.value == '~'; + constexpr auto is_csi_terminator = [](byte_received e) { + return e.value >= 0x40 && e.value <= 0x7e; }; /// Transitions @@ -89,16 +204,23 @@ namespace ttwhy::detail // clang-format off return make_transition_table( - *idle + event<byte_received>[is_escape] = escape_sequence, - idle + event<byte_received>[is_backspace] / push_backspace = idle, - idle + event<byte_received>[is_printable] / push_character = idle, - - escape_sequence + event<byte_received>[is_csi_introducer] = csi_sequence, - escape_sequence + event<byte_received>[!is_csi_introducer] / fallback_escape = idle, - - csi_sequence + event<byte_received>[is_csi_param] = csi_sequence, - csi_sequence + event<byte_received>[is_tilde] / push_delete = idle, - csi_sequence + event<byte_received>[is_csi_terminator] = idle + *idle + event<byte_received>[is_escape] = escape_sequence, + idle + event<byte_received>[is_backspace] / push_backspace = idle, + idle + event<byte_received>[is_tab] / push_tab = idle, + idle + event<byte_received>[is_enter] / push_enter = idle, + idle + event<byte_received>[is_printable] / push_character = idle, + + escape_sequence + event<byte_received>[is_csi_introducer] / clear_csi = csi_sequence, + escape_sequence + event<byte_received>[is_ss3_introducer] = ss3_sequence, + escape_sequence + event<byte_received>[is_invalid_introducer] / fallback_escape = idle, + escape_sequence + event<timeout_expired> / emit_timeout_escape = idle, + + csi_sequence + event<byte_received>[is_csi_param] / push_csi_parameter = csi_sequence, + csi_sequence + event<byte_received>[is_csi_terminator] / resolve_csi = idle, + csi_sequence + event<timeout_expired> / emit_timeout_escape = idle, + + ss3_sequence + event<byte_received> / resolve_ss3 = idle, + ss3_sequence + event<timeout_expired> / emit_timeout_escape = idle ); // clang-format on } @@ -112,7 +234,7 @@ export namespace ttwhy struct ansi_scanner { explicit ansi_scanner(std::vector<input_event> & queue) - : m_state_machine{queue} + : m_state_machine{queue, m_csi_buffer} {} auto process(std::span<char const> buffer) -> void @@ -120,7 +242,20 @@ export namespace ttwhy std::ranges::for_each(buffer, [&](auto byte) { m_state_machine.process_event(detail::byte_received{byte}); }); } + auto timeout() + { + m_state_machine.process_event(detail::timeout_expired{}); + } + + [[nodiscard]] auto is_pending() const -> bool + { + return m_state_machine.is(detail::escape_sequence) || // + m_state_machine.is(detail::csi_sequence) || // + m_state_machine.is(detail::ss3_sequence); + } + private: + std::string m_csi_buffer{}; boost::sml::sm<detail::transition_table> m_state_machine; }; |
