class Toys::Utils::Terminal
* An array of ANSI codes as integers.
* An ANSI code string in ‘e[XXm` form.
* An rgb string in hex “rgb” or “rrggbb” form.
a defined style.
* A symbol indicating the name of a well-known style, or the name of
Styles may be specified in any of the following forms:
This class supports ANSI styled output where supported.
## Styles
A simple terminal class.
#
def self.remove_style_escapes(str)
-
(String)- String with styles removed
Parameters:
-
str(String) -- Input string
def self.remove_style_escapes(str) str.gsub(/\e\[\d+(;\d+)*m/, "") end
def <<(str)
-
(self)-
Parameters:
-
str(String) -- The line to write
def <<(str) puts(str) end
def apply_styles(str, *styles)
-
(String)- The styled string
Parameters:
-
styles(Symbol, String, Array) -- Styles to apply... -
str(String) -- String to style
def apply_styles(str, *styles) if styled prefix = escape_styles(*styles) suffix = prefix.empty? || str.end_with?(CLEAR_CODE) ? "" : CLEAR_CODE "#{prefix}#{str}#{suffix}" else Terminal.remove_style_escapes(str) end end
def ask(prompt, *styles, default: nil, trailing_text: :default)
-
(String)-
Parameters:
-
trailing_text(:default, String, nil) -- Trailing text appended to -
default(String, nil) -- Default value, or `nil` for no default. -
styles(Symbol, String, Array) -- Styles to apply to the... -
prompt(String) -- Required prompt string.
def ask(prompt, *styles, default: nil, trailing_text: :default) if trailing_text == :default trailing_text = default.nil? ? nil : "[#{default}]" end if trailing_text ptext, pspaces, = prompt.partition(/\s+$/) prompt = "#{ptext} #{trailing_text}#{pspaces}" end write(prompt, *styles) resp = readline.to_s.chomp resp.empty? ? default.to_s : resp end
def close
a log device target, but it does not actually close anything.
This method is defined so that `::Logger` will recognize a terminal as
#
def close nil end
def confirm(prompt = "Proceed? ", *styles, default: nil)
-
(Boolean)-
Parameters:
-
default(Boolean, nil) -- Default value, or `nil` for no default. -
styles(Symbol, String, Array) -- Styles to apply to the... -
prompt(String) -- Prompt string. Defaults to `"Proceed?"`.
def confirm(prompt = "Proceed? ", *styles, default: nil) default_val, trailing_text = case default when true ["y", "(Y/n)"] when false ["n", "(y/N)"] else [nil, "(y/n)"] end resp = ask(prompt, *styles, default: default_val, trailing_text: trailing_text) return true if resp =~ /^y/i return false if resp =~ /^n/i if resp.nil? && default.nil? raise TerminalError, "Cannot confirm because the input stream is at eof." end if !resp.strip.empty? || default.nil? if input.nil? raise TerminalError, "Cannot confirm because there is no input stream." end confirm('Please answer "y" or "n"', default: default) else default end end
def define_style(name, *styles)
-
(self)-
Parameters:
-
styles(Symbol, String, Array) --... -
name(Symbol) -- The name for the style
def define_style(name, *styles) @named_styles[name] = resolve_styles(*styles) self end
def escape_styles(*styles)
Resolve a style to an ANSI style escape sequence.
#
def escape_styles(*styles) codes = resolve_styles(*styles) codes.empty? ? "" : "\e[#{codes.join(';')}m" end
def height
-
(Integer)-
def height size[1] end
def initialize(input: $stdin, output: $stdout, styled: nil)
-
styled(Boolean, nil) -- Whether to output ansi styles. If `nil`, the -
output(IO, Logger, nil) -- Output stream or logger. -
input(IO, nil) -- Input stream.
def initialize(input: $stdin, output: $stdout, styled: nil) @input = input @output = output @styled = if styled.nil? output.respond_to?(:tty?) && output.tty? else styled ? true : false end @named_styles = BUILTIN_STYLE_NAMES.dup @output_mutex = ::Monitor.new @input_mutex = ::Monitor.new end
def interpret_style_string(style)
Transform various style string formats into a list of style codes.
#
def interpret_style_string(style) case style when /^[0-9a-fA-F]{6}$/ rgb = style.to_i(16) [38, 2, rgb >> 16, (rgb & 0xff00) >> 8, rgb & 0xff] when /^[0-9a-fA-F]{3}$/ rgb = style.to_i(16) [38, 2, (rgb >> 8) * 0x11, ((rgb & 0xf0) >> 4) * 0x11, (rgb & 0xf) * 0x11] when /^\e\[([\d;]+)m$/ ::Regexp.last_match(1).split(";").map(&:to_i) end end
def newline
-
(self)-
def newline puts end
def puts(str = "", *styles)
-
(self)-
Parameters:
-
styles(Symbol, String, Array) -- Styles to apply to the... -
str(String) -- The line to write
def puts(str = "", *styles) str = "#{str}\n" unless str.end_with?("\n") write(str, *styles) end
def readline
-
(nil)- if the input is closed or at eof, or there is no input -
(String)- the entire string including the temrinating newline
def readline @input_mutex.synchronize do begin input&.gets rescue ::IOError nil end end end
def resolve_styles(*styles)
Resolve a style to an array of ANSI style codes (integers).
#
def resolve_styles(*styles) result = [] styles.each do |style| codes = case style when ::Array style when ::String interpret_style_string(style) when ::Symbol @named_styles[style] end raise ::ArgumentError, "Unknown style code: #{s.inspect}" unless codes result.concat(codes) end result end
def size
-
(Array(Integer,Integer))-
def size if output.respond_to?(:tty?) && output.tty? && output.respond_to?(:winsize) output.winsize.reverse else [80, 25] end end
def spinner(leading_text: "", final_text: "",
-
(Object)- The return value of the block.
Parameters:
-
final_text(String) -- Optional final string to display when the -
style(Symbol, Array) -- A terminal style or array of styles -
frames(Array) -- An array of frames. Defaults to -
frame_length(Float) -- Length of a single frame, in seconds. -
leading_text(String) -- Optional leading string to display to the
def spinner(leading_text: "", final_text: "", frame_length: nil, frames: nil, style: nil) return nil unless block_given? frame_length ||= DEFAULT_SPINNER_FRAME_LENGTH frames ||= DEFAULT_SPINNER_FRAMES write(leading_text) unless leading_text.empty? spin = SpinDriver.new(self, frames, Array(style), frame_length) begin yield ensure spin.stop write(final_text) unless final_text.empty? end end
def width
-
(Integer)-
def width size[0] end
def write(str = "", *styles)
-
(self)-
Parameters:
-
styles(Symbol, String, Array) -- Styles to apply to the... -
str(String) -- The line to write
def write(str = "", *styles) @output_mutex.synchronize do begin output&.write(apply_styles(str, *styles)) output&.flush rescue ::IOError nil end end self end