aboutsummaryrefslogtreecommitdiff
path: root/ttwhy/scanners/terminal_scanner.cppm
diff options
context:
space:
mode:
Diffstat (limited to 'ttwhy/scanners/terminal_scanner.cppm')
-rw-r--r--ttwhy/scanners/terminal_scanner.cppm236
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