aboutsummaryrefslogtreecommitdiff
path: root/ttwhy/scanners/terminal_policies.cppm
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2026-06-20 11:54:06 +0200
committerFelix Morgner <felix.morgner@gmail.com>2026-06-20 11:54:06 +0200
commit912e7b10facdd3b2565423206ae25b1d6e4f7dd9 (patch)
treee744bc76893e8b1faa216b1aae93c7ec6e933a04 /ttwhy/scanners/terminal_policies.cppm
parent280190248bfbadaec4575932dc956401f7bb6390 (diff)
downloadttwhy-912e7b10facdd3b2565423206ae25b1d6e4f7dd9.tar.xz
ttwhy-912e7b10facdd3b2565423206ae25b1d6e4f7dd9.zip
lib: add xterm policy
Diffstat (limited to 'ttwhy/scanners/terminal_policies.cppm')
-rw-r--r--ttwhy/scanners/terminal_policies.cppm180
1 files changed, 136 insertions, 44 deletions
diff --git a/ttwhy/scanners/terminal_policies.cppm b/ttwhy/scanners/terminal_policies.cppm
index e5863d3..bf7c126 100644
--- a/ttwhy/scanners/terminal_policies.cppm
+++ b/ttwhy/scanners/terminal_policies.cppm
@@ -1,70 +1,162 @@
module;
+#include <optional>
#include <string>
export module ttwhy.scanners:terminal_policies;
-import :events;
-import :concepts;
+import :terminal_events;
+import :terminal_concepts;
namespace ttwhy::scanners
{
+ namespace detail
+ {
+ constexpr auto map_vt220_keypad(char terminator) -> std::optional<navigation_key>
+ {
+ switch (terminator)
+ {
+ case '1':
+ case '7':
+ return navigation_key::home;
+ case '2':
+ return navigation_key::insert_key;
+ case '3':
+ return navigation_key::delete_key;
+ case '4':
+ case '8':
+ return navigation_key::end;
+ case '5':
+ return navigation_key::page_up;
+ case '6':
+ return navigation_key::page_down;
+ default:
+ return std::nullopt;
+ }
+ }
+
+ constexpr auto map_vt100_cursor(char terminator) -> std::optional<navigation_key>
+ {
+ switch (terminator)
+ {
+ case 'A':
+ return navigation_key::up;
+ case 'B':
+ return navigation_key::down;
+ case 'C':
+ return navigation_key::right;
+ case 'D':
+ return navigation_key::left;
+ case 'H':
+ return navigation_key::home;
+ case 'F':
+ return navigation_key::end;
+ default:
+ return std::nullopt;
+ }
+ }
+
+ } // namespace detail
+
+ export template<typename T>
+ using associated_terminal_policy_t = typename T::terminal_policy;
+
export struct ansi_policy
{
constexpr auto static resolve_vt220_keypad(std::string & buffer, ttwhy::ansi_sink auto & sink) -> void
{
- auto key = [](auto terminator) {
- switch (terminator)
- {
- case '1':
- case '7':
- return navigation_key::home;
- case '2':
- return navigation_key::insert_key;
- case '3':
- return navigation_key::delete_key;
- case '4':
- case '8':
- return navigation_key::end;
- case '5':
- return navigation_key::page_up;
- case '6':
- return navigation_key::page_down;
- default:
- return static_cast<navigation_key>(-1);
- }
- }(buffer.back());
- sink(navigation_event{key});
+ if (buffer.empty())
+ {
+ return;
+ }
+
+ if (auto key = detail::map_vt220_keypad(buffer.front()))
+ {
+ sink(navigation_event{*key});
+ }
+ buffer.clear();
}
- constexpr auto static resolve_vt100_cursor(char terminator, ttwhy::ansi_sink auto & sink) -> void
+ constexpr auto static resolve_vt100_cursor(char terminator, std::string &, ttwhy::ansi_sink auto & sink) -> void
{
- auto key = [terminator] {
- switch (terminator)
+ if (auto key = detail::map_vt100_cursor(terminator))
+ {
+ sink(navigation_event{*key});
+ }
+ }
+
+ constexpr auto static resolve_ss3(char terminator, ttwhy::ansi_sink auto & sink) -> void
+ {
+ if (auto key = detail::map_vt100_cursor(terminator))
+ {
+ sink(navigation_event{*key});
+ }
+ }
+ };
+
+ export struct xterm_policy
+ {
+ constexpr auto static parse_modifiers(std::string_view buffer) -> modifier_set
+ {
+ auto delimiter = buffer.find(';');
+ if (delimiter == std::string_view::npos)
+ {
+ return {};
+ }
+
+ auto modifier_string = buffer.substr(delimiter + 1);
+ auto modifier_value = 0u;
+
+ for (auto character : modifier_string)
+ {
+ if (character >= '0' && character <= '9')
{
- case 'A':
- return navigation_key::up;
- case 'B':
- return navigation_key::down;
- case 'C':
- return navigation_key::right;
- case 'D':
- return navigation_key::left;
- case 'H':
- return navigation_key::home;
- case 'F':
- return navigation_key::end;
- default:
- return static_cast<navigation_key>(-1);
+ modifier_value = modifier_value * 10 + static_cast<unsigned int>(character - '0');
}
- }();
- sink(navigation_event{key});
+ }
+
+ if (modifier_value <= 1)
+ {
+ return {};
+ }
+
+ return static_cast<modifier_set>(modifier_value - 1);
+ }
+
+ constexpr auto static resolve_vt220_keypad(std::string & buffer, ttwhy::ansi_sink auto & sink) -> void
+ {
+ if (buffer.empty())
+ {
+ return;
+ }
+
+ auto modifiers = parse_modifiers(buffer);
+
+ if (auto key = detail::map_vt220_keypad(buffer.front()))
+ {
+ sink(navigation_event{*key, modifiers});
+ }
+ buffer.clear();
+ }
+
+ constexpr auto static resolve_vt100_cursor(char terminator, std::string & buffer, ttwhy::ansi_sink auto & sink)
+ -> void
+ {
+ auto modifiers = parse_modifiers(buffer);
+
+ if (auto key = detail::map_vt100_cursor(terminator))
+ {
+ sink(navigation_event{*key, modifiers});
+ }
}
constexpr auto static resolve_ss3(char terminator, ttwhy::ansi_sink auto & sink) -> void
{
- return resolve_vt100_cursor(terminator, sink);
+ if (auto key = detail::map_vt100_cursor(terminator))
+ {
+ sink(navigation_event{*key});
+ }
}
};