Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 96
Introduce a new class Reline::Face to configure character attributes#552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
122486317114b9e033f88629db24a993e52cab307fe4d61dd0e7acfbb442c57389ff41c3f92f1d652fc015505196e4b4e9e8eb85b7ea200e26cb1159286c59f00134828197beefb75ede7a6d565a5308467a8497c02205c728ca2dcde902e23d23602eee3b076dd7b01ce48187c5133ca33109f544f3d1File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2,7 +2,6 @@ | ||
| /.yardoc | ||
| /_yardoc/ | ||
| /coverage/ | ||
| /doc/ | ||
| /pkg/ | ||
| /spec/reports/ | ||
| /tmp/ | ||
| 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' | ||
| 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 | ||
| 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 | ||
Comment on lines
+141
to
+145
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this config required for? It does not appear to be used.
| ||
| 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 | ||
| 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' | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.