aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHASUMI Hitoshi <hasumikin@gmail.com>2023-11-06 23:40:38 +0900
committergit <svn-admin@ruby-lang.org>2023-11-06 14:40:42 +0000
commit16403f41abcbaccf32484d10575d3542dbb3247e (patch)
treeafca50d51bcb5bcb432dc35581fa7f251ea02dc0
parentf6ba87ca8899cd753306ffbca475b16c367995a3 (diff)
downloadruby-16403f41abcbaccf32484d10575d3542dbb3247e.tar.gz
[ruby/reline] Introduce a new class Reline::Face to configure
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> --------- https://github.com/ruby/reline/commit/fdc1d3b1e5 Co-authored-by: Stan Lo <stan001212@gmail.com> Co-authored-by: ima1zumi <52617472+ima1zumi@users.noreply.github.com>
-rw-r--r--doc/reline/face.md108
-rw-r--r--lib/reline.rb14
-rw-r--r--lib/reline/face.rb157
-rw-r--r--lib/reline/line_editor.rb23
-rw-r--r--test/reline/helper.rb1
-rw-r--r--test/reline/test_face.rb204
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl2
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb155
8 files changed, 582 insertions, 82 deletions
diff --git a/doc/reline/face.md b/doc/reline/face.md
new file mode 100644
index 0000000000..cf3bb69440
--- /dev/null
+++ b/doc/reline/face.md
@@ -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
+
diff --git a/lib/reline.rb b/lib/reline.rb
index 3d1716c81b..fb19982081 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -7,6 +7,7 @@ require 'reline/key_stroke'
require 'reline/line_editor'
require 'reline/history'
require 'reline/terminfo'
+require 'reline/face'
require 'rbconfig'
module Reline
@@ -36,10 +37,8 @@ module Reline
DialogRenderInfo = Struct.new(
:pos,
:contents,
- :bg_color,
- :pointer_bg_color,
- :fg_color,
- :pointer_fg_color,
+ :face,
+ :bg_color, # For the time being, this line should stay here for the compatibility with IRB.
:width,
:height,
:scrollbar,
@@ -260,10 +259,7 @@ module Reline
contents: result,
scrollbar: true,
height: [15, preferred_dialog_height].min,
- bg_color: 46,
- pointer_bg_color: 45,
- fg_color: 37,
- pointer_fg_color: 37
+ face: :completion_dialog
)
}
Reline::DEFAULT_DIALOG_CONTEXT = Array.new
@@ -606,4 +602,6 @@ else
io
end
+Reline::Face.load_initial_configs
+
Reline::HISTORY = Reline::History.new(Reline.core.config)
diff --git a/lib/reline/face.rb b/lib/reline/face.rb
new file mode 100644
index 0000000000..b78f3b1ca5
--- /dev/null
+++ b/lib/reline/face.rb
@@ -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
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 0d990c2c0a..d71b903701 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -831,27 +831,24 @@ class Reline::LineEditor
dialog.column = 0
dialog.width = @screen_size.last
end
+ face = Reline::Face[dialog_render_info.face || :default]
+ scrollbar_sgr = face[:scrollbar]
+ default_sgr = face[:default]
+ enhanced_sgr = face[:enhanced]
dialog.contents = contents.map.with_index do |item, i|
- if i == pointer
- fg_color = dialog_render_info.pointer_fg_color
- bg_color = dialog_render_info.pointer_bg_color
- else
- fg_color = dialog_render_info.fg_color
- bg_color = dialog_render_info.bg_color
- end
+ line_sgr = i == pointer ? enhanced_sgr : default_sgr
str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
- colored_content = "\e[#{bg_color}m\e[#{fg_color}m#{str}"
+ colored_content = "#{line_sgr}#{str}"
if scrollbar_pos
- color_seq = "\e[37m"
if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
- colored_content + color_seq + @full_block
+ colored_content + scrollbar_sgr + @full_block
elsif scrollbar_pos <= (i * 2) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + color_seq + @upper_half_block
+ colored_content + scrollbar_sgr + @upper_half_block
elsif scrollbar_pos <= (i * 2 + 1) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + color_seq + @lower_half_block
+ colored_content + scrollbar_sgr + @lower_half_block
else
- colored_content + color_seq + ' ' * @block_elem_width
+ colored_content + scrollbar_sgr + ' ' * @block_elem_width
end
else
colored_content
diff --git a/test/reline/helper.rb b/test/reline/helper.rb
index fb2262e7f5..4d0c883c86 100644
--- a/test/reline/helper.rb
+++ b/test/reline/helper.rb
@@ -4,6 +4,7 @@ ENV['TERM'] = 'xterm' # for some CI environments
require 'reline'
require 'test/unit'
+require 'test/unit/rr'
begin
require 'rbconfig'
diff --git a/test/reline/test_face.rb b/test/reline/test_face.rb
new file mode 100644
index 0000000000..371b4b0d2e
--- /dev/null
+++ b/test/reline/test_face.rb
@@ -0,0 +1,204 @@
+# frozen_string_literal: true
+
+require_relative 'helper'
+
+class Reline::Face::Test < Reline::TestCase
+ RESET_SGR = "\e[0m"
+
+ def teardown
+ Reline::Face.reset_to_initial_configs
+ end
+
+ class WithInsufficientSetupTest < self
+ def setup
+ Reline::Face.config(:my_insufficient_config) do |face|
+ end
+ @face = Reline::Face[:my_insufficient_config]
+ end
+
+ def test_my_insufficient_config_line
+ assert_equal RESET_SGR, @face[:default]
+ assert_equal RESET_SGR, @face[:enhanced]
+ assert_equal RESET_SGR, @face[:scrollbar]
+ end
+
+ def test_my_insufficient_configs
+ my_configs = Reline::Face.configs[:my_insufficient_config]
+ assert_equal(
+ {
+ default: { style: :reset, escape_sequence: RESET_SGR },
+ enhanced: { style: :reset, escape_sequence: RESET_SGR },
+ scrollbar: { style: :reset, escape_sequence: RESET_SGR }
+ },
+ my_configs
+ )
+ end
+ end
+
+ class WithSetupTest < self
+ def setup
+ Reline::Face.config(:my_config) do |face|
+ face.define :default, foreground: :blue
+ face.define :enhanced, foreground: "#FF1020", background: :black, style: [:bold, :underlined]
+ end
+ Reline::Face.config(:another_config) do |face|
+ face.define :another_label, foreground: :red
+ end
+ @face = Reline::Face[:my_config]
+ end
+
+ def test_now_there_are_four_configs
+ assert_equal %i(default completion_dialog my_config another_config), Reline::Face.configs.keys
+ end
+
+ def test_resetting_config_discards_user_defined_configs
+ Reline::Face.reset_to_initial_configs
+ assert_equal %i(default completion_dialog), Reline::Face.configs.keys
+ end
+
+ def test_my_configs
+ my_configs = Reline::Face.configs[:my_config]
+ assert_equal(
+ {
+ default: {
+ escape_sequence: "#{RESET_SGR}\e[34m", foreground: :blue
+ },
+ enhanced: {
+ background: :black,
+ foreground: "#FF1020",
+ style: [:bold, :underlined],
+ escape_sequence: "\e[0m\e[38;2;255;16;32;40;1;4m"
+ },
+ scrollbar: {
+ style: :reset,
+ escape_sequence: "\e[0m"
+ }
+ },
+ my_configs
+ )
+ end
+
+ def test_my_config_line
+ assert_equal "#{RESET_SGR}\e[34m", @face[:default]
+ end
+
+ def test_my_config_enhanced
+ assert_equal "#{RESET_SGR}\e[38;2;255;16;32;40;1;4m", @face[:enhanced]
+ end
+
+ def test_not_respond_to_another_label
+ assert_equal false, @face.respond_to?(:another_label)
+ end
+ end
+
+ class WithoutSetupTest < self
+ def test_my_config_default
+ Reline::Face.config(:my_config) do |face|
+ # do nothing
+ end
+ face = Reline::Face[:my_config]
+ assert_equal RESET_SGR, face[:default]
+ end
+
+ def test_style_does_not_exist
+ face = Reline::Face[:default]
+ assert_raise ArgumentError do
+ face[:style_does_not_exist]
+ end
+ end
+
+ def test_invalid_keyword
+ assert_raise ArgumentError do
+ Reline::Face.config(:invalid_config) do |face|
+ face.define :default, invalid_keyword: :red
+ end
+ end
+ end
+
+ def test_invalid_foreground_name
+ assert_raise ArgumentError do
+ Reline::Face.config(:invalid_config) do |face|
+ face.define :default, foreground: :invalid_name
+ end
+ end
+ end
+
+ def test_invalid_background_name
+ assert_raise ArgumentError do
+ Reline::Face.config(:invalid_config) do |face|
+ face.define :default, background: :invalid_name
+ end
+ end
+ end
+
+ def test_invalid_style_name
+ assert_raise ArgumentError do
+ Reline::Face.config(:invalid_config) do |face|
+ face.define :default, style: :invalid_name
+ end
+ end
+ end
+
+ def test_private_constants
+ [:SGR_PARAMETER, :Config, :CONFIGS].each do |name|
+ assert_equal false, Reline::Face.constants.include?(name)
+ end
+ end
+ end
+
+ class ConfigTest < self
+ def setup
+ @config = Reline::Face.const_get(:Config).new(:my_config) { }
+ end
+
+ def test_the_order_of_define_values_should_be_preserved
+ any_instance_of(Reline::Face.const_get(:Config)) do |config|
+ mock(config).format_to_sgr(
+ [[:foreground, :blue], [:style, [:bold, :italicized]], [:background, :red]]
+ )
+ end
+ Reline::Face.config(:my_config) do |face|
+ face.define :default, foreground: :blue, style: [:bold, :italicized], background: :red
+ end
+ end
+
+ def test_rgb?
+ assert_equal true, @config.send(:rgb_expression?, "#FFFFFF")
+ end
+
+ def test_invalid_rgb?
+ assert_equal false, @config.send(:rgb_expression?, "FFFFFF")
+ assert_equal false, @config.send(:rgb_expression?, "#FFFFF")
+ end
+
+ def test_format_to_sgr
+ assert_equal(
+ "#{RESET_SGR}\e[37;41;1;3m",
+ @config.send(:format_to_sgr, foreground: :white, background: :red, style: [:bold, :italicized])
+ )
+ end
+
+ def test_format_to_sgr_with_reset
+ assert_equal(
+ RESET_SGR,
+ @config.send(:format_to_sgr, style: :reset)
+ )
+ assert_equal(
+ "#{RESET_SGR}\e[37;0;41m",
+ @config.send(:format_to_sgr, foreground: :white, style: :reset, background: :red)
+ )
+ end
+
+ def test_format_to_sgr_with_single_style
+ assert_equal(
+ "#{RESET_SGR}\e[37;41;1m",
+ @config.send(:format_to_sgr, foreground: :white, background: :red, style: :bold)
+ )
+ end
+
+ def test_sgr_rgb
+ assert_equal "38;2;255;255;255", @config.send(:sgr_rgb, :foreground, "#ffffff")
+ assert_equal "48;2;18;52;86", @config.send(:sgr_rgb, :background, "#123456")
+ end
+ end
+end
diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl
index bdefc48faa..e2a900b251 100755
--- a/test/reline/yamatanooroti/multiline_repl
+++ b/test/reline/yamatanooroti/multiline_repl
@@ -136,7 +136,7 @@ opt.on('--dialog VAL') { |v|
if v.include?('alt-scrollbar')
scrollbar = true
end
- Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar)
+ Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar, face: :completion_dialog)
})
if v.include?('alt-scrollbar')
ENV['RELINE_ALT_SCROLLBAR'] = '1'
diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb
index 8ac0c0c096..670432d86b 100644
--- a/test/reline/yamatanooroti/test_rendering.rb
+++ b/test/reline/yamatanooroti/test_rendering.rb
@@ -4,6 +4,33 @@ begin
require 'yamatanooroti'
class Reline::RenderingTest < Yamatanooroti::TestCase
+
+ FACE_CONFIGS = { no_config: "", valid_config: <<~VALID_CONFIG, incomplete_config: <<~INCOMPLETE_CONFIG }
+ require "reline"
+ Reline::Face.config(:completion_dialog) do |face|
+ face.define :default, foreground: :white, background: :blue
+ face.define :enhanced, foreground: :white, background: :magenta
+ face.define :scrollbar, foreground: :white, background: :blue
+ end
+ VALID_CONFIG
+ require "reline"
+ Reline::Face.config(:completion_dialog) do |face|
+ face.define :default, foreground: :white, background: :black
+ face.define :scrollbar, foreground: :white, background: :cyan
+ end
+ INCOMPLETE_CONFIG
+
+ def iterate_over_face_configs(&block)
+ FACE_CONFIGS.each do |config_name, face_config|
+ config_file = Tempfile.create(%w{face_config- .rb})
+ config_file.write face_config
+ block.call(config_name, config_file)
+ config_file.close
+ ensure
+ File.delete(config_file)
+ end
+ end
+
def setup
@pwd = Dir.pwd
suffix = '%010d' % Random.rand(0..65535)
@@ -954,75 +981,83 @@ begin
end
def test_simple_dialog
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
- write('a')
- write('b')
- write('c')
- write("\C-h")
- close
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> ab
- Ruby is...
- A dynamic, open source programming
- language with a focus on simplicity
- and productivity. It has an elegant
- syntax that is natural to read and
- easy to write.
- EOC
+ iterate_over_face_configs do |config_name, config_file|
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
+ write('a')
+ write('b')
+ write('c')
+ write("\C-h")
+ close
+ assert_screen(<<~'EOC', "Failed with `#{config_name}` in Face")
+ Multiline REPL.
+ prompt> ab
+ Ruby is...
+ A dynamic, open source programming
+ language with a focus on simplicity
+ and productivity. It has an elegant
+ syntax that is natural to read and
+ easy to write.
+ EOC
+ end
end
def test_simple_dialog_at_right_edge
- start_terminal(20, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
- write('a')
- write('b')
- write('c')
- write("\C-h")
- close
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> ab
- Ruby is...
- A dynamic, open source programming
- language with a focus on simplicity
- and productivity. It has an elegant
- syntax that is natural to read and
- easy to write.
- EOC
+ iterate_over_face_configs do |config_name, config_file|
+ start_terminal(20, 40, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
+ write('a')
+ write('b')
+ write('c')
+ write("\C-h")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> ab
+ Ruby is...
+ A dynamic, open source programming
+ language with a focus on simplicity
+ and productivity. It has an elegant
+ syntax that is natural to read and
+ easy to write.
+ EOC
+ end
end
def test_dialog_scroll_pushup_condition
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("\n" * 10)
- write("if 1\n sSt\nend")
- write("\C-p\C-h\C-e")
- close
- assert_screen(<<~'EOC')
- prompt>
- prompt>
- prompt>
- prompt>
- prompt>
- prompt>
- prompt> if 1
- prompt> St
- prompt> enString
- Struct
- EOC
+ iterate_over_face_configs do |config_name, config_file|
+ start_terminal(10, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("\n" * 10)
+ write("if 1\n sSt\nend")
+ write("\C-p\C-h\C-e")
+ close
+ assert_screen(<<~'EOC')
+ prompt>
+ prompt>
+ prompt>
+ prompt>
+ prompt>
+ prompt>
+ prompt> if 1
+ prompt> St
+ prompt> enString
+ Struct
+ EOC
+ end
end
def test_simple_dialog_with_scroll_screen
- start_terminal(5, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
- write("if 1\n 2\n 3\n 4\n 5\n 6")
- write("\C-p\C-n\C-p\C-p\C-p#")
- close
- assert_screen(<<~'EOC')
- prompt> 2
- prompt> 3#
- prompt> 4
- prompt> 5
- prompt> 6 Ruby is...
- EOC
+ iterate_over_face_configs do |config_name, config_file|
+ start_terminal(5, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
+ write("if 1\n 2\n 3\n 4\n 5\n 6")
+ write("\C-p\C-n\C-p\C-p\C-p#")
+ close
+ assert_screen(<<~'EOC')
+ prompt> 2
+ prompt> 3#
+ prompt> 4
+ prompt> 5
+ prompt> 6 Ruby is...
+ EOC
+ end
end
def test_autocomplete_at_bottom