summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2020-03-30 19:09:50 +0900
committerGitHub <noreply@github.com>2020-03-30 19:09:50 +0900
commit0057fe4063b57b445d6ffc893e442f362e3a19e0 (patch)
tree4471ba18ce89ff86c6874897bf2fbb06b79d9728
parentecf874edea92796c63cc2b50b36b1179de5114c6 (diff)
Ruby 2.7 backport about IRB (#2990)
* [ruby/reline] Sort completion list #### Legacy mode: ```console $ irb --legacy irb(main):001:0> l[TAB][TAB] lambda load local_variables loop ``` #### Before this patch: ```console $ irb irb(main):001:0> l[TAB][TAB] local_variables loop lambda load ``` #### After this patch: ```console $ irb irb(main):001:0> l[TAB][TAB] lambda load local_variables loop ``` https://github.com/ruby/reline/commit/6074069c7d * Drop an invalid char as UTF-8 * Add test_completion_with_indent_and_completer_quote_characters This is for 8a705245e55575d4d310a2e956b89a36a5931971. * [ruby/irb] Add tests for RubyLex The set_auto_indent method calculates the correct number of spaces for indenting a line. We think there might be a few bugs in this method so we are testing the current functionality to make sure nothing breaks when we address those bugs. Example test failure: ``` 1) Failure: TestIRB::TestRubyLex#test_auto_indent [/Users/Ben/Projects/irb/test/irb/test_ruby_lex.rb:75]: Calculated the wrong number of spaces for: def each_top_level_statement initialize_input catch(:TERM_INPUT) do loop do begin prompt unless l = lex throw :TERM_INPUT if @line == '' else . <10> expected but was <12>. ``` https://github.com/ruby/irb/commit/752d5597ab * [ruby/reline] Degenerate the terminal size to [$LINES, $COLUMNS] if it is unknown This is a workaround for https://github.com/ruby/irb/issues/50 https://github.com/ruby/reline/commit/5725677d1a * [ruby/irb] Fix newline depth with multiple braces This commit fixes the check_newline_depth_difference method to multiple open braces on one line into account. Before this change we were subtracting from the depth in check_newline_depth_difference on every open brace. This is the right thing to do if the opening and closing brace are on the same line. For example in a method definition we have an opening and closing parentheses we want to add 1 to our depth, and then remove it. ``` def foo() end ``` However this isn't the correct behavior when the brace spans multiple lines. If a brace spans multiple lines we don't want to subtract from check_newline_depth_difference and we want to treat the braces the same way as we do `end` and allow check_corresponding_token_depth to pop the correct depth. Example of bad behavior: ``` def foo() [ ] puts 'bar' end ``` Example of desired behavior: ``` def foo() [ ] puts 'bar' end ``` https://github.com/ruby/irb/commit/7dc8af01e0 * text/readline/test_readline.rb - fix skip on Reline (#2743) TestRelineAsReadline#test_input_metachar passes on MinGW * Add "require 'openstruct'" what is forgotten * [ruby/irb] Fix lib name of OpenStruct https://github.com/ruby/irb/commit/1f3a84ab6b * Add load path and require for ruby/ruby * Rescue EOFError If C-d is pressed before IRB is ready, IRB crashes because EOFError occurs. * Complete indented and quoted string correctly def foo ''.upca[TAB] This will be completed to be: def foo ''.upcase The indent was gone. This commit fixes the bug. * [ruby/irb] Fix crashing when multiple open braces per line https://github.com/ruby/irb/issues/55 If we had put multiple open braces on a line the with no closing brace spaces_of_nest array keeps getting '0' added to it. This means that when we pop off of this array we are saying that we should be in position zero for the next line. This is an issue because we don't always want to be in position 0 after a closing brace. Example: ``` [[[ ] ] ] ``` In the above example the 'spaces_of_nest' array looks like this after the first line is entered: [0,0,0]. We really want to be indented 4 spaces for the 1st closing brace 2 for the 2nd and 0 for the 3rd. i.e. we want it to be: [0,2,4]. We also saw this issue with a heredoc inside of an array. ``` [<<FOO] hello FOO ``` https://github.com/ruby/irb/commit/80c69c8272 * Support history-size in .inputrc correctly * Introduce an abstracted structure about the encoding of Reline The command prompt on Windows always uses Unicode to take input and print output but most Reline implementation depends on Encoding.default_external. This commit introduces an abstracted structure about the encoding of Reline. * Remove an unused setting variable * Use Reline.encoding_system_needs if exists * Add tests for vi_insert and vi_add * Implement vi_insert_at_bol and vi_add_at_eol * [ruby/reline] Implement vi_to_next_char https://github.com/ruby/reline/commit/066ecb0a21 * [ruby/reline] Implement vi_prev_char and vi_to_prev_char https://github.com/ruby/reline/commit/0ad3ee63fa * [ruby/readline-ext] Include ruby/assert.h in ruby/ruby.h so that assertions can be there https://github.com/ruby/readline-ext/commit/4d44c12832 * Stop using minitest dependent methods * Skip a test that uses assert_ruby_status if it doesn't exist * Use omit instead of skip * Check DONT_RUN_RELINE_TEST envvar * [ruby/irb] Add newline_before_multiline_output https://github.com/ruby/irb/commit/9eb1801a66 * [ruby/irb] Fix compatibility with rails before 5.2 Rails before 5.2 added Array#append as an alias to Array#<< , so that it expects only one argument. However ruby-2.5 added Array#append as an alias to Array#push which takes any number of arguments. If irb completion is used in `rails c` (for example "IO.<tab>") it fails with: irb/completion.rb:206:in `<<': wrong number of arguments (given 3, expected 1) (ArgumentError) Using Array#push instead of Array#append fixes compatibility. https://github.com/ruby/irb/commit/5b7bbf9c34 * Reline: Use a more robust detection of MinTTY The previous detection per get_screen_size fails when stdout is passed to a pipe. That is the case when running ruby tests in parallel ("-j" switch). In this case Reline believes that it's running on MinTTY and the tests are running with ANSI IOGate instead of the Windows adapter on MINGW. So parallel test results were different to that of a single process. This commit fixes these differencies. The code is taken from git sources and translated to ruby. NtQueryObject() is replaced by GetFileInformationByHandleEx(), because NtQueryObject() is undocumented and is more difficult to use: https://github.com/git-for-windows/git/blob/c5a03b1e29c69f3f06c8fabd92493edb73469176/compat/winansi.c#L558 * Reline: Fix changed test results due to change to UTF-8 on Windows In commit f8ea2860b0cac1aec79978e6c44168802958e8af the Reline encoding for native windows console was changed to hardcoded UTF-8. This caused failures in reline and readline tests, but they were hidden, because parallel ruby tests incorrectly used Reline::ANSI as IOGate. Tests failures were raised in single process mode, but not with -j switch. This patch corrects encodings on native Windows console. * [ruby/irb] [ruby/irb] Rewrite an expression to detect multiline https://github.com/ruby/irb/commit/ed5cf375a6 https://github.com/ruby/irb/commit/5b7bbf9c34 * [ruby/reline] Implement vi_change_meta https://github.com/ruby/reline/commit/8538e0e10f * Always refer to Reline::IOGate.encoding * Always use UTF-8 for Reline::GeneralIO on Windows * Use test_mode on Reline::History::Test for encoding * [ruby/reline] Support GNOME style Home/End key sequences [Bug #16510] https://github.com/ruby/reline/commit/788f0df845 * [ruby/irb] Add a new easter egg: dancing ruby https://github.com/ruby/irb/commit/e37dc7e58e * [ruby/irb] Exclude useless files from RDoc https://github.com/ruby/irb/commit/8f1ab2400c * [ruby/irb] Exclude useless files from RDoc * Fix inaccuracy in encoding tests These tests assume Encoding.find('locale') == Encoding.find('external') and fail if they are distinct. * [ruby/reline] Fix Reline::Windows#scroll_down I mistook Right and Bottom. https://github.com/ruby/reline/commit/8be401c5f5 * [ruby/reline] Bypass cursor down when a char is rendered at eol on Windows A newline is automatically inserted if a character is rendered at eol on Windows command prompt. https://github.com/ruby/reline/commit/4bfea07e4a * [ruby/reline] Organize special keys escape sequences https://github.com/ruby/reline/commit/41deb1a3d9 * [ruby/readline-ext] Remove unnecessary -I$(top_srcdir) when it's an individual gem https://github.com/ruby/readline-ext/commit/efaca4a5f4 * [ruby/readline-ext] Check TestRelineAsReadline existance https://github.com/ruby/readline-ext/commit/c0a6303168 * [ruby/readline-ext] The ruby/assert.h is adopted by Ruby 2.7 or later https://github.com/ruby/readline-ext/commit/106c31fc1b * Revert "[ruby/readline-ext] Include ruby/assert.h in ruby/ruby.h so that assertions can be there" This reverts commit 425b2064d394639101854c83a061a0918b33b857. This cherry-pick was a mistake. * [ruby/readline-ext] Use require check instead of DONT_RUN_RELINE_TEST env https://github.com/ruby/readline-ext/commit/1df99d1481 * [ruby/readline-ext] Add spec.extensions https://github.com/ruby/readline-ext/commit/8c33abb13c * [ruby/readline-ext] Use rake/extensiokntask to build https://github.com/ruby/readline-ext/commit/b0b5f709bd * Fix readline build dependency * [ruby/irb] Add test_complete_symbol https://github.com/ruby/irb/commit/dbbf086c1f * [ruby/irb] Check doc namespace correctly IRB::InputCompletor::PerfectMatchedProc crashes when doc not found because a variable name was incorrect. https://github.com/ruby/irb/commit/889fd4928f * [ruby/irb] Fix auto indent with closed brace A closed brace in auto-indent shouldn't affect the next brace in the same line, but it behaves like below: p() { } It's a bug. https://github.com/ruby/irb/commit/fbe59e344f * [ruby/irb] Use 0.step instead of (..0).each for Ruby 2.5 https://github.com/ruby/irb/commit/5d628ca40e * Revert "[ruby/irb] Add test_complete_symbol" This reverts commit 3af3431c2c145134996e66f3d8d9ade8ad81bde0. * [ruby/irb] fix reserved words and completion for them https://github.com/ruby/irb/commit/6184b227ad * Add test_complete_symbol The previous version of the test method used a symbol, ":abcdefg" to complete but longer symbols that can be completed are defined by other test methods of other libs. * test/irb/test_completion.rb: suppress a warning: unused literal ignored * [ruby/reline] Use IO#write instead of IO#print IO#print always adds a string of $\ automatically. https://github.com/ruby/reline/commit/a93119c847 * [ruby/irb] Version 1.2.2 https://github.com/ruby/irb/commit/a71753f15a * [ruby/reline] Version 0.1.3 https://github.com/ruby/reline/commit/ea2b182466 * [ruby/irb] Include easter-egg.rb in gemspec `irb` doesn't run because this file isn't included in the gem. https://github.com/ruby/irb/commit/73cda56d25 * [ruby/irb] Version 1.2.3 https://github.com/ruby/irb/commit/dd56e06df5 * support multi-run test for test_readline.rb * [ruby/irb] `yield` outside method definition is a syntax error https://github.com/ruby/irb/commit/dbc7b059c7 * test/readline - allow ENV control of test class creation In ruby/ruby, the tests run on both readline & reline by creating four test classes: ``` TestReadline TestReadlineHistory TestRelineAsReadline TestRelineAsReadlineHistory ``` Reline inports the test files and uses them in its CI. Adding the ENV control allows it to only run the `TestRelineAsReadline` classes. * Omit test_using_quoting_detection_proc_with_multibyte_input temporarily for random order test * support random order test. test_readline: HISTORY should be empty. test_using_quoting_detection_proc: test_using_quoting_detection_proc_with_multibyte_input: Readline.completer_quote_characters= and Readline.completer_word_break_characters= doesn't accept nil, so skip if previous values are nil. * Set Readline.completion_append_character = nil always GNU Readline add a white space when Readline.completion_append_character is not initialized. * Fix a typo [ci skip] * skip test if Reline.completion_proc is nil. Some other tests can set Reline.completion_proc, so if it is nil, simply skip this test. * Reset Reline.point TestRelineAsReadline#test_insert_text expects Readline.point == 0 at the beginning of the test, but a test violate this assumption. * Convert incompatible encoding symbol names * Ignore incompatible convert of symbols * Add workaround for test-bundler failure https://github.com/ruby/actions/runs/500526558?check_suite_focus=true#step:16:127 ``` Failures: 1) Bundler.setup when Bundler is bundled doesn't blow up Failure/Error: expect(err).to be_empty expected `"fatal: not a git repository (or any of the parent directories): .git\nfatal: not a git repository (o...the parent directories): .git\nfatal: not a git repository (or any of the parent directories): .git".empty?` to return true, got false Commands: $ /home/runner/work/actions/actions/snapshot-master/ruby \ -I/home/runner/work/actions/actions/snapshot-master/lib:/home/runner/work/actions/actions/snapshot-master/spec/bundler \ -rsupport/hax -rsupport/artifice/fail \ /home/runner/work/actions/actions/snapshot-master/libexec/bundle install --retry 0 Resolving dependencies... Using bundler 2.1.4 Bundle complete! 1 Gemfile dependency, 1 gem now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. fatal: not a git repository (or any of the parent directories): .git fatal: not a git repository (or any of the parent directories): .git fatal: not a git repository (or any of the parent directories): .git # $? => 0 $ /home/runner/work/actions/actions/snapshot-master/ruby \ -I/home/runner/work/actions/actions/snapshot-master/lib:/home/runner/work/actions/actions/snapshot-master/spec/bundler \ -rsupport/hax -rsupport/artifice/fail \ /home/runner/work/actions/actions/snapshot-master/libexec/bundle exec ruby -e \ require\ \'bundler\'\;\ Bundler.setup fatal: not a git repository (or any of the parent directories): .git fatal: not a git repository (or any of the parent directories): .git fatal: not a git repository (or any of the parent directories): .git # $? => 0 # ./spec/bundler/runtime/setup_spec.rb:1056:in `block (3 levels) in <top (required)>' # ./spec/bundler/spec_helper.rb:111:in `block (3 levels) in <top (required)>' # ./spec/bundler/spec_helper.rb:111:in `block (2 levels) in <top (required)>' # ./spec/bundler/spec_helper.rb:78:in `block (2 levels) in <top (required)>' make: *** [yes-test-bundler] Error 1 ``` * [ruby/irb] Unnamed groups are not captured when named groups are used https://github.com/ruby/irb/commit/0a641a69b0 * [ruby/reline] Work with wrong $/ value correctly https://github.com/ruby/reline/commit/962ebf5a1b * [ruby/irb] Detect multiple lines output simplify The old implementation performance test code: require 'objspace' puts "%.5g MB" % (ObjectSpace.memsize_of_all * 0.001 * 0.001) /\A.*\Z/ !~ ('abc' * 20_000_000) puts "%.5g MB" % (ObjectSpace.memsize_of_all * 0.001 * 0.001) and run `time test.rb`: 2.5868 MB 62.226 MB real 0m1.307s user 0m0.452s sys 0m0.797s The new implementation performance test code: require 'objspace' puts "%.5g MB" % (ObjectSpace.memsize_of_all * 0.001 * 0.001) ('abc' * 20_000_000).include?("\n") puts "%.5g MB" % (ObjectSpace.memsize_of_all * 0.001 * 0.001) and run `time test.rb`: 2.5861 MB 62.226 MB real 0m0.132s user 0m0.088s sys 0m0.042s https://github.com/ruby/irb/commit/40d6610baf * [ruby/reline] Suppress error in case INPUTRC env is empty https://github.com/ruby/reline/commit/bce7e7562b * [ruby/reline] Add yamatanooroti rendering test https://github.com/ruby/reline/commit/f092519525 * [ruby/reline] Rename test suite name of yamatanooroti test https://github.com/ruby/reline/commit/b0f32f5de4 * [ruby/reline] Add a comment why rescue yamatanooroti loading error on the test https://github.com/ruby/reline/commit/2a8061daec * [ruby/irb] Suppress crashing when EncodingError has occurred without lineno https://github.com/ruby/irb/commit/13572d8cdc * [ruby/reline] Suppress error when check ambiguous char width in LANG=C https://github.com/ruby/reline/commit/623dffdd75 * [ruby/io-console] Enable only interrupt bits on `intr: true` https://github.com/ruby/io-console/commit/baaf929041 * [ruby/io-console] bump up to 0.5.4 * [ruby/io-console] Update the minimum requirement of Ruby version https://github.com/ruby/io-console/commit/73e7b6318a * [ruby/io-console] Filter Ruby engine name rather than just /ruby/ This breaks tests using this path on JRuby because the `jruby` executable turns into `jjruby` after the sub. https://github.com/ruby/io-console/commit/e5951aa34c * [ruby/io-console] bump up to 0.5.5 * [ruby/io-console] Prefer keyword arguments https://github.com/ruby/io-console/commit/5facbfc4c8 * [ruby/io-console] [DOC] Improved about `intr:` https://github.com/ruby/io-console/commit/82b630cd79 * [ruby/io-console] Just ignore the extension on other than CRuby https://github.com/ruby/io-console/commit/41b6f09574 * [ruby/io-console] bump up to 0.5.6 Co-authored-by: KOBAYASHI Shuji <shuujii@gmail.com> Co-authored-by: Ben <kanobt61@gmail.com> Co-authored-by: Yusuke Endoh <mame@ruby-lang.org> Co-authored-by: MSP-Greg <MSP-Greg@users.noreply.github.com> Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org> Co-authored-by: Kenta Murata <mrkn@mrkn.jp> Co-authored-by: Lars Kanis <lars@greiz-reinsdorf.de> Co-authored-by: Lars Kanis <kanis@comcard.de> Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org> Co-authored-by: Nobuhiro IMAI <nov@yo.rim.or.jp> Co-authored-by: Nick Lewis <nick@puppet.com> Co-authored-by: S-H-GAMELINKS <gamelinks007@gmail.com> Co-authored-by: Koichi Sasada <ko1@atdot.net> Co-authored-by: Kazuhiro NISHIYAMA <zn@mbf.nifty.com> Co-authored-by: Charles Oliver Nutter <headius@headius.com>
-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