diff options
Diffstat (limited to 'ttwhy/scanners/ansi.cppm')
| -rw-r--r-- | ttwhy/scanners/ansi.cppm | 261 |
1 files changed, 0 insertions, 261 deletions
diff --git a/ttwhy/scanners/ansi.cppm b/ttwhy/scanners/ansi.cppm deleted file mode 100644 index 886e699..0000000 --- a/ttwhy/scanners/ansi.cppm +++ /dev/null @@ -1,261 +0,0 @@ -module; - -#include <algorithm> -#include <boost/sml.hpp> - -#include <span> -#include <string> - -export module ttwhy.scanners:ansi; - -import :events; - -namespace ttwhy::scanners::detail -{ - - /// Events - - struct byte_received - { - char value; - }; - - struct timeout_expired - { - }; - - /// States - - 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>; - - /// Guards - - constexpr auto is_backspace = [](byte_received e) { - return e.value == '\x08' || e.value == '\x7f'; - }; - - 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'; - }; - - constexpr auto is_printable = [](byte_received e) { - return e.value >= 0x20 && e.value <= 0x7e; - }; - - constexpr auto is_csi_introducer = [](byte_received e) { - return e.value == '['; - }; - - constexpr auto is_ss3_introducer = [](byte_received e) { - return e.value == 'O'; - }; - - 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; - }; - - constexpr auto is_csi_terminator = [](byte_received e) { - return e.value >= 0x40 && e.value <= 0x7e; - }; - - /// Transitions - - template<typename SinkType> - struct transition_table - { - auto operator()() const noexcept - { - using namespace boost::sml; - - constexpr auto push_character = [](byte_received const & event, SinkType & sink) { - sink(character_event{event.value}); - }; - - constexpr auto push_backspace = [](SinkType & sink) { - sink(control_event{control_key::backspace}); - }; - - constexpr auto push_tab = [](SinkType & sink) { - sink(control_event(control_key::tab)); - }; - - constexpr auto push_enter = [](SinkType & sink) { - sink(control_event(control_key::enter)); - }; - - constexpr auto emit_timeout_escape = [](SinkType & sink, std::string & buffer) { - sink(control_event{control_key::escape}); - buffer.clear(); - }; - - constexpr auto fallback_escape = [](byte_received const & event, SinkType & sink) { - sink(control_event{control_key::escape}); - if (event.value >= 0x20 && event.value <= 0x7e) - { - sink(character_event{event.value}); - } - }; - - 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, SinkType & sink) { - if (event.value == '~') - { - switch (buffer.at(0)) - { - case '1': - case '7': - sink(navigation_event{navigation_key::home}); - break; - case '2': - sink(navigation_event{navigation_key::insert_key}); - break; - case '3': - sink(navigation_event{navigation_key::delete_key}); - break; - case '4': - case '8': - sink(navigation_event{navigation_key::end}); - break; - case '5': - sink(navigation_event{navigation_key::page_up}); - break; - case '6': - sink(navigation_event{navigation_key::page_down}); - break; - default: - } - } - else - { - switch (event.value) - { - case 'A': - sink(navigation_event{navigation_key::up}); - break; - case 'B': - sink(navigation_event{navigation_key::down}); - break; - case 'C': - sink(navigation_event{navigation_key::right}); - break; - case 'D': - sink(navigation_event{navigation_key::left}); - break; - case 'H': - sink(navigation_event{navigation_key::home}); - break; - case 'F': - sink(navigation_event{navigation_key::end}); - break; - default: - } - } - buffer.clear(); - }; - - constexpr auto resolve_ss3 = [](byte_received const & event, SinkType & sink) { - switch (event.value) - { - case 'A': - sink(navigation_event{navigation_key::up}); - break; - case 'B': - sink(navigation_event{navigation_key::down}); - break; - case 'C': - sink(navigation_event{navigation_key::right}); - break; - case 'D': - sink(navigation_event{navigation_key::left}); - break; - case 'H': - sink(navigation_event{navigation_key::home}); - break; - case 'F': - sink(navigation_event{navigation_key::end}); - break; - default: - } - }; - - // 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_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 - } - }; - -} // namespace ttwhy::scanners::detail - -export namespace ttwhy::scanners -{ - - template<typename SinkType> - struct ansi - { - explicit ansi(SinkType & sink) - : m_state_machine{sink, m_csi_buffer} - {} - - auto process(std::span<char const> buffer) -> void - { - 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<SinkType>> m_state_machine; - }; - -} // namespace ttwhy::scanners |
