mirror of
https://github.com/ruby/ruby.git
synced 2025-09-19 10:33:58 +02:00
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 ```6074069c7d
* Drop an invalid char as UTF-8 * Add test_completion_with_indent_and_completer_quote_characters This is for8a705245e5
. * [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>. ```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/505725677d1a
* [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 ```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 OpenStruct1f3a84ab6b
* 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 ```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_char066ecb0a21
* [ruby/reline] Implement vi_prev_char and vi_to_prev_char0ad3ee63fa
* [ruby/readline-ext] Include ruby/assert.h in ruby/ruby.h so that assertions can be there4d44c12832
* 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_output9eb1801a66
* [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.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:c5a03b1e29/compat/winansi.c (L558)
* Reline: Fix changed test results due to change to UTF-8 on Windows In commitf8ea2860b0
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 multilineed5cf375a6
5b7bbf9c34
* [ruby/reline] Implement vi_change_meta8538e0e10f
* 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]788f0df845
* [ruby/irb] Add a new easter egg: dancing rubye37dc7e58e
* [ruby/irb] Exclude useless files from RDoc8f1ab2400c
* [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.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.4bfea07e4a
* [ruby/reline] Organize special keys escape sequences41deb1a3d9
* [ruby/readline-ext] Remove unnecessary -I$(top_srcdir) when it's an individual gemefaca4a5f4
* [ruby/readline-ext] Check TestRelineAsReadline existancec0a6303168
* [ruby/readline-ext] The ruby/assert.h is adopted by Ruby 2.7 or later106c31fc1b
* Revert "[ruby/readline-ext] Include ruby/assert.h in ruby/ruby.h so that assertions can be there" This reverts commit425b2064d3
. This cherry-pick was a mistake. * [ruby/readline-ext] Use require check instead of DONT_RUN_RELINE_TEST env1df99d1481
* [ruby/readline-ext] Add spec.extensions8c33abb13c
* [ruby/readline-ext] Use rake/extensiokntask to buildb0b5f709bd
* Fix readline build dependency * [ruby/irb] Add test_complete_symboldbbf086c1f
* [ruby/irb] Check doc namespace correctly IRB::InputCompletor::PerfectMatchedProc crashes when doc not found because a variable name was incorrect.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.fbe59e344f
* [ruby/irb] Use 0.step instead of (..0).each for Ruby 2.55d628ca40e
* Revert "[ruby/irb] Add test_complete_symbol" This reverts commit3af3431c2c
. * [ruby/irb] fix reserved words and completion for them6184b227ad
* 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.a93119c847
* [ruby/irb] Version 1.2.2a71753f15a
* [ruby/reline] Version 0.1.3ea2b182466
* [ruby/irb] Include easter-egg.rb in gemspec `irb` doesn't run because this file isn't included in the gem.73cda56d25
* [ruby/irb] Version 1.2.3dd56e06df5
* support multi-run test for test_readline.rb * [ruby/irb] `yield` outside method definition is a syntax errordbc7b059c7
* 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 failure500526558 (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 used0a641a69b0
* [ruby/reline] Work with wrong $/ value correctly962ebf5a1b
* [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.042s40d6610baf
* [ruby/reline] Suppress error in case INPUTRC env is emptybce7e7562b
* [ruby/reline] Add yamatanooroti rendering testf092519525
* [ruby/reline] Rename test suite name of yamatanooroti testb0f32f5de4
* [ruby/reline] Add a comment why rescue yamatanooroti loading error on the test2a8061daec
* [ruby/irb] Suppress crashing when EncodingError has occurred without lineno13572d8cdc
* [ruby/reline] Suppress error when check ambiguous char width in LANG=C623dffdd75
* [ruby/io-console] Enable only interrupt bits on `intr: true`baaf929041
* [ruby/io-console] bump up to 0.5.4 * [ruby/io-console] Update the minimum requirement of Ruby version73e7b6318a
* [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.e5951aa34c
* [ruby/io-console] bump up to 0.5.5 * [ruby/io-console] Prefer keyword arguments5facbfc4c8
* [ruby/io-console] [DOC] Improved about `intr:`82b630cd79
* [ruby/io-console] Just ignore the extension on other than CRuby41b6f09574
* [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>
This commit is contained in:
parent
ecf874edea
commit
0057fe4063
57 changed files with 1169 additions and 260 deletions
|
@ -111,6 +111,9 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
|
||||||
int argc = *argcp;
|
int argc = *argcp;
|
||||||
rawmode_arg_t *optp = NULL;
|
rawmode_arg_t *optp = NULL;
|
||||||
VALUE vopts = Qnil;
|
VALUE vopts = Qnil;
|
||||||
|
#ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
|
||||||
|
argc = rb_scan_args(argc, argv, "*:", NULL, &vopts);
|
||||||
|
#else
|
||||||
if (argc > min_argc) {
|
if (argc > min_argc) {
|
||||||
vopts = rb_check_hash_type(argv[argc-1]);
|
vopts = rb_check_hash_type(argv[argc-1]);
|
||||||
if (!NIL_P(vopts)) {
|
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;
|
if (!vopts) vopts = Qnil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
rb_check_arity(argc, min_argc, max_argc);
|
rb_check_arity(argc, min_argc, max_argc);
|
||||||
if (!NIL_P(vopts)) {
|
if (!NIL_P(vopts)) {
|
||||||
VALUE vmin = rb_hash_aref(vopts, ID2SYM(id_min));
|
VALUE vmin = rb_hash_aref(vopts, ID2SYM(id_min));
|
||||||
|
@ -188,7 +192,7 @@ set_rawmode(conmode *t, void *arg)
|
||||||
#endif
|
#endif
|
||||||
#ifdef ISIG
|
#ifdef ISIG
|
||||||
if (r->intr) {
|
if (r->intr) {
|
||||||
t->c_iflag |= BRKINT|IXON;
|
t->c_iflag |= BRKINT;
|
||||||
t->c_lflag |= ISIG;
|
t->c_lflag |= ISIG;
|
||||||
t->c_oflag |= OPOST;
|
t->c_oflag |= OPOST;
|
||||||
}
|
}
|
||||||
|
@ -356,9 +360,9 @@ ttymode_with_io(VALUE io, VALUE (*func)(VALUE, VALUE), VALUE farg, void (*setter
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* 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)
|
* 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
|
* The parameter +time+ specifies the timeout in _seconds_ with a
|
||||||
* precision of 1/10 of a second. (default: 0)
|
* 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.
|
* Refer to the manual page of termios for further details.
|
||||||
*
|
*
|
||||||
* You must require 'io/console' to use this method.
|
* You must require 'io/console' to use this method.
|
||||||
|
@ -383,11 +390,11 @@ console_raw(int argc, VALUE *argv, VALUE io)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* 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.
|
* See IO#raw for details on the parameters.
|
||||||
*
|
*
|
||||||
|
@ -483,7 +490,7 @@ nogvl_getch(void *p)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* 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.
|
* Reads and returns a character in raw mode.
|
||||||
*
|
*
|
||||||
|
@ -1490,7 +1497,7 @@ console_dev(int argc, VALUE *argv, VALUE klass)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* io.getch(min: nil, time: nil) -> char
|
* io.getch(min: nil, time: nil, intr: nil) -> char
|
||||||
*
|
*
|
||||||
* See IO#getch.
|
* See IO#getch.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
require 'mkmf'
|
require 'mkmf'
|
||||||
|
|
||||||
ok = true
|
ok = true if RUBY_ENGINE == "ruby"
|
||||||
hdr = nil
|
hdr = nil
|
||||||
case
|
case
|
||||||
when macro_defined?("_WIN32", "")
|
when macro_defined?("_WIN32", "")
|
||||||
|
@ -14,8 +14,9 @@ when have_header(hdr = "sgtty.h")
|
||||||
%w"stty gtty".each {|f| have_func(f, hdr)}
|
%w"stty gtty".each {|f| have_func(f, hdr)}
|
||||||
else
|
else
|
||||||
ok = false
|
ok = false
|
||||||
end
|
end if ok
|
||||||
if ok
|
case ok
|
||||||
|
when true
|
||||||
have_header("sys/ioctl.h") if hdr
|
have_header("sys/ioctl.h") if hdr
|
||||||
# rb_check_hash_type: 1.9.3
|
# rb_check_hash_type: 1.9.3
|
||||||
# rb_io_get_write_io: 1.9.1
|
# rb_io_get_write_io: 1.9.1
|
||||||
|
@ -27,4 +28,6 @@ if ok
|
||||||
create_makefile("io/console") {|conf|
|
create_makefile("io/console") {|conf|
|
||||||
conf << "\n""VK_HEADER = #{vk_header}\n"
|
conf << "\n""VK_HEADER = #{vk_header}\n"
|
||||||
}
|
}
|
||||||
|
when nil
|
||||||
|
File.write("Makefile", dummy_makefile($srcdir).join(""))
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- ruby -*-
|
# -*- ruby -*-
|
||||||
_VERSION = "0.5.3"
|
_VERSION = "0.5.6"
|
||||||
date = %w$Date:: $[1]
|
date = %w$Date:: $[1]
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
|
@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
||||||
s.summary = "Console interface"
|
s.summary = "Console interface"
|
||||||
s.email = "nobu@ruby-lang.org"
|
s.email = "nobu@ruby-lang.org"
|
||||||
s.description = "add console capabilities to IO instances."
|
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.homepage = "https://github.com/ruby/io-console"
|
||||||
s.metadata["source_code_url"] = s.homepage
|
s.metadata["source_code_url"] = s.homepage
|
||||||
s.authors = ["Nobu Nakada"]
|
s.authors = ["Nobu Nakada"]
|
||||||
|
|
|
@ -109,5 +109,4 @@ unless readline.have_type("rl_hook_func_t*")
|
||||||
$defs << "-Drl_hook_func_t=Function"
|
$defs << "-Drl_hook_func_t=Function"
|
||||||
end
|
end
|
||||||
|
|
||||||
$INCFLAGS << " -I$(top_srcdir)"
|
|
||||||
create_makefile("readline")
|
create_makefile("readline")
|
||||||
|
|
|
@ -8,14 +8,19 @@ Gem::Specification.new do |spec|
|
||||||
spec.description = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
|
spec.description = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
|
||||||
spec.homepage = "https://github.com/ruby/readline-ext"
|
spec.homepage = "https://github.com/ruby/readline-ext"
|
||||||
spec.license = "BSD-2-Clause"
|
spec.license = "BSD-2-Clause"
|
||||||
|
spec.extensions = %w[ext/readline/extconf.rb]
|
||||||
|
|
||||||
spec.metadata["homepage_uri"] = spec.homepage
|
spec.metadata["homepage_uri"] = spec.homepage
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
spec.require_paths = ["lib"]
|
spec.require_paths = ["lib"]
|
||||||
|
|
||||||
|
spec.add_development_dependency "bundler"
|
||||||
|
spec.add_development_dependency "rake"
|
||||||
|
spec.add_development_dependency "rake-compiler"
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
12
lib/irb.rb
12
lib/irb.rb
|
@ -21,6 +21,7 @@ require "irb/locale"
|
||||||
require "irb/color"
|
require "irb/color"
|
||||||
|
|
||||||
require "irb/version"
|
require "irb/version"
|
||||||
|
require "irb/easter-egg"
|
||||||
|
|
||||||
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
|
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
|
||||||
# expressions read from the standard input.
|
# expressions read from the standard input.
|
||||||
|
@ -553,7 +554,8 @@ module IRB
|
||||||
|
|
||||||
def handle_exception(exc)
|
def handle_exception(exc)
|
||||||
if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
|
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
|
irb_bug = true
|
||||||
else
|
else
|
||||||
irb_bug = false
|
irb_bug = false
|
||||||
|
@ -736,7 +738,13 @@ module IRB
|
||||||
end
|
end
|
||||||
|
|
||||||
def output_value # :nodoc:
|
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
|
end
|
||||||
|
|
||||||
# Outputs the local variables to this current session, including
|
# Outputs the local variables to this current session, including
|
||||||
|
|
1
lib/irb/.document
Normal file
1
lib/irb/.document
Normal file
|
@ -0,0 +1 @@
|
||||||
|
**/*.rb
|
|
@ -17,11 +17,12 @@ module IRB
|
||||||
# Set of reserved words used by Ruby, you should not use these for
|
# Set of reserved words used by Ruby, you should not use these for
|
||||||
# constants or variables
|
# constants or variables
|
||||||
ReservedWords = %w[
|
ReservedWords = %w[
|
||||||
|
__ENCODING__ __LINE__ __FILE__
|
||||||
BEGIN END
|
BEGIN END
|
||||||
alias and
|
alias and
|
||||||
begin break
|
begin break
|
||||||
case class
|
case class
|
||||||
def defined do
|
def defined? do
|
||||||
else elsif end ensure
|
else elsif end ensure
|
||||||
false for
|
false for
|
||||||
if in
|
if in
|
||||||
|
@ -98,7 +99,11 @@ module IRB
|
||||||
return nil if doc_namespace
|
return nil if doc_namespace
|
||||||
if Symbol.respond_to?(:all_symbols)
|
if Symbol.respond_to?(:all_symbols)
|
||||||
sym = $1
|
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)}/)
|
candidates.grep(/^#{Regexp.quote(sym)}/)
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
|
@ -143,7 +148,7 @@ module IRB
|
||||||
select_message(receiver, message, candidates, sep)
|
select_message(receiver, message, candidates, sep)
|
||||||
end
|
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
|
# Numeric
|
||||||
receiver = $~[:num]
|
receiver = $~[:num]
|
||||||
sep = $~[:sep]
|
sep = $~[:sep]
|
||||||
|
@ -203,7 +208,7 @@ module IRB
|
||||||
sep = $2
|
sep = $2
|
||||||
message = Regexp.quote($3)
|
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}
|
lv = eval("local_variables", bind).collect{|m| m.to_s}
|
||||||
iv = eval("instance_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}
|
cv = eval("self.class.constants", bind).collect{|m| m.to_s}
|
||||||
|
@ -255,7 +260,7 @@ module IRB
|
||||||
|
|
||||||
else
|
else
|
||||||
candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s}
|
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
|
if doc_namespace
|
||||||
candidates.find{ |i| i == input }
|
candidates.find{ |i| i == input }
|
||||||
|
@ -265,18 +270,14 @@ module IRB
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
PerfectMatchedProc = ->(matched) {
|
PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
|
||||||
RDocRIDriver ||= RDoc::RI::Driver.new
|
RDocRIDriver ||= RDoc::RI::Driver.new
|
||||||
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
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|
|
IRB.send(:easter_egg)
|
||||||
RDocRIDriver.page do |io|
|
|
||||||
IO.copy_stream(f, io)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
namespace = retrieve_completion_data(matched, doc_namespace: true)
|
namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
||||||
return unless matched
|
return unless namespace
|
||||||
if namespace.is_a?(Array)
|
if namespace.is_a?(Array)
|
||||||
out = RDoc::Markup::Document.new
|
out = RDoc::Markup::Document.new
|
||||||
namespace.each do |m|
|
namespace.each do |m|
|
||||||
|
|
|
@ -133,6 +133,11 @@ module IRB
|
||||||
if @echo_on_assignment.nil?
|
if @echo_on_assignment.nil?
|
||||||
@echo_on_assignment = false
|
@echo_on_assignment = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT]
|
||||||
|
if @newline_before_multiline_output.nil?
|
||||||
|
@newline_before_multiline_output = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# The top-level workspace, see WorkSpace#main
|
# The top-level workspace, see WorkSpace#main
|
||||||
|
@ -253,6 +258,20 @@ module IRB
|
||||||
# a = "omg"
|
# a = "omg"
|
||||||
# #=> omg
|
# #=> omg
|
||||||
attr_accessor :echo_on_assignment
|
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.
|
# Whether verbose messages are displayed or not.
|
||||||
#
|
#
|
||||||
# A copy of the default <code>IRB.conf[:VERBOSE]</code>
|
# A copy of the default <code>IRB.conf[:VERBOSE]</code>
|
||||||
|
@ -287,6 +306,7 @@ module IRB
|
||||||
alias ignore_eof? ignore_eof
|
alias ignore_eof? ignore_eof
|
||||||
alias echo? echo
|
alias echo? echo
|
||||||
alias echo_on_assignment? echo_on_assignment
|
alias echo_on_assignment? echo_on_assignment
|
||||||
|
alias newline_before_multiline_output? newline_before_multiline_output
|
||||||
|
|
||||||
# Returns whether messages are displayed or not.
|
# Returns whether messages are displayed or not.
|
||||||
def verbose?
|
def verbose?
|
||||||
|
|
137
lib/irb/easter-egg.rb
Normal file
137
lib/irb/easter-egg.rb
Normal file
|
@ -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__
|
|
@ -72,7 +72,7 @@ module IRB
|
||||||
end
|
end
|
||||||
history_file = IRB.rc_file("_history") unless history_file
|
history_file = IRB.rc_file("_history") unless history_file
|
||||||
if File.exist?(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|
|
f.each { |l|
|
||||||
l = l.chomp
|
l = l.chomp
|
||||||
if self.class == ReidlineInputMethod and history.last&.end_with?("\\")
|
if self.class == ReidlineInputMethod and history.last&.end_with?("\\")
|
||||||
|
@ -107,7 +107,7 @@ module IRB
|
||||||
raise
|
raise
|
||||||
end
|
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") }
|
hist = history.map{ |l| l.split("\n").join("\\\n") }
|
||||||
f.puts(hist[-num..-1] || hist)
|
f.puts(hist[-num..-1] || hist)
|
||||||
end
|
end
|
||||||
|
|
|
@ -296,15 +296,18 @@ module IRB # :nodoc:
|
||||||
DefaultEncodings = Struct.new(:external, :internal)
|
DefaultEncodings = Struct.new(:external, :internal)
|
||||||
class << IRB
|
class << IRB
|
||||||
private
|
private
|
||||||
def set_encoding(extern, intern = nil)
|
def set_encoding(extern, intern = nil, override: true)
|
||||||
verbose, $VERBOSE = $VERBOSE, nil
|
verbose, $VERBOSE = $VERBOSE, nil
|
||||||
Encoding.default_external = extern unless extern.nil? || extern.empty?
|
Encoding.default_external = extern unless extern.nil? || extern.empty?
|
||||||
Encoding.default_internal = intern unless intern.nil? || intern.empty?
|
Encoding.default_internal = intern unless intern.nil? || intern.empty?
|
||||||
@CONF[:ENCODINGS] = IRB::DefaultEncodings.new(extern, intern)
|
|
||||||
[$stdin, $stdout, $stderr].each do |io|
|
[$stdin, $stdout, $stderr].each do |io|
|
||||||
io.set_encoding(extern, intern)
|
io.set_encoding(extern, intern)
|
||||||
end
|
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
|
ensure
|
||||||
$VERBOSE = verbose
|
$VERBOSE = verbose
|
||||||
end
|
end
|
||||||
|
|
|
@ -133,6 +133,9 @@ module IRB
|
||||||
include Readline
|
include Readline
|
||||||
# Creates a new input method object using Readline
|
# Creates a new input method object using Readline
|
||||||
def initialize
|
def initialize
|
||||||
|
if Readline.respond_to?(:encoding_system_needs)
|
||||||
|
IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
|
||||||
|
end
|
||||||
super
|
super
|
||||||
|
|
||||||
@line_no = 0
|
@line_no = 0
|
||||||
|
@ -207,6 +210,7 @@ module IRB
|
||||||
include Reline
|
include Reline
|
||||||
# Creates a new input method object using Readline
|
# Creates a new input method object using Readline
|
||||||
def initialize
|
def initialize
|
||||||
|
IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)
|
||||||
super
|
super
|
||||||
|
|
||||||
@line_no = 0
|
@line_no = 0
|
||||||
|
|
|
@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.license = "BSD-2-Clause"
|
spec.license = "BSD-2-Clause"
|
||||||
|
|
||||||
spec.files = [
|
spec.files = [
|
||||||
|
".document",
|
||||||
"Gemfile",
|
"Gemfile",
|
||||||
"LICENSE.txt",
|
"LICENSE.txt",
|
||||||
"README.md",
|
"README.md",
|
||||||
|
@ -38,6 +39,7 @@ Gem::Specification.new do |spec|
|
||||||
"lib/irb/color.rb",
|
"lib/irb/color.rb",
|
||||||
"lib/irb/completion.rb",
|
"lib/irb/completion.rb",
|
||||||
"lib/irb/context.rb",
|
"lib/irb/context.rb",
|
||||||
|
"lib/irb/easter-egg.rb",
|
||||||
"lib/irb/ext/change-ws.rb",
|
"lib/irb/ext/change-ws.rb",
|
||||||
"lib/irb/ext/history.rb",
|
"lib/irb/ext/history.rb",
|
||||||
"lib/irb/ext/loader.rb",
|
"lib/irb/ext/loader.rb",
|
||||||
|
@ -52,7 +54,6 @@ Gem::Specification.new do |spec|
|
||||||
"lib/irb/init.rb",
|
"lib/irb/init.rb",
|
||||||
"lib/irb/input-method.rb",
|
"lib/irb/input-method.rb",
|
||||||
"lib/irb/inspector.rb",
|
"lib/irb/inspector.rb",
|
||||||
"lib/irb/lc/.document",
|
|
||||||
"lib/irb/lc/error.rb",
|
"lib/irb/lc/error.rb",
|
||||||
"lib/irb/lc/help-message",
|
"lib/irb/lc/help-message",
|
||||||
"lib/irb/lc/ja/encoding_aliases.rb",
|
"lib/irb/lc/ja/encoding_aliases.rb",
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
# hide help-message files which contain usage information
|
|
||||||
error.rb
|
|
||||||
ja/encoding_aliases.rb
|
|
||||||
ja/error.rb
|
|
|
@ -24,6 +24,7 @@ module IRB # :nodoc:
|
||||||
@@loaded = []
|
@@loaded = []
|
||||||
|
|
||||||
def initialize(locale = nil)
|
def initialize(locale = nil)
|
||||||
|
@override_encoding = nil
|
||||||
@lang = @territory = @encoding_name = @modifier = nil
|
@lang = @territory = @encoding_name = @modifier = nil
|
||||||
@locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C"
|
@locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C"
|
||||||
if m = LOCALE_NAME_RE.match(@locale)
|
if m = LOCALE_NAME_RE.match(@locale)
|
||||||
|
@ -40,12 +41,16 @@ module IRB # :nodoc:
|
||||||
@encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
|
@encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :lang, :territory, :encoding, :modifier
|
attr_reader :lang, :territory, :modifier
|
||||||
|
|
||||||
|
def encoding
|
||||||
|
@override_encoding || @encoding
|
||||||
|
end
|
||||||
|
|
||||||
def String(mes)
|
def String(mes)
|
||||||
mes = super(mes)
|
mes = super(mes)
|
||||||
if @encoding
|
if encoding
|
||||||
mes.encode(@encoding, undef: :replace)
|
mes.encode(encoding, undef: :replace)
|
||||||
else
|
else
|
||||||
mes
|
mes
|
||||||
end
|
end
|
||||||
|
|
|
@ -211,6 +211,8 @@ class RubyLex
|
||||||
else
|
else
|
||||||
RubyVM::InstructionSequence.compile(code)
|
RubyVM::InstructionSequence.compile(code)
|
||||||
end
|
end
|
||||||
|
rescue EncodingError
|
||||||
|
# This is for a hash with invalid encoding symbol, {"\xAE": 1}
|
||||||
rescue SyntaxError => e
|
rescue SyntaxError => e
|
||||||
case e.message
|
case e.message
|
||||||
when /unterminated (?:string|regexp) meets end of file/
|
when /unterminated (?:string|regexp) meets end of file/
|
||||||
|
@ -317,11 +319,13 @@ class RubyLex
|
||||||
|
|
||||||
def check_newline_depth_difference
|
def check_newline_depth_difference
|
||||||
depth_difference = 0
|
depth_difference = 0
|
||||||
|
open_brace_on_line = 0
|
||||||
@tokens.each_with_index do |t, index|
|
@tokens.each_with_index do |t, index|
|
||||||
case t[1]
|
case t[1]
|
||||||
when :on_ignored_nl, :on_nl, :on_comment
|
when :on_ignored_nl, :on_nl, :on_comment
|
||||||
if index != (@tokens.size - 1)
|
if index != (@tokens.size - 1)
|
||||||
depth_difference = 0
|
depth_difference = 0
|
||||||
|
open_brace_on_line = 0
|
||||||
end
|
end
|
||||||
next
|
next
|
||||||
when :on_sp
|
when :on_sp
|
||||||
|
@ -330,8 +334,9 @@ class RubyLex
|
||||||
case t[1]
|
case t[1]
|
||||||
when :on_lbracket, :on_lbrace, :on_lparen
|
when :on_lbracket, :on_lbrace, :on_lparen
|
||||||
depth_difference += 1
|
depth_difference += 1
|
||||||
|
open_brace_on_line += 1
|
||||||
when :on_rbracket, :on_rbrace, :on_rparen
|
when :on_rbracket, :on_rbrace, :on_rparen
|
||||||
depth_difference -= 1
|
depth_difference -= 1 if open_brace_on_line > 0
|
||||||
when :on_kw
|
when :on_kw
|
||||||
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
|
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
|
||||||
case t[2]
|
case t[2]
|
||||||
|
@ -365,6 +370,7 @@ class RubyLex
|
||||||
is_first_printable_of_line = true
|
is_first_printable_of_line = true
|
||||||
spaces_of_nest = []
|
spaces_of_nest = []
|
||||||
spaces_at_line_head = 0
|
spaces_at_line_head = 0
|
||||||
|
open_brace_on_line = 0
|
||||||
@tokens.each_with_index do |t, index|
|
@tokens.each_with_index do |t, index|
|
||||||
case t[1]
|
case t[1]
|
||||||
when :on_ignored_nl, :on_nl, :on_comment
|
when :on_ignored_nl, :on_nl, :on_comment
|
||||||
|
@ -372,6 +378,7 @@ class RubyLex
|
||||||
spaces_at_line_head = 0
|
spaces_at_line_head = 0
|
||||||
is_first_spaces_of_line = true
|
is_first_spaces_of_line = true
|
||||||
is_first_printable_of_line = true
|
is_first_printable_of_line = true
|
||||||
|
open_brace_on_line = 0
|
||||||
next
|
next
|
||||||
when :on_sp
|
when :on_sp
|
||||||
spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
|
spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
|
||||||
|
@ -380,7 +387,8 @@ class RubyLex
|
||||||
end
|
end
|
||||||
case t[1]
|
case t[1]
|
||||||
when :on_lbracket, :on_lbrace, :on_lparen
|
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
|
when :on_rbracket, :on_rbrace, :on_rparen
|
||||||
if is_first_printable_of_line
|
if is_first_printable_of_line
|
||||||
corresponding_token_depth = spaces_of_nest.pop
|
corresponding_token_depth = spaces_of_nest.pop
|
||||||
|
@ -388,6 +396,7 @@ class RubyLex
|
||||||
spaces_of_nest.pop
|
spaces_of_nest.pop
|
||||||
corresponding_token_depth = nil
|
corresponding_token_depth = nil
|
||||||
end
|
end
|
||||||
|
open_brace_on_line -= 1
|
||||||
when :on_kw
|
when :on_kw
|
||||||
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
|
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
|
||||||
case t[2]
|
case t[2]
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
module IRB # :nodoc:
|
module IRB # :nodoc:
|
||||||
VERSION = "1.2.1"
|
VERSION = "1.2.3"
|
||||||
@RELEASE_VERSION = VERSION
|
@RELEASE_VERSION = VERSION
|
||||||
@LAST_UPDATE_DATE = "2019-12-24"
|
@LAST_UPDATE_DATE = "2020-02-15"
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -45,40 +45,44 @@ module Reline
|
||||||
@completion_quote_character = nil
|
@completion_quote_character = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def encoding
|
||||||
|
Reline::IOGate.encoding
|
||||||
|
end
|
||||||
|
|
||||||
def completion_append_character=(val)
|
def completion_append_character=(val)
|
||||||
if val.nil?
|
if val.nil?
|
||||||
@completion_append_character = nil
|
@completion_append_character = nil
|
||||||
elsif val.size == 1
|
elsif val.size == 1
|
||||||
@completion_append_character = val.encode(Encoding::default_external)
|
@completion_append_character = val.encode(Reline::IOGate.encoding)
|
||||||
elsif val.size > 1
|
elsif val.size > 1
|
||||||
@completion_append_character = val[0].encode(Encoding::default_external)
|
@completion_append_character = val[0].encode(Reline::IOGate.encoding)
|
||||||
else
|
else
|
||||||
@completion_append_character = nil
|
@completion_append_character = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def basic_word_break_characters=(v)
|
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
|
end
|
||||||
|
|
||||||
def completer_word_break_characters=(v)
|
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
|
end
|
||||||
|
|
||||||
def basic_quote_characters=(v)
|
def basic_quote_characters=(v)
|
||||||
@basic_quote_characters = v.encode(Encoding::default_external)
|
@basic_quote_characters = v.encode(Reline::IOGate.encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def completer_quote_characters=(v)
|
def completer_quote_characters=(v)
|
||||||
@completer_quote_characters = v.encode(Encoding::default_external)
|
@completer_quote_characters = v.encode(Reline::IOGate.encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def filename_quote_characters=(v)
|
def filename_quote_characters=(v)
|
||||||
@filename_quote_characters = v.encode(Encoding::default_external)
|
@filename_quote_characters = v.encode(Reline::IOGate.encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def special_prefixes=(v)
|
def special_prefixes=(v)
|
||||||
@special_prefixes = v.encode(Encoding::default_external)
|
@special_prefixes = v.encode(Reline::IOGate.encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def completion_case_fold=(v)
|
def completion_case_fold=(v)
|
||||||
|
@ -171,7 +175,7 @@ module Reline
|
||||||
|
|
||||||
whole_buffer = line_editor.whole_buffer.dup
|
whole_buffer = line_editor.whole_buffer.dup
|
||||||
whole_buffer.taint if RUBY_VERSION < '2.7'
|
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
|
Reline::HISTORY << whole_buffer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -184,8 +188,8 @@ module Reline
|
||||||
|
|
||||||
line = line_editor.line.dup
|
line = line_editor.line.dup
|
||||||
line.taint if RUBY_VERSION < '2.7'
|
line.taint if RUBY_VERSION < '2.7'
|
||||||
if add_hist and line and line.chomp.size > 0
|
if add_hist and line and line.chomp("\n").size > 0
|
||||||
Reline::HISTORY << line.chomp
|
Reline::HISTORY << line.chomp("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
line_editor.reset_line if line_editor.line.nil?
|
line_editor.reset_line if line_editor.line.nil?
|
||||||
|
@ -201,7 +205,7 @@ module Reline
|
||||||
otio = Reline::IOGate.prep
|
otio = Reline::IOGate.prep
|
||||||
|
|
||||||
may_req_ambiguous_char_width
|
may_req_ambiguous_char_width
|
||||||
line_editor.reset(prompt)
|
line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
|
||||||
if multiline
|
if multiline
|
||||||
line_editor.multiline_on
|
line_editor.multiline_on
|
||||||
if block_given?
|
if block_given?
|
||||||
|
@ -332,8 +336,14 @@ module Reline
|
||||||
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
|
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
|
||||||
return if ambiguous_width
|
return if ambiguous_width
|
||||||
Reline::IOGate.move_cursor_column(0)
|
Reline::IOGate.move_cursor_column(0)
|
||||||
print "\u{25bd}"
|
begin
|
||||||
@ambiguous_width = Reline::IOGate.cursor_pos.x
|
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.move_cursor_column(0)
|
||||||
Reline::IOGate.erase_after_cursor
|
Reline::IOGate.erase_after_cursor
|
||||||
end
|
end
|
||||||
|
@ -387,11 +397,15 @@ module Reline
|
||||||
def_instance_delegators self, :readmultiline
|
def_instance_delegators self, :readmultiline
|
||||||
private :readmultiline
|
private :readmultiline
|
||||||
|
|
||||||
|
def self.encoding_system_needs
|
||||||
|
self.core.encoding
|
||||||
|
end
|
||||||
|
|
||||||
def self.core
|
def self.core
|
||||||
@core ||= Core.new { |core|
|
@core ||= Core.new { |core|
|
||||||
core.config = Reline::Config.new
|
core.config = Reline::Config.new
|
||||||
core.key_stroke = Reline::KeyStroke.new(core.config)
|
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.basic_word_break_characters = " \t\n`><=;|&{("
|
||||||
core.completer_word_break_characters = " \t\n`><=;|&{("
|
core.completer_word_break_characters = " \t\n`><=;|&{("
|
||||||
|
@ -405,14 +419,11 @@ module Reline
|
||||||
def self.line_editor
|
def self.line_editor
|
||||||
core.line_editor
|
core.line_editor
|
||||||
end
|
end
|
||||||
|
|
||||||
HISTORY = History.new(core.config)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
||||||
require 'reline/windows'
|
require 'reline/windows'
|
||||||
if Reline::Windows.get_screen_size == [0, 0]
|
if Reline::Windows.msys_tty?
|
||||||
# Maybe Mintty on Cygwin
|
|
||||||
require 'reline/ansi'
|
require 'reline/ansi'
|
||||||
Reline::IOGate = Reline::ANSI
|
Reline::IOGate = Reline::ANSI
|
||||||
else
|
else
|
||||||
|
@ -422,4 +433,5 @@ else
|
||||||
require 'reline/ansi'
|
require 'reline/ansi'
|
||||||
Reline::IOGate = Reline::ANSI
|
Reline::IOGate = Reline::ANSI
|
||||||
end
|
end
|
||||||
|
Reline::HISTORY = Reline::History.new(Reline.core.config)
|
||||||
require 'reline/general_io'
|
require 'reline/general_io'
|
||||||
|
|
|
@ -1,20 +1,49 @@
|
||||||
require 'io/console'
|
require 'io/console'
|
||||||
|
|
||||||
class Reline::ANSI
|
class Reline::ANSI
|
||||||
|
def self.encoding
|
||||||
|
Encoding.default_external
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.win?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
RAW_KEYSTROKE_CONFIG = {
|
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, 65] => :ed_prev_history, # ↑
|
||||||
[27, 91, 66] => :ed_next_history, # ↓
|
[27, 91, 66] => :ed_next_history, # ↓
|
||||||
[27, 91, 67] => :ed_next_char, # →
|
[27, 91, 67] => :ed_next_char, # →
|
||||||
[27, 91, 68] => :ed_prev_char, # ←
|
[27, 91, 68] => :ed_prev_char, # ←
|
||||||
[27, 91, 51, 126] => :key_delete, # Del
|
|
||||||
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
# KDE
|
||||||
[27, 91, 52, 126] => :ed_move_to_end, # End
|
|
||||||
[27, 91, 72] => :ed_move_to_beg, # Home
|
[27, 91, 72] => :ed_move_to_beg, # Home
|
||||||
[27, 91, 70] => :ed_move_to_end, # End
|
[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>
|
[27, 32] => :em_set_mark, # M-<space>
|
||||||
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
[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, 67] => :em_next_word, # Ctrl+→
|
||||||
[27, 91, 49, 59, 53, 68] => :ed_prev_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
|
@@input = STDIN
|
||||||
|
@ -41,16 +70,23 @@ class Reline::ANSI
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.retrieve_keybuffer
|
def self.retrieve_keybuffer
|
||||||
|
begin
|
||||||
result = select([@@input], [], [], 0.001)
|
result = select([@@input], [], [], 0.001)
|
||||||
return if result.nil?
|
return if result.nil?
|
||||||
str = @@input.read_nonblock(1024)
|
str = @@input.read_nonblock(1024)
|
||||||
str.bytes.each do |c|
|
str.bytes.each do |c|
|
||||||
@@buf.push(c)
|
@@buf.push(c)
|
||||||
end
|
end
|
||||||
|
rescue EOFError
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_screen_size
|
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
|
rescue Errno::ENOTTY
|
||||||
[24, 80]
|
[24, 80]
|
||||||
end
|
end
|
||||||
|
@ -88,12 +124,12 @@ class Reline::ANSI
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.move_cursor_column(x)
|
def self.move_cursor_column(x)
|
||||||
print "\e[#{x + 1}G"
|
@@output.write "\e[#{x + 1}G"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.move_cursor_up(x)
|
def self.move_cursor_up(x)
|
||||||
if x > 0
|
if x > 0
|
||||||
print "\e[#{x}A" if x > 0
|
@@output.write "\e[#{x}A" if x > 0
|
||||||
elsif x < 0
|
elsif x < 0
|
||||||
move_cursor_down(-x)
|
move_cursor_down(-x)
|
||||||
end
|
end
|
||||||
|
@ -101,24 +137,24 @@ class Reline::ANSI
|
||||||
|
|
||||||
def self.move_cursor_down(x)
|
def self.move_cursor_down(x)
|
||||||
if x > 0
|
if x > 0
|
||||||
print "\e[#{x}B" if x > 0
|
@@output.write "\e[#{x}B" if x > 0
|
||||||
elsif x < 0
|
elsif x < 0
|
||||||
move_cursor_up(-x)
|
move_cursor_up(-x)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.erase_after_cursor
|
def self.erase_after_cursor
|
||||||
print "\e[K"
|
@@output.write "\e[K"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.scroll_down(x)
|
def self.scroll_down(x)
|
||||||
return if x.zero?
|
return if x.zero?
|
||||||
print "\e[#{x}S"
|
@@output.write "\e[#{x}S"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.clear_screen
|
def self.clear_screen
|
||||||
print "\e[2J"
|
@@output.write "\e[2J"
|
||||||
print "\e[1;1H"
|
@@output.write "\e[1;1H"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@old_winch_handler = nil
|
@@old_winch_handler = nil
|
||||||
|
|
|
@ -83,8 +83,17 @@ class Reline::Config
|
||||||
@key_actors[@keymap_label]
|
@key_actors[@keymap_label]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inputrc_path
|
||||||
|
case ENV['INPUTRC']
|
||||||
|
when nil, ''
|
||||||
|
DEFAULT_PATH
|
||||||
|
else
|
||||||
|
ENV['INPUTRC']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def read(file = nil)
|
def read(file = nil)
|
||||||
file ||= File.expand_path(ENV['INPUTRC'] || DEFAULT_PATH)
|
file ||= File.expand_path(inputrc_path)
|
||||||
begin
|
begin
|
||||||
if file.respond_to?(:readlines)
|
if file.respond_to?(:readlines)
|
||||||
lines = file.readlines
|
lines = file.readlines
|
||||||
|
@ -184,9 +193,8 @@ class Reline::Config
|
||||||
|
|
||||||
def bind_variable(name, value)
|
def bind_variable(name, value)
|
||||||
case name
|
case name
|
||||||
when *VARIABLE_NAMES then
|
when 'history-size'
|
||||||
variable_name = :"@#{name.tr(?-, ?_)}"
|
@history_size = value.to_i
|
||||||
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
|
||||||
when 'bell-style'
|
when 'bell-style'
|
||||||
@bell_style =
|
@bell_style =
|
||||||
case value
|
case value
|
||||||
|
@ -225,6 +233,9 @@ class Reline::Config
|
||||||
end
|
end
|
||||||
when 'keyseq-timeout'
|
when 'keyseq-timeout'
|
||||||
@keyseq_timeout = value.to_i
|
@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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
require 'timeout'
|
require 'timeout'
|
||||||
|
|
||||||
class Reline::GeneralIO
|
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 = {}
|
RAW_KEYSTROKE_CONFIG = {}
|
||||||
|
|
||||||
@@buf = []
|
@@buf = []
|
||||||
|
|
|
@ -19,7 +19,7 @@ class Reline::History < Array
|
||||||
|
|
||||||
def []=(index, val)
|
def []=(index, val)
|
||||||
index = check_index(index)
|
index = check_index(index)
|
||||||
super(index, String.new(val, encoding: Encoding::default_external))
|
super(index, String.new(val, encoding: Reline.encoding_system_needs))
|
||||||
end
|
end
|
||||||
|
|
||||||
def concat(*val)
|
def concat(*val)
|
||||||
|
@ -39,12 +39,12 @@ class Reline::History < Array
|
||||||
val.shift(diff)
|
val.shift(diff)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
def <<(val)
|
def <<(val)
|
||||||
shift if size + 1 > @config.history_size
|
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
|
end
|
||||||
|
|
||||||
private def check_index(index)
|
private def check_index(index)
|
||||||
|
|
|
@ -57,10 +57,10 @@ class Reline::LineEditor
|
||||||
NON_PRINTING_END = "\2"
|
NON_PRINTING_END = "\2"
|
||||||
WIDTH_SCANNER = /\G(?:#{NON_PRINTING_START}|#{NON_PRINTING_END}|#{CSI_REGEXP}|#{OSC_REGEXP}|\X)/
|
WIDTH_SCANNER = /\G(?:#{NON_PRINTING_START}|#{NON_PRINTING_END}|#{CSI_REGEXP}|#{OSC_REGEXP}|\X)/
|
||||||
|
|
||||||
def initialize(config)
|
def initialize(config, encoding)
|
||||||
@config = config
|
@config = config
|
||||||
@completion_append_character = ''
|
@completion_append_character = ''
|
||||||
reset_variables
|
reset_variables(encoding: encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def check_multiline_prompt(buffer, prompt)
|
private def check_multiline_prompt(buffer, prompt)
|
||||||
|
@ -85,10 +85,10 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
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
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
||||||
@screen_size = Reline::IOGate.get_screen_size
|
@screen_size = Reline::IOGate.get_screen_size
|
||||||
reset_variables(prompt, encoding)
|
reset_variables(prompt, encoding: encoding)
|
||||||
@old_trap = Signal.trap('SIGINT') {
|
@old_trap = Signal.trap('SIGINT') {
|
||||||
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
||||||
raise Interrupt
|
raise Interrupt
|
||||||
|
@ -139,7 +139,7 @@ class Reline::LineEditor
|
||||||
@eof
|
@eof
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_variables(prompt = '', encoding = Encoding.default_external)
|
def reset_variables(prompt = '', encoding:)
|
||||||
@prompt = prompt
|
@prompt = prompt
|
||||||
@mark_pointer = nil
|
@mark_pointer = nil
|
||||||
@encoding = encoding
|
@encoding = encoding
|
||||||
|
@ -317,9 +317,9 @@ class Reline::LineEditor
|
||||||
if @menu_info
|
if @menu_info
|
||||||
scroll_down(@highest_in_all - @first_line_started_from)
|
scroll_down(@highest_in_all - @first_line_started_from)
|
||||||
@rerender_all = true
|
@rerender_all = true
|
||||||
@menu_info.list.each do |item|
|
@menu_info.list.sort!.each do |item|
|
||||||
Reline::IOGate.move_cursor_column(0)
|
Reline::IOGate.move_cursor_column(0)
|
||||||
@output.print item
|
@output.write item
|
||||||
@output.flush
|
@output.flush
|
||||||
scroll_down(1)
|
scroll_down(1)
|
||||||
end
|
end
|
||||||
|
@ -507,12 +507,20 @@ class Reline::LineEditor
|
||||||
Reline::IOGate.move_cursor_column(0)
|
Reline::IOGate.move_cursor_column(0)
|
||||||
visual_lines.each_with_index do |line, index|
|
visual_lines.each_with_index do |line, index|
|
||||||
if line.nil?
|
if line.nil?
|
||||||
Reline::IOGate.erase_after_cursor
|
if Reline::IOGate.win? and calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
|
||||||
move_cursor_down(1)
|
# A newline is automatically inserted if a character is rendered at eol on command prompt.
|
||||||
Reline::IOGate.move_cursor_column(0)
|
else
|
||||||
|
Reline::IOGate.erase_after_cursor
|
||||||
|
move_cursor_down(1)
|
||||||
|
Reline::IOGate.move_cursor_column(0)
|
||||||
|
end
|
||||||
next
|
next
|
||||||
end
|
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
|
@output.flush
|
||||||
if @first_prompt
|
if @first_prompt
|
||||||
@first_prompt = false
|
@first_prompt = false
|
||||||
|
@ -535,7 +543,7 @@ class Reline::LineEditor
|
||||||
return before if before.nil? || before.empty?
|
return before if before.nil? || before.empty?
|
||||||
|
|
||||||
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
|
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
|
||||||
after.lines(chomp: true)
|
after.lines("\n", chomp: true)
|
||||||
else
|
else
|
||||||
before
|
before
|
||||||
end
|
end
|
||||||
|
@ -905,7 +913,6 @@ class Reline::LineEditor
|
||||||
quote = nil
|
quote = nil
|
||||||
i += 1
|
i += 1
|
||||||
rest = nil
|
rest = nil
|
||||||
break_pointer = nil
|
|
||||||
elsif quote and slice.start_with?(escaped_quote)
|
elsif quote and slice.start_with?(escaped_quote)
|
||||||
# skip
|
# skip
|
||||||
i += 2
|
i += 2
|
||||||
|
@ -915,7 +922,7 @@ class Reline::LineEditor
|
||||||
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
||||||
escaped_quote = /\\#{Regexp.escape(quote)}/
|
escaped_quote = /\\#{Regexp.escape(quote)}/
|
||||||
i += 1
|
i += 1
|
||||||
break_pointer = i
|
break_pointer = i - 1
|
||||||
elsif not quote and slice =~ word_break_regexp
|
elsif not quote and slice =~ word_break_regexp
|
||||||
rest = $'
|
rest = $'
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -937,6 +944,11 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
preposing = ''
|
preposing = ''
|
||||||
|
if break_pointer
|
||||||
|
preposing = @line.byteslice(0, break_pointer)
|
||||||
|
else
|
||||||
|
preposing = ''
|
||||||
|
end
|
||||||
target = before
|
target = before
|
||||||
end
|
end
|
||||||
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
||||||
|
@ -1091,6 +1103,11 @@ class Reline::LineEditor
|
||||||
|
|
||||||
private def ed_insert(key)
|
private def ed_insert(key)
|
||||||
if key.instance_of?(String)
|
if key.instance_of?(String)
|
||||||
|
begin
|
||||||
|
key.encode(Encoding::UTF_8)
|
||||||
|
rescue Encoding::UndefinedConversionError
|
||||||
|
return
|
||||||
|
end
|
||||||
width = Reline::Unicode.get_mbchar_width(key)
|
width = Reline::Unicode.get_mbchar_width(key)
|
||||||
if @cursor == @cursor_max
|
if @cursor == @cursor_max
|
||||||
@line += key
|
@line += key
|
||||||
|
@ -1101,6 +1118,11 @@ class Reline::LineEditor
|
||||||
@cursor += width
|
@cursor += width
|
||||||
@cursor_max += width
|
@cursor_max += width
|
||||||
else
|
else
|
||||||
|
begin
|
||||||
|
key.chr.encode(Encoding::UTF_8)
|
||||||
|
rescue Encoding::UndefinedConversionError
|
||||||
|
return
|
||||||
|
end
|
||||||
if @cursor == @cursor_max
|
if @cursor == @cursor_max
|
||||||
@line += key.chr
|
@line += key.chr
|
||||||
else
|
else
|
||||||
|
@ -1876,6 +1898,16 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
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)
|
private def ed_delete_prev_char(key, arg: 1)
|
||||||
deleted = ''
|
deleted = ''
|
||||||
arg.times do
|
arg.times do
|
||||||
|
@ -1898,6 +1930,18 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
|
|
||||||
private def vi_change_meta(key)
|
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
|
end
|
||||||
|
|
||||||
private def vi_delete_meta(key)
|
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) }
|
@waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg) }
|
||||||
end
|
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)
|
if key.instance_of?(String)
|
||||||
inputed_char = key
|
inputed_char = key
|
||||||
else
|
else
|
||||||
inputed_char = key.chr
|
inputed_char = key.chr
|
||||||
end
|
end
|
||||||
|
prev_total = nil
|
||||||
total = nil
|
total = nil
|
||||||
found = false
|
found = false
|
||||||
@line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
|
@line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
|
||||||
|
@ -2086,13 +2135,66 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
width = Reline::Unicode.get_mbchar_width(mbchar)
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
||||||
|
prev_total = total
|
||||||
total = [total.first + mbchar.bytesize, total.last + width]
|
total = [total.first + mbchar.bytesize, total.last + width]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if found and total
|
if not need_prev_char and found and total
|
||||||
byte_size, width = total
|
byte_size, width = total
|
||||||
@byte_pointer += byte_size
|
@byte_pointer += byte_size
|
||||||
@cursor += width
|
@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
|
end
|
||||||
@waiting_proc = nil
|
@waiting_proc = nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
module Reline
|
module Reline
|
||||||
VERSION = '0.1.2'
|
VERSION = '0.1.3'
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
require 'fiddle/import'
|
require 'fiddle/import'
|
||||||
|
|
||||||
class Reline::Windows
|
class Reline::Windows
|
||||||
|
def self.encoding
|
||||||
|
Encoding::UTF_8
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.win?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
RAW_KEYSTROKE_CONFIG = {
|
RAW_KEYSTROKE_CONFIG = {
|
||||||
[224, 72] => :ed_prev_history, # ↑
|
[224, 72] => :ed_prev_history, # ↑
|
||||||
[224, 80] => :ed_next_history, # ↓
|
[224, 80] => :ed_next_history, # ↓
|
||||||
|
@ -68,6 +76,8 @@ class Reline::Windows
|
||||||
STD_INPUT_HANDLE = -10
|
STD_INPUT_HANDLE = -10
|
||||||
STD_OUTPUT_HANDLE = -11
|
STD_OUTPUT_HANDLE = -11
|
||||||
WINDOW_BUFFER_SIZE_EVENT = 0x04
|
WINDOW_BUFFER_SIZE_EVENT = 0x04
|
||||||
|
FILE_TYPE_PIPE = 0x0003
|
||||||
|
FILE_NAME_INFO = 2
|
||||||
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
||||||
@@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
@@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
||||||
@@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
@@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
||||||
|
@ -80,9 +90,36 @@ class Reline::Windows
|
||||||
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
||||||
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
||||||
@@ReadConsoleInput = Win32API.new('kernel32', 'ReadConsoleInput', ['L', 'P', '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 = []
|
@@input_buf = []
|
||||||
@@output_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
|
def self.getwch
|
||||||
unless @@input_buf.empty?
|
unless @@input_buf.empty?
|
||||||
return @@input_buf.shift
|
return @@input_buf.shift
|
||||||
|
@ -99,7 +136,7 @@ class Reline::Windows
|
||||||
return @@input_buf.shift
|
return @@input_buf.shift
|
||||||
end
|
end
|
||||||
begin
|
begin
|
||||||
bytes = ret.chr(Encoding::UTF_8).encode(Encoding.default_external).bytes
|
bytes = ret.chr(Encoding::UTF_8).bytes
|
||||||
@@input_buf.push(*bytes)
|
@@input_buf.push(*bytes)
|
||||||
rescue Encoding::UndefinedConversionError
|
rescue Encoding::UndefinedConversionError
|
||||||
@@input_buf << ret
|
@@input_buf << ret
|
||||||
|
@ -205,7 +242,7 @@ class Reline::Windows
|
||||||
|
|
||||||
def self.scroll_down(val)
|
def self.scroll_down(val)
|
||||||
return if val.zero?
|
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
|
destination_origin = 0 # y * 65536 + x
|
||||||
fill = [' '.ord, 0].pack('SS')
|
fill = [' '.ord, 0].pack('SS')
|
||||||
@@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
|
@@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
|
||||||
|
@ -213,8 +250,8 @@ class Reline::Windows
|
||||||
|
|
||||||
def self.clear_screen
|
def self.clear_screen
|
||||||
# TODO: Use FillConsoleOutputCharacter and FillConsoleOutputAttribute
|
# TODO: Use FillConsoleOutputCharacter and FillConsoleOutputAttribute
|
||||||
print "\e[2J"
|
write "\e[2J"
|
||||||
print "\e[1;1H"
|
write "\e[1;1H"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_screen_size(rows, columns)
|
def self.set_screen_size(rows, columns)
|
||||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.metadata["source_code_uri"] = spec.homepage
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
|
||||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
||||||
# Specify which files should be added to the gem when it is released.
|
# 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.
|
# 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
|
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
|
end
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
|
|
|
@ -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)
|
||||||
assert_ctrl("#{cc.ord}", cc, r, w)
|
assert_ctrl("#{cc.ord}", cc, r, w)
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -457,7 +462,7 @@ defined?(IO.console) and TestIO_Console.class_eval do
|
||||||
noctty = [EnvUtil.rubybin, "-e", "Process.daemon(true)"]
|
noctty = [EnvUtil.rubybin, "-e", "Process.daemon(true)"]
|
||||||
when !(rubyw = RbConfig::CONFIG["RUBYW_INSTALL_NAME"]).empty?
|
when !(rubyw = RbConfig::CONFIG["RUBYW_INSTALL_NAME"]).empty?
|
||||||
dir, base = File.split(EnvUtil.rubybin)
|
dir, base = File.split(EnvUtil.rubybin)
|
||||||
noctty = [File.join(dir, base.sub(/ruby/, rubyw))]
|
noctty = [File.join(dir, base.sub(RUBY_ENGINE, rubyw))]
|
||||||
end
|
end
|
||||||
|
|
||||||
if noctty
|
if noctty
|
||||||
|
|
|
@ -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}",
|
"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})",
|
'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}",
|
"# 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}",
|
'"##@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}",
|
'"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}",
|
'/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e#{RED}}#{CLEAR}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
|
||||||
|
|
|
@ -25,5 +25,27 @@ module TestIRB
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("1r.positi", bind: binding), "1r.positive?")
|
assert_include(IRB::InputCompletor.retrieve_completion_data("1r.positi", bind: binding), "1r.positive?")
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("1i.positi", bind: binding))
|
assert_empty(IRB::InputCompletor.retrieve_completion_data("1i.positi", bind: binding))
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,6 +63,13 @@ module TestIRB
|
||||||
assert_not_match(/rescue _\.class/, e.message)
|
assert_not_match(/rescue _\.class/, e.message)
|
||||||
end
|
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
|
def test_evaluate_with_onigmo_warning
|
||||||
assert_warning("(irb):1: warning: character class has duplicated range: /[aa]/\n") do
|
assert_warning("(irb):1: warning: character class has duplicated range: /[aa]/\n") do
|
||||||
@context.evaluate('/[aa]/', 1)
|
@context.evaluate('/[aa]/', 1)
|
||||||
|
@ -216,5 +223,36 @@ module TestIRB
|
||||||
assert(irb.context.echo?, "echo? should be true by default")
|
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")
|
assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to true")
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
130
test/irb/test_ruby_lex.rb
Normal file
130
test/irb/test_ruby_lex.rb
Normal file
|
@ -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
|
|
@ -3,18 +3,22 @@ begin
|
||||||
ReadlineSo = Readline
|
ReadlineSo = Readline
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
end
|
end
|
||||||
require "reline"
|
|
||||||
|
|
||||||
def use_ext_readline # Use ext/readline as Readline
|
def use_ext_readline # Use ext/readline as Readline
|
||||||
Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
|
Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
|
||||||
Object.const_set(:Readline, ReadlineSo)
|
Object.const_set(:Readline, ReadlineSo)
|
||||||
end
|
end
|
||||||
|
|
||||||
def use_lib_reline # Use lib/reline as Readline
|
begin
|
||||||
Reline.send(:remove_const, 'IOGate') if Reline.const_defined?('IOGate')
|
require "reline"
|
||||||
Reline.const_set('IOGate', Reline::GeneralIO)
|
rescue LoadError
|
||||||
Reline.send(:core).config.instance_variable_set(:@test_mode, true)
|
else
|
||||||
Reline.send(:core).config.reset
|
def use_lib_reline # Use lib/reline as Readline
|
||||||
Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
|
Reline.send(:remove_const, 'IOGate') if Reline.const_defined?('IOGate')
|
||||||
Object.const_set(:Readline, Reline)
|
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
|
end
|
||||||
|
|
|
@ -21,13 +21,16 @@ module BasetestReadline
|
||||||
Readline.point = 0
|
Readline.point = 0
|
||||||
rescue NotImplementedError
|
rescue NotImplementedError
|
||||||
end
|
end
|
||||||
|
Readline.special_prefixes = ""
|
||||||
|
Readline.completion_append_character = nil
|
||||||
Readline.input = nil
|
Readline.input = nil
|
||||||
Readline.output = nil
|
Readline.output = nil
|
||||||
SAVED_ENV.each_with_index {|k, i| ENV[k] = @saved_env[i] }
|
SAVED_ENV.each_with_index {|k, i| ENV[k] = @saved_env[i] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_readline
|
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|
|
with_temp_stdio do |stdin, stdout|
|
||||||
stdin.write("hello\n")
|
stdin.write("hello\n")
|
||||||
stdin.close
|
stdin.close
|
||||||
|
@ -45,7 +48,7 @@ module BasetestReadline
|
||||||
# Work around lack of SecurityError in Reline
|
# Work around lack of SecurityError in Reline
|
||||||
# test mode with tainted prompt.
|
# test mode with tainted prompt.
|
||||||
# Also skip test on Ruby 2.7+, where $SAFE/taint is deprecated.
|
# 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
|
begin
|
||||||
Thread.start {
|
Thread.start {
|
||||||
$SAFE = 1
|
$SAFE = 1
|
||||||
|
@ -65,8 +68,8 @@ module BasetestReadline
|
||||||
# line_buffer
|
# line_buffer
|
||||||
# point
|
# point
|
||||||
def test_line_buffer__point
|
def test_line_buffer__point
|
||||||
skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
||||||
skip "GNU Readline has special behaviors" if defined?(Reline) and Readline == Reline
|
omit "GNU Readline has special behaviors" if defined?(Reline) and Readline == Reline
|
||||||
begin
|
begin
|
||||||
Readline.line_buffer
|
Readline.line_buffer
|
||||||
Readline.point
|
Readline.point
|
||||||
|
@ -154,7 +157,7 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_completion_proc_empty_result
|
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|
|
with_temp_stdio do |stdin, stdout|
|
||||||
stdin.write("first\t")
|
stdin.write("first\t")
|
||||||
stdin.flush
|
stdin.flush
|
||||||
|
@ -233,12 +236,12 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_completion_encoding
|
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]'
|
bug5941 = '[Bug #5941]'
|
||||||
append_character = Readline.completion_append_character
|
append_character = Readline.completion_append_character
|
||||||
Readline.completion_append_character = ""
|
Readline.completion_append_character = ""
|
||||||
completion_case_fold = Readline.completion_case_fold
|
completion_case_fold = Readline.completion_case_fold
|
||||||
locale = Encoding.find("locale")
|
locale = get_default_internal_encoding
|
||||||
if locale == Encoding::UTF_8
|
if locale == Encoding::UTF_8
|
||||||
enc1 = Encoding::EUC_JP
|
enc1 = Encoding::EUC_JP
|
||||||
else
|
else
|
||||||
|
@ -261,7 +264,7 @@ module BasetestReadline
|
||||||
end or
|
end or
|
||||||
begin
|
begin
|
||||||
return if assert_under_utf8
|
return if assert_under_utf8
|
||||||
skip("missing test for locale #{locale.name}")
|
omit("missing test for locale #{locale.name}")
|
||||||
end
|
end
|
||||||
expected = results[0][0...1]
|
expected = results[0][0...1]
|
||||||
Readline.completion_case_fold = false
|
Readline.completion_case_fold = false
|
||||||
|
@ -285,32 +288,6 @@ module BasetestReadline
|
||||||
# filename_quote_characters
|
# filename_quote_characters
|
||||||
# special_prefixes
|
# special_prefixes
|
||||||
def test_some_characters_methods
|
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
|
end
|
||||||
|
|
||||||
def test_closed_outstream
|
def test_closed_outstream
|
||||||
|
@ -335,7 +312,7 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_point
|
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)
|
assert_equal(0, Readline.point)
|
||||||
Readline.insert_text('12345')
|
Readline.insert_text('12345')
|
||||||
assert_equal(5, Readline.point)
|
assert_equal(5, Readline.point)
|
||||||
|
@ -350,7 +327,7 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_insert_text
|
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"
|
str = "test_insert_text"
|
||||||
assert_equal(0, Readline.point)
|
assert_equal(0, Readline.point)
|
||||||
assert_equal(Readline, Readline.insert_text(str))
|
assert_equal(Readline, Readline.insert_text(str))
|
||||||
|
@ -381,7 +358,7 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_delete_text
|
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"
|
str = "test_insert_text"
|
||||||
assert_equal(0, Readline.point)
|
assert_equal(0, Readline.point)
|
||||||
assert_equal(Readline, Readline.insert_text(str))
|
assert_equal(Readline, Readline.insert_text(str))
|
||||||
|
@ -401,7 +378,7 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_modify_text_in_pre_input_hook
|
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|
|
with_temp_stdio {|stdin, stdout|
|
||||||
begin
|
begin
|
||||||
stdin.write("world\n")
|
stdin.write("world\n")
|
||||||
|
@ -432,9 +409,10 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_input_metachar
|
def test_input_metachar
|
||||||
skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
||||||
skip("Won't pass on mingw w/readline 7.0.005 [ruby-core:45682]") if mingw?
|
# test will pass on Windows reline, but not readline
|
||||||
skip 'Needs GNU Readline 6 or later' if windows? and defined?(TestReadline) and kind_of?(TestReadline) and Readline::VERSION < '6.0'
|
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]'
|
bug6601 = '[ruby-core:45682]'
|
||||||
Readline::HISTORY << "hello"
|
Readline::HISTORY << "hello"
|
||||||
wo = nil
|
wo = nil
|
||||||
|
@ -451,10 +429,10 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_input_metachar_multibyte
|
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
|
unless Encoding.find("locale") == Encoding::UTF_8
|
||||||
return if assert_under_utf8
|
return if assert_under_utf8
|
||||||
skip 'this test needs UTF-8 locale'
|
omit 'this test needs UTF-8 locale'
|
||||||
end
|
end
|
||||||
bug6602 = '[ruby-core:45683]'
|
bug6602 = '[ruby-core:45683]'
|
||||||
Readline::HISTORY << "\u3042\u3093"
|
Readline::HISTORY << "\u3042\u3093"
|
||||||
|
@ -481,7 +459,8 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_refresh_line
|
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'
|
bug6232 = '[ruby-core:43957] [Bug #6232] refresh_line after set_screen_size'
|
||||||
with_temp_stdio do |stdin, stdout|
|
with_temp_stdio do |stdin, stdout|
|
||||||
replace_stdio(stdin.path, stdout.path) do
|
replace_stdio(stdin.path, stdout.path) do
|
||||||
|
@ -508,83 +487,98 @@ module BasetestReadline
|
||||||
def test_using_quoting_detection_proc
|
def test_using_quoting_detection_proc
|
||||||
saved_completer_quote_characters = Readline.completer_quote_characters
|
saved_completer_quote_characters = Readline.completer_quote_characters
|
||||||
saved_completer_word_break_characters = Readline.completer_word_break_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=)
|
return unless Readline.respond_to?(:quoting_detection_proc=)
|
||||||
|
|
||||||
passed_text = nil
|
begin
|
||||||
line = nil
|
passed_text = nil
|
||||||
|
line = nil
|
||||||
|
|
||||||
with_temp_stdio do |stdin, stdout|
|
with_temp_stdio do |stdin, stdout|
|
||||||
replace_stdio(stdin.path, stdout.path) do
|
replace_stdio(stdin.path, stdout.path) do
|
||||||
Readline.completion_proc = ->(text) do
|
Readline.completion_proc = ->(text) do
|
||||||
passed_text = text
|
passed_text = text
|
||||||
['completion'].map { |i|
|
['completion'].map { |i|
|
||||||
i.encode(Encoding.default_external)
|
i.encode(Encoding.default_external)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
Readline.completer_quote_characters = '\'"'
|
Readline.completer_quote_characters = '\'"'
|
||||||
Readline.completer_word_break_characters = ' '
|
Readline.completer_word_break_characters = ' '
|
||||||
Readline.quoting_detection_proc = ->(text, index) do
|
Readline.quoting_detection_proc = ->(text, index) do
|
||||||
index > 0 && text[index-1] == '\\'
|
index > 0 && text[index-1] == '\\'
|
||||||
end
|
end
|
||||||
|
|
||||||
stdin.write("first second\\ third\t")
|
stdin.write("first second\\ third\t")
|
||||||
stdin.flush
|
stdin.flush
|
||||||
line = Readline.readline('> ', false)
|
line = Readline.readline('> ', false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal('second\\ third', passed_text)
|
assert_equal('second\\ third', passed_text)
|
||||||
assert_equal('first completion', line.chomp(' '))
|
assert_equal('first completion', line.chomp(' '))
|
||||||
ensure
|
ensure
|
||||||
Readline.completer_quote_characters = saved_completer_quote_characters
|
Readline.completer_quote_characters = saved_completer_quote_characters
|
||||||
Readline.completer_word_break_characters = saved_completer_word_break_characters
|
Readline.completer_word_break_characters = saved_completer_word_break_characters
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_using_quoting_detection_proc_with_multibyte_input
|
def test_using_quoting_detection_proc_with_multibyte_input
|
||||||
|
Readline.completion_append_character = nil
|
||||||
saved_completer_quote_characters = Readline.completer_quote_characters
|
saved_completer_quote_characters = Readline.completer_quote_characters
|
||||||
saved_completer_word_break_characters = Readline.completer_word_break_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=)
|
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
|
return if assert_under_utf8
|
||||||
skip 'this test needs UTF-8 locale'
|
omit 'this test needs UTF-8 locale'
|
||||||
end
|
end
|
||||||
|
|
||||||
passed_text = nil
|
begin
|
||||||
escaped_char_indexes = []
|
passed_text = nil
|
||||||
line = nil
|
escaped_char_indexes = []
|
||||||
|
line = nil
|
||||||
|
|
||||||
with_temp_stdio do |stdin, stdout|
|
with_temp_stdio do |stdin, stdout|
|
||||||
replace_stdio(stdin.path, stdout.path) do
|
replace_stdio(stdin.path, stdout.path) do
|
||||||
Readline.completion_proc = ->(text) do
|
Readline.completion_proc = ->(text) do
|
||||||
passed_text = text
|
passed_text = text
|
||||||
['completion'].map { |i|
|
['completion'].map { |i|
|
||||||
i.encode(Encoding.default_external)
|
i.encode(Encoding.default_external)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
Readline.completer_quote_characters = '\'"'
|
Readline.completer_quote_characters = '\'"'
|
||||||
Readline.completer_word_break_characters = ' '
|
Readline.completer_word_break_characters = ' '
|
||||||
Readline.quoting_detection_proc = ->(text, index) do
|
Readline.quoting_detection_proc = ->(text, index) do
|
||||||
escaped = index > 0 && text[index-1] == '\\'
|
escaped = index > 0 && text[index-1] == '\\'
|
||||||
escaped_char_indexes << index if escaped
|
escaped_char_indexes << index if escaped
|
||||||
escaped
|
escaped
|
||||||
end
|
end
|
||||||
|
|
||||||
stdin.write("\u3042\u3093 second\\ third\t")
|
stdin.write("\u3042\u3093 second\\ third\t")
|
||||||
stdin.flush
|
stdin.flush
|
||||||
line = Readline.readline('> ', false)
|
line = Readline.readline('> ', false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal([10], escaped_char_indexes)
|
assert_equal([10], escaped_char_indexes)
|
||||||
assert_equal('second\\ third', passed_text)
|
assert_equal('second\\ third', passed_text)
|
||||||
assert_equal("\u3042\u3093 completion", line)
|
assert_equal("\u3042\u3093 completion#{Readline.completion_append_character}", line)
|
||||||
ensure
|
ensure
|
||||||
Readline.completer_quote_characters = saved_completer_quote_characters
|
Readline.completer_quote_characters = saved_completer_quote_characters
|
||||||
Readline.completer_word_break_characters = saved_completer_word_break_characters
|
Readline.completer_word_break_characters = saved_completer_word_break_characters
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_simple_completion
|
def test_simple_completion
|
||||||
skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
||||||
|
|
||||||
line = nil
|
line = nil
|
||||||
|
|
||||||
|
@ -594,7 +588,7 @@ module BasetestReadline
|
||||||
Readline.output = null
|
Readline.output = null
|
||||||
Readline.completion_proc = ->(text) do
|
Readline.completion_proc = ->(text) do
|
||||||
['abcde', 'abc12'].map { |i|
|
['abcde', 'abc12'].map { |i|
|
||||||
i.encode(Encoding.default_external)
|
i.encode(get_default_internal_encoding)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
w.write("a\t\n")
|
w.write("a\t\n")
|
||||||
|
@ -607,8 +601,8 @@ module BasetestReadline
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_completion_with_completion_append_character
|
def test_completion_with_completion_append_character
|
||||||
skip "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
|
||||||
skip "Readline.completion_append_character is not implemented" unless Readline.respond_to?(:completion_append_character=)
|
omit "Readline.completion_append_character is not implemented" unless Readline.respond_to?(:completion_append_character=)
|
||||||
line = nil
|
line = nil
|
||||||
|
|
||||||
append_character = Readline.completion_append_character
|
append_character = Readline.completion_append_character
|
||||||
|
@ -619,7 +613,7 @@ module BasetestReadline
|
||||||
Readline.completion_append_character = '!'
|
Readline.completion_append_character = '!'
|
||||||
Readline.completion_proc = ->(text) do
|
Readline.completion_proc = ->(text) do
|
||||||
['abcde'].map { |i|
|
['abcde'].map { |i|
|
||||||
i.encode(Encoding.default_external)
|
i.encode(get_default_internal_encoding)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
w.write("a\t\n")
|
w.write("a\t\n")
|
||||||
|
@ -681,9 +675,9 @@ module BasetestReadline
|
||||||
return unless Readline.respond_to?(:completion_quote_character)
|
return unless Readline.respond_to?(:completion_quote_character)
|
||||||
if /solaris/i =~ RUBY_PLATFORM
|
if /solaris/i =~ RUBY_PLATFORM
|
||||||
# http://rubyci.s3.amazonaws.com/solaris11s-sunc/ruby-trunk/log/20181228T102505Z.fail.html.gz
|
# 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
|
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.completion_proc = -> (_) { [] }
|
||||||
Readline.completer_quote_characters = "'\""
|
Readline.completer_quote_characters = "'\""
|
||||||
|
@ -730,7 +724,7 @@ module BasetestReadline
|
||||||
Tempfile.create("test_readline_stdin") {|stdin|
|
Tempfile.create("test_readline_stdin") {|stdin|
|
||||||
Tempfile.create("test_readline_stdout") {|stdout|
|
Tempfile.create("test_readline_stdout") {|stdout|
|
||||||
yield stdin, stdout
|
yield stdin, stdout
|
||||||
if windows?
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
# needed since readline holds refs to tempfiles, can't delete on Windows
|
# needed since readline holds refs to tempfiles, can't delete on Windows
|
||||||
Readline.input = STDIN
|
Readline.input = STDIN
|
||||||
Readline.output = STDOUT
|
Readline.output = STDOUT
|
||||||
|
@ -766,7 +760,7 @@ module BasetestReadline
|
||||||
return false if ENV['LC_ALL'] == 'UTF-8'
|
return false if ENV['LC_ALL'] == 'UTF-8'
|
||||||
loc = caller_locations(1, 1)[0].base_label.to_s
|
loc = caller_locations(1, 1)[0].base_label.to_s
|
||||||
assert_separately([{"LC_ALL"=>"UTF-8"}, "-r", __FILE__], <<SRC)
|
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)
|
#{self.class.name}.new(#{loc.dump}).run(Test::Unit::Runner.new)
|
||||||
SRC
|
SRC
|
||||||
return true
|
return true
|
||||||
|
@ -780,7 +774,7 @@ class TestReadline < Test::Unit::TestCase
|
||||||
use_ext_readline
|
use_ext_readline
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
end if defined?(ReadlineSo)
|
end if defined?(ReadlineSo) && ENV["TEST_READLINE_OR_RELINE"] != "Reline"
|
||||||
|
|
||||||
class TestRelineAsReadline < Test::Unit::TestCase
|
class TestRelineAsReadline < Test::Unit::TestCase
|
||||||
include BasetestReadline
|
include BasetestReadline
|
||||||
|
@ -789,4 +783,12 @@ class TestRelineAsReadline < Test::Unit::TestCase
|
||||||
use_lib_reline
|
use_lib_reline
|
||||||
super
|
super
|
||||||
end
|
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"
|
||||||
|
|
|
@ -260,6 +260,7 @@ class TestReadlineHistory < Test::Unit::TestCase
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
end if defined?(::ReadlineSo) && defined?(::ReadlineSo::HISTORY) &&
|
end if defined?(::ReadlineSo) && defined?(::ReadlineSo::HISTORY) &&
|
||||||
|
ENV["TEST_READLINE_OR_RELINE"] != "Reline" &&
|
||||||
(
|
(
|
||||||
begin
|
begin
|
||||||
ReadlineSo::HISTORY.clear
|
ReadlineSo::HISTORY.clear
|
||||||
|
@ -275,4 +276,12 @@ class TestRelineAsReadlineHistory < Test::Unit::TestCase
|
||||||
use_lib_reline
|
use_lib_reline
|
||||||
super
|
super
|
||||||
end
|
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"
|
||||||
|
|
|
@ -195,4 +195,24 @@ class Reline::Config::Test < Reline::TestCase
|
||||||
expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes }
|
expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes }
|
||||||
assert_equal expected, @config.key_bindings
|
assert_equal expected, @config.key_bindings
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -2,6 +2,10 @@ require_relative 'helper'
|
||||||
require "reline/history"
|
require "reline/history"
|
||||||
|
|
||||||
class Reline::History::Test < Reline::TestCase
|
class Reline::History::Test < Reline::TestCase
|
||||||
|
def setup
|
||||||
|
Reline.send(:test_mode)
|
||||||
|
end
|
||||||
|
|
||||||
def test_ancestors
|
def test_ancestors
|
||||||
assert_equal(Reline::History.ancestors.include?(Array), true)
|
assert_equal(Reline::History.ancestors.include?(Array), true)
|
||||||
end
|
end
|
||||||
|
@ -268,6 +272,10 @@ class Reline::History::Test < Reline::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_default_internal_encoding
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,8 +8,8 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
|
||||||
Reline::HISTORY.instance_variable_set(:@config, @config)
|
Reline::HISTORY.instance_variable_set(:@config, @config)
|
||||||
Reline::HISTORY.clear
|
Reline::HISTORY.clear
|
||||||
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
||||||
@line_editor = Reline::LineEditor.new(@config)
|
@line_editor = Reline::LineEditor.new(@config, @encoding)
|
||||||
@line_editor.reset(@prompt, @encoding)
|
@line_editor.reset(@prompt, encoding: @encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ed_insert_one
|
def test_ed_insert_one
|
||||||
|
@ -1325,6 +1325,68 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
|
||||||
assert_line('foo_ba')
|
assert_line('foo_ba')
|
||||||
end
|
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
|
def test_completion_with_perfect_match
|
||||||
@line_editor.completion_proc = proc { |word|
|
@line_editor.completion_proc = proc { |word|
|
||||||
%w{
|
%w{
|
||||||
|
@ -1834,6 +1896,15 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
|
||||||
assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer))
|
assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer))
|
||||||
end
|
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
|
=begin # TODO: move KeyStroke instance from Reline to LineEditor
|
||||||
def test_key_delete
|
def test_key_delete
|
||||||
input_keys('ab')
|
input_keys('ab')
|
||||||
|
|
|
@ -9,8 +9,8 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
||||||
set editing-mode vi
|
set editing-mode vi
|
||||||
LINES
|
LINES
|
||||||
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
||||||
@line_editor = Reline::LineEditor.new(@config)
|
@line_editor = Reline::LineEditor.new(@config, @encoding)
|
||||||
@line_editor.reset(@prompt, @encoding)
|
@line_editor.reset(@prompt, encoding: @encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_vi_command_mode
|
def test_vi_command_mode
|
||||||
|
@ -24,6 +24,74 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
||||||
assert_line('abc')
|
assert_line('abc')
|
||||||
end
|
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
|
def test_ed_insert_one
|
||||||
input_keys('a')
|
input_keys('a')
|
||||||
assert_line('a')
|
assert_line('a')
|
||||||
|
@ -565,6 +633,60 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
||||||
assert_cursor_max(6)
|
assert_cursor_max(6)
|
||||||
end
|
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
|
def test_vi_delete_next_char
|
||||||
input_keys("abc\C-[h")
|
input_keys("abc\C-[h")
|
||||||
assert_byte_pointer_size('a')
|
assert_byte_pointer_size('a')
|
||||||
|
@ -1092,4 +1214,27 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
||||||
assert_cursor_max(11)
|
assert_cursor_max(11)
|
||||||
assert_line('aaa ddd eee')
|
assert_line('aaa ddd eee')
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -3,7 +3,8 @@ require_relative 'helper'
|
||||||
class Reline::MacroTest < Reline::TestCase
|
class Reline::MacroTest < Reline::TestCase
|
||||||
def setup
|
def setup
|
||||||
@config = Reline::Config.new
|
@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])
|
@line_editor.instance_variable_set(:@screen_size, [24, 80])
|
||||||
@output = @line_editor.output = File.open(IO::NULL, "w")
|
@output = @line_editor.output = File.open(IO::NULL, "w")
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,15 +21,15 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.completion_append_character = "a".encode(Encoding::ASCII)
|
Reline.completion_append_character = "a".encode(Encoding::ASCII)
|
||||||
assert_equal("a", Reline.completion_append_character)
|
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)
|
Reline.completion_append_character = "ba".encode(Encoding::ASCII)
|
||||||
assert_equal("b", Reline.completion_append_character)
|
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)
|
Reline.completion_append_character = "cba".encode(Encoding::ASCII)
|
||||||
assert_equal("c", Reline.completion_append_character)
|
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
|
Reline.completion_append_character = nil
|
||||||
assert_equal(nil, Reline.completion_append_character)
|
assert_equal(nil, Reline.completion_append_character)
|
||||||
|
@ -40,7 +40,7 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.basic_word_break_characters = "[".encode(Encoding::ASCII)
|
Reline.basic_word_break_characters = "[".encode(Encoding::ASCII)
|
||||||
assert_equal("[", Reline.basic_word_break_characters)
|
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
|
end
|
||||||
|
|
||||||
def test_completer_word_break_characters
|
def test_completer_word_break_characters
|
||||||
|
@ -48,7 +48,7 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.completer_word_break_characters = "[".encode(Encoding::ASCII)
|
Reline.completer_word_break_characters = "[".encode(Encoding::ASCII)
|
||||||
assert_equal("[", Reline.completer_word_break_characters)
|
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
|
end
|
||||||
|
|
||||||
def test_basic_quote_characters
|
def test_basic_quote_characters
|
||||||
|
@ -56,7 +56,7 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.basic_quote_characters = "`".encode(Encoding::ASCII)
|
Reline.basic_quote_characters = "`".encode(Encoding::ASCII)
|
||||||
assert_equal("`", Reline.basic_quote_characters)
|
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
|
end
|
||||||
|
|
||||||
def test_completer_quote_characters
|
def test_completer_quote_characters
|
||||||
|
@ -64,7 +64,7 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.completer_quote_characters = "`".encode(Encoding::ASCII)
|
Reline.completer_quote_characters = "`".encode(Encoding::ASCII)
|
||||||
assert_equal("`", Reline.completer_quote_characters)
|
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
|
end
|
||||||
|
|
||||||
def test_filename_quote_characters
|
def test_filename_quote_characters
|
||||||
|
@ -72,7 +72,7 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.filename_quote_characters = "\'".encode(Encoding::ASCII)
|
Reline.filename_quote_characters = "\'".encode(Encoding::ASCII)
|
||||||
assert_equal("\'", Reline.filename_quote_characters)
|
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
|
end
|
||||||
|
|
||||||
def test_special_prefixes
|
def test_special_prefixes
|
||||||
|
@ -80,7 +80,7 @@ class Reline::Test < Reline::TestCase
|
||||||
|
|
||||||
Reline.special_prefixes = "\'".encode(Encoding::ASCII)
|
Reline.special_prefixes = "\'".encode(Encoding::ASCII)
|
||||||
assert_equal("\'", Reline.special_prefixes)
|
assert_equal("\'", Reline.special_prefixes)
|
||||||
assert_equal(Encoding::default_external, Reline.special_prefixes.encoding)
|
assert_equal(get_reline_encoding, Reline.special_prefixes.encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_completion_case_fold
|
def test_completion_case_fold
|
||||||
|
@ -94,7 +94,10 @@ class Reline::Test < Reline::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_completion_proc
|
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 {}
|
p = proc {}
|
||||||
Reline.completion_proc = p
|
Reline.completion_proc = p
|
||||||
|
@ -267,4 +270,8 @@ class Reline::Test < Reline::TestCase
|
||||||
def test_may_req_ambiguous_char_width
|
def test_may_req_ambiguous_char_width
|
||||||
# TODO in Reline::Core
|
# TODO in Reline::Core
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_reline_encoding
|
||||||
|
RUBY_PLATFORM =~ /mswin|mingw/ ? Encoding::UTF_8 : Encoding::default_external
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,8 +7,8 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase
|
||||||
@config = Reline::Config.new
|
@config = Reline::Config.new
|
||||||
Reline::HISTORY.instance_variable_set(:@config, @config)
|
Reline::HISTORY.instance_variable_set(:@config, @config)
|
||||||
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
||||||
@line_editor = Reline::LineEditor.new(@config)
|
@line_editor = Reline::LineEditor.new(@config, @encoding)
|
||||||
@line_editor.reset(@prompt, @encoding)
|
@line_editor.reset(@prompt, encoding: @encoding)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_calculate_width
|
def test_calculate_width
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Reline::WithinPipeTest < Reline::TestCase
|
||||||
def teardown
|
def teardown
|
||||||
Reline.input = STDIN
|
Reline.input = STDIN
|
||||||
Reline.output = STDOUT
|
Reline.output = STDOUT
|
||||||
|
Reline.point = 0
|
||||||
@reader.close
|
@reader.close
|
||||||
@writer.close
|
@writer.close
|
||||||
@output.close
|
@output.close
|
||||||
|
|
41
test/reline/yamatanooroti/test_rendering.rb
Normal file
41
test/reline/yamatanooroti/test_rendering.rb
Normal file
|
@ -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
|
|
@ -285,7 +285,7 @@ class TestRubyOptions < Test::Unit::TestCase
|
||||||
/unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/)
|
/unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/)
|
||||||
|
|
||||||
if /mswin|mingw|aix|android/ =~ RUBY_PLATFORM &&
|
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
|
# This result depends on locale because LANG=C doesn't affect locale
|
||||||
# on Windows.
|
# on Windows.
|
||||||
# On AIX, the source encoding of stdin with LANG=C is ISO-8859-1,
|
# 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
|
def test_command_line_glob_nonascii
|
||||||
bug10555 = '[ruby-dev:48752] [Bug #10555]'
|
bug10555 = '[ruby-dev:48752] [Bug #10555]'
|
||||||
name = "\u{3042}.txt"
|
name = "\u{3042}.txt"
|
||||||
expected = name.encode("locale") rescue "?.txt"
|
expected = name.encode("external") rescue "?.txt"
|
||||||
with_tmpchdir do |dir|
|
with_tmpchdir do |dir|
|
||||||
open(name, "w") {}
|
open(name, "w") {}
|
||||||
assert_in_out_err(["-e", "puts ARGV", "?.txt"], "", [expected], [],
|
assert_in_out_err(["-e", "puts ARGV", "?.txt"], "", [expected], [],
|
||||||
bug10555, encoding: "locale")
|
bug10555, encoding: "external")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -875,7 +875,7 @@ class TestRubyOptions < Test::Unit::TestCase
|
||||||
with_tmpchdir do |dir|
|
with_tmpchdir do |dir|
|
||||||
Ougai.each {|f| open(f, "w") {}}
|
Ougai.each {|f| open(f, "w") {}}
|
||||||
assert_in_out_err(["-Eutf-8", "-e", "puts ARGV", "*"], "", Ougai, encoding: "utf-8")
|
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)
|
assert_in_out_err(["-e", "puts ARGV", "*.txt"], "", ougai)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue