diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-06-19 19:47:03 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-06-19 19:47:40 +0200 |
| commit | 90fa52db708c42d9707581156b957da99987bd1c (patch) | |
| tree | 5afd9b4daf9254cd969b9d3f8082af46bedb19a5 | |
| parent | 7da39cd68d2bed2f49452ac5f9a3c01c52d0c5ba (diff) | |
| download | ttwhy-90fa52db708c42d9707581156b957da99987bd1c.tar.xz ttwhy-90fa52db708c42d9707581156b957da99987bd1c.zip | |
lib/scanners: inject scanner sink
| -rw-r--r-- | ttwhy/io.cppm | 10 | ||||
| -rw-r--r-- | ttwhy/scanners/ansi.cppm | 247 |
2 files changed, 130 insertions, 127 deletions
diff --git a/ttwhy/io.cppm b/ttwhy/io.cppm index 5fd5e50..4b83996 100644 --- a/ttwhy/io.cppm +++ b/ttwhy/io.cppm @@ -3,7 +3,7 @@ module; #include <asio.hpp> #include <asio/experimental/awaitable_operators.hpp> -#include <chrono> +#include <chrono> // IWYU pragma: keep #include <format> #include <span> #include <vector> @@ -71,7 +71,11 @@ namespace ttwhy::io auto queue = std::vector<scanners::input_event>{}; queue.reserve(16); - auto scanner = scanners::ansi{queue}; + auto sink = [&queue](auto const & event) { + queue.push_back(event); + }; + auto scanner = scanners::ansi{sink}; + auto raw_buffer = std::array<char, 64>{}; while (true) @@ -81,7 +85,7 @@ namespace ttwhy::io if (scanner.is_pending()) { - timer.expires_after(500ms); + timer.expires_after(50ms); auto result = co_await (stream.async_read_some(asio::buffer(raw_buffer), asio::as_tuple(asio::use_awaitable)) || timer.async_wait(asio::as_tuple(asio::use_awaitable))); diff --git a/ttwhy/scanners/ansi.cppm b/ttwhy/scanners/ansi.cppm index b248753..886e699 100644 --- a/ttwhy/scanners/ansi.cppm +++ b/ttwhy/scanners/ansi.cppm @@ -5,7 +5,6 @@ module; #include <span> #include <string> -#include <vector> export module ttwhy.scanners:ansi; @@ -32,126 +31,6 @@ namespace ttwhy::scanners::detail constexpr auto csi_sequence = boost::sml::state<class csi_sequence>; constexpr auto ss3_sequence = boost::sml::state<class ss3_sequence>; - /// Actions - - constexpr auto push_character = [](byte_received const & event, std::vector<input_event> & queue) { - queue.push_back(character_event{event.value}); - }; - - constexpr auto push_backspace = [](std::vector<input_event> & queue) { - queue.push_back(control_event{control_key::backspace}); - }; - - 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)); - }; - - 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) - { - queue.push_back(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, 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 constexpr auto is_backspace = [](byte_received e) { @@ -196,12 +75,131 @@ namespace ttwhy::scanners::detail /// 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, @@ -231,10 +229,11 @@ namespace ttwhy::scanners::detail export namespace ttwhy::scanners { + template<typename SinkType> struct ansi { - explicit ansi(std::vector<input_event> & queue) - : m_state_machine{queue, m_csi_buffer} + explicit ansi(SinkType & sink) + : m_state_machine{sink, m_csi_buffer} {} auto process(std::span<char const> buffer) -> void @@ -256,7 +255,7 @@ export namespace ttwhy::scanners private: std::string m_csi_buffer{}; - boost::sml::sm<detail::transition_table> m_state_machine; + boost::sml::sm<detail::transition_table<SinkType>> m_state_machine; }; } // namespace ttwhy::scanners |
