mirror of
https://github.com/ruby/ruby.git
synced 2025-09-20 11:03:58 +02:00

character attributes
(https://github.com/ruby/reline/pull/552)
* Reine::Face
* fix test_yamatanooroti
* Define singleton methods to make accessors to attributes of a face
* s/display/foreground/
* s/default/default_style/ && s/normal_line/default/ && s/enhanced_line/enhanced/
* fix typo
* FaceConfig.new now takes keyword arguments
* Update lib/reline/face.rb
Co-authored-by: Stan Lo <stan001212@gmail.com>
* Update test/reline/test_face.rb
Co-authored-by: Stan Lo <stan001212@gmail.com>
* Fix to correspond to frozen_string_literal
* Face::FaceConfig -> Face::Config
* ref https://github.com/ruby/reline/pull/552#pullrequestreview-1677282576
* delete unused ivar
* ref https://github.com/ruby/reline/pull/552#discussion_r1358783723
* insert "\e[0m" into all SGR
* tiny fix
* ESSENTIAL_DEFINE_NAMES
ref https://github.com/ruby/reline/pull/552#discussion_r1367722247
* Change to Hash-accessor style
- Reline::Face[:completion_dialog].enhanced ->
Reline::Face[:completion_dialog][:enhanced]
- Reline::Face.configs shows all defined values
* Cache array method call in local variable
* Tests for Face configuration variations
* resolve https://github.com/ruby/reline/pull/552#pullrequestreview-1710938154
* amend to
* check invalid SGR parameter in :style
* The order of define values should be preserved
* Update test/reline/test_face.rb
Co-authored-by: Stan Lo <stan001212@gmail.com>
* Update test/reline/test_face.rb
Co-authored-by: Stan Lo <stan001212@gmail.com>
* Add methods: load_initial_config and reset_to_initial_config. And teardown in tests
* omission in amending "style: :default" to "style: :reset"
* refs https://github.com/ruby/reline/issues/598
* Fix link
* amend method name
* Update lib/reline/face.rb
Co-authored-by: ima1zumi <52617472+ima1zumi@users.noreply.github.com>
---------
fdc1d3b1e5
Co-authored-by: Stan Lo <stan001212@gmail.com>
Co-authored-by: ima1zumi <52617472+ima1zumi@users.noreply.github.com>
157 lines
3.6 KiB
Ruby
157 lines
3.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Reline::Face
|
|
SGR_PARAMETERS = {
|
|
foreground: {
|
|
black: 30,
|
|
red: 31,
|
|
green: 32,
|
|
yellow: 33,
|
|
blue: 34,
|
|
magenta: 35,
|
|
cyan: 36,
|
|
white: 37,
|
|
bright_black: 90,
|
|
gray: 90,
|
|
bright_red: 91,
|
|
bright_green: 92,
|
|
bright_yellow: 93,
|
|
bright_blue: 94,
|
|
bright_magenta: 95,
|
|
bright_cyan: 96,
|
|
bright_white: 97
|
|
},
|
|
background: {
|
|
black: 40,
|
|
red: 41,
|
|
green: 42,
|
|
yellow: 43,
|
|
blue: 44,
|
|
magenta: 45,
|
|
cyan: 46,
|
|
white: 47,
|
|
bright_black: 100,
|
|
gray: 100,
|
|
bright_red: 101,
|
|
bright_green: 102,
|
|
bright_yellow: 103,
|
|
bright_blue: 104,
|
|
bright_magenta: 105,
|
|
bright_cyan: 106,
|
|
bright_white: 107,
|
|
},
|
|
style: {
|
|
reset: 0,
|
|
bold: 1,
|
|
faint: 2,
|
|
italicized: 3,
|
|
underlined: 4,
|
|
slowly_blinking: 5,
|
|
blinking: 5,
|
|
rapidly_blinking: 6,
|
|
negative: 7,
|
|
concealed: 8,
|
|
crossed_out: 9
|
|
}
|
|
}.freeze
|
|
|
|
class Config
|
|
ESSENTIAL_DEFINE_NAMES = %i(default enhanced scrollbar).freeze
|
|
RESET_SGR = "\e[0m".freeze
|
|
|
|
def initialize(name, &block)
|
|
@definition = {}
|
|
block.call(self)
|
|
ESSENTIAL_DEFINE_NAMES.each do |name|
|
|
@definition[name] ||= { style: :reset, escape_sequence: RESET_SGR }
|
|
end
|
|
end
|
|
|
|
attr_reader :definition
|
|
|
|
def define(name, **values)
|
|
values[:escape_sequence] = format_to_sgr(values.to_a).freeze
|
|
@definition[name] = values
|
|
end
|
|
|
|
def [](name)
|
|
@definition.dig(name, :escape_sequence) or raise ArgumentError, "unknown face: #{name}"
|
|
end
|
|
|
|
private
|
|
|
|
def sgr_rgb(key, value)
|
|
return nil unless rgb_expression?(value)
|
|
case key
|
|
when :foreground
|
|
"38;2;"
|
|
when :background
|
|
"48;2;"
|
|
end + value[1, 6].scan(/../).map(&:hex).join(";")
|
|
end
|
|
|
|
def format_to_sgr(ordered_values)
|
|
sgr = "\e[" + ordered_values.map do |key_value|
|
|
key, value = key_value
|
|
case key
|
|
when :foreground, :background
|
|
case value
|
|
when Symbol
|
|
SGR_PARAMETERS[key][value]
|
|
when String
|
|
sgr_rgb(key, value)
|
|
end
|
|
when :style
|
|
[ value ].flatten.map do |style_name|
|
|
SGR_PARAMETERS[:style][style_name]
|
|
end.then do |sgr_parameters|
|
|
sgr_parameters.include?(nil) ? nil : sgr_parameters
|
|
end
|
|
end.then do |rendition_expression|
|
|
unless rendition_expression
|
|
raise ArgumentError, "invalid SGR parameter: #{value.inspect}"
|
|
end
|
|
rendition_expression
|
|
end
|
|
end.join(';') + "m"
|
|
sgr == RESET_SGR ? RESET_SGR : RESET_SGR + sgr
|
|
end
|
|
|
|
def rgb_expression?(color)
|
|
color.respond_to?(:match?) and color.match?(/\A#[0-9a-fA-F]{6}\z/)
|
|
end
|
|
end
|
|
|
|
private_constant :SGR_PARAMETERS, :Config
|
|
|
|
def self.[](name)
|
|
@configs[name]
|
|
end
|
|
|
|
def self.config(name, &block)
|
|
@configs ||= {}
|
|
@configs[name] = Config.new(name, &block)
|
|
end
|
|
|
|
def self.configs
|
|
@configs.transform_values(&:definition)
|
|
end
|
|
|
|
def self.load_initial_configs
|
|
config(:default) do |conf|
|
|
conf.define :default, style: :reset
|
|
conf.define :enhanced, style: :reset
|
|
conf.define :scrollbar, style: :reset
|
|
end
|
|
config(:completion_dialog) do |conf|
|
|
conf.define :default, foreground: :white, background: :cyan
|
|
conf.define :enhanced, foreground: :white, background: :magenta
|
|
conf.define :scrollbar, foreground: :white, background: :cyan
|
|
end
|
|
end
|
|
|
|
def self.reset_to_initial_configs
|
|
@configs = {}
|
|
load_initial_configs
|
|
end
|
|
end
|