From 80c537172cf50777bada29ae0062647993031307 Mon Sep 17 00:00:00 2001 From: TEC Date: Tue, 2 May 2023 00:34:14 +0800 Subject: [PATCH 1/4] Add method of checking tty for truecolor support This is part of the groundwork for styled printing of StyledStrings. --- base/client.jl | 1 + base/ttyhascolor.jl | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/base/client.jl b/base/client.jl index 4ae345b14f113..3153974e5a5c5 100644 --- a/base/client.jl +++ b/base/client.jl @@ -4,6 +4,7 @@ ## and REPL have_color = nothing +have_truecolor = nothing const default_color_warn = :yellow const default_color_error = :light_red const default_color_info = :cyan diff --git a/base/ttyhascolor.jl b/base/ttyhascolor.jl index 5984dba6d592e..2a14790da5f06 100644 --- a/base/ttyhascolor.jl +++ b/base/ttyhascolor.jl @@ -16,11 +16,64 @@ else end end end + +""" + ttyhastruecolor() + +Return a boolean signifying whether the current terminal supports 24-bit colors. + +This uses the `COLORTERM` environment variable if possible, returning true if it +is set to either `"truecolor"` or `"24bit"`. + +As a fallback, first on unix systems the `colors` terminal capability is checked +— should more than 256 colors be reported, this is taken to signify 24-bit +support. Lastly, the color is attempted to be set to `#010203` and then the +current color queried via the DCS (Device Control String) sequence `\$qm`. If +the output contains `":1:2:3"` this is taken to signify 24-bit support. + +If the fallbacks are used, the `"COLORTERM"` entry in `ENV` is updated according +to the result. This ensures that frequent calls will only potentially be slow +the first time. +""" +function ttyhastruecolor() + function test24bitcolor_dcs() + REPL.Terminals.raw!(REPL.TerminalMenus.terminal, true) + print(stdout, "\e[48;2;1;2;3m\eP\$qm\e\\\e[m") + flush(stdout) + # Some terminals are bad and haven't got DCS sequence support, + # if we don't see a response from stdin we need to abort. + output = @task readuntil(stdin, 'm') + schedule(output) + Timer(0.1) do _ + istaskdone(output) || Base.throwto(output, InterruptException()) + end + color = try + fetch(output) + catch _ "" end + REPL.Terminals.raw!(REPL.TerminalMenus.terminal, false) + occursin(":1:2:3", color) + end + get(ENV, "COLORTERM", "") ∈ ("truecolor", "24bit") || + @static if Sys.isunix() + get(current_terminfo, :colors, 0) > 256 || + isinteractive() && test24bitcolor_dcs() + else + false + end +end + function get_have_color() global have_color have_color === nothing && (have_color = ttyhascolor()) return have_color::Bool end + +function get_have_truecolor() + global have_truecolor + have_truecolor === nothing && (have_truecolor = ttyhastruecolor()) + return have_truecolor::Bool +end + in(key_value::Pair{Symbol,Bool}, ::TTY) = key_value.first === :color && key_value.second === get_have_color() haskey(::TTY, key::Symbol) = key === :color getindex(::TTY, key::Symbol) = key === :color ? get_have_color() : throw(KeyError(key)) From 8c1ba252395559efbd35c86f1462d90c04265410 Mon Sep 17 00:00:00 2001 From: TEC Date: Tue, 2 May 2023 00:37:26 +0800 Subject: [PATCH 2/4] Replace tput calls with a terminfo parser Implement a terminfo parser, and use it to replace the tput calls. While tput calls are fairly safe, given tput it part of the UNIX specification, it's nice to remove a system dependency and call one less executable. More crucially, switching to parsing terminfo ourselves makes it much more convenient to check terminfo capabilities. A try-catch wrapped success(`tput termcap`) call can now be replaced with a simple haskey(current_terminfo, :termcap) or get(current_terminfo, :termcap, false) as appropriate. This is part of the groundwork for styled printing of StyledStrings. --- NEWS.md | 1 + base/Base.jl | 2 +- base/client.jl | 1 + base/terminfo.jl | 327 +++++++++++++++++++++++++ base/terminfo_data.jl | 540 ++++++++++++++++++++++++++++++++++++++++++ base/ttyhascolor.jl | 80 ------- 6 files changed, 870 insertions(+), 81 deletions(-) create mode 100644 base/terminfo.jl create mode 100644 base/terminfo_data.jl delete mode 100644 base/ttyhascolor.jl diff --git a/NEWS.md b/NEWS.md index 51e760b07772c..16afb8c168443 100644 --- a/NEWS.md +++ b/NEWS.md @@ -74,6 +74,7 @@ Deprecated or removed External dependencies --------------------- +* `tput` is no longer called to check terminal capabilities, it has been replaced with a pure-Julia terminfo parser. Tooling Improvements -------------------- diff --git a/base/Base.jl b/base/Base.jl index ecc0f0e5522ed..578e829e53c74 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -358,7 +358,7 @@ include("filesystem.jl") using .Filesystem include("cmd.jl") include("process.jl") -include("ttyhascolor.jl") +include("terminfo.jl") include("secretbuffer.jl") # core math functions diff --git a/base/client.jl b/base/client.jl index 3153974e5a5c5..47159b6a77fc4 100644 --- a/base/client.jl +++ b/base/client.jl @@ -416,6 +416,7 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_f if interactive && isassigned(REPL_MODULE_REF) invokelatest(REPL_MODULE_REF[]) do REPL term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb") + global current_terminfo = load_terminfo(term_env) term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr) banner == :no || Base.banner(term, short=banner==:short) if term.term_type == "dumb" diff --git a/base/terminfo.jl b/base/terminfo.jl new file mode 100644 index 0000000000000..fc2b392871a06 --- /dev/null +++ b/base/terminfo.jl @@ -0,0 +1,327 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +include("terminfo_data.jl") + +""" + struct TermInfoRaw + +A structured representation of a terminfo file, without any knowledge of +particular capabilities, solely based on `term(5)`. + +!!! warning + This is not part of the public API, and thus subject to change without notice. + +# Fields + +- `names::Vector{String}`: The names this terminal is known by. +- `flags::BitVector`: A list of 0–$(length(TERM_FLAGS)) flag values. +- `numbers::Union{Vector{UInt16}, Vector{UInt32}}`: A list of 0–$(length(TERM_NUMBERS)) + number values. A value of `typemax(eltype(numbers))` is used to skip over + unspecified capabilities while ensuring value indices are correct. +- `strings::Vector{Union{String, Nothing}}`: A list of 0–$(length(TERM_STRINGS)) + string values. A value of `nothing` is used to skip over unspecified + capabilities while ensuring value indices are correct. +- `extended::Union{Nothing, Dict{Symbol, Union{Bool, Int, String}}}`: Should an + extended info section exist, this gives the entire extended info as a + dictionary. Otherwise `nothing`. + +See also: `TermInfo` and `TermCapability`. +""" +struct TermInfoRaw + names::Vector{String} + flags::BitVector + numbers::Union{Vector{UInt16}, Vector{UInt32}} + strings::Vector{Union{String, Nothing}} + extended::Union{Nothing, Dict{Symbol, Union{Bool, Int, String}}} +end + +""" + struct TermInfo + +A parsed terminfo paired with capability information. + +!!! warning + This is not part of the public API, and thus subject to change without notice. + +# Fields + +- `names::Vector{String}`: The names this terminal is known by. +- `flags::Int`: The number of flags specified. +- `numbers::BitVector`: A mask indicating which of `TERM_NUMBERS` have been + specified. +- `strings::BitVector`: A mask indicating which of `TERM_STRINGS` have been + specified. +- `extensions::Vector{Symbol}`: A list of extended capability variable names. +- `capabilities::Dict{Symbol, Union{Bool, Int, String}}`: The capability values + themselves. + +See also: `TermInfoRaw` and `TermCapability`. +""" +struct TermInfo + names::Vector{String} + flags::Int + numbers::BitVector + strings::BitVector + extensions::Vector{Symbol} + capabilities::Dict{Symbol, Union{Bool, Int, String}} +end + +TermInfo() = TermInfo([], 0, [], [], [], Dict()) + +function read(data::IO, ::Type{TermInfoRaw}) + # Parse according to `term(5)` + # Header + magic = read(data, UInt16) |> ltoh + NumInt = if magic == 0o0432 + UInt16 + elseif magic == 0o01036 + UInt32 + else + throw(ArgumentError("Terminfo data did not start with the magic number 0o0432 or 0o01036")) + end + name_bytes = read(data, UInt16) |> ltoh + flag_bytes = read(data, UInt16) |> ltoh + numbers_count = read(data, UInt16) |> ltoh + string_count = read(data, UInt16) |> ltoh + table_bytes = read(data, UInt16) |> ltoh + # Terminal Names + term_names = split(String(read(data, name_bytes - 1)), '|') .|> String + 0x00 == read(data, UInt8) || + throw(ArgumentError("Terminfo data did not contain a null byte after the terminal names section")) + # Boolean Flags + flags = read(data, flag_bytes) .== 0x01 + if position(data) % 2 != 0 + 0x00 == read(data, UInt8) || + throw(ArgumentError("Terminfo did not contain a null byte after the flag section, expected to position the start of the numbers section on an even byte")) + end + # Numbers, Strings, Table + numbers = reinterpret(NumInt, read(data, numbers_count * sizeof(NumInt))) .|> ltoh + string_indices = reinterpret(UInt16, read(data, string_count * sizeof(UInt16))) .|> ltoh + strings_table = read(data, table_bytes) + strings = map(string_indices) do idx + if idx ∉ (0xffff, 0xfffe) + len = findfirst(==(0x00), view(strings_table, 1+idx:length(strings_table))) + !isnothing(len) || + throw(ArgumentError("Terminfo string table entry does not terminate with a null byte")) + String(strings_table[1+idx:idx+len-1]) + end + end + TermInfoRaw(term_names, flags, numbers, strings, + if !eof(data) extendedterminfo(data; NumInt) end) +end + +""" + extendedterminfo(data::IO; NumInt::Union{Type{UInt16}, Type{UInt32}}) + +Read an extended terminfo section from `data`, with `NumInt` as the numbers type. + +This will accept any terminfo content that conforms with `term(5)`. + +See also: `read(::IO, ::Type{TermInfoRaw})` +""" +function extendedterminfo(data::IO; NumInt::Union{Type{UInt16}, Type{UInt32}}) + # Extended info + if position(data) % 2 != 0 + 0x00 == read(data, UInt8) || + throw(ArgumentError("Terminfo did not contain a null byte before the extended section, expected to position the start on an even byte")) + end + # Extended header + flag_bytes = read(data, UInt16) |> ltoh + numbers_count = read(data, UInt16) |> ltoh + string_count = read(data, UInt16) |> ltoh + table_count = read(data, UInt16) |> ltoh + table_bytes = read(data, UInt16) |> ltoh + # Extended flags/numbers/strings + flags = read(data, flag_bytes) .== 0x01 + if flag_bytes % 2 != 0 + 0x00 == read(data, UInt8) || + throw(ArgumentError("Terminfo did not contain a null byte after the extended flag section, expected to position the start of the numbers section on an even byte")) + end + numbers = reinterpret(NumInt, read(data, numbers_count * sizeof(NumInt))) .|> ltoh + table_indices = reinterpret(UInt16, read(data, table_count * sizeof(UInt16))) .|> ltoh + table_strings = [String(readuntil(data, 0x00)) for _ in 1:length(table_indices)] + strings = table_strings[1:string_count] + labels = Symbol.(table_strings[string_count+1:end]) + Dict{Symbol, Union{Bool, Int, String}}( + labels .=> vcat(flags, numbers, strings)) +end + +""" + TermInfo(raw::TermInfoRaw) + +Construct a `TermInfo` from `raw`, using known terminal capabilities (as of +NCurses 6.3, see `TERM_FLAGS`, `TERM_NUMBERS`, and `TERM_STRINGS`). +""" +function TermInfo(raw::TermInfoRaw) + capabilities = Dict{Symbol, Union{Bool, Int, String}}() + sizehint!(capabilities, 2 * (length(raw.flags) + length(raw.numbers) + length(raw.strings))) + for (flag, value) in zip(TERM_FLAGS, raw.flags) + capabilities[flag.short] = value + capabilities[flag.long] = value + end + for (num, value) in zip(TERM_NUMBERS, raw.numbers) + if value != typemax(eltype(raw.numbers)) + capabilities[num.short] = Int(value) + capabilities[num.long] = Int(value) + end + end + for (str, value) in zip(TERM_STRINGS, raw.strings) + if !isnothing(value) + capabilities[str.short] = value + capabilities[str.long] = value + end + end + extensions = if !isnothing(raw.extended) + capabilities = merge(capabilities, raw.extended) + keys(raw.extended) |> collect + else + Symbol[] + end + TermInfo(raw.names, length(raw.flags), + raw.numbers .!= typemax(eltype(raw.numbers)), + map(!isnothing, raw.strings), + extensions, capabilities) +end + +getindex(ti::TermInfo, key::Symbol) = ti.capabilities[key] +get(ti::TermInfo, key::Symbol, default::D) where D<:Union{Bool, Int, String} = + get(ti.capabilities, key, default)::D +get(ti::TermInfo, key::Symbol, default) = get(ti.capabilities, key, default) +keys(ti::TermInfo) = keys(ti.capabilities) +haskey(ti::TermInfo, key::Symbol) = haskey(ti.capabilities, key) + +function show(io::IO, ::MIME"text/plain", ti::TermInfo) + print(io, "TermInfo(", ti.names, "; ", ti.flags, " flags, ", + sum(ti.numbers), " numbers, ", sum(ti.strings), " strings") + !isempty(ti.extensions) > 0 && + print(io, ", ", length(ti.extensions), " extended capabilities") + print(io, ')') +end + +""" + find_terminfo_file(term::String) + +Locate the terminfo file for `term`, return `nothing` if none could be found. + +The lookup policy is described in `terminfo(5)` "Fetching Compiled +Descriptions". +""" +function find_terminfo_file(term::String) + isempty(term) && return + chr, chrcode = string(first(term)), string(Int(first(term)), base=16) + terminfo_dirs = if haskey(ENV, "TERMINFO") + [ENV["TERMINFO"]] + elseif isdir(joinpath(homedir(), ".terminfo")) + [joinpath(homedir(), ".terminfo")] + elseif haskey(ENV, "TERMINFO_DIRS") + split(ENV["TERMINFO_DIRS"], ':') + elseif Sys.isunix() + ["/usr/share/terminfo"] + else + String[] + end + for dir in terminfo_dirs + if isfile(joinpath(dir, chr, term)) + return joinpath(dir, chr, term) + elseif isfile(joinpath(dir, chrcode, term)) + return joinpath(dir, chrcode, term) + end + end +end + +""" + load_terminfo(term::String) + +Load the `TermInfo` for `term`, falling back on a blank `TermInfo`. +""" +function load_terminfo(term::String) + file = find_terminfo_file(term) + isnothing(file) && return TermInfo() + try + TermInfo(read(file, TermInfoRaw)) + catch err + if err isa ArgumentError || err isa IOError + TermInfo() + else + rethrow() + end + end +end + +""" +The terminfo of the current terminal. +""" +current_terminfo::TermInfo = TermInfo() + +# Legacy/TTY methods and the `:color` parameter + +if Sys.iswindows() + ttyhascolor(term_type = nothing) = true +else + function ttyhascolor(term_type = get(ENV, "TERM", "")) + startswith(term_type, "xterm") || + haskey(current_terminfo, :setaf) + end +end + +""" + ttyhastruecolor() + +Return a boolean signifying whether the current terminal supports 24-bit colors. + +This uses the `COLORTERM` environment variable if possible, returning true if it +is set to either `"truecolor"` or `"24bit"`. + +As a fallback, first on unix systems the `colors` terminal capability is checked +— should more than 256 colors be reported, this is taken to signify 24-bit +support. Lastly, the color is attempted to be set to `#010203` and then the +current color queried via the DCS (Device Control String) sequence `\$qm`. If +the output contains `":1:2:3"` this is taken to signify 24-bit support. + +If the fallbacks are used, the `"COLORTERM"` entry in `ENV` is updated according +to the result. This ensures that frequent calls will only potentially be slow +the first time. +""" +function ttyhastruecolor() + function test24bitcolor_dcs() + REPL.Terminals.raw!(REPL.TerminalMenus.terminal, true) + print(stdout, "\e[48;2;1;2;3m\eP\$qm\e\\\e[m") + flush(stdout) + # Some terminals are bad and haven't got DCS sequence support, + # if we don't see a response from stdin we need to abort. + output = @task readuntil(stdin, 'm') + schedule(output) + Timer(0.1) do _ + istaskdone(output) || Base.throwto(output, InterruptException()) + end + color::String = try + fetch(output) + catch _ "" end + REPL.Terminals.raw!(REPL.TerminalMenus.terminal, false) + occursin(":1:2:3", color) + end + get(ENV, "COLORTERM", "") ∈ ("truecolor", "24bit") || + @static if Sys.isunix() + get(current_terminfo, :colors, 0) > 256 || + isinteractive() && test24bitcolor_dcs() + else + false + end +end + +function get_have_color() + global have_color + have_color === nothing && (have_color = ttyhascolor()) + return have_color::Bool +end + +function get_have_truecolor() + global have_truecolor + have_truecolor === nothing && (have_truecolor = ttyhastruecolor()) + return have_truecolor::Bool +end + +in(key_value::Pair{Symbol,Bool}, ::TTY) = key_value.first === :color && key_value.second === get_have_color() +haskey(::TTY, key::Symbol) = key === :color +getindex(::TTY, key::Symbol) = key === :color ? get_have_color() : throw(KeyError(key)) +get(::TTY, key::Symbol, default) = key === :color ? get_have_color() : default diff --git a/base/terminfo_data.jl b/base/terminfo_data.jl new file mode 100644 index 0000000000000..38c058f414f07 --- /dev/null +++ b/base/terminfo_data.jl @@ -0,0 +1,540 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +""" + struct TermCapability + +Specification of a single terminal capability. + +!!! warning + This is not part of the public API, and thus subject to change without notice. + +# Fields + +- `short::Symbol`: The *Cap-name* of the capability +- `long::Symbol`: The name of the terminfo capability variable +- `description::String`: A description of the purpose of the capability + +See also: `TermInfo`, `TERM_FLAGS`, `TERM_NUMBERS`, and `TERM_STRINGS`. +""" +struct TermCapability + short::Symbol + long::Symbol + description::String +end + +# Terminfo Capabilities as of NCurses 6.3 + +""" +Ordered list of known terminal capability flag fields, as of NCurses 6.3. +""" +const TERM_FLAGS = [ + TermCapability(:bw, :auto_left_margin, "cub1 wraps from column 0 to last column"), + TermCapability(:am, :auto_right_margin, "terminal has automatic margins"), + TermCapability(:xsb, :no_esc_ctlc, "beehive (f1=escape, f2=ctrl C)"), + TermCapability(:xhp, :ceol_standout_glitch, "standout not erased by overwriting (hp)"), + TermCapability(:xenl, :eat_newline_glitch, "newline ignored after 80 cols (concept)"), + TermCapability(:eo, :erase_overstrike, "can erase overstrikes with a blank"), + TermCapability(:gn, :generic_type, "generic line type"), + TermCapability(:hc, :hard_copy, "hardcopy terminal"), + TermCapability(:km, :has_meta_key, "Has a meta key (i.e., sets 8th-bit)"), + TermCapability(:hs, :has_status_line, "has extra status line"), + TermCapability(:in, :insert_null_glitch, "insert mode distinguishes nulls"), + TermCapability(:db, :memory_below, "display may be retained below the screen"), + TermCapability(:da, :memory_above, "display may be retained above the screen"), + TermCapability(:mir, :move_insert_mode, "safe to move while in insert mode"), + TermCapability(:msgr, :move_standout_mode, "safe to move while in standout mode"), + TermCapability(:os, :over_strike, "terminal can overstrike"), + TermCapability(:eslok, :status_line_esc_ok, "escape can be used on the status line"), + TermCapability(:xt, :dest_tabs_magic_smso, "tabs destructive, magic so char (t1061)"), + TermCapability(:hz, :tilde_glitch, "cannot print ~'s (Hazeltine)"), + TermCapability(:ul, :transparent_underline, "underline character overstrikes"), + TermCapability(:xon, :xon_xoff, "terminal uses xon/xoff handshaking"), + TermCapability(:nxon, :needs_xon_xoff, "padding will not work, xon/xoff required"), + TermCapability(:mc5i, :prtr_silent, "printer will not echo on screen"), + TermCapability(:chts, :hard_cursor, "cursor is hard to see"), + TermCapability(:nrrmc, :non_rev_rmcup, "smcup does not reverse rmcup"), + TermCapability(:npc, :no_pad_char, "pad character does not exist"), + TermCapability(:ndscr, :non_dest_scroll_region, "scrolling region is non-destructive"), + TermCapability(:ccc, :can_change, "terminal can re-define existing colors"), + TermCapability(:bce, :back_color_erase, "screen erased with background color"), + TermCapability(:hls, :hue_lightness_saturation, "terminal uses only HLS color notation (Tektronix)"), + TermCapability(:xhpa, :col_addr_glitch, "only positive motion for hpa/mhpa caps"), + TermCapability(:crxm, :cr_cancels_micro_mode, "using cr turns off micro mode"), + TermCapability(:daisy, :has_print_wheel, "printer needs operator to change character set"), + TermCapability(:xvpa, :row_addr_glitch, "only positive motion for vpa/mvpa caps"), + TermCapability(:sam, :semi_auto_right_margin, "printing in last column causes cr"), + TermCapability(:cpix, :cpi_changes_res, "changing character pitch changes resolution"), + TermCapability(:lpix, :lpi_changes_res, "changing line pitch changes resolution"), + TermCapability(:OTbs, :backspaces_with_bs, "uses ^H to move left"), + TermCapability(:OTns, :crt_no_scrolling, "crt cannot scroll"), + TermCapability(:OTnc, :no_correctly_working_cr, "no way to go to start of line"), + TermCapability(:OTMT, :gnu_has_meta_key, "has meta key"), + TermCapability(:OTNL, :linefeed_is_newline, "move down with \n"), + TermCapability(:OTpt, :has_hardware_tabs, "has 8-char tabs invoked with ^I"), + TermCapability(:OTxr, :return_does_clr_eol, "return clears the line"), +] + +""" +Ordered list of known terminal capability number fields, as of NCurses 6.3. +""" +const TERM_NUMBERS = [ + TermCapability(:cols, :columns, "number of columns in a line"), + TermCapability(:it, :init_tabs, "tabs initially every # spaces"), + TermCapability(:lines, :lines, "number of lines on screen or page"), + TermCapability(:lm, :lines_of_memory, "lines of memory if > line. 0 means varies"), + TermCapability(:xmc, :magic_cookie_glitch, "number of blank characters left by smso or rmso"), + TermCapability(:pb, :padding_baud_rate, "lowest baud rate where padding needed"), + TermCapability(:vt, :virtual_terminal, "virtual terminal number (CB/unix)"), + TermCapability(:wsl, :width_status_line, "number of columns in status line"), + TermCapability(:nlab, :num_labels, "number of labels on screen"), + TermCapability(:lh, :label_height, "rows in each label"), + TermCapability(:lw, :label_width, "columns in each label"), + TermCapability(:ma, :max_attributes, "maximum combined attributes terminal can handle"), + TermCapability(:wnum, :maximum_windows, "maximum number of definable windows"), + TermCapability(:colors, :max_colors, "maximum number of colors on screen"), + TermCapability(:pairs, :max_pairs, "maximum number of color-pairs on the screen"), + TermCapability(:ncv, :no_color_video, "video attributes that cannot be used with colors"), + TermCapability(:bufsz, :buffer_capacity, "numbers of bytes buffered before printing"), + TermCapability(:spinv, :dot_vert_spacing, "spacing of pins vertically in pins per inch"), + TermCapability(:spinh, :dot_horz_spacing, "spacing of dots horizontally in dots per inch"), + TermCapability(:maddr, :max_micro_address, "maximum value in micro_..._address"), + TermCapability(:mjump, :max_micro_jump, "maximum value in parm_..._micro"), + TermCapability(:mcs, :micro_col_size, "character step size when in micro mode"), + TermCapability(:mls, :micro_line_size, "line step size when in micro mode"), + TermCapability(:npins, :number_of_pins, "numbers of pins in print-head"), + TermCapability(:orc, :output_res_char, "horizontal resolution in units per line"), + TermCapability(:orl, :output_res_line, "vertical resolution in units per line"), + TermCapability(:orhi, :output_res_horz_inch, "horizontal resolution in units per inch"), + TermCapability(:orvi, :output_res_vert_inch, "vertical resolution in units per inch"), + TermCapability(:cps, :print_rate, "print rate in characters per second"), + TermCapability(:widcs, :wide_char_size, "character step size when in double wide mode"), + TermCapability(:btns, :buttons, "number of buttons on mouse"), + TermCapability(:bitwin, :bit_image_entwining, "number of passes for each bit-image row"), + TermCapability(:bitype, :bit_image_type, "type of bit-image device"), + TermCapability(:OTug, :magic_cookie_glitch_ul, "number of blanks left by ul"), + TermCapability(:OTdC, :carriage_return_delay, "pad needed for CR"), + TermCapability(:OTdN, :new_line_delay, "pad needed for LF"), + TermCapability(:OTdB, :backspace_delay, "padding required for ^H"), + TermCapability(:OTdT, :horizontal_tab_delay, "padding required for ^I"), + TermCapability(:OTkn, :number_of_function_keys, "count of function keys"), +] + +""" +Ordered list of known terminal capability string fields, as of NCurses 6.3. +""" +const TERM_STRINGS = [ + TermCapability(:cbt, :back_tab, "back tab (P)"), + TermCapability(:bel, :bell, "audible signal (bell) (P)"), + TermCapability(:cr, :carriage_return, "carriage return (P*) (P*)"), + TermCapability(:csr, :change_scroll_region, "change region to line #1 to line #2 (P)"), + TermCapability(:tbc, :clear_all_tabs, "clear all tab stops (P)"), + TermCapability(:clear, :clear_screen, "clear screen and home cursor (P*)"), + TermCapability(:el, :clr_eol, "clear to end of line (P)"), + TermCapability(:ed, :clr_eos, "clear to end of screen (P*)"), + TermCapability(:hpa, :column_address, "horizontal position #1, absolute (P)"), + TermCapability(:cmdch, :command_character, "terminal settable cmd character in prototype !?"), + TermCapability(:cup, :cursor_address, "move to row #1 columns #2"), + TermCapability(:cud1, :cursor_down, "down one line"), + TermCapability(:home, :cursor_home, "home cursor (if no cup)"), + TermCapability(:civis, :cursor_invisible, "make cursor invisible"), + TermCapability(:cub1, :cursor_left, "move left one space"), + TermCapability(:mrcup, :cursor_mem_address, "memory relative cursor addressing, move to row #1 columns #2"), + TermCapability(:cnorm, :cursor_normal, "make cursor appear normal (undo civis/cvvis)"), + TermCapability(:cuf1, :cursor_right, "non-destructive space (move right one space)"), + TermCapability(:ll, :cursor_to_ll, "last line, first column (if no cup)"), + TermCapability(:cuu1, :cursor_up, "up one line"), + TermCapability(:cvvis, :cursor_visible, "make cursor very visible"), + TermCapability(:dch1, :delete_character, "delete character (P*)"), + TermCapability(:dl1, :delete_line, "delete line (P*)"), + TermCapability(:dsl, :dis_status_line, "disable status line"), + TermCapability(:hd, :down_half_line, "half a line down"), + TermCapability(:smacs, :enter_alt_charset_mode, "start alternate character set (P)"), + TermCapability(:blink, :enter_blink_mode, "turn on blinking"), + TermCapability(:bold, :enter_bold_mode, "turn on bold (extra bright) mode"), + TermCapability(:smcup, :enter_ca_mode, "string to start programs using cup"), + TermCapability(:smdc, :enter_delete_mode, "enter delete mode"), + TermCapability(:dim, :enter_dim_mode, "turn on half-bright mode"), + TermCapability(:smir, :enter_insert_mode, "enter insert mode"), + TermCapability(:invis, :enter_secure_mode, "turn on blank mode (characters invisible)"), + TermCapability(:prot, :enter_protected_mode, "turn on protected mode"), + TermCapability(:rev, :enter_reverse_mode, "turn on reverse video mode"), + TermCapability(:smso, :enter_standout_mode, "begin standout mode"), + TermCapability(:smul, :enter_underline_mode, "begin underline mode"), + TermCapability(:ech, :erase_chars, "erase #1 characters (P)"), + TermCapability(:rmacs, :exit_alt_charset_mode, "end alternate character set (P)"), + TermCapability(:sgr0, :exit_attribute_mode, "turn off all attributes"), + TermCapability(:rmcup, :exit_ca_mode, "strings to end programs using cup"), + TermCapability(:rmdc, :exit_delete_mode, "end delete mode"), + TermCapability(:rmir, :exit_insert_mode, "exit insert mode"), + TermCapability(:rmso, :exit_standout_mode, "exit standout mode"), + TermCapability(:rmul, :exit_underline_mode, "exit underline mode"), + TermCapability(:flash, :flash_screen, "visible bell (may not move cursor)"), + TermCapability(:ff, :form_feed, "hardcopy terminal page eject (P*)"), + TermCapability(:fsl, :from_status_line, "return from status line"), + TermCapability(:is1, :init_1string, "initialization string"), + TermCapability(:is2, :init_2string, "initialization string"), + TermCapability(:is3, :init_3string, "initialization string"), + TermCapability(:if, :init_file, "name of initialization file"), + TermCapability(:ich1, :insert_character, "insert character (P)"), + TermCapability(:il1, :insert_line, "insert line (P*)"), + TermCapability(:ip, :insert_padding, "insert padding after inserted character"), + TermCapability(:kbs, :key_backspace, "backspace key"), + TermCapability(:ktbc, :key_catab, "clear-all-tabs key"), + TermCapability(:kclr, :key_clear, "clear-screen or erase key"), + TermCapability(:kctab, :key_ctab, "clear-tab key"), + TermCapability(:kdch1, :key_dc, "delete-character key"), + TermCapability(:kdl1, :key_dl, "delete-line key"), + TermCapability(:kcud1, :key_down, "down-arrow key"), + TermCapability(:krmir, :key_eic, "sent by rmir or smir in insert mode"), + TermCapability(:kel, :key_eol, "clear-to-end-of-line key"), + TermCapability(:ked, :key_eos, "clear-to-end-of-screen key"), + TermCapability(:kf0, :key_f0, "F0 function key"), + TermCapability(:kf1, :key_f1, "F1 function key"), + TermCapability(:kf10, :key_f10, "F10 function key"), + TermCapability(:kf2, :key_f2, "F2 function key"), + TermCapability(:kf3, :key_f3, "F3 function key"), + TermCapability(:kf4, :key_f4, "F4 function key"), + TermCapability(:kf5, :key_f5, "F5 function key"), + TermCapability(:kf6, :key_f6, "F6 function key"), + TermCapability(:kf7, :key_f7, "F7 function key"), + TermCapability(:kf8, :key_f8, "F8 function key"), + TermCapability(:kf9, :key_f9, "F9 function key"), + TermCapability(:khome, :key_home, "home key"), + TermCapability(:kich1, :key_ic, "insert-character key"), + TermCapability(:kil1, :key_il, "insert-line key"), + TermCapability(:kcub1, :key_left, "left-arrow key"), + TermCapability(:kll, :key_ll, "lower-left key (home down)"), + TermCapability(:knp, :key_npage, "next-page key"), + TermCapability(:kpp, :key_ppage, "previous-page key"), + TermCapability(:kcuf1, :key_right, "right-arrow key"), + TermCapability(:kind, :key_sf, "scroll-forward key"), + TermCapability(:kri, :key_sr, "scroll-backward key"), + TermCapability(:khts, :key_stab, "set-tab key"), + TermCapability(:kcuu1, :key_up, "up-arrow key"), + TermCapability(:rmkx, :keypad_local, "leave 'keyboard_transmit' mode"), + TermCapability(:smkx, :keypad_xmit, "enter 'keyboard_transmit' mode"), + TermCapability(:lf0, :lab_f0, "label on function key f0 if not f0"), + TermCapability(:lf1, :lab_f1, "label on function key f1 if not f1"), + TermCapability(:lf10, :lab_f10, "label on function key f10 if not f10"), + TermCapability(:lf2, :lab_f2, "label on function key f2 if not f2"), + TermCapability(:lf3, :lab_f3, "label on function key f3 if not f3"), + TermCapability(:lf4, :lab_f4, "label on function key f4 if not f4"), + TermCapability(:lf5, :lab_f5, "label on function key f5 if not f5"), + TermCapability(:lf6, :lab_f6, "label on function key f6 if not f6"), + TermCapability(:lf7, :lab_f7, "label on function key f7 if not f7"), + TermCapability(:lf8, :lab_f8, "label on function key f8 if not f8"), + TermCapability(:lf9, :lab_f9, "label on function key f9 if not f9"), + TermCapability(:rmm, :meta_off, "turn off meta mode"), + TermCapability(:smm, :meta_on, "turn on meta mode (8th-bit on)"), + TermCapability(:nel, :newline, "newline (behave like cr followed by lf)"), + TermCapability(:pad, :pad_char, "padding char (instead of null)"), + TermCapability(:dch, :parm_dch, "delete #1 characters (P*)"), + TermCapability(:dl, :parm_delete_line, "delete #1 lines (P*)"), + TermCapability(:cud, :parm_down_cursor, "down #1 lines (P*)"), + TermCapability(:ich, :parm_ich, "insert #1 characters (P*)"), + TermCapability(:indn, :parm_index, "scroll forward #1 lines (P)"), + TermCapability(:il, :parm_insert_line, "insert #1 lines (P*)"), + TermCapability(:cub, :parm_left_cursor, "move #1 characters to the left (P)"), + TermCapability(:cuf, :parm_right_cursor, "move #1 characters to the right (P*)"), + TermCapability(:rin, :parm_rindex, "scroll back #1 lines (P)"), + TermCapability(:cuu, :parm_up_cursor, "up #1 lines (P*)"), + TermCapability(:pfkey, :pkey_key, "program function key #1 to type string #2"), + TermCapability(:pfloc, :pkey_local, "program function key #1 to execute string #2"), + TermCapability(:pfx, :pkey_xmit, "program function key #1 to transmit string #2"), + TermCapability(:mc0, :print_screen, "print contents of screen"), + TermCapability(:mc4, :prtr_off, "turn off printer"), + TermCapability(:mc5, :prtr_on, "turn on printer"), + TermCapability(:rep, :repeat_char, "repeat char #1 #2 times (P*)"), + TermCapability(:rs1, :reset_1string, "reset string"), + TermCapability(:rs2, :reset_2string, "reset string"), + TermCapability(:rs3, :reset_3string, "reset string"), + TermCapability(:rf, :reset_file, "name of reset file"), + TermCapability(:rc, :restore_cursor, "restore cursor to position of last save_cursor"), + TermCapability(:vpa, :row_address, "vertical position #1 absolute (P)"), + TermCapability(:sc, :save_cursor, "save current cursor position (P)"), + TermCapability(:ind, :scroll_forward, "scroll text up (P)"), + TermCapability(:ri, :scroll_reverse, "scroll text down (P)"), + TermCapability(:sgr, :set_attributes, "define video attributes #1-#9 (PG9)"), + TermCapability(:hts, :set_tab, "set a tab in every row, current columns"), + TermCapability(:wind, :set_window, "current window is lines #1-#2 cols #3-#4"), + TermCapability(:ht, :tab, "tab to next 8-space hardware tab stop"), + TermCapability(:tsl, :to_status_line, "move to status line, column #1"), + TermCapability(:uc, :underline_char, "underline char and move past it"), + TermCapability(:hu, :up_half_line, "half a line up"), + TermCapability(:iprog, :init_prog, "path name of program for initialization"), + TermCapability(:ka1, :key_a1, "upper left of keypad"), + TermCapability(:ka3, :key_a3, "upper right of keypad"), + TermCapability(:kb2, :key_b2, "center of keypad"), + TermCapability(:kc1, :key_c1, "lower left of keypad"), + TermCapability(:kc3, :key_c3, "lower right of keypad"), + TermCapability(:mc5p, :prtr_non, "turn on printer for #1 bytes"), + TermCapability(:rmp, :char_padding, "like ip but when in insert mode"), + TermCapability(:acsc, :acs_chars, "graphics charset pairs, based on vt100"), + TermCapability(:pln, :plab_norm, "program label #1 to show string #2"), + TermCapability(:kcbt, :key_btab, "back-tab key"), + TermCapability(:smxon, :enter_xon_mode, "turn on xon/xoff handshaking"), + TermCapability(:rmxon, :exit_xon_mode, "turn off xon/xoff handshaking"), + TermCapability(:smam, :enter_am_mode, "turn on automatic margins"), + TermCapability(:rmam, :exit_am_mode, "turn off automatic margins"), + TermCapability(:xonc, :xon_character, "XON character"), + TermCapability(:xoffc, :xoff_character, "XOFF character"), + TermCapability(:enacs, :ena_acs, "enable alternate char set"), + TermCapability(:smln, :label_on, "turn on soft labels"), + TermCapability(:rmln, :label_off, "turn off soft labels"), + TermCapability(:kbeg, :key_beg, "begin key"), + TermCapability(:kcan, :key_cancel, "cancel key"), + TermCapability(:kclo, :key_close, "close key"), + TermCapability(:kcmd, :key_command, "command key"), + TermCapability(:kcpy, :key_copy, "copy key"), + TermCapability(:kcrt, :key_create, "create key"), + TermCapability(:kend, :key_end, "end key"), + TermCapability(:kent, :key_enter, "enter/send key"), + TermCapability(:kext, :key_exit, "exit key"), + TermCapability(:kfnd, :key_find, "find key"), + TermCapability(:khlp, :key_help, "help key"), + TermCapability(:kmrk, :key_mark, "mark key"), + TermCapability(:kmsg, :key_message, "message key"), + TermCapability(:kmov, :key_move, "move key"), + TermCapability(:knxt, :key_next, "next key"), + TermCapability(:kopn, :key_open, "open key"), + TermCapability(:kopt, :key_options, "options key"), + TermCapability(:kprv, :key_previous, "previous key"), + TermCapability(:kprt, :key_print, "print key"), + TermCapability(:krdo, :key_redo, "redo key"), + TermCapability(:kref, :key_reference, "reference key"), + TermCapability(:krfr, :key_refresh, "refresh key"), + TermCapability(:krpl, :key_replace, "replace key"), + TermCapability(:krst, :key_restart, "restart key"), + TermCapability(:kres, :key_resume, "resume key"), + TermCapability(:ksav, :key_save, "save key"), + TermCapability(:kspd, :key_suspend, "suspend key"), + TermCapability(:kund, :key_undo, "undo key"), + TermCapability(:kBEG, :key_sbeg, "shifted begin key"), + TermCapability(:kCAN, :key_scancel, "shifted cancel key"), + TermCapability(:kCMD, :key_scommand, "shifted command key"), + TermCapability(:kCPY, :key_scopy, "shifted copy key"), + TermCapability(:kCRT, :key_screate, "shifted create key"), + TermCapability(:kDC, :key_sdc, "shifted delete-character key"), + TermCapability(:kDL, :key_sdl, "shifted delete-line key"), + TermCapability(:kslt, :key_select, "select key"), + TermCapability(:kEND, :key_send, "shifted end key"), + TermCapability(:kEOL, :key_seol, "shifted clear-to-end-of-line key"), + TermCapability(:kEXT, :key_sexit, "shifted exit key"), + TermCapability(:kFND, :key_sfind, "shifted find key"), + TermCapability(:kHLP, :key_shelp, "shifted help key"), + TermCapability(:kHOM, :key_shome, "shifted home key"), + TermCapability(:kIC, :key_sic, "shifted insert-character key"), + TermCapability(:kLFT, :key_sleft, "shifted left-arrow key"), + TermCapability(:kMSG, :key_smessage, "shifted message key"), + TermCapability(:kMOV, :key_smove, "shifted move key"), + TermCapability(:kNXT, :key_snext, "shifted next key"), + TermCapability(:kOPT, :key_soptions, "shifted options key"), + TermCapability(:kPRV, :key_sprevious, "shifted previous key"), + TermCapability(:kPRT, :key_sprint, "shifted print key"), + TermCapability(:kRDO, :key_sredo, "shifted redo key"), + TermCapability(:kRPL, :key_sreplace, "shifted replace key"), + TermCapability(:kRIT, :key_sright, "shifted right-arrow key"), + TermCapability(:kRES, :key_srsume, "shifted resume key"), + TermCapability(:kSAV, :key_ssave, "shifted save key"), + TermCapability(:kSPD, :key_ssuspend, "shifted suspend key"), + TermCapability(:kUND, :key_sundo, "shifted undo key"), + TermCapability(:rfi, :req_for_input, "send next input char (for ptys)"), + TermCapability(:kf11, :key_f11, "F11 function key"), + TermCapability(:kf12, :key_f12, "F12 function key"), + TermCapability(:kf13, :key_f13, "F13 function key"), + TermCapability(:kf14, :key_f14, "F14 function key"), + TermCapability(:kf15, :key_f15, "F15 function key"), + TermCapability(:kf16, :key_f16, "F16 function key"), + TermCapability(:kf17, :key_f17, "F17 function key"), + TermCapability(:kf18, :key_f18, "F18 function key"), + TermCapability(:kf19, :key_f19, "F19 function key"), + TermCapability(:kf20, :key_f20, "F20 function key"), + TermCapability(:kf21, :key_f21, "F21 function key"), + TermCapability(:kf22, :key_f22, "F22 function key"), + TermCapability(:kf23, :key_f23, "F23 function key"), + TermCapability(:kf24, :key_f24, "F24 function key"), + TermCapability(:kf25, :key_f25, "F25 function key"), + TermCapability(:kf26, :key_f26, "F26 function key"), + TermCapability(:kf27, :key_f27, "F27 function key"), + TermCapability(:kf28, :key_f28, "F28 function key"), + TermCapability(:kf29, :key_f29, "F29 function key"), + TermCapability(:kf30, :key_f30, "F30 function key"), + TermCapability(:kf31, :key_f31, "F31 function key"), + TermCapability(:kf32, :key_f32, "F32 function key"), + TermCapability(:kf33, :key_f33, "F33 function key"), + TermCapability(:kf34, :key_f34, "F34 function key"), + TermCapability(:kf35, :key_f35, "F35 function key"), + TermCapability(:kf36, :key_f36, "F36 function key"), + TermCapability(:kf37, :key_f37, "F37 function key"), + TermCapability(:kf38, :key_f38, "F38 function key"), + TermCapability(:kf39, :key_f39, "F39 function key"), + TermCapability(:kf40, :key_f40, "F40 function key"), + TermCapability(:kf41, :key_f41, "F41 function key"), + TermCapability(:kf42, :key_f42, "F42 function key"), + TermCapability(:kf43, :key_f43, "F43 function key"), + TermCapability(:kf44, :key_f44, "F44 function key"), + TermCapability(:kf45, :key_f45, "F45 function key"), + TermCapability(:kf46, :key_f46, "F46 function key"), + TermCapability(:kf47, :key_f47, "F47 function key"), + TermCapability(:kf48, :key_f48, "F48 function key"), + TermCapability(:kf49, :key_f49, "F49 function key"), + TermCapability(:kf50, :key_f50, "F50 function key"), + TermCapability(:kf51, :key_f51, "F51 function key"), + TermCapability(:kf52, :key_f52, "F52 function key"), + TermCapability(:kf53, :key_f53, "F53 function key"), + TermCapability(:kf54, :key_f54, "F54 function key"), + TermCapability(:kf55, :key_f55, "F55 function key"), + TermCapability(:kf56, :key_f56, "F56 function key"), + TermCapability(:kf57, :key_f57, "F57 function key"), + TermCapability(:kf58, :key_f58, "F58 function key"), + TermCapability(:kf59, :key_f59, "F59 function key"), + TermCapability(:kf60, :key_f60, "F60 function key"), + TermCapability(:kf61, :key_f61, "F61 function key"), + TermCapability(:kf62, :key_f62, "F62 function key"), + TermCapability(:kf63, :key_f63, "F63 function key"), + TermCapability(:el1, :clr_bol, "Clear to beginning of line"), + TermCapability(:mgc, :clear_margins, "clear right and left soft margins"), + TermCapability(:smgl, :set_left_margin, "set left soft margin at current column. (ML is not in BSD termcap)."), + TermCapability(:smgr, :set_right_margin, "set right soft margin at current column"), + TermCapability(:fln, :label_format, "label format"), + TermCapability(:sclk, :set_clock, "set clock, #1 hrs #2 mins #3 secs"), + TermCapability(:dclk, :display_clock, "display clock"), + TermCapability(:rmclk, :remove_clock, "remove clock"), + TermCapability(:cwin, :create_window, "define a window #1 from #2, #3 to #4, #5"), + TermCapability(:wingo, :goto_window, "go to window #1"), + TermCapability(:hup, :hangup, "hang-up phone"), + TermCapability(:dial, :dial_phone, "dial number #1"), + TermCapability(:qdial, :quick_dial, "dial number #1 without checking"), + TermCapability(:tone, :tone, "select touch tone dialing"), + TermCapability(:pulse, :pulse, "select pulse dialing"), + TermCapability(:hook, :flash_hook, "flash switch hook"), + TermCapability(:pause, :fixed_pause, "pause for 2-3 seconds"), + TermCapability(:wait, :wait_tone, "wait for dial-tone"), + TermCapability(:u0, :user0, "User string #0"), + TermCapability(:u1, :user1, "User string #1"), + TermCapability(:u2, :user2, "User string #2"), + TermCapability(:u3, :user3, "User string #3"), + TermCapability(:u4, :user4, "User string #4"), + TermCapability(:u5, :user5, "User string #5"), + TermCapability(:u6, :user6, "User string #6"), + TermCapability(:u7, :user7, "User string #7"), + TermCapability(:u8, :user8, "User string #8"), + TermCapability(:u9, :user9, "User string #9"), + TermCapability(:op, :orig_pair, "Set default pair to its original value"), + TermCapability(:oc, :orig_colors, "Set all color pairs to the original ones"), + TermCapability(:initc, :initialize_color, "Initialize color #1 to (#2, #3, #4)"), + TermCapability(:initp, :initialize_pair, "Initialize color pair #1 to fg=(#2, #3, #4), bg=(#5,#6,#7)"), + TermCapability(:scp, :set_color_pair, "Set current color pair to #1"), + TermCapability(:setf, :set_foreground, "Set foreground color #1"), + TermCapability(:setb, :set_background, "Set background color #1"), + TermCapability(:cpi, :change_char_pitch, "Change number of characters per inch to #1"), + TermCapability(:lpi, :change_line_pitch, "Change number of lines per inch to #1"), + TermCapability(:chr, :change_res_horz, "Change horizontal resolution to #1"), + TermCapability(:cvr, :change_res_vert, "Change vertical resolution to #1"), + TermCapability(:defc, :define_char, "Define a character #1, #2 dots wide, descender #3"), + TermCapability(:swidm, :enter_doublewide_mode, "Enter double-wide mode"), + TermCapability(:sdrfq, :enter_draft_quality, "Enter draft-quality mode"), + TermCapability(:sitm, :enter_italics_mode, "Enter italic mode"), + TermCapability(:slm, :enter_leftward_mode, "Start leftward carriage motion"), + TermCapability(:smicm, :enter_micro_mode, "Start micro-motion mode"), + TermCapability(:snlq, :enter_near_letter_quality, "Enter NLQ mode"), + TermCapability(:snrmq, :enter_normal_quality, "Enter normal-quality mode"), + TermCapability(:sshm, :enter_shadow_mode, "Enter shadow-print mode"), + TermCapability(:ssubm, :enter_subscript_mode, "Enter subscript mode"), + TermCapability(:ssupm, :enter_superscript_mode, "Enter superscript mode"), + TermCapability(:sum, :enter_upward_mode, "Start upward carriage motion"), + TermCapability(:rwidm, :exit_doublewide_mode, "End double-wide mode"), + TermCapability(:ritm, :exit_italics_mode, "End italic mode"), + TermCapability(:rlm, :exit_leftward_mode, "End left-motion mode"), + TermCapability(:rmicm, :exit_micro_mode, "End micro-motion mode"), + TermCapability(:rshm, :exit_shadow_mode, "End shadow-print mode"), + TermCapability(:rsubm, :exit_subscript_mode, "End subscript mode"), + TermCapability(:rsupm, :exit_superscript_mode, "End superscript mode"), + TermCapability(:rum, :exit_upward_mode, "End reverse character motion"), + TermCapability(:mhpa, :micro_column_address, "Like column_address in micro mode"), + TermCapability(:mcud1, :micro_down, "Like cursor_down in micro mode"), + TermCapability(:mcub1, :micro_left, "Like cursor_left in micro mode"), + TermCapability(:mcuf1, :micro_right, "Like cursor_right in micro mode"), + TermCapability(:mvpa, :micro_row_address, "Like row_address #1 in micro mode"), + TermCapability(:mcuu1, :micro_up, "Like cursor_up in micro mode"), + TermCapability(:porder, :order_of_pins, "Match software bits to print-head pins"), + TermCapability(:mcud, :parm_down_micro, "Like parm_down_cursor in micro mode"), + TermCapability(:mcub, :parm_left_micro, "Like parm_left_cursor in micro mode"), + TermCapability(:mcuf, :parm_right_micro, "Like parm_right_cursor in micro mode"), + TermCapability(:mcuu, :parm_up_micro, "Like parm_up_cursor in micro mode"), + TermCapability(:scs, :select_char_set, "Select character set, #1"), + TermCapability(:smgb, :set_bottom_margin, "Set bottom margin at current line"), + TermCapability(:smgbp, :set_bottom_margin_parm, "Set bottom margin at line #1 or (if smgtp is not given) #2 lines from bottom"), + TermCapability(:smglp, :set_left_margin_parm, "Set left (right) margin at column #1"), + TermCapability(:smgrp, :set_right_margin_parm, "Set right margin at column #1"), + TermCapability(:smgt, :set_top_margin, "Set top margin at current line"), + TermCapability(:smgtp, :set_top_margin_parm, "Set top (bottom) margin at row #1"), + TermCapability(:sbim, :start_bit_image, "Start printing bit image graphics"), + TermCapability(:scsd, :start_char_set_def, "Start character set definition #1, with #2 characters in the set"), + TermCapability(:rbim, :stop_bit_image, "Stop printing bit image graphics"), + TermCapability(:rcsd, :stop_char_set_def, "End definition of character set #1"), + TermCapability(:subcs, :subscript_characters, "List of subscriptable characters"), + TermCapability(:supcs, :superscript_characters, "List of superscriptable characters"), + TermCapability(:docr, :these_cause_cr, "Printing any of these characters causes CR"), + TermCapability(:zerom, :zero_motion, "No motion for subsequent character"), + TermCapability(:csnm, :char_set_names, "Produce #1'th item from list of character set names"), + TermCapability(:kmous, :key_mouse, "Mouse event has occurred"), + TermCapability(:minfo, :mouse_info, "Mouse status information"), + TermCapability(:reqmp, :req_mouse_pos, "Request mouse position"), + TermCapability(:getm, :get_mouse, "Curses should get button events, parameter #1 not documented."), + TermCapability(:setaf, :set_a_foreground, "Set foreground color to #1, using ANSI escape"), + TermCapability(:setab, :set_a_background, "Set background color to #1, using ANSI escape"), + TermCapability(:pfxl, :pkey_plab, "Program function key #1 to type string #2 and show string #3"), + TermCapability(:devt, :device_type, "Indicate language/codeset support"), + TermCapability(:csin, :code_set_init, "Init sequence for multiple codesets"), + TermCapability(:s0ds, :set0_des_seq, "Shift to codeset 0 (EUC set 0, ASCII)"), + TermCapability(:s1ds, :set1_des_seq, "Shift to codeset 1"), + TermCapability(:s2ds, :set2_des_seq, "Shift to codeset 2"), + TermCapability(:s3ds, :set3_des_seq, "Shift to codeset 3"), + TermCapability(:smglr, :set_lr_margin, "Set both left and right margins to #1, #2. (ML is not in BSD termcap)."), + TermCapability(:smgtb, :set_tb_margin, "Sets both top and bottom margins to #1, #2"), + TermCapability(:birep, :bit_image_repeat, "Repeat bit image cell #1 #2 times"), + TermCapability(:binel, :bit_image_newline, "Move to next row of the bit image"), + TermCapability(:bicr, :bit_image_carriage_return, "Move to beginning of same row"), + TermCapability(:colornm, :color_names, "Give name for color #1"), + TermCapability(:defbi, :define_bit_image_region, "Define rectangular bit image region"), + TermCapability(:endbi, :end_bit_image_region, "End a bit-image region"), + TermCapability(:setcolor, :set_color_band, "Change to ribbon color #1"), + TermCapability(:slines, :set_page_length, "Set page length to #1 lines"), + TermCapability(:dispc, :display_pc_char, "Display PC character #1"), + TermCapability(:smpch, :enter_pc_charset_mode, "Enter PC character display mode"), + TermCapability(:rmpch, :exit_pc_charset_mode, "Exit PC character display mode"), + TermCapability(:smsc, :enter_scancode_mode, "Enter PC scancode mode"), + TermCapability(:rmsc, :exit_scancode_mode, "Exit PC scancode mode"), + TermCapability(:pctrm, :pc_term_options, "PC terminal options"), + TermCapability(:scesc, :scancode_escape, "Escape for scancode emulation"), + TermCapability(:scesa, :alt_scancode_esc, "Alternate escape for scancode emulation"), + TermCapability(:ehhlm, :enter_horizontal_hl_mode, "Enter horizontal highlight mode"), + TermCapability(:elhlm, :enter_left_hl_mode, "Enter left highlight mode"), + TermCapability(:elohlm, :enter_low_hl_mode, "Enter low highlight mode"), + TermCapability(:erhlm, :enter_right_hl_mode, "Enter right highlight mode"), + TermCapability(:ethlm, :enter_top_hl_mode, "Enter top highlight mode"), + TermCapability(:evhlm, :enter_vertical_hl_mode, "Enter vertical highlight mode"), + TermCapability(:sgr1, :set_a_attributes, "Define second set of video attributes #1-#6"), + TermCapability(:slength, :set_pglen_inch, "Set page length to #1 hundredth of an inch (some implementations use sL for termcap)."), + TermCapability(:OTi2, :termcap_init2, "secondary initialization string"), + TermCapability(:OTrs, :termcap_reset, "terminal reset string"), + TermCapability(:OTnl, :linefeed_if_not_lf, "use to move down"), + TermCapability(:OTbs, :backspaces_with_bs, "uses ^H to move left"), + TermCapability(:OTko, :other_non_function_keys, "list of self-mapped keycaps"), + TermCapability(:OTma, :arrow_key_map, "map motion-keys for vi version 2"), + TermCapability(:OTG2, :acs_ulcorner, "single upper left"), + TermCapability(:OTG3, :acs_llcorner, "single lower left"), + TermCapability(:OTG1, :acs_urcorner, "single upper right"), + TermCapability(:OTG4, :acs_lrcorner, "single lower right"), + TermCapability(:OTGR, :acs_ltee, "tee pointing right"), + TermCapability(:OTGL, :acs_rtee, "tee pointing left"), + TermCapability(:OTGU, :acs_btee, "tee pointing up"), + TermCapability(:OTGD, :acs_ttee, "tee pointing down"), + TermCapability(:OTGH, :acs_hline, "single horizontal line"), + TermCapability(:OTGV, :acs_vline, "single vertical line"), + TermCapability(:OTGC, :acs_plus, "single intersection"), + TermCapability(:meml, :memory_lock, "lock memory above cursor"), + TermCapability(:memu, :memory_unlock, "unlock memory"), + TermCapability(:box1, :box_chars_1, "box characters primary set"), +] diff --git a/base/ttyhascolor.jl b/base/ttyhascolor.jl deleted file mode 100644 index 2a14790da5f06..0000000000000 --- a/base/ttyhascolor.jl +++ /dev/null @@ -1,80 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -if Sys.iswindows() - ttyhascolor(term_type = nothing) = true -else - function ttyhascolor(term_type = get(ENV, "TERM", "")) - startswith(term_type, "xterm") && return true - try - @static if Sys.KERNEL === :FreeBSD - return success(`tput AF 0`) - else - return success(`tput setaf 0`) - end - catch e - return false - end - end -end - -""" - ttyhastruecolor() - -Return a boolean signifying whether the current terminal supports 24-bit colors. - -This uses the `COLORTERM` environment variable if possible, returning true if it -is set to either `"truecolor"` or `"24bit"`. - -As a fallback, first on unix systems the `colors` terminal capability is checked -— should more than 256 colors be reported, this is taken to signify 24-bit -support. Lastly, the color is attempted to be set to `#010203` and then the -current color queried via the DCS (Device Control String) sequence `\$qm`. If -the output contains `":1:2:3"` this is taken to signify 24-bit support. - -If the fallbacks are used, the `"COLORTERM"` entry in `ENV` is updated according -to the result. This ensures that frequent calls will only potentially be slow -the first time. -""" -function ttyhastruecolor() - function test24bitcolor_dcs() - REPL.Terminals.raw!(REPL.TerminalMenus.terminal, true) - print(stdout, "\e[48;2;1;2;3m\eP\$qm\e\\\e[m") - flush(stdout) - # Some terminals are bad and haven't got DCS sequence support, - # if we don't see a response from stdin we need to abort. - output = @task readuntil(stdin, 'm') - schedule(output) - Timer(0.1) do _ - istaskdone(output) || Base.throwto(output, InterruptException()) - end - color = try - fetch(output) - catch _ "" end - REPL.Terminals.raw!(REPL.TerminalMenus.terminal, false) - occursin(":1:2:3", color) - end - get(ENV, "COLORTERM", "") ∈ ("truecolor", "24bit") || - @static if Sys.isunix() - get(current_terminfo, :colors, 0) > 256 || - isinteractive() && test24bitcolor_dcs() - else - false - end -end - -function get_have_color() - global have_color - have_color === nothing && (have_color = ttyhascolor()) - return have_color::Bool -end - -function get_have_truecolor() - global have_truecolor - have_truecolor === nothing && (have_truecolor = ttyhastruecolor()) - return have_truecolor::Bool -end - -in(key_value::Pair{Symbol,Bool}, ::TTY) = key_value.first === :color && key_value.second === get_have_color() -haskey(::TTY, key::Symbol) = key === :color -getindex(::TTY, key::Symbol) = key === :color ? get_have_color() : throw(KeyError(key)) -get(::TTY, key::Symbol, default) = key === :color ? get_have_color() : default From 6b7fa6fb6f053de29c6aada1001a409113e876c2 Mon Sep 17 00:00:00 2001 From: TEC Date: Fri, 4 Aug 2023 13:54:21 +0100 Subject: [PATCH 3/4] Add terminfo test set The terminfo files are taken from my local device, and the assertions are generated from the current terminfo implementation but have been partially manually checked for correctness. As such, this is mainly a barrier against potential implementation drift in the future, as unlikely as it may be. --- test/choosetests.jl | 2 +- test/terminfo.jl | 911 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 912 insertions(+), 1 deletion(-) create mode 100644 test/terminfo.jl diff --git a/test/choosetests.jl b/test/choosetests.jl index 18af88ea191e9..c38817bb4eeb9 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -19,7 +19,7 @@ const TESTNAMES = [ "mpfr", "broadcast", "complex", "floatapprox", "stdlib", "reflection", "regex", "float16", "combinatorics", "sysinfo", "env", "rounding", "ranges", "mod2pi", - "euler", "show", "client", + "euler", "show", "client", "terminfo", "errorshow", "sets", "goto", "llvmcall", "llvmcall2", "ryu", "some", "meta", "stacktraces", "docs", "gc", "misc", "threads", "stress", "binaryplatforms", "atexit", diff --git a/test/terminfo.jl b/test/terminfo.jl new file mode 100644 index 0000000000000..cbaab346a617b --- /dev/null +++ b/test/terminfo.jl @@ -0,0 +1,911 @@ +let + dumb_terminfo = UInt8[ + 0x1a, 0x01, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x82, 0x00, 0x08, 0x00, + 0x64, 0x75, 0x6d, 0x62, 0x7c, 0x38, 0x30, 0x2d, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x20, 0x64, 0x75, 0x6d, 0x62, 0x20, 0x74, 0x74, 0x79, 0x00, + 0x00, 0x01, 0x50, 0x00, 0xff, 0xff, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, + 0x07, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x0a, 0x00] + + dumb_capabilities = Dict{Symbol, Union{Bool, Int, String}}( + :am => true, + :auto_right_margin => true, + :bw => false, + :auto_left_margin => false, + :bel => "\a", + :bell => "\a", + :cr => "\r", + :carriage_return => "\r", + :cols => 80, + :columns => 80, + :cud1 => "\n", + :cursor_down => "\n", + :ind => "\n", + :scroll_forward => "\n") + + xterm_terminfo = UInt8[ + 0x1a, 0x01, 0x30, 0x00, 0x26, 0x00, 0x0f, 0x00, 0x9d, 0x01, 0xe6, 0x05, + 0x78, 0x74, 0x65, 0x72, 0x6d, 0x7c, 0x78, 0x74, 0x65, 0x72, 0x6d, 0x20, + 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x65, 0x6d, 0x75, + 0x6c, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x28, 0x58, 0x20, 0x57, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x50, 0x00, 0x08, 0x00, 0x18, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x08, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x2a, 0x00, + 0x2e, 0x00, 0xff, 0xff, 0x39, 0x00, 0x4a, 0x00, 0x4c, 0x00, 0x50, 0x00, + 0x57, 0x00, 0xff, 0xff, 0x59, 0x00, 0x66, 0x00, 0xff, 0xff, 0x6a, 0x00, + 0x6e, 0x00, 0x78, 0x00, 0x7c, 0x00, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x84, 0x00, 0x89, 0x00, 0x8e, 0x00, 0xff, 0xff, 0xa0, 0x00, 0xa5, 0x00, + 0xaa, 0x00, 0xff, 0xff, 0xaf, 0x00, 0xb4, 0x00, 0xb9, 0x00, 0xbe, 0x00, + 0xc7, 0x00, 0xcb, 0x00, 0xd2, 0x00, 0xff, 0xff, 0xe4, 0x00, 0xe9, 0x00, + 0xef, 0x00, 0xf5, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x01, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x01, 0xff, 0xff, 0x1d, 0x01, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x01, 0xff, 0xff, 0x24, 0x01, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x01, 0x2c, 0x01, + 0x32, 0x01, 0x36, 0x01, 0x3a, 0x01, 0x3e, 0x01, 0x44, 0x01, 0x4a, 0x01, + 0x50, 0x01, 0x56, 0x01, 0x5c, 0x01, 0x60, 0x01, 0xff, 0xff, 0x65, 0x01, + 0xff, 0xff, 0x69, 0x01, 0x6e, 0x01, 0x73, 0x01, 0x77, 0x01, 0x7e, 0x01, + 0xff, 0xff, 0x85, 0x01, 0x89, 0x01, 0x91, 0x01, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x01, 0xa2, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xab, 0x01, 0xb4, 0x01, 0xbd, 0x01, 0xc6, 0x01, 0xcf, 0x01, + 0xd8, 0x01, 0xe1, 0x01, 0xea, 0x01, 0xf3, 0x01, 0xfc, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x05, 0x02, 0x09, 0x02, 0x0e, 0x02, 0x13, 0x02, + 0x27, 0x02, 0x2a, 0x02, 0xff, 0xff, 0xff, 0xff, 0x3c, 0x02, 0x3f, 0x02, + 0x4a, 0x02, 0x4d, 0x02, 0x4f, 0x02, 0x52, 0x02, 0xaf, 0x02, 0xff, 0xff, + 0xb2, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x02, + 0xb8, 0x02, 0xbc, 0x02, 0xc0, 0x02, 0xc4, 0x02, 0xff, 0xff, 0xff, 0xff, + 0xc8, 0x02, 0xff, 0xff, 0xfd, 0x02, 0xff, 0xff, 0xff, 0xff, 0x01, 0x03, + 0x07, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0d, 0x03, 0x11, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x03, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x23, 0x03, + 0x2a, 0x03, 0x31, 0x03, 0xff, 0xff, 0xff, 0xff, 0x38, 0x03, 0xff, 0xff, + 0x3f, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x46, 0x03, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4d, 0x03, 0x53, 0x03, + 0x59, 0x03, 0x60, 0x03, 0x67, 0x03, 0x6e, 0x03, 0x75, 0x03, 0x7d, 0x03, + 0x85, 0x03, 0x8d, 0x03, 0x95, 0x03, 0x9d, 0x03, 0xa5, 0x03, 0xad, 0x03, + 0xb5, 0x03, 0xbc, 0x03, 0xc3, 0x03, 0xca, 0x03, 0xd1, 0x03, 0xd9, 0x03, + 0xe1, 0x03, 0xe9, 0x03, 0xf1, 0x03, 0xf9, 0x03, 0x01, 0x04, 0x09, 0x04, + 0x11, 0x04, 0x18, 0x04, 0x1f, 0x04, 0x26, 0x04, 0x2d, 0x04, 0x35, 0x04, + 0x3d, 0x04, 0x45, 0x04, 0x4d, 0x04, 0x55, 0x04, 0x5d, 0x04, 0x65, 0x04, + 0x6d, 0x04, 0x74, 0x04, 0x7b, 0x04, 0x82, 0x04, 0x89, 0x04, 0x91, 0x04, + 0x99, 0x04, 0xa1, 0x04, 0xa9, 0x04, 0xb1, 0x04, 0xb9, 0x04, 0xc1, 0x04, + 0xc9, 0x04, 0xd0, 0x04, 0xd7, 0x04, 0xde, 0x04, 0xe3, 0x04, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x04, 0xf5, 0x04, 0xfa, 0x04, + 0x0d, 0x05, 0x11, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1a, 0x05, 0x60, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x05, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xab, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x05, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb5, 0x05, 0xbf, 0x05, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc9, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x05, 0xe3, 0x05, 0x1b, 0x5b, 0x5a, 0x00, 0x07, 0x00, + 0x0d, 0x00, 0x1b, 0x5b, 0x25, 0x69, 0x25, 0x70, 0x31, 0x25, 0x64, 0x3b, + 0x25, 0x70, 0x32, 0x25, 0x64, 0x72, 0x00, 0x1b, 0x5b, 0x33, 0x67, 0x00, + 0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a, 0x00, 0x1b, 0x5b, 0x4b, 0x00, + 0x1b, 0x5b, 0x4a, 0x00, 0x1b, 0x5b, 0x25, 0x69, 0x25, 0x70, 0x31, 0x25, + 0x64, 0x47, 0x00, 0x1b, 0x5b, 0x25, 0x69, 0x25, 0x70, 0x31, 0x25, 0x64, + 0x3b, 0x25, 0x70, 0x32, 0x25, 0x64, 0x48, 0x00, 0x0a, 0x00, 0x1b, 0x5b, + 0x48, 0x00, 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c, 0x00, 0x08, 0x00, 0x1b, + 0x5b, 0x3f, 0x31, 0x32, 0x6c, 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x68, 0x00, + 0x1b, 0x5b, 0x43, 0x00, 0x1b, 0x5b, 0x41, 0x00, 0x1b, 0x5b, 0x3f, 0x31, + 0x32, 0x3b, 0x32, 0x35, 0x68, 0x00, 0x1b, 0x5b, 0x50, 0x00, 0x1b, 0x5b, + 0x4d, 0x00, 0x1b, 0x28, 0x30, 0x00, 0x1b, 0x5b, 0x35, 0x6d, 0x00, 0x1b, + 0x5b, 0x31, 0x6d, 0x00, 0x1b, 0x5b, 0x3f, 0x31, 0x30, 0x34, 0x39, 0x68, + 0x1b, 0x5b, 0x32, 0x32, 0x3b, 0x30, 0x3b, 0x30, 0x74, 0x00, 0x1b, 0x5b, + 0x32, 0x6d, 0x00, 0x1b, 0x5b, 0x34, 0x68, 0x00, 0x1b, 0x5b, 0x38, 0x6d, + 0x00, 0x1b, 0x5b, 0x37, 0x6d, 0x00, 0x1b, 0x5b, 0x37, 0x6d, 0x00, 0x1b, + 0x5b, 0x34, 0x6d, 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x58, + 0x00, 0x1b, 0x28, 0x42, 0x00, 0x1b, 0x28, 0x42, 0x1b, 0x5b, 0x6d, 0x00, + 0x1b, 0x5b, 0x3f, 0x31, 0x30, 0x34, 0x39, 0x6c, 0x1b, 0x5b, 0x32, 0x33, + 0x3b, 0x30, 0x3b, 0x30, 0x74, 0x00, 0x1b, 0x5b, 0x34, 0x6c, 0x00, 0x1b, + 0x5b, 0x32, 0x37, 0x6d, 0x00, 0x1b, 0x5b, 0x32, 0x34, 0x6d, 0x00, 0x1b, + 0x5b, 0x3f, 0x35, 0x68, 0x24, 0x3c, 0x31, 0x30, 0x30, 0x2f, 0x3e, 0x1b, + 0x5b, 0x3f, 0x35, 0x6c, 0x00, 0x1b, 0x5b, 0x21, 0x70, 0x1b, 0x5b, 0x3f, + 0x33, 0x3b, 0x34, 0x6c, 0x1b, 0x5b, 0x34, 0x6c, 0x1b, 0x3e, 0x00, 0x1b, + 0x5b, 0x4c, 0x00, 0x08, 0x00, 0x1b, 0x5b, 0x33, 0x7e, 0x00, 0x1b, 0x4f, + 0x42, 0x00, 0x1b, 0x4f, 0x50, 0x00, 0x1b, 0x5b, 0x32, 0x31, 0x7e, 0x00, + 0x1b, 0x4f, 0x51, 0x00, 0x1b, 0x4f, 0x52, 0x00, 0x1b, 0x4f, 0x53, 0x00, + 0x1b, 0x5b, 0x31, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x37, 0x7e, 0x00, + 0x1b, 0x5b, 0x31, 0x38, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x39, 0x7e, 0x00, + 0x1b, 0x5b, 0x32, 0x30, 0x7e, 0x00, 0x1b, 0x4f, 0x48, 0x00, 0x1b, 0x5b, + 0x32, 0x7e, 0x00, 0x1b, 0x4f, 0x44, 0x00, 0x1b, 0x5b, 0x36, 0x7e, 0x00, + 0x1b, 0x5b, 0x35, 0x7e, 0x00, 0x1b, 0x4f, 0x43, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x32, 0x42, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x41, 0x00, 0x1b, + 0x4f, 0x41, 0x00, 0x1b, 0x5b, 0x3f, 0x31, 0x6c, 0x1b, 0x3e, 0x00, 0x1b, + 0x5b, 0x3f, 0x31, 0x68, 0x1b, 0x3d, 0x00, 0x1b, 0x5b, 0x3f, 0x31, 0x30, + 0x33, 0x34, 0x6c, 0x00, 0x1b, 0x5b, 0x3f, 0x31, 0x30, 0x33, 0x34, 0x68, + 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x50, 0x00, 0x1b, 0x5b, + 0x25, 0x70, 0x31, 0x25, 0x64, 0x4d, 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, + 0x25, 0x64, 0x42, 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x40, + 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x53, 0x00, 0x1b, 0x5b, + 0x25, 0x70, 0x31, 0x25, 0x64, 0x4c, 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, + 0x25, 0x64, 0x44, 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x43, + 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x54, 0x00, 0x1b, 0x5b, + 0x25, 0x70, 0x31, 0x25, 0x64, 0x41, 0x00, 0x1b, 0x5b, 0x69, 0x00, 0x1b, + 0x5b, 0x34, 0x69, 0x00, 0x1b, 0x5b, 0x35, 0x69, 0x00, 0x25, 0x70, 0x31, + 0x25, 0x63, 0x1b, 0x5b, 0x25, 0x70, 0x32, 0x25, 0x7b, 0x31, 0x7d, 0x25, + 0x2d, 0x25, 0x64, 0x62, 0x00, 0x1b, 0x63, 0x00, 0x1b, 0x5b, 0x21, 0x70, + 0x1b, 0x5b, 0x3f, 0x33, 0x3b, 0x34, 0x6c, 0x1b, 0x5b, 0x34, 0x6c, 0x1b, + 0x3e, 0x00, 0x1b, 0x38, 0x00, 0x1b, 0x5b, 0x25, 0x69, 0x25, 0x70, 0x31, + 0x25, 0x64, 0x64, 0x00, 0x1b, 0x37, 0x00, 0x0a, 0x00, 0x1b, 0x4d, 0x00, + 0x25, 0x3f, 0x25, 0x70, 0x39, 0x25, 0x74, 0x1b, 0x28, 0x30, 0x25, 0x65, + 0x1b, 0x28, 0x42, 0x25, 0x3b, 0x1b, 0x5b, 0x30, 0x25, 0x3f, 0x25, 0x70, + 0x36, 0x25, 0x74, 0x3b, 0x31, 0x25, 0x3b, 0x25, 0x3f, 0x25, 0x70, 0x35, + 0x25, 0x74, 0x3b, 0x32, 0x25, 0x3b, 0x25, 0x3f, 0x25, 0x70, 0x32, 0x25, + 0x74, 0x3b, 0x34, 0x25, 0x3b, 0x25, 0x3f, 0x25, 0x70, 0x31, 0x25, 0x70, + 0x33, 0x25, 0x7c, 0x25, 0x74, 0x3b, 0x37, 0x25, 0x3b, 0x25, 0x3f, 0x25, + 0x70, 0x34, 0x25, 0x74, 0x3b, 0x35, 0x25, 0x3b, 0x25, 0x3f, 0x25, 0x70, + 0x37, 0x25, 0x74, 0x3b, 0x38, 0x25, 0x3b, 0x6d, 0x00, 0x1b, 0x48, 0x00, + 0x09, 0x00, 0x1b, 0x4f, 0x77, 0x00, 0x1b, 0x4f, 0x79, 0x00, 0x1b, 0x4f, + 0x75, 0x00, 0x1b, 0x4f, 0x71, 0x00, 0x1b, 0x4f, 0x73, 0x00, 0x60, 0x60, + 0x61, 0x61, 0x66, 0x66, 0x67, 0x67, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, + 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, + 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, + 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, + 0x7e, 0x7e, 0x00, 0x1b, 0x5b, 0x5a, 0x00, 0x1b, 0x5b, 0x3f, 0x37, 0x68, + 0x00, 0x1b, 0x5b, 0x3f, 0x37, 0x6c, 0x00, 0x1b, 0x4f, 0x46, 0x00, 0x1b, + 0x4f, 0x4d, 0x00, 0x1b, 0x5b, 0x33, 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, + 0x31, 0x3b, 0x32, 0x46, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x48, 0x00, + 0x1b, 0x5b, 0x32, 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x32, + 0x44, 0x00, 0x1b, 0x5b, 0x36, 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x35, + 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x43, 0x00, 0x1b, + 0x5b, 0x32, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x34, 0x7e, 0x00, 0x1b, + 0x5b, 0x31, 0x3b, 0x32, 0x50, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x51, + 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x52, 0x00, 0x1b, 0x5b, 0x31, 0x3b, + 0x32, 0x53, 0x00, 0x1b, 0x5b, 0x31, 0x35, 0x3b, 0x32, 0x7e, 0x00, 0x1b, + 0x5b, 0x31, 0x37, 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x38, 0x3b, + 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x39, 0x3b, 0x32, 0x7e, 0x00, 0x1b, + 0x5b, 0x32, 0x30, 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x31, 0x3b, + 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x33, 0x3b, 0x32, 0x7e, 0x00, 0x1b, + 0x5b, 0x32, 0x34, 0x3b, 0x32, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, + 0x50, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x51, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x35, 0x52, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x53, 0x00, 0x1b, + 0x5b, 0x31, 0x35, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x37, 0x3b, + 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x38, 0x3b, 0x35, 0x7e, 0x00, 0x1b, + 0x5b, 0x31, 0x39, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x30, 0x3b, + 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x31, 0x3b, 0x35, 0x7e, 0x00, 0x1b, + 0x5b, 0x32, 0x33, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x34, 0x3b, + 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x50, 0x00, 0x1b, 0x5b, + 0x31, 0x3b, 0x36, 0x51, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x52, 0x00, + 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x53, 0x00, 0x1b, 0x5b, 0x31, 0x35, 0x3b, + 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x37, 0x3b, 0x36, 0x7e, 0x00, 0x1b, + 0x5b, 0x31, 0x38, 0x3b, 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x39, 0x3b, + 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x30, 0x3b, 0x36, 0x7e, 0x00, 0x1b, + 0x5b, 0x32, 0x31, 0x3b, 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x33, 0x3b, + 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x34, 0x3b, 0x36, 0x7e, 0x00, 0x1b, + 0x5b, 0x31, 0x3b, 0x33, 0x50, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x51, + 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x52, 0x00, 0x1b, 0x5b, 0x31, 0x3b, + 0x33, 0x53, 0x00, 0x1b, 0x5b, 0x31, 0x35, 0x3b, 0x33, 0x7e, 0x00, 0x1b, + 0x5b, 0x31, 0x37, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x38, 0x3b, + 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x39, 0x3b, 0x33, 0x7e, 0x00, 0x1b, + 0x5b, 0x32, 0x30, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x31, 0x3b, + 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x33, 0x3b, 0x33, 0x7e, 0x00, 0x1b, + 0x5b, 0x32, 0x34, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x34, + 0x50, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x34, 0x51, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x34, 0x52, 0x00, 0x1b, 0x5b, 0x31, 0x4b, 0x00, 0x1b, 0x5b, 0x3f, + 0x36, 0x39, 0x6c, 0x00, 0x1b, 0x5b, 0x25, 0x69, 0x25, 0x64, 0x3b, 0x25, + 0x64, 0x52, 0x00, 0x1b, 0x5b, 0x36, 0x6e, 0x00, 0x1b, 0x5b, 0x3f, 0x25, + 0x5b, 0x3b, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x5d, 0x63, 0x00, 0x1b, 0x5b, 0x63, 0x00, 0x1b, 0x5b, 0x33, 0x39, 0x3b, + 0x34, 0x39, 0x6d, 0x00, 0x1b, 0x5b, 0x33, 0x25, 0x3f, 0x25, 0x70, 0x31, + 0x25, 0x7b, 0x31, 0x7d, 0x25, 0x3d, 0x25, 0x74, 0x34, 0x25, 0x65, 0x25, + 0x70, 0x31, 0x25, 0x7b, 0x33, 0x7d, 0x25, 0x3d, 0x25, 0x74, 0x36, 0x25, + 0x65, 0x25, 0x70, 0x31, 0x25, 0x7b, 0x34, 0x7d, 0x25, 0x3d, 0x25, 0x74, + 0x31, 0x25, 0x65, 0x25, 0x70, 0x31, 0x25, 0x7b, 0x36, 0x7d, 0x25, 0x3d, + 0x25, 0x74, 0x33, 0x25, 0x65, 0x25, 0x70, 0x31, 0x25, 0x64, 0x25, 0x3b, + 0x6d, 0x00, 0x1b, 0x5b, 0x34, 0x25, 0x3f, 0x25, 0x70, 0x31, 0x25, 0x7b, + 0x31, 0x7d, 0x25, 0x3d, 0x25, 0x74, 0x34, 0x25, 0x65, 0x25, 0x70, 0x31, + 0x25, 0x7b, 0x33, 0x7d, 0x25, 0x3d, 0x25, 0x74, 0x36, 0x25, 0x65, 0x25, + 0x70, 0x31, 0x25, 0x7b, 0x34, 0x7d, 0x25, 0x3d, 0x25, 0x74, 0x31, 0x25, + 0x65, 0x25, 0x70, 0x31, 0x25, 0x7b, 0x36, 0x7d, 0x25, 0x3d, 0x25, 0x74, + 0x33, 0x25, 0x65, 0x25, 0x70, 0x31, 0x25, 0x64, 0x25, 0x3b, 0x6d, 0x00, + 0x1b, 0x5b, 0x33, 0x6d, 0x00, 0x1b, 0x5b, 0x32, 0x33, 0x6d, 0x00, 0x1b, + 0x5b, 0x3c, 0x00, 0x1b, 0x5b, 0x33, 0x25, 0x70, 0x31, 0x25, 0x64, 0x6d, + 0x00, 0x1b, 0x5b, 0x34, 0x25, 0x70, 0x31, 0x25, 0x64, 0x6d, 0x00, 0x1b, + 0x5b, 0x3f, 0x36, 0x39, 0x68, 0x1b, 0x5b, 0x25, 0x69, 0x25, 0x70, 0x31, + 0x25, 0x64, 0x3b, 0x25, 0x70, 0x32, 0x25, 0x64, 0x73, 0x00, 0x1b, 0x6c, + 0x00, 0x1b, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x96, 0x00, + 0xac, 0x03, 0x01, 0x01, 0x00, 0x00, 0x07, 0x00, 0x13, 0x00, 0x18, 0x00, + 0x2a, 0x00, 0x30, 0x00, 0x3a, 0x00, 0x5a, 0x00, 0x61, 0x00, 0x68, 0x00, + 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00, + 0x99, 0x00, 0xa0, 0x00, 0xa7, 0x00, 0xae, 0x00, 0xb5, 0x00, 0xbc, 0x00, + 0xc3, 0x00, 0xca, 0x00, 0xd1, 0x00, 0xd8, 0x00, 0xdf, 0x00, 0xe6, 0x00, + 0xed, 0x00, 0xf4, 0x00, 0xfb, 0x00, 0x02, 0x01, 0x09, 0x01, 0x10, 0x01, + 0x17, 0x01, 0x1e, 0x01, 0x25, 0x01, 0x2c, 0x01, 0x33, 0x01, 0x3a, 0x01, + 0x41, 0x01, 0x48, 0x01, 0x4f, 0x01, 0x56, 0x01, 0x5d, 0x01, 0x64, 0x01, + 0x6b, 0x01, 0x72, 0x01, 0x79, 0x01, 0x80, 0x01, 0x87, 0x01, 0x8e, 0x01, + 0x95, 0x01, 0x9c, 0x01, 0xa3, 0x01, 0xaa, 0x01, 0xb1, 0x01, 0xb8, 0x01, + 0xbf, 0x01, 0xc6, 0x01, 0xca, 0x01, 0xce, 0x01, 0xd2, 0x01, 0xd6, 0x01, + 0xda, 0x01, 0xde, 0x01, 0xe2, 0x01, 0xe6, 0x01, 0xea, 0x01, 0xee, 0x01, + 0xf2, 0x01, 0xf6, 0x01, 0xfc, 0x01, 0x01, 0x02, 0x00, 0x00, 0x03, 0x00, + 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x15, 0x00, + 0x18, 0x00, 0x1b, 0x00, 0x20, 0x00, 0x25, 0x00, 0x2a, 0x00, 0x2f, 0x00, + 0x34, 0x00, 0x38, 0x00, 0x3d, 0x00, 0x42, 0x00, 0x47, 0x00, 0x4c, 0x00, + 0x51, 0x00, 0x57, 0x00, 0x5d, 0x00, 0x63, 0x00, 0x69, 0x00, 0x6f, 0x00, + 0x75, 0x00, 0x7b, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8d, 0x00, 0x92, 0x00, + 0x97, 0x00, 0x9c, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xac, 0x00, 0xb2, 0x00, + 0xb8, 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xca, 0x00, 0xd0, 0x00, 0xd6, 0x00, + 0xdc, 0x00, 0xe2, 0x00, 0xe8, 0x00, 0xee, 0x00, 0xf4, 0x00, 0xfa, 0x00, + 0x00, 0x01, 0x06, 0x01, 0x0c, 0x01, 0x12, 0x01, 0x18, 0x01, 0x1e, 0x01, + 0x22, 0x01, 0x27, 0x01, 0x2c, 0x01, 0x31, 0x01, 0x36, 0x01, 0x3b, 0x01, + 0x3f, 0x01, 0x43, 0x01, 0x47, 0x01, 0x4b, 0x01, 0x4f, 0x01, 0x55, 0x01, + 0x5b, 0x01, 0x61, 0x01, 0x67, 0x01, 0x6d, 0x01, 0x73, 0x01, 0x79, 0x01, + 0x7e, 0x01, 0x83, 0x01, 0x1b, 0x5d, 0x31, 0x31, 0x32, 0x07, 0x00, 0x1b, + 0x5d, 0x31, 0x32, 0x3b, 0x25, 0x70, 0x31, 0x25, 0x73, 0x07, 0x00, 0x1b, + 0x5b, 0x33, 0x4a, 0x00, 0x1b, 0x5d, 0x35, 0x32, 0x3b, 0x25, 0x70, 0x31, + 0x25, 0x73, 0x3b, 0x25, 0x70, 0x32, 0x25, 0x73, 0x07, 0x00, 0x1b, 0x5b, + 0x32, 0x20, 0x71, 0x00, 0x1b, 0x5b, 0x25, 0x70, 0x31, 0x25, 0x64, 0x20, + 0x71, 0x00, 0x1b, 0x5b, 0x3f, 0x31, 0x30, 0x30, 0x36, 0x3b, 0x31, 0x30, + 0x30, 0x30, 0x25, 0x3f, 0x25, 0x70, 0x31, 0x25, 0x7b, 0x31, 0x7d, 0x25, + 0x3d, 0x25, 0x74, 0x68, 0x25, 0x65, 0x6c, 0x25, 0x3b, 0x00, 0x1b, 0x5b, + 0x33, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x33, 0x3b, 0x34, 0x7e, 0x00, + 0x1b, 0x5b, 0x33, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x33, 0x3b, 0x36, + 0x7e, 0x00, 0x1b, 0x5b, 0x33, 0x3b, 0x37, 0x7e, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x32, 0x42, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x42, 0x00, 0x1b, + 0x5b, 0x31, 0x3b, 0x34, 0x42, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x42, + 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x42, 0x00, 0x1b, 0x5b, 0x31, 0x3b, + 0x37, 0x42, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x46, 0x00, 0x1b, 0x5b, + 0x31, 0x3b, 0x34, 0x46, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x46, 0x00, + 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x46, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x37, + 0x46, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x48, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x34, 0x48, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x48, 0x00, 0x1b, + 0x5b, 0x31, 0x3b, 0x36, 0x48, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x37, 0x48, + 0x00, 0x1b, 0x5b, 0x32, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x3b, + 0x34, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, + 0x32, 0x3b, 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x32, 0x3b, 0x37, 0x7e, 0x00, + 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x44, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x34, + 0x44, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x44, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x36, 0x44, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x37, 0x44, 0x00, 0x1b, + 0x5b, 0x36, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x36, 0x3b, 0x34, 0x7e, + 0x00, 0x1b, 0x5b, 0x36, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x36, 0x3b, + 0x36, 0x7e, 0x00, 0x1b, 0x5b, 0x36, 0x3b, 0x37, 0x7e, 0x00, 0x1b, 0x5b, + 0x35, 0x3b, 0x33, 0x7e, 0x00, 0x1b, 0x5b, 0x35, 0x3b, 0x34, 0x7e, 0x00, + 0x1b, 0x5b, 0x35, 0x3b, 0x35, 0x7e, 0x00, 0x1b, 0x5b, 0x35, 0x3b, 0x36, + 0x7e, 0x00, 0x1b, 0x5b, 0x35, 0x3b, 0x37, 0x7e, 0x00, 0x1b, 0x5b, 0x31, + 0x3b, 0x33, 0x43, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x34, 0x43, 0x00, 0x1b, + 0x5b, 0x31, 0x3b, 0x35, 0x43, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x43, + 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x37, 0x43, 0x00, 0x1b, 0x5b, 0x31, 0x3b, + 0x32, 0x41, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x33, 0x41, 0x00, 0x1b, 0x5b, + 0x31, 0x3b, 0x34, 0x41, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x41, 0x00, + 0x1b, 0x5b, 0x31, 0x3b, 0x36, 0x41, 0x00, 0x1b, 0x5b, 0x31, 0x3b, 0x37, + 0x41, 0x00, 0x1b, 0x4f, 0x78, 0x00, 0x1b, 0x4f, 0x74, 0x00, 0x1b, 0x4f, + 0x76, 0x00, 0x1b, 0x4f, 0x72, 0x00, 0x1b, 0x4f, 0x45, 0x00, 0x1b, 0x4f, + 0x6b, 0x00, 0x1b, 0x4f, 0x6c, 0x00, 0x1b, 0x4f, 0x6f, 0x00, 0x1b, 0x4f, + 0x6e, 0x00, 0x1b, 0x4f, 0x6a, 0x00, 0x1b, 0x4f, 0x6d, 0x00, 0x1b, 0x4f, + 0x70, 0x00, 0x1b, 0x5b, 0x32, 0x39, 0x6d, 0x00, 0x1b, 0x5b, 0x39, 0x6d, + 0x00, 0x1b, 0x5b, 0x3c, 0x25, 0x69, 0x25, 0x70, 0x33, 0x25, 0x64, 0x3b, + 0x25, 0x70, 0x31, 0x25, 0x64, 0x3b, 0x25, 0x70, 0x32, 0x25, 0x64, 0x3b, + 0x25, 0x3f, 0x25, 0x70, 0x34, 0x25, 0x74, 0x4d, 0x25, 0x65, 0x6d, 0x25, + 0x3b, 0x00, 0x41, 0x58, 0x00, 0x58, 0x54, 0x00, 0x43, 0x72, 0x00, 0x43, + 0x73, 0x00, 0x45, 0x33, 0x00, 0x4d, 0x73, 0x00, 0x53, 0x65, 0x00, 0x53, + 0x73, 0x00, 0x58, 0x4d, 0x00, 0x6b, 0x44, 0x43, 0x33, 0x00, 0x6b, 0x44, + 0x43, 0x34, 0x00, 0x6b, 0x44, 0x43, 0x35, 0x00, 0x6b, 0x44, 0x43, 0x36, + 0x00, 0x6b, 0x44, 0x43, 0x37, 0x00, 0x6b, 0x44, 0x4e, 0x00, 0x6b, 0x44, + 0x4e, 0x33, 0x00, 0x6b, 0x44, 0x4e, 0x34, 0x00, 0x6b, 0x44, 0x4e, 0x35, + 0x00, 0x6b, 0x44, 0x4e, 0x36, 0x00, 0x6b, 0x44, 0x4e, 0x37, 0x00, 0x6b, + 0x45, 0x4e, 0x44, 0x33, 0x00, 0x6b, 0x45, 0x4e, 0x44, 0x34, 0x00, 0x6b, + 0x45, 0x4e, 0x44, 0x35, 0x00, 0x6b, 0x45, 0x4e, 0x44, 0x36, 0x00, 0x6b, + 0x45, 0x4e, 0x44, 0x37, 0x00, 0x6b, 0x48, 0x4f, 0x4d, 0x33, 0x00, 0x6b, + 0x48, 0x4f, 0x4d, 0x34, 0x00, 0x6b, 0x48, 0x4f, 0x4d, 0x35, 0x00, 0x6b, + 0x48, 0x4f, 0x4d, 0x36, 0x00, 0x6b, 0x48, 0x4f, 0x4d, 0x37, 0x00, 0x6b, + 0x49, 0x43, 0x33, 0x00, 0x6b, 0x49, 0x43, 0x34, 0x00, 0x6b, 0x49, 0x43, + 0x35, 0x00, 0x6b, 0x49, 0x43, 0x36, 0x00, 0x6b, 0x49, 0x43, 0x37, 0x00, + 0x6b, 0x4c, 0x46, 0x54, 0x33, 0x00, 0x6b, 0x4c, 0x46, 0x54, 0x34, 0x00, + 0x6b, 0x4c, 0x46, 0x54, 0x35, 0x00, 0x6b, 0x4c, 0x46, 0x54, 0x36, 0x00, + 0x6b, 0x4c, 0x46, 0x54, 0x37, 0x00, 0x6b, 0x4e, 0x58, 0x54, 0x33, 0x00, + 0x6b, 0x4e, 0x58, 0x54, 0x34, 0x00, 0x6b, 0x4e, 0x58, 0x54, 0x35, 0x00, + 0x6b, 0x4e, 0x58, 0x54, 0x36, 0x00, 0x6b, 0x4e, 0x58, 0x54, 0x37, 0x00, + 0x6b, 0x50, 0x52, 0x56, 0x33, 0x00, 0x6b, 0x50, 0x52, 0x56, 0x34, 0x00, + 0x6b, 0x50, 0x52, 0x56, 0x35, 0x00, 0x6b, 0x50, 0x52, 0x56, 0x36, 0x00, + 0x6b, 0x50, 0x52, 0x56, 0x37, 0x00, 0x6b, 0x52, 0x49, 0x54, 0x33, 0x00, + 0x6b, 0x52, 0x49, 0x54, 0x34, 0x00, 0x6b, 0x52, 0x49, 0x54, 0x35, 0x00, + 0x6b, 0x52, 0x49, 0x54, 0x36, 0x00, 0x6b, 0x52, 0x49, 0x54, 0x37, 0x00, + 0x6b, 0x55, 0x50, 0x00, 0x6b, 0x55, 0x50, 0x33, 0x00, 0x6b, 0x55, 0x50, + 0x34, 0x00, 0x6b, 0x55, 0x50, 0x35, 0x00, 0x6b, 0x55, 0x50, 0x36, 0x00, + 0x6b, 0x55, 0x50, 0x37, 0x00, 0x6b, 0x61, 0x32, 0x00, 0x6b, 0x62, 0x31, + 0x00, 0x6b, 0x62, 0x33, 0x00, 0x6b, 0x63, 0x32, 0x00, 0x6b, 0x70, 0x35, + 0x00, 0x6b, 0x70, 0x41, 0x44, 0x44, 0x00, 0x6b, 0x70, 0x43, 0x4d, 0x41, + 0x00, 0x6b, 0x70, 0x44, 0x49, 0x56, 0x00, 0x6b, 0x70, 0x44, 0x4f, 0x54, + 0x00, 0x6b, 0x70, 0x4d, 0x55, 0x4c, 0x00, 0x6b, 0x70, 0x53, 0x55, 0x42, + 0x00, 0x6b, 0x70, 0x5a, 0x52, 0x4f, 0x00, 0x72, 0x6d, 0x78, 0x78, 0x00, + 0x73, 0x6d, 0x78, 0x78, 0x00, 0x78, 0x6d, 0x00] + + xterm_extensions = + [:kEND5, :Cs, :kDN5, :Cr, :kDC6, :kPRV6, :kDN7, :kb1, :kpZRO, :kNXT6, + :kLFT5, :kPRV3, :kRIT4, :kDC4, :kc2, :kp5, :kLFT6, :kIC6, :kEND6, :kIC4, + :kRIT7, :rmxx, :kpADD, :xm, :kNXT3, :XT, :kIC7, :kHOM4, :kDC7, :kPRV7, + :ka2, :kUP7, :kDN6, :kIC5, :kNXT4, :kUP5, :AX, :kpSUB, :kb3, :kDN4, + :kHOM5, :kHOM6, :kDN3, :kLFT4, :kRIT5, :kIC3, :kPRV4, :kUP, :kRIT6, :E3, + :kEND3, :kHOM7, :kDC3, :kLFT7, :kNXT5, :Se, :Ss, :kHOM3, :kRIT3, :kNXT7, + :smxx, :kEND4, :kDN, :kUP6, :XM, :kPRV5, :kUP4, :kpDOT, :kpMUL, :kEND7, + :Ms, :kpCMA, :kDC5, :kLFT3, :kpDIV, :kUP3] + + xterm_capabilities = Dict{Symbol, Union{Bool, Int, String}}( + :AX => true, + :Cr => "\e]112\a", + :Cs => "\e]12;%p1%s\a", + :E3 => "\e[3J", + :Ms => "\e]52;%p1%s;%p2%s\a", + :OTbs => true, + :Se => "\e[2 q", + :Ss => "\e[%p1%d q", + :XM => "\e[?1006;1000%?%p1%{1}%=%th%el%;", + :XT => true, + :acs_chars => "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", + :acsc => "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~", + :am => true, + :auto_left_margin => false, + :auto_right_margin => true, + :back_color_erase => true, + :back_tab => "\e[Z", + :backspaces_with_bs => true, + :bce => true, + :bel => "\a", + :bell => "\a", + :blink => "\e[5m", + :bold => "\e[1m", + :bw => false, + :can_change => false, + :carriage_return => "\r", + :cbt => "\e[Z", + :ccc => false, + :ceol_standout_glitch => false, + :change_scroll_region => "\e[%i%p1%d;%p2%dr", + :chts => false, + :civis => "\e[?25l", + :clear => "\e[H\e[2J", + :clear_all_tabs => "\e[3g", + :clear_margins => "\e[?69l", + :clear_screen => "\e[H\e[2J", + :clr_bol => "\e[1K", + :clr_eol => "\e[K", + :clr_eos => "\e[J", + :cnorm => "\e[?12l\e[?25h", + :col_addr_glitch => false, + :colors => 8, + :cols => 80, + :column_address => "\e[%i%p1%dG", + :columns => 80, + :cpi_changes_res => false, + :cpix => false, + :cr => "\r", + :cr_cancels_micro_mode => false, + :crxm => false, + :csr => "\e[%i%p1%d;%p2%dr", + :cub => "\e[%p1%dD", + :cub1 => "\b", + :cud => "\e[%p1%dB", + :cud1 => "\n", + :cuf => "\e[%p1%dC", + :cuf1 => "\e[C", + :cup => "\e[%i%p1%d;%p2%dH", + :cursor_address => "\e[%i%p1%d;%p2%dH", + :cursor_down => "\n", + :cursor_home => "\e[H", + :cursor_invisible => "\e[?25l", + :cursor_left => "\b", + :cursor_normal => "\e[?12l\e[?25h", + :cursor_right => "\e[C", + :cursor_up => "\e[A", + :cursor_visible => "\e[?12;25h", + :cuu => "\e[%p1%dA", + :cuu1 => "\e[A", + :cvvis => "\e[?12;25h", + :da => false, + :daisy => false, + :db => false, + :dch => "\e[%p1%dP", + :dch1 => "\e[P", + :delete_character => "\e[P", + :delete_line => "\e[M", + :dest_tabs_magic_smso => false, + :dim => "\e[2m", + :dl => "\e[%p1%dM", + :dl1 => "\e[M", + :eat_newline_glitch => true, + :ech => "\e[%p1%dX", + :ed => "\e[J", + :el => "\e[K", + :el1 => "\e[1K", + :enter_alt_charset_mode => "\e(0", + :enter_am_mode => "\e[?7h", + :enter_blink_mode => "\e[5m", + :enter_bold_mode => "\e[1m", + :enter_ca_mode => "\e[?1049h\e[22;0;0t", + :enter_dim_mode => "\e[2m", + :enter_insert_mode => "\e[4h", + :enter_italics_mode => "\e[3m", + :enter_reverse_mode => "\e[7m", + :enter_secure_mode => "\e[8m", + :enter_standout_mode => "\e[7m", + :enter_underline_mode => "\e[4m", + :eo => false, + :erase_chars => "\e[%p1%dX", + :erase_overstrike => false, + :eslok => false, + :exit_alt_charset_mode => "\e(B", + :exit_am_mode => "\e[?7l", + :exit_attribute_mode => "\e(B\e[m", + :exit_ca_mode => "\e[?1049l\e[23;0;0t", + :exit_insert_mode => "\e[4l", + :exit_italics_mode => "\e[23m", + :exit_standout_mode => "\e[27m", + :exit_underline_mode => "\e[24m", + :flash => "\e[?5h\$<100/>\e[?5l", + :flash_screen => "\e[?5h\$<100/>\e[?5l", + :generic_type => false, + :gn => false, + :hard_copy => false, + :hard_cursor => false, + :has_meta_key => true, + :has_print_wheel => false, + :has_status_line => false, + :hc => false, + :hls => false, + :home => "\e[H", + :hpa => "\e[%i%p1%dG", + :hs => false, + :ht => "\t", + :hts => "\eH", + :hue_lightness_saturation => false, + :hz => false, + :ich => "\e[%p1%d@", + :il => "\e[%p1%dL", + :il1 => "\e[L", + :in => false, + :ind => "\n", + :indn => "\e[%p1%dS", + :init_2string => "\e[!p\e[?3;4l\e[4l\e>", + :init_tabs => 8, + :insert_line => "\e[L", + :insert_null_glitch => false, + :invis => "\e[8m", + :is2 => "\e[!p\e[?3;4l\e[4l\e>", + :it => 8, + :kDC => "\e[3;2~", + :kDC3 => "\e[3;3~", + :kDC4 => "\e[3;4~", + :kDC5 => "\e[3;5~", + :kDC6 => "\e[3;6~", + :kDC7 => "\e[3;7~", + :kDN => "\e[1;2B", + :kDN3 => "\e[1;3B", + :kDN4 => "\e[1;4B", + :kDN5 => "\e[1;5B", + :kDN6 => "\e[1;6B", + :kDN7 => "\e[1;7B", + :kEND => "\e[1;2F", + :kEND3 => "\e[1;3F", + :kEND4 => "\e[1;4F", + :kEND5 => "\e[1;5F", + :kEND6 => "\e[1;6F", + :kEND7 => "\e[1;7F", + :kHOM => "\e[1;2H", + :kHOM3 => "\e[1;3H", + :kHOM4 => "\e[1;4H", + :kHOM5 => "\e[1;5H", + :kHOM6 => "\e[1;6H", + :kHOM7 => "\e[1;7H", + :kIC => "\e[2;2~", + :kIC3 => "\e[2;3~", + :kIC4 => "\e[2;4~", + :kIC5 => "\e[2;5~", + :kIC6 => "\e[2;6~", + :kIC7 => "\e[2;7~", + :kLFT => "\e[1;2D", + :kLFT3 => "\e[1;3D", + :kLFT4 => "\e[1;4D", + :kLFT5 => "\e[1;5D", + :kLFT6 => "\e[1;6D", + :kLFT7 => "\e[1;7D", + :kNXT => "\e[6;2~", + :kNXT3 => "\e[6;3~", + :kNXT4 => "\e[6;4~", + :kNXT5 => "\e[6;5~", + :kNXT6 => "\e[6;6~", + :kNXT7 => "\e[6;7~", + :kPRV => "\e[5;2~", + :kPRV3 => "\e[5;3~", + :kPRV4 => "\e[5;4~", + :kPRV5 => "\e[5;5~", + :kPRV6 => "\e[5;6~", + :kPRV7 => "\e[5;7~", + :kRIT => "\e[1;2C", + :kRIT3 => "\e[1;3C", + :kRIT4 => "\e[1;4C", + :kRIT5 => "\e[1;5C", + :kRIT6 => "\e[1;6C", + :kRIT7 => "\e[1;7C", + :kUP => "\e[1;2A", + :kUP3 => "\e[1;3A", + :kUP4 => "\e[1;4A", + :kUP5 => "\e[1;5A", + :kUP6 => "\e[1;6A", + :kUP7 => "\e[1;7A", + :ka1 => "\eOw", + :ka2 => "\eOx", + :ka3 => "\eOy", + :kb1 => "\eOt", + :kb2 => "\eOu", + :kb3 => "\eOv", + :kbs => "\b", + :kc1 => "\eOq", + :kc2 => "\eOr", + :kc3 => "\eOs", + :kcbt => "\e[Z", + :kcub1 => "\eOD", + :kcud1 => "\eOB", + :kcuf1 => "\eOC", + :kcuu1 => "\eOA", + :kdch1 => "\e[3~", + :kend => "\eOF", + :kent => "\eOM", + :key_a1 => "\eOw", + :key_a3 => "\eOy", + :key_b2 => "\eOu", + :key_backspace => "\b", + :key_btab => "\e[Z", + :key_c1 => "\eOq", + :key_c3 => "\eOs", + :key_dc => "\e[3~", + :key_down => "\eOB", + :key_end => "\eOF", + :key_enter => "\eOM", + :key_f1 => "\eOP", + :key_f10 => "\e[21~", + :key_f11 => "\e[23~", + :key_f12 => "\e[24~", + :key_f13 => "\e[1;2P", + :key_f14 => "\e[1;2Q", + :key_f15 => "\e[1;2R", + :key_f16 => "\e[1;2S", + :key_f17 => "\e[15;2~", + :key_f18 => "\e[17;2~", + :key_f19 => "\e[18;2~", + :key_f2 => "\eOQ", + :key_f20 => "\e[19;2~", + :key_f21 => "\e[20;2~", + :key_f22 => "\e[21;2~", + :key_f23 => "\e[23;2~", + :key_f24 => "\e[24;2~", + :key_f25 => "\e[1;5P", + :key_f26 => "\e[1;5Q", + :key_f27 => "\e[1;5R", + :key_f28 => "\e[1;5S", + :key_f29 => "\e[15;5~", + :key_f3 => "\eOR", + :key_f30 => "\e[17;5~", + :key_f31 => "\e[18;5~", + :key_f32 => "\e[19;5~", + :key_f33 => "\e[20;5~", + :key_f34 => "\e[21;5~", + :key_f35 => "\e[23;5~", + :key_f36 => "\e[24;5~", + :key_f37 => "\e[1;6P", + :key_f38 => "\e[1;6Q", + :key_f39 => "\e[1;6R", + :key_f4 => "\eOS", + :key_f40 => "\e[1;6S", + :key_f41 => "\e[15;6~", + :key_f42 => "\e[17;6~", + :key_f43 => "\e[18;6~", + :key_f44 => "\e[19;6~", + :key_f45 => "\e[20;6~", + :key_f46 => "\e[21;6~", + :key_f47 => "\e[23;6~", + :key_f48 => "\e[24;6~", + :key_f49 => "\e[1;3P", + :key_f5 => "\e[15~", + :key_f50 => "\e[1;3Q", + :key_f51 => "\e[1;3R", + :key_f52 => "\e[1;3S", + :key_f53 => "\e[15;3~", + :key_f54 => "\e[17;3~", + :key_f55 => "\e[18;3~", + :key_f56 => "\e[19;3~", + :key_f57 => "\e[20;3~", + :key_f58 => "\e[21;3~", + :key_f59 => "\e[23;3~", + :key_f6 => "\e[17~", + :key_f60 => "\e[24;3~", + :key_f61 => "\e[1;4P", + :key_f62 => "\e[1;4Q", + :key_f63 => "\e[1;4R", + :key_f7 => "\e[18~", + :key_f8 => "\e[19~", + :key_f9 => "\e[20~", + :key_home => "\eOH", + :key_ic => "\e[2~", + :key_left => "\eOD", + :key_mouse => "\e[<", + :key_npage => "\e[6~", + :key_ppage => "\e[5~", + :key_right => "\eOC", + :key_sdc => "\e[3;2~", + :key_send => "\e[1;2F", + :key_sf => "\e[1;2B", + :key_shome => "\e[1;2H", + :key_sic => "\e[2;2~", + :key_sleft => "\e[1;2D", + :key_snext => "\e[6;2~", + :key_sprevious => "\e[5;2~", + :key_sr => "\e[1;2A", + :key_sright => "\e[1;2C", + :key_up => "\eOA", + :keypad_local => "\e[?1l\e>", + :keypad_xmit => "\e[?1h\e=", + :kf1 => "\eOP", + :kf10 => "\e[21~", + :kf11 => "\e[23~", + :kf12 => "\e[24~", + :kf13 => "\e[1;2P", + :kf14 => "\e[1;2Q", + :kf15 => "\e[1;2R", + :kf16 => "\e[1;2S", + :kf17 => "\e[15;2~", + :kf18 => "\e[17;2~", + :kf19 => "\e[18;2~", + :kf2 => "\eOQ", + :kf20 => "\e[19;2~", + :kf21 => "\e[20;2~", + :kf22 => "\e[21;2~", + :kf23 => "\e[23;2~", + :kf24 => "\e[24;2~", + :kf25 => "\e[1;5P", + :kf26 => "\e[1;5Q", + :kf27 => "\e[1;5R", + :kf28 => "\e[1;5S", + :kf29 => "\e[15;5~", + :kf3 => "\eOR", + :kf30 => "\e[17;5~", + :kf31 => "\e[18;5~", + :kf32 => "\e[19;5~", + :kf33 => "\e[20;5~", + :kf34 => "\e[21;5~", + :kf35 => "\e[23;5~", + :kf36 => "\e[24;5~", + :kf37 => "\e[1;6P", + :kf38 => "\e[1;6Q", + :kf39 => "\e[1;6R", + :kf4 => "\eOS", + :kf40 => "\e[1;6S", + :kf41 => "\e[15;6~", + :kf42 => "\e[17;6~", + :kf43 => "\e[18;6~", + :kf44 => "\e[19;6~", + :kf45 => "\e[20;6~", + :kf46 => "\e[21;6~", + :kf47 => "\e[23;6~", + :kf48 => "\e[24;6~", + :kf49 => "\e[1;3P", + :kf5 => "\e[15~", + :kf50 => "\e[1;3Q", + :kf51 => "\e[1;3R", + :kf52 => "\e[1;3S", + :kf53 => "\e[15;3~", + :kf54 => "\e[17;3~", + :kf55 => "\e[18;3~", + :kf56 => "\e[19;3~", + :kf57 => "\e[20;3~", + :kf58 => "\e[21;3~", + :kf59 => "\e[23;3~", + :kf6 => "\e[17~", + :kf60 => "\e[24;3~", + :kf61 => "\e[1;4P", + :kf62 => "\e[1;4Q", + :kf63 => "\e[1;4R", + :kf7 => "\e[18~", + :kf8 => "\e[19~", + :kf9 => "\e[20~", + :khome => "\eOH", + :kich1 => "\e[2~", + :kind => "\e[1;2B", + :km => true, + :kmous => "\e[<", + :knp => "\e[6~", + :kp5 => "\eOE", + :kpADD => "\eOk", + :kpCMA => "\eOl", + :kpDIV => "\eOo", + :kpDOT => "\eOn", + :kpMUL => "\eOj", + :kpSUB => "\eOm", + :kpZRO => "\eOp", + :kpp => "\e[5~", + :kri => "\e[1;2A", + :lines => 24, + :lpi_changes_res => false, + :lpix => false, + :max_colors => 8, + :max_pairs => 64, + :mc0 => "\e[i", + :mc4 => "\e[4i", + :mc5 => "\e[5i", + :mc5i => true, + :meml => "\el", + :memory_above => false, + :memory_below => false, + :memory_lock => "\el", + :memory_unlock => "\em", + :memu => "\em", + :meta_off => "\e[?1034l", + :meta_on => "\e[?1034h", + :mgc => "\e[?69l", + :mir => true, + :move_insert_mode => true, + :move_standout_mode => true, + :msgr => true, + :ndscr => false, + :needs_xon_xoff => false, + :no_esc_ctlc => false, + :no_pad_char => true, + :non_dest_scroll_region => false, + :non_rev_rmcup => false, + :npc => true, + :nrrmc => false, + :nxon => false, + :op => "\e[39;49m", + :orig_pair => "\e[39;49m", + :os => false, + :over_strike => false, + :pairs => 64, + :parm_dch => "\e[%p1%dP", + :parm_delete_line => "\e[%p1%dM", + :parm_down_cursor => "\e[%p1%dB", + :parm_ich => "\e[%p1%d@", + :parm_index => "\e[%p1%dS", + :parm_insert_line => "\e[%p1%dL", + :parm_left_cursor => "\e[%p1%dD", + :parm_right_cursor => "\e[%p1%dC", + :parm_rindex => "\e[%p1%dT", + :parm_up_cursor => "\e[%p1%dA", + :print_screen => "\e[i", + :prtr_off => "\e[4i", + :prtr_on => "\e[5i", + :prtr_silent => true, + :rc => "\e8", + :rep => "%p1%c\e[%p2%{1}%-%db", + :repeat_char => "%p1%c\e[%p2%{1}%-%db", + :reset_1string => "\ec", + :reset_2string => "\e[!p\e[?3;4l\e[4l\e>", + :restore_cursor => "\e8", + :rev => "\e[7m", + :ri => "\eM", + :rin => "\e[%p1%dT", + :ritm => "\e[23m", + :rmacs => "\e(B", + :rmam => "\e[?7l", + :rmcup => "\e[?1049l\e[23;0;0t", + :rmir => "\e[4l", + :rmkx => "\e[?1l\e>", + :rmm => "\e[?1034l", + :rmso => "\e[27m", + :rmul => "\e[24m", + :rmxx => "\e[29m", + :row_addr_glitch => false, + :row_address => "\e[%i%p1%dd", + :rs1 => "\ec", + :rs2 => "\e[!p\e[?3;4l\e[4l\e>", + :sam => false, + :save_cursor => "\e7", + :sc => "\e7", + :scroll_forward => "\n", + :scroll_reverse => "\eM", + :semi_auto_right_margin => false, + :set_a_background => "\e[4%p1%dm", + :set_a_foreground => "\e[3%p1%dm", + :set_attributes => "%?%p9%t\e(0%e\e(B%;\e[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m", + :set_background => "\e[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m", + :set_foreground => "\e[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m", + :set_lr_margin => "\e[?69h\e[%i%p1%d;%p2%ds", + :set_tab => "\eH", + :setab => "\e[4%p1%dm", + :setaf => "\e[3%p1%dm", + :setb => "\e[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m", + :setf => "\e[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m", + :sgr => "%?%p9%t\e(0%e\e(B%;\e[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m", + :sgr0 => "\e(B\e[m", + :sitm => "\e[3m", + :smacs => "\e(0", + :smam => "\e[?7h", + :smcup => "\e[?1049h\e[22;0;0t", + :smglr => "\e[?69h\e[%i%p1%d;%p2%ds", + :smir => "\e[4h", + :smkx => "\e[?1h\e=", + :smm => "\e[?1034h", + :smso => "\e[7m", + :smul => "\e[4m", + :smxx => "\e[9m", + :status_line_esc_ok => false, + :tab => "\t", + :tbc => "\e[3g", + :tilde_glitch => false, + :transparent_underline => false, + :u6 => "\e[%i%d;%dR", + :u7 => "\e[6n", + :u8 => "\e[?%[;0123456789]c", + :u9 => "\e[c", + :ul => false, + :user6 => "\e[%i%d;%dR", + :user7 => "\e[6n", + :user8 => "\e[?%[;0123456789]c", + :user9 => "\e[c", + :vpa => "\e[%i%p1%dd", + :xenl => true, + :xhp => false, + :xhpa => false, + :xm => "\e[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;", + :xon => false, + :xon_xoff => false, + :xsb => false, + :xt => false, + :xvpa => false) + +@testset "terminfo" begin + dumb = Base.TermInfo(read(IOBuffer(dumb_terminfo), Base.TermInfoRaw)) + @test dumb.names == ["dumb", "80-column dumb tty"] + @test dumb.flags == 2 + @test dumb.numbers == [true] + @test dumb.extensions == Symbol[] + @test length(dumb.capabilities) == 14 + for (key, value) in dumb_capabilities + @test dumb[key] == value + end + + xterm = Base.TermInfo(read(IOBuffer(xterm_terminfo), Base.TermInfoRaw)) + @test xterm.names == ["xterm", "xterm terminal emulator (X Window System)"] + @test xterm.flags == 38 + @test xterm.numbers == Bool[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] + @test sort(xterm.extensions) == sort(xterm_extensions) + @test length(xterm.capabilities) == 519 + for (key, value) in xterm_capabilities + @test xterm[key] == value + end +end + +end From 2205231b45b698ba78eb45d2cace41f674f326a5 Mon Sep 17 00:00:00 2001 From: TEC Date: Fri, 4 Aug 2023 14:02:46 +0100 Subject: [PATCH 4/4] Remove DCS-based TTY truecolor test The idea is still sound, but the REPL stdlib is not available in Base, and REPL.Terminals.raw! is non-trivial. Since this is the final fallback, and it's also been a bit flakey on various terminal emulators, we'll just remove it for now. --- base/terminfo.jl | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/base/terminfo.jl b/base/terminfo.jl index fc2b392871a06..c2844d189a3e5 100644 --- a/base/terminfo.jl +++ b/base/terminfo.jl @@ -274,36 +274,12 @@ is set to either `"truecolor"` or `"24bit"`. As a fallback, first on unix systems the `colors` terminal capability is checked — should more than 256 colors be reported, this is taken to signify 24-bit -support. Lastly, the color is attempted to be set to `#010203` and then the -current color queried via the DCS (Device Control String) sequence `\$qm`. If -the output contains `":1:2:3"` this is taken to signify 24-bit support. - -If the fallbacks are used, the `"COLORTERM"` entry in `ENV` is updated according -to the result. This ensures that frequent calls will only potentially be slow -the first time. +support. """ function ttyhastruecolor() - function test24bitcolor_dcs() - REPL.Terminals.raw!(REPL.TerminalMenus.terminal, true) - print(stdout, "\e[48;2;1;2;3m\eP\$qm\e\\\e[m") - flush(stdout) - # Some terminals are bad and haven't got DCS sequence support, - # if we don't see a response from stdin we need to abort. - output = @task readuntil(stdin, 'm') - schedule(output) - Timer(0.1) do _ - istaskdone(output) || Base.throwto(output, InterruptException()) - end - color::String = try - fetch(output) - catch _ "" end - REPL.Terminals.raw!(REPL.TerminalMenus.terminal, false) - occursin(":1:2:3", color) - end get(ENV, "COLORTERM", "") ∈ ("truecolor", "24bit") || @static if Sys.isunix() - get(current_terminfo, :colors, 0) > 256 || - isinteractive() && test24bitcolor_dcs() + get(current_terminfo, :colors, 0) > 256 else false end