class CLI::UI::Formatter
Constants
- BEGIN_EXPR
- DISCARD_BRACES
- END_EXPR
- LITERAL_BRACES
- SCAN_BODY
- SCAN_FUNCNAME
- SCAN_GLYPH
- SCAN_WIDGET
- SGR_MAP
Available mappings of formattings To use any of them, you can use {{<key>:<string>}} There are presentational (colours and formatters) and semantic (error, info, command) formatters available
Public Class Methods
Public Instance Methods
format(sgr_map = SGR_MAP, enable_color: CLI::UI.enable_color?)
click to toggle source
Format the text using a map.
Attributes¶ ↑
-
sgr_map
- the mapping of the formattings. Defaults toSGR_MAP
Options¶ ↑
-
:enable_color
- enable color output? Default is true unless output is redirected
# File lib/cli/ui/formatter.rb, line 84 def format(sgr_map = SGR_MAP, enable_color: CLI::UI.enable_color?) @nodes = [] stack = parse_body(StringScanner.new(@text)) prev_fmt = nil content = @nodes.each_with_object(+'') do |(text, fmt), str| if prev_fmt != fmt && enable_color text = apply_format(text, fmt, sgr_map) end str << text prev_fmt = fmt end stack.reject! { |e| e == LITERAL_BRACES } return content unless enable_color return content if stack == prev_fmt unless stack.empty? && (@nodes.size.zero? || @nodes.last[1].empty?) content << apply_format('', stack, sgr_map) end content end
Private Instance Methods
apply_format(text, fmt, sgr_map)
click to toggle source
# File lib/cli/ui/formatter.rb, line 109 def apply_format(text, fmt, sgr_map) sgr = fmt.each_with_object(+'0') do |name, str| next if name == LITERAL_BRACES begin str << ';' << sgr_map.fetch(name) rescue KeyError raise FormatError.new( "invalid format specifier: #{name}", @text, -1 ) end end CLI::UI::ANSI.sgr(sgr) + text end
emit(text, stack)
click to toggle source
# File lib/cli/ui/formatter.rb, line 186 def emit(text, stack) return if text.nil? || text.empty? @nodes << [text, stack.reject { |n| n == LITERAL_BRACES }] end
parse_body(sc, stack = [])
click to toggle source
# File lib/cli/ui/formatter.rb, line 167 def parse_body(sc, stack = []) match = sc.scan(SCAN_BODY) if match&.end_with?(BEGIN_EXPR) emit(match[DISCARD_BRACES], stack) parse_expr(sc, stack) elsif match&.end_with?(END_EXPR) emit(match[DISCARD_BRACES], stack) if stack.pop == LITERAL_BRACES emit('}}', stack) end parse_body(sc, stack) elsif match emit(match, stack) else emit(sc.rest, stack) end stack end
parse_expr(sc, stack)
click to toggle source
# File lib/cli/ui/formatter.rb, line 125 def parse_expr(sc, stack) if (match = sc.scan(SCAN_GLYPH)) glyph_handle = match[0] begin glyph = Glyph.lookup(glyph_handle) emit(glyph.char, [glyph.color.name.to_s]) rescue Glyph::InvalidGlyphHandle index = sc.pos - 2 # rewind past '}}' raise FormatError.new( "invalid glyph handle at index #{index}: '#{glyph_handle}'", @text, index ) end elsif (match = sc.scan(SCAN_WIDGET)) match_data = SCAN_WIDGET.match(match) # Regexp.last_match doesn't work here widget_handle = match_data['handle'] begin widget = Widgets.lookup(widget_handle) emit(widget.call(match_data['args']), stack) rescue Widgets::InvalidWidgetHandle index = sc.pos - 2 # rewind past '}}' raise(FormatError.new( "invalid widget handle at index #{index}: '#{widget_handle}'", @text, index, )) end elsif (match = sc.scan(SCAN_FUNCNAME)) funcname = match.chop stack.push(funcname) else # We read a {{ but it's not apparently Formatter syntax. # We could error, but it's nicer to just pass through as text. # We do kind of assume that the text will probably have balanced # pairs of {{ }} at least. emit('{{', stack) stack.push(LITERAL_BRACES) end parse_body(sc, stack) stack end