-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce a new class Reline::Face to configure character attributes (#…
…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 <[email protected]> * Update test/reline/test_face.rb Co-authored-by: Stan Lo <[email protected]> * Fix to correspond to frozen_string_literal * Face::FaceConfig -> Face::Config * ref #552 (review) * delete unused ivar * ref #552 (comment) * insert "\e[0m" into all SGR * tiny fix * ESSENTIAL_DEFINE_NAMES ref #552 (comment) * 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 #552 (review) * 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 <[email protected]> * Update test/reline/test_face.rb Co-authored-by: Stan Lo <[email protected]> * Add methods: load_initial_config and reset_to_initial_config. And teardown in tests * omission in amending "style: :default" to "style: :reset" * refs #598 * Fix link * amend method name * Update lib/reline/face.rb Co-authored-by: ima1zumi <[email protected]> --------- Co-authored-by: Stan Lo <[email protected]> Co-authored-by: ima1zumi <[email protected]>
- Loading branch information
1 parent
e094be0
commit fdc1d3b
Showing
11 changed files
with
590 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ | |
/.yardoc | ||
/_yardoc/ | ||
/coverage/ | ||
/doc/ | ||
/pkg/ | ||
/spec/reports/ | ||
/tmp/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,5 +12,6 @@ end | |
gem 'bundler' | ||
gem 'rake' | ||
gem 'test-unit' | ||
gem 'test-unit-rr' | ||
|
||
gem 'racc' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# Face | ||
|
||
With the `Reline::Face` class, you can modify the text color and text decorations in your terminal emulator. | ||
This is primarily used to customize the appearance of the method completion dialog in IRB. | ||
|
||
## Usage | ||
|
||
### ex: Change the background color of the completion dialog cyan to blue | ||
|
||
```ruby | ||
Reline::Face.config(:completion_dialog) do |conf| | ||
conf.define :default, foreground: :white, background: :blue | ||
# ^^^^^ `:cyan` by default | ||
conf.define :enhanced, foreground: :white, background: :magenta | ||
conf.define :scrollbar, foreground: :white, background: :blue | ||
end | ||
``` | ||
|
||
If you provide the above code to an IRB session in some way, you can apply the configuration. | ||
It's generally done by writing it in `.irbrc`. | ||
|
||
Regarding `.irbrc`, please refer to the following link: [https://docs.ruby-lang.org/en/master/IRB.html](https://docs.ruby-lang.org/en/master/IRB.html) | ||
|
||
## Available parameters | ||
|
||
`Reline::Face` internally creates SGR (Select Graphic Rendition) code according to the block parameter of `Reline::Face.config` method. | ||
|
||
| Key | Value | SGR Code (numeric part following "\e[")| | ||
|:------------|:------------------|-----:| | ||
| :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 | | ||
|
||
- The value for `:style` can be both a Symbol and an Array | ||
```ruby | ||
# Single symbol | ||
conf.define :default, style: :bold | ||
# Array | ||
conf.define :default, style: [:bold, :negative] | ||
``` | ||
- The availability of specific SGR codes depends on your terminal emulator | ||
- You can specify a hex color code to `:foreground` and `:background` color like `foreground: "#FF1020"`. Its availability also depends on your terminal emulator | ||
|
||
## Debugging | ||
|
||
You can see the current Face configuration by `Reline::Face.configs` method | ||
|
||
Example: | ||
|
||
```ruby | ||
irb(main):001:0> Reline::Face.configs | ||
=> | ||
{:default=> | ||
{:default=>{:style=>:reset, :escape_sequence=>"\e[0m"}, | ||
:enhanced=>{:style=>:reset, :escape_sequence=>"\e[0m"}, | ||
:scrollbar=>{:style=>:reset, :escape_sequence=>"\e[0m"}}, | ||
:completion_dialog=> | ||
{:default=>{:foreground=>:white, :background=>:cyan, :escape_sequence=>"\e[0m\e[37;46m"}, | ||
:enhanced=>{:foreground=>:white, :background=>:magenta, :escape_sequence=>"\e[0m\e[37;45m"}, | ||
:scrollbar=>{:foreground=>:white, :background=>:cyan, :escape_sequence=>"\e[0m\e[37;46m"}}} | ||
``` | ||
|
||
## Backlog | ||
|
||
- Support for 256-color terminal emulator. Fallback hex color code such as "#FF1020" to 256 colors | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
|
||
require 'reline' | ||
require 'test/unit' | ||
require 'test/unit/rr' | ||
|
||
begin | ||
require 'rbconfig' | ||
|
Oops, something went wrong.