Module: Przn::EchoesClient
- Defined in:
- lib/przn/echoes_client.rb
Overview
Thin wrappers around Echoes-specific OSC 7772 commands the presenter uses to set up extended-display mode. Other terminals ignore OSC 7772, so each method silently fails (returns nil / false) when not running inside Echoes.
Constant Summary collapse
- OSC =
"\e]7772"- BEL =
"\a"- REPLY_TIMEOUT_S =
0.5
Class Method Summary collapse
-
.display_info(io_in: $stdin, io_out: $stdout) ⇒ Object
Ask Echoes how many displays are attached and a tiny descriptor for each.
-
.open_window(display:, argv:, fullscreen: true, io_out: $stdout) ⇒ Object
Open a new Echoes window on the given display, running ‘argv` (an Array of strings — argv is the executable).
-
.read_osc_reply(io_in) ⇒ Object
Read an OSC reply up to ST or BEL.
- .read_osc_reply_inner(io_in) ⇒ Object
Class Method Details
.display_info(io_in: $stdin, io_out: $stdout) ⇒ Object
Ask Echoes how many displays are attached and a tiny descriptor for each. Returns an Array of Hashes like [0, w: 1920, h: 1080, …] or nil when no reply arrives within the timeout (non-Echoes terminal, or an Echoes that doesn’t speak this command yet).
22 23 24 25 26 27 28 29 30 |
# File 'lib/przn/echoes_client.rb', line 22 def display_info(io_in: $stdin, io_out: $stdout) io_out.write("#{OSC};display-info#{BEL}") io_out.flush if io_out.respond_to?(:flush) reply = read_osc_reply(io_in) return nil unless reply JSON.parse(reply, symbolize_names: true) rescue JSON::ParserError nil end |
.open_window(display:, argv:, fullscreen: true, io_out: $stdout) ⇒ Object
Open a new Echoes window on the given display, running ‘argv` (an Array of strings — argv is the executable). `fullscreen:` is a hint. Returns true if the request was emitted; nothing in the protocol confirms success synchronously.
36 37 38 39 40 41 42 43 44 45 |
# File 'lib/przn/echoes_client.rb', line 36 def open_window(display:, argv:, fullscreen: true, io_out: $stdout) # `pack('m0')` is strict (no-newline) base64 — same as # Base64.strict_encode64 but without pulling in the base64 stdlib, # which is no longer a default gem in Ruby 3.4+. payload = [JSON.generate(argv)].pack('m0') args = "display=#{display}:program=#{payload}:fullscreen=#{fullscreen ? 'yes' : 'no'}" io_out.write("#{OSC};open-window;#{args}#{BEL}") io_out.flush if io_out.respond_to?(:flush) true end |
.read_osc_reply(io_in) ⇒ Object
Read an OSC reply up to ST or BEL. Returns the payload string or nil on timeout. Echoes replies follow the same ‘e]7772;…a` shape it accepts.
Stdin defaults to canonical (line-buffered) mode in a shell context, so ‘getc` would block waiting for a newline that an OSC reply never sends. Put the input in raw mode for the duration of the read; IO#raw saves and restores termios automatically.
54 55 56 57 58 59 60 |
# File 'lib/przn/echoes_client.rb', line 54 def read_osc_reply(io_in) if io_in.respond_to?(:raw) && io_in.respond_to?(:tty?) && io_in.tty? io_in.raw { read_osc_reply_inner(io_in) } else read_osc_reply_inner(io_in) end end |
.read_osc_reply_inner(io_in) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/przn/echoes_client.rb', line 62 def read_osc_reply_inner(io_in) Timeout.timeout(REPLY_TIMEOUT_S) do buf = +"" loop do c = io_in.getc return nil if c.nil? break if c == BEL if c == "\e" nxt = io_in.getc break if nxt == "\\" buf << c << nxt else buf << c end end buf.sub(/\A\e?\]?7772;[\w-]+;/, '') end rescue Timeout::Error nil end |