summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/io/console/console.c23
-rw-r--r--ext/io/console/extconf.rb9
-rw-r--r--ext/io/console/io-console.gemspec4
-rw-r--r--ext/readline/extconf.rb1
-rw-r--r--ext/readline/readline-ext.gemspec7
-rw-r--r--lib/benchmark/benchmark.gemspec2
-rw-r--r--lib/cgi/cgi.gemspec2
-rw-r--r--lib/delegate/delegate.gemspec2
-rw-r--r--lib/getoptlong/getoptlong.gemspec2
-rw-r--r--lib/irb.rb12
-rw-r--r--lib/irb/.document1
-rw-r--r--lib/irb/completion.rb27
-rw-r--r--lib/irb/context.rb20
-rw-r--r--lib/irb/easter-egg.rb137
-rw-r--r--lib/irb/ext/save-history.rb4
-rw-r--r--lib/irb/init.rb9
-rw-r--r--lib/irb/input-method.rb4
-rw-r--r--lib/irb/irb.gemspec3
-rw-r--r--lib/irb/lc/.document4
-rw-r--r--lib/irb/locale.rb11
-rw-r--r--lib/irb/ruby-lex.rb13
-rw-r--r--lib/irb/version.rb4
-rw-r--r--lib/net/pop/net-pop.gemspec2
-rw-r--r--lib/net/smtp/net-smtp.gemspec2
-rw-r--r--lib/observer/observer.gemspec2
-rw-r--r--lib/open3/open3.gemspec2
-rw-r--r--lib/pstore/pstore.gemspec2
-rw-r--r--lib/reline.rb50
-rw-r--r--lib/reline/ansi.rb58
-rw-r--r--lib/reline/config.rb19
-rw-r--r--lib/reline/general_io.rb8
-rw-r--r--lib/reline/history.rb6
-rw-r--r--lib/reline/line_editor.rb134
-rw-r--r--lib/reline/version.rb2
-rw-r--r--lib/reline/windows.rb45
-rw-r--r--lib/singleton/singleton.gemspec2
-rw-r--r--lib/timeout/timeout.gemspec2
-rw-r--r--lib/uri/uri.gemspec2
-rw-r--r--lib/yaml/yaml.gemspec2
-rw-r--r--test/io/console/test_io_console.rb7
-rw-r--r--test/irb/test_color.rb2
-rw-r--r--test/irb/test_completion.rb22
-rw-r--r--test/irb/test_context.rb38
-rw-r--r--test/irb/test_ruby_lex.rb130
-rw-r--r--test/readline/helper.rb20
-rw-r--r--test/readline/test_readline.rb220
-rw-r--r--test/readline/test_readline_history.rb11
-rw-r--r--test/reline/test_config.rb20
-rw-r--r--test/reline/test_history.rb10
-rw-r--r--test/reline/test_key_actor_emacs.rb75
-rw-r--r--test/reline/test_key_actor_vi.rb149
-rw-r--r--test/reline/test_macro.rb3
-rw-r--r--test/reline/test_reline.rb27
-rw-r--r--test/reline/test_string_processing.rb4
-rw-r--r--test/reline/test_within_pipe.rb1
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb41
-rw-r--r--test/ruby/test_rubyoptions.rb8
57 files changed, 1169 insertions, 260 deletions
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 3688fd4240..9baad2bf17 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -111,6 +111,9 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
int argc = *argcp;
rawmode_arg_t *optp = NULL;
VALUE vopts = Qnil;
+#ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
+ argc = rb_scan_args(argc, argv, "*:", NULL, &vopts);
+#else
if (argc > min_argc) {
vopts = rb_check_hash_type(argv[argc-1]);
if (!NIL_P(vopts)) {
@@ -120,6 +123,7 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
if (!vopts) vopts = Qnil;
}
}
+#endif
rb_check_arity(argc, min_argc, max_argc);
if (!NIL_P(vopts)) {
VALUE vmin = rb_hash_aref(vopts, ID2SYM(id_min));
@@ -188,7 +192,7 @@ set_rawmode(conmode *t, void *arg)
#endif
#ifdef ISIG
if (r->intr) {
- t->c_iflag |= BRKINT|IXON;
+ t->c_iflag |= BRKINT;
t->c_lflag |= ISIG;
t->c_oflag |= OPOST;
}
@@ -356,9 +360,9 @@ ttymode_with_io(VALUE io, VALUE (*func)(VALUE, VALUE), VALUE farg, void (*setter
/*
* call-seq:
- * io.raw(min: nil, time: nil) {|io| }
+ * io.raw(min: nil, time: nil, intr: nil) {|io| }
*
- * Yields +self+ within raw mode.
+ * Yields +self+ within raw mode, and returns the result of the block.
*
* STDIN.raw(&:gets)
*
@@ -370,6 +374,9 @@ ttymode_with_io(VALUE io, VALUE (*func)(VALUE, VALUE), VALUE farg, void (*setter
* The parameter +time+ specifies the timeout in _seconds_ with a
* precision of 1/10 of a second. (default: 0)
*
+ * If the parameter +intr+ is +true+, enables break, interrupt, quit,
+ * and suspend special characters.
+ *
* Refer to the manual page of termios for further details.
*
* You must require 'io/console' to use this method.
@@ -383,11 +390,11 @@ console_raw(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
- * io.raw!(min: nil, time: nil)
+ * io.raw!(min: nil, time: nil, intr: nil) -> io
*
- * Enables raw mode.
+ * Enables raw mode, and returns +io+.
*
- * If the terminal mode needs to be back, use io.raw { ... }.
+ * If the terminal mode needs to be back, use <code>io.raw { ... }</code>.
*
* See IO#raw for details on the parameters.
*
@@ -483,7 +490,7 @@ nogvl_getch(void *p)
/*
* call-seq:
- * io.getch(min: nil, time: nil) -> char
+ * io.getch(min: nil, time: nil, intr: nil) -> char
*
* Reads and returns a character in raw mode.
*
@@ -1490,7 +1497,7 @@ console_dev(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * io.getch(min: nil, time: nil) -> char
+ * io.getch(min: nil, time: nil, intr: nil) -> char
*
* See IO#getch.
*/
diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb
index a6049da667..3d7e75e2af 100644
--- a/ext/io/console/extconf.rb
+++ b/ext/io/console/extconf.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
require 'mkmf'
-ok = true
+ok = true if RUBY_ENGINE == "ruby"
hdr = nil
case
when macro_defined?("_WIN32", "")
@@ -14,8 +14,9 @@ when have_header(hdr = "sgtty.h")
%w"stty gtty".each {|f| have_func(f, hdr)}
else
ok = false
-end
-if ok
+end if ok
+case ok
+when true
have_header("sys/ioctl.h") if hdr
# rb_check_hash_type: 1.9.3
# rb_io_get_write_io: 1.9.1
@@ -27,4 +28,6 @@ if ok
create_makefile("io/console") {|conf|
conf << "\n""VK_HEADER = #{vk_header}\n"
}
+when nil
+ File.write("Makefile", dummy_makefile($srcdir).join(""))
end
diff --git a/ext/io/console/io-console.gemspec b/ext/io/console/io-console.gemspec
index fac9bff9b7..814bd4ef7d 100644
--- a/ext/io/console/io-console.gemspec
+++ b/ext/io/console/io-console.gemspec
@@ -1,5 +1,5 @@
# -*- ruby -*-
-_VERSION = "0.5.3"
+_VERSION = "0.5.6"
date = %w$Date:: $[1]
Gem::Specification.new do |s|
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.summary = "Console interface"
s.email = "nobu@ruby-lang.org"
s.description = "add console capabilities to IO instances."
- s.required_ruby_version = ">= 2.2.0"
+ s.required_ruby_version = ">= 2.4.0"
s.homepage = "https://github.com/ruby/io-console"
s.metadata["source_code_url"] = s.homepage
s.authors = ["Nobu Nakada"]
diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb
index fcc62921ae..d3e7872e65 100644
--- a/ext/readline/extconf.rb
+++ b/ext/readline/extconf.rb
@@ -109,5 +109,4 @@ unless readline.have_type("rl_hook_func_t*")
$defs << "-Drl_hook_func_t=Function"
end
-$INCFLAGS << " -I$(top_srcdir)"
create_makefile("readline")
diff --git a/ext/readline/readline-ext.gemspec b/ext/readline/readline-ext.gemspec
index a611a8ea9a..b85e07dd93 100644
--- a/ext/readline/readline-ext.gemspec
+++ b/ext/readline/readline-ext.gemspec
@@ -8,14 +8,19 @@ Gem::Specification.new do |spec|
spec.description = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
spec.homepage = "https://github.com/ruby/readline-ext"
spec.license = "BSD-2-Clause"
+ spec.extensions = %w[ext/readline/extconf.rb]
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
+
+ spec.add_development_dependency "bundler"
+ spec.add_development_dependency "rake"
+ spec.add_development_dependency "rake-compiler"
end
diff --git a/lib/benchmark/benchmark.gemspec b/lib/benchmark/benchmark.gemspec
index aad5205f8d..773cab19b0 100644
--- a/lib/benchmark/benchmark.gemspec
+++ b/lib/benchmark/benchmark.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/cgi/cgi.gemspec b/lib/cgi/cgi.gemspec
index 403d31c978..58bd77027d 100644
--- a/lib/cgi/cgi.gemspec
+++ b/lib/cgi/cgi.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/delegate/delegate.gemspec b/lib/delegate/delegate.gemspec
index e51b50a98f..268cc5a817 100644
--- a/lib/delegate/delegate.gemspec
+++ b/lib/delegate/delegate.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/getoptlong/getoptlong.gemspec b/lib/getoptlong/getoptlong.gemspec
index 198bba83ac..5e218b8e93 100644
--- a/lib/getoptlong/getoptlong.gemspec
+++ b/lib/getoptlong/getoptlong.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/irb.rb b/lib/irb.rb
index bcd6599af9..ee6979c6d0 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -21,6 +21,7 @@ require "irb/locale"
require "irb/color"
require "irb/version"
+require "irb/easter-egg"
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
# expressions read from the standard input.
@@ -553,7 +554,8 @@ module IRB
def handle_exception(exc)
if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
- !(SyntaxError === exc)
+ !(SyntaxError === exc) && !(EncodingError === exc)
+ # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
irb_bug = true
else
irb_bug = false
@@ -736,7 +738,13 @@ module IRB
end
def output_value # :nodoc:
- printf @context.return_format, @context.inspect_last_value
+ str = @context.inspect_last_value
+ multiline_p = str.include?("\n")
+ if multiline_p && @context.newline_before_multiline_output?
+ printf @context.return_format, "\n#{str}"
+ else
+ printf @context.return_format, str
+ end
end
# Outputs the local variables to this current session, including
diff --git a/lib/irb/.document b/lib/irb/.document
new file mode 100644
index 0000000000..3b0d6fa4ed
--- /dev/null
+++ b/lib/irb/.document
@@ -0,0 +1 @@
+**/*.rb
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index 3536e8ec87..c44aa9039e 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -17,11 +17,12 @@ module IRB
# Set of reserved words used by Ruby, you should not use these for
# constants or variables
ReservedWords = %w[
+ __ENCODING__ __LINE__ __FILE__
BEGIN END
alias and
begin break
case class
- def defined do
+ def defined? do
else elsif end ensure
false for
if in
@@ -98,7 +99,11 @@ module IRB
return nil if doc_namespace
if Symbol.respond_to?(:all_symbols)
sym = $1
- candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
+ candidates = Symbol.all_symbols.collect do |s|
+ ":" + s.id2name.encode(Encoding.default_external)
+ rescue Encoding::UndefinedConversionError
+ # ignore
+ end
candidates.grep(/^#{Regexp.quote(sym)}/)
else
[]
@@ -143,7 +148,7 @@ module IRB
select_message(receiver, message, candidates, sep)
end
- when /^(?<num>-?(0[dbo])?[0-9_]+(\.[0-9_]+)?(([eE][+-]?[0-9]+)?i?|r)?)(?<sep>\.|::)(?<mes>[^.]*)$/
+ when /^(?<num>-?(?:0[dbo])?[0-9_]+(?:\.[0-9_]+)?(?:(?:[eE][+-]?[0-9]+)?i?|r)?)(?<sep>\.|::)(?<mes>[^.]*)$/
# Numeric
receiver = $~[:num]
sep = $~[:sep]
@@ -203,7 +208,7 @@ module IRB
sep = $2
message = Regexp.quote($3)
- gv = eval("global_variables", bind).collect{|m| m.to_s}.append("true", "false", "nil")
+ gv = eval("global_variables", bind).collect{|m| m.to_s}.push("true", "false", "nil")
lv = eval("local_variables", bind).collect{|m| m.to_s}
iv = eval("instance_variables", bind).collect{|m| m.to_s}
cv = eval("self.class.constants", bind).collect{|m| m.to_s}
@@ -255,7 +260,7 @@ module IRB
else
candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s}
- conditions |= ReservedWords
+ candidates |= ReservedWords
if doc_namespace
candidates.find{ |i| i == input }
@@ -265,18 +270,14 @@ module IRB
end
end
- PerfectMatchedProc = ->(matched) {
+ PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
RDocRIDriver ||= RDoc::RI::Driver.new
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
- File.open(File.join(__dir__, 'ruby_logo.aa')) do |f|
- RDocRIDriver.page do |io|
- IO.copy_stream(f, io)
- end
- end
+ IRB.send(:easter_egg)
return
end
- namespace = retrieve_completion_data(matched, doc_namespace: true)
- return unless matched
+ namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
+ return unless namespace
if namespace.is_a?(Array)
out = RDoc::Markup::Document.new
namespace.each do |m|
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index 686738cd40..218f7c6037 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -133,6 +133,11 @@ module IRB
if @echo_on_assignment.nil?
@echo_on_assignment = false
end
+
+ @newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT]
+ if @newline_before_multiline_output.nil?
+ @newline_before_multiline_output = true
+ end
end
# The top-level workspace, see WorkSpace#main
@@ -253,6 +258,20 @@ module IRB
# a = "omg"
# #=> omg
attr_accessor :echo_on_assignment
+ # Whether a newline is put before multiline output.
+ #
+ # Uses IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if available,
+ # or defaults to +true+.
+ #
+ # "abc\ndef"
+ # #=>
+ # abc
+ # def
+ # IRB.CurrentContext.newline_before_multiline_output = false
+ # "abc\ndef"
+ # #=> abc
+ # def
+ attr_accessor :newline_before_multiline_output
# Whether verbose messages are displayed or not.
#
# A copy of the default <code>IRB.conf[:VERBOSE]</code>
@@ -287,6 +306,7 @@ module IRB
alias ignore_eof? ignore_eof
alias echo? echo
alias echo_on_assignment? echo_on_assignment
+ alias newline_before_multiline_output? newline_before_multiline_output
# Returns whether messages are displayed or not.
def verbose?
diff --git a/lib/irb/easter-egg.rb b/lib/irb/easter-egg.rb
new file mode 100644
index 0000000000..64869d85fa
--- /dev/null
+++ b/lib/irb/easter-egg.rb
@@ -0,0 +1,137 @@
+require "reline"
+
+module IRB
+ class << self
+ class Vec
+ def initialize(x, y, z)
+ @x, @y, @z = x, y, z
+ end
+
+ attr_reader :x, :y, :z
+
+ def sub(other)
+ Vec.new(@x - other.x, @y - other.y, @z - other.z)
+ end
+
+ def dot(other)
+ @x*other.x + @y*other.y + @z*other.z
+ end
+
+ def cross(other)
+ ox, oy, oz = other.x, other.y, other.z
+ Vec.new(@y*oz-@z*oy, @z*ox-@x*oz, @x*oy-@y*ox)
+ end
+
+ def normalize
+ r = Math.sqrt(self.dot(self))
+ Vec.new(@x / r, @y / r, @z / r)
+ end
+ end
+
+ class Canvas
+ def initialize((h, w))
+ @data = (0..h-2).map { [0] * w }
+ @scale = [w / 2.0, h-2].min
+ @center = Complex(w / 2, h-2)
+ end
+
+ def line((x1, y1), (x2, y2))
+ p1 = Complex(x1, y1) / 2 * @scale + @center
+ p2 = Complex(x2, y2) / 2 * @scale + @center
+ line0(p1, p2)
+ end
+
+ private def line0(p1, p2)
+ mid = (p1 + p2) / 2
+ if (p1 - p2).abs < 1
+ x, y = mid.rect
+ @data[y / 2][x] |= (y % 2 > 1 ? 2 : 1)
+ else
+ line0(p1, mid)
+ line0(p2, mid)
+ end
+ end
+
+ def draw
+ @data.each {|row| row.fill(0) }
+ yield
+ @data.map {|row| row.map {|n| " ',;"[n] }.join }.join("\n")
+ end
+ end
+
+ class RubyModel
+ def initialize
+ @faces = init_ruby_model
+ end
+
+ def init_ruby_model
+ cap_vertices = (0..5).map {|i| Vec.new(*Complex.polar(1, i * Math::PI / 3).rect, 1) }
+ middle_vertices = (0..5).map {|i| Vec.new(*Complex.polar(2, (i + 0.5) * Math::PI / 3).rect, 0) }
+ bottom_vertex = Vec.new(0, 0, -2)
+
+ faces = [cap_vertices]
+ 6.times do |j|
+ i = j-1
+ faces << [cap_vertices[i], middle_vertices[i], cap_vertices[j]]
+ faces << [cap_vertices[j], middle_vertices[i], middle_vertices[j]]
+ faces << [middle_vertices[i], bottom_vertex, middle_vertices[j]]
+ end
+
+ faces
+ end
+
+ def render_frame(i)
+ angle = i / 10.0
+ dir = Vec.new(*Complex.polar(1, angle).rect, Math.sin(angle)).normalize
+ dir2 = Vec.new(*Complex.polar(1, angle - Math::PI/2).rect, 0)
+ up = dir.cross(dir2)
+ nm = dir.cross(up)
+ @faces.each do |vertices|
+ v0, v1, v2, = vertices
+ if v1.sub(v0).cross(v2.sub(v0)).dot(dir) > 0
+ points = vertices.map {|p| [nm.dot(p), up.dot(p)] }
+ (points + [points[0]]).each_cons(2) do |p1, p2|
+ yield p1, p2
+ end
+ end
+ end
+ end
+ end
+
+ private def easter_egg(type = nil)
+ type ||= [:logo, :dancing].sample
+ case type
+ when :logo
+ File.open(File.join(__dir__, 'ruby_logo.aa')) do |f|
+ require "rdoc"
+ RDoc::RI::Driver.new.page do |io|
+ IO.copy_stream(f, io)
+ end
+ end
+ when :dancing
+ begin
+ canvas = Canvas.new(Reline.get_screen_size)
+ Reline::IOGate.set_winch_handler do
+ canvas = Canvas.new(Reline.get_screen_size)
+ end
+ ruby_model = RubyModel.new
+ print "\e[?1049h"
+ 0.step do |i| # TODO (0..).each needs Ruby 2.6 or later
+ buff = canvas.draw do
+ ruby_model.render_frame(i) do |p1, p2|
+ canvas.line(p1, p2)
+ end
+ end
+ buff[0, 20] = "\e[0mPress Ctrl+C to stop\e[31m\e[1m"
+ print "\e[H" + buff
+ sleep 0.05
+ end
+ ensure
+ print "\e[0m\e[?1049l"
+ end
+ end
+ end
+ end
+end
+
+IRB.send(:easter_egg, ARGV[0]&.to_sym) if $0 == __FILE__
diff --git a/lib/irb/ext/save-history.rb b/lib/irb/ext/save-history.rb
index c0d4d372b7..edc4f234cc 100644
--- a/lib/irb/ext/save-history.rb
+++ b/lib/irb/ext/save-history.rb
@@ -72,7 +72,7 @@ module IRB
end
history_file = IRB.rc_file("_history") unless history_file
if File.exist?(history_file)
- open(history_file) do |f|
+ open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
f.each { |l|
l = l.chomp
if self.class == ReidlineInputMethod and history.last&.end_with?("\\")
@@ -107,7 +107,7 @@ module IRB
raise
end
- open(history_file, 'w', 0600 ) do |f|
+ open(history_file, "w:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f|
hist = history.map{ |l| l.split("\n").join("\\\n") }
f.puts(hist[-num..-1] || hist)
end
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 2af872fd03..37d1f8d609 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -296,15 +296,18 @@ module IRB # :nodoc:
DefaultEncodings = Struct.new(:external, :internal)
class << IRB
private
- def set_encoding(extern, intern = nil)
+ def set_encoding(extern, intern = nil, override: true)
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_external = extern unless extern.nil? || extern.empty?
Encoding.default_internal = intern unless intern.nil? || intern.empty?
- @CONF[:ENCODINGS] = IRB::DefaultEncodings.new(extern, intern)
[$stdin, $stdout, $stderr].each do |io|
io.set_encoding(extern, intern)
end
- @CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern)
+ if override
+ @CONF[:LC_MESSAGES].instance_variable_set(:@override_encoding, extern)
+ else
+ @CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern)
+ end
ensure
$VERBOSE = verbose
end
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index a1777d7904..9fbbaeb0f3 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -133,6 +133,9 @@ module IRB
include Readline
# Creates a new input method object using Readline
def initialize
+ if Readline.respond_to?(:encoding_system_needs)
+ IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
+ end
super
@line_no = 0
@@ -207,6 +210,7 @@ module IRB
include Reline
# Creates a new input method object using Readline
def initialize
+ IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)
super
@line_no = 0
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
index c3208954c5..658fe813f1 100644
--- a/lib/irb/irb.gemspec
+++ b/lib/irb/irb.gemspec
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
spec.license = "BSD-2-Clause"
spec.files = [
+ ".document",
"Gemfile",
"LICENSE.txt",
"README.md",
@@ -38,6 +39,7 @@ Gem::Specification.new do |spec|
"lib/irb/color.rb",
"lib/irb/completion.rb",
"lib/irb/context.rb",
+ "lib/irb/easter-egg.rb",
"lib/irb/ext/change-ws.rb",
"lib/irb/ext/history.rb",
"lib/irb/ext/loader.rb",
@@ -52,7 +54,6 @@ Gem::Specification.new do |spec|
"lib/irb/init.rb",
"lib/irb/input-method.rb",
"lib/irb/inspector.rb",
- "lib/irb/lc/.document",
"lib/irb/lc/error.rb",
"lib/irb/lc/help-message",
"lib/irb/lc/ja/encoding_aliases.rb",
diff --git a/lib/irb/lc/.document b/lib/irb/lc/.document
deleted file mode 100644
index 524bb9430b..0000000000
--- a/lib/irb/lc/.document
+++ /dev/null
@@ -1,4 +0,0 @@
-# hide help-message files which contain usage information
-error.rb
-ja/encoding_aliases.rb
-ja/error.rb
diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb
index ba833eced4..bb44b41002 100644
--- a/lib/irb/locale.rb
+++ b/lib/irb/locale.rb
@@ -24,6 +24,7 @@ module IRB # :nodoc:
@@loaded = []
def initialize(locale = nil)
+ @override_encoding = nil
@lang = @territory = @encoding_name = @modifier = nil
@locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C"
if m = LOCALE_NAME_RE.match(@locale)
@@ -40,12 +41,16 @@ module IRB # :nodoc:
@encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
end
- attr_reader :lang, :territory, :encoding, :modifier
+ attr_reader :lang, :territory, :modifier
+
+ def encoding
+ @override_encoding || @encoding
+ end
def String(mes)
mes = super(mes)
- if @encoding
- mes.encode(@encoding, undef: :replace)
+ if encoding
+ mes.encode(encoding, undef: :replace)
else
mes
end
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index b4c31c16fe..d5630c8b52 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -211,6 +211,8 @@ class RubyLex
else
RubyVM::InstructionSequence.compile(code)
end
+ rescue EncodingError
+ # This is for a hash with invalid encoding symbol, {"\xAE": 1}
rescue SyntaxError => e
case e.message
when /unterminated (?:string|regexp) meets end of file/
@@ -317,11 +319,13 @@ class RubyLex
def check_newline_depth_difference
depth_difference = 0
+ open_brace_on_line = 0
@tokens.each_with_index do |t, index|
case t[1]
when :on_ignored_nl, :on_nl, :on_comment
if index != (@tokens.size - 1)
depth_difference = 0
+ open_brace_on_line = 0
end
next
when :on_sp
@@ -330,8 +334,9 @@ class RubyLex
case t[1]
when :on_lbracket, :on_lbrace, :on_lparen
depth_difference += 1
+ open_brace_on_line += 1
when :on_rbracket, :on_rbrace, :on_rparen
- depth_difference -= 1
+ depth_difference -= 1 if open_brace_on_line > 0
when :on_kw
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
case t[2]
@@ -365,6 +370,7 @@ class RubyLex
is_first_printable_of_line = true
spaces_of_nest = []
spaces_at_line_head = 0
+ open_brace_on_line = 0
@tokens.each_with_index do |t, index|
case t[1]
when :on_ignored_nl, :on_nl, :on_comment
@@ -372,6 +378,7 @@ class RubyLex
spaces_at_line_head = 0
is_first_spaces_of_line = true
is_first_printable_of_line = true
+ open_brace_on_line = 0
next
when :on_sp
spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
@@ -380,7 +387,8 @@ class RubyLex
end
case t[1]
when :on_lbracket, :on_lbrace, :on_lparen
- spaces_of_nest.push(spaces_at_line_head)
+ spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2)
+ open_brace_on_line += 1
when :on_rbracket, :on_rbrace, :on_rparen
if is_first_printable_of_line
corresponding_token_depth = spaces_of_nest.pop
@@ -388,6 +396,7 @@ class RubyLex
spaces_of_nest.pop
corresponding_token_depth = nil
end
+ open_brace_on_line -= 1
when :on_kw
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
case t[2]
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index 9b8bd9b161..7669c1c535 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -11,7 +11,7 @@
#
module IRB # :nodoc:
- VERSION = "1.2.1"
+ VERSION = "1.2.3"
@RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2019-12-24"
+ @LAST_UPDATE_DATE = "2020-02-15"
end
diff --git a/lib/net/pop/net-pop.gemspec b/lib/net/pop/net-pop.gemspec
index 8166968d7d..c1b0ffbd2b 100644
--- a/lib/net/pop/net-pop.gemspec
+++ b/lib/net/pop/net-pop.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/net/smtp/net-smtp.gemspec b/lib/net/smtp/net-smtp.gemspec
index e9635cd091..1dddfa7ca8 100644
--- a/lib/net/smtp/net-smtp.gemspec
+++ b/lib/net/smtp/net-smtp.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/observer/observer.gemspec b/lib/observer/observer.gemspec
index 625a30eada..188c6bae76 100644
--- a/lib/observer/observer.gemspec
+++ b/lib/observer/observer.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/open3/open3.gemspec b/lib/open3/open3.gemspec
index 65ddaa4723..543416e427 100644
--- a/lib/open3/open3.gemspec
+++ b/lib/open3/open3.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/pstore/pstore.gemspec b/lib/pstore/pstore.gemspec
index 408af0a078..e781c77043 100644
--- a/lib/pstore/pstore.gemspec
+++ b/lib/pstore/pstore.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/reline.rb b/lib/reline.rb
index 9a9f742909..1537ee7e69 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -45,40 +45,44 @@ module Reline
@completion_quote_character = nil
end
+ def encoding
+ Reline::IOGate.encoding
+ end
+
def completion_append_character=(val)
if val.nil?
@completion_append_character = nil
elsif val.size == 1
- @completion_append_character = val.encode(Encoding::default_external)
+ @completion_append_character = val.encode(Reline::IOGate.encoding)
elsif val.size > 1
- @completion_append_character = val[0].encode(Encoding::default_external)
+ @completion_append_character = val[0].encode(Reline::IOGate.encoding)
else
@completion_append_character = nil
end
end
def basic_word_break_characters=(v)
- @basic_word_break_characters = v.encode(Encoding::default_external)
+ @basic_word_break_characters = v.encode(Reline::IOGate.encoding)
end
def completer_word_break_characters=(v)
- @completer_word_break_characters = v.encode(Encoding::default_external)
+ @completer_word_break_characters = v.encode(Reline::IOGate.encoding)
end
def basic_quote_characters=(v)
- @basic_quote_characters = v.encode(Encoding::default_external)
+ @basic_quote_characters = v.encode(Reline::IOGate.encoding)
end
def completer_quote_characters=(v)
- @completer_quote_characters = v.encode(Encoding::default_external)
+ @completer_quote_characters = v.encode(Reline::IOGate.encoding)
end
def filename_quote_characters=(v)
- @filename_quote_characters = v.encode(Encoding::default_external)
+ @filename_quote_characters = v.encode(Reline::IOGate.encoding)
end
def special_prefixes=(v)
- @special_prefixes = v.encode(Encoding::default_external)
+ @special_prefixes = v.encode(Reline::IOGate.encoding)
end
def completion_case_fold=(v)
@@ -171,7 +175,7 @@ module Reline
whole_buffer = line_editor.whole_buffer.dup
whole_buffer.taint if RUBY_VERSION < '2.7'
- if add_hist and whole_buffer and whole_buffer.chomp.size > 0
+ if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
Reline::HISTORY << whole_buffer
end
@@ -184,8 +188,8 @@ module Reline
line = line_editor.line.dup
line.taint if RUBY_VERSION < '2.7'
- if add_hist and line and line.chomp.size > 0
- Reline::HISTORY << line.chomp
+ if add_hist and line and line.chomp("\n").size > 0
+ Reline::HISTORY << line.chomp("\n")
end
line_editor.reset_line if line_editor.line.nil?
@@ -201,7 +205,7 @@ module Reline
otio = Reline::IOGate.prep
may_req_ambiguous_char_width
- line_editor.reset(prompt)
+ line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
if multiline
line_editor.multiline_on
if block_given?
@@ -332,8 +336,14 @@ module Reline
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
return if ambiguous_width
Reline::IOGate.move_cursor_column(0)
- print "\u{25bd}"
- @ambiguous_width = Reline::IOGate.cursor_pos.x
+ begin
+ output.write "\u{25bd}"
+ rescue Encoding::UndefinedConversionError
+ # LANG=C
+ @ambiguous_width = 1
+ else
+ @ambiguous_width = Reline::IOGate.cursor_pos.x
+ end
Reline::IOGate.move_cursor_column(0)
Reline::IOGate.erase_after_cursor
end
@@ -387,11 +397,15 @@ module Reline
def_instance_delegators self, :readmultiline
private :readmultiline
+ def self.encoding_system_needs
+ self.core.encoding
+ end
+
def self.core
@core ||= Core.new { |core|
core.config = Reline::Config.new
core.key_stroke = Reline::KeyStroke.new(core.config)
- core.line_editor = Reline::LineEditor.new(core.config)
+ core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
core.basic_word_break_characters = " \t\n`><=;|&{("
core.completer_word_break_characters = " \t\n`><=;|&{("
@@ -405,14 +419,11 @@ module Reline
def self.line_editor
core.line_editor
end
-
- HISTORY = History.new(core.config)
end
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
require 'reline/windows'
- if Reline::Windows.get_screen_size == [0, 0]
- # Maybe Mintty on Cygwin
+ if Reline::Windows.msys_tty?
require 'reline/ansi'
Reline::IOGate = Reline::ANSI
else
@@ -422,4 +433,5 @@ else
require 'reline/ansi'
Reline::IOGate = Reline::ANSI
end
+Reline::HISTORY = Reline::History.new(Reline.core.config)
require 'reline/general_io'
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
index 8d83da854c..3ef02d6e7a 100644
--- a/lib/reline/ansi.rb
+++ b/lib/reline/ansi.rb
@@ -1,20 +1,49 @@
require 'io/console'
class Reline::ANSI
+ def self.encoding
+ Encoding.default_external
+ end
+
+ def self.win?
+ false
+ end
+
RAW_KEYSTROKE_CONFIG = {
+ # Console (80x25)
+ [27, 91, 49, 126] => :ed_move_to_beg, # Home
+ [27, 91, 52, 126] => :ed_move_to_end, # End
+ [27, 91, 51, 126] => :key_delete, # Del
[27, 91, 65] => :ed_prev_history, # ↑
[27, 91, 66] => :ed_next_history, # ↓
[27, 91, 67] => :ed_next_char, # →
[27, 91, 68] => :ed_prev_char, # ←
- [27, 91, 51, 126] => :key_delete, # Del
- [27, 91, 49, 126] => :ed_move_to_beg, # Home
- [27, 91, 52, 126] => :ed_move_to_end, # End
+
+ # KDE
[27, 91, 72] => :ed_move_to_beg, # Home
[27, 91, 70] => :ed_move_to_end, # End
+ # Del is 0x08
+ [27, 71, 65] => :ed_prev_history, # ↑
+ [27, 71, 66] => :ed_next_history, # ↓
+ [27, 71, 67] => :ed_next_char, # →
+ [27, 71, 68] => :ed_prev_char, # ←
+
+ # GNOME
+ [27, 79, 72] => :ed_move_to_beg, # Home
+ [27, 79, 70] => :ed_move_to_end, # End
+ # Del is 0x08
+ # Arrow keys are the same of KDE
+
+ # others
[27, 32] => :em_set_mark, # M-<space>
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←
+
+ [27, 79, 65] => :ed_prev_history, # ↑
+ [27, 79, 66] => :ed_next_history, # ↓
+ [27, 79, 67] => :ed_next_char, # →
+ [27, 79, 68] => :ed_prev_char, # ←
}
@@input = STDIN
@@ -41,16 +70,23 @@ class Reline::ANSI
end
def self.retrieve_keybuffer
+ begin
result = select([@@input], [], [], 0.001)
return if result.nil?
str = @@input.read_nonblock(1024)
str.bytes.each do |c|
@@buf.push(c)
end
+ rescue EOFError
+ end
end
def self.get_screen_size
- @@input.winsize
+ s = @@input.winsize
+ return s if s[0] > 0 && s[1] > 0
+ s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
+ return s if s[0] > 0 && s[1] > 0
+ [24, 80]
rescue Errno::ENOTTY
[24, 80]
end
@@ -88,12 +124,12 @@ class Reline::ANSI
end
def self.move_cursor_column(x)
- print "\e[#{x + 1}G"
+ @@output.write "\e[#{x + 1}G"
end
def self.move_cursor_up(x)
if x > 0
- print "\e[#{x}A" if x > 0
+ @@output.write "\e[#{x}A" if x > 0
elsif x < 0
move_cursor_down(-x)
end
@@ -101,24 +137,24 @@ class Reline::ANSI
def self.move_cursor_down(x)
if x > 0
- print "\e[#{x}B" if x > 0
+ @@output.write "\e[#{x}B" if x > 0
elsif x < 0
move_cursor_up(-x)
end
end
def self.erase_after_cursor
- print "\e[K"
+ @@output.write "\e[K"
end
def self.scroll_down(x)
return if x.zero?
- print "\e[#{x}S"
+ @@output.write "\e[#{x}S"
end
def self.clear_screen
- print "\e[2J"
- print "\e[1;1H"
+ @@output.write "\e[2J"
+ @@output.write "\e[1;1H"
end
@@old_winch_handler = nil
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
index fdc2b39c1b..53b868fd2e 100644
--- a/lib/reline/config.rb
+++ b/lib/reline/config.rb
@@ -83,8 +83,17 @@ class Reline::Config
@key_actors[@keymap_label]
end
+ def inputrc_path
+ case ENV['INPUTRC']
+ when nil, ''
+ DEFAULT_PATH
+ else
+ ENV['INPUTRC']
+ end
+ end
+
def read(file = nil)
- file ||= File.expand_path(ENV['INPUTRC'] || DEFAULT_PATH)
+ file ||= File.expand_path(inputrc_path)
begin
if file.respond_to?(:readlines)
lines = file.readlines
@@ -184,9 +193,8 @@ class Reline::Config
def bind_variable(name, value)
case name
- when *VARIABLE_NAMES then
- variable_name = :"@#{name.tr(?-, ?_)}"
- instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
+ when 'history-size'
+ @history_size = value.to_i
when 'bell-style'
@bell_style =
case value
@@ -225,6 +233,9 @@ class Reline::Config
end
when 'keyseq-timeout'
@keyseq_timeout = value.to_i
+ when *VARIABLE_NAMES then
+ variable_name = :"@#{name.tr(?-, ?_)}"
+ instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
end
end
diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
index 291c14c7b3..85f1f13eed 100644
--- a/lib/reline/general_io.rb
+++ b/lib/reline/general_io.rb
@@ -1,6 +1,14 @@
require 'timeout'
class Reline::GeneralIO
+ def self.encoding
+ RUBY_PLATFORM =~ /mswin|mingw/ ? Encoding::UTF_8 : Encoding::default_external
+ end
+
+ def self.win?
+ false
+ end
+
RAW_KEYSTROKE_CONFIG = {}
@@buf = []
diff --git a/lib/reline/history.rb b/lib/reline/history.rb
index 238fcf2a76..d95f1cebc3 100644
--- a/lib/reline/history.rb
+++ b/lib/reline/history.rb
@@ -19,7 +19,7 @@ class Reline::History < Array
def []=(index, val)
index = check_index(index)
- super(index, String.new(val, encoding: Encoding::default_external))
+ super(index, String.new(val, encoding: Reline.encoding_system_needs))
end
def concat(*val)
@@ -39,12 +39,12 @@ class Reline::History < Array
val.shift(diff)
end
end
- super(*(val.map{ |v| String.new(v, encoding: Encoding::default_external) }))
+ super(*(val.map{ |v| String.new(v, encoding: Reline.encoding_system_needs) }))
end
def <<(val)
shift if size + 1 > @config.history_size
- super(String.new(val, encoding: Encoding::default_external))
+ super(String.new(val, encoding: Reline.encoding_system_needs))
end
private def check_index(index)
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 75af50a908..095a7b5a09 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -57,10 +57,10 @@ class Reline::LineEditor
NON_PRINTING_END = "\2"
WIDTH_SCANNER = /\G(?:#{NON_PRINTING_START}|#{NON_PRINTING_END}|#{CSI_REGEXP}|#{OSC_REGEXP}|\X)/
- def initialize(config)
+ def initialize(config, encoding)
@config = config
@completion_append_character = ''
- reset_variables
+ reset_variables(encoding: encoding)
end
private def check_multiline_prompt(buffer, prompt)
@@ -85,10 +85,10 @@ class Reline::LineEditor
end
end
- def reset(prompt = '', encoding = Encoding.default_external)
+ def reset(prompt = '', encoding:)
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
@screen_size = Reline::IOGate.get_screen_size
- reset_variables(prompt, encoding)
+ reset_variables(prompt, encoding: encoding)
@old_trap = Signal.trap('SIGINT') {
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
raise Interrupt
@@ -139,7 +139,7 @@ class Reline::LineEditor
@eof
end
- def reset_variables(prompt = '', encoding = Encoding.default_external)
+ def reset_variables(prompt = '', encoding:)
@prompt = prompt
@mark_pointer = nil
@encoding = encoding
@@ -317,9 +317,9 @@ class Reline::LineEditor
if @menu_info
scroll_down(@highest_in_all - @first_line_started_from)
@rerender_all = true
- @menu_info.list.each do |item|
+ @menu_info.list.sort!.each do |item|
Reline::IOGate.move_cursor_column(0)
- @output.print item
+ @output.write item
@output.flush
scroll_down(1)
end
@@ -507,12 +507,20 @@ class Reline::LineEditor
Reline::IOGate.move_cursor_column(0)
visual_lines.each_with_index do |line, index|
if line.nil?
- Reline::IOGate.erase_after_cursor
- move_cursor_down(1)
- Reline::IOGate.move_cursor_column(0)
+ if Reline::IOGate.win? and calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
+ # A newline is automatically inserted if a character is rendered at eol on command prompt.
+ else
+ Reline::IOGate.erase_after_cursor
+ move_cursor_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ end
next
end
- @output.print line
+ @output.write line
+ if Reline::IOGate.win? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
+ # A newline is automatically inserted if a character is rendered at eol on command prompt.
+ @rest_height -= 1 if @rest_height > 0
+ end
@output.flush
if @first_prompt
@first_prompt = false
@@ -535,7 +543,7 @@ class Reline::LineEditor
return before if before.nil? || before.empty?
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
- after.lines(chomp: true)
+ after.lines("\n", chomp: true)
else
before
end
@@ -905,7 +913,6 @@ class Reline::LineEditor
quote = nil
i += 1
rest = nil
- break_pointer = nil
elsif quote and slice.start_with?(escaped_quote)
# skip
i += 2
@@ -915,7 +922,7 @@ class Reline::LineEditor
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
escaped_quote = /\\#{Regexp.escape(quote)}/
i += 1
- break_pointer = i
+ break_pointer = i - 1
elsif not quote and slice =~ word_break_regexp
rest = $'
i += 1
@@ -937,6 +944,11 @@ class Reline::LineEditor
end
else
preposing = ''
+ if break_pointer
+ preposing = @line.byteslice(0, break_pointer)
+ else
+ preposing = ''
+ end
target = before
end
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
@@ -1091,6 +1103,11 @@ class Reline::LineEditor
private def ed_insert(key)
if key.instance_of?(String)
+ begin
+ key.encode(Encoding::UTF_8)
+ rescue Encoding::UndefinedConversionError
+ return
+ end
width = Reline::Unicode.get_mbchar_width(key)
if @cursor == @cursor_max
@line += key
@@ -1101,6 +1118,11 @@ class Reline::LineEditor
@cursor += width
@cursor_max += width
else
+ begin
+ key.chr.encode(Encoding::UTF_8)
+ rescue Encoding::UndefinedConversionError
+ return
+ end
if @cursor == @cursor_max
@line += key.chr
else
@@ -1876,6 +1898,16 @@ class Reline::LineEditor
end
end
+ private def vi_insert_at_bol(key)
+ ed_move_to_beg(key)
+ @config.editing_mode = :vi_insert
+ end
+
+ private def vi_add_at_eol(key)
+ ed_move_to_end(key)
+ @config.editing_mode = :vi_insert
+ end
+
private def ed_delete_prev_char(key, arg: 1)
deleted = ''
arg.times do
@@ -1898,6 +1930,18 @@ class Reline::LineEditor
end
private def vi_change_meta(key)
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ @cursor += cursor_diff if cursor_diff < 0
+ @cursor_max -= cursor_diff.abs
+ @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
+ @config.editing_mode = :vi_insert
+ }
end
private def vi_delete_meta(key)
@@ -2063,12 +2107,17 @@ class Reline::LineEditor
@waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg) }
end
- private def search_next_char(key, arg)
+ private def vi_to_next_char(key, arg: 1)
+ @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, true) }
+ end
+
+ private def search_next_char(key, arg, need_prev_char = false)
if key.instance_of?(String)
inputed_char = key
else
inputed_char = key.chr
end
+ prev_total = nil
total = nil
found = false
@line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
@@ -2086,13 +2135,66 @@ class Reline::LineEditor
end
end
width = Reline::Unicode.get_mbchar_width(mbchar)
+ prev_total = total
total = [total.first + mbchar.bytesize, total.last + width]
end
end
- if found and total
+ if not need_prev_char and found and total
byte_size, width = total
@byte_pointer += byte_size
@cursor += width
+ elsif need_prev_char and found and prev_total
+ byte_size, width = prev_total
+ @byte_pointer += byte_size
+ @cursor += width
+ end
+ @waiting_proc = nil
+ end
+
+ private def vi_prev_char(key, arg: 1)
+ @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg) }
+ end
+
+ private def vi_to_prev_char(key, arg: 1)
+ @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg, true) }
+ end
+
+ private def search_prev_char(key, arg, need_next_char = false)
+ if key.instance_of?(String)
+ inputed_char = key
+ else
+ inputed_char = key.chr
+ end
+ prev_total = nil
+ total = nil
+ found = false
+ @line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
+ # total has [byte_size, cursor]
+ unless total
+ # skip cursor point
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ total = [mbchar.bytesize, width]
+ else
+ if inputed_char == mbchar
+ arg -= 1
+ if arg.zero?
+ found = true
+ break
+ end
+ end
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ prev_total = total
+ total = [total.first + mbchar.bytesize, total.last + width]
+ end
+ end
+ if not need_next_char and found and total
+ byte_size, width = total
+ @byte_pointer -= byte_size
+ @cursor -= width
+ elsif need_next_char and found and prev_total
+ byte_size, width = prev_total
+ @byte_pointer -= byte_size
+ @cursor -= width
end
@waiting_proc = nil
end
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
index 47b29bd946..1bf544d74b 100644
--- a/lib/reline/version.rb
+++ b/lib/reline/version.rb
@@ -1,3 +1,3 @@
module Reline
- VERSION = '0.1.2'
+ VERSION = '0.1.3'
end
diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
index aef3073a7e..c229c8536f 100644
--- a/lib/reline/windows.rb
+++ b/lib/reline/windows.rb
@@ -1,6 +1,14 @@
require 'fiddle/import'
class Reline::Windows
+ def self.encoding
+ Encoding::UTF_8
+ end
+
+ def self.win?
+ true
+ end
+
RAW_KEYSTROKE_CONFIG = {
[224, 72] => :ed_prev_history, # ↑
[224, 80] => :ed_next_history, # ↓
@@ -68,6 +76,8 @@ class Reline::Windows
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
WINDOW_BUFFER_SIZE_EVENT = 0x04
+ FILE_TYPE_PIPE = 0x0003
+ FILE_NAME_INFO = 2
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
@@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
@@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
@@ -80,9 +90,36 @@ class Reline::Windows
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
@@ReadConsoleInput = Win32API.new('kernel32', 'ReadConsoleInput', ['L', 'P', 'L', 'P'], 'L')
+ @@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
+ @@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
+
@@input_buf = []
@@output_buf = []
+ def self.msys_tty?(io=@@hConsoleInputHandle)
+ # check if fd is a pipe
+ if @@GetFileType.call(io) != FILE_TYPE_PIPE
+ return false
+ end
+
+ bufsize = 1024
+ p_buffer = "\0" * bufsize
+ res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
+ return false if res == 0
+
+ # get pipe name: p_buffer layout is:
+ # struct _FILE_NAME_INFO {
+ # DWORD FileNameLength;
+ # WCHAR FileName[1];
+ # } FILE_NAME_INFO
+ len = p_buffer[0, 4].unpack("L")[0]
+ name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
+
+ # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
+ # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
+ name =~ /(msys-|cygwin-).*-pty/ ? true : false
+ end
+
def self.getwch
unless @@input_buf.empty?
return @@input_buf.shift
@@ -99,7 +136,7 @@ class Reline::Windows
return @@input_buf.shift
end
begin
- bytes = ret.chr(Encoding::UTF_8).encode(Encoding.default_external).bytes
+ bytes = ret.chr(Encoding::UTF_8).bytes
@@input_buf.push(*bytes)
rescue Encoding::UndefinedConversionError
@@input_buf << ret
@@ -205,7 +242,7 @@ class Reline::Windows
def self.scroll_down(val)
return if val.zero?
- scroll_rectangle = [0, val, get_screen_size.first, get_screen_size.last].pack('s4')
+ scroll_rectangle = [0, val, get_screen_size.last, get_screen_size.first].pack('s4')
destination_origin = 0 # y * 65536 + x
fill = [' '.ord, 0].pack('SS')
@@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
@@ -213,8 +250,8 @@ class Reline::Windows
def self.clear_screen
# TODO: Use FillConsoleOutputCharacter and FillConsoleOutputAttribute
- print "\e[2J"
- print "\e[1;1H"
+ write "\e[2J"
+ write "\e[1;1H"
end
def self.set_screen_size(rows, columns)
diff --git a/lib/singleton/singleton.gemspec b/lib/singleton/singleton.gemspec
index f7ee6bb2dc..c6a273a839 100644
--- a/lib/singleton/singleton.gemspec
+++ b/lib/singleton/singleton.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/timeout/timeout.gemspec b/lib/timeout/timeout.gemspec
index 88babe9f8b..7b650bdc31 100644
--- a/lib/timeout/timeout.gemspec
+++ b/lib/timeout/timeout.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["source_code_uri"] = spec.homepage
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/uri/uri.gemspec b/lib/uri/uri.gemspec
index 5c51721755..95cb8e2d42 100644
--- a/lib/uri/uri.gemspec
+++ b/lib/uri/uri.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/yaml/yaml.gemspec b/lib/yaml/yaml.gemspec
index d78e8164a4..ba5027a9b6 100644
--- a/lib/yaml/yaml.gemspec
+++ b/lib/yaml/yaml.gemspec
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/test/io/console/test_io_console.rb b/test/io/console/test_io_console.rb
index d71e42603f..a02605dd1e 100644
--- a/test/io/console/test_io_console.rb
+++ b/test/io/console/test_io_console.rb
@@ -364,6 +364,11 @@ defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do
assert_ctrl("#{cc.ord}", cc, r, w)
assert_ctrl("#{cc.ord}", cc, r, w)
end
+ if cc = ctrl["stop"]
+ assert_ctrl("#{cc.ord}", cc, r, w)
+ assert_ctrl("#{cc.ord}", cc, r, w)
+ assert_ctrl("#{cc.ord}", cc, r, w)
+ end
end
end
@@ -457,7 +462,7 @@ defined?(IO.console) and TestIO_Console.class_eval do
noctty = [EnvUtil.rubybin, "-e", "Process.daemon(true)"]
when !(rubyw = RbConfig::CONFIG["RUBYW_INSTALL_NAME"]).empty?
dir, base = File.split(EnvUtil.rubybin)
- noctty = [File.join(dir, base.sub(/ruby/, rubyw))]
+ noctty = [File.join(dir, base.sub(RUBY_ENGINE, rubyw))]
end
if noctty
diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb
index 3ced640004..cb90d29c9d 100644
--- a/test/irb/test_color.rb
+++ b/test/irb/test_color.rb
@@ -29,7 +29,7 @@ module TestIRB
"def self.foo; bar; end" => "#{GREEN}def#{CLEAR} #{CYAN}#{BOLD}self#{CLEAR}.#{BLUE}#{BOLD}foo#{CLEAR}; bar; #{GREEN}end#{CLEAR}",
'erb = ERB.new("a#{nil}b", trim_mode: "-")' => "erb = #{BLUE}#{BOLD}#{UNDERLINE}ERB#{CLEAR}.new(#{RED}#{BOLD}\"#{CLEAR}#{RED}a#{CLEAR}#{RED}\#{#{CLEAR}#{CYAN}#{BOLD}nil#{CLEAR}#{RED}}#{CLEAR}#{RED}b#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}, #{MAGENTA}trim_mode:#{CLEAR} #{RED}#{BOLD}\"#{CLEAR}#{RED}-#{CLEAR}#{RED}#{BOLD}\"#{CLEAR})",
"# comment" => "#{BLUE}#{BOLD}# comment#{CLEAR}",
- "yield(hello)" => "#{GREEN}yield#{CLEAR}(hello)",
+ "def f;yield(hello);end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}f#{CLEAR};#{GREEN}yield#{CLEAR}(hello);#{GREEN}end#{CLEAR}",
'"##@var]"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}\##{CLEAR}#{RED}\##{CLEAR}@var#{RED}]#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
'"foo#{a} #{b}"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}a#{RED}}#{CLEAR}#{RED} #{CLEAR}#{RED}\#{#{CLEAR}b#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
'/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e#{RED}}#{CLEAR}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb
index 52bbc7b2cc..a765bbf3a5 100644
--- a/test/irb/test_completion.rb
+++ b/test/irb/test_completion.rb
@@ -25,5 +25,27 @@ module TestIRB
assert_include(IRB::InputCompletor.retrieve_completion_data("1r.positi", bind: binding), "1r.positive?")
assert_empty(IRB::InputCompletor.retrieve_completion_data("1i.positi", bind: binding))
end
+
+ def test_complete_symbol
+ _ = :aiueo
+ assert_include(IRB::InputCompletor.retrieve_completion_data(":a", bind: binding), ":aiueo")
+ assert_empty(IRB::InputCompletor.retrieve_completion_data(":irb_unknown_symbol_abcdefg", bind: binding))
+ end
+
+ def test_complete_symbol_failure
+ assert_nil(IRB::InputCompletor::PerfectMatchedProc.(":aiueo", bind: binding))
+ end
+
+ def test_complete_reserved_words
+ candidates = IRB::InputCompletor.retrieve_completion_data("de", bind: binding)
+ %w[def defined?].each do |word|
+ assert_include candidates, word
+ end
+
+ candidates = IRB::InputCompletor.retrieve_completion_data("__", bind: binding)
+ %w[__ENCODING__ __LINE__ __FILE__].each do |word|
+ assert_include candidates, word
+ end
+ end
end
end
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
index 693ebbeaea..d03cc30c78 100644
--- a/test/irb/test_context.rb
+++ b/test/irb/test_context.rb
@@ -63,6 +63,13 @@ module TestIRB
assert_not_match(/rescue _\.class/, e.message)
end
+ def test_evaluate_with_encoding_error_without_lineno
+ assert_raise_with_message(EncodingError, /invalid symbol/) {
+ @context.evaluate(%q[{"\xAE": 1}], 1)
+ # The backtrace of this invalid encoding hash doesn't contain lineno.
+ }
+ end
+
def test_evaluate_with_onigmo_warning
assert_warning("(irb):1: warning: character class has duplicated range: /[aa]/\n") do
@context.evaluate('/[aa]/', 1)
@@ -216,5 +223,36 @@ module TestIRB
assert(irb.context.echo?, "echo? should be true by default")
assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to true")
end
+
+ def test_multiline_output_on_default_inspector
+ main = Object.new
+ def main.inspect
+ "abc\ndef"
+ end
+ input = TestInputMethod.new([
+ "self"
+ ])
+ irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
+ irb.context.return_format = "=> %s\n"
+
+ # The default
+ irb.context.newline_before_multiline_output = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> \nabc\ndef\n",
+ out)
+
+ # No newline before multiline output
+ input.reset
+ irb.context.newline_before_multiline_output = false
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> abc\ndef\n",
+ out)
+ end
end
end
diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb
new file mode 100644
index 0000000000..dd5a1f7ca5
--- /dev/null
+++ b/test/irb/test_ruby_lex.rb
@@ -0,0 +1,130 @@
+$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
+require 'irb/ruby-lex'
+require 'test/unit'
+require 'ostruct'
+
+module TestIRB
+ class TestRubyLex < Test::Unit::TestCase
+ Row = Struct.new(:content, :current_line_spaces, :new_line_spaces)
+
+ class MockIO
+ def initialize(params, &assertion)
+ @params = params
+ @assertion = assertion
+ end
+
+ def auto_indent(&block)
+ result = block.call(*@params)
+ @assertion.call(result)
+ end
+ end
+
+ def assert_indenting(lines, correct_space_count, add_new_line)
+ lines = lines + [""] if add_new_line
+ last_line_index = lines.length - 1
+ byte_pointer = lines.last.length
+
+ ruby_lex = RubyLex.new()
+ io = MockIO.new([lines, last_line_index, byte_pointer, add_new_line]) do |auto_indent|
+ error_message = "Calculated the wrong number of spaces for:\n #{lines.join("\n")}"
+ assert_equal(correct_space_count, auto_indent, error_message)
+ end
+ ruby_lex.set_input(io)
+ context = OpenStruct.new(auto_indent_mode: true)
+ ruby_lex.set_auto_indent(context)
+ end
+
+ def test_auto_indent
+ input_with_correct_indents = [
+ Row.new(%q(def each_top_level_statement), nil, 2),
+ Row.new(%q( initialize_input), nil, 2),
+ Row.new(%q( catch(:TERM_INPUT) do), nil, 4),
+ Row.new(%q( loop do), nil, 6),
+ Row.new(%q( begin), nil, 8),
+ Row.new(%q( prompt), nil, 8),
+ Row.new(%q( unless l = lex), nil, 10),
+ Row.new(%q( throw :TERM_INPUT if @line == ''), nil, 10),
+ Row.new(%q( else), 8, 10),
+ Row.new(%q( @line_no += l.count("\n")), nil, 10),
+ Row.new(%q( next if l == "\n"), nil, 10),
+ Row.new(%q( @line.concat l), nil, 10),
+ Row.new(%q( if @code_block_open or @ltype or @continue or @indent > 0), nil, 12),
+ Row.new(%q( next), nil, 12),
+ Row.new(%q( end), 10, 10),
+ Row.new(%q( end), 8, 8),
+ Row.new(%q( if @line != "\n"), nil, 10),
+ Row.new(%q( @line.force_encoding(@io.encoding)), nil, 10),
+ Row.new(%q( yield @line, @exp_line_no), nil, 10),
+ Row.new(%q( end), 8, 8),
+ Row.new(%q( break if @io.eof?), nil, 8),
+ Row.new(%q( @line = ''), nil, 8),
+ Row.new(%q( @exp_line_no = @line_no), nil, 8),
+ Row.new(%q( ), nil, 8),
+ Row.new(%q( @indent = 0), nil, 8),
+ Row.new(%q( rescue TerminateLineInput), 6, 8),
+ Row.new(%q( initialize_input), nil, 8),
+ Row.new(%q( prompt), nil, 8),
+ Row.new(%q( end), 6, 6),
+ Row.new(%q( end), 4, 4),
+ Row.new(%q( end), 2, 2),
+ Row.new(%q(end), 0, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_braces_on_their_own_line
+ input_with_correct_indents = [
+ Row.new(%q(if true), nil, 2),
+ Row.new(%q( [), nil, 4),
+ Row.new(%q( ]), 2, 2),
+ Row.new(%q(end), 0, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_multiple_braces_in_a_line
+ input_with_correct_indents = [
+ Row.new(%q([[[), nil, 6),
+ Row.new(%q( ]), 4, 4),
+ Row.new(%q( ]), 2, 2),
+ Row.new(%q(]), 0, 0),
+ Row.new(%q([<<FOO]), nil, 0),
+ Row.new(%q(hello), nil, 0),
+ Row.new(%q(FOO), nil, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_a_closed_brace_and_not_closed_brace_in_a_line
+ input_with_correct_indents = [
+ Row.new(%q(p() {), nil, 2),
+ Row.new(%q(}), 0, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+ end
+end
diff --git a/test/readline/helper.rb b/test/readline/helper.rb
index ee157722f1..1b80327b57 100644
--- a/test/readline/helper.rb
+++ b/test/readline/helper.rb
@@ -3,18 +3,22 @@ begin
ReadlineSo = Readline
rescue LoadError
end
-require "reline"
def use_ext_readline # Use ext/readline as Readline
Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
Object.const_set(:Readline, ReadlineSo)
end
-def use_lib_reline # Use lib/reline as Readline
- Reline.send(:remove_const, 'IOGate') if Reline.const_defined?('IOGate')
- Reline.const_set('IOGate', Reline::GeneralIO)
- Reline.send(:core).config.instance_variable_set(:@test_mode, true)
- Reline.send(:core).config.reset
- Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
- Object.const_set(:Readline, Reline)
+begin
+ require "reline"
+rescue LoadError
+else
+ def use_lib_reline # Use lib/reline as Readline
+ Reline.send(:remove_const, 'IOGate') if Reline.const_defined?('IOGate')
+ Reline.const_set('IOGate', Reline::GeneralIO)
+ Reline.send(:core).config.instance_variable_set(:@test_mode, true)
+ Reline.send(:core).config.reset
+ Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
+ Object.const_set(:Readline, Reline)
+ end
end
diff --git a/test/readline/test_readline.rb b/test/readline/test_readline.rb
index be9ac24d25..7ac2212719 100644
--- a/test/readline/test_readline.rb
+++ b/test/readline/test_readline.rb
@@ -21,13 +21,16 @@ module BasetestReadline
Readline.point = 0
rescue NotImplementedError
end
+ Readline.special_prefixes = ""
+ Readline.completion_append_character = nil
Readline.input = nil
Readline.output = nil
SAVED_ENV.each_with_index {|k, i| ENV[k] = @saved_env[i] }
end
def test_readline
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ Readline::HISTORY.clear
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
with_temp_stdio do |stdin, stdout|
stdin.write("hello\n")
stdin.close
@@ -45,7 +48,7 @@ module BasetestReadline
# Work around lack of SecurityError in Reline
# test mode with tainted prompt.
# Also skip test on Ruby 2.7+, where $SAFE/taint is deprecated.
- if RUBY_VERSION < '2.7' && !kind_of?(TestRelineAsReadline)
+ if RUBY_VERSION < '2.7' && defined?(TestRelineAsReadline) && !kind_of?(TestRelineAsReadline)
begin
Thread.start {
$SAFE = 1
@@ -65,8 +68,8 @@ module BasetestReadline
# line_buffer
# point
def test_line_buffer__point
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- skip "GNU Readline has special behaviors" if defined?(Reline) and Readline == Reline
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "GNU Readline has special behaviors" if defined?(Reline) and Readline == Reline
begin
Readline.line_buffer
Readline.point
@@ -154,7 +157,7 @@ module BasetestReadline
end
def test_completion_proc_empty_result
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
with_temp_stdio do |stdin, stdout|
stdin.write("first\t")
stdin.flush
@@ -233,12 +236,12 @@ module BasetestReadline
end
def test_completion_encoding
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
bug5941 = '[Bug #5941]'
append_character = Readline.completion_append_character
Readline.completion_append_character = ""
completion_case_fold = Readline.completion_case_fold
- locale = Encoding.find("locale")
+ locale = get_default_internal_encoding
if locale == Encoding::UTF_8
enc1 = Encoding::EUC_JP
else
@@ -261,7 +264,7 @@ module BasetestReadline
end or
begin
return if assert_under_utf8
- skip("missing test for locale #{locale.name}")
+ omit("missing test for locale #{locale.name}")
end
expected = results[0][0...1]
Readline.completion_case_fold = false
@@ -285,32 +288,6 @@ module BasetestReadline
# filename_quote_characters
# special_prefixes
def test_some_characters_methods
- method_names = [
- "basic_word_break_characters",
- "completer_word_break_characters",
- "basic_quote_characters",
- "completer_quote_characters",
- "filename_quote_characters",
- "special_prefixes",
- ]
- method_names.each do |method_name|
- begin
- begin
- enc = get_default_internal_encoding
- saved = Readline.send(method_name.to_sym)
- expecteds = [" ", " .,|\t", ""]
- expecteds.each do |e|
- Readline.send((method_name + "=").to_sym, e)
- res = Readline.send(method_name.to_sym)
- assert_equal(e, res)
- assert_equal(enc, res.encoding, "Readline.#{method_name} should be #{enc.name}")
- end
- ensure
- Readline.send((method_name + "=").to_sym, saved) if saved
- end
- rescue NotImplementedError
- end
- end
end
def test_closed_outstream
@@ -335,7 +312,7 @@ module BasetestReadline
end
def test_point
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
assert_equal(0, Readline.point)
Readline.insert_text('12345')
assert_equal(5, Readline.point)
@@ -350,7 +327,7 @@ module BasetestReadline
end
def test_insert_text
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
str = "test_insert_text"
assert_equal(0, Readline.point)
assert_equal(Readline, Readline.insert_text(str))
@@ -381,7 +358,7 @@ module BasetestReadline
end
def test_delete_text
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
str = "test_insert_text"
assert_equal(0, Readline.point)
assert_equal(Readline, Readline.insert_text(str))
@@ -401,7 +378,7 @@ module BasetestReadline
end
def test_modify_text_in_pre_input_hook
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
with_temp_stdio {|stdin, stdout|
begin
stdin.write("world\n")
@@ -432,9 +409,10 @@ module BasetestReadline
end
def test_input_metachar
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- skip("Won't pass on mingw w/readline 7.0.005 [ruby-core:45682]") if mingw?
- skip 'Needs GNU Readline 6 or later' if windows? and defined?(TestReadline) and kind_of?(TestReadline) and Readline::VERSION < '6.0'
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ # test will pass on Windows reline, but not readline
+ omit "Won't pass on mingw readline.so using 8.0.001" if /mingw/ =~ RUBY_PLATFORM and defined?(TestReadline) and kind_of?(TestReadline)
+ omit 'Needs GNU Readline 6 or later' if /mswin|mingw/ =~ RUBY_PLATFORM and defined?(TestReadline) and kind_of?(TestReadline) and Readline::VERSION < '6.0'
bug6601 = '[ruby-core:45682]'
Readline::HISTORY << "hello"
wo = nil
@@ -451,10 +429,10 @@ module BasetestReadline
end
def test_input_metachar_multibyte
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
unless Encoding.find("locale") == Encoding::UTF_8
return if assert_under_utf8
- skip 'this test needs UTF-8 locale'
+ omit 'this test needs UTF-8 locale'
end
bug6602 = '[ruby-core:45683]'
Readline::HISTORY << "\u3042\u3093"
@@ -481,7 +459,8 @@ module BasetestReadline
end
def test_refresh_line
- skip "Only when refresh_line exists" unless Readline.respond_to?(:refresh_line)
+ omit "Only when refresh_line exists" unless Readline.respond_to?(:refresh_line)
+ omit unless respond_to?(:assert_ruby_status)
bug6232 = '[ruby-core:43957] [Bug #6232] refresh_line after set_screen_size'
with_temp_stdio do |stdin, stdout|
replace_stdio(stdin.path, stdout.path) do
@@ -508,83 +487,98 @@ module BasetestReadline
def test_using_quoting_detection_proc
saved_completer_quote_characters = Readline.completer_quote_characters
saved_completer_word_break_characters = Readline.completer_word_break_characters
+
+ # skip if previous value is nil because Readline... = nil is not allowed.
+ skip unless saved_completer_quote_characters
+ skip unless saved_completer_word_break_characters
+
return unless Readline.respond_to?(:quoting_detection_proc=)
- passed_text = nil
- line = nil
+ begin
+ passed_text = nil
+ line = nil
- with_temp_stdio do |stdin, stdout|
- replace_stdio(stdin.path, stdout.path) do
- Readline.completion_proc = ->(text) do
- passed_text = text
- ['completion'].map { |i|
- i.encode(Encoding.default_external)
- }
- end
- Readline.completer_quote_characters = '\'"'
- Readline.completer_word_break_characters = ' '
- Readline.quoting_detection_proc = ->(text, index) do
- index > 0 && text[index-1] == '\\'
- end
+ with_temp_stdio do |stdin, stdout|
+ replace_stdio(stdin.path, stdout.path) do
+ Readline.completion_proc = ->(text) do
+ passed_text = text
+ ['completion'].map { |i|
+ i.encode(Encoding.default_external)
+ }
+ end
+ Readline.completer_quote_characters = '\'"'
+ Readline.completer_word_break_characters = ' '
+ Readline.quoting_detection_proc = ->(text, index) do
+ index > 0 && text[index-1] == '\\'
+ end
- stdin.write("first second\\ third\t")
- stdin.flush
- line = Readline.readline('> ', false)
+ stdin.write("first second\\ third\t")
+ stdin.flush
+ line = Readline.readline('> ', false)
+ end
end
- end
- assert_equal('second\\ third', passed_text)
- assert_equal('first completion', line.chomp(' '))
- ensure
- Readline.completer_quote_characters = saved_completer_quote_characters
- Readline.completer_word_break_characters = saved_completer_word_break_characters
+ assert_equal('second\\ third', passed_text)
+ assert_equal('first completion', line.chomp(' '))
+ ensure
+ Readline.completer_quote_characters = saved_completer_quote_characters
+ Readline.completer_word_break_characters = saved_completer_word_break_characters
+ end
end
def test_using_quoting_detection_proc_with_multibyte_input
+ Readline.completion_append_character = nil
saved_completer_quote_characters = Readline.completer_quote_characters
saved_completer_word_break_characters = Readline.completer_word_break_characters
+
+ # skip if previous value is nil because Readline... = nil is not allowed.
+ skip unless saved_completer_quote_characters
+ skip unless saved_completer_word_break_characters
+
return unless Readline.respond_to?(:quoting_detection_proc=)
- unless Encoding.find("locale") == Encoding::UTF_8
+ unless get_default_internal_encoding == Encoding::UTF_8
return if assert_under_utf8
- skip 'this test needs UTF-8 locale'
+ omit 'this test needs UTF-8 locale'
end
- passed_text = nil
- escaped_char_indexes = []
- line = nil
+ begin
+ passed_text = nil
+ escaped_char_indexes = []
+ line = nil
- with_temp_stdio do |stdin, stdout|
- replace_stdio(stdin.path, stdout.path) do
- Readline.completion_proc = ->(text) do
- passed_text = text
- ['completion'].map { |i|
- i.encode(Encoding.default_external)
- }
- end
- Readline.completer_quote_characters = '\'"'
- Readline.completer_word_break_characters = ' '
- Readline.quoting_detection_proc = ->(text, index) do
- escaped = index > 0 && text[index-1] == '\\'
- escaped_char_indexes << index if escaped
- escaped
- end
+ with_temp_stdio do |stdin, stdout|
+ replace_stdio(stdin.path, stdout.path) do
+ Readline.completion_proc = ->(text) do
+ passed_text = text
+ ['completion'].map { |i|
+ i.encode(Encoding.default_external)
+ }
+ end
+ Readline.completer_quote_characters = '\'"'
+ Readline.completer_word_break_characters = ' '
+ Readline.quoting_detection_proc = ->(text, index) do
+ escaped = index > 0 && text[index-1] == '\\'
+ escaped_char_indexes << index if escaped
+ escaped
+ end
- stdin.write("\u3042\u3093 second\\ third\t")
- stdin.flush
- line = Readline.readline('> ', false)
+ stdin.write("\u3042\u3093 second\\ third\t")
+ stdin.flush
+ line = Readline.readline('> ', false)
+ end
end
- end
- assert_equal([10], escaped_char_indexes)
- assert_equal('second\\ third', passed_text)
- assert_equal("\u3042\u3093 completion", line)
- ensure
- Readline.completer_quote_characters = saved_completer_quote_characters
- Readline.completer_word_break_characters = saved_completer_word_break_characters
+ assert_equal([10], escaped_char_indexes)
+ assert_equal('second\\ third', passed_text)
+ assert_equal("\u3042\u3093 completion#{Readline.completion_append_character}", line)
+ ensure
+ Readline.completer_quote_characters = saved_completer_quote_characters
+ Readline.completer_word_break_characters = saved_completer_word_break_characters
+ end
end
def test_simple_completion
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
line = nil
@@ -594,7 +588,7 @@ module BasetestReadline
Readline.output = null
Readline.completion_proc = ->(text) do
['abcde', 'abc12'].map { |i|
- i.encode(Encoding.default_external)
+ i.encode(get_default_internal_encoding)
}
end
w.write("a\t\n")
@@ -607,8 +601,8 @@ module BasetestReadline
end
def test_completion_with_completion_append_character
- skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- skip "Readline.completion_append_character is not implemented" unless Readline.respond_to?(:completion_append_character=)
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ omit "Readline.completion_append_character is not implemented" unless Readline.respond_to?(:completion_append_character=)
line = nil
append_character = Readline.completion_append_character
@@ -619,7 +613,7 @@ module BasetestReadline
Readline.completion_append_character = '!'
Readline.completion_proc = ->(text) do
['abcde'].map { |i|
- i.encode(Encoding.default_external)
+ i.encode(get_default_internal_encoding)
}
end
w.write("a\t\n")
@@ -681,9 +675,9 @@ module BasetestReadline
return unless Readline.respond_to?(:completion_quote_character)
if /solaris/i =~ RUBY_PLATFORM
# http://rubyci.s3.amazonaws.com/solaris11s-sunc/ruby-trunk/log/20181228T102505Z.fail.html.gz
- skip 'This test does not succeed on Oracle Developer Studio for now'
+ omit 'This test does not succeed on Oracle Developer Studio for now'
end
- skip 'Needs GNU Readline 6 or later' if windows? and defined?(TestReadline) and kind_of?(TestReadline) and Readline::VERSION < '6.0'
+ omit 'Needs GNU Readline 6 or later' if /mswin|mingw/ =~ RUBY_PLATFORM and defined?(TestReadline) and kind_of?(TestReadline) and Readline::VERSION < '6.0'
Readline.completion_proc = -> (_) { [] }
Readline.completer_quote_characters = "'\""
@@ -730,7 +724,7 @@ module BasetestReadline
Tempfile.create("test_readline_stdin") {|stdin|
Tempfile.create("test_readline_stdout") {|stdout|
yield stdin, stdout
- if windows?
+ if /mswin|mingw/ =~ RUBY_PLATFORM
# needed since readline holds refs to tempfiles, can't delete on Windows
Readline.input = STDIN
Readline.output = STDOUT
@@ -766,7 +760,7 @@ module BasetestReadline
return false if ENV['LC_ALL'] == 'UTF-8'
loc = caller_locations(1, 1)[0].base_label.to_s
assert_separately([{"LC_ALL"=>"UTF-8"}, "-r", __FILE__], <<SRC)
-#skip "test \#{ENV['LC_ALL']}"
+#omit "test \#{ENV['LC_ALL']}"
#{self.class.name}.new(#{loc.dump}).run(Test::Unit::Runner.new)
SRC
return true
@@ -780,7 +774,7 @@ class TestReadline < Test::Unit::TestCase
use_ext_readline
super
end
-end if defined?(ReadlineSo)
+end if defined?(ReadlineSo) && ENV["TEST_READLINE_OR_RELINE"] != "Reline"
class TestRelineAsReadline < Test::Unit::TestCase
include BasetestReadline
@@ -789,4 +783,12 @@ class TestRelineAsReadline < Test::Unit::TestCase
use_lib_reline
super
end
-end
+
+ def get_default_internal_encoding
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ Encoding.default_internal || Encoding::UTF_8
+ else
+ super
+ end
+ end
+end if defined?(Reline) && ENV["TEST_READLINE_OR_RELINE"] != "Readline"
diff --git a/test/readline/test_readline_history.rb b/test/readline/test_readline_history.rb
index 34ab745eb0..f4e93fa1b6 100644
--- a/test/readline/test_readline_history.rb
+++ b/test/readline/test_readline_history.rb
@@ -260,6 +260,7 @@ class TestReadlineHistory < Test::Unit::TestCase
super
end
end if defined?(::ReadlineSo) && defined?(::ReadlineSo::HISTORY) &&
+ ENV["TEST_READLINE_OR_RELINE"] != "Reline" &&
(
begin
ReadlineSo::HISTORY.clear
@@ -275,4 +276,12 @@ class TestRelineAsReadlineHistory < Test::Unit::TestCase
use_lib_reline
super
end
-end
+
+ def get_default_internal_encoding
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ Encoding.default_internal || Encoding::UTF_8
+ else
+ super
+ end
+ end
+end if defined?(Reline) && ENV["TEST_READLINE_OR_RELINE"] != "Readline"
diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb
index dd5142d587..cecb364f89 100644
--- a/test/reline/test_config.rb
+++ b/test/reline/test_config.rb
@@ -195,4 +195,24 @@ class Reline::Config::Test < Reline::TestCase
expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes }
assert_equal expected, @config.key_bindings
end
+
+ def test_history_size
+ @config.read_lines(<<~LINES.lines)
+ set history-size 5000
+ LINES
+
+ assert_equal 5000, @config.instance_variable_get(:@history_size)
+ history = Reline::History.new(@config)
+ history << "a\n"
+ assert_equal 1, history.size
+ end
+
+ def test_empty_inputrc_env
+ inputrc_backup = ENV['INPUTRC']
+ ENV['INPUTRC'] = ''
+ assert_nothing_raised do
+ @config.read
+ end
+ ENV['INPUTRC'] = inputrc_backup
+ end
end
diff --git a/test/reline/test_history.rb b/test/reline/test_history.rb
index 260b6e8528..189f2db86d 100644
--- a/test/reline/test_history.rb
+++ b/test/reline/test_history.rb
@@ -2,6 +2,10 @@ require_relative 'helper'
require "reline/history"
class Reline::History::Test < Reline::TestCase
+ def setup
+ Reline.send(:test_mode)
+ end
+
def test_ancestors
assert_equal(Reline::History.ancestors.include?(Array), true)
end
@@ -268,6 +272,10 @@ class Reline::History::Test < Reline::TestCase
end
def get_default_internal_encoding
- return Encoding.default_internal || Encoding.find("locale")
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ Encoding.default_internal || Encoding::UTF_8
+ else
+ Encoding.default_internal || Encoding.find("locale")
+ end
end
end
diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb
index 97ff654506..c16212c626 100644
--- a/test/reline/test_key_actor_emacs.rb
+++ b/test/reline/test_key_actor_emacs.rb
@@ -8,8 +8,8 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
Reline::HISTORY.instance_variable_set(:@config, @config)
Reline::HISTORY.clear
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
- @line_editor = Reline::LineEditor.new(@config)
- @line_editor.reset(@prompt, @encoding)
+ @line_editor = Reline::LineEditor.new(@config, @encoding)
+ @line_editor.reset(@prompt, encoding: @encoding)
end
def test_ed_insert_one
@@ -1325,6 +1325,68 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
assert_line('foo_ba')
end
+ def test_completion_with_indent
+ @line_editor.completion_proc = proc { |word|
+ %w{
+ foo_foo
+ foo_bar
+ foo_baz
+ qux
+ }.map { |i|
+ i.encode(@encoding)
+ }
+ }
+ input_keys(' fo')
+ assert_byte_pointer_size(' fo')
+ assert_cursor(4)
+ assert_cursor_max(4)
+ assert_line(' fo')
+ assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
+ input_keys("\C-i", false)
+ assert_byte_pointer_size(' foo_')
+ assert_cursor(6)
+ assert_cursor_max(6)
+ assert_line(' foo_')
+ assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
+ input_keys("\C-i", false)
+ assert_byte_pointer_size(' foo_')
+ assert_cursor(6)
+ assert_cursor_max(6)
+ assert_line(' foo_')
+ assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
+ end
+
+ def test_completion_with_indent_and_completer_quote_characters
+ @line_editor.completion_proc = proc { |word|
+ %w{
+ "".foo_foo
+ "".foo_bar
+ "".foo_baz
+ "".qux
+ }.map { |i|
+ i.encode(@encoding)
+ }
+ }
+ input_keys(' "".fo')
+ assert_byte_pointer_size(' "".fo')
+ assert_cursor(7)
+ assert_cursor_max(7)
+ assert_line(' "".fo')
+ assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
+ input_keys("\C-i", false)
+ assert_byte_pointer_size(' "".foo_')
+ assert_cursor(9)
+ assert_cursor_max(9)
+ assert_line(' "".foo_')
+ assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
+ input_keys("\C-i", false)
+ assert_byte_pointer_size(' "".foo_')
+ assert_cursor(9)
+ assert_cursor_max(9)
+ assert_line(' "".foo_')
+ assert_equal(%w{"".foo_foo "".foo_bar "".foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
+ end
+
def test_completion_with_perfect_match
@line_editor.completion_proc = proc { |word|
%w{
@@ -1834,6 +1896,15 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer))
end
+ def test_modify_lines_with_wrong_rs
+ original_global_slash = $/
+ $/ = 'b'
+ @line_editor.output_modifier_proc = proc { |output| Reline::Unicode.escape_for_print(output) }
+ input_keys("abcdef\n")
+ assert_equal(['abcdef'], @line_editor.__send__(:modify_lines, @line_editor.whole_lines))
+ $/ = original_global_slash
+ end
+
=begin # TODO: move KeyStroke instance from Reline to LineEditor
def test_key_delete
input_keys('ab')
diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb
index 1ea160b6b5..c6337baea7 100644
--- a/test/reline/test_key_actor_vi.rb
+++ b/test/reline/test_key_actor_vi.rb
@@ -9,8 +9,8 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
set editing-mode vi
LINES
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
- @line_editor = Reline::LineEditor.new(@config)
- @line_editor.reset(@prompt, @encoding)
+ @line_editor = Reline::LineEditor.new(@config, @encoding)
+ @line_editor.reset(@prompt, encoding: @encoding)
end
def test_vi_command_mode
@@ -24,6 +24,74 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
assert_line('abc')
end
+ def test_vi_insert
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ input_keys('i')
+ assert_line('i')
+ assert_cursor(1)
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ input_keys("\C-[")
+ assert_line('i')
+ assert_cursor(0)
+ assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode)
+ input_keys('i')
+ assert_line('i')
+ assert_cursor(0)
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ end
+
+ def test_vi_add
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ input_keys('a')
+ assert_line('a')
+ assert_cursor(1)
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ input_keys("\C-[")
+ assert_line('a')
+ assert_cursor(0)
+ assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode)
+ input_keys('a')
+ assert_line('a')
+ assert_cursor(1)
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ end
+
+ def test_vi_insert_at_bol
+ input_keys('I')
+ assert_line('I')
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ input_keys("12345\C-[hh")
+ assert_line('I12345')
+ assert_byte_pointer_size('I12')
+ assert_cursor(3)
+ assert_cursor_max(6)
+ assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode)
+ input_keys('I')
+ assert_line('I12345')
+ assert_byte_pointer_size('')
+ assert_cursor(0)
+ assert_cursor_max(6)
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ end
+
+ def test_vi_add_at_eol
+ input_keys('A')
+ assert_line('A')
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ input_keys("12345\C-[hh")
+ assert_line('A12345')
+ assert_byte_pointer_size('A12')
+ assert_cursor(3)
+ assert_cursor_max(6)
+ assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode)
+ input_keys('A')
+ assert_line('A12345')
+ assert_byte_pointer_size('A12345')
+ assert_cursor(6)
+ assert_cursor_max(6)
+ assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode)
+ end
+
def test_ed_insert_one
input_keys('a')
assert_line('a')
@@ -565,6 +633,60 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
assert_cursor_max(6)
end
+ def test_vi_to_next_char
+ input_keys("abcdef\C-[0")
+ assert_line('abcdef')
+ assert_byte_pointer_size('')
+ assert_cursor(0)
+ assert_cursor_max(6)
+ input_keys('tz')
+ assert_line('abcdef')
+ assert_byte_pointer_size('')
+ assert_cursor(0)
+ assert_cursor_max(6)
+ input_keys('te')
+ assert_line('abcdef')
+ assert_byte_pointer_size('abc')
+ assert_cursor(3)
+ assert_cursor_max(6)
+ end
+
+ def test_vi_prev_char
+ input_keys("abcdef\C-[")
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Fz')
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Fa')
+ assert_line('abcdef')
+ assert_byte_pointer_size('')
+ assert_cursor(0)
+ assert_cursor_max(6)
+ end
+
+ def test_vi_to_prev_char
+ input_keys("abcdef\C-[")
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Tz')
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Ta')
+ assert_line('abcdef')
+ assert_byte_pointer_size('a')
+ assert_cursor(1)
+ assert_cursor_max(6)
+ end
+
def test_vi_delete_next_char
input_keys("abc\C-[h")
assert_byte_pointer_size('a')
@@ -1092,4 +1214,27 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
assert_cursor_max(11)
assert_line('aaa ddd eee')
end
+
+ def test_vi_change_meta
+ input_keys("aaa bbb ccc ddd eee\C-[02w")
+ assert_byte_pointer_size('aaa bbb ')
+ assert_cursor(8)
+ assert_cursor_max(19)
+ assert_line('aaa bbb ccc ddd eee')
+ input_keys('cwaiueo ')
+ assert_byte_pointer_size('aaa bbb aiueo ')
+ assert_cursor(14)
+ assert_cursor_max(21)
+ assert_line('aaa bbb aiueo ddd eee')
+ input_keys("\C-[")
+ assert_byte_pointer_size('aaa bbb aiueo')
+ assert_cursor(13)
+ assert_cursor_max(21)
+ assert_line('aaa bbb aiueo ddd eee')
+ input_keys('cb')
+ assert_byte_pointer_size('aaa bbb ')
+ assert_cursor(8)
+ assert_cursor_max(16)
+ assert_line('aaa bbb ddd eee')
+ end
end
diff --git a/test/reline/test_macro.rb b/test/reline/test_macro.rb
index c69b50416a..b97de88a97 100644
--- a/test/reline/test_macro.rb
+++ b/test/reline/test_macro.rb
@@ -3,7 +3,8 @@ require_relative 'helper'
class Reline::MacroTest < Reline::TestCase
def setup
@config = Reline::Config.new
- @line_editor = Reline::LineEditor.new(@config)
+ @encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
+ @line_editor = Reline::LineEditor.new(@config, @encoding)
@line_editor.instance_variable_set(:@screen_size, [24, 80])
@output = @line_editor.output = File.open(IO::NULL, "w")
end
diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb
index 274f1aa6ba..0de2462a08 100644
--- a/test/reline/test_reline.rb
+++ b/test/reline/test_reline.rb
@@ -21,15 +21,15 @@ class Reline::Test < Reline::TestCase
Reline.completion_append_character = "a".encode(Encoding::ASCII)
assert_equal("a", Reline.completion_append_character)
- assert_equal(Encoding::default_external, Reline.completion_append_character.encoding)
+ assert_equal(get_reline_encoding, Reline.completion_append_character.encoding)
Reline.completion_append_character = "ba".encode(Encoding::ASCII)
assert_equal("b", Reline.completion_append_character)
- assert_equal(Encoding::default_external, Reline.completion_append_character.encoding)
+ assert_equal(get_reline_encoding, Reline.completion_append_character.encoding)
Reline.completion_append_character = "cba".encode(Encoding::ASCII)
assert_equal("c", Reline.completion_append_character)
- assert_equal(Encoding::default_external, Reline.completion_append_character.encoding)
+ assert_equal(get_reline_encoding, Reline.completion_append_character.encoding)
Reline.completion_append_character = nil
assert_equal(nil, Reline.completion_append_character)
@@ -40,7 +40,7 @@ class Reline::Test < Reline::TestCase
Reline.basic_word_break_characters = "[".encode(Encoding::ASCII)
assert_equal("[", Reline.basic_word_break_characters)
- assert_equal(Encoding::default_external, Reline.basic_word_break_characters.encoding)
+ assert_equal(get_reline_encoding, Reline.basic_word_break_characters.encoding)
end
def test_completer_word_break_characters
@@ -48,7 +48,7 @@ class Reline::Test < Reline::TestCase
Reline.completer_word_break_characters = "[".encode(Encoding::ASCII)
assert_equal("[", Reline.completer_word_break_characters)
- assert_equal(Encoding::default_external, Reline.completer_word_break_characters.encoding)
+ assert_equal(get_reline_encoding, Reline.completer_word_break_characters.encoding)
end
def test_basic_quote_characters
@@ -56,7 +56,7 @@ class Reline::Test < Reline::TestCase
Reline.basic_quote_characters = "`".encode(Encoding::ASCII)
assert_equal("`", Reline.basic_quote_characters)
- assert_equal(Encoding::default_external, Reline.basic_quote_characters.encoding)
+ assert_equal(get_reline_encoding, Reline.basic_quote_characters.encoding)
end
def test_completer_quote_characters
@@ -64,7 +64,7 @@ class Reline::Test < Reline::TestCase
Reline.completer_quote_characters = "`".encode(Encoding::ASCII)
assert_equal("`", Reline.completer_quote_characters)
- assert_equal(Encoding::default_external, Reline.completer_quote_characters.encoding)
+ assert_equal(get_reline_encoding, Reline.completer_quote_characters.encoding)
end
def test_filename_quote_characters
@@ -72,7 +72,7 @@ class Reline::Test < Reline::TestCase
Reline.filename_quote_characters = "\'".encode(Encoding::ASCII)
assert_equal("\'", Reline.filename_quote_characters)
- assert_equal(Encoding::default_external, Reline.filename_quote_characters.encoding)
+ assert_equal(get_reline_encoding, Reline.filename_quote_characters.encoding)
end
def test_special_prefixes
@@ -80,7 +80,7 @@ class Reline::Test < Reline::TestCase
Reline.special_prefixes = "\'".encode(Encoding::ASCII)
assert_equal("\'", Reline.special_prefixes)
- assert_equal(Encoding::default_external, Reline.special_prefixes.encoding)
+ assert_equal(get_reline_encoding, Reline.special_prefixes.encoding)
end
def test_completion_case_fold
@@ -94,7 +94,10 @@ class Reline::Test < Reline::TestCase
end
def test_completion_proc
- assert_equal(nil, Reline.completion_proc)
+ skip unless Reline.completion_proc == nil
+ # Another test can set Reline.completion_proc
+
+ # assert_equal(nil, Reline.completion_proc)
p = proc {}
Reline.completion_proc = p
@@ -267,4 +270,8 @@ class Reline::Test < Reline::TestCase
def test_may_req_ambiguous_char_width
# TODO in Reline::Core
end
+
+ def get_reline_encoding
+ RUBY_PLATFORM =~ /mswin|mingw/ ? Encoding::UTF_8 : Encoding::default_external
+ end
end
diff --git a/test/reline/test_string_processing.rb b/test/reline/test_string_processing.rb
index 4df0363848..e76fa384f2 100644
--- a/test/reline/test_string_processing.rb
+++ b/test/reline/test_string_processing.rb
@@ -7,8 +7,8 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase
@config = Reline::Config.new
Reline::HISTORY.instance_variable_set(:@config, @config)
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
- @line_editor = Reline::LineEditor.new(@config)
- @line_editor.reset(@prompt, @encoding)
+ @line_editor = Reline::LineEditor.new(@config, @encoding)
+ @line_editor.reset(@prompt, encoding: @encoding)
end
def test_calculate_width
diff --git a/test/reline/test_within_pipe.rb b/test/reline/test_within_pipe.rb
index 11c3c0e86a..46b4465f32 100644
--- a/test/reline/test_within_pipe.rb
+++ b/test/reline/test_within_pipe.rb
@@ -13,6 +13,7 @@ class Reline::WithinPipeTest < Reline::TestCase
def teardown
Reline.input = STDIN
Reline.output = STDOUT
+ Reline.point = 0
@reader.close
@writer.close
@output.close
diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb
new file mode 100644
index 0000000000..4eab6661d6
--- /dev/null
+++ b/test/reline/yamatanooroti/test_rendering.rb
@@ -0,0 +1,41 @@
+require 'reline'
+
+begin
+ require 'yamatanooroti'
+
+ class Reline::TestRendering < Yamatanooroti::TestCase
+ def setup
+ inputrc_backup = ENV['INPUTRC']
+ ENV['INPUTRC'] = 'nonexistent_file'
+ start_terminal(5, 30, %w{ruby -Ilib bin/multiline_repl})
+ sleep 0.5
+ ENV['INPUTRC'] = inputrc_backup
+ end
+
+ def test_history_back
+ write(":a\n")
+ write("\C-p")
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> :a
+ => :a
+ prompt> :a
+ EOC
+ end
+
+ def test_backspace
+ write(":abc\C-h\n")
+ close
+ assert_screen(<<~EOC)
+ Multiline REPL.
+ prompt> :ab
+ => :ab
+ prompt>
+ EOC
+ end
+ end
+rescue LoadError, NameError
+ # On Ruby repository, this test suit doesn't run because Ruby repo doesn't
+ # have the yamatanooroti gem.
+end
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index cac420422d..093720b1fc 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -285,7 +285,7 @@ class TestRubyOptions < Test::Unit::TestCase
/unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/)
if /mswin|mingw|aix|android/ =~ RUBY_PLATFORM &&
- (str = "\u3042".force_encoding(Encoding.find("locale"))).valid_encoding?
+ (str = "\u3042".force_encoding(Encoding.find("external"))).valid_encoding?
# This result depends on locale because LANG=C doesn't affect locale
# on Windows.
# On AIX, the source encoding of stdin with LANG=C is ISO-8859-1,
@@ -836,11 +836,11 @@ class TestRubyOptions < Test::Unit::TestCase
def test_command_line_glob_nonascii
bug10555 = '[ruby-dev:48752] [Bug #10555]'
name = "\u{3042}.txt"
- expected = name.encode("locale") rescue "?.txt"
+ expected = name.encode("external") rescue "?.txt"
with_tmpchdir do |dir|
open(name, "w") {}
assert_in_out_err(["-e", "puts ARGV", "?.txt"], "", [expected], [],
- bug10555, encoding: "locale")
+ bug10555, encoding: "external")
end
end
@@ -875,7 +875,7 @@ class TestRubyOptions < Test::Unit::TestCase
with_tmpchdir do |dir|
Ougai.each {|f| open(f, "w") {}}
assert_in_out_err(["-Eutf-8", "-e", "puts ARGV", "*"], "", Ougai, encoding: "utf-8")
- ougai = Ougai.map {|f| f.encode("locale", replace: "?")}
+ ougai = Ougai.map {|f| f.encode("external", replace: "?")}
assert_in_out_err(["-e", "puts ARGV", "*.txt"], "", ougai)
end
end