summaryrefslogtreecommitdiff
path: root/test/reline/yamatanooroti
diff options
context:
space:
mode:
Diffstat (limited to 'test/reline/yamatanooroti')
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl137
-rw-r--r--test/reline/yamatanooroti/termination_checker.rb38
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb875
3 files changed, 951 insertions, 99 deletions
diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl
index 473d9d0f00..eba410f6dd 100755
--- a/test/reline/yamatanooroti/multiline_repl
+++ b/test/reline/yamatanooroti/multiline_repl
@@ -1,14 +1,14 @@
#!/usr/bin/env ruby
+
+require 'bundler'
+Bundler.require
+
require 'reline'
require 'optparse'
require_relative 'termination_checker'
opt = OptionParser.new
-opt.on('--prompt-list-cache-timeout VAL') { |v|
- Reline::LineEditor.__send__(:remove_const, :PROMPT_LIST_CACHE_TIMEOUT)
- Reline::LineEditor::PROMPT_LIST_CACHE_TIMEOUT = v.to_f
-}
opt.on('--dynamic-prompt') {
Reline.prompt_proc = proc { |lines|
lines.each_with_index.map { |l, i|
@@ -27,8 +27,54 @@ opt.on('--broken-dynamic-prompt') {
opt.on('--dynamic-prompt-returns-empty') {
Reline.prompt_proc = proc { |l| [] }
}
+opt.on('--dynamic-prompt-with-newline') {
+ Reline.prompt_proc = proc { |lines|
+ range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0)
+ lines[range].each_with_index.map { |l, i|
+ '[%04d\n]> ' % i
+ }
+ }
+}
+opt.on('--broken-dynamic-prompt-assert-no-escape-sequence') {
+ Reline.prompt_proc = proc { |lines|
+ has_escape_sequence = lines.join.include?("\e")
+ (lines.size + 1).times.map { |i|
+ has_escape_sequence ? 'error>' : '[%04d]> ' % i
+ }
+ }
+}
+opt.on('--color-bold') {
+ Reline.output_modifier_proc = ->(output, complete:){
+ output.gsub(/./) { |c| "\e[1m#{c}\e[0m" }
+ }
+}
+opt.on('--dynamic-prompt-show-line') {
+ Reline.prompt_proc = proc { |lines|
+ lines.map { |l|
+ '[%4.4s]> ' % l
+ }
+ }
+}
+
+def assert_auto_indent_params(lines, line_index, byte_pointer, is_newline)
+ raise 'Wrong lines type' unless lines.all?(String)
+
+ line = lines[line_index]
+ raise 'Wrong line_index value' unless line
+
+ # The condition `byte_pointer <= line.bytesize` is not satisfied. Maybe bug.
+ # Instead, loose constraint `byte_pointer <= line.bytesize + 1` seems to be satisfied when is_newline is false.
+ return if is_newline
+
+ raise 'byte_pointer out of bounds' unless byte_pointer <= line.bytesize + 1
+ raise 'Invalid byte_pointer' unless line.byteslice(0, byte_pointer).valid_encoding?
+end
+
opt.on('--auto-indent') {
- AutoIndent.new
+ Reline.auto_indent_proc = lambda do |lines, line_index, byte_pointer, is_newline|
+ assert_auto_indent_params(lines, line_index, byte_pointer, is_newline)
+ AutoIndent.calculate_indent(lines, line_index, byte_pointer, is_newline)
+ end
}
opt.on('--dialog VAL') { |v|
Reline.add_dialog_proc(:simple_dialog, lambda {
@@ -55,6 +101,15 @@ opt.on('--dialog VAL') { |v|
natural to read
and easy to write.
RUBY
+ elsif v.include?('fullwidth')
+ contents = <<~RUBY.split("\n")
+ Rubyとは...
+
+ オープンソースの動的なプログラミン
+ グ言語で、シンプルさと高い生産性を
+ 備えています。エレガントな文法を持
+ ち、自然に読み書きができます。
+ RUBY
end
if v.include?('scrollkey')
dialog.trap_key = nil
@@ -74,24 +129,89 @@ opt.on('--dialog VAL') { |v|
if v.include?('scrollbar')
scrollbar = true
end
- Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar)
+ if v.include?('alt-scrollbar')
+ scrollbar = true
+ end
+ 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'
+ end
}
opt.on('--complete') {
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
%w{String ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
}
}
+opt.on('--complete-menu-with-perfect-match') {
+ Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
+ %w{abs abs2}.select{ |c| c.start_with?(target) }
+ }
+}
opt.on('--autocomplete') {
Reline.autocompletion = true
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
%w{String Struct Symbol ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
}
}
+opt.on('--autocomplete-empty') {
+ Reline.autocompletion = true
+ Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| [] }
+}
opt.on('--autocomplete-long') {
Reline.autocompletion = true
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- %w{String Struct Symbol StopIteration SystemCallError SystemExit SystemStackError ScriptError SyntaxError Signal SizedQueue Set SecureRandom Socket StringIO StringScanner Shellwords Syslog Singleton SDBM}.select{ |c| c.start_with?(target) }
+ %w{
+ String
+ Struct
+ Symbol
+ StopIteration
+ SystemCallError
+ SystemExit
+ SystemStackError
+ ScriptError
+ SyntaxError
+ Signal
+ SizedQueue
+ Set
+ SecureRandom
+ Socket
+ StringIO
+ StringScanner
+ Shellwords
+ Syslog
+ Singleton
+ SDBM
+ }.select{ |c| c.start_with?(target) }
+ }
+}
+opt.on('--autocomplete-super-long') {
+ Reline.autocompletion = true
+ Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
+ c = +'A'
+ 2000.times.map{ s = "Str_#{c}"; c.succ!; s }.select{ |c| c.start_with?(target) }
+ }
+}
+
+opt.on('--autocomplete-width-long') {
+ Reline.autocompletion = true
+ Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
+ %w{
+ remove_instance_variable
+ respond_to?
+ ruby2_keywords
+ rand
+ readline
+ readlines
+ require
+ require_relative
+ raise
+ respond_to_missing?
+ redo
+ rescue
+ retry
+ return
+ }.select{ |c| c.start_with?(target) }
}
}
opt.parse!(ARGV)
@@ -104,8 +224,7 @@ end
begin
prompt = ENV['RELINE_TEST_PROMPT'] || 'prompt> '
puts 'Multiline REPL.'
- checker = TerminationChecker.new
- while code = Reline.readmultiline(prompt, true) { |code| checker.terminated?(code) }
+ while code = Reline.readmultiline(prompt, true) { |code| TerminationChecker.terminated?(code) }
case code.chomp
when 'exit', 'quit', 'q'
exit 0
diff --git a/test/reline/yamatanooroti/termination_checker.rb b/test/reline/yamatanooroti/termination_checker.rb
index 9c2c3ae740..b97c798c59 100644
--- a/test/reline/yamatanooroti/termination_checker.rb
+++ b/test/reline/yamatanooroti/termination_checker.rb
@@ -1,30 +1,26 @@
require 'ripper'
-require 'irb/ruby-lex'
-class TerminationChecker < RubyLex
- def terminated?(code)
- code.gsub!(/\n*$/, '').concat("\n")
- @tokens = Ripper.lex(code)
- continue = process_continue
- code_block_open = check_code_block(code)
- indent = process_nesting_level
- ltype = process_literal_type
- if code_block_open or ltype or continue or indent > 0
- false
- else
- true
- end
+module TerminationChecker
+ def self.terminated?(code)
+ Ripper.sexp(code) ? true : false
end
end
-class AutoIndent < RubyLex
- def initialize
- set_input(self)
- context = Struct.new(:auto_indent_mode, :workspace).new(true, nil)
- set_auto_indent(context)
+module AutoIndent
+ def self.calculate_indent(lines, line_index, byte_pointer, is_newline)
+ if is_newline
+ 2 * nesting_level(lines[0..line_index - 1])
+ else
+ lines = lines.dup
+ lines[line_index] = lines[line_index]&.byteslice(0, byte_pointer)
+ prev_level = nesting_level(lines[0..line_index - 1])
+ level = nesting_level(lines[0..line_index])
+ 2 * level if level < prev_level
+ end
end
- def auto_indent(&block)
- Reline.auto_indent_proc = block
+ def self.nesting_level(lines)
+ code = lines.join("\n")
+ code.scan(/if|def|\(|\[|\{/).size - code.scan(/end|\)|\]|\}/).size
end
end
diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb
index 58d23a40fd..74798c338f 100644
--- a/test/reline/yamatanooroti/test_rendering.rb
+++ b/test/reline/yamatanooroti/test_rendering.rb
@@ -3,7 +3,34 @@ require 'reline'
begin
require 'yamatanooroti'
- class Reline::TestRendering < Yamatanooroti::TestCase
+ 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)
@@ -121,6 +148,7 @@ begin
end
def test_finish_autowrapped_line_in_the_middle_of_multilines
+ omit if RUBY_VERSION < '2.7'
start_terminal(30, 16, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("<<~EOM\n ABCDEFG\nEOM\n")
close
@@ -169,9 +197,12 @@ begin
LINES
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write(":a\n\C-[k")
+ write("i\n:a")
+ write("\C-[h")
close
assert_screen(<<~EOC)
- Multiline REPL.
+ (ins)prompt> :a
+ => :a
(ins)prompt> :a
=> :a
(cmd)prompt> :a
@@ -236,6 +267,21 @@ begin
EOC
end
+ def test_esc_input
+ omit if Reline::IOGate.win?
+ start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write("def\C-aabc")
+ write("\e") # single ESC
+ sleep 1
+ write("A")
+ write("B\eAC") # ESC + A (M-A, specified ed_unassigned in Reline::KeyActor::Emacs)
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> abcABCdef
+ EOC
+ end
+
def test_prompt_with_escape_sequence
ENV['RELINE_TEST_PROMPT'] = "\1\e[30m\2prompt> \1\e[m\2"
start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
@@ -263,6 +309,21 @@ begin
EOC
end
+ def test_readline_with_multiline_input
+ start_terminal(5, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt}, startup_message: 'Multiline REPL.')
+ write("def foo\n bar\nend\n")
+ write("Reline.readline('prompt> ')\n")
+ write("\C-p\C-p")
+ close
+ assert_screen(<<~EOC)
+ => :foo
+ [0000]> Reline.readline('prompt> ')
+ prompt> def foo
+ bar
+ end
+ EOC
+ end
+
def test_multiline_and_autowrap
start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("def aaaaaaaaaa\n 33333333\n end\C-a\C-pputs\C-e\e\C-m888888888888888")
@@ -280,6 +341,23 @@ begin
EOC
end
+ def test_multiline_add_new_line_and_autowrap
+ start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write("def aaaaaaaaaa")
+ write("\n")
+ write(" bbbbbbbbbbbb")
+ write("\n")
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> def aaaaaaaa
+ aa
+ prompt> bbbbbbbbbb
+ bb
+ prompt>
+ EOC
+ end
+
def test_clear
start_terminal(10, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("3\C-l")
@@ -404,6 +482,9 @@ begin
write("def a\n 8\nend\ndef b\n 3\nend\C-s8")
close
assert_screen(<<~EOC)
+ prompt> 8
+ prompt> end
+ => :a
(i-search)`8'def a
(i-search)`8' 8
(i-search)`8'end
@@ -415,6 +496,9 @@ begin
write("def a\n 8\nend\ndef b\n 3\nend\C-r8\C-j")
close
assert_screen(<<~EOC)
+ prompt> 8
+ prompt> end
+ => :a
prompt> def a
prompt> 8
prompt> end
@@ -424,10 +508,10 @@ begin
def test_binding_for_vi_movement_mode
write_inputrc <<~LINES
set editing-mode vi
- "\\C-j": vi-movement-mode
+ "\\C-a": vi-movement-mode
LINES
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":1234\C-jhhhi0")
+ write(":1234\C-ahhhi0")
close
assert_screen(<<~EOC)
Multiline REPL.
@@ -435,32 +519,32 @@ begin
EOC
end
- def test_prompt_list_caching
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --prompt-list-cache-timeout 10 --dynamic-prompt}, startup_message: 'Multiline REPL.')
+ def test_broken_prompt_list
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --broken-dynamic-prompt}, startup_message: 'Multiline REPL.')
write("def hoge\n 3\nend")
close
assert_screen(<<~EOC)
Multiline REPL.
[0000]> def hoge
[0001]> 3
- [0002]> end
+ [0001]> end
EOC
end
- def test_broken_prompt_list
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --broken-dynamic-prompt}, startup_message: 'Multiline REPL.')
- write("def hoge\n 3\nend")
+ def test_no_escape_sequence_passed_to_dynamic_prompt
+ start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --color-bold --broken-dynamic-prompt-assert-no-escape-sequence}, startup_message: 'Multiline REPL.')
+ write("%[ S")
+ write("\n")
close
assert_screen(<<~EOC)
Multiline REPL.
- [0000]> def hoge
- [0001]> 3
- [0001]> end
+ [0000]> %[ S
+ [0001]>
EOC
end
def test_enable_bracketed_paste
- omit if Reline::IOGate.win?
+ omit if Reline.core.io_gate.win?
write_inputrc <<~LINES
set enable-bracketed-paste on
LINES
@@ -631,6 +715,31 @@ begin
EOC
end
+ def test_longer_than_screen_height_nearest_cursor_with_scroll_back
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write(<<~EOC.chomp)
+ if 1
+ if 2
+ if 3
+ if 4
+ puts
+ end
+ end
+ end
+ end
+ EOC
+ write("\C-p" * 4 + "\C-e" + "\C-p" * 4)
+ write("2")
+ close
+ assert_screen(<<~EOC)
+ prompt> if 12
+ prompt> if 2
+ prompt> if 3
+ prompt> if 4
+ prompt> puts
+ EOC
+ end
+
def test_update_cursor_correctly_when_just_cursor_moving
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("def hoge\n 01234678")
@@ -648,6 +757,66 @@ begin
EOC
end
+ def test_auto_indent
+ start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ "def hoge\nputs(\n1,\n2\n)\nend".lines do |line|
+ write line
+ end
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> def hoge
+ prompt> puts(
+ prompt> 1,
+ prompt> 2
+ prompt> )
+ prompt> end
+ EOC
+ end
+
+ def test_auto_indent_when_inserting_line
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ write 'aa(bb(cc(dd(ee('
+ write "\C-b" * 5 + "\n"
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> aa(bb(cc(d
+ prompt> d(ee(
+ EOC
+ end
+
+ def test_auto_indent_multibyte_insert_line
+ start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ write "if true\n"
+ write "あいうえお\n"
+ 4.times { write "\C-b\C-b\C-b\C-b\e\r" }
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> if true
+ prompt> あ
+ prompt> い
+ prompt> う
+ prompt> え
+ prompt> お
+ prompt>
+ EOC
+ end
+
+ def test_newline_after_wrong_indent
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ write "if 1\n aa"
+ write "\n"
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> if 1
+ prompt> aa
+ prompt>
+ EOC
+ end
+
def test_suppress_auto_indent_just_after_pasted
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
write("def hoge\n [[\n 3]]\ned")
@@ -677,6 +846,20 @@ begin
EOC
end
+ def test_auto_indent_with_various_spaces
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ write "(\n\C-v"
+ write "\C-k\n\C-v"
+ write "\C-k)"
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> (
+ prompt> ^K
+ prompt> )
+ EOC
+ end
+
def test_autowrap_in_the_middle_of_a_line
start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("def abcdefg; end\C-b\C-b\C-b\C-b\C-b")
@@ -730,7 +913,7 @@ begin
end
def test_meta_key
- start_terminal(50, 200, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ start_terminal(30, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("def ge\M-bho")
close
assert_screen(<<~EOC)
@@ -739,8 +922,18 @@ begin
EOC
end
+ def test_not_meta_key
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write("おだんご") # "だ" in UTF-8 contains "\xA0"
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> おだんご
+ EOC
+ end
+
def test_force_enter
- start_terminal(50, 200, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ start_terminal(30, 120, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
write("def hoge\nend\C-p\C-e")
write("\M-\x0D")
close
@@ -752,36 +945,27 @@ begin
EOC
end
- def test_cyrillic_chars
- omit unless Reline::IOGate.win?
- start_terminal(50, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("`chcp 850`\n")
- write("`chcp`\n")
- write("def гопота; 3; end\n")
- write("гопота\n")
- close
+ def test_eof_with_newline
+ omit if Reline.core.io_gate.win?
+ cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
+ start_terminal(40, 50, ['bash', '-c', cmd])
+ sleep 1
+ close rescue nil
assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> `chcp 850`
- => "Active code page: 850\n"
- prompt> `chcp`
- => "Active code page: 850\n"
- prompt> def гопота; 3; end
- => :гопота
- prompt> гопота
- => 3
- prompt>
+ > abc def
+ "abc def "
EOC
end
- def test_with_newline
- omit if Reline::IOGate.win?
- cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
- start_terminal(50, 50, ['bash', '-c', cmd])
- close
+ def test_eof_without_newline
+ omit if Reline.core.io_gate.win?
+ cmd = %Q{ruby -e 'print(%{hello})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
+ start_terminal(40, 50, ['bash', '-c', cmd])
+ sleep 1
+ close rescue nil
assert_screen(<<~'EOC')
- > abc def
- "abc def "
+ > hello
+ "hello"
EOC
end
@@ -795,6 +979,18 @@ begin
EOC
end
+ def test_multiline_completion
+ start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
+ write("def hoge\n St\n St\C-p\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> def hoge
+ prompt> String
+ prompt> St
+ EOC
+ end
+
def test_completion_journey_2nd_line
write_inputrc <<~LINES
set editing-mode vi
@@ -822,44 +1018,127 @@ begin
EOC
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")
+ def test_completion_menu_is_displayed_horizontally
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
+ write("S\t\t")
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.
+ prompt> S
+ ScriptError String
+ Signal SyntaxError
EOC
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")
+ def test_show_all_if_ambiguous_on
+ write_inputrc <<~LINES
+ set show-all-if-ambiguous on
+ LINES
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
+ write("S\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> S
+ ScriptError String
+ Signal SyntaxError
+ EOC
+ end
+
+ def test_show_all_if_ambiguous_on_and_menu_with_perfect_match
+ write_inputrc <<~LINES
+ set show-all-if-ambiguous on
+ LINES
+ start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete-menu-with-perfect-match}, startup_message: 'Multiline REPL.')
+ write("a\t")
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.
+ prompt> abs
+ abs abs2
EOC
end
+ def test_simple_dialog
+ 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
+ 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
+ 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 sSts\nend")
+ write("\C-p\C-h\C-e\C-h")
+ 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
+ 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 Ruby is...
+ prompt> 6 A dynamic, open source programming
+ EOC
+ end
+ end
+
def test_autocomplete_at_bottom
start_terminal(15, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
write('def hoge' + "\C-m" * 10 + "end\C-p ")
@@ -906,8 +1185,50 @@ begin
assert_screen(<<~'EOC')
Multiline REPL.
prompt> St
- r String
- Struct
+ r
+ String
+ Struct
+ EOC
+ end
+
+ def test_autocomplete_target_at_end_of_line
+ start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write(' ')
+ write('Str')
+ write("\C-i")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Str
+ ing String
+ Struct
+ EOC
+ end
+
+ def test_autocomplete_completed_input_is_wrapped
+ start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write(' ')
+ write('Str')
+ write("\C-i")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Stri
+ ng String
+ Struct
+ EOC
+ end
+
+ def test_force_insert_before_autocomplete
+ start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write('Sy')
+ write(";St\t\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Sy;Struct
+ String
+ Struct
EOC
end
@@ -957,6 +1278,40 @@ begin
EOC
end
+ def test_dialog_with_fullwidth_chars
+ ENV['RELINE_TEST_PROMPT'] = '> '
+ start_terminal(20, 5, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.')
+ 6.times{ write('j') }
+ close
+ assert_screen(<<~'EOC')
+ Multi
+ line
+ REPL.
+ >
+ オー
+ グ言▄
+ 備え█
+ ち、█
+ EOC
+ end
+
+ def test_dialog_with_fullwidth_chars_split
+ ENV['RELINE_TEST_PROMPT'] = '> '
+ start_terminal(20, 6, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.')
+ 6.times{ write('j') }
+ close
+ assert_screen(<<~'EOC')
+ Multil
+ ine RE
+ PL.
+ >
+ オー
+ グ言 ▄
+ 備え █
+ ち、 █
+ EOC
+ end
+
def test_autocomplete_empty
start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
write('Street')
@@ -979,6 +1334,32 @@ begin
EOC
end
+ def test_autocomplete_empty_string
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("\C-i")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> String
+ String █
+ Struct ▀
+ Symbol
+ EOC
+ end
+
+ def test_paste_code_with_tab_indent_does_not_fail
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-empty}, startup_message: 'Multiline REPL.')
+ write("2.times do\n\tputs\n\tputs\nend")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> 2.times do
+ prompt> puts
+ prompt> puts
+ prompt> end
+ EOC
+ end
+
def test_autocomplete_after_2nd_line
start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
write("def hoge\n Str")
@@ -1007,6 +1388,23 @@ begin
EOC
end
+ def test_rerender_multiple_dialog
+ start_terminal(20, 60, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --dialog simple}, startup_message: 'Multiline REPL.')
+ write("if\n abcdef\n 123456\n 456789\nend\C-p\C-p\C-p\C-p Str")
+ write("\t")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> if String
+ prompt> aStringRuby is...
+ prompt> 1StructA dynamic, open source programming
+ prompt> 456789 language with a focus on simplicity
+ prompt> end and productivity. It has an elegant
+ syntax that is natural to read and
+ easy to write.
+ EOC
+ end
+
def test_autocomplete_long_with_scrollbar
start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.')
write('S')
@@ -1057,6 +1455,59 @@ begin
EOC
end
+ def test_autocomplete_super_long_scroll_to_bottom
+ start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.')
+ shift_tab = [27, 91, 90]
+ write('S' + shift_tab.map(&:chr).join)
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Str_BXX
+ Str_BXJ
+ Str_BXK
+ Str_BXL
+ Str_BXM
+ Str_BXN
+ Str_BXO
+ Str_BXP
+ Str_BXQ
+ Str_BXR
+ Str_BXS
+ Str_BXT
+ Str_BXU
+ Str_BXV
+ Str_BXW
+ Str_BXX▄
+ EOC
+ end
+
+ def test_autocomplete_super_long_and_backspace
+ start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.')
+ shift_tab = [27, 91, 90]
+ write('S' + shift_tab.map(&:chr).join)
+ write("\C-h")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> Str_BX
+ Str_BX █
+ Str_BXA█
+ Str_BXB█
+ Str_BXC█
+ Str_BXD█
+ Str_BXE█
+ Str_BXF█
+ Str_BXG█
+ Str_BXH█
+ Str_BXI
+ Str_BXJ
+ Str_BXK
+ Str_BXL
+ Str_BXM
+ Str_BXN
+ EOC
+ end
+
def test_dialog_callback_returns_nil
start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog nil}, startup_message: 'Multiline REPL.')
write('a')
@@ -1067,6 +1518,292 @@ begin
EOC
end
+ def test_dialog_narrower_than_screen
+ start_terminal(20, 11, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
+ close
+ assert_screen(<<~'EOC')
+ Multiline R
+ EPL.
+ prompt>
+ Ruby is...
+ A dynamic,
+ language wi
+ and product
+ syntax that
+ easy to wri
+ EOC
+ end
+
+ def test_dialog_narrower_than_screen_with_scrollbar
+ start_terminal(20, 11, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.')
+ write('S' + "\C-i" * 3)
+ close
+ assert_screen(<<~'EOC')
+ Multiline R
+ EPL.
+ prompt> Sym
+ String █
+ Struct █
+ Symbol █
+ StopIterat█
+ SystemCall█
+ SystemExit█
+ SystemStac█
+ ScriptErro█
+ SyntaxErro█
+ Signal █
+ SizedQueue█
+ Set
+ SecureRand
+ Socket
+ StringIO
+ EOC
+ end
+
+ def test_dialog_with_fullwidth_scrollbar
+ start_terminal(20, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple,scrollkey,alt-scrollbar}, startup_message: 'Multiline REPL.')
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt>
+ Ruby is... ::
+ A dynamic, open source programming ::
+ language with a focus on simplicity''
+ and productivity. It has an elegant
+ EOC
+ end
+
+ def test_rerender_argument_prompt_after_pasting
+ start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write('abcdef')
+ write("\M-3\C-h")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> abc
+ EOC
+ end
+
+ def test_autocomplete_old_dialog_width_greater_than_dialog_width
+ start_terminal(40, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-width-long}, startup_message: 'Multiline REPL.')
+ write("0+ \n12345678901234")
+ write("\C-p")
+ write("r")
+ write("a")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> 0+ ra
+ prompt> 123rand 901234
+ raise
+ EOC
+ end
+
+ def test_scroll_at_bottom_for_dialog
+ start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("\n\n\n\n\n\n\n\n\n\n\n")
+ write("def hoge\n\nend\C-p\C-e")
+ write(" S")
+ close
+ assert_screen(<<~'EOC')
+ prompt>
+ prompt>
+ prompt>
+ prompt>
+ prompt>
+ prompt> def hoge
+ prompt> S
+ prompt> enString █
+ Struct ▀
+ Symbol
+ EOC
+ end
+
+ def test_clear_dialog_in_pasting
+ start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("S")
+ write("tring ")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt> String
+ EOC
+ end
+
+ def test_prompt_with_newline
+ ENV['RELINE_TEST_PROMPT'] = "::\n> "
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write("def hoge\n 3\nend")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ ::\n> def hoge
+ ::\n> 3
+ ::\n> end
+ EOC
+ end
+
+ def test_dynamic_prompt_with_newline
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-with-newline}, startup_message: 'Multiline REPL.')
+ write("def hoge\n 3\nend")
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ [0000\n]> def hoge
+ [0001\n]> 3
+ [0001\n]> end
+ EOC
+ end
+
+ def test_lines_passed_to_dynamic_prompt
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-show-line}, startup_message: 'Multiline REPL.')
+ write("if true")
+ write("\n")
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ [if t]> if true
+ [ ]>
+ EOC
+ end
+
+ def test_clear_dialog_when_just_move_cursor_at_last_line
+ start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("class A\n 3\nend\n\n\n")
+ write("\C-p\C-p\C-e; S")
+ write("\C-n")
+ write(";")
+ close
+ assert_screen(<<~'EOC')
+ prompt> 3
+ prompt> end
+ => 3
+ prompt>
+ prompt>
+ prompt> class A
+ prompt> 3; S
+ prompt> end;
+ EOC
+ end
+
+ def test_clear_dialog_when_adding_new_line_to_end_of_buffer
+ start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("class A\n def a\n 3\n 3\n end\nend")
+ write("\n")
+ write("class S")
+ write("\n")
+ write(" 3")
+ close
+ assert_screen(<<~'EOC')
+ prompt> def a
+ prompt> 3
+ prompt> 3
+ prompt> end
+ prompt> end
+ => :a
+ prompt> class S
+ prompt> 3
+ EOC
+ end
+
+ def test_insert_newline_in_the_middle_of_buffer_just_after_dialog
+ start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("class A\n def a\n 3\n end\nend")
+ write("\n")
+ write("\C-p\C-p\C-p\C-p\C-p\C-e\C-hS")
+ write("\M-\x0D")
+ write(" 3")
+ close
+ assert_screen(<<~'EOC')
+ prompt> 3
+ prompt> end
+ prompt> end
+ => :a
+ prompt> class S
+ prompt> 3
+ prompt> def a
+ prompt> 3
+ prompt> end
+ prompt> end
+ EOC
+ end
+
+ def test_incremental_search_on_not_last_line
+ start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
+ write("def abc\nend\n")
+ write("def def\nend\n")
+ write("\C-p\C-p\C-e")
+ write("\C-r")
+ write("a")
+ write("\n\n")
+ close
+ assert_screen(<<~'EOC')
+ prompt> def abc
+ prompt> end
+ => :abc
+ prompt> def def
+ prompt> end
+ => :def
+ prompt> def abc
+ prompt> end
+ => :abc
+ prompt>
+ EOC
+ end
+
+ def test_bracket_newline_indent
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ write("[\n")
+ write("1")
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> [
+ prompt> 1
+ EOC
+ end
+
+ def test_repeated_input_delete
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
+ write("a\C-h" * 4000)
+ close
+ assert_screen(<<~'EOC')
+ Multiline REPL.
+ prompt>
+ EOC
+ end
+
+ def test_exit_with_ctrl_d
+ start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ begin
+ write("\C-d")
+ close
+ rescue EOFError
+ # EOFError is raised when process terminated.
+ end
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt>
+ EOC
+ end
+
+ def test_thread_safe
+ start_terminal(6, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
+ write("[Thread.new{Reline.readline'>'},Thread.new{Reline.readmultiline('>'){true}}].map(&:join).size\n")
+ write("exit\n")
+ write("exit\n")
+ write("42\n")
+ close
+ assert_screen(<<~EOC)
+ >exit
+ >exit
+ => 2
+ prompt> 42
+ => 42
+ prompt>
+ EOC
+ end
+
def write_inputrc(content)
File.open(@inputrc_file, 'w') do |f|
f.write content