module Tput::Probe

Overview

Runtime terminal probing.

Unlike Features/Emulator, which infer capabilities statically from ENV and terminfo, this module discovers them by writing a batch of query escape sequences to the terminal and reading the replies back (the same technique used by Microsoft's edit):

Results are stored on Tput#features (Features#default_foreground, #default_background, #palette, #ambiguous_width, #da_params).

Included Modules

Direct including types

Defined in:

tput/probe.cr

Constant Summary

Log = ::Log.for((self.name.gsub("::", '.')).underscore)

Instance Method Summary

Instance Method Detail

def build_probe_cleanup : String #

Builds the post-probe cleanup string, run after all replies are consumed.

The width probe printed at column 1 (#build_probe_query does \r…), so the leftover sits left of wherever the cursor was when probing started. A bare \e8\e[J erases only from the saved column rightward, leaving the (and any echoed fragments) on screen when probing didn't begin at column 1.

So: \e8 restores to the DECSC-saved cursor line (even if echoed output wrapped it downward); \r parks at column 1 of that line; \e[J erases to the end of the display, wiping the and any echoed fragments (including ones wrapped onto following lines); a final \e8 restores the exact pre-probe cursor position.


[View source]
def build_probe_query : String #

Builds the single batched query string. DECSC (\e7) saves the cursor up front so #probe! can restore it exactly and erase anything a non-conforming terminal echoed back. For the width probe, \r parks the cursor at column 1 so the CPR column maps directly to rendered width. DA1 goes last so its reply terminates the read.


[View source]
def probe!(timeout : Time::Span = 3.seconds) : Bool #

Probes the terminal for its features by round-tripping query sequences.

Returns true if at least the DA1 terminator came back (i.e. the terminal participated), false if probing was skipped or timed out with no response. timeout bounds the wait for each individual reply; a responsive terminal returns almost immediately thanks to the DA1 sentinel.


[View source]
def probe_capable? : Bool #

Whether probing is possible (both ends must be a real terminal).


[View source]
def probe_consume(io : IO, timeout : Time::Span) : ProbeResult #

Reads and parses the terminal's replies from io until DA1 arrives or a read times out. OSC color replies are applied to features as they come in; the ambiguous-width measurement and DA1 presence are returned.

Decoupled from @input so it can be exercised against an IO::Memory holding canned responses, without a real terminal.


[View source]