diff options
Diffstat (limited to 'ttwhy/scanners/terminal_scanner.cppm')
| -rw-r--r-- | ttwhy/scanners/terminal_scanner.cppm | 236 |
1 files changed, 0 insertions, 236 deletions
diff --git a/ttwhy/scanners/terminal_scanner.cppm b/ttwhy/scanners/terminal_scanner.cppm deleted file mode 100644 index a791909..0000000 --- a/ttwhy/scanners/terminal_scanner.cppm +++ /dev/null @@ -1,236 +0,0 @@ -module; - -#include <algorithm> -#include <boost/sml.hpp> - -#include <queue> -#include <span> -#include <string> - -export module ttwhy.scanners:terminal_scanner; - -import :concepts; -import :terminal_events; -import :terminal_policies; - -namespace ttwhy::scanners::detail -{ - - /// Events - - struct byte_received - { - char value; - }; - - struct c1_received - { - unsigned 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 >= ' ' && e.value <= '~'; - }; - - constexpr auto is_c0_chord = [](byte_received e) { - return e.value >= '\0' && e.value <= '\x1f' && !is_backspace(e) && !is_tab(e) && !is_enter(e) && !is_escape(e); - }; - - constexpr auto is_fe = [](byte_received e) { - return e.value >= '@' && e.value <= '_'; - }; - - constexpr auto is_csi = [](c1_received e) { - return e.value == u'\x9b'; - }; - - constexpr auto is_ss3 = [](c1_received e) { - return e.value == u'\x8f'; - }; - - constexpr auto is_unhandled_c1 = [](c1_received e) { - return !(is_csi(e) || is_ss3(e)); - }; - - constexpr auto is_csi_param = [](byte_received e) { - return e.value >= ' ' && e.value <= '?'; - }; - - constexpr auto is_vt100_terminator = [](byte_received e) { - return e.value >= '@' && e.value <= '}'; - }; - - constexpr auto is_vt220_terminator = [](byte_received e) { - return e.value == '~'; - }; - - /// Transitions - - template<terminal_event_sink Sink, typename TerminalPolicy> - struct transition_table - { - auto operator()() const noexcept - { - using namespace boost::sml; - - constexpr auto push_character = [](byte_received event, Sink & sink) { - sink(character_event{event.value}); - }; - - constexpr auto push_backspace = [](Sink & sink) { - sink(control_event{control_key::backspace}); - }; - - constexpr auto push_tab = [](Sink & sink) { - sink(control_event(control_key::tab)); - }; - - constexpr auto push_enter = [](Sink & sink) { - sink(control_event(control_key::enter)); - }; - - constexpr auto push_c0_chord = [](byte_received event, Sink & sink) { - sink(ctrl_chord_event{static_cast<char>(event.value + 0x40)}); - }; - - constexpr auto dispatch_c1 = [](byte_received event, back::process<c1_received> process) { - process(c1_received{static_cast<unsigned char>(event.value + 0x40)}); - }; - - constexpr auto fallback_fe = [](c1_received event, Sink & sink) { - sink(control_event{control_key::escape}); - sink(character_event{static_cast<char>(event.value - 0x40)}); - }; - - constexpr auto emit_timeout_escape = [](Sink & sink, std::string & buffer) { - sink(control_event{control_key::escape}); - buffer.clear(); - }; - - constexpr auto fallback_escape = [](byte_received event, Sink & sink) { - sink(control_event{control_key::escape}); - if (event.value >= ' ' && event.value <= '~') - { - 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_vt100_cursor = [](byte_received event, std::string & buffer, Sink & sink) { - TerminalPolicy::resolve_vt100_cursor(event.value, buffer, sink); - buffer.clear(); - }; - - constexpr auto resolve_vt220_keypad = [](std::string & buffer, Sink & sink) { - TerminalPolicy::resolve_vt220_keypad(buffer, sink); - buffer.clear(); - }; - - constexpr auto resolve_ss3 = [](byte_received event, Sink & sink) { - TerminalPolicy::resolve_ss3(event.value, sink); - }; - - // 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_c0_chord] / push_c0_chord = idle, - idle + event<byte_received>[is_printable] / push_character = idle, - - escape_sequence + event<byte_received>[is_fe] / dispatch_c1 = idle, - escape_sequence + event<byte_received>[!is_fe] / fallback_escape = idle, - escape_sequence + event<timeout_expired> / emit_timeout_escape = idle, - - idle + event<c1_received>[is_csi] / clear_csi = csi_sequence, - idle + event<c1_received>[is_ss3] = ss3_sequence, - idle + event<c1_received>[is_unhandled_c1] / fallback_fe = idle, - - csi_sequence + event<byte_received>[is_csi_param] / push_csi_parameter = csi_sequence, - csi_sequence + event<byte_received>[is_vt220_terminator] / resolve_vt220_keypad = idle, - csi_sequence + event<byte_received>[is_vt100_terminator] / resolve_vt100_cursor = 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<terminal_event_sink Sink, typename TerminalPolicy> - struct terminal_scanner - { - explicit terminal_scanner(Sink & 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<Sink, TerminalPolicy>, boost::sml::process_queue<std::queue>> - m_state_machine; - }; - - template<terminal_event_sink Sink> - using ansi = terminal_scanner<Sink, ansi_policy>; - -} // namespace ttwhy::scanners |
