summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiroshi SHIBATA <[email protected]>2025-01-23 16:13:13 +0900
committerHiroshi SHIBATA <[email protected]>2025-01-24 15:46:46 +0900
commit0fdc9b9fd168f9d25d78c79a9e970be7d0967363 (patch)
tree6a7b0bc8b9f94fdcb609689c1b644dcfa0c43d36
parent881924f2593e89e5ef78a73a4e14948a66ca0e08 (diff)
Migrate irb and reline to the bundled gems
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12624
-rw-r--r--gems/bundled_gems3
-rw-r--r--lib/irb.rb736
-rw-r--r--lib/irb/cmd/nop.rb4
-rw-r--r--lib/irb/color.rb263
-rw-r--r--lib/irb/color_printer.rb56
-rw-r--r--lib/irb/command.rb23
-rw-r--r--lib/irb/command/backtrace.rb17
-rw-r--r--lib/irb/command/base.rb60
-rw-r--r--lib/irb/command/break.rb17
-rw-r--r--lib/irb/command/catch.rb17
-rw-r--r--lib/irb/command/cd.rb51
-rw-r--r--lib/irb/command/chws.rb40
-rw-r--r--lib/irb/command/context.rb16
-rw-r--r--lib/irb/command/continue.rb17
-rw-r--r--lib/irb/command/copy.rb73
-rw-r--r--lib/irb/command/debug.rb73
-rw-r--r--lib/irb/command/delete.rb17
-rw-r--r--lib/irb/command/disable_irb.rb19
-rw-r--r--lib/irb/command/edit.rb63
-rw-r--r--lib/irb/command/exit.rb18
-rw-r--r--lib/irb/command/finish.rb17
-rw-r--r--lib/irb/command/force_exit.rb18
-rw-r--r--lib/irb/command/help.rb83
-rw-r--r--lib/irb/command/history.rb45
-rw-r--r--lib/irb/command/info.rb17
-rw-r--r--lib/irb/command/internal_helpers.rb27
-rw-r--r--lib/irb/command/irb_info.rb33
-rw-r--r--lib/irb/command/load.rb91
-rw-r--r--lib/irb/command/ls.rb167
-rw-r--r--lib/irb/command/measure.rb49
-rw-r--r--lib/irb/command/next.rb17
-rw-r--r--lib/irb/command/pushws.rb65
-rw-r--r--lib/irb/command/show_doc.rb51
-rw-r--r--lib/irb/command/show_source.rb74
-rw-r--r--lib/irb/command/step.rb17
-rw-r--r--lib/irb/command/subirb.rb123
-rw-r--r--lib/irb/command/whereami.rb23
-rw-r--r--lib/irb/completion.rb504
-rw-r--r--lib/irb/context.rb751
-rw-r--r--lib/irb/debug.rb127
-rw-r--r--lib/irb/debug/ui.rb101
-rw-r--r--lib/irb/default_commands.rb279
-rw-r--r--lib/irb/easter-egg.rb152
-rw-r--r--lib/irb/ext/change-ws.rb37
-rw-r--r--lib/irb/ext/eval_history.rb149
-rw-r--r--lib/irb/ext/loader.rb127
-rw-r--r--lib/irb/ext/multi-irb.rb258
-rw-r--r--lib/irb/ext/tracer.rb39
-rw-r--r--lib/irb/ext/use-loader.rb67
-rw-r--r--lib/irb/ext/workspaces.rb36
-rw-r--r--lib/irb/frame.rb80
-rw-r--r--lib/irb/help.rb28
-rw-r--r--lib/irb/helper_method.rb29
-rw-r--r--lib/irb/helper_method/base.rb16
-rw-r--r--lib/irb/helper_method/conf.rb11
-rw-r--r--lib/irb/history.rb116
-rw-r--r--lib/irb/init.rb540
-rw-r--r--lib/irb/input-method.rb515
-rw-r--r--lib/irb/inspector.rb136
-rw-r--r--lib/irb/irb.gemspec46
-rw-r--r--lib/irb/lc/error.rb52
-rw-r--r--lib/irb/lc/help-message55
-rw-r--r--lib/irb/lc/ja/error.rb53
-rw-r--r--lib/irb/lc/ja/help-message58
-rw-r--r--lib/irb/locale.rb153
-rw-r--r--lib/irb/nesting_parser.rb239
-rw-r--r--lib/irb/notifier.rb230
-rw-r--r--lib/irb/output-method.rb80
-rw-r--r--lib/irb/pager.rb213
-rw-r--r--lib/irb/ruby-lex.rb476
-rw-r--r--lib/irb/ruby_logo.aa118
-rw-r--r--lib/irb/source_finder.rb138
-rw-r--r--lib/irb/statement.rb101
-rw-r--r--lib/irb/version.rb11
-rw-r--r--lib/irb/workspace.rb171
-rw-r--r--lib/irb/ws-for-case-2.rb9
-rw-r--r--lib/irb/xmp.rb164
-rw-r--r--lib/readline.gemspec33
-rw-r--r--lib/readline.rb7
-rw-r--r--lib/reline.rb518
-rw-r--r--lib/reline/config.rb373
-rw-r--r--lib/reline/face.rb199
-rw-r--r--lib/reline/history.rb76
-rw-r--r--lib/reline/io.rb55
-rw-r--r--lib/reline/io/ansi.rb332
-rw-r--r--lib/reline/io/dumb.rb120
-rw-r--r--lib/reline/io/windows.rb530
-rw-r--r--lib/reline/key_actor.rb8
-rw-r--r--lib/reline/key_actor/base.rb37
-rw-r--r--lib/reline/key_actor/composite.rb17
-rw-r--r--lib/reline/key_actor/emacs.rb517
-rw-r--r--lib/reline/key_actor/vi_command.rb518
-rw-r--r--lib/reline/key_actor/vi_insert.rb517
-rw-r--r--lib/reline/key_stroke.rb119
-rw-r--r--lib/reline/kill_ring.rb125
-rw-r--r--lib/reline/line_editor.rb2362
-rw-r--r--lib/reline/reline.gemspec30
-rw-r--r--lib/reline/unicode.rb415
-rw-r--r--lib/reline/unicode/east_asian_width.rb1293
-rw-r--r--lib/reline/version.rb3
-rw-r--r--test/irb/command/test_cd.rb84
-rw-r--r--test/irb/command/test_command_aliasing.rb50
-rw-r--r--test/irb/command/test_copy.rb70
-rw-r--r--test/irb/command/test_custom_command.rb194
-rw-r--r--test/irb/command/test_disable_irb.rb28
-rw-r--r--test/irb/command/test_force_exit.rb51
-rw-r--r--test/irb/command/test_help.rb75
-rw-r--r--test/irb/command/test_multi_irb_commands.rb50
-rw-r--r--test/irb/command/test_show_source.rb410
-rw-r--r--test/irb/helper.rb234
-rw-r--r--test/irb/test_color.rb275
-rw-r--r--test/irb/test_color_printer.rb82
-rw-r--r--test/irb/test_command.rb1001
-rw-r--r--test/irb/test_completion.rb317
-rw-r--r--test/irb/test_context.rb737
-rw-r--r--test/irb/test_debugger_integration.rb513
-rw-r--r--test/irb/test_eval_history.rb69
-rw-r--r--test/irb/test_evaluation.rb44
-rw-r--r--test/irb/test_helper_method.rb135
-rw-r--r--test/irb/test_history.rb573
-rw-r--r--test/irb/test_init.rb408
-rw-r--r--test/irb/test_input_method.rb195
-rw-r--r--test/irb/test_irb.rb936
-rw-r--r--test/irb/test_locale.rb118
-rw-r--r--test/irb/test_nesting_parser.rb339
-rw-r--r--test/irb/test_option.rb13
-rw-r--r--test/irb/test_pager.rb74
-rw-r--r--test/irb/test_raise_exception.rb74
-rw-r--r--test/irb/test_ruby_lex.rb242
-rw-r--r--test/irb/test_tracer.rb90
-rw-r--r--test/irb/test_type_completor.rb109
-rw-r--r--test/irb/test_workspace.rb126
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb494
-rw-r--r--test/reline/helper.rb158
-rw-r--r--test/reline/test_ansi.rb72
-rw-r--r--test/reline/test_config.rb616
-rw-r--r--test/reline/test_face.rb257
-rw-r--r--test/reline/test_history.rb317
-rw-r--r--test/reline/test_key_actor_emacs.rb1743
-rw-r--r--test/reline/test_key_actor_vi.rb967
-rw-r--r--test/reline/test_key_stroke.rb111
-rw-r--r--test/reline/test_kill_ring.rb268
-rw-r--r--test/reline/test_line_editor.rb271
-rw-r--r--test/reline/test_macro.rb40
-rw-r--r--test/reline/test_reline.rb487
-rw-r--r--test/reline/test_reline_key.rb10
-rw-r--r--test/reline/test_string_processing.rb46
-rw-r--r--test/reline/test_unicode.rb286
-rw-r--r--test/reline/test_within_pipe.rb77
-rw-r--r--test/reline/windows/test_key_event_record.rb41
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl257
-rw-r--r--test/reline/yamatanooroti/termination_checker.rb26
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb1915
153 files changed, 3 insertions, 33341 deletions
diff --git a/gems/bundled_gems b/gems/bundled_gems
index c254e979a4..0fa265b352 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -41,3 +41,6 @@ benchmark 0.4.0 https://github.com/ruby/benchmark
logger 1.6.5 https://github.com/ruby/logger
rdoc 6.11.0 https://github.com/ruby/rdoc
win32ole 1.9.1 https://github.com/ruby/win32ole
+irb 1.15.1 https://github.com/ruby/irb
+reline 0.6.0 https://github.com/ruby/reline
+readline 0.0.4 https://github.com/ruby/readline
diff --git a/lib/irb.rb b/lib/irb.rb
deleted file mode 100644
index fd0bfe35c7..0000000000
--- a/lib/irb.rb
+++ /dev/null
@@ -1,736 +0,0 @@
-# frozen_string_literal: true
-
-# :markup: markdown
-# irb.rb - irb main module
-# by Keiju ISHITSUKA([email protected])
-#
-
-require "ripper"
-require "reline"
-
-require_relative "irb/init"
-require_relative "irb/context"
-require_relative "irb/default_commands"
-
-require_relative "irb/ruby-lex"
-require_relative "irb/statement"
-require_relative "irb/history"
-require_relative "irb/input-method"
-require_relative "irb/locale"
-require_relative "irb/color"
-
-require_relative "irb/version"
-require_relative "irb/easter-egg"
-require_relative "irb/debug"
-require_relative "irb/pager"
-
-module IRB
-
- # An exception raised by IRB.irb_abort
- class Abort < Exception;end # :nodoc:
-
- class << self
- # The current IRB::Context of the session, see IRB.conf
- #
- # irb
- # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
- # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
- def CurrentContext # :nodoc:
- conf[:MAIN_CONTEXT]
- end
-
- # Initializes IRB and creates a new Irb.irb object at the `TOPLEVEL_BINDING`
- def start(ap_path = nil)
- STDOUT.sync = true
- $0 = File::basename(ap_path, ".rb") if ap_path
-
- setup(ap_path)
-
- if @CONF[:SCRIPT]
- irb = Irb.new(nil, @CONF[:SCRIPT])
- else
- irb = Irb.new
- end
- irb.run(@CONF)
- end
-
- # Quits irb
- def irb_exit(*) # :nodoc:
- throw :IRB_EXIT, false
- end
-
- # Aborts then interrupts irb.
- #
- # Will raise an Abort exception, or the given `exception`.
- def irb_abort(irb, exception = Abort) # :nodoc:
- irb.context.thread.raise exception, "abort then interrupt!"
- end
- end
-
- class Irb
- # Note: instance and index assignment expressions could also be written like:
- # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former be
- # parsed as :assign and echo will be suppressed, but the latter is parsed as a
- # :method_add_arg and the output won't be suppressed
-
- PROMPT_MAIN_TRUNCATE_LENGTH = 32
- PROMPT_MAIN_TRUNCATE_OMISSION = '...'
- CONTROL_CHARACTERS_PATTERN = "\x00-\x1F"
-
- # Returns the current context of this irb session
- attr_reader :context
- # The lexer used by this irb session
- attr_accessor :scanner
-
- attr_reader :from_binding
-
- # Creates a new irb session
- def initialize(workspace = nil, input_method = nil, from_binding: false)
- @from_binding = from_binding
- @context = Context.new(self, workspace, input_method)
- @context.workspace.load_helper_methods_to_main
- @signal_status = :IN_IRB
- @scanner = RubyLex.new
- @line_no = 1
- end
-
- # A hook point for `debug` command's breakpoint after :IRB_EXIT as well as its
- # clean-up
- def debug_break
- # it means the debug integration has been activated
- if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:capture_frames_without_irb)
- # after leaving this initial breakpoint, revert the capture_frames patch
- DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :capture_frames_without_irb)
- # and remove the redundant method
- DEBUGGER__.singleton_class.send(:undef_method, :capture_frames_without_irb)
- end
- end
-
- def debug_readline(binding)
- workspace = IRB::WorkSpace.new(binding)
- context.replace_workspace(workspace)
- context.workspace.load_helper_methods_to_main
- @line_no += 1
-
- # When users run:
- # 1. Debugging commands, like `step 2`
- # 2. Any input that's not irb-command, like `foo = 123`
- #
- #
- # Irb#eval_input will simply return the input, and we need to pass it to the
- # debugger.
- input = nil
- forced_exit = catch(:IRB_EXIT) do
- if History.save_history? && context.io.support_history_saving?
- # Previous IRB session's history has been saved when `Irb#run` is exited We need
- # to make sure the saved history is not saved again by resetting the counter
- context.io.reset_history_counter
-
- begin
- input = eval_input
- ensure
- context.io.save_history
- end
- else
- input = eval_input
- end
- false
- end
-
- Kernel.exit if forced_exit
-
- if input&.include?("\n")
- @line_no += input.count("\n") - 1
- end
-
- input
- end
-
- def run(conf = IRB.conf)
- in_nested_session = !!conf[:MAIN_CONTEXT]
- conf[:IRB_RC].call(context) if conf[:IRB_RC]
- prev_context = conf[:MAIN_CONTEXT]
- conf[:MAIN_CONTEXT] = context
-
- load_history = !in_nested_session && context.io.support_history_saving?
- save_history = load_history && History.save_history?
-
- if load_history
- context.io.load_history
- end
-
- prev_trap = trap("SIGINT") do
- signal_handle
- end
-
- begin
- if defined?(RubyVM.keep_script_lines)
- keep_script_lines_backup = RubyVM.keep_script_lines
- RubyVM.keep_script_lines = true
- end
-
- forced_exit = catch(:IRB_EXIT) do
- eval_input
- end
- ensure
- # Do not restore to nil. It will cause IRB crash when used with threads.
- IRB.conf[:MAIN_CONTEXT] = prev_context if prev_context
-
- RubyVM.keep_script_lines = keep_script_lines_backup if defined?(RubyVM.keep_script_lines)
- trap("SIGINT", prev_trap)
- conf[:AT_EXIT].each{|hook| hook.call}
-
- context.io.save_history if save_history
- Kernel.exit if forced_exit
- end
- end
-
- # Evaluates input for this session.
- def eval_input
- configure_io
-
- each_top_level_statement do |statement, line_no|
- signal_status(:IN_EVAL) do
- begin
- # If the integration with debugger is activated, we return certain input if it
- # should be dealt with by debugger
- if @context.with_debugger && statement.should_be_handled_by_debugger?
- return statement.code
- end
-
- @context.evaluate(statement, line_no)
-
- if @context.echo? && !statement.suppresses_echo?
- if statement.is_assignment?
- if @context.echo_on_assignment?
- output_value(@context.echo_on_assignment? == :truncate)
- end
- else
- output_value
- end
- end
- rescue SystemExit, SignalException
- raise
- rescue Interrupt, Exception => exc
- handle_exception(exc)
- @context.workspace.local_variable_set(:_, exc)
- end
- end
- end
- end
-
- def read_input(prompt)
- signal_status(:IN_INPUT) do
- @context.io.prompt = prompt
- if l = @context.io.gets
- print l if @context.verbose?
- else
- if @context.ignore_eof? and @context.io.readable_after_eof?
- l = "\n"
- if @context.verbose?
- printf "Use \"exit\" to leave %s\n", @context.ap_name
- end
- else
- print "\n" if @context.prompting?
- end
- end
- l
- end
- end
-
- def readmultiline
- prompt = generate_prompt([], false, 0)
-
- # multiline
- return read_input(prompt) if @context.io.respond_to?(:check_termination)
-
- # nomultiline
- code = +''
- line_offset = 0
- loop do
- line = read_input(prompt)
- unless line
- return code.empty? ? nil : code
- end
-
- code << line
- return code if command?(code)
-
- tokens, opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
- return code if terminated
-
- line_offset += 1
- continue = @scanner.should_continue?(tokens)
- prompt = generate_prompt(opens, continue, line_offset)
- end
- end
-
- def each_top_level_statement
- loop do
- code = readmultiline
- break unless code
- yield parse_input(code), @line_no
- @line_no += code.count("\n")
- rescue RubyLex::TerminateLineInput
- end
- end
-
- def parse_input(code)
- if code.match?(/\A\n*\z/)
- return Statement::EmptyInput.new
- end
-
- code = code.dup.force_encoding(@context.io.encoding)
- is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
-
- @context.parse_input(code, is_assignment_expression)
- end
-
- def command?(code)
- parse_input(code).is_a?(Statement::Command)
- end
-
- def configure_io
- if @context.io.respond_to?(:check_termination)
- @context.io.check_termination do |code|
- if Reline::IOGate.in_pasting?
- rest = @scanner.check_termination_in_prev_line(code, local_variables: @context.local_variables)
- if rest
- Reline.delete_text
- rest.bytes.reverse_each do |c|
- Reline.ungetc(c)
- end
- true
- else
- false
- end
- else
- next true if command?(code)
-
- _tokens, _opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
- terminated
- end
- end
- end
- if @context.io.respond_to?(:dynamic_prompt)
- @context.io.dynamic_prompt do |lines|
- tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, local_variables: @context.local_variables)
- line_results = IRB::NestingParser.parse_by_line(tokens)
- tokens_until_line = []
- line_results.map.with_index do |(line_tokens, _prev_opens, next_opens, _min_depth), line_num_offset|
- line_tokens.each do |token, _s|
- # Avoid appending duplicated token. Tokens that include "n" like multiline
- # tstring_content can exist in multiple lines.
- tokens_until_line << token if token != tokens_until_line.last
- end
- continue = @scanner.should_continue?(tokens_until_line)
- generate_prompt(next_opens, continue, line_num_offset)
- end
- end
- end
-
- if @context.io.respond_to?(:auto_indent) and @context.auto_indent_mode
- @context.io.auto_indent do |lines, line_index, byte_pointer, is_newline|
- next nil if lines == [nil] # Workaround for exit IRB with CTRL+d
- next nil if !is_newline && lines[line_index]&.byteslice(0, byte_pointer)&.match?(/\A\s*\z/)
-
- code = lines[0..line_index].map { |l| "#{l}\n" }.join
- tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
- @scanner.process_indent_level(tokens, lines, line_index, is_newline)
- end
- end
- end
-
- def convert_invalid_byte_sequence(str, enc)
- str.force_encoding(enc)
- str.scrub { |c|
- c.bytes.map{ |b| "\\x#{b.to_s(16).upcase}" }.join
- }
- end
-
- def encode_with_invalid_byte_sequence(str, enc)
- conv = Encoding::Converter.new(str.encoding, enc)
- dst = String.new
- begin
- ret = conv.primitive_convert(str, dst)
- case ret
- when :invalid_byte_sequence
- conv.insert_output(conv.primitive_errinfo[3].dump[1..-2])
- redo
- when :undefined_conversion
- c = conv.primitive_errinfo[3].dup.force_encoding(conv.primitive_errinfo[1])
- conv.insert_output(c.dump[1..-2])
- redo
- when :incomplete_input
- conv.insert_output(conv.primitive_errinfo[3].dump[1..-2])
- when :finished
- end
- break
- end while nil
- dst
- end
-
- def handle_exception(exc)
- if exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
- !(SyntaxError === exc) && !(EncodingError === exc)
- # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
- irb_bug = true
- else
- irb_bug = false
- # To support backtrace filtering while utilizing Exception#full_message, we need to clone
- # the exception to avoid modifying the original exception's backtrace.
- exc = exc.clone
- filtered_backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact
- backtrace_filter = IRB.conf[:BACKTRACE_FILTER]
-
- if backtrace_filter
- if backtrace_filter.respond_to?(:call)
- filtered_backtrace = backtrace_filter.call(filtered_backtrace)
- else
- warn "IRB.conf[:BACKTRACE_FILTER] #{backtrace_filter} should respond to `call` method"
- end
- end
-
- exc.set_backtrace(filtered_backtrace)
- end
-
- highlight = Color.colorable?
-
- order =
- if RUBY_VERSION < '3.0.0'
- STDOUT.tty? ? :bottom : :top
- else # '3.0.0' <= RUBY_VERSION
- :top
- end
-
- message = exc.full_message(order: order, highlight: highlight)
- message = convert_invalid_byte_sequence(message, exc.message.encoding)
- message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
- message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
- case order
- when :top
- lines = m.split("\n")
- when :bottom
- lines = m.split("\n").reverse
- end
- unless irb_bug
- if lines.size > @context.back_trace_limit
- omit = lines.size - @context.back_trace_limit
- lines = lines[0..(@context.back_trace_limit - 1)]
- lines << "\t... %d levels..." % omit
- end
- end
- lines = lines.reverse if order == :bottom
- lines.map{ |l| l + "\n" }.join
- }
- # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
- message = message.gsub(/\(irb\):(?<num>\d+):in (?<open_quote>[`'])<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in #{$~[:open_quote]}<main>'" }
- puts message
-
- if irb_bug
- puts "This may be an issue with IRB. If you believe this is an unexpected behavior, please report it to https://github.com/ruby/irb/issues"
- end
- rescue Exception => handler_exc
- begin
- puts exc.inspect
- puts "backtraces are hidden because #{handler_exc} was raised when processing them"
- rescue Exception
- puts 'Uninspectable exception occurred'
- end
- end
-
- # Evaluates the given block using the given `path` as the Context#irb_path and
- # `name` as the Context#irb_name.
- #
- # Used by the irb command `source`, see IRB@IRB+Sessions for more information.
- def suspend_name(path = nil, name = nil)
- @context.irb_path, back_path = path, @context.irb_path if path
- @context.irb_name, back_name = name, @context.irb_name if name
- begin
- yield back_path, back_name
- ensure
- @context.irb_path = back_path if path
- @context.irb_name = back_name if name
- end
- end
-
- # Evaluates the given block using the given `workspace` as the
- # Context#workspace.
- #
- # Used by the irb command `irb_load`, see IRB@IRB+Sessions for more information.
- def suspend_workspace(workspace)
- current_workspace = @context.workspace
- @context.replace_workspace(workspace)
- yield
- ensure
- @context.replace_workspace current_workspace
- end
-
- # Evaluates the given block using the given `input_method` as the Context#io.
- #
- # Used by the irb commands `source` and `irb_load`, see IRB@IRB+Sessions for
- # more information.
- def suspend_input_method(input_method)
- back_io = @context.io
- @context.instance_eval{@io = input_method}
- begin
- yield back_io
- ensure
- @context.instance_eval{@io = back_io}
- end
- end
-
- # Handler for the signal SIGINT, see Kernel#trap for more information.
- def signal_handle
- unless @context.ignore_sigint?
- print "\nabort!\n" if @context.verbose?
- exit
- end
-
- case @signal_status
- when :IN_INPUT
- print "^C\n"
- raise RubyLex::TerminateLineInput
- when :IN_EVAL
- IRB.irb_abort(self)
- when :IN_LOAD
- IRB.irb_abort(self, LoadAbort)
- when :IN_IRB
- # ignore
- else
- # ignore other cases as well
- end
- end
-
- # Evaluates the given block using the given `status`.
- def signal_status(status)
- return yield if @signal_status == :IN_LOAD
-
- signal_status_back = @signal_status
- @signal_status = status
- begin
- yield
- ensure
- @signal_status = signal_status_back
- end
- end
-
- def output_value(omit = false) # :nodoc:
- unless @context.return_format.include?('%')
- puts @context.return_format
- return
- end
-
- winheight, winwidth = @context.io.winsize
- if omit
- content, overflow = Pager.take_first_page(winwidth, 1) do |out|
- @context.inspect_last_value(out)
- end
- if overflow
- content = "\n#{content}" if @context.newline_before_multiline_output?
- content = "#{content}..."
- content = "#{content}\e[0m" if Color.colorable?
- end
- puts format(@context.return_format, content.chomp)
- elsif Pager.should_page? && @context.inspector_support_stream_output?
- formatter_proc = ->(content, multipage) do
- content = content.chomp
- content = "\n#{content}" if @context.newline_before_multiline_output? && (multipage || content.include?("\n"))
- format(@context.return_format, content)
- end
- Pager.page_with_preview(winwidth, winheight, formatter_proc) do |out|
- @context.inspect_last_value(out)
- end
- else
- content = @context.inspect_last_value.chomp
- content = "\n#{content}" if @context.newline_before_multiline_output? && content.include?("\n")
- Pager.page_content(format(@context.return_format, content), retain_content: true)
- end
- end
-
- # Outputs the local variables to this current session, including #signal_status
- # and #context, using IRB::Locale.
- def inspect
- ary = []
- for iv in instance_variables
- case (iv = iv.to_s)
- when "@signal_status"
- ary.push format("%s=:%s", iv, @signal_status.id2name)
- when "@context"
- ary.push format("%s=%s", iv, eval(iv).__to_s__)
- else
- ary.push format("%s=%s", iv, eval(iv))
- end
- end
- format("#<%s: %s>", self.class, ary.join(", "))
- end
-
- private
-
- def generate_prompt(opens, continue, line_offset)
- ltype = @scanner.ltype_from_open_tokens(opens)
- indent = @scanner.calc_indent_level(opens)
- continue = opens.any? || continue
- line_no = @line_no + line_offset
-
- if ltype
- f = @context.prompt_s
- elsif continue
- f = @context.prompt_c
- else
- f = @context.prompt_i
- end
- f = "" unless f
- if @context.prompting?
- p = format_prompt(f, ltype, indent, line_no)
- else
- p = ""
- end
- if @context.auto_indent_mode and [email protected]_to?(:auto_indent)
- unless ltype
- prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
- ind = format_prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
- indent * 2 - p.size
- p += " " * ind if ind > 0
- end
- end
- p
- end
-
- def truncate_prompt_main(str) # :nodoc:
- str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
- if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
- str
- else
- str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
- end
- end
-
- def format_prompt(format, ltype, indent, line_no) # :nodoc:
- format.gsub(/%([0-9]+)?([a-zA-Z%])/) do
- case $2
- when "N"
- @context.irb_name
- when "m"
- main_str = @context.safe_method_call_on_main(:to_s) rescue "!#{$!.class}"
- truncate_prompt_main(main_str)
- when "M"
- main_str = @context.safe_method_call_on_main(:inspect) rescue "!#{$!.class}"
- truncate_prompt_main(main_str)
- when "l"
- ltype
- when "i"
- if indent < 0
- if $1
- "-".rjust($1.to_i)
- else
- "-"
- end
- else
- if $1
- format("%" + $1 + "d", indent)
- else
- indent.to_s
- end
- end
- when "n"
- if $1
- format("%" + $1 + "d", line_no)
- else
- line_no.to_s
- end
- when "%"
- "%" unless $1
- end
- end
- end
- end
-end
-
-class Binding
- # Opens an IRB session where `binding.irb` is called which allows for
- # interactive debugging. You can call any methods or variables available in the
- # current scope, and mutate state if you need to.
- #
- # Given a Ruby file called `potato.rb` containing the following code:
- #
- # class Potato
- # def initialize
- # @cooked = false
- # binding.irb
- # puts "Cooked potato: #{@cooked}"
- # end
- # end
- #
- # Potato.new
- #
- # Running `ruby potato.rb` will open an IRB session where `binding.irb` is
- # called, and you will see the following:
- #
- # $ ruby potato.rb
- #
- # From: potato.rb @ line 4 :
- #
- # 1: class Potato
- # 2: def initialize
- # 3: @cooked = false
- # => 4: binding.irb
- # 5: puts "Cooked potato: #{@cooked}"
- # 6: end
- # 7: end
- # 8:
- # 9: Potato.new
- #
- # irb(#<Potato:0x00007feea1916670>):001:0>
- #
- # You can type any valid Ruby code and it will be evaluated in the current
- # context. This allows you to debug without having to run your code repeatedly:
- #
- # irb(#<Potato:0x00007feea1916670>):001:0> @cooked
- # => false
- # irb(#<Potato:0x00007feea1916670>):002:0> self.class
- # => Potato
- # irb(#<Potato:0x00007feea1916670>):003:0> caller.first
- # => ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'"
- # irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
- # => true
- #
- # You can exit the IRB session with the `exit` command. Note that exiting will
- # resume execution where `binding.irb` had paused it, as you can see from the
- # output printed to standard output in this example:
- #
- # irb(#<Potato:0x00007feea1916670>):005:0> exit
- # Cooked potato: true
- #
- # See IRB for more information.
- def irb(show_code: true)
- # Setup IRB with the current file's path and no command line arguments
- IRB.setup(source_location[0], argv: []) unless IRB.initialized?
- # Create a new workspace using the current binding
- workspace = IRB::WorkSpace.new(self)
- # Print the code around the binding if show_code is true
- STDOUT.print(workspace.code_around_binding) if show_code
- # Get the original IRB instance
- debugger_irb = IRB.instance_variable_get(:@debugger_irb)
-
- irb_path = File.expand_path(source_location[0])
-
- if debugger_irb
- # If we're already in a debugger session, set the workspace and irb_path for the original IRB instance
- debugger_irb.context.replace_workspace(workspace)
- debugger_irb.context.irb_path = irb_path
- # If we've started a debugger session and hit another binding.irb, we don't want
- # to start an IRB session instead, we want to resume the irb:rdbg session.
- IRB::Debug.setup(debugger_irb)
- IRB::Debug.insert_debug_break
- debugger_irb.debug_break
- else
- # If we're not in a debugger session, create a new IRB instance with the current
- # workspace
- binding_irb = IRB::Irb.new(workspace, from_binding: true)
- binding_irb.context.irb_path = irb_path
- binding_irb.run(IRB.conf)
- binding_irb.debug_break
- end
- end
-end
diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb
deleted file mode 100644
index 9d2e3c4d47..0000000000
--- a/lib/irb/cmd/nop.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-
-# This file is just a placeholder for backward-compatibility.
-# Please require 'irb' and inherit your command from `IRB::Command::Base` instead.
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
deleted file mode 100644
index a7e311087a..0000000000
--- a/lib/irb/color.rb
+++ /dev/null
@@ -1,263 +0,0 @@
-# frozen_string_literal: true
-require 'reline'
-require 'ripper'
-require_relative 'ruby-lex'
-
-module IRB # :nodoc:
- module Color
- CLEAR = 0
- BOLD = 1
- UNDERLINE = 4
- REVERSE = 7
- BLACK = 30
- RED = 31
- GREEN = 32
- YELLOW = 33
- BLUE = 34
- MAGENTA = 35
- CYAN = 36
- WHITE = 37
-
- TOKEN_KEYWORDS = {
- on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__', '__ENCODING__'],
- on_const: ['ENV'],
- }
- private_constant :TOKEN_KEYWORDS
-
- # A constant of all-bit 1 to match any Ripper's state in #dispatch_seq
- ALL = -1
- private_constant :ALL
-
- begin
- # Following pry's colors where possible, but sometimes having a compromise like making
- # backtick and regexp as red (string's color, because they're sharing tokens).
- TOKEN_SEQ_EXPRS = {
- on_CHAR: [[BLUE, BOLD], ALL],
- on_backtick: [[RED, BOLD], ALL],
- on_comment: [[BLUE, BOLD], ALL],
- on_const: [[BLUE, BOLD, UNDERLINE], ALL],
- on_embexpr_beg: [[RED], ALL],
- on_embexpr_end: [[RED], ALL],
- on_embvar: [[RED], ALL],
- on_float: [[MAGENTA, BOLD], ALL],
- on_gvar: [[GREEN, BOLD], ALL],
- on_backref: [[GREEN, BOLD], ALL],
- on_heredoc_beg: [[RED], ALL],
- on_heredoc_end: [[RED], ALL],
- on_ident: [[BLUE, BOLD], Ripper::EXPR_ENDFN],
- on_imaginary: [[BLUE, BOLD], ALL],
- on_int: [[BLUE, BOLD], ALL],
- on_kw: [[GREEN], ALL],
- on_label: [[MAGENTA], ALL],
- on_label_end: [[RED, BOLD], ALL],
- on_qsymbols_beg: [[RED, BOLD], ALL],
- on_qwords_beg: [[RED, BOLD], ALL],
- on_rational: [[BLUE, BOLD], ALL],
- on_regexp_beg: [[RED, BOLD], ALL],
- on_regexp_end: [[RED, BOLD], ALL],
- on_symbeg: [[YELLOW], ALL],
- on_symbols_beg: [[RED, BOLD], ALL],
- on_tstring_beg: [[RED, BOLD], ALL],
- on_tstring_content: [[RED], ALL],
- on_tstring_end: [[RED, BOLD], ALL],
- on_words_beg: [[RED, BOLD], ALL],
- on_parse_error: [[RED, REVERSE], ALL],
- compile_error: [[RED, REVERSE], ALL],
- on_assign_error: [[RED, REVERSE], ALL],
- on_alias_error: [[RED, REVERSE], ALL],
- on_class_name_error:[[RED, REVERSE], ALL],
- on_param_error: [[RED, REVERSE], ALL],
- on___end__: [[GREEN], ALL],
- }
- rescue NameError
- # Give up highlighting Ripper-incompatible older Ruby
- TOKEN_SEQ_EXPRS = {}
- end
- private_constant :TOKEN_SEQ_EXPRS
-
- ERROR_TOKENS = TOKEN_SEQ_EXPRS.keys.select { |k| k.to_s.end_with?('error') }
- private_constant :ERROR_TOKENS
-
- class << self
- def colorable?
- supported = $stdout.tty? && (/mswin|mingw/.match?(RUBY_PLATFORM) || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
-
- # because ruby/debug also uses irb's color module selectively,
- # irb won't be activated in that case.
- if IRB.respond_to?(:conf)
- supported && !!IRB.conf.fetch(:USE_COLORIZE, true)
- else
- supported
- end
- end
-
- def inspect_colorable?(obj, seen: {}.compare_by_identity)
- case obj
- when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass
- true
- when Hash
- without_circular_ref(obj, seen: seen) do
- obj.all? { |k, v| inspect_colorable?(k, seen: seen) && inspect_colorable?(v, seen: seen) }
- end
- when Array
- without_circular_ref(obj, seen: seen) do
- obj.all? { |o| inspect_colorable?(o, seen: seen) }
- end
- when Range
- inspect_colorable?(obj.begin, seen: seen) && inspect_colorable?(obj.end, seen: seen)
- when Module
- !obj.name.nil?
- else
- false
- end
- end
-
- def clear(colorable: colorable?)
- return '' unless colorable
- "\e[#{CLEAR}m"
- end
-
- def colorize(text, seq, colorable: colorable?)
- return text unless colorable
- seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('')
- "#{seq}#{text}#{clear(colorable: colorable)}"
- end
-
- # If `complete` is false (code is incomplete), this does not warn compile_error.
- # This option is needed to avoid warning a user when the compile_error is happening
- # because the input is not wrong but just incomplete.
- def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?, local_variables: [])
- return code unless colorable
-
- symbol_state = SymbolState.new
- colored = +''
- lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
- code_with_lvars = lvars_code ? "#{lvars_code}\n#{code}" : code
-
- scan(code_with_lvars, allow_last_error: !complete) do |token, str, expr|
- # handle uncolorable code
- if token.nil?
- colored << Reline::Unicode.escape_for_print(str)
- next
- end
-
- # IRB::ColorPrinter skips colorizing fragments with any invalid token
- if ignore_error && ERROR_TOKENS.include?(token)
- return Reline::Unicode.escape_for_print(code)
- end
-
- in_symbol = symbol_state.scan_token(token)
- str.each_line do |line|
- line = Reline::Unicode.escape_for_print(line)
- if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol)
- colored << seq.map { |s| "\e[#{s}m" }.join('')
- colored << line.sub(/\Z/, clear(colorable: colorable))
- else
- colored << line
- end
- end
- end
-
- if lvars_code
- raise "#{lvars_code.dump} should have no \\n" if lvars_code.include?("\n")
- colored.sub!(/\A.+\n/, '') # delete_prefix lvars_code with colors
- end
- colored
- end
-
- private
-
- def without_circular_ref(obj, seen:, &block)
- return false if seen.key?(obj)
- seen[obj] = true
- block.call
- ensure
- seen.delete(obj)
- end
-
- def scan(code, allow_last_error:)
- verbose, $VERBOSE = $VERBOSE, nil
- RubyLex.compile_with_errors_suppressed(code) do |inner_code, line_no|
- lexer = Ripper::Lexer.new(inner_code, '(ripper)', line_no)
- byte_pos = 0
- line_positions = [0]
- inner_code.lines.each do |line|
- line_positions << line_positions.last + line.bytesize
- end
-
- on_scan = proc do |elem|
- start_pos = line_positions[elem.pos[0] - 1] + elem.pos[1]
-
- # yield uncolorable code
- if byte_pos < start_pos
- yield(nil, inner_code.byteslice(byte_pos...start_pos), nil)
- end
-
- if byte_pos <= start_pos
- str = elem.tok
- yield(elem.event, str, elem.state)
- byte_pos = start_pos + str.bytesize
- end
- end
-
- lexer.scan.each do |elem|
- next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
- on_scan.call(elem)
- end
- # yield uncolorable DATA section
- yield(nil, inner_code.byteslice(byte_pos...inner_code.bytesize), nil) if byte_pos < inner_code.bytesize
- end
- ensure
- $VERBOSE = verbose
- end
-
- def dispatch_seq(token, expr, str, in_symbol:)
- if ERROR_TOKENS.include?(token)
- TOKEN_SEQ_EXPRS[token][0]
- elsif in_symbol
- [YELLOW]
- elsif TOKEN_KEYWORDS.fetch(token, []).include?(str)
- [CYAN, BOLD]
- elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; (expr & (exprs || 0)) != 0)
- seq
- else
- nil
- end
- end
- end
-
- # A class to manage a state to know whether the current token is for Symbol or not.
- class SymbolState
- def initialize
- # Push `true` to detect Symbol. `false` to increase the nest level for non-Symbol.
- @stack = []
- end
-
- # Return true if the token is a part of Symbol.
- def scan_token(token)
- prev_state = @stack.last
- case token
- when :on_symbeg, :on_symbols_beg, :on_qsymbols_beg
- @stack << true
- when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw, :on_backtick
- if @stack.last # Pop only when it's Symbol
- @stack.pop
- return prev_state
- end
- when :on_tstring_beg
- @stack << false
- when :on_embexpr_beg
- @stack << false
- return prev_state
- when :on_tstring_end # :on_tstring_end may close Symbol
- @stack.pop
- return prev_state
- when :on_embexpr_end
- @stack.pop
- end
- @stack.last
- end
- end
- private_constant :SymbolState
- end
-end
diff --git a/lib/irb/color_printer.rb b/lib/irb/color_printer.rb
deleted file mode 100644
index 7a7e817858..0000000000
--- a/lib/irb/color_printer.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-require 'pp'
-require_relative 'color'
-
-module IRB
- class ColorPrinter < ::PP
- class << self
- def pp(obj, out = $>, width = screen_width, colorize: true)
- q = ColorPrinter.new(out, width, colorize: colorize)
- q.guard_inspect_key {q.pp obj}
- q.flush
- out << "\n"
- end
-
- private
-
- def screen_width
- Reline.get_screen_size.last
- rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
- 79
- end
- end
-
- def initialize(out, width, colorize: true)
- @colorize = colorize
-
- super(out, width)
- end
-
- def pp(obj)
- if String === obj
- # Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
- text(obj.inspect)
- else
- super
- end
- end
-
- def text(str, width = nil)
- unless str.is_a?(String)
- str = str.inspect
- end
- width ||= str.length
-
- case str
- when ''
- when ',', '=>', '[', ']', '{', '}', '..', '...', /\A@\w+\z/
- super(str, width)
- when /\A#</, '=', '>'
- super(@colorize ? Color.colorize(str, [:GREEN]) : str, width)
- else
- super(@colorize ? Color.colorize_code(str, ignore_error: true) : str, width)
- end
- end
- end
-end
diff --git a/lib/irb/command.rb b/lib/irb/command.rb
deleted file mode 100644
index 68a4b52727..0000000000
--- a/lib/irb/command.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/command.rb - irb command
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative "command/base"
-
-module IRB # :nodoc:
- module Command
- @commands = {}
-
- class << self
- attr_reader :commands
-
- # Registers a command with the given name.
- # Aliasing is intentionally not supported at the moment.
- def register(name, command_class)
- @commands[name.to_sym] = [command_class, []]
- end
- end
- end
-end
diff --git a/lib/irb/command/backtrace.rb b/lib/irb/command/backtrace.rb
deleted file mode 100644
index 687bb075ac..0000000000
--- a/lib/irb/command/backtrace.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Backtrace < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "backtrace #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/base.rb b/lib/irb/command/base.rb
deleted file mode 100644
index 2f39b75cca..0000000000
--- a/lib/irb/command/base.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-#
-# nop.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- module Command
- class CommandArgumentError < StandardError; end # :nodoc:
-
- class << self
- def extract_ruby_args(*args, **kwargs) # :nodoc:
- throw :EXTRACT_RUBY_ARGS, [args, kwargs]
- end
- end
-
- class Base
- class << self
- def category(category = nil)
- @category = category if category
- @category || "No category"
- end
-
- def description(description = nil)
- @description = description if description
- @description || "No description provided."
- end
-
- def help_message(help_message = nil)
- @help_message = help_message if help_message
- @help_message
- end
-
- def execute(irb_context, arg)
- new(irb_context).execute(arg)
- rescue CommandArgumentError => e
- puts e.message
- end
-
- private
-
- def highlight(text)
- Color.colorize(text, [:BOLD, :BLUE])
- end
- end
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- attr_reader :irb_context
-
- def execute(arg)
- #nop
- end
- end
-
- Nop = Base # :nodoc:
- end
-end
diff --git a/lib/irb/command/break.rb b/lib/irb/command/break.rb
deleted file mode 100644
index a8f81fe665..0000000000
--- a/lib/irb/command/break.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Break < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "break #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/catch.rb b/lib/irb/command/catch.rb
deleted file mode 100644
index 529dcbca5a..0000000000
--- a/lib/irb/command/catch.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Catch < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "catch #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/cd.rb b/lib/irb/command/cd.rb
deleted file mode 100644
index b83c8689ae..0000000000
--- a/lib/irb/command/cd.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class CD < Base
- category "Workspace"
- description "Move into the given object or leave the current context."
-
- help_message(<<~HELP)
- Usage: cd ([target]|..)
-
- IRB uses a stack of workspaces to keep track of context(s), with `pushws` and `popws` commands to manipulate the stack.
- The `cd` command is an attempt to simplify the operation and will be subject to change.
-
- When given:
- - an object, cd will use that object as the new context by pushing it onto the workspace stack.
- - "..", cd will leave the current context by popping the top workspace off the stack.
- - no arguments, cd will move to the top workspace on the stack by popping off all workspaces.
-
- Examples:
-
- cd Foo
- cd Foo.new
- cd @ivar
- cd ..
- cd
- HELP
-
- def execute(arg)
- case arg
- when ".."
- irb_context.pop_workspace
- when ""
- # TODO: decide what workspace commands should be kept, and underlying APIs should look like,
- # and perhaps add a new API to clear the workspace stack.
- prev_workspace = irb_context.pop_workspace
- while prev_workspace
- prev_workspace = irb_context.pop_workspace
- end
- else
- begin
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.push_workspace(obj)
- rescue StandardError => e
- warn "Error: #{e}"
- end
- end
- end
- end
- end
-end
diff --git a/lib/irb/command/chws.rb b/lib/irb/command/chws.rb
deleted file mode 100644
index ef456d0961..0000000000
--- a/lib/irb/command/chws.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-#
-# change-ws.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-require_relative "../ext/change-ws"
-
-module IRB
- # :stopdoc:
-
- module Command
-
- class CurrentWorkingWorkspace < Base
- category "Workspace"
- description "Show the current workspace."
-
- def execute(_arg)
- puts "Current workspace: #{irb_context.main}"
- end
- end
-
- class ChangeWorkspace < Base
- category "Workspace"
- description "Change the current workspace to an object."
-
- def execute(arg)
- if arg.empty?
- irb_context.change_workspace
- else
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.change_workspace(obj)
- end
-
- puts "Current workspace: #{irb_context.main}"
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/context.rb b/lib/irb/command/context.rb
deleted file mode 100644
index b4fc807343..0000000000
--- a/lib/irb/command/context.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Context < Base
- category "IRB"
- description "Displays current configuration."
-
- def execute(_arg)
- # This command just displays the configuration.
- # Modifying the configuration is achieved by sending a message to IRB.conf.
- Pager.page_content(IRB.CurrentContext.inspect)
- end
- end
- end
-end
diff --git a/lib/irb/command/continue.rb b/lib/irb/command/continue.rb
deleted file mode 100644
index 0daa029b15..0000000000
--- a/lib/irb/command/continue.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Continue < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "continue #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/copy.rb b/lib/irb/command/copy.rb
deleted file mode 100644
index 93410b878a..0000000000
--- a/lib/irb/command/copy.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Copy < Base
- category "Misc"
- description "Copy expression output to clipboard"
-
- help_message(<<~HELP)
- Usage: copy ([expression])
-
- When given:
- - an expression, copy the inspect result of the expression to the clipboard.
- - no arguments, copy the last evaluated result (`_`) to the clipboard.
-
- Examples:
-
- copy Foo.new
- copy User.all.to_a
- copy
- HELP
-
- def execute(arg)
- # Copy last value if no expression was supplied
- arg = '_' if arg.to_s.strip.empty?
-
- value = irb_context.workspace.binding.eval(arg)
- output = irb_context.inspect_method.inspect_value(value, +'', colorize: false).chomp
-
- if clipboard_available?
- copy_to_clipboard(output)
- else
- warn "System clipboard not found"
- end
- rescue StandardError => e
- warn "Error: #{e}"
- end
-
- private
-
- def copy_to_clipboard(text)
- IO.popen(clipboard_program, 'w') do |io|
- io.write(text)
- end
-
- raise IOError.new("Copying to clipboard failed") unless $? == 0
-
- puts "Copied to system clipboard"
- rescue Errno::ENOENT => e
- warn e.message
- warn "Is IRB.conf[:COPY_COMMAND] set to a bad value?"
- end
-
- def clipboard_program
- @clipboard_program ||= if IRB.conf[:COPY_COMMAND]
- IRB.conf[:COPY_COMMAND]
- elsif executable?("pbcopy")
- "pbcopy"
- elsif executable?("xclip")
- "xclip -selection clipboard"
- end
- end
-
- def executable?(command)
- system("which #{command} > /dev/null 2>&1")
- end
-
- def clipboard_available?
- !!clipboard_program
- end
- end
- end
-end
diff --git a/lib/irb/command/debug.rb b/lib/irb/command/debug.rb
deleted file mode 100644
index 3ebb57fe54..0000000000
--- a/lib/irb/command/debug.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-require_relative "../debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Debug < Base
- category "Debugging"
- description "Start the debugger of debug.gem."
-
- def execute(_arg)
- execute_debug_command
- end
-
- def execute_debug_command(pre_cmds: nil, do_cmds: nil)
- pre_cmds = pre_cmds&.rstrip
- do_cmds = do_cmds&.rstrip
-
- if irb_context.with_debugger
- # If IRB is already running with a debug session, throw the command and IRB.debug_readline will pass it to the debugger.
- if cmd = pre_cmds || do_cmds
- throw :IRB_EXIT, cmd
- else
- puts "IRB is already running with a debug session."
- return
- end
- else
- # If IRB is not running with a debug session yet, then:
- # 1. Check if the debugging command is run from a `binding.irb` call.
- # 2. If so, try setting up the debug gem.
- # 3. Insert a debug breakpoint at `Irb#debug_break` with the intended command.
- # 4. Exit the current Irb#run call via `throw :IRB_EXIT`.
- # 5. `Irb#debug_break` will be called and trigger the breakpoint, which will run the intended command.
- unless irb_context.from_binding?
- puts "Debugging commands are only available when IRB is started with binding.irb"
- return
- end
-
- if IRB.respond_to?(:JobManager)
- warn "Can't start the debugger when IRB is running in a multi-IRB session."
- return
- end
-
- unless IRB::Debug.setup(irb_context.irb)
- puts <<~MSG
- You need to install the debug gem before using this command.
- If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
- MSG
- return
- end
-
- IRB::Debug.insert_debug_break(pre_cmds: pre_cmds, do_cmds: do_cmds)
-
- # exit current Irb#run call
- throw :IRB_EXIT
- end
- end
- end
-
- class DebugCommand < Debug
- class << self
- def category
- "Debugging"
- end
-
- def description
- command_name = self.name.split("::").last.downcase
- "Start the debugger of debug.gem and run its `#{command_name}` command."
- end
- end
- end
- end
-end
diff --git a/lib/irb/command/delete.rb b/lib/irb/command/delete.rb
deleted file mode 100644
index 2a57a4a3de..0000000000
--- a/lib/irb/command/delete.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Delete < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "delete #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/disable_irb.rb b/lib/irb/command/disable_irb.rb
deleted file mode 100644
index 0b00d0302b..0000000000
--- a/lib/irb/command/disable_irb.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class DisableIrb < Base
- category "IRB"
- description "Disable binding.irb."
-
- def execute(*)
- ::Binding.define_method(:irb) {}
- IRB.irb_exit
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/edit.rb b/lib/irb/command/edit.rb
deleted file mode 100644
index cb7e0c4873..0000000000
--- a/lib/irb/command/edit.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'shellwords'
-
-require_relative "../color"
-require_relative "../source_finder"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Edit < Base
- include RubyArgsExtractor
-
- category "Misc"
- description 'Open a file or source location.'
- help_message <<~HELP_MESSAGE
- Usage: edit [FILE or constant or method signature]
-
- Open a file in the editor specified in #{highlight('ENV["VISUAL"]')} or #{highlight('ENV["EDITOR"]')}
-
- - If no arguments are provided, IRB will attempt to open the file the current context was defined in.
- - If FILE is provided, IRB will open the file.
- - If a constant or method signature is provided, IRB will attempt to locate the source file and open it.
-
- Examples:
-
- edit
- edit foo.rb
- edit Foo
- edit Foo#bar
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- path = unwrap_string_literal(arg)
-
- if path.nil?
- path = @irb_context.irb_path
- elsif !File.exist?(path)
- source = SourceFinder.new(@irb_context).find_source(path)
-
- if source&.file_exist? && !source.binary_file?
- path = source.file
- end
- end
-
- unless File.exist?(path)
- puts "Can not find file: #{path}"
- return
- end
-
- if editor = (ENV['VISUAL'] || ENV['EDITOR'])
- puts "command: '#{editor}'"
- puts " path: #{path}"
- system(*Shellwords.split(editor), path)
- else
- puts "Can not find editor setting: ENV['VISUAL'] or ENV['EDITOR']"
- end
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/exit.rb b/lib/irb/command/exit.rb
deleted file mode 100644
index b4436f0343..0000000000
--- a/lib/irb/command/exit.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class Exit < Base
- category "IRB"
- description "Exit the current irb session."
-
- def execute(_arg)
- IRB.irb_exit
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/finish.rb b/lib/irb/command/finish.rb
deleted file mode 100644
index 3311a0e6e9..0000000000
--- a/lib/irb/command/finish.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Finish < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "finish #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/force_exit.rb b/lib/irb/command/force_exit.rb
deleted file mode 100644
index 14086aa849..0000000000
--- a/lib/irb/command/force_exit.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class ForceExit < Base
- category "IRB"
- description "Exit the current process."
-
- def execute(_arg)
- throw :IRB_EXIT, true
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/help.rb b/lib/irb/command/help.rb
deleted file mode 100644
index 12b468fefc..0000000000
--- a/lib/irb/command/help.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Help < Base
- category "Help"
- description "List all available commands. Use `help <command>` to get information about a specific command."
-
- def execute(command_name)
- content =
- if command_name.empty?
- help_message
- else
- if command_class = Command.load_command(command_name)
- command_class.help_message || command_class.description
- else
- "Can't find command `#{command_name}`. Please check the command name and try again.\n\n"
- end
- end
- Pager.page_content(content)
- end
-
- private
-
- def help_message
- commands_info = IRB::Command.all_commands_info
- helper_methods_info = IRB::HelperMethod.all_helper_methods_info
- commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
- commands_grouped_by_categories["Helper methods"] = helper_methods_info
-
- if irb_context.with_debugger
- # Remove the original "Debugging" category
- commands_grouped_by_categories.delete("Debugging")
- end
-
- longest_cmd_name_length = commands_info.map { |c| c[:display_name].length }.max
-
- output = StringIO.new
-
- help_cmds = commands_grouped_by_categories.delete("Help")
- no_category_cmds = commands_grouped_by_categories.delete("No category")
- aliases = irb_context.instance_variable_get(:@command_aliases).map do |alias_name, target|
- { display_name: alias_name, description: "Alias for `#{target}`" }
- end
-
- # Display help commands first
- add_category_to_output("Help", help_cmds, output, longest_cmd_name_length)
-
- # Display the rest of the commands grouped by categories
- commands_grouped_by_categories.each do |category, cmds|
- add_category_to_output(category, cmds, output, longest_cmd_name_length)
- end
-
- # Display commands without a category
- if no_category_cmds
- add_category_to_output("No category", no_category_cmds, output, longest_cmd_name_length)
- end
-
- # Display aliases
- add_category_to_output("Aliases", aliases, output, longest_cmd_name_length)
-
- # Append the debugger help at the end
- if irb_context.with_debugger
- # Add "Debugging (from debug.gem)" category as title
- add_category_to_output("Debugging (from debug.gem)", [], output, longest_cmd_name_length)
- output.puts DEBUGGER__.help
- end
-
- output.string
- end
-
- def add_category_to_output(category, cmds, output, longest_cmd_name_length)
- output.puts Color.colorize(category, [:BOLD])
-
- cmds.each do |cmd|
- output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
- end
-
- output.puts
- end
- end
- end
-end
diff --git a/lib/irb/command/history.rb b/lib/irb/command/history.rb
deleted file mode 100644
index e385c66102..0000000000
--- a/lib/irb/command/history.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require "stringio"
-
-require_relative "../pager"
-
-module IRB
- # :stopdoc:
-
- module Command
- class History < Base
- category "IRB"
- description "Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output."
-
- def execute(arg)
-
- if (match = arg&.match(/(-g|-G)\s+(?<grep>.+)\s*\z/))
- grep = Regexp.new(match[:grep])
- end
-
- formatted_inputs = irb_context.io.class::HISTORY.each_with_index.reverse_each.filter_map do |input, index|
- next if grep && !input.match?(grep)
-
- header = "#{index}: "
-
- first_line, *other_lines = input.split("\n")
- first_line = "#{header}#{first_line}"
-
- truncated_lines = other_lines.slice!(1..) # Show 1 additional line (2 total)
- other_lines << "..." if truncated_lines&.any?
-
- other_lines.map! do |line|
- " " * header.length + line
- end
-
- [first_line, *other_lines].join("\n") + "\n"
- end
-
- Pager.page_content(formatted_inputs.join)
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/info.rb b/lib/irb/command/info.rb
deleted file mode 100644
index d08ce00a32..0000000000
--- a/lib/irb/command/info.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Info < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "info #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/internal_helpers.rb b/lib/irb/command/internal_helpers.rb
deleted file mode 100644
index a01ddb1d45..0000000000
--- a/lib/irb/command/internal_helpers.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- # Internal use only, for default command's backward compatibility.
- module RubyArgsExtractor # :nodoc:
- def unwrap_string_literal(str)
- return if str.empty?
-
- sexp = Ripper.sexp(str)
- if sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
- @irb_context.workspace.binding.eval(str).to_s
- else
- str
- end
- end
-
- def ruby_args(arg)
- # Use throw and catch to handle arg that includes `;`
- # For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
- catch(:EXTRACT_RUBY_ARGS) do
- @irb_context.workspace.binding.eval "::IRB::Command.extract_ruby_args #{arg}"
- end || [[], {}]
- end
- end
- end
-end
diff --git a/lib/irb/command/irb_info.rb b/lib/irb/command/irb_info.rb
deleted file mode 100644
index 6d868de94c..0000000000
--- a/lib/irb/command/irb_info.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class IrbInfo < Base
- category "IRB"
- description "Show information about IRB."
-
- def execute(_arg)
- str = "Ruby version: #{RUBY_VERSION}\n"
- str += "IRB version: #{IRB.version}\n"
- str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
- str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n"
- rc_files = IRB.irbrc_files
- str += ".irbrc paths: #{rc_files.join(", ")}\n" if rc_files.any?
- str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
- str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
- str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
- str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
- str += "Code page: #{codepage}\n"
- end
- puts str
- nil
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/load.rb b/lib/irb/command/load.rb
deleted file mode 100644
index 1cd3f279d1..0000000000
--- a/lib/irb/command/load.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-#
-# load.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-require_relative "../ext/loader"
-
-module IRB
- # :stopdoc:
-
- module Command
- class LoaderCommand < Base
- include RubyArgsExtractor
- include IrbLoader
-
- def raise_cmd_argument_error
- raise CommandArgumentError.new("Please specify the file name.")
- end
- end
-
- class Load < LoaderCommand
- category "IRB"
- description "Load a Ruby file."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil, priv = nil)
- raise_cmd_argument_error unless file_name
- irb_load(file_name, priv)
- end
- end
-
- class Require < LoaderCommand
- category "IRB"
- description "Require a Ruby file."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil)
- raise_cmd_argument_error unless file_name
-
- rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
- return false if $".find{|f| f =~ rex}
-
- case file_name
- when /\.rb$/
- begin
- if irb_load(file_name)
- $".push file_name
- return true
- end
- rescue LoadError
- end
- when /\.(so|o|sl)$/
- return ruby_require(file_name)
- end
-
- begin
- irb_load(f = file_name + ".rb")
- $".push f
- return true
- rescue LoadError
- return ruby_require(file_name)
- end
- end
- end
-
- class Source < LoaderCommand
- category "IRB"
- description "Loads a given file in the current session."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil)
- raise_cmd_argument_error unless file_name
-
- source_file(file_name)
- end
- end
- end
- # :startdoc:
-end
diff --git a/lib/irb/command/ls.rb b/lib/irb/command/ls.rb
deleted file mode 100644
index 944efd7570..0000000000
--- a/lib/irb/command/ls.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-# frozen_string_literal: true
-
-require "reline"
-require "stringio"
-
-require_relative "../pager"
-require_relative "../color"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Ls < Base
- class EvaluationError < StandardError; end
-
- category "Context"
- description "Show methods, constants, and variables."
-
- help_message <<~HELP_MESSAGE
- Usage: ls [obj] [-g [query]]
-
- -g [query] Filter the output with a query.
- HELP_MESSAGE
-
- def evaluate(code)
- @irb_context.workspace.binding.eval(code)
- rescue Exception => e
- puts "#{e.class}: #{e.message}"
- raise EvaluationError
- end
-
- def execute(arg)
- if match = arg.match(/\A(?<target>.+\s|)(-g|-G)\s+(?<grep>.+)$/)
- target = match[:target]
- grep = Regexp.new(match[:grep])
- elsif match = arg.match(/\A((?<target>.+),|)\s*grep:(?<grep>.+)/)
- # Legacy style `ls obj, grep: /regexp/`
- # Evaluation order should be eval(target) then eval(grep)
- target = match[:target] || ''
- grep_regexp_code = match[:grep]
- else
- target = arg.strip
- end
-
- if target.empty?
- obj = irb_context.workspace.main
- locals = irb_context.workspace.binding.local_variables
- else
- obj = evaluate(target)
- end
-
- if grep_regexp_code
- grep = evaluate(grep_regexp_code)
- end
-
- o = Output.new(grep: grep)
-
- klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
-
- o.dump("constants", obj.constants) if obj.respond_to?(:constants)
- dump_methods(o, klass, obj)
- o.dump("instance variables", obj.instance_variables)
- o.dump("class variables", klass.class_variables)
- o.dump("locals", locals) if locals
- o.print_result
- rescue EvaluationError
- end
-
- def dump_methods(o, klass, obj)
- singleton_class = begin obj.singleton_class; rescue TypeError; nil end
- dumped_mods = Array.new
- ancestors = klass.ancestors
- ancestors = ancestors.reject { |c| c >= Object } if klass < Object
- singleton_ancestors = (singleton_class&.ancestors || []).reject { |c| c >= Class }
-
- # singleton_class' ancestors should be at the front
- maps = class_method_map(singleton_ancestors, dumped_mods) + class_method_map(ancestors, dumped_mods)
- maps.each do |mod, methods|
- name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
- o.dump(name, methods)
- end
- end
-
- def class_method_map(classes, dumped_mods)
- dumped_methods = Array.new
- classes.map do |mod|
- next if dumped_mods.include? mod
-
- dumped_mods << mod
-
- methods = mod.public_instance_methods(false).select do |method|
- if dumped_methods.include? method
- false
- else
- dumped_methods << method
- true
- end
- end
-
- [mod, methods]
- end.compact
- end
-
- class Output
- MARGIN = " "
-
- def initialize(grep: nil)
- @grep = grep
- @line_width = screen_width - MARGIN.length # right padding
- @io = StringIO.new
- end
-
- def print_result
- Pager.page_content(@io.string)
- end
-
- def dump(name, strs)
- strs = strs.grep(@grep) if @grep
- strs = strs.sort
- return if strs.empty?
-
- # Attempt a single line
- @io.print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
- if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
- @io.puts strs.join(MARGIN)
- return
- end
- @io.puts
-
- # Dump with the largest # of columns that fits on a line
- cols = strs.size
- until fits_on_line?(strs, cols: cols, offset: MARGIN.length) || cols == 1
- cols -= 1
- end
- widths = col_widths(strs, cols: cols)
- strs.each_slice(cols) do |ss|
- @io.puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
- end
- end
-
- private
-
- def fits_on_line?(strs, cols:, offset: 0)
- width = col_widths(strs, cols: cols).sum + MARGIN.length * (cols - 1)
- width <= @line_width - offset
- end
-
- def col_widths(strs, cols:)
- cols.times.map do |col|
- (col...strs.size).step(cols).map do |i|
- strs[i].length
- end.max
- end
- end
-
- def screen_width
- Reline.get_screen_size.last
- rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
- 80
- end
- end
- private_constant :Output
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/measure.rb b/lib/irb/command/measure.rb
deleted file mode 100644
index f96be20de8..0000000000
--- a/lib/irb/command/measure.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-module IRB
- # :stopdoc:
-
- module Command
- class Measure < Base
- include RubyArgsExtractor
-
- category "Misc"
- description "`measure` enables the mode to measure processing time. `measure :off` disables it."
-
- def initialize(*args)
- super(*args)
- end
-
- def execute(arg)
- if arg&.match?(/^do$|^do[^\w]|^\{/)
- warn 'Configure IRB.conf[:MEASURE_PROC] to add custom measure methods.'
- return
- end
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(type = nil, arg = nil)
- # Please check IRB.init_config in lib/irb/init.rb that sets
- # IRB.conf[:MEASURE_PROC] to register default "measure" methods,
- # "measure :time" (abbreviated as "measure") and "measure :stackprof".
-
- case type
- when :off
- IRB.unset_measure_callback(arg)
- when :list
- IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val|
- puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '')
- end
- when :on
- added = IRB.set_measure_callback(arg)
- puts "#{added[0]} is added." if added
- else
- added = IRB.set_measure_callback(type, arg)
- puts "#{added[0]} is added." if added
- end
- nil
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/next.rb b/lib/irb/command/next.rb
deleted file mode 100644
index 3fc6b68d21..0000000000
--- a/lib/irb/command/next.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Next < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "next #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/pushws.rb b/lib/irb/command/pushws.rb
deleted file mode 100644
index b51928c650..0000000000
--- a/lib/irb/command/pushws.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-#
-# change-ws.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative "../ext/workspaces"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Workspaces < Base
- category "Workspace"
- description "Show workspaces."
-
- def execute(_arg)
- inspection_resuls = irb_context.instance_variable_get(:@workspace_stack).map do |ws|
- truncated_inspect(ws.main)
- end
-
- puts "[" + inspection_resuls.join(", ") + "]"
- end
-
- private
-
- def truncated_inspect(obj)
- obj_inspection = obj.inspect
-
- if obj_inspection.size > 20
- obj_inspection = obj_inspection[0, 19] + "...>"
- end
-
- obj_inspection
- end
- end
-
- class PushWorkspace < Workspaces
- category "Workspace"
- description "Push an object to the workspace stack."
-
- def execute(arg)
- if arg.empty?
- irb_context.push_workspace
- else
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.push_workspace(obj)
- end
- super
- end
- end
-
- class PopWorkspace < Workspaces
- category "Workspace"
- description "Pop a workspace from the workspace stack."
-
- def execute(_arg)
- irb_context.pop_workspace
- super
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/show_doc.rb b/lib/irb/command/show_doc.rb
deleted file mode 100644
index 8a2188e4eb..0000000000
--- a/lib/irb/command/show_doc.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class ShowDoc < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Look up documentation with RI."
-
- help_message <<~HELP_MESSAGE
- Usage: show_doc [name]
-
- When name is provided, IRB will look up the documentation for the given name.
- When no name is provided, a RI session will be started.
-
- Examples:
-
- show_doc
- show_doc Array
- show_doc Array#each
-
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- name = unwrap_string_literal(arg)
- require 'rdoc/ri/driver'
-
- unless ShowDoc.const_defined?(:Ri)
- opts = RDoc::RI::Driver.process_args([])
- ShowDoc.const_set(:Ri, RDoc::RI::Driver.new(opts))
- end
-
- if name.nil?
- Ri.interactive
- else
- begin
- Ri.display_name(name)
- rescue RDoc::RI::Error
- puts $!.message
- end
- end
-
- nil
- rescue LoadError, SystemExit
- warn "Can't display document because `rdoc` is not installed."
- end
- end
- end
-end
diff --git a/lib/irb/command/show_source.rb b/lib/irb/command/show_source.rb
deleted file mode 100644
index f4c6f104a2..0000000000
--- a/lib/irb/command/show_source.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../source_finder"
-require_relative "../pager"
-require_relative "../color"
-
-module IRB
- module Command
- class ShowSource < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Show the source code of a given method, class/module, or constant."
-
- help_message <<~HELP_MESSAGE
- Usage: show_source [target] [-s]
-
- -s Show the super method. You can stack it like `-ss` to show the super of the super, etc.
-
- Examples:
-
- show_source Foo
- show_source Foo#bar
- show_source Foo#bar -s
- show_source Foo.baz
- show_source Foo::BAR
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- str = unwrap_string_literal(arg)
- unless str.is_a?(String)
- puts "Error: Expected a string but got #{str.inspect}"
- return
- end
-
- str, esses = str.split(" -")
- super_level = esses ? esses.count("s") : 0
- source = SourceFinder.new(@irb_context).find_source(str, super_level)
-
- if source
- show_source(source)
- elsif super_level > 0
- puts "Error: Couldn't locate a super definition for #{str}"
- else
- puts "Error: Couldn't locate a definition for #{str}"
- end
- nil
- end
-
- private
-
- def show_source(source)
- if source.binary_file?
- content = "\n#{bold('Defined in binary file')}: #{source.file}\n\n"
- else
- code = source.colorized_content || 'Source not available'
- content = <<~CONTENT
-
- #{bold("From")}: #{source.file}:#{source.line}
-
- #{code.chomp}
-
- CONTENT
- end
- Pager.page_content(content)
- end
-
- def bold(str)
- Color.colorize(str, [:BOLD])
- end
- end
- end
-end
diff --git a/lib/irb/command/step.rb b/lib/irb/command/step.rb
deleted file mode 100644
index 29e5e35ac0..0000000000
--- a/lib/irb/command/step.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Step < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "step #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/subirb.rb b/lib/irb/command/subirb.rb
deleted file mode 100644
index 85af28c1a5..0000000000
--- a/lib/irb/command/subirb.rb
+++ /dev/null
@@ -1,123 +0,0 @@
-# frozen_string_literal: true
-#
-# multi.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- # :stopdoc:
-
- module Command
- class MultiIRBCommand < Base
- include RubyArgsExtractor
-
- private
-
- def print_deprecated_warning
- warn <<~MSG
- Multi-irb commands are deprecated and will be removed in IRB 2.0.0. Please use workspace commands instead.
- If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653
- MSG
- end
-
- def extend_irb_context
- # this extension patches IRB context like IRB.CurrentContext
- require_relative "../ext/multi-irb"
- end
-
- def print_debugger_warning
- warn "Multi-IRB commands are not available when the debugger is enabled."
- end
- end
-
- class IrbCommand < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Start a child IRB."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(*obj)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- IRB.irb(nil, *obj)
- puts IRB.JobManager.inspect
- end
- end
-
- class Jobs < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "List of current sessions."
-
- def execute(_arg)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- puts IRB.JobManager.inspect
- end
- end
-
- class Foreground < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Switches to the session of the given number."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(key = nil)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
-
- raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
- IRB.JobManager.switch(key)
- puts IRB.JobManager.inspect
- end
- end
-
- class Kill < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Kills the session with the given number."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(*keys)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- IRB.JobManager.kill(*keys)
- puts IRB.JobManager.inspect
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/whereami.rb b/lib/irb/command/whereami.rb
deleted file mode 100644
index c8439f1212..0000000000
--- a/lib/irb/command/whereami.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class Whereami < Base
- category "Context"
- description "Show the source code around binding.irb again."
-
- def execute(_arg)
- code = irb_context.workspace.code_around_binding
- if code
- puts code
- else
- puts "The current context doesn't have code."
- end
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
deleted file mode 100644
index 3e97047067..0000000000
--- a/lib/irb/completion.rb
+++ /dev/null
@@ -1,504 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/completion.rb -
-# by Keiju ISHITSUKA([email protected])
-# From Original Idea of [email protected]
-#
-
-require_relative 'ruby-lex'
-
-module IRB
- class BaseCompletor # :nodoc:
-
- # Set of reserved words used by Ruby, you should not use these for
- # constants or variables
- ReservedWords = %w[
- __ENCODING__ __LINE__ __FILE__
- BEGIN END
- alias and
- begin break
- case class
- def defined? do
- else elsif end ensure
- false for
- if in
- module
- next nil not
- or
- redo rescue retry return
- self super
- then true
- undef unless until
- when while
- yield
- ]
-
- HELP_COMMAND_PREPOSING = /\Ahelp\s+/
-
- def completion_candidates(preposing, target, postposing, bind:)
- raise NotImplementedError
- end
-
- def doc_namespace(preposing, matched, postposing, bind:)
- raise NotImplementedError
- end
-
- GEM_PATHS =
- if defined?(Gem::Specification)
- Gem::Specification.latest_specs(true).map { |s|
- s.require_paths.map { |p|
- if File.absolute_path?(p)
- p
- else
- File.join(s.full_gem_path, p)
- end
- }
- }.flatten
- else
- []
- end.freeze
-
- def retrieve_gem_and_system_load_path
- candidates = (GEM_PATHS | $LOAD_PATH)
- candidates.map do |p|
- if p.respond_to?(:to_path)
- p.to_path
- else
- String(p) rescue nil
- end
- end.compact.sort
- end
-
- def retrieve_files_to_require_from_load_path
- @files_from_load_path ||=
- (
- shortest = []
- rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
- begin
- names = Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: path)
- rescue Errno::ENOENT
- nil
- end
- next if names.empty?
- names.map! { |n| n.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '') }.sort!
- shortest << names.shift
- result.concat(names)
- }
- shortest.sort! | rest
- )
- end
-
- def command_candidates(target)
- if !target.empty?
- IRB::Command.command_names.select { _1.start_with?(target) }
- else
- []
- end
- end
-
- def retrieve_files_to_require_relative_from_current_dir
- @files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
- path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
- }
- end
- end
-
- class TypeCompletor < BaseCompletor # :nodoc:
- def initialize(context)
- @context = context
- end
-
- def inspect
- ReplTypeCompletor.info
- end
-
- def completion_candidates(preposing, target, _postposing, bind:)
- # When completing the argument of `help` command, only commands should be candidates
- return command_candidates(target) if preposing.match?(HELP_COMMAND_PREPOSING)
-
- commands = if preposing.empty?
- command_candidates(target)
- # It doesn't make sense to propose commands with other preposing
- else
- []
- end
-
- result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path)
-
- return commands unless result
-
- commands | result.completion_candidates.map { target + _1 }
- end
-
- def doc_namespace(preposing, matched, _postposing, bind:)
- result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
- result&.doc_namespace('')
- end
- end
-
- class RegexpCompletor < BaseCompletor # :nodoc:
- KERNEL_METHODS = ::Kernel.instance_method(:methods)
- KERNEL_PRIVATE_METHODS = ::Kernel.instance_method(:private_methods)
- KERNEL_INSTANCE_VARIABLES = ::Kernel.instance_method(:instance_variables)
- OBJECT_CLASS_INSTANCE_METHOD = ::Object.instance_method(:class)
- MODULE_CONSTANTS_INSTANCE_METHOD = ::Module.instance_method(:constants)
-
- using Module.new {
- refine ::Binding do
- def eval_methods
- KERNEL_METHODS.bind_call(receiver)
- end
-
- def eval_private_methods
- KERNEL_PRIVATE_METHODS.bind_call(receiver)
- end
-
- def eval_instance_variables
- KERNEL_INSTANCE_VARIABLES.bind_call(receiver)
- end
-
- def eval_global_variables
- ::Kernel.global_variables
- end
-
- def eval_class_constants
- klass = OBJECT_CLASS_INSTANCE_METHOD.bind_call(receiver)
- MODULE_CONSTANTS_INSTANCE_METHOD.bind_call(klass)
- end
- end
- }
-
- def inspect
- 'RegexpCompletor'
- end
-
- def complete_require_path(target, preposing, postposing)
- if target =~ /\A(['"])([^'"]+)\Z/
- quote = $1
- actual_target = $2
- else
- return nil # It's not String literal
- end
- tokens = RubyLex.ripper_lex_without_warning(preposing.gsub(/\s*\z/, ''))
- tok = nil
- tokens.reverse_each do |t|
- unless [:on_lparen, :on_sp, :on_ignored_sp, :on_nl, :on_ignored_nl, :on_comment].include?(t.event)
- tok = t
- break
- end
- end
- return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
-
- case tok.tok
- when 'require'
- retrieve_files_to_require_from_load_path.select { |path|
- path.start_with?(actual_target)
- }.map { |path|
- quote + path
- }
- when 'require_relative'
- retrieve_files_to_require_relative_from_current_dir.select { |path|
- path.start_with?(actual_target)
- }.map { |path|
- quote + path
- }
- end
- end
-
- def completion_candidates(preposing, target, postposing, bind:)
- if result = complete_require_path(target, preposing, postposing)
- return result
- end
-
- commands = command_candidates(target)
-
- # When completing the argument of `help` command, only commands should be candidates
- return commands if preposing.match?(HELP_COMMAND_PREPOSING)
-
- # It doesn't make sense to propose commands with other preposing
- commands = [] unless preposing.empty?
-
- completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
- commands | completion_data
- end
-
- def doc_namespace(_preposing, matched, _postposing, bind:)
- retrieve_completion_data(matched, bind: bind, doc_namespace: true)
- end
-
- def retrieve_completion_data(input, bind:, doc_namespace:)
- case input
- # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
- # details are described in: https://github.com/ruby/irb/pull/523
- when /^(.*["'`])\.([^.]*)$/
- # String
- receiver = $1
- message = $2
-
- if doc_namespace
- "String.#{message}"
- else
- candidates = String.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, candidates)
- end
-
- # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
- # details are described in: https://github.com/ruby/irb/pull/523
- when /^(.*\/)\.([^.]*)$/
- # Regexp
- receiver = $1
- message = $2
-
- if doc_namespace
- "Regexp.#{message}"
- else
- candidates = Regexp.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, candidates)
- end
-
- when /^([^\]]*\])\.([^.]*)$/
- # Array
- receiver = $1
- message = $2
-
- if doc_namespace
- "Array.#{message}"
- else
- candidates = Array.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, candidates)
- end
-
- when /^([^\}]*\})\.([^.]*)$/
- # Hash or Proc
- receiver = $1
- message = $2
-
- if doc_namespace
- ["Hash.#{message}", "Proc.#{message}"]
- else
- hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
- proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, hash_candidates | proc_candidates)
- end
-
- when /^(:[^:.]+)$/
- # Symbol
- if doc_namespace
- nil
- else
- sym = $1
- candidates = Symbol.all_symbols.collect do |s|
- s.inspect
- rescue EncodingError
- # ignore
- end
- candidates.grep(/^#{Regexp.quote(sym)}/)
- end
- when /^::([A-Z][^:\.\(\)]*)$/
- # Absolute Constant or class methods
- receiver = $1
-
- candidates = Object.constants.collect{|m| m.to_s}
-
- if doc_namespace
- candidates.find { |i| i == receiver }
- else
- candidates.grep(/^#{Regexp.quote(receiver)}/).collect{|e| "::" + e}
- end
-
- when /^([A-Z].*)::([^:.]*)$/
- # Constant or class methods
- receiver = $1
- message = $2
-
- if doc_namespace
- "#{receiver}::#{message}"
- else
- begin
- candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
- candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
- rescue Exception
- candidates = []
- end
-
- select_message(receiver, message, candidates.sort, "::")
- end
-
- when /^(:[^:.]+)(\.|::)([^.]*)$/
- # Symbol
- receiver = $1
- sep = $2
- message = $3
-
- if doc_namespace
- "Symbol.#{message}"
- else
- candidates = Symbol.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, candidates, sep)
- end
-
- when /^(?<num>-?(?:0[dbo])?[0-9_]+(?:\.[0-9_]+)?(?:(?:[eE][+-]?[0-9]+)?i?|r)?)(?<sep>\.|::)(?<mes>[^.]*)$/
- # Numeric
- receiver = $~[:num]
- sep = $~[:sep]
- message = $~[:mes]
-
- begin
- instance = eval(receiver, bind)
-
- if doc_namespace
- "#{instance.class.name}.#{message}"
- else
- candidates = instance.methods.collect{|m| m.to_s}
- select_message(receiver, message, candidates, sep)
- end
- rescue Exception
- if doc_namespace
- nil
- else
- []
- end
- end
-
- when /^(-?0x[0-9a-fA-F_]+)(\.|::)([^.]*)$/
- # Numeric(0xFFFF)
- receiver = $1
- sep = $2
- message = $3
-
- begin
- instance = eval(receiver, bind)
- if doc_namespace
- "#{instance.class.name}.#{message}"
- else
- candidates = instance.methods.collect{|m| m.to_s}
- select_message(receiver, message, candidates, sep)
- end
- rescue Exception
- if doc_namespace
- nil
- else
- []
- end
- end
-
- when /^(\$[^.]*)$/
- # global var
- gvar = $1
- all_gvars = global_variables.collect{|m| m.to_s}
-
- if doc_namespace
- all_gvars.find{ |i| i == gvar }
- else
- all_gvars.grep(Regexp.new(Regexp.quote(gvar)))
- end
-
- when /^([^.:"].*)(\.|::)([^.]*)$/
- # variable.func or func.func
- receiver = $1
- sep = $2
- message = $3
-
- gv = bind.eval_global_variables.collect{|m| m.to_s}.push("true", "false", "nil")
- lv = bind.local_variables.collect{|m| m.to_s}
- iv = bind.eval_instance_variables.collect{|m| m.to_s}
- cv = bind.eval_class_constants.collect{|m| m.to_s}
-
- if (gv | lv | iv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
- # foo.func and foo is var. OR
- # foo::func and foo is var. OR
- # foo::Const and foo is var. OR
- # Foo::Bar.func
- begin
- candidates = []
- rec = eval(receiver, bind)
- if sep == "::" and rec.kind_of?(Module)
- candidates = rec.constants.collect{|m| m.to_s}
- end
- candidates |= rec.methods.collect{|m| m.to_s}
- rescue Exception
- candidates = []
- end
- else
- # func1.func2
- candidates = []
- end
-
- if doc_namespace
- rec_class = rec.is_a?(Module) ? rec : rec.class
- "#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}" rescue nil
- else
- select_message(receiver, message, candidates, sep)
- end
-
- when /^\.([^.]*)$/
- # unknown(maybe String)
-
- receiver = ""
- message = $1
-
- candidates = String.instance_methods(true).collect{|m| m.to_s}
-
- if doc_namespace
- "String.#{candidates.find{ |i| i == message }}"
- else
- select_message(receiver, message, candidates.sort)
- end
- when /^\s*$/
- # empty input
- if doc_namespace
- nil
- else
- []
- end
- else
- if doc_namespace
- vars = (bind.local_variables | bind.eval_instance_variables).collect{|m| m.to_s}
- perfect_match_var = vars.find{|m| m.to_s == input}
- if perfect_match_var
- eval("#{perfect_match_var}.class.name", bind) rescue nil
- else
- candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
- candidates |= ReservedWords
- candidates.find{ |i| i == input }
- end
- else
- candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
- candidates |= ReservedWords
- candidates.grep(/^#{Regexp.quote(input)}/).sort
- end
- end
- end
-
- # Set of available operators in Ruby
- Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
-
- def select_message(receiver, message, candidates, sep = ".")
- candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
- case e
- when /^[a-zA-Z_]/
- receiver + sep + e
- when /^[0-9]/
- when *Operators
- #receiver + " " + e
- end
- end
- end
- end
-
- module InputCompletor
- class << self
- private def regexp_completor
- @regexp_completor ||= RegexpCompletor.new
- end
-
- def retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
- regexp_completor.retrieve_completion_data(input, bind: bind, doc_namespace: doc_namespace)
- end
- end
- CompletionProc = ->(target, preposing = nil, postposing = nil) {
- regexp_completor.completion_candidates(preposing || '', target, postposing || '', bind: IRB.conf[:MAIN_CONTEXT].workspace.binding)
- }
- end
- deprecate_constant :InputCompletor
-end
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
deleted file mode 100644
index 395d9081f8..0000000000
--- a/lib/irb/context.rb
+++ /dev/null
@@ -1,751 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/context.rb - irb context
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative "workspace"
-require_relative "inspector"
-require_relative "input-method"
-require_relative "output-method"
-
-module IRB
- # A class that wraps the current state of the irb session, including the
- # configuration of IRB.conf.
- class Context
- KERNEL_PUBLIC_METHOD = ::Kernel.instance_method(:public_method)
- KERNEL_METHOD = ::Kernel.instance_method(:method)
-
- ASSIGN_OPERATORS_REGEXP = Regexp.union(%w[= += -= *= /= %= **= &= |= &&= ||= ^= <<= >>=])
- # Creates a new IRB context.
- #
- # The optional +input_method+ argument:
- #
- # +nil+:: uses stdin or Reline or Readline
- # +String+:: uses a File
- # +other+:: uses this as InputMethod
- def initialize(irb, workspace = nil, input_method = nil)
- @irb = irb
- @workspace_stack = []
- if workspace
- @workspace_stack << workspace
- else
- @workspace_stack << WorkSpace.new
- end
- @thread = Thread.current
-
- # copy of default configuration
- @ap_name = IRB.conf[:AP_NAME]
- @rc = IRB.conf[:RC]
- @load_modules = IRB.conf[:LOAD_MODULES]
-
- if IRB.conf.has_key?(:USE_SINGLELINE)
- @use_singleline = IRB.conf[:USE_SINGLELINE]
- elsif IRB.conf.has_key?(:USE_READLINE) # backward compatibility
- @use_singleline = IRB.conf[:USE_READLINE]
- else
- @use_singleline = nil
- end
- if IRB.conf.has_key?(:USE_MULTILINE)
- @use_multiline = IRB.conf[:USE_MULTILINE]
- elsif IRB.conf.has_key?(:USE_RELINE) # backward compatibility
- warn <<~MSG.strip
- USE_RELINE is deprecated, please use USE_MULTILINE instead.
- MSG
- @use_multiline = IRB.conf[:USE_RELINE]
- elsif IRB.conf.has_key?(:USE_REIDLINE)
- warn <<~MSG.strip
- USE_REIDLINE is deprecated, please use USE_MULTILINE instead.
- MSG
- @use_multiline = IRB.conf[:USE_REIDLINE]
- else
- @use_multiline = nil
- end
- @use_autocomplete = IRB.conf[:USE_AUTOCOMPLETE]
- @verbose = IRB.conf[:VERBOSE]
- @io = nil
-
- self.inspect_mode = IRB.conf[:INSPECT_MODE]
- self.use_tracer = IRB.conf[:USE_TRACER]
- self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER]
- self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY]
-
- @ignore_sigint = IRB.conf[:IGNORE_SIGINT]
- @ignore_eof = IRB.conf[:IGNORE_EOF]
-
- @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT]
-
- self.prompt_mode = IRB.conf[:PROMPT_MODE]
-
- @irb_name = IRB.conf[:IRB_NAME]
-
- unless IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager)
- @irb_name = @irb_name + "#" + IRB.JobManager.n_jobs.to_s
- end
-
- self.irb_path = "(" + @irb_name + ")"
-
- case input_method
- when nil
- @io = nil
- case use_multiline?
- when nil
- if term_interactive? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
- # Both of multiline mode and singleline mode aren't specified.
- @io = RelineInputMethod.new(build_completor)
- else
- @io = nil
- end
- when false
- @io = nil
- when true
- @io = RelineInputMethod.new(build_completor)
- end
- unless @io
- case use_singleline?
- when nil
- if (defined?(ReadlineInputMethod) && term_interactive? &&
- IRB.conf[:PROMPT_MODE] != :INF_RUBY)
- @io = ReadlineInputMethod.new
- else
- @io = nil
- end
- when false
- @io = nil
- when true
- if defined?(ReadlineInputMethod)
- @io = ReadlineInputMethod.new
- else
- @io = nil
- end
- else
- @io = nil
- end
- end
- @io = StdioInputMethod.new unless @io
-
- when '-'
- @io = FileInputMethod.new($stdin)
- @irb_name = '-'
- self.irb_path = '-'
- when String
- @io = FileInputMethod.new(input_method)
- @irb_name = File.basename(input_method)
- self.irb_path = input_method
- else
- @io = input_method
- end
- @extra_doc_dirs = IRB.conf[:EXTRA_DOC_DIRS]
-
- @echo = IRB.conf[:ECHO]
- if @echo.nil?
- @echo = true
- end
-
- @echo_on_assignment = IRB.conf[:ECHO_ON_ASSIGNMENT]
- if @echo_on_assignment.nil?
- @echo_on_assignment = :truncate
- end
-
- @newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT]
- if @newline_before_multiline_output.nil?
- @newline_before_multiline_output = true
- end
-
- @command_aliases = IRB.conf[:COMMAND_ALIASES].dup
- end
-
- def use_tracer=(val)
- require_relative "ext/tracer" if val
- IRB.conf[:USE_TRACER] = val
- end
-
- def eval_history=(val)
- self.class.remove_method(__method__)
- require_relative "ext/eval_history"
- __send__(__method__, val)
- end
-
- def use_loader=(val)
- self.class.remove_method(__method__)
- require_relative "ext/use-loader"
- __send__(__method__, val)
- end
-
- def save_history=(val)
- IRB.conf[:SAVE_HISTORY] = val
- end
-
- def save_history
- IRB.conf[:SAVE_HISTORY]
- end
-
- # A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
- def history_file
- IRB.conf[:HISTORY_FILE]
- end
-
- # Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
- def history_file=(hist)
- IRB.conf[:HISTORY_FILE] = hist
- end
-
- # Workspace in the current context.
- def workspace
- @workspace_stack.last
- end
-
- # Replace the current workspace with the given +workspace+.
- def replace_workspace(workspace)
- @workspace_stack.pop
- @workspace_stack.push(workspace)
- end
-
- # The top-level workspace, see WorkSpace#main
- def main
- workspace.main
- end
-
- # The toplevel workspace, see #home_workspace
- attr_reader :workspace_home
- # The current thread in this context.
- attr_reader :thread
- # The current input method.
- #
- # Can be either StdioInputMethod, ReadlineInputMethod,
- # RelineInputMethod, FileInputMethod or other specified when the
- # context is created. See ::new for more # information on +input_method+.
- attr_accessor :io
-
- # Current irb session.
- attr_accessor :irb
- # A copy of the default <code>IRB.conf[:AP_NAME]</code>
- attr_accessor :ap_name
- # A copy of the default <code>IRB.conf[:RC]</code>
- attr_accessor :rc
- # A copy of the default <code>IRB.conf[:LOAD_MODULES]</code>
- attr_accessor :load_modules
- # Can be either name from <code>IRB.conf[:IRB_NAME]</code>, or the number of
- # the current job set by JobManager, such as <code>irb#2</code>
- attr_accessor :irb_name
-
- # Can be one of the following:
- # - the #irb_name surrounded by parenthesis
- # - the +input_method+ passed to Context.new
- # - the file path of the current IRB context in a binding.irb session
- attr_reader :irb_path
-
- # Sets @irb_path to the given +path+ as well as @eval_path
- # @eval_path is used for evaluating code in the context of IRB session
- # It's the same as irb_path, but with the IRB name postfix
- # This makes sure users can distinguish the methods defined in the IRB session
- # from the methods defined in the current file's context, especially with binding.irb
- def irb_path=(path)
- @irb_path = path
-
- if File.exist?(path)
- @eval_path = "#{path}(#{IRB.conf[:IRB_NAME]})"
- else
- @eval_path = path
- end
- end
-
- # Whether multiline editor mode is enabled or not.
- #
- # A copy of the default <code>IRB.conf[:USE_MULTILINE]</code>
- attr_reader :use_multiline
- # Whether singleline editor mode is enabled or not.
- #
- # A copy of the default <code>IRB.conf[:USE_SINGLELINE]</code>
- attr_reader :use_singleline
- # Whether colorization is enabled or not.
- #
- # A copy of the default <code>IRB.conf[:USE_AUTOCOMPLETE]</code>
- attr_reader :use_autocomplete
- # A copy of the default <code>IRB.conf[:INSPECT_MODE]</code>
- attr_reader :inspect_mode
- # Inspector for the current context
- attr_reader :inspect_method
-
- # A copy of the default <code>IRB.conf[:PROMPT_MODE]</code>
- attr_reader :prompt_mode
- # Standard IRB prompt.
- #
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
- attr_accessor :prompt_i
- # IRB prompt for continuated strings.
- #
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
- attr_accessor :prompt_s
- # IRB prompt for continuated statement. (e.g. immediately after an +if+)
- #
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
- attr_accessor :prompt_c
-
- # TODO: Remove this when developing v2.0
- def prompt_n
- warn "IRB::Context#prompt_n is deprecated and will be removed in the next major release."
- ""
- end
-
- # TODO: Remove this when developing v2.0
- def prompt_n=(_)
- warn "IRB::Context#prompt_n= is deprecated and will be removed in the next major release."
- ""
- end
-
- # Can be either the default <code>IRB.conf[:AUTO_INDENT]</code>, or the
- # mode set by #prompt_mode=
- #
- # To disable auto-indentation in irb:
- #
- # IRB.conf[:AUTO_INDENT] = false
- #
- # or
- #
- # irb_context.auto_indent_mode = false
- #
- # or
- #
- # IRB.CurrentContext.auto_indent_mode = false
- #
- # See IRB@Configuration for more information.
- attr_accessor :auto_indent_mode
- # The format of the return statement, set by #prompt_mode= using the
- # +:RETURN+ of the +mode+ passed to set the current #prompt_mode.
- attr_accessor :return_format
-
- # Whether <code>^C</code> (+control-c+) will be ignored or not.
- #
- # If set to +false+, <code>^C</code> will quit irb.
- #
- # If set to +true+,
- #
- # * during input: cancel input then return to top level.
- # * during execute: abandon current execution.
- attr_accessor :ignore_sigint
- # Whether <code>^D</code> (+control-d+) will be ignored or not.
- #
- # If set to +false+, <code>^D</code> will quit irb.
- attr_accessor :ignore_eof
- # Specify the installation locations of the ri file to be displayed in the
- # document dialog.
- attr_accessor :extra_doc_dirs
- # Whether to echo the return value to output or not.
- #
- # Uses <code>IRB.conf[:ECHO]</code> if available, or defaults to +true+.
- #
- # puts "hello"
- # # hello
- # #=> nil
- # IRB.CurrentContext.echo = false
- # puts "omg"
- # # omg
- attr_accessor :echo
- # Whether to echo for assignment expressions.
- #
- # If set to +false+, the value of assignment will not be shown.
- #
- # If set to +true+, the value of assignment will be shown.
- #
- # If set to +:truncate+, the value of assignment will be shown and truncated.
- #
- # It defaults to +:truncate+.
- #
- # a = "omg"
- # #=> omg
- #
- # a = "omg" * 10
- # #=> omgomgomgomgomgomgomg...
- #
- # IRB.CurrentContext.echo_on_assignment = false
- # a = "omg"
- #
- # IRB.CurrentContext.echo_on_assignment = true
- # a = "omg" * 10
- # #=> omgomgomgomgomgomgomgomgomgomg
- #
- # To set the behaviour of showing on assignment in irb:
- #
- # IRB.conf[:ECHO_ON_ASSIGNMENT] = :truncate or true or false
- #
- # or
- #
- # irb_context.echo_on_assignment = :truncate or true or false
- #
- # or
- #
- # IRB.CurrentContext.echo_on_assignment = :truncate or true or false
- attr_accessor :echo_on_assignment
- # Whether a newline is put before multiline output.
- #
- # Uses <code>IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT]</code> if available,
- # or defaults to +true+.
- #
- # "abc\ndef"
- # #=>
- # abc
- # def
- # IRB.CurrentContext.newline_before_multiline_output = false
- # "abc\ndef"
- # #=> abc
- # def
- attr_accessor :newline_before_multiline_output
- # Whether verbose messages are displayed or not.
- #
- # A copy of the default <code>IRB.conf[:VERBOSE]</code>
- attr_accessor :verbose
-
- # The limit of backtrace lines displayed as top +n+ and tail +n+.
- #
- # The default value is 16.
- #
- # Can also be set using the +--back-trace-limit+ command line option.
- attr_accessor :back_trace_limit
-
- # User-defined IRB command aliases
- attr_accessor :command_aliases
-
- attr_accessor :with_debugger
-
- # Alias for #use_multiline
- alias use_multiline? use_multiline
- # Alias for #use_singleline
- alias use_singleline? use_singleline
- # backward compatibility
- alias use_reline use_multiline
- # backward compatibility
- alias use_reline? use_multiline
- # backward compatibility
- alias use_readline use_singleline
- # backward compatibility
- alias use_readline? use_singleline
- # Alias for #use_autocomplete
- alias use_autocomplete? use_autocomplete
- # Alias for #rc
- alias rc? rc
- alias ignore_sigint? ignore_sigint
- alias ignore_eof? ignore_eof
- alias echo? echo
- alias echo_on_assignment? echo_on_assignment
- alias newline_before_multiline_output? newline_before_multiline_output
-
- # Returns whether messages are displayed or not.
- def verbose?
- if @verbose.nil?
- if @io.kind_of?(RelineInputMethod)
- false
- elsif defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)
- false
- elsif !STDIN.tty? or @io.kind_of?(FileInputMethod)
- true
- else
- false
- end
- else
- @verbose
- end
- end
-
- # Whether #verbose? is +true+, and +input_method+ is either
- # StdioInputMethod or RelineInputMethod or ReadlineInputMethod, see #io
- # for more information.
- def prompting?
- verbose? || @io.prompting?
- end
-
- # The return value of the last statement evaluated.
- attr_reader :last_value
-
- # Sets the return value from the last statement evaluated in this context
- # to #last_value.
- def set_last_value(value)
- @last_value = value
- workspace.local_variable_set :_, value
- end
-
- # Sets the +mode+ of the prompt in this context.
- #
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
- def prompt_mode=(mode)
- @prompt_mode = mode
- pconf = IRB.conf[:PROMPT][mode]
- @prompt_i = pconf[:PROMPT_I]
- @prompt_s = pconf[:PROMPT_S]
- @prompt_c = pconf[:PROMPT_C]
- @return_format = pconf[:RETURN]
- @return_format = "%s\n" if @return_format == nil
- if ai = pconf.include?(:AUTO_INDENT)
- @auto_indent_mode = ai
- else
- @auto_indent_mode = IRB.conf[:AUTO_INDENT]
- end
- end
-
- # Whether #inspect_mode is set or not, see #inspect_mode= for more detail.
- def inspect?
- @inspect_mode.nil? or @inspect_mode
- end
-
- # Whether #io uses a File for the +input_method+ passed when creating the
- # current context, see ::new
- def file_input?
- @io.class == FileInputMethod
- end
-
- # Specifies the inspect mode with +opt+:
- #
- # +true+:: display +inspect+
- # +false+:: display +to_s+
- # +nil+:: inspect mode in non-math mode,
- # non-inspect mode in math mode
- #
- # See IRB::Inspector for more information.
- #
- # Can also be set using the +--inspect+ and +--noinspect+ command line
- # options.
- def inspect_mode=(opt)
-
- if i = Inspector::INSPECTORS[opt]
- @inspect_mode = opt
- @inspect_method = i
- i.init
- else
- case opt
- when nil
- if Inspector.keys_with_inspector(Inspector::INSPECTORS[true]).include?(@inspect_mode)
- self.inspect_mode = false
- elsif Inspector.keys_with_inspector(Inspector::INSPECTORS[false]).include?(@inspect_mode)
- self.inspect_mode = true
- else
- puts "Can't switch inspect mode."
- return
- end
- when /^\s*\{.*\}\s*$/
- begin
- inspector = eval "proc#{opt}"
- rescue Exception
- puts "Can't switch inspect mode(#{opt})."
- return
- end
- self.inspect_mode = inspector
- when Proc
- self.inspect_mode = IRB::Inspector(opt)
- when Inspector
- prefix = "usr%d"
- i = 1
- while Inspector::INSPECTORS[format(prefix, i)]; i += 1; end
- @inspect_mode = format(prefix, i)
- @inspect_method = opt
- Inspector.def_inspector(format(prefix, i), @inspect_method)
- else
- puts "Can't switch inspect mode(#{opt})."
- return
- end
- end
- print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose?
- @inspect_mode
- end
-
- def evaluate(statement, line_no) # :nodoc:
- @line_no = line_no
-
- case statement
- when Statement::EmptyInput
- return
- when Statement::Expression
- result = evaluate_expression(statement.code, line_no)
- set_last_value(result)
- when Statement::Command
- statement.command_class.execute(self, statement.arg)
- when Statement::IncorrectAlias
- warn statement.message
- end
-
- nil
- end
-
- def from_binding?
- @irb.from_binding
- end
-
- def evaluate_expression(code, line_no) # :nodoc:
- result = nil
- if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
- IRB.set_measure_callback
- end
-
- if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
- last_proc = proc do
- result = workspace.evaluate(code, @eval_path, line_no)
- end
- IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) do |chain, item|
- _name, callback, arg = item
- proc do
- callback.(self, code, line_no, arg) do
- chain.call
- end
- end
- end.call
- else
- result = workspace.evaluate(code, @eval_path, line_no)
- end
- result
- end
-
- def parse_input(code, is_assignment_expression)
- command_name, arg = code.strip.split(/\s+/, 2)
- arg ||= ''
-
- # command can only be 1 line
- if code.lines.size != 1 ||
- # command name is required
- command_name.nil? ||
- # local variable have precedence over command
- local_variables.include?(command_name.to_sym) ||
- # assignment expression is not a command
- (is_assignment_expression ||
- (arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/)))
- return Statement::Expression.new(code, is_assignment_expression)
- end
-
- command = command_name.to_sym
-
- # Check command aliases
- if aliased_name = command_aliases[command]
- if command_class = Command.load_command(aliased_name)
- command = aliased_name
- elsif HelperMethod.helper_methods[aliased_name]
- message = <<~MESSAGE
- Using command alias `#{command}` for helper method `#{aliased_name}` is not supported.
- Please check the value of `IRB.conf[:COMMAND_ALIASES]`.
- MESSAGE
- return Statement::IncorrectAlias.new(message)
- else
- message = <<~MESSAGE
- You're trying to use command alias `#{command}` for command `#{aliased_name}`, but `#{aliased_name}` does not exist.
- Please check the value of `IRB.conf[:COMMAND_ALIASES]`.
- MESSAGE
- return Statement::IncorrectAlias.new(message)
- end
- else
- command_class = Command.load_command(command)
- end
-
- # Check visibility
- public_method = !!KERNEL_PUBLIC_METHOD.bind_call(main, command) rescue false
- private_method = !public_method && !!KERNEL_METHOD.bind_call(main, command) rescue false
- if command_class && Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
- Statement::Command.new(code, command_class, arg)
- else
- Statement::Expression.new(code, is_assignment_expression)
- end
- end
-
- def colorize_input(input, complete:)
- if IRB.conf[:USE_COLORIZE] && IRB::Color.colorable?
- lvars = local_variables || []
- parsed_input = parse_input(input, false)
- if parsed_input.is_a?(Statement::Command)
- name, sep, arg = input.split(/(\s+)/, 2)
- arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars)
- "#{IRB::Color.colorize(name, [:BOLD])}\e[m#{sep}#{arg}"
- else
- IRB::Color.colorize_code(input, complete: complete, local_variables: lvars)
- end
- else
- Reline::Unicode.escape_for_print(input)
- end
- end
-
- def inspect_last_value(output = +'') # :nodoc:
- @inspect_method.inspect_value(@last_value, output)
- end
-
- def inspector_support_stream_output?
- @inspect_method.support_stream_output?
- end
-
- NOPRINTING_IVARS = ["@last_value"] # :nodoc:
- NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc:
- IDNAME_IVARS = ["@prompt_mode"] # :nodoc:
-
- alias __inspect__ inspect
- def inspect # :nodoc:
- array = []
- for ivar in instance_variables.sort{|e1, e2| e1 <=> e2}
- ivar = ivar.to_s
- name = ivar.sub(/^@(.*)$/, '\1')
- val = instance_eval(ivar)
- case ivar
- when *NOPRINTING_IVARS
- array.push format("conf.%s=%s", name, "...")
- when *NO_INSPECTING_IVARS
- array.push format("conf.%s=%s", name, val.to_s)
- when *IDNAME_IVARS
- array.push format("conf.%s=:%s", name, val.id2name)
- else
- array.push format("conf.%s=%s", name, val.inspect)
- end
- end
- array.join("\n")
- end
- alias __to_s__ to_s
- alias to_s inspect
-
- def local_variables # :nodoc:
- workspace.binding.local_variables
- end
-
- def safe_method_call_on_main(method_name)
- main_object = main
- Object === main_object ? main_object.__send__(method_name) : Object.instance_method(method_name).bind_call(main_object)
- end
-
- private
-
- def term_interactive?
- return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
- STDIN.tty? && ENV['TERM'] != 'dumb'
- end
-
- def build_completor
- completor_type = IRB.conf[:COMPLETOR]
-
- # Gem repl_type_completor is added to bundled gems in Ruby 3.4.
- # Use :type as default completor only in Ruby 3.4 or later.
- verbose = !!completor_type
- completor_type ||= RUBY_VERSION >= '3.4' ? :type : :regexp
-
- case completor_type
- when :regexp
- return RegexpCompletor.new
- when :type
- completor = build_type_completor(verbose: verbose)
- return completor if completor
- else
- warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
- end
- # Fallback to RegexpCompletor
- RegexpCompletor.new
- end
-
- def build_type_completor(verbose:)
- if RUBY_ENGINE == 'truffleruby'
- # Avoid SyntaxError. truffleruby does not support endless method definition yet.
- warn 'TypeCompletor is not supported on TruffleRuby yet' if verbose
- return
- end
-
- begin
- require 'repl_type_completor'
- rescue LoadError => e
- warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}" if verbose
- return
- end
-
- ReplTypeCompletor.preload_rbs
- TypeCompletor.new(self)
- end
- end
-end
diff --git a/lib/irb/debug.rb b/lib/irb/debug.rb
deleted file mode 100644
index 59be1365bd..0000000000
--- a/lib/irb/debug.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Debug
- IRB_DIR = File.expand_path('..', __dir__)
-
- class << self
- def insert_debug_break(pre_cmds: nil, do_cmds: nil)
- options = { oneshot: true, hook_call: false }
-
- if pre_cmds || do_cmds
- options[:command] = ['irb', pre_cmds, do_cmds]
- end
- if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
- options[:skip_src] = true
- end
-
- # To make debugger commands like `next` or `continue` work without asking
- # the user to quit IRB after that, we need to exit IRB first and then hit
- # a TracePoint on #debug_break.
- file, lineno = IRB::Irb.instance_method(:debug_break).source_location
- DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
- end
-
- def setup(irb)
- # When debug session is not started at all
- unless defined?(DEBUGGER__::SESSION)
- begin
- require "debug/session"
- rescue LoadError # debug.gem is not written in Gemfile
- return false unless load_bundled_debug_gem
- end
- DEBUGGER__::CONFIG.set_config
- configure_irb_for_debugger(irb)
-
- DEBUGGER__.initialize_session{ IRB::Debug::UI.new(irb) }
- end
-
- # When debug session was previously started but not by IRB
- if defined?(DEBUGGER__::SESSION) && !irb.context.with_debugger
- configure_irb_for_debugger(irb)
- DEBUGGER__::SESSION.reset_ui(IRB::Debug::UI.new(irb))
- end
-
- # Apply patches to debug gem so it skips IRB frames
- unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
- DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
-
- def DEBUGGER__.capture_frames(*args)
- frames = capture_frames_without_irb(*args)
- frames.reject! do |frame|
- frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
- end
- frames
- end
-
- DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
- end
-
- if !DEBUGGER__::CONFIG[:no_hint] && irb.context.io.is_a?(RelineInputMethod)
- Reline.output_modifier_proc = proc do |input, complete:|
- unless input.strip.empty?
- cmd = input.split(/\s/, 2).first
-
- if !complete && DEBUGGER__.commands.key?(cmd)
- input = input.sub(/\n$/, " # debug command\n")
- end
- end
-
- irb.context.colorize_input(input, complete: complete)
- end
- end
-
- true
- end
-
- private
-
- def configure_irb_for_debugger(irb)
- require 'irb/debug/ui'
- IRB.instance_variable_set(:@debugger_irb, irb)
- irb.context.with_debugger = true
- irb.context.irb_name += ":rdbg"
- irb.context.io.load_history if irb.context.io.class < HistorySavingAbility
- end
-
- module SkipPathHelperForIRB
- def skip_internal_path?(path)
- # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
- super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
- end
- end
-
- # This is used when debug.gem is not written in Gemfile. Even if it's not
- # installed by `bundle install`, debug.gem is installed by default because
- # it's a bundled gem. This method tries to activate and load that.
- def load_bundled_debug_gem
- # Discover latest debug.gem under GEM_PATH
- debug_gem = Gem.paths.path.flat_map { |path| Dir.glob("#{path}/gems/debug-*") }.select do |path|
- File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+(\w+)?\z/)
- end.sort_by do |path|
- Gem::Version.new(File.basename(path).delete_prefix('debug-'))
- end.last
- return false unless debug_gem
-
- # Discover debug/debug.so under extensions for Ruby 3.2+
- ext_name = "/debug/debug.#{RbConfig::CONFIG['DLEXT']}"
- ext_path = Gem.paths.path.flat_map do |path|
- Dir.glob("#{path}/extensions/**/#{File.basename(debug_gem)}#{ext_name}")
- end.first
-
- # Attempt to forcibly load the bundled gem
- if ext_path
- $LOAD_PATH << ext_path.delete_suffix(ext_name)
- end
- $LOAD_PATH << "#{debug_gem}/lib"
- begin
- require "debug/session"
- puts "Loaded #{File.basename(debug_gem)}"
- true
- rescue LoadError
- false
- end
- end
- end
- end
-end
diff --git a/lib/irb/debug/ui.rb b/lib/irb/debug/ui.rb
deleted file mode 100644
index a21ec6b11d..0000000000
--- a/lib/irb/debug/ui.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-require 'io/console/size'
-require 'debug/console'
-
-module IRB
- module Debug
- class UI < DEBUGGER__::UI_Base
- def initialize(irb)
- @irb = irb
- end
-
- def remote?
- false
- end
-
- def activate session, on_fork: false
- end
-
- def deactivate
- end
-
- def width
- if (w = IO.console_size[1]) == 0 # for tests PTY
- 80
- else
- w
- end
- end
-
- def quit n
- yield
- exit n
- end
-
- def ask prompt
- setup_interrupt do
- print prompt
- ($stdin.gets || '').strip
- end
- end
-
- def puts str = nil
- case str
- when Array
- str.each{|line|
- $stdout.puts line.chomp
- }
- when String
- Pager.page_content(str, retain_content: true)
- when nil
- $stdout.puts
- end
- end
-
- def readline _
- setup_interrupt do
- tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
- cmd = @irb.debug_readline(tc.current_frame.eval_binding || TOPLEVEL_BINDING)
-
- case cmd
- when nil # when user types C-d
- "continue"
- else
- cmd
- end
- end
- end
-
- def setup_interrupt
- DEBUGGER__::SESSION.intercept_trap_sigint false do
- current_thread = Thread.current # should be session_server thread
-
- prev_handler = trap(:INT){
- current_thread.raise Interrupt
- }
-
- yield
- ensure
- trap(:INT, prev_handler)
- end
- end
-
- def after_fork_parent
- parent_pid = Process.pid
-
- at_exit{
- DEBUGGER__::SESSION.intercept_trap_sigint_end
- trap(:SIGINT, :IGNORE)
-
- if Process.pid == parent_pid
- # only check child process from its parent
- begin
- # wait for all child processes to keep terminal
- Process.waitpid
- rescue Errno::ESRCH, Errno::ECHILD
- end
- end
- }
- end
- end
- end
-end
diff --git a/lib/irb/default_commands.rb b/lib/irb/default_commands.rb
deleted file mode 100644
index 9820a1f304..0000000000
--- a/lib/irb/default_commands.rb
+++ /dev/null
@@ -1,279 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "command"
-require_relative "command/internal_helpers"
-require_relative "command/backtrace"
-require_relative "command/break"
-require_relative "command/catch"
-require_relative "command/cd"
-require_relative "command/chws"
-require_relative "command/context"
-require_relative "command/continue"
-require_relative "command/copy"
-require_relative "command/debug"
-require_relative "command/delete"
-require_relative "command/disable_irb"
-require_relative "command/edit"
-require_relative "command/exit"
-require_relative "command/finish"
-require_relative "command/force_exit"
-require_relative "command/help"
-require_relative "command/history"
-require_relative "command/info"
-require_relative "command/irb_info"
-require_relative "command/load"
-require_relative "command/ls"
-require_relative "command/measure"
-require_relative "command/next"
-require_relative "command/pushws"
-require_relative "command/show_doc"
-require_relative "command/show_source"
-require_relative "command/step"
-require_relative "command/subirb"
-require_relative "command/whereami"
-
-module IRB
- module Command
- NO_OVERRIDE = 0
- OVERRIDE_PRIVATE_ONLY = 0x01
- OVERRIDE_ALL = 0x02
-
- class << self
- # This API is for IRB's internal use only and may change at any time.
- # Please do NOT use it.
- def _register_with_aliases(name, command_class, *aliases)
- @commands[name.to_sym] = [command_class, aliases]
- end
-
- def all_commands_info
- user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
- result[target] ||= []
- result[target] << alias_name
- end
-
- commands.map do |command_name, (command_class, aliases)|
- aliases = aliases.map { |a| a.first }
-
- if additional_aliases = user_aliases[command_name]
- aliases += additional_aliases
- end
-
- display_name = aliases.shift || command_name
- {
- display_name: display_name,
- description: command_class.description,
- category: command_class.category
- }
- end
- end
-
- def command_override_policies
- @@command_override_policies ||= commands.flat_map do |cmd_name, (cmd_class, aliases)|
- [[cmd_name, OVERRIDE_ALL]] + aliases
- end.to_h
- end
-
- def execute_as_command?(name, public_method:, private_method:)
- case command_override_policies[name]
- when OVERRIDE_ALL
- true
- when OVERRIDE_PRIVATE_ONLY
- !public_method
- when NO_OVERRIDE
- !public_method && !private_method
- end
- end
-
- def command_names
- command_override_policies.keys.map(&:to_s)
- end
-
- # Convert a command name to its implementation class if such command exists
- def load_command(command)
- command = command.to_sym
- commands.each do |command_name, (command_class, aliases)|
- if command_name == command || aliases.any? { |alias_name, _| alias_name == command }
- return command_class
- end
- end
- nil
- end
- end
-
- _register_with_aliases(:irb_context, Command::Context,
- [:context, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_exit, Command::Exit,
- [:exit, OVERRIDE_PRIVATE_ONLY],
- [:quit, OVERRIDE_PRIVATE_ONLY],
- [:irb_quit, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_exit!, Command::ForceExit,
- [:exit!, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_current_working_workspace, Command::CurrentWorkingWorkspace,
- [:cwws, NO_OVERRIDE],
- [:pwws, NO_OVERRIDE],
- [:irb_print_working_workspace, OVERRIDE_ALL],
- [:irb_cwws, OVERRIDE_ALL],
- [:irb_pwws, OVERRIDE_ALL],
- [:irb_current_working_binding, OVERRIDE_ALL],
- [:irb_print_working_binding, OVERRIDE_ALL],
- [:irb_cwb, OVERRIDE_ALL],
- [:irb_pwb, OVERRIDE_ALL],
- )
-
- _register_with_aliases(:irb_change_workspace, Command::ChangeWorkspace,
- [:chws, NO_OVERRIDE],
- [:cws, NO_OVERRIDE],
- [:irb_chws, OVERRIDE_ALL],
- [:irb_cws, OVERRIDE_ALL],
- [:irb_change_binding, OVERRIDE_ALL],
- [:irb_cb, OVERRIDE_ALL],
- [:cb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_workspaces, Command::Workspaces,
- [:workspaces, NO_OVERRIDE],
- [:irb_bindings, OVERRIDE_ALL],
- [:bindings, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_push_workspace, Command::PushWorkspace,
- [:pushws, NO_OVERRIDE],
- [:irb_pushws, OVERRIDE_ALL],
- [:irb_push_binding, OVERRIDE_ALL],
- [:irb_pushb, OVERRIDE_ALL],
- [:pushb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_pop_workspace, Command::PopWorkspace,
- [:popws, NO_OVERRIDE],
- [:irb_popws, OVERRIDE_ALL],
- [:irb_pop_binding, OVERRIDE_ALL],
- [:irb_popb, OVERRIDE_ALL],
- [:popb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_load, Command::Load)
- _register_with_aliases(:irb_require, Command::Require)
- _register_with_aliases(:irb_source, Command::Source,
- [:source, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb, Command::IrbCommand)
- _register_with_aliases(:irb_jobs, Command::Jobs,
- [:jobs, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_fg, Command::Foreground,
- [:fg, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_kill, Command::Kill,
- [:kill, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_debug, Command::Debug,
- [:debug, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_edit, Command::Edit,
- [:edit, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_break, Command::Break,
- [:break, OVERRIDE_ALL]
- )
- _register_with_aliases(:irb_catch, Command::Catch,
- [:catch, OVERRIDE_PRIVATE_ONLY]
- )
- _register_with_aliases(:irb_next, Command::Next,
- [:next, OVERRIDE_ALL]
- )
- _register_with_aliases(:irb_delete, Command::Delete,
- [:delete, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_step, Command::Step,
- [:step, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_continue, Command::Continue,
- [:continue, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_finish, Command::Finish,
- [:finish, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_backtrace, Command::Backtrace,
- [:backtrace, NO_OVERRIDE],
- [:bt, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_debug_info, Command::Info,
- [:info, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_help, Command::Help,
- [:help, NO_OVERRIDE],
- [:show_cmds, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_show_doc, Command::ShowDoc,
- [:show_doc, NO_OVERRIDE],
- [:ri, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_info, Command::IrbInfo)
-
- _register_with_aliases(:irb_ls, Command::Ls,
- [:ls, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_measure, Command::Measure,
- [:measure, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_show_source, Command::ShowSource,
- [:show_source, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_whereami, Command::Whereami,
- [:whereami, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_history, Command::History,
- [:history, NO_OVERRIDE],
- [:hist, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_disable_irb, Command::DisableIrb,
- [:disable_irb, NO_OVERRIDE]
- )
-
- register(:cd, Command::CD)
- register(:copy, Command::Copy)
- end
-
- ExtendCommand = Command
-
- # For backward compatibility, we need to keep this module:
- # - As a container of helper methods
- # - As a place to register commands with the deprecated def_extend_command method
- module ExtendCommandBundle
- # For backward compatibility
- NO_OVERRIDE = Command::NO_OVERRIDE
- OVERRIDE_PRIVATE_ONLY = Command::OVERRIDE_PRIVATE_ONLY
- OVERRIDE_ALL = Command::OVERRIDE_ALL
-
- # Deprecated. Doesn't have any effect.
- @EXTEND_COMMANDS = []
-
- class << self
- # Drepcated. Use Command.regiser instead.
- def def_extend_command(cmd_name, cmd_class, _, *aliases)
- Command._register_with_aliases(cmd_name, cmd_class, *aliases)
- Command.class_variable_set(:@@command_override_policies, nil)
- end
- end
- end
-end
diff --git a/lib/irb/easter-egg.rb b/lib/irb/easter-egg.rb
deleted file mode 100644
index 07b6137be3..0000000000
--- a/lib/irb/easter-egg.rb
+++ /dev/null
@@ -1,152 +0,0 @@
-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_logo(type)
- @easter_egg_logos ||= File.read(File.join(__dir__, 'ruby_logo.aa'), encoding: 'UTF-8:UTF-8')
- .split(/TYPE: ([A-Z_]+)\n/)[1..]
- .each_slice(2)
- .to_h
- @easter_egg_logos[type.to_s.upcase]
- end
-
- private def easter_egg(type = nil)
- print "\e[?1049h"
- type ||= [:logo, :dancing].sample
- case type
- when :logo
- Pager.page do |io|
- logo_type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode_large : :ascii_large
- io.write easter_egg_logo(logo_type)
- STDIN.raw { STDIN.getc } if io == STDOUT
- end
- when :dancing
- STDOUT.cooked do
- interrupted = false
- prev_trap = trap("SIGINT") { interrupted = true }
- 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[?25l" # hide cursor
- 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
- break if interrupted
- end
- rescue Interrupt
- ensure
- print "\e[?25h" # show cursor
- trap("SIGINT", prev_trap)
- end
- end
- ensure
- print "\e[0m\e[?1049l"
- end
- end
-end
-
-IRB.__send__(:easter_egg, ARGV[0]&.to_sym) if $0 == __FILE__
diff --git a/lib/irb/ext/change-ws.rb b/lib/irb/ext/change-ws.rb
deleted file mode 100644
index 60e8afe31f..0000000000
--- a/lib/irb/ext/change-ws.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/ext/cb.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
- class Context
-
- # Inherited from +TOPLEVEL_BINDING+.
- def home_workspace
- if defined? @home_workspace
- @home_workspace
- else
- @home_workspace = workspace
- end
- end
-
- # Changes the current workspace to given object or binding.
- #
- # If the optional argument is omitted, the workspace will be
- # #home_workspace which is inherited from +TOPLEVEL_BINDING+ or the main
- # object, <code>IRB.conf[:MAIN_CONTEXT]</code> when irb was initialized.
- #
- # See IRB::WorkSpace.new for more information.
- def change_workspace(*_main)
- if _main.empty?
- replace_workspace(home_workspace)
- return main
- end
-
- workspace = WorkSpace.new(_main[0])
- replace_workspace(workspace)
- workspace.load_helper_methods_to_main
- end
- end
-end
diff --git a/lib/irb/ext/eval_history.rb b/lib/irb/ext/eval_history.rb
deleted file mode 100644
index 6c21ff00ee..0000000000
--- a/lib/irb/ext/eval_history.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-#
-# history.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
-
- class Context
-
- NOPRINTING_IVARS.push "@eval_history_values"
-
- # See #set_last_value
- alias _set_last_value set_last_value
-
- def set_last_value(value)
- _set_last_value(value)
-
- if defined?(@eval_history) && @eval_history
- @eval_history_values.push @line_no, @last_value
- workspace.evaluate "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
- end
-
- @last_value
- end
-
- remove_method :eval_history= if method_defined?(:eval_history=)
- # The command result history limit. This method is not available until
- # #eval_history= was called with non-nil value (directly or via
- # setting <code>IRB.conf[:EVAL_HISTORY]</code> in <code>.irbrc</code>).
- attr_reader :eval_history
- # Sets command result history limit. Default value is set from
- # <code>IRB.conf[:EVAL_HISTORY]</code>.
- #
- # +no+ is an Integer or +nil+.
- #
- # Returns +no+ of history items if greater than 0.
- #
- # If +no+ is 0, the number of history items is unlimited.
- #
- # If +no+ is +nil+, execution result history isn't used (default).
- #
- # EvalHistory values are available via <code>__</code> variable, see
- # IRB::EvalHistory.
- def eval_history=(no)
- if no
- if defined?(@eval_history) && @eval_history
- @eval_history_values.size(no)
- else
- @eval_history_values = EvalHistory.new(no)
- IRB.conf[:__TMP__EHV__] = @eval_history_values
- workspace.evaluate("__ = IRB.conf[:__TMP__EHV__]")
- IRB.conf.delete(:__TMP_EHV__)
- end
- else
- @eval_history_values = nil
- end
- @eval_history = no
- end
- end
-
- # Represents history of results of previously evaluated commands.
- #
- # Available via <code>__</code> variable, only if <code>IRB.conf[:EVAL_HISTORY]</code>
- # or <code>IRB::CurrentContext().eval_history</code> is non-nil integer value
- # (by default it is +nil+).
- #
- # Example (in `irb`):
- #
- # # Initialize history
- # IRB::CurrentContext().eval_history = 10
- # # => 10
- #
- # # Perform some commands...
- # 1 + 2
- # # => 3
- # puts 'x'
- # # x
- # # => nil
- # raise RuntimeError
- # # ...error raised
- #
- # # Inspect history (format is "<item number> <evaluated value>":
- # __
- # # => 1 10
- # # 2 3
- # # 3 nil
- #
- # __[1]
- # # => 10
- #
- class EvalHistory
-
- def initialize(size = 16) # :nodoc:
- @size = size
- @contents = []
- end
-
- def size(size) # :nodoc:
- if size != 0 && size < @size
- @contents = @contents[@size - size .. @size]
- end
- @size = size
- end
-
- # Get one item of the content (both positive and negative indexes work).
- def [](idx)
- begin
- if idx >= 0
- @contents.find{|no, val| no == idx}[1]
- else
- @contents[idx][1]
- end
- rescue NameError
- nil
- end
- end
-
- def push(no, val) # :nodoc:
- @contents.push [no, val]
- @contents.shift if @size != 0 && @contents.size > @size
- end
-
- alias real_inspect inspect
-
- def inspect # :nodoc:
- if @contents.empty?
- return real_inspect
- end
-
- unless (last = @contents.pop)[1].equal?(self)
- @contents.push last
- last = nil
- end
- str = @contents.collect{|no, val|
- if val.equal?(self)
- "#{no} ...self-history..."
- else
- "#{no} #{val.inspect}"
- end
- }.join("\n")
- if str == ""
- str = "Empty."
- end
- @contents.push last if last
- str
- end
- end
-end
diff --git a/lib/irb/ext/loader.rb b/lib/irb/ext/loader.rb
deleted file mode 100644
index df5aaa8e5a..0000000000
--- a/lib/irb/ext/loader.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-# frozen_string_literal: true
-#
-# loader.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
- # Raised in the event of an exception in a file loaded from an Irb session
- class LoadAbort < Exception;end
-
- # Provides a few commands for loading files within an irb session.
- #
- # See ExtendCommandBundle for more information.
- module IrbLoader
-
- alias ruby_load load
- alias ruby_require require
-
- # Loads the given file similarly to Kernel#load
- def irb_load(fn, priv = nil)
- path = search_file_from_ruby_path(fn)
- raise LoadError, "No such file to load -- #{fn}" unless path
-
- load_file(path, priv)
- end
-
- def search_file_from_ruby_path(fn) # :nodoc:
- if File.absolute_path?(fn)
- return fn if File.exist?(fn)
- return nil
- end
-
- for path in $:
- if File.exist?(f = File.join(path, fn))
- return f
- end
- end
- return nil
- end
-
- # Loads a given file in the current session and displays the source lines
- #
- # See Irb#suspend_input_method for more information.
- def source_file(path)
- irb = irb_context.irb
- irb.suspend_name(path, File.basename(path)) do
- FileInputMethod.open(path) do |io|
- irb.suspend_input_method(io) do
- |back_io|
- irb.signal_status(:IN_LOAD) do
- if back_io.kind_of?(FileInputMethod)
- irb.eval_input
- else
- begin
- irb.eval_input
- rescue LoadAbort
- print "load abort!!\n"
- end
- end
- end
- end
- end
- end
- end
-
- # Loads the given file in the current session's context and evaluates it.
- #
- # See Irb#suspend_input_method for more information.
- def load_file(path, priv = nil)
- irb = irb_context.irb
- irb.suspend_name(path, File.basename(path)) do
-
- if priv
- ws = WorkSpace.new(Module.new)
- else
- ws = WorkSpace.new
- end
- irb.suspend_workspace(ws) do
- FileInputMethod.open(path) do |io|
- irb.suspend_input_method(io) do
- |back_io|
- irb.signal_status(:IN_LOAD) do
- if back_io.kind_of?(FileInputMethod)
- irb.eval_input
- else
- begin
- irb.eval_input
- rescue LoadAbort
- print "load abort!!\n"
- end
- end
- end
- end
- end
- end
- end
- end
-
- def old # :nodoc:
- back_io = @io
- back_path = irb_path
- back_name = @irb_name
- back_scanner = @irb.scanner
- begin
- @io = FileInputMethod.new(path)
- @irb_name = File.basename(path)
- self.irb_path = path
- @irb.signal_status(:IN_LOAD) do
- if back_io.kind_of?(FileInputMethod)
- @irb.eval_input
- else
- begin
- @irb.eval_input
- rescue LoadAbort
- print "load abort!!\n"
- end
- end
- end
- ensure
- @io = back_io
- @irb_name = back_name
- self.irb_path = back_path
- @irb.scanner = back_scanner
- end
- end
- end
-end
diff --git a/lib/irb/ext/multi-irb.rb b/lib/irb/ext/multi-irb.rb
deleted file mode 100644
index 9f234f0cdc..0000000000
--- a/lib/irb/ext/multi-irb.rb
+++ /dev/null
@@ -1,258 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/multi-irb.rb - multiple irb module
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- class JobManager # :nodoc:
-
- # Creates a new JobManager object
- def initialize
- @jobs = []
- @current_job = nil
- end
-
- # The active irb session
- attr_accessor :current_job
-
- # The total number of irb sessions, used to set +irb_name+ of the current
- # Context.
- def n_jobs
- @jobs.size
- end
-
- # Returns the thread for the given +key+ object, see #search for more
- # information.
- def thread(key)
- th, = search(key)
- th
- end
-
- # Returns the irb session for the given +key+ object, see #search for more
- # information.
- def irb(key)
- _, irb = search(key)
- irb
- end
-
- # Returns the top level thread.
- def main_thread
- @jobs[0][0]
- end
-
- # Returns the top level irb session.
- def main_irb
- @jobs[0][1]
- end
-
- # Add the given +irb+ session to the jobs Array.
- def insert(irb)
- @jobs.push [Thread.current, irb]
- end
-
- # Changes the current active irb session to the given +key+ in the jobs
- # Array.
- #
- # Raises an IrbAlreadyDead exception if the given +key+ is no longer alive.
- #
- # If the given irb session is already active, an IrbSwitchedToCurrentThread
- # exception is raised.
- def switch(key)
- th, irb = search(key)
- fail IrbAlreadyDead unless th.alive?
- fail IrbSwitchedToCurrentThread if th == Thread.current
- @current_job = irb
- th.run
- Thread.stop
- @current_job = irb(Thread.current)
- end
-
- # Terminates the irb sessions specified by the given +keys+.
- #
- # Raises an IrbAlreadyDead exception if one of the given +keys+ is already
- # terminated.
- #
- # See Thread#exit for more information.
- def kill(*keys)
- for key in keys
- th, _ = search(key)
- fail IrbAlreadyDead unless th.alive?
- th.exit
- end
- end
-
- # Returns the associated job for the given +key+.
- #
- # If given an Integer, it will return the +key+ index for the jobs Array.
- #
- # When an instance of Irb is given, it will return the irb session
- # associated with +key+.
- #
- # If given an instance of Thread, it will return the associated thread
- # +key+ using Object#=== on the jobs Array.
- #
- # Otherwise returns the irb session with the same top-level binding as the
- # given +key+.
- #
- # Raises a NoSuchJob exception if no job can be found with the given +key+.
- def search(key)
- job = case key
- when Integer
- @jobs[key]
- when Irb
- @jobs.find{|k, v| v.equal?(key)}
- when Thread
- @jobs.assoc(key)
- else
- @jobs.find{|k, v| v.context.main.equal?(key)}
- end
- fail NoSuchJob, key if job.nil?
- job
- end
-
- # Deletes the job at the given +key+.
- def delete(key)
- case key
- when Integer
- fail NoSuchJob, key unless @jobs[key]
- @jobs[key] = nil
- else
- catch(:EXISTS) do
- @jobs.each_index do
- |i|
- if @jobs[i] and (@jobs[i][0] == key ||
- @jobs[i][1] == key ||
- @jobs[i][1].context.main.equal?(key))
- @jobs[i] = nil
- throw :EXISTS
- end
- end
- fail NoSuchJob, key
- end
- end
- until assoc = @jobs.pop; end unless @jobs.empty?
- @jobs.push assoc
- end
-
- # Outputs a list of jobs, see the irb command +irb_jobs+, or +jobs+.
- def inspect
- ary = []
- @jobs.each_index do
- |i|
- th, irb = @jobs[i]
- next if th.nil?
-
- if th.alive?
- if th.stop?
- t_status = "stop"
- else
- t_status = "running"
- end
- else
- t_status = "exited"
- end
- ary.push format("#%d->%s on %s (%s: %s)",
- i,
- irb.context.irb_name,
- irb.context.main,
- th,
- t_status)
- end
- ary.join("\n")
- end
- end
-
- @JobManager = JobManager.new
-
- # The current JobManager in the session
- def IRB.JobManager # :nodoc:
- @JobManager
- end
-
- # The current Context in this session
- def IRB.CurrentContext # :nodoc:
- IRB.JobManager.irb(Thread.current).context
- end
-
- # Creates a new IRB session, see Irb.new.
- #
- # The optional +file+ argument is given to Context.new, along with the
- # workspace created with the remaining arguments, see WorkSpace.new
- def IRB.irb(file = nil, *main) # :nodoc:
- workspace = WorkSpace.new(*main)
- parent_thread = Thread.current
- Thread.start do
- begin
- irb = Irb.new(workspace, file)
- rescue
- print "Subirb can't start with context(self): ", workspace.main.inspect, "\n"
- print "return to main irb\n"
- Thread.pass
- Thread.main.wakeup
- Thread.exit
- end
- @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
- @JobManager.insert(irb)
- @JobManager.current_job = irb
- begin
- system_exit = false
- catch(:IRB_EXIT) do
- irb.eval_input
- end
- rescue SystemExit
- system_exit = true
- raise
- #fail
- ensure
- unless system_exit
- @JobManager.delete(irb)
- if @JobManager.current_job == irb
- if parent_thread.alive?
- @JobManager.current_job = @JobManager.irb(parent_thread)
- parent_thread.run
- else
- @JobManager.current_job = @JobManager.main_irb
- @JobManager.main_thread.run
- end
- end
- end
- end
- end
- Thread.stop
- @JobManager.current_job = @JobManager.irb(Thread.current)
- end
-
- @CONF[:SINGLE_IRB_MODE] = false
- @JobManager.insert(@CONF[:MAIN_CONTEXT].irb)
- @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb
-
- class Irb
- def signal_handle
- unless @context.ignore_sigint?
- print "\nabort!!\n" if @context.verbose?
- exit
- end
-
- case @signal_status
- when :IN_INPUT
- print "^C\n"
- IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput
- when :IN_EVAL
- IRB.irb_abort(self)
- when :IN_LOAD
- IRB.irb_abort(self, LoadAbort)
- when :IN_IRB
- # ignore
- else
- # ignore other cases as well
- end
- end
- end
-
- trap("SIGINT") do
- @JobManager.current_job.signal_handle
- Thread.stop
- end
-
-end
diff --git a/lib/irb/ext/tracer.rb b/lib/irb/ext/tracer.rb
deleted file mode 100644
index fd6daa88ae..0000000000
--- a/lib/irb/ext/tracer.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/lib/tracer.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-# Loading the gem "tracer" will cause it to extend IRB commands with:
-# https://github.com/ruby/tracer/blob/v0.2.2/lib/tracer/irb.rb
-begin
- require "tracer"
-rescue LoadError
- $stderr.puts "Tracer extension of IRB is enabled but tracer gem wasn't found."
- return # This is about to disable loading below
-end
-
-module IRB
- class CallTracer < ::CallTracer
- IRB_DIR = File.expand_path('../..', __dir__)
-
- def skip?(tp)
- super || tp.path.match?(IRB_DIR) || tp.path.match?('<internal:prelude>')
- end
- end
- class WorkSpace
- alias __evaluate__ evaluate
- # Evaluate the context of this workspace and use the Tracer library to
- # output the exact lines of code are being executed in chronological order.
- #
- # See https://github.com/ruby/tracer for more information.
- def evaluate(statements, file = __FILE__, line = __LINE__)
- if IRB.conf[:USE_TRACER] == true
- CallTracer.new(colorize: Color.colorable?).start do
- __evaluate__(statements, file, line)
- end
- else
- __evaluate__(statements, file, line)
- end
- end
- end
-end
diff --git a/lib/irb/ext/use-loader.rb b/lib/irb/ext/use-loader.rb
deleted file mode 100644
index c8a3ea1fe8..0000000000
--- a/lib/irb/ext/use-loader.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-#
-# use-loader.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative "../command/load"
-require_relative "loader"
-
-class Object
- alias __original__load__IRB_use_loader__ load
- alias __original__require__IRB_use_loader__ require
-end
-
-module IRB
- module ExtendCommandBundle
- remove_method :irb_load if method_defined?(:irb_load)
- # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
- def irb_load(*opts, &b)
- Command::Load.execute(irb_context, *opts, &b)
- end
- remove_method :irb_require if method_defined?(:irb_require)
- # Loads the given file similarly to Kernel#require
- def irb_require(*opts, &b)
- Command::Require.execute(irb_context, *opts, &b)
- end
- end
-
- class Context
-
- IRB.conf[:USE_LOADER] = false
-
- # Returns whether +irb+'s own file reader method is used by
- # +load+/+require+ or not.
- #
- # This mode is globally affected (irb-wide).
- def use_loader
- IRB.conf[:USE_LOADER]
- end
-
- alias use_loader? use_loader
-
- remove_method :use_loader= if method_defined?(:use_loader=)
- # Sets <code>IRB.conf[:USE_LOADER]</code>
- #
- # See #use_loader for more information.
- def use_loader=(opt)
-
- if IRB.conf[:USE_LOADER] != opt
- IRB.conf[:USE_LOADER] = opt
- if opt
- (class<<workspace.main;self;end).instance_eval {
- alias_method :load, :irb_load
- alias_method :require, :irb_require
- }
- else
- (class<<workspace.main;self;end).instance_eval {
- alias_method :load, :__original__load__IRB_use_loader__
- alias_method :require, :__original__require__IRB_use_loader__
- }
- end
- end
- print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose?
- opt
- end
- end
-end
diff --git a/lib/irb/ext/workspaces.rb b/lib/irb/ext/workspaces.rb
deleted file mode 100644
index da09faa83e..0000000000
--- a/lib/irb/ext/workspaces.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-#
-# push-ws.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
- class Context
- # Creates a new workspace with the given object or binding, and appends it
- # onto the current #workspaces stack.
- #
- # See IRB::Context#change_workspace and IRB::WorkSpace.new for more
- # information.
- def push_workspace(*_main)
- if _main.empty?
- if @workspace_stack.size > 1
- # swap the top two workspaces
- previous_workspace, current_workspace = @workspace_stack.pop(2)
- @workspace_stack.push current_workspace, previous_workspace
- end
- else
- new_workspace = WorkSpace.new(workspace.binding, _main[0])
- @workspace_stack.push new_workspace
- new_workspace.load_helper_methods_to_main
- end
- end
-
- # Removes the last element from the current #workspaces stack and returns
- # it, or +nil+ if the current workspace stack is empty.
- #
- # Also, see #push_workspace.
- def pop_workspace
- @workspace_stack.pop if @workspace_stack.size > 1
- end
- end
-end
diff --git a/lib/irb/frame.rb b/lib/irb/frame.rb
deleted file mode 100644
index 4b697c8719..0000000000
--- a/lib/irb/frame.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-#
-# frame.rb -
-# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd)
-#
-
-module IRB
- class Frame
- class FrameOverflow < StandardError
- def initialize
- super("frame overflow")
- end
- end
- class FrameUnderflow < StandardError
- def initialize
- super("frame underflow")
- end
- end
-
- # Default number of stack frames
- INIT_STACK_TIMES = 3
- # Default number of frames offset
- CALL_STACK_OFFSET = 3
-
- # Creates a new stack frame
- def initialize
- @frames = [TOPLEVEL_BINDING] * INIT_STACK_TIMES
- end
-
- # Used by Kernel#set_trace_func to register each event in the call stack
- def trace_func(event, file, line, id, binding)
- case event
- when 'call', 'class'
- @frames.push binding
- when 'return', 'end'
- @frames.pop
- end
- end
-
- # Returns the +n+ number of frames on the call stack from the last frame
- # initialized.
- #
- # Raises FrameUnderflow if there are no frames in the given stack range.
- def top(n = 0)
- bind = @frames[-(n + CALL_STACK_OFFSET)]
- fail FrameUnderflow unless bind
- bind
- end
-
- # Returns the +n+ number of frames on the call stack from the first frame
- # initialized.
- #
- # Raises FrameOverflow if there are no frames in the given stack range.
- def bottom(n = 0)
- bind = @frames[n]
- fail FrameOverflow unless bind
- bind
- end
-
- # Convenience method for Frame#bottom
- def Frame.bottom(n = 0)
- @backtrace.bottom(n)
- end
-
- # Convenience method for Frame#top
- def Frame.top(n = 0)
- @backtrace.top(n)
- end
-
- # Returns the binding context of the caller from the last frame initialized
- def Frame.sender
- eval "self", @backtrace.top
- end
-
- @backtrace = Frame.new
- set_trace_func proc{|event, file, line, id, binding, klass|
- @backtrace.trace_func(event, file, line, id, binding)
- }
- end
-end
diff --git a/lib/irb/help.rb b/lib/irb/help.rb
deleted file mode 100644
index a24bc10a15..0000000000
--- a/lib/irb/help.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/help.rb - print usage module
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- # Outputs the irb help message, see IRB@Command-Line+Options.
- def IRB.print_usage # :nodoc:
- lc = IRB.conf[:LC_MESSAGES]
- path = lc.find("irb/help-message")
- space_line = false
- File.open(path){|f|
- f.each_line do |l|
- if /^\s*$/ =~ l
- lc.puts l unless space_line
- space_line = true
- next
- end
- space_line = false
-
- l.sub!(/#.*$/, "")
- next if /^\s*$/ =~ l
- lc.puts l
- end
- }
- end
-end
diff --git a/lib/irb/helper_method.rb b/lib/irb/helper_method.rb
deleted file mode 100644
index f1f6fff915..0000000000
--- a/lib/irb/helper_method.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative "helper_method/base"
-
-module IRB
- module HelperMethod
- @helper_methods = {}
-
- class << self
- attr_reader :helper_methods
-
- def register(name, helper_class)
- @helper_methods[name] = helper_class
-
- if defined?(HelpersContainer)
- HelpersContainer.install_helper_methods
- end
- end
-
- def all_helper_methods_info
- @helper_methods.map do |name, helper_class|
- { display_name: name, description: helper_class.description }
- end
- end
- end
-
- # Default helper_methods
- require_relative "helper_method/conf"
- register(:conf, HelperMethod::Conf)
- end
-end
diff --git a/lib/irb/helper_method/base.rb b/lib/irb/helper_method/base.rb
deleted file mode 100644
index a68001ed28..0000000000
--- a/lib/irb/helper_method/base.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require "singleton"
-
-module IRB
- module HelperMethod
- class Base
- include Singleton
-
- class << self
- def description(description = nil)
- @description = description if description
- @description
- end
- end
- end
- end
-end
diff --git a/lib/irb/helper_method/conf.rb b/lib/irb/helper_method/conf.rb
deleted file mode 100644
index 718ed279c0..0000000000
--- a/lib/irb/helper_method/conf.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module IRB
- module HelperMethod
- class Conf < Base
- description "Returns the current IRB context."
-
- def execute
- IRB.CurrentContext
- end
- end
- end
-end
diff --git a/lib/irb/history.rb b/lib/irb/history.rb
deleted file mode 100644
index 0beff15539..0000000000
--- a/lib/irb/history.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-require "pathname"
-
-module IRB
- module History
- DEFAULT_ENTRY_LIMIT = 1000
-
- class << self
- # Integer representation of <code>IRB.conf[:HISTORY_FILE]</code>.
- def save_history
- return 0 if IRB.conf[:SAVE_HISTORY] == false
- return DEFAULT_ENTRY_LIMIT if IRB.conf[:SAVE_HISTORY] == true
- IRB.conf[:SAVE_HISTORY].to_i
- end
-
- def save_history?
- !save_history.zero?
- end
-
- def infinite?
- save_history.negative?
- end
-
- # Might be nil when HOME and XDG_CONFIG_HOME are not available.
- def history_file
- if (history_file = IRB.conf[:HISTORY_FILE])
- File.expand_path(history_file)
- else
- IRB.rc_file("_history")
- end
- end
- end
- end
-
- module HistorySavingAbility # :nodoc:
- def support_history_saving?
- true
- end
-
- def reset_history_counter
- @loaded_history_lines = self.class::HISTORY.size
- end
-
- def load_history
- history_file = History.history_file
- return unless File.exist?(history_file.to_s)
-
- history = self.class::HISTORY
-
- File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
- f.each { |l|
- l = l.chomp
- if self.class == RelineInputMethod and history.last&.end_with?("\\")
- history.last.delete_suffix!("\\")
- history.last << "\n" << l
- else
- history << l
- end
- }
- end
- @loaded_history_lines = history.size
- @loaded_history_mtime = File.mtime(history_file)
- end
-
- def save_history
- return unless History.save_history?
- return unless (history_file = History.history_file)
- unless ensure_history_file_writable(history_file)
- warn <<~WARN
- Can't write history to #{History.history_file.inspect} due to insufficient permissions.
- Please verify the value of `IRB.conf[:HISTORY_FILE]`. Ensure the folder exists and that both the folder and file (if it exists) are writable.
- WARN
- return
- end
-
- history = self.class::HISTORY.to_a
-
- if File.exist?(history_file) &&
- File.mtime(history_file) != @loaded_history_mtime
- history = history[@loaded_history_lines..-1] if @loaded_history_lines
- append_history = true
- end
-
- File.open(history_file, (append_history ? "a" : "w"), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
- hist = history.map { |l| l.scrub.split("\n").join("\\\n") }
-
- unless append_history || History.infinite?
- # Check size before slicing because array.last(huge_number) raises RangeError.
- hist = hist.last(History.save_history) if hist.size > History.save_history
- end
-
- f.puts(hist)
- end
- end
-
- private
-
- # Returns boolean whether writing to +history_file+ will be possible.
- # Permissions of already existing +history_file+ are changed to
- # owner-only-readable if necessary [BUG #7694].
- def ensure_history_file_writable(history_file)
- history_file = Pathname.new(history_file)
-
- return false unless history_file.dirname.writable?
- return true unless history_file.exist?
-
- begin
- if history_file.stat.mode & 0o66 != 0
- history_file.chmod 0o600
- end
- true
- rescue Errno::EPERM # no permissions
- false
- end
- end
- end
-end
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
deleted file mode 100644
index 720c4fec46..0000000000
--- a/lib/irb/init.rb
+++ /dev/null
@@ -1,540 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/init.rb - irb initialize module
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
- @CONF = {}
- @INITIALIZED = false
- # Displays current configuration.
- #
- # Modifying the configuration is achieved by sending a message to IRB.conf.
- #
- # See IRB@Configuration for more information.
- def IRB.conf
- @CONF
- end
-
- def @CONF.inspect
- array = []
- for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
- case k
- when :MAIN_CONTEXT, :__TMP__EHV__
- array.push format("CONF[:%s]=...myself...", k.id2name)
- when :PROMPT
- s = v.collect{
- |kk, vv|
- ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
- format(":%s=>{%s}", kk.id2name, ss.join(", "))
- }
- array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
- else
- array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
- end
- end
- array.join("\n")
- end
-
- # Returns the current version of IRB, including release version and last
- # updated date.
- def IRB.version
- format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
- end
-
- def IRB.initialized?
- !!@INITIALIZED
- end
-
- # initialize config
- def IRB.setup(ap_path, argv: ::ARGV)
- IRB.init_config(ap_path)
- IRB.init_error
- IRB.parse_opts(argv: argv)
- IRB.run_config
- IRB.validate_config
- IRB.load_modules
-
- unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]]
- fail UndefinedPromptMode, @CONF[:PROMPT_MODE]
- end
- @INITIALIZED = true
- end
-
- # @CONF default setting
- def IRB.init_config(ap_path)
- # default configurations
- unless ap_path and @CONF[:AP_NAME]
- ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb")
- end
- @CONF[:VERSION] = version
- @CONF[:AP_NAME] = File::basename(ap_path, ".rb")
-
- @CONF[:IRB_NAME] = "irb"
- @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__)
-
- @CONF[:RC] = true
- @CONF[:LOAD_MODULES] = []
- @CONF[:IRB_RC] = nil
-
- @CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
- @CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
- @CONF[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "true") != "false"
- @CONF[:COMPLETOR] = ENV["IRB_COMPLETOR"]&.to_sym
- @CONF[:INSPECT_MODE] = true
- @CONF[:USE_TRACER] = false
- @CONF[:USE_LOADER] = false
- @CONF[:IGNORE_SIGINT] = true
- @CONF[:IGNORE_EOF] = false
- @CONF[:USE_PAGER] = true
- @CONF[:EXTRA_DOC_DIRS] = []
- @CONF[:ECHO] = nil
- @CONF[:ECHO_ON_ASSIGNMENT] = nil
- @CONF[:VERBOSE] = nil
-
- @CONF[:EVAL_HISTORY] = nil
- @CONF[:SAVE_HISTORY] = History::DEFAULT_ENTRY_LIMIT
-
- @CONF[:BACK_TRACE_LIMIT] = 16
-
- @CONF[:PROMPT] = {
- :NULL => {
- :PROMPT_I => nil,
- :PROMPT_S => nil,
- :PROMPT_C => nil,
- :RETURN => "%s\n"
- },
- :DEFAULT => {
- :PROMPT_I => "%N(%m):%03n> ",
- :PROMPT_S => "%N(%m):%03n%l ",
- :PROMPT_C => "%N(%m):%03n* ",
- :RETURN => "=> %s\n"
- },
- :CLASSIC => {
- :PROMPT_I => "%N(%m):%03n:%i> ",
- :PROMPT_S => "%N(%m):%03n:%i%l ",
- :PROMPT_C => "%N(%m):%03n:%i* ",
- :RETURN => "%s\n"
- },
- :SIMPLE => {
- :PROMPT_I => ">> ",
- :PROMPT_S => "%l> ",
- :PROMPT_C => "?> ",
- :RETURN => "=> %s\n"
- },
- :INF_RUBY => {
- :PROMPT_I => "%N(%m):%03n> ",
- :PROMPT_S => nil,
- :PROMPT_C => nil,
- :RETURN => "%s\n",
- :AUTO_INDENT => true
- },
- :XMP => {
- :PROMPT_I => nil,
- :PROMPT_S => nil,
- :PROMPT_C => nil,
- :RETURN => " ==>%s\n"
- }
- }
-
- @CONF[:PROMPT_MODE] = (STDIN.tty? ? :DEFAULT : :NULL)
- @CONF[:AUTO_INDENT] = true
-
- @CONF[:CONTEXT_MODE] = 4 # use a copy of TOPLEVEL_BINDING
- @CONF[:SINGLE_IRB] = false
-
- @CONF[:MEASURE] = false
- @CONF[:MEASURE_PROC] = {}
- @CONF[:MEASURE_PROC][:TIME] = proc { |context, code, line_no, &block|
- time = Time.now
- result = block.()
- now = Time.now
- puts 'processing time: %fs' % (now - time) if IRB.conf[:MEASURE]
- result
- }
- # arg can be either a symbol for the mode (:cpu, :wall, ..) or a hash for
- # a more complete configuration.
- # See https://github.com/tmm1/stackprof#all-options.
- @CONF[:MEASURE_PROC][:STACKPROF] = proc { |context, code, line_no, arg, &block|
- return block.() unless IRB.conf[:MEASURE]
- success = false
- begin
- require 'stackprof'
- success = true
- rescue LoadError
- puts 'Please run "gem install stackprof" before measuring by StackProf.'
- end
- if success
- result = nil
- arg = { mode: arg || :cpu } unless arg.is_a?(Hash)
- stackprof_result = StackProf.run(**arg) do
- result = block.()
- end
- case stackprof_result
- when File
- puts "StackProf report saved to #{stackprof_result.path}"
- when Hash
- StackProf::Report.new(stackprof_result).print_text
- else
- puts "Stackprof ran with #{arg.inspect}"
- end
- result
- else
- block.()
- end
- }
- @CONF[:MEASURE_CALLBACKS] = []
-
- @CONF[:LC_MESSAGES] = Locale.new
-
- @CONF[:AT_EXIT] = []
-
- @CONF[:COMMAND_ALIASES] = {
- # Symbol aliases
- :'$' => :show_source,
- :'@' => :whereami,
- }
-
- @CONF[:COPY_COMMAND] = ENV.fetch("IRB_COPY_COMMAND", nil)
- end
-
- def IRB.set_measure_callback(type = nil, arg = nil, &block)
- added = nil
- if type
- type_sym = type.upcase.to_sym
- if IRB.conf[:MEASURE_PROC][type_sym]
- added = [type_sym, IRB.conf[:MEASURE_PROC][type_sym], arg]
- end
- elsif IRB.conf[:MEASURE_PROC][:CUSTOM]
- added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM], arg]
- elsif block_given?
- added = [:BLOCK, block, arg]
- found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
- if found
- found[1] = block
- return added
- else
- IRB.conf[:MEASURE_CALLBACKS] << added
- return added
- end
- else
- added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg]
- end
- if added
- IRB.conf[:MEASURE] = true
- found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
- if found
- # already added
- nil
- else
- IRB.conf[:MEASURE_CALLBACKS] << added if added
- added
- end
- else
- nil
- end
- end
-
- def IRB.unset_measure_callback(type = nil)
- if type.nil?
- IRB.conf[:MEASURE_CALLBACKS].clear
- else
- type_sym = type.upcase.to_sym
- IRB.conf[:MEASURE_CALLBACKS].reject!{ |t, | t == type_sym }
- end
- IRB.conf[:MEASURE] = nil if IRB.conf[:MEASURE_CALLBACKS].empty?
- end
-
- def IRB.init_error
- @CONF[:LC_MESSAGES].load("irb/error.rb")
- end
-
- # option analyzing
- def IRB.parse_opts(argv: ::ARGV)
- load_path = []
- while opt = argv.shift
- case opt
- when "-f"
- @CONF[:RC] = false
- when "-d"
- $DEBUG = true
- $VERBOSE = true
- when "-w"
- Warning[:deprecated] = $VERBOSE = true
- when /^-W(.+)?/
- opt = $1 || argv.shift
- case opt
- when "0"
- $VERBOSE = nil
- when "1"
- $VERBOSE = false
- else
- Warning[:deprecated] = $VERBOSE = true
- end
- when /^-r(.+)?/
- opt = $1 || argv.shift
- @CONF[:LOAD_MODULES].push opt if opt
- when /^-I(.+)?/
- opt = $1 || argv.shift
- load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt
- when '-U'
- set_encoding("UTF-8", "UTF-8")
- when /^-E(.+)?/, /^--encoding(?:=(.+))?/
- opt = $1 || argv.shift
- set_encoding(*opt.split(':', 2))
- when "--inspect"
- if /^-/ !~ argv.first
- @CONF[:INSPECT_MODE] = argv.shift
- else
- @CONF[:INSPECT_MODE] = true
- end
- when "--noinspect"
- @CONF[:INSPECT_MODE] = false
- when "--no-pager"
- @CONF[:USE_PAGER] = false
- when "--singleline", "--readline", "--legacy"
- @CONF[:USE_SINGLELINE] = true
- when "--nosingleline", "--noreadline"
- @CONF[:USE_SINGLELINE] = false
- when "--multiline", "--reidline"
- if opt == "--reidline"
- warn <<~MSG.strip
- --reidline is deprecated, please use --multiline instead.
- MSG
- end
-
- @CONF[:USE_MULTILINE] = true
- when "--nomultiline", "--noreidline"
- if opt == "--noreidline"
- warn <<~MSG.strip
- --noreidline is deprecated, please use --nomultiline instead.
- MSG
- end
-
- @CONF[:USE_MULTILINE] = false
- when /^--extra-doc-dir(?:=(.+))?/
- opt = $1 || argv.shift
- @CONF[:EXTRA_DOC_DIRS] << opt
- when "--echo"
- @CONF[:ECHO] = true
- when "--noecho"
- @CONF[:ECHO] = false
- when "--echo-on-assignment"
- @CONF[:ECHO_ON_ASSIGNMENT] = true
- when "--noecho-on-assignment"
- @CONF[:ECHO_ON_ASSIGNMENT] = false
- when "--truncate-echo-on-assignment"
- @CONF[:ECHO_ON_ASSIGNMENT] = :truncate
- when "--verbose"
- @CONF[:VERBOSE] = true
- when "--noverbose"
- @CONF[:VERBOSE] = false
- when "--colorize"
- @CONF[:USE_COLORIZE] = true
- when "--nocolorize"
- @CONF[:USE_COLORIZE] = false
- when "--autocomplete"
- @CONF[:USE_AUTOCOMPLETE] = true
- when "--noautocomplete"
- @CONF[:USE_AUTOCOMPLETE] = false
- when "--regexp-completor"
- @CONF[:COMPLETOR] = :regexp
- when "--type-completor"
- @CONF[:COMPLETOR] = :type
- when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/
- opt = $1 || argv.shift
- prompt_mode = opt.upcase.tr("-", "_").intern
- @CONF[:PROMPT_MODE] = prompt_mode
- when "--noprompt"
- @CONF[:PROMPT_MODE] = :NULL
- when "--script"
- noscript = false
- when "--noscript"
- noscript = true
- when "--inf-ruby-mode"
- @CONF[:PROMPT_MODE] = :INF_RUBY
- when "--sample-book-mode", "--simple-prompt"
- @CONF[:PROMPT_MODE] = :SIMPLE
- when "--tracer"
- @CONF[:USE_TRACER] = true
- when /^--back-trace-limit(?:=(.+))?/
- @CONF[:BACK_TRACE_LIMIT] = ($1 || argv.shift).to_i
- when /^--context-mode(?:=(.+))?/
- @CONF[:CONTEXT_MODE] = ($1 || argv.shift).to_i
- when "--single-irb"
- @CONF[:SINGLE_IRB] = true
- when "-v", "--version"
- print IRB.version, "\n"
- exit 0
- when "-h", "--help"
- require_relative "help"
- IRB.print_usage
- exit 0
- when "--"
- if !noscript && (opt = argv.shift)
- @CONF[:SCRIPT] = opt
- $0 = opt
- end
- break
- when /^-./
- fail UnrecognizedSwitch, opt
- else
- if noscript
- argv.unshift(opt)
- else
- @CONF[:SCRIPT] = opt
- $0 = opt
- end
- break
- end
- end
-
- load_path.collect! do |path|
- /\A\.\// =~ path ? path : File.expand_path(path)
- end
- $LOAD_PATH.unshift(*load_path)
- end
-
- # Run the config file
- def IRB.run_config
- if @CONF[:RC]
- irbrc_files.each do |rc|
- load rc
- rescue StandardError, ScriptError => e
- warn "Error loading RC file '#{rc}':\n#{e.full_message(highlight: false)}"
- end
- end
- end
-
- IRBRC_EXT = "rc"
-
- def IRB.rc_file(ext)
- prepare_irbrc_name_generators
-
- # When irbrc exist in default location
- if (rcgen = @existing_rc_name_generators.first)
- return rcgen.call(ext)
- end
-
- # When irbrc does not exist in default location
- rc_file_generators do |rcgen|
- return rcgen.call(ext)
- end
-
- # When HOME and XDG_CONFIG_HOME are not available
- nil
- end
-
- def IRB.irbrc_files
- prepare_irbrc_name_generators
- @irbrc_files
- end
-
- def IRB.validate_config
- conf[:IRB_NAME] = conf[:IRB_NAME].to_s
-
- irb_rc = conf[:IRB_RC]
- unless irb_rc.nil? || irb_rc.respond_to?(:call)
- raise_validation_error "IRB.conf[:IRB_RC] should be a callable object. Got #{irb_rc.inspect}."
- end
-
- back_trace_limit = conf[:BACK_TRACE_LIMIT]
- unless back_trace_limit.is_a?(Integer)
- raise_validation_error "IRB.conf[:BACK_TRACE_LIMIT] should be an integer. Got #{back_trace_limit.inspect}."
- end
-
- prompt = conf[:PROMPT]
- unless prompt.is_a?(Hash)
- msg = "IRB.conf[:PROMPT] should be a Hash. Got #{prompt.inspect}."
-
- if prompt.is_a?(Symbol)
- msg += " Did you mean to set `IRB.conf[:PROMPT_MODE]`?"
- end
-
- raise_validation_error msg
- end
-
- eval_history = conf[:EVAL_HISTORY]
- unless eval_history.nil? || eval_history.is_a?(Integer)
- raise_validation_error "IRB.conf[:EVAL_HISTORY] should be an integer. Got #{eval_history.inspect}."
- end
- end
-
- def IRB.raise_validation_error(msg)
- raise TypeError, msg, @irbrc_files
- end
-
- # loading modules
- def IRB.load_modules
- for m in @CONF[:LOAD_MODULES]
- begin
- require m
- rescue LoadError => err
- warn "#{err.class}: #{err}", uplevel: 0
- end
- end
- end
-
- class << IRB
- private
-
- def prepare_irbrc_name_generators
- return if @existing_rc_name_generators
-
- @existing_rc_name_generators = []
- @irbrc_files = []
- rc_file_generators do |rcgen|
- irbrc = rcgen.call(IRBRC_EXT)
- if File.exist?(irbrc)
- @irbrc_files << irbrc
- @existing_rc_name_generators << rcgen
- end
- end
- generate_current_dir_irbrc_files.each do |irbrc|
- @irbrc_files << irbrc if File.exist?(irbrc)
- end
- @irbrc_files.uniq!
- end
-
- # enumerate possible rc-file base name generators
- def rc_file_generators
- if irbrc = ENV["IRBRC"]
- yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
- end
- if xdg_config_home = ENV["XDG_CONFIG_HOME"]
- irb_home = File.join(xdg_config_home, "irb")
- if File.directory?(irb_home)
- yield proc{|rc| irb_home + "/irb#{rc}"}
- end
- end
- if home = ENV["HOME"]
- yield proc{|rc| home+"/.irb#{rc}"}
- if xdg_config_home.nil? || xdg_config_home.empty?
- yield proc{|rc| home+"/.config/irb/irb#{rc}"}
- end
- end
- end
-
- # possible irbrc files in current directory
- def generate_current_dir_irbrc_files
- current_dir = Dir.pwd
- %w[.irbrc irbrc _irbrc $irbrc].map { |file| "#{current_dir}/#{file}" }
- end
-
- def set_encoding(extern, intern = nil, override: true)
- verbose, $VERBOSE = $VERBOSE, nil
- Encoding.default_external = extern unless extern.nil? || extern.empty?
- Encoding.default_internal = intern unless intern.nil? || intern.empty?
- [$stdin, $stdout, $stderr].each do |io|
- io.set_encoding(extern, intern)
- end
- if override
- @CONF[:LC_MESSAGES].instance_variable_set(:@override_encoding, extern)
- else
- @CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern)
- end
- ensure
- $VERBOSE = verbose
- end
- end
-end
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
deleted file mode 100644
index 260d9a1cbf..0000000000
--- a/lib/irb/input-method.rb
+++ /dev/null
@@ -1,515 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/input-method.rb - input methods used irb
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative 'completion'
-require_relative "history"
-require 'io/console'
-require 'reline'
-
-module IRB
- class InputMethod
- BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
-
- # The irb prompt associated with this input method
- attr_accessor :prompt
-
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- fail NotImplementedError
- end
- public :gets
-
- def winsize
- if instance_variable_defined?(:@stdout) && @stdout.tty?
- @stdout.winsize
- else
- [24, 80]
- end
- end
-
- # Whether this input method is still readable when there is no more data to
- # read.
- #
- # See IO#eof for more information.
- def readable_after_eof?
- false
- end
-
- def support_history_saving?
- false
- end
-
- def prompting?
- false
- end
-
- # For debug message
- def inspect
- 'Abstract InputMethod'
- end
- end
-
- class StdioInputMethod < InputMethod
- # Creates a new input method object
- def initialize
- @line_no = 0
- @line = []
- @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
- @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
- end
-
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- # Workaround for debug compatibility test https://github.com/ruby/debug/pull/1100
- puts if ENV['RUBY_DEBUG_TEST_UI']
-
- print @prompt
- line = @stdin.gets
- @line[@line_no += 1] = line
- end
-
- # Whether the end of this input method has been reached, returns +true+ if
- # there is no more data to read.
- #
- # See IO#eof? for more information.
- def eof?
- if @stdin.wait_readable(0.00001)
- c = @stdin.getc
- result = c.nil? ? true : false
- @stdin.ungetc(c) unless c.nil?
- result
- else # buffer is empty
- false
- end
- end
-
- # Whether this input method is still readable when there is no more data to
- # read.
- #
- # See IO#eof for more information.
- def readable_after_eof?
- true
- end
-
- def prompting?
- STDIN.tty?
- end
-
- # Returns the current line number for #io.
- #
- # #line counts the number of times #gets is called.
- #
- # See IO#lineno for more information.
- def line(line_no)
- @line[line_no]
- end
-
- # The external encoding for standard input.
- def encoding
- @stdin.external_encoding
- end
-
- # For debug message
- def inspect
- 'StdioInputMethod'
- end
- end
-
- # Use a File for IO with irb, see InputMethod
- class FileInputMethod < InputMethod
- class << self
- def open(file, &block)
- begin
- io = new(file)
- block.call(io)
- ensure
- io&.close
- end
- end
- end
-
- # Creates a new input method object
- def initialize(file)
- @io = file.is_a?(IO) ? file : File.open(file)
- @external_encoding = @io.external_encoding
- end
-
- # Whether the end of this input method has been reached, returns +true+ if
- # there is no more data to read.
- #
- # See IO#eof? for more information.
- def eof?
- @io.closed? || @io.eof?
- end
-
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- print @prompt
- @io.gets
- end
-
- # The external encoding for standard input.
- def encoding
- @external_encoding
- end
-
- # For debug message
- def inspect
- 'FileInputMethod'
- end
-
- def close
- @io.close
- end
- end
-
- class ReadlineInputMethod < StdioInputMethod
- class << self
- def initialize_readline
- require "readline"
- rescue LoadError
- else
- include ::Readline
- end
- end
-
- include HistorySavingAbility
-
- # Creates a new input method object using Readline
- def initialize
- self.class.initialize_readline
- if Readline.respond_to?(:encoding_system_needs)
- IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
- end
-
- super
-
- @eof = false
- @completor = RegexpCompletor.new
-
- if Readline.respond_to?("basic_word_break_characters=")
- Readline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
- end
- Readline.completion_append_character = nil
- Readline.completion_proc = ->(target) {
- bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
- @completor.completion_candidates('', target, '', bind: bind)
- }
- end
-
- def completion_info
- 'RegexpCompletor'
- end
-
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- Readline.input = @stdin
- Readline.output = @stdout
- if l = readline(@prompt, false)
- HISTORY.push(l) if !l.empty?
- @line[@line_no += 1] = l + "\n"
- else
- @eof = true
- l
- end
- end
-
- # Whether the end of this input method has been reached, returns +true+
- # if there is no more data to read.
- #
- # See IO#eof? for more information.
- def eof?
- @eof
- end
-
- def prompting?
- true
- end
-
- # For debug message
- def inspect
- readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline'
- str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}"
- inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
- str += " and #{inputrc_path}" if File.exist?(inputrc_path)
- str
- end
- end
-
- class RelineInputMethod < StdioInputMethod
- HISTORY = Reline::HISTORY
- include HistorySavingAbility
- # Creates a new input method object using Reline
- def initialize(completor)
- IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)
-
- super()
-
- @eof = false
- @completor = completor
-
- Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
- Reline.completion_append_character = nil
- Reline.completer_quote_characters = ''
- Reline.completion_proc = ->(target, preposing, postposing) {
- bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
- @completion_params = [preposing, target, postposing, bind]
- @completor.completion_candidates(preposing, target, postposing, bind: bind)
- }
- Reline.output_modifier_proc = proc do |input, complete:|
- IRB.CurrentContext.colorize_input(input, complete: complete)
- end
- Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
- Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
-
- if IRB.conf[:USE_AUTOCOMPLETE]
- begin
- require 'rdoc'
- Reline.add_dialog_proc(:show_doc, show_doc_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
- rescue LoadError
- end
- end
- end
-
- def completion_info
- autocomplete_message = Reline.autocompletion ? 'Autocomplete' : 'Tab Complete'
- "#{autocomplete_message}, #{@completor.inspect}"
- end
-
- def check_termination(&block)
- @check_termination_proc = block
- end
-
- def dynamic_prompt(&block)
- @prompt_proc = block
- end
-
- def auto_indent(&block)
- @auto_indent_proc = block
- end
-
- def retrieve_doc_namespace(matched)
- preposing, _target, postposing, bind = @completion_params
- @completor.doc_namespace(preposing, matched, postposing, bind: bind)
- end
-
- def rdoc_ri_driver
- return @rdoc_ri_driver if defined?(@rdoc_ri_driver)
-
- begin
- require 'rdoc'
- rescue LoadError
- @rdoc_ri_driver = nil
- else
- options = {}
- options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
- @rdoc_ri_driver = RDoc::RI::Driver.new(options)
- end
- end
-
- def show_doc_dialog_proc
- input_method = self # self is changed in the lambda below.
- ->() {
- dialog.trap_key = nil
- alt_d = [
- [27, 100], # Normal Alt+d when convert-meta isn't used.
- # When option/alt is not configured as a meta key in terminal emulator,
- # option/alt + d will send a unicode character depend on OS keyboard setting.
- [195, 164], # "ä" in somewhere (FIXME: environment information is unknown).
- [226, 136, 130] # "∂" Alt+d on Mac keyboard.
- ]
-
- if just_cursor_moving and completion_journey_data.nil?
- return nil
- end
- cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
- return nil if result.nil? or pointer.nil? or pointer < 0
-
- name = input_method.retrieve_doc_namespace(result[pointer])
- # Use first one because document dialog does not support multiple namespaces.
- name = name.first if name.is_a?(Array)
-
- show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
-
- driver = input_method.rdoc_ri_driver
-
- if key.match?(dialog.name)
- if show_easter_egg
- IRB.__send__(:easter_egg)
- else
- # RDoc::RI::Driver#display_names uses pager command internally.
- # Some pager command like `more` doesn't use alternate screen
- # so we need to turn on and off alternate screen manually.
- begin
- print "\e[?1049h"
- driver.display_names([name])
- rescue RDoc::RI::Driver::NotFoundError
- ensure
- print "\e[?1049l"
- end
- end
- end
-
- begin
- name = driver.expand_name(name)
- rescue RDoc::RI::Driver::NotFoundError
- return nil
- rescue
- return nil # unknown error
- end
- doc = nil
- used_for_class = false
- if not name =~ /#|\./
- found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
- if not found.empty?
- doc = driver.class_document(name, found, klasses, includes, extends)
- used_for_class = true
- end
- end
- unless used_for_class
- doc = RDoc::Markup::Document.new
- begin
- driver.add_method(doc, name)
- rescue RDoc::RI::Driver::NotFoundError
- doc = nil
- rescue
- return nil # unknown error
- end
- end
- return nil if doc.nil?
- width = 40
-
- right_x = cursor_pos_to_render.x + autocomplete_dialog.width
- if right_x + width > screen_width
- right_width = screen_width - (right_x + 1)
- left_x = autocomplete_dialog.column - width
- left_x = 0 if left_x < 0
- left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
- if right_width.positive? and left_width.positive?
- if right_width >= left_width
- width = right_width
- x = right_x
- else
- width = left_width
- x = left_x
- end
- elsif right_width.positive? and left_width <= 0
- width = right_width
- x = right_x
- elsif right_width <= 0 and left_width.positive?
- width = left_width
- x = left_x
- else # Both are negative width.
- return nil
- end
- else
- x = right_x
- end
- formatter = RDoc::Markup::ToAnsi.new
- formatter.width = width
- dialog.trap_key = alt_d
- mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
- if show_easter_egg
- type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
- contents = IRB.send(:easter_egg_logo, type).split("\n")
- message = "Press #{mod_key}+d to see more"
- contents[0][0, message.size] = message
- else
- message = "Press #{mod_key}+d to read the full document"
- contents = [message] + doc.accept(formatter).split("\n")
- end
- contents = contents.take(preferred_dialog_height)
-
- y = cursor_pos_to_render.y
- Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
- }
- end
-
- def display_document(matched)
- driver = rdoc_ri_driver
- return unless driver
-
- if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
- IRB.__send__(:easter_egg)
- return
- end
-
- namespace = retrieve_doc_namespace(matched)
- return unless namespace
-
- if namespace.is_a?(Array)
- out = RDoc::Markup::Document.new
- namespace.each do |m|
- begin
- driver.add_method(out, m)
- rescue RDoc::RI::Driver::NotFoundError
- end
- end
- driver.display(out)
- else
- begin
- driver.display_names([namespace])
- rescue RDoc::RI::Driver::NotFoundError
- end
- end
- end
-
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- Reline.input = @stdin
- Reline.output = @stdout
- Reline.prompt_proc = @prompt_proc
- Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
- if l = Reline.readmultiline(@prompt, false, &@check_termination_proc)
- Reline::HISTORY.push(l) if !l.empty?
- @line[@line_no += 1] = l + "\n"
- else
- @eof = true
- l
- end
- end
-
- # Whether the end of this input method has been reached, returns +true+
- # if there is no more data to read.
- #
- # See IO#eof? for more information.
- def eof?
- @eof
- end
-
- def prompting?
- true
- end
-
- # For debug message
- def inspect
- config = Reline::Config.new
- str = "RelineInputMethod with Reline #{Reline::VERSION}"
- inputrc_path = File.expand_path(config.inputrc_path)
- str += " and #{inputrc_path}" if File.exist?(inputrc_path)
- str
- end
- end
-
- class ReidlineInputMethod < RelineInputMethod
- def initialize
- warn <<~MSG.strip
- IRB::ReidlineInputMethod is deprecated, please use IRB::RelineInputMethod instead.
- MSG
- super
- end
- end
-end
diff --git a/lib/irb/inspector.rb b/lib/irb/inspector.rb
deleted file mode 100644
index 75a257b4ba..0000000000
--- a/lib/irb/inspector.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/inspector.rb - inspect methods
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
-
- # Convenience method to create a new Inspector, using the given +inspect+
- # proc, and optional +init+ proc and passes them to Inspector.new
- #
- # irb(main):001:0> ins = IRB::Inspector(proc{ |v| "omg! #{v}" })
- # irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! #<IRB::Inspector:0x007f46f7ba7d28>
- # irb(main):001:0> "what?" #=> omg! what?
- #
- def IRB::Inspector(inspect, init = nil)
- Inspector.new(inspect, init)
- end
-
- # An irb inspector
- #
- # In order to create your own custom inspector there are two things you
- # should be aware of:
- #
- # Inspector uses #inspect_value, or +inspect_proc+, for output of return values.
- #
- # This also allows for an optional #init+, or +init_proc+, which is called
- # when the inspector is activated.
- #
- # Knowing this, you can create a rudimentary inspector as follows:
- #
- # irb(main):001:0> ins = IRB::Inspector.new(proc{ |v| "omg! #{v}" })
- # irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! #<IRB::Inspector:0x007f46f7ba7d28>
- # irb(main):001:0> "what?" #=> omg! what?
- #
- class Inspector
- KERNEL_INSPECT = Object.instance_method(:inspect)
- # Default inspectors available to irb, this includes:
- #
- # +:pp+:: Using Kernel#pretty_inspect
- # +:yaml+:: Using YAML.dump
- # +:marshal+:: Using Marshal.dump
- INSPECTORS = {}
-
- class << self
- # Determines the inspector to use where +inspector+ is one of the keys passed
- # during inspector definition.
- def keys_with_inspector(inspector)
- INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k}
- end
-
- # Example
- #
- # Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
- # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
- # Inspector.def_inspector(key, inspector)
- # Inspector.def_inspector([key1,...], inspector)
- def def_inspector(key, arg=nil, &block)
- if block_given?
- inspector = IRB::Inspector(block, arg)
- else
- inspector = arg
- end
-
- case key
- when Array
- for k in key
- def_inspector(k, inspector)
- end
- when Symbol
- INSPECTORS[key] = inspector
- INSPECTORS[key.to_s] = inspector
- when String
- INSPECTORS[key] = inspector
- INSPECTORS[key.intern] = inspector
- else
- INSPECTORS[key] = inspector
- end
- end
- end
-
- # Creates a new inspector object, using the given +inspect_proc+ when
- # output return values in irb.
- def initialize(inspect_proc, init_proc = nil)
- @init = init_proc
- @inspect = inspect_proc
- end
-
- # Proc to call when the inspector is activated, good for requiring
- # dependent libraries.
- def init
- @init.call if @init
- end
-
- def support_stream_output?
- second_parameter_type = @inspect.parameters[1]&.first
- second_parameter_type == :req || second_parameter_type == :opt
- end
-
- # Proc to call when the input is evaluated and output in irb.
- def inspect_value(v, output, colorize: true)
- support_stream_output? ? @inspect.call(v, output, colorize: colorize) : output << @inspect.call(v, colorize: colorize)
- rescue => e
- puts "An error occurred when inspecting the object: #{e.inspect}"
-
- begin
- puts "Result of Kernel#inspect: #{KERNEL_INSPECT.bind_call(v)}"
- ''
- rescue => e
- puts "An error occurred when running Kernel#inspect: #{e.inspect}"
- puts e.backtrace.join("\n")
- ''
- end
- end
- end
-
- Inspector.def_inspector([false, :to_s, :raw]){|v| v.to_s}
- Inspector.def_inspector([:p, :inspect]){|v, colorize: true|
- Color.colorize_code(v.inspect, colorable: colorize && Color.colorable? && Color.inspect_colorable?(v))
- }
- Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require_relative "color_printer"}){|v, output, colorize: true|
- IRB::ColorPrinter.pp(v, output, colorize: colorize)
- }
- Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v|
- begin
- YAML.dump(v)
- rescue
- puts "(can't dump yaml. use inspect)"
- v.inspect
- end
- }
-
- Inspector.def_inspector([:marshal, :Marshal, :MARSHAL, Marshal]){|v|
- Marshal.dump(v)
- }
-end
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
deleted file mode 100644
index 9a93382b7a..0000000000
--- a/lib/irb/irb.gemspec
+++ /dev/null
@@ -1,46 +0,0 @@
-begin
- require_relative "lib/irb/version"
-rescue LoadError
- # for Ruby core repository
- require_relative "version"
-end
-
-Gem::Specification.new do |spec|
- spec.name = "irb"
- spec.version = IRB::VERSION
- spec.authors = ["aycabta", "Keiju ISHITSUKA"]
-
- spec.summary = %q{Interactive Ruby command-line tool for REPL (Read Eval Print Loop).}
- spec.description = %q{Interactive Ruby command-line tool for REPL (Read Eval Print Loop).}
- spec.homepage = "https://github.com/ruby/irb"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
- spec.metadata["documentation_uri"] = "https://ruby.github.io/irb/"
- spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
-
- spec.files = [
- "Gemfile",
- "LICENSE.txt",
- "README.md",
- "Rakefile",
- "bin/console",
- "bin/setup",
- "doc/irb/irb-tools.rd.ja",
- "doc/irb/irb.rd.ja",
- "exe/irb",
- "irb.gemspec",
- "man/irb.1",
- ] + Dir.glob("lib/**/*")
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7")
-
- spec.add_dependency "reline", ">= 0.4.2"
- spec.add_dependency "rdoc", ">= 4.0.0"
- spec.add_dependency "pp", ">= 0.6.0"
-end
diff --git a/lib/irb/lc/error.rb b/lib/irb/lc/error.rb
deleted file mode 100644
index ee0f047822..0000000000
--- a/lib/irb/lc/error.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/lc/error.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- # :stopdoc:
-
- class UnrecognizedSwitch < StandardError
- def initialize(val)
- super("Unrecognized switch: #{val}")
- end
- end
- class CantReturnToNormalMode < StandardError
- def initialize
- super("Can't return to normal mode.")
- end
- end
- class IllegalParameter < StandardError
- def initialize(val)
- super("Invalid parameter(#{val}).")
- end
- end
- class IrbAlreadyDead < StandardError
- def initialize
- super("Irb is already dead.")
- end
- end
- class IrbSwitchedToCurrentThread < StandardError
- def initialize
- super("Switched to current thread.")
- end
- end
- class NoSuchJob < StandardError
- def initialize(val)
- super("No such job(#{val}).")
- end
- end
- class CantChangeBinding < StandardError
- def initialize(val)
- super("Can't change binding to (#{val}).")
- end
- end
- class UndefinedPromptMode < StandardError
- def initialize(val)
- super("Undefined prompt mode(#{val}).")
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/lc/help-message b/lib/irb/lc/help-message
deleted file mode 100644
index 37347306e8..0000000000
--- a/lib/irb/lc/help-message
+++ /dev/null
@@ -1,55 +0,0 @@
-Usage: irb.rb [options] [programfile] [arguments]
- -f Don't initialize from configuration file.
- -d Set $DEBUG and $VERBOSE to true (same as 'ruby -d').
- -r load-module Require load-module (same as 'ruby -r').
- -I path Specify $LOAD_PATH directory (same as 'ruby -I').
- -U Set external and internal encodings to UTF-8.
- -E ex[:in] Set default external (ex) and internal (in) encodings
- (same as 'ruby -E').
- -w Suppress warnings (same as 'ruby -w').
- -W[level=2] Set warning level: 0=silence, 1=medium, 2=verbose
- (same as 'ruby -W').
- --context-mode n Set n[0-4] to method to create Binding Object,
- when new workspace was created.
- --extra-doc-dir Add an extra doc dir for the doc dialog.
- --echo Show result (default).
- --noecho Don't show result.
- --echo-on-assignment
- Show result on assignment.
- --noecho-on-assignment
- Don't show result on assignment.
- --truncate-echo-on-assignment
- Show truncated result on assignment (default).
- --inspect Use 'inspect' for output.
- --noinspect Don't use 'inspect' for output.
- --no-pager Don't use pager.
- --multiline Use multiline editor module (default).
- --nomultiline Don't use multiline editor module.
- --singleline Use single line editor module.
- --nosingleline Don't use single line editor module (default).
- --colorize Use color-highlighting (default).
- --nocolorize Don't use color-highlighting.
- --autocomplete Use auto-completion (default).
- --noautocomplete Don't use auto-completion.
- --regexp-completor
- Use regexp based completion (default).
- --type-completor Use type based completion.
- --prompt prompt-mode, --prompt-mode prompt-mode
- Set prompt mode. Pre-defined prompt modes are:
- 'default', 'classic', 'simple', 'inf-ruby', 'xmp', 'null'.
- --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
- Suppresses --multiline and --singleline.
- --sample-book-mode, --simple-prompt
- Set prompt mode to 'simple'.
- --noprompt Don't output prompt.
- --script Script mode (default, treat first argument as script)
- --noscript No script mode (leave arguments in argv)
- --single-irb Share self with sub-irb.
- --tracer Show stack trace for each command.
- --back-trace-limit n[=16]
- Display backtrace top n and bottom n.
- --verbose Show details.
- --noverbose Don't show details.
- -v, --version Print the version of irb.
- -h, --help Print help.
- -- Separate options of irb from the list of command-line args.
diff --git a/lib/irb/lc/ja/error.rb b/lib/irb/lc/ja/error.rb
deleted file mode 100644
index 9e2e5b8870..0000000000
--- a/lib/irb/lc/ja/error.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/lc/ja/error.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- # :stopdoc:
-
- class UnrecognizedSwitch < StandardError
- def initialize(val)
- super("スイッチ(#{val})が分りません")
- end
- end
- class CantReturnToNormalMode < StandardError
- def initialize
- super("Normalモードに戻れません.")
- end
- end
- class IllegalParameter < StandardError
- def initialize(val)
- super("パラメータ(#{val})が間違っています.")
- end
- end
- class IrbAlreadyDead < StandardError
- def initialize
- super("Irbは既に死んでいます.")
- end
- end
- class IrbSwitchedToCurrentThread < StandardError
- def initialize
- super("カレントスレッドに切り替わりました.")
- end
- end
- class NoSuchJob < StandardError
- def initialize(val)
- super("そのようなジョブ(#{val})はありません.")
- end
- end
- class CantChangeBinding < StandardError
- def initialize(val)
- super("バインディング(#{val})に変更できません.")
- end
- end
- class UndefinedPromptMode < StandardError
- def initialize(val)
- super("プロンプトモード(#{val})は定義されていません.")
- end
- end
-
- # :startdoc:
-end
-# vim:fileencoding=utf-8
diff --git a/lib/irb/lc/ja/help-message b/lib/irb/lc/ja/help-message
deleted file mode 100644
index 844c67bbba..0000000000
--- a/lib/irb/lc/ja/help-message
+++ /dev/null
@@ -1,58 +0,0 @@
-Usage: irb.rb [options] [programfile] [arguments]
- -f ~/.irbrc を読み込まない.
- -d $DEBUG をtrueにする(ruby -d と同じ)
- -r load-module ruby -r と同じ.
- -I path $LOAD_PATH に path を追加する.
- -U ruby -U と同じ.
- -E enc ruby -E と同じ.
- -w ruby -w と同じ.
- -W[level=2] ruby -W と同じ.
- --context-mode n 新しいワークスペースを作成した時に関連する Binding
- オブジェクトの作成方法を 0 から 4 のいずれかに設定する.
- --extra-doc-dir 指定したディレクトリのドキュメントを追加で読み込む.
- --echo 実行結果を表示する(デフォルト).
- --noecho 実行結果を表示しない.
- --echo-on-assignment
- 代入結果を表示する.
- --noecho-on-assignment
- 代入結果を表示しない.
- --truncate-echo-on-assignment
- truncateされた代入結果を表示する(デフォルト).
- --inspect 結果出力にinspectを用いる.
- --noinspect 結果出力にinspectを用いない.
- --no-pager ページャを使用しない.
- --multiline マルチラインエディタを利用する.
- --nomultiline マルチラインエディタを利用しない.
- --singleline シングルラインエディタを利用する.
- --nosingleline シングルラインエディタを利用しない.
- --colorize 色付けを利用する.
- --nocolorize 色付けを利用しない.
- --autocomplete オートコンプリートを利用する.
- --noautocomplete オートコンプリートを利用しない.
- --regexp-completor
- 補完に正規表現を利用する.
- --type-completor 補完に型情報を利用する.
- --prompt prompt-mode/--prompt-mode prompt-mode
- プロンプトモードを切り替える.
- 現在定義されているプロンプトモードは,
- default, classic, simple, inf-ruby, xmp, null.
- --inf-ruby-mode emacsのinf-ruby-mode用のプロンプト表示を行なう. 特
- に指定がない限り, シングルラインエディタとマルチラ
- インエディタは使わなくなる.
- --sample-book-mode/--simple-prompt
- 非常にシンプルなプロンプトを用いるモードです.
- --noprompt プロンプト表示を行なわない.
- --script スクリプトモード(最初の引数をスクリプトファイルとして扱う、デフォルト)
- --noscript 引数をargvとして扱う.
- --single-irb irb 中で self を実行して得られるオブジェクトをサ
- ブ irb と共有する.
- --tracer コマンド実行時にトレースを行なう.
- --back-trace-limit n
- バックトレース表示をバックトレースの頭から n, 後ろ
- からnだけ行なう. デフォルトは16
-
- --verbose 詳細なメッセージを出力する.
- --noverbose 詳細なメッセージを出力しない(デフォルト).
- -v, --version irbのバージョンを表示する.
- -h, --help irb のヘルプを表示する.
- -- 以降のコマンドライン引数をオプションとして扱わない.
diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb
deleted file mode 100644
index 2abcc7354b..0000000000
--- a/lib/irb/locale.rb
+++ /dev/null
@@ -1,153 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/locale.rb - internationalization module
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
- class Locale
-
- LOCALE_NAME_RE = %r[
- (?<language>[[:alpha:]]{2,3})
- (?:_ (?<territory>[[:alpha:]]{2,3}) )?
- (?:\. (?<codeset>[^@]+) )?
- (?:@ (?<modifier>.*) )?
- ]x
- LOCALE_DIR = "/lc/"
-
- LEGACY_ENCODING_ALIAS_MAP = {
- 'ujis' => Encoding::EUC_JP,
- 'euc' => Encoding::EUC_JP
- }
-
- @@loaded = []
-
- def initialize(locale = nil)
- @override_encoding = nil
- @lang = @territory = @encoding_name = @modifier = nil
- @locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C"
- if m = LOCALE_NAME_RE.match(@locale)
- @lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier]
-
- if @encoding_name
- if @encoding = LEGACY_ENCODING_ALIAS_MAP[@encoding_name]
- warn(("%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]), uplevel: 1)
- else
- @encoding = Encoding.find(@encoding_name) rescue nil
- end
- end
- end
- @encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
- end
-
- attr_reader :lang, :territory, :modifier
-
- def encoding
- @override_encoding || @encoding
- end
-
- def String(mes)
- mes = super(mes)
- if encoding
- mes.encode(encoding, undef: :replace)
- else
- mes
- end
- end
-
- def format(*opts)
- String(super(*opts))
- end
-
- def gets(*rs)
- String(super(*rs))
- end
-
- def readline(*rs)
- String(super(*rs))
- end
-
- def print(*opts)
- ary = opts.collect{|opt| String(opt)}
- super(*ary)
- end
-
- def printf(*opts)
- s = format(*opts)
- print s
- end
-
- def puts(*opts)
- ary = opts.collect{|opt| String(opt)}
- super(*ary)
- end
-
- def load(file)
- found = find(file)
- if found
- unless @@loaded.include?(found)
- @@loaded << found # cache
- Kernel.load(found)
- end
- else
- raise LoadError, "No such file to load -- #{file}"
- end
- end
-
- def find(file, paths = $:)
- dir = File.dirname(file)
- dir = "" if dir == "."
- base = File.basename(file)
-
- if dir.start_with?('/')
- return each_localized_path(dir, base).find{|full_path| File.readable? full_path}
- else
- return search_file(paths, dir, base)
- end
- end
-
- # @param paths load paths in which IRB find a localized file.
- # @param dir directory
- # @param file basename to be localized
- #
- # typically, for the parameters and a <path> in paths, it searches
- # <path>/<dir>/<locale>/<file>
- def search_file(lib_paths, dir, file)
- each_localized_path(dir, file) do |lc_path|
- lib_paths.each do |libpath|
- full_path = File.join(libpath, lc_path)
- return full_path if File.readable?(full_path)
- end
- redo if defined?(Gem) and Gem.try_activate(lc_path)
- end
- nil
- end
-
- def each_localized_path(dir, file)
- return enum_for(:each_localized_path) unless block_given?
- each_sublocale do |lc|
- yield lc.nil? ? File.join(dir, LOCALE_DIR, file) : File.join(dir, LOCALE_DIR, lc, file)
- end
- end
-
- def each_sublocale
- if @lang
- if @territory
- if @encoding_name
- yield "#{@lang}_#{@territory}.#{@encoding_name}@#{@modifier}" if @modifier
- yield "#{@lang}_#{@territory}.#{@encoding_name}"
- end
- yield "#{@lang}_#{@territory}@#{@modifier}" if @modifier
- yield "#{@lang}_#{@territory}"
- end
- if @encoding_name
- yield "#{@lang}.#{@encoding_name}@#{@modifier}" if @modifier
- yield "#{@lang}.#{@encoding_name}"
- end
- yield "#{@lang}@#{@modifier}" if @modifier
- yield "#{@lang}"
- end
- yield nil
- end
- end
-end
diff --git a/lib/irb/nesting_parser.rb b/lib/irb/nesting_parser.rb
deleted file mode 100644
index c1c9a5cc76..0000000000
--- a/lib/irb/nesting_parser.rb
+++ /dev/null
@@ -1,239 +0,0 @@
-# frozen_string_literal: true
-module IRB
- module NestingParser
- IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
-
- class << self
- # Scan each token and call the given block with array of token and other information for parsing
- def scan_opens(tokens)
- opens = []
- pending_heredocs = []
- first_token_on_line = true
- tokens.each do |t|
- skip = false
- last_tok, state, args = opens.last
- case state
- when :in_alias_undef
- skip = t.event == :on_kw
- when :in_unquoted_symbol
- unless IGNORE_TOKENS.include?(t.event)
- opens.pop
- skip = true
- end
- when :in_lambda_head
- opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
- when :in_method_head
- unless IGNORE_TOKENS.include?(t.event)
- next_args = []
- body = nil
- if args.include?(:receiver)
- case t.event
- when :on_lparen, :on_ivar, :on_gvar, :on_cvar
- # def (receiver). | def @ivar. | def $gvar. | def @@cvar.
- next_args << :dot
- when :on_kw
- case t.tok
- when 'self', 'true', 'false', 'nil'
- # def self(arg) | def self.
- next_args.push(:arg, :dot)
- else
- # def if(arg)
- skip = true
- next_args << :arg
- end
- when :on_op, :on_backtick
- # def +(arg)
- skip = true
- next_args << :arg
- when :on_ident, :on_const
- # def a(arg) | def a.
- next_args.push(:arg, :dot)
- end
- end
- if args.include?(:dot)
- # def receiver.name
- next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
- end
- if args.include?(:name)
- if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
- # def name(arg) | def receiver.name(arg)
- next_args << :arg
- skip = true
- end
- end
- if args.include?(:arg)
- case t.event
- when :on_nl, :on_semicolon
- # def receiver.f;
- body = :normal
- when :on_lparen
- # def receiver.f()
- next_args << :eq
- else
- if t.event == :on_op && t.tok == '='
- # def receiver.f =
- body = :oneliner
- else
- # def receiver.f arg
- next_args << :arg_without_paren
- end
- end
- end
- if args.include?(:eq)
- if t.event == :on_op && t.tok == '='
- body = :oneliner
- else
- body = :normal
- end
- end
- if args.include?(:arg_without_paren)
- if %i[on_semicolon on_nl].include?(t.event)
- # def f a;
- body = :normal
- else
- # def f a, b
- next_args << :arg_without_paren
- end
- end
- if body == :oneliner
- opens.pop
- elsif body
- opens[-1] = [last_tok, nil]
- else
- opens[-1] = [last_tok, :in_method_head, next_args]
- end
- end
- when :in_for_while_until_condition
- if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
- skip = true if t.event == :on_kw && t.tok == 'do'
- opens[-1] = [last_tok, nil]
- end
- end
-
- unless skip
- case t.event
- when :on_kw
- case t.tok
- when 'begin', 'class', 'module', 'do', 'case'
- opens << [t, nil]
- when 'end'
- opens.pop
- when 'def'
- opens << [t, :in_method_head, [:receiver, :name]]
- when 'if', 'unless'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens << [t, nil]
- end
- when 'while', 'until'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens << [t, :in_for_while_until_condition]
- end
- when 'ensure', 'rescue'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens.pop
- opens << [t, nil]
- end
- when 'alias'
- opens << [t, :in_alias_undef, 2]
- when 'undef'
- opens << [t, :in_alias_undef, 1]
- when 'elsif', 'else', 'when'
- opens.pop
- opens << [t, nil]
- when 'for'
- opens << [t, :in_for_while_until_condition]
- when 'in'
- if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
- opens.pop
- opens << [t, nil]
- end
- end
- when :on_tlambda
- opens << [t, :in_lambda_head]
- when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
- opens << [t, nil]
- when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
- opens.pop
- when :on_heredoc_beg
- pending_heredocs << t
- when :on_heredoc_end
- opens.pop
- when :on_backtick
- opens << [t, nil] unless t.state == Ripper::EXPR_ARG
- when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
- opens << [t, nil]
- when :on_tstring_end, :on_regexp_end, :on_label_end
- opens.pop
- when :on_symbeg
- if t.tok == ':'
- opens << [t, :in_unquoted_symbol]
- else
- opens << [t, nil]
- end
- end
- end
- if t.event == :on_nl || t.event == :on_semicolon
- first_token_on_line = true
- elsif t.event != :on_sp
- first_token_on_line = false
- end
- if pending_heredocs.any? && t.tok.include?("\n")
- pending_heredocs.reverse_each { |t| opens << [t, nil] }
- pending_heredocs = []
- end
- if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
- tok, state, arg = opens.pop
- opens << [tok, state, arg - 1] if arg >= 1
- end
- yield t, opens if block_given?
- end
- opens.map(&:first) + pending_heredocs.reverse
- end
-
- def open_tokens(tokens)
- # scan_opens without block will return a list of open tokens at last token position
- scan_opens(tokens)
- end
-
- # Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
- # Example code
- # ["hello
- # world"+(
- # First line
- # line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
- # prev_opens: []
- # next_tokens: [lbracket, tstring_beg]
- # min_depth: 0 (minimum at beginning of line)
- # Second line
- # line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
- # prev_opens: [lbracket, tstring_beg]
- # next_tokens: [lbracket, lparen]
- # min_depth: 1 (minimum just after tstring_end)
- def parse_by_line(tokens)
- line_tokens = []
- prev_opens = []
- min_depth = 0
- output = []
- last_opens = scan_opens(tokens) do |t, opens|
- depth = t == opens.last&.first ? opens.size - 1 : opens.size
- min_depth = depth if depth < min_depth
- if t.tok.include?("\n")
- t.tok.each_line do |line|
- line_tokens << [t, line]
- next if line[-1] != "\n"
- next_opens = opens.map(&:first)
- output << [line_tokens, prev_opens, next_opens, min_depth]
- prev_opens = next_opens
- min_depth = prev_opens.size
- line_tokens = []
- end
- else
- line_tokens << [t, t.tok]
- end
- end
- output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
- output
- end
- end
- end
-end
diff --git a/lib/irb/notifier.rb b/lib/irb/notifier.rb
deleted file mode 100644
index dc1b9ef14b..0000000000
--- a/lib/irb/notifier.rb
+++ /dev/null
@@ -1,230 +0,0 @@
-# frozen_string_literal: true
-#
-# notifier.rb - output methods used by irb
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative "output-method"
-
-module IRB
- # An output formatter used internally by the lexer.
- module Notifier
- class ErrUndefinedNotifier < StandardError
- def initialize(val)
- super("undefined notifier level: #{val} is specified")
- end
- end
- class ErrUnrecognizedLevel < StandardError
- def initialize(val)
- super("unrecognized notifier level: #{val} is specified")
- end
- end
-
- # Define a new Notifier output source, returning a new CompositeNotifier
- # with the given +prefix+ and +output_method+.
- #
- # The optional +prefix+ will be appended to all objects being inspected
- # during output, using the given +output_method+ as the output source. If
- # no +output_method+ is given, StdioOutputMethod will be used, and all
- # expressions will be sent directly to STDOUT without any additional
- # formatting.
- def def_notifier(prefix = "", output_method = StdioOutputMethod.new)
- CompositeNotifier.new(prefix, output_method)
- end
- module_function :def_notifier
-
- # An abstract class, or superclass, for CompositeNotifier and
- # LeveledNotifier to inherit. It provides several wrapper methods for the
- # OutputMethod object used by the Notifier.
- class AbstractNotifier
- # Creates a new Notifier object
- def initialize(prefix, base_notifier)
- @prefix = prefix
- @base_notifier = base_notifier
- end
-
- # The +prefix+ for this Notifier, which is appended to all objects being
- # inspected during output.
- attr_reader :prefix
-
- # A wrapper method used to determine whether notifications are enabled.
- #
- # Defaults to +true+.
- def notify?
- true
- end
-
- # See OutputMethod#print for more detail.
- def print(*opts)
- @base_notifier.print prefix, *opts if notify?
- end
-
- # See OutputMethod#printn for more detail.
- def printn(*opts)
- @base_notifier.printn prefix, *opts if notify?
- end
-
- # See OutputMethod#printf for more detail.
- def printf(format, *opts)
- @base_notifier.printf(prefix + format, *opts) if notify?
- end
-
- # See OutputMethod#puts for more detail.
- def puts(*objs)
- if notify?
- @base_notifier.puts(*objs.collect{|obj| prefix + obj.to_s})
- end
- end
-
- # Same as #ppx, except it uses the #prefix given during object
- # initialization.
- # See OutputMethod#ppx for more detail.
- def pp(*objs)
- if notify?
- @base_notifier.ppx @prefix, *objs
- end
- end
-
- # Same as #pp, except it concatenates the given +prefix+ with the #prefix
- # given during object initialization.
- #
- # See OutputMethod#ppx for more detail.
- def ppx(prefix, *objs)
- if notify?
- @base_notifier.ppx @prefix+prefix, *objs
- end
- end
-
- # Execute the given block if notifications are enabled.
- def exec_if
- yield(@base_notifier) if notify?
- end
- end
-
- # A class that can be used to create a group of notifier objects with the
- # intent of representing a leveled notification system for irb.
- #
- # This class will allow you to generate other notifiers, and assign them
- # the appropriate level for output.
- #
- # The Notifier class provides a class-method Notifier.def_notifier to
- # create a new composite notifier. Using the first composite notifier
- # object you create, sibling notifiers can be initialized with
- # #def_notifier.
- class CompositeNotifier < AbstractNotifier
- # Create a new composite notifier object with the given +prefix+, and
- # +base_notifier+ to use for output.
- def initialize(prefix, base_notifier)
- super
-
- @notifiers = [D_NOMSG]
- @level_notifier = D_NOMSG
- end
-
- # List of notifiers in the group
- attr_reader :notifiers
-
- # Creates a new LeveledNotifier in the composite #notifiers group.
- #
- # The given +prefix+ will be assigned to the notifier, and +level+ will
- # be used as the index of the #notifiers Array.
- #
- # This method returns the newly created instance.
- def def_notifier(level, prefix = "")
- notifier = LeveledNotifier.new(self, level, prefix)
- @notifiers[level] = notifier
- notifier
- end
-
- # Returns the leveled notifier for this object
- attr_reader :level_notifier
- alias level level_notifier
-
- # Sets the leveled notifier for this object.
- #
- # When the given +value+ is an instance of AbstractNotifier,
- # #level_notifier is set to the given object.
- #
- # When an Integer is given, #level_notifier is set to the notifier at the
- # index +value+ in the #notifiers Array.
- #
- # If no notifier exists at the index +value+ in the #notifiers Array, an
- # ErrUndefinedNotifier exception is raised.
- #
- # An ErrUnrecognizedLevel exception is raised if the given +value+ is not
- # found in the existing #notifiers Array, or an instance of
- # AbstractNotifier
- def level_notifier=(value)
- case value
- when AbstractNotifier
- @level_notifier = value
- when Integer
- l = @notifiers[value]
- raise ErrUndefinedNotifier, value unless l
- @level_notifier = l
- else
- raise ErrUnrecognizedLevel, value unless l
- end
- end
-
- alias level= level_notifier=
- end
-
- # A leveled notifier is comparable to the composite group from
- # CompositeNotifier#notifiers.
- class LeveledNotifier < AbstractNotifier
- include Comparable
-
- # Create a new leveled notifier with the given +base+, and +prefix+ to
- # send to AbstractNotifier.new
- #
- # The given +level+ is used to compare other leveled notifiers in the
- # CompositeNotifier group to determine whether or not to output
- # notifications.
- def initialize(base, level, prefix)
- super(prefix, base)
-
- @level = level
- end
-
- # The current level of this notifier object
- attr_reader :level
-
- # Compares the level of this notifier object with the given +other+
- # notifier.
- #
- # See the Comparable module for more information.
- def <=>(other)
- @level <=> other.level
- end
-
- # Whether to output messages to the output method, depending on the level
- # of this notifier object.
- def notify?
- @base_notifier.level >= self
- end
- end
-
- # NoMsgNotifier is a LeveledNotifier that's used as the default notifier
- # when creating a new CompositeNotifier.
- #
- # This notifier is used as the +zero+ index, or level +0+, for
- # CompositeNotifier#notifiers, and will not output messages of any sort.
- class NoMsgNotifier < LeveledNotifier
- # Creates a new notifier that should not be used to output messages.
- def initialize
- @base_notifier = nil
- @level = 0
- @prefix = ""
- end
-
- # Ensures notifications are ignored, see AbstractNotifier#notify? for
- # more information.
- def notify?
- false
- end
- end
-
- D_NOMSG = NoMsgNotifier.new # :nodoc:
- end
-end
diff --git a/lib/irb/output-method.rb b/lib/irb/output-method.rb
deleted file mode 100644
index 69942f47a2..0000000000
--- a/lib/irb/output-method.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-#
-# output-method.rb - output methods used by irb
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB
- # An abstract output class for IO in irb. This is mainly used internally by
- # IRB::Notifier. You can define your own output method to use with Irb.new,
- # or Context.new
- class OutputMethod
- # Open this method to implement your own output method, raises a
- # NotImplementedError if you don't define #print in your own class.
- def print(*opts)
- raise NotImplementedError
- end
-
- # Prints the given +opts+, with a newline delimiter.
- def printn(*opts)
- print opts.join(" "), "\n"
- end
-
- # Extends IO#printf to format the given +opts+ for Kernel#sprintf using
- # #parse_printf_format
- def printf(format, *opts)
- if /(%*)%I/ =~ format
- format, opts = parse_printf_format(format, opts)
- end
- print sprintf(format, *opts)
- end
-
- # Returns an array of the given +format+ and +opts+ to be used by
- # Kernel#sprintf, if there was a successful Regexp match in the given
- # +format+ from #printf
- #
- # %
- # <flag> [#0- +]
- # <minimum field width> (\*|\*[1-9][0-9]*\$|[1-9][0-9]*)
- # <precision>.(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)?
- # #<length modifier>(hh|h|l|ll|L|q|j|z|t)
- # <conversion specifier>[diouxXeEfgGcsb%]
- def parse_printf_format(format, opts)
- return format, opts if $1.size % 2 == 1
- end
-
- # Calls #print on each element in the given +objs+, followed by a newline
- # character.
- def puts(*objs)
- for obj in objs
- print(*obj)
- print "\n"
- end
- end
-
- # Prints the given +objs+ calling Object#inspect on each.
- #
- # See #puts for more detail.
- def pp(*objs)
- puts(*objs.collect{|obj| obj.inspect})
- end
-
- # Prints the given +objs+ calling Object#inspect on each and appending the
- # given +prefix+.
- #
- # See #puts for more detail.
- def ppx(prefix, *objs)
- puts(*objs.collect{|obj| prefix+obj.inspect})
- end
-
- end
-
- # A standard output printer
- class StdioOutputMethod < OutputMethod
- # Prints the given +opts+ to standard output, see IO#print for more
- # information.
- def print(*opts)
- STDOUT.print(*opts)
- end
- end
-end
diff --git a/lib/irb/pager.rb b/lib/irb/pager.rb
deleted file mode 100644
index 16ff30cf89..0000000000
--- a/lib/irb/pager.rb
+++ /dev/null
@@ -1,213 +0,0 @@
-# frozen_string_literal: true
-
-require 'reline'
-
-module IRB
- # The implementation of this class is borrowed from RDoc's lib/rdoc/ri/driver.rb.
- # Please do NOT use this class directly outside of IRB.
- class Pager
- PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
-
- class << self
- def page_content(content, **options)
- if content_exceeds_screen_height?(content)
- page(**options) do |io|
- io.puts content
- end
- else
- $stdout.puts content
- end
- end
-
- def page(retain_content: false)
- if should_page? && pager = setup_pager(retain_content: retain_content)
- begin
- pid = pager.pid
- yield pager
- ensure
- pager.close
- end
- else
- yield $stdout
- end
- # When user presses Ctrl-C, IRB would raise `IRB::Abort`
- # But since Pager is implemented by running paging commands like `less` in another process with `IO.popen`,
- # the `IRB::Abort` exception only interrupts IRB's execution but doesn't affect the pager
- # So to properly terminate the pager with Ctrl-C, we need to catch `IRB::Abort` and kill the pager process
- rescue IRB::Abort
- begin
- begin
- Process.kill("TERM", pid) if pid
- rescue Errno::EINVAL
- # SIGTERM not supported (windows)
- Process.kill("KILL", pid)
- end
- rescue Errno::ESRCH
- # Pager process already terminated
- end
- nil
- rescue Errno::EPIPE
- end
-
- def should_page?
- IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
- end
-
- def page_with_preview(width, height, formatter_proc)
- overflow_callback = ->(lines) do
- modified_output = formatter_proc.call(lines.join, true)
- content, = take_first_page(width, [height - 2, 0].max) {|o| o.write modified_output }
- content = content.chomp
- content = "#{content}\e[0m" if Color.colorable?
- $stdout.puts content
- $stdout.puts 'Preparing full inspection value...'
- end
- out = PageOverflowIO.new(width, height, overflow_callback, delay: 0.1)
- yield out
- content = formatter_proc.call(out.string, out.multipage?)
- if out.multipage?
- page(retain_content: true) do |io|
- io.puts content
- end
- else
- $stdout.puts content
- end
- end
-
- def take_first_page(width, height)
- overflow_callback = proc do |lines|
- return lines.join, true
- end
- out = Pager::PageOverflowIO.new(width, height, overflow_callback)
- yield out
- [out.string, false]
- end
-
- private
-
- def content_exceeds_screen_height?(content)
- screen_height, screen_width = begin
- Reline.get_screen_size
- rescue Errno::EINVAL
- [24, 80]
- end
-
- pageable_height = screen_height - 3 # leave some space for previous and the current prompt
-
- return true if content.lines.size > pageable_height
-
- _, overflow = take_first_page(screen_width, pageable_height) {|out| out.write content }
- overflow
- end
-
- def setup_pager(retain_content:)
- require 'shellwords'
-
- PAGE_COMMANDS.each do |pager_cmd|
- cmd = Shellwords.split(pager_cmd)
- next if cmd.empty?
-
- if cmd.first == 'less'
- cmd << '-R' unless cmd.include?('-R')
- cmd << '-X' if retain_content && !cmd.include?('-X')
- end
-
- begin
- io = IO.popen(cmd, 'w')
- rescue
- next
- end
-
- if $? && $?.pid == io.pid && $?.exited? # pager didn't work
- next
- end
-
- return io
- end
-
- nil
- end
- end
-
- # Writable IO that has page overflow callback
- class PageOverflowIO
- attr_reader :string, :first_page_lines
-
- # Maximum size of a single cell in terminal
- # Assumed worst case: "\e[1;3;4;9;38;2;255;128;128;48;2;128;128;255mA\e[0m"
- # bold, italic, underline, crossed_out, RGB forgound, RGB background
- MAX_CHAR_PER_CELL = 50
-
- def initialize(width, height, overflow_callback, delay: nil)
- @lines = []
- @first_page_lines = nil
- @width = width
- @height = height
- @buffer = +''
- @overflow_callback = overflow_callback
- @col = 0
- @string = +''
- @multipage = false
- @delay_until = (Time.now + delay if delay)
- end
-
- def puts(text = '')
- text = text.to_s unless text.is_a?(String)
- write(text)
- write("\n") unless text.end_with?("\n")
- end
-
- def write(text)
- text = text.to_s unless text.is_a?(String)
- @string << text
- if @multipage
- if @delay_until && Time.now > @delay_until
- @overflow_callback.call(@first_page_lines)
- @delay_until = nil
- end
- return
- end
-
- overflow_size = (@width * (@height - @lines.size) + @width - @col) * MAX_CHAR_PER_CELL
- if text.size >= overflow_size
- text = text[0, overflow_size]
- overflow = true
- end
- @buffer << text
- @col += Reline::Unicode.calculate_width(text, true)
- if text.include?("\n") || @col >= @width
- @buffer.lines.each do |line|
- wrapped_lines = Reline::Unicode.split_by_width(line.chomp, @width).first.compact
- wrapped_lines.pop if wrapped_lines.last == ''
- @lines.concat(wrapped_lines)
- if line.end_with?("\n")
- if @lines.empty? || @lines.last.end_with?("\n")
- @lines << "\n"
- else
- @lines[-1] += "\n"
- end
- end
- end
- @buffer.clear
- @buffer << @lines.pop unless @lines.last.end_with?("\n")
- @col = Reline::Unicode.calculate_width(@buffer, true)
- end
- if overflow || @lines.size > @height || (@lines.size == @height && @col > 0)
- @first_page_lines = @lines.take(@height)
- if !@delay_until || Time.now > @delay_until
- @overflow_callback.call(@first_page_lines)
- @delay_until = nil
- end
- @multipage = true
- end
- end
-
- def multipage?
- @multipage
- end
-
- alias print write
- alias << write
- end
- end
-end
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
deleted file mode 100644
index 3abb53b4ea..0000000000
--- a/lib/irb/ruby-lex.rb
+++ /dev/null
@@ -1,476 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/ruby-lex.rb - ruby lexcal analyzer
-# by Keiju ISHITSUKA([email protected])
-#
-
-require "ripper"
-require "jruby" if RUBY_ENGINE == "jruby"
-require_relative "nesting_parser"
-
-module IRB
- # :stopdoc:
- class RubyLex
- ASSIGNMENT_NODE_TYPES = [
- # Local, instance, global, class, constant, instance, and index assignment:
- # "foo = bar",
- # "@foo = bar",
- # "$foo = bar",
- # "@@foo = bar",
- # "::Foo = bar",
- # "a::Foo = bar",
- # "Foo = bar"
- # "foo.bar = 1"
- # "foo[1] = bar"
- :assign,
-
- # Operation assignment:
- # "foo += bar"
- # "foo -= bar"
- # "foo ||= bar"
- # "foo &&= bar"
- :opassign,
-
- # Multiple assignment:
- # "foo, bar = 1, 2
- :massign,
- ]
-
- ERROR_TOKENS = [
- :on_parse_error,
- :compile_error,
- :on_assign_error,
- :on_alias_error,
- :on_class_name_error,
- :on_param_error
- ]
-
- LTYPE_TOKENS = %i[
- on_heredoc_beg on_tstring_beg
- on_regexp_beg on_symbeg on_backtick
- on_symbols_beg on_qsymbols_beg
- on_words_beg on_qwords_beg
- ]
-
- class TerminateLineInput < StandardError
- def initialize
- super("Terminate Line Input")
- end
- end
-
- class << self
- def compile_with_errors_suppressed(code, line_no: 1)
- begin
- result = yield code, line_no
- rescue ArgumentError
- # Ruby can issue an error for the code if there is an
- # incomplete magic comment for encoding in it. Force an
- # expression with a new line before the code in this
- # case to prevent magic comment handling. To make sure
- # line numbers in the lexed code remain the same,
- # decrease the line number by one.
- code = ";\n#{code}"
- line_no -= 1
- result = yield code, line_no
- end
- result
- end
-
- def generate_local_variables_assign_code(local_variables)
- "#{local_variables.join('=')}=nil;" unless local_variables.empty?
- end
-
- # Some part of the code is not included in Ripper's token.
- # Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr.
- # With interpolated tokens, tokens.map(&:tok).join will be equal to code.
- def interpolate_ripper_ignored_tokens(code, tokens)
- line_positions = [0]
- code.lines.each do |line|
- line_positions << line_positions.last + line.bytesize
- end
- prev_byte_pos = 0
- interpolated = []
- prev_line = 1
- tokens.each do |t|
- line, col = t.pos
- byte_pos = line_positions[line - 1] + col
- if prev_byte_pos < byte_pos
- tok = code.byteslice(prev_byte_pos...byte_pos)
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
- prev_line += tok.count("\n")
- end
- interpolated << t
- prev_byte_pos = byte_pos + t.tok.bytesize
- prev_line += t.tok.count("\n")
- end
- if prev_byte_pos < code.bytesize
- tok = code.byteslice(prev_byte_pos..)
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
- end
- interpolated
- end
-
- def ripper_lex_without_warning(code, local_variables: [])
- verbose, $VERBOSE = $VERBOSE, nil
- lvars_code = generate_local_variables_assign_code(local_variables)
- original_code = code
- if lvars_code
- code = "#{lvars_code}\n#{code}"
- line_no = 0
- else
- line_no = 1
- end
-
- compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
- lexer = Ripper::Lexer.new(inner_code, '-', line_no)
- tokens = []
- lexer.scan.each do |t|
- next if t.pos.first == 0
- prev_tk = tokens.last
- position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
- if position_overlapped
- tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
- else
- tokens << t
- end
- end
- interpolate_ripper_ignored_tokens(original_code, tokens)
- end
- ensure
- $VERBOSE = verbose
- end
- end
-
- def check_code_state(code, local_variables:)
- tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
- opens = NestingParser.open_tokens(tokens)
- [tokens, opens, code_terminated?(code, tokens, opens, local_variables: local_variables)]
- end
-
- def code_terminated?(code, tokens, opens, local_variables:)
- case check_code_syntax(code, local_variables: local_variables)
- when :unrecoverable_error
- true
- when :recoverable_error
- false
- when :other_error
- opens.empty? && !should_continue?(tokens)
- when :valid
- !should_continue?(tokens)
- end
- end
-
- def assignment_expression?(code, local_variables:)
- # Try to parse the code and check if the last of possibly multiple
- # expressions is an assignment type.
-
- # If the expression is invalid, Ripper.sexp should return nil which will
- # result in false being returned. Any valid expression should return an
- # s-expression where the second element of the top level array is an
- # array of parsed expressions. The first element of each expression is the
- # expression's type.
- verbose, $VERBOSE = $VERBOSE, nil
- code = "#{RubyLex.generate_local_variables_assign_code(local_variables) || 'nil;'}\n#{code}"
- # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
- node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
- ASSIGNMENT_NODE_TYPES.include?(node_type)
- ensure
- $VERBOSE = verbose
- end
-
- def should_continue?(tokens)
- # Look at the last token and check if IRB need to continue reading next line.
- # Example code that should continue: `a\` `a +` `a.`
- # Trailing spaces, newline, comments are skipped
- return true if tokens.last&.event == :on_sp && tokens.last.tok == "\\\n"
-
- tokens.reverse_each do |token|
- case token.event
- when :on_sp, :on_nl, :on_ignored_nl, :on_comment, :on_embdoc_beg, :on_embdoc, :on_embdoc_end
- # Skip
- when :on_regexp_end, :on_heredoc_end, :on_semicolon
- # State is EXPR_BEG but should not continue
- return false
- else
- # Endless range should not continue
- return false if token.event == :on_op && token.tok.match?(/\A\.\.\.?\z/)
-
- # EXPR_DOT and most of the EXPR_BEG should continue
- return token.state.anybits?(Ripper::EXPR_BEG | Ripper::EXPR_DOT)
- end
- end
- false
- end
-
- def check_code_syntax(code, local_variables:)
- lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
- code = "#{lvars_code}\n#{code}"
-
- begin # check if parser error are available
- verbose, $VERBOSE = $VERBOSE, nil
- case RUBY_ENGINE
- when 'ruby'
- self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
- RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no)
- end
- when 'jruby'
- JRuby.compile_ir(code)
- else
- catch(:valid) do
- eval("BEGIN { throw :valid, true }\n#{code}")
- false
- end
- end
- rescue EncodingError
- # This is for a hash with invalid encoding symbol, {"\xAE": 1}
- :unrecoverable_error
- rescue SyntaxError => e
- case e.message
- when /unexpected keyword_end/
- # "syntax error, unexpected keyword_end"
- #
- # example:
- # if (
- # end
- #
- # example:
- # end
- return :unrecoverable_error
- when /unexpected '\.'/
- # "syntax error, unexpected '.'"
- #
- # example:
- # .
- return :unrecoverable_error
- when /unexpected tREGEXP_BEG/
- # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('"
- #
- # example:
- # method / f /
- return :unrecoverable_error
- when /unterminated (?:string|regexp) meets end of file/
- # "unterminated regexp meets end of file"
- #
- # example:
- # /
- #
- # "unterminated string meets end of file"
- #
- # example:
- # '
- return :recoverable_error
- when /unexpected end-of-input/
- # "syntax error, unexpected end-of-input, expecting keyword_end"
- #
- # example:
- # if true
- # hoge
- # if false
- # fuga
- # end
- return :recoverable_error
- else
- return :other_error
- end
- ensure
- $VERBOSE = verbose
- end
- :valid
- end
-
- def calc_indent_level(opens)
- indent_level = 0
- opens.each_with_index do |t, index|
- case t.event
- when :on_heredoc_beg
- if opens[index + 1]&.event != :on_heredoc_beg
- if t.tok.match?(/^<<[~-]/)
- indent_level += 1
- else
- indent_level = 0
- end
- end
- when :on_tstring_beg, :on_regexp_beg, :on_symbeg, :on_backtick
- # No indent: "", //, :"", ``
- # Indent: %(), %r(), %i(), %x()
- indent_level += 1 if t.tok.start_with? '%'
- when :on_embdoc_beg
- indent_level = 0
- else
- indent_level += 1 unless t.tok == 'alias' || t.tok == 'undef'
- end
- end
- indent_level
- end
-
- FREE_INDENT_TOKENS = %i[on_tstring_beg on_backtick on_regexp_beg on_symbeg]
-
- def free_indent_token?(token)
- FREE_INDENT_TOKENS.include?(token&.event)
- end
-
- # Calculates the difference of pasted code's indent and indent calculated from tokens
- def indent_difference(lines, line_results, line_index)
- loop do
- _tokens, prev_opens, _next_opens, min_depth = line_results[line_index]
- open_token = prev_opens.last
- if !open_token || (open_token.event != :on_heredoc_beg && !free_indent_token?(open_token))
- # If the leading whitespace is an indent, return the difference
- indent_level = calc_indent_level(prev_opens.take(min_depth))
- calculated_indent = 2 * indent_level
- actual_indent = lines[line_index][/^ */].size
- return actual_indent - calculated_indent
- elsif open_token.event == :on_heredoc_beg && open_token.tok.match?(/^<<[^-~]/)
- return 0
- end
- # If the leading whitespace is not an indent but part of a multiline token
- # Calculate base_indent of the multiline token's beginning line
- line_index = open_token.pos[0] - 1
- end
- end
-
- def process_indent_level(tokens, lines, line_index, is_newline)
- line_results = NestingParser.parse_by_line(tokens)
- result = line_results[line_index]
- if result
- _tokens, prev_opens, next_opens, min_depth = result
- else
- # When last line is empty
- prev_opens = next_opens = line_results.last[2]
- min_depth = next_opens.size
- end
-
- # To correctly indent line like `end.map do`, we use shortest open tokens on each line for indent calculation.
- # Shortest open tokens can be calculated by `opens.take(min_depth)`
- indent = 2 * calc_indent_level(prev_opens.take(min_depth))
-
- preserve_indent = lines[line_index - (is_newline ? 1 : 0)][/^ */].size
-
- prev_open_token = prev_opens.last
- next_open_token = next_opens.last
-
- # Calculates base indent for pasted code on the line where prev_open_token is located
- # irb(main):001:1* if a # base_indent is 2, indent calculated from tokens is 0
- # irb(main):002:1* if b # base_indent is 6, indent calculated from tokens is 2
- # irb(main):003:0> c # base_indent is 6, indent calculated from tokens is 4
- if prev_open_token
- base_indent = [0, indent_difference(lines, line_results, prev_open_token.pos[0] - 1)].max
- else
- base_indent = 0
- end
-
- if free_indent_token?(prev_open_token)
- if is_newline && prev_open_token.pos[0] == line_index
- # First newline inside free-indent token
- base_indent + indent
- else
- # Accept any number of indent inside free-indent token
- preserve_indent
- end
- elsif prev_open_token&.event == :on_embdoc_beg || next_open_token&.event == :on_embdoc_beg
- if prev_open_token&.event == next_open_token&.event
- # Accept any number of indent inside embdoc content
- preserve_indent
- else
- # =begin or =end
- 0
- end
- elsif prev_open_token&.event == :on_heredoc_beg
- tok = prev_open_token.tok
- if prev_opens.size <= next_opens.size
- if is_newline && lines[line_index].empty? && line_results[line_index - 1][1].last != next_open_token
- # First line in heredoc
- tok.match?(/^<<[-~]/) ? base_indent + indent : indent
- elsif tok.match?(/^<<~/)
- # Accept extra indent spaces inside `<<~` heredoc
- [base_indent + indent, preserve_indent].max
- else
- # Accept any number of indent inside other heredoc
- preserve_indent
- end
- else
- # Heredoc close
- prev_line_indent_level = calc_indent_level(prev_opens)
- tok.match?(/^<<[~-]/) ? base_indent + 2 * (prev_line_indent_level - 1) : 0
- end
- else
- base_indent + indent
- end
- end
-
- def ltype_from_open_tokens(opens)
- start_token = opens.reverse_each.find do |tok|
- LTYPE_TOKENS.include?(tok.event)
- end
- return nil unless start_token
-
- case start_token&.event
- when :on_tstring_beg
- case start_token&.tok
- when ?" then ?"
- when /^%.$/ then ?"
- when /^%Q.$/ then ?"
- when ?' then ?'
- when /^%q.$/ then ?'
- end
- when :on_regexp_beg then ?/
- when :on_symbeg then ?:
- when :on_backtick then ?`
- when :on_qwords_beg then ?]
- when :on_words_beg then ?]
- when :on_qsymbols_beg then ?]
- when :on_symbols_beg then ?]
- when :on_heredoc_beg
- start_token&.tok =~ /<<[-~]?(['"`])\w+\1/
- $1 || ?"
- else
- nil
- end
- end
-
- def check_termination_in_prev_line(code, local_variables:)
- tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
- past_first_newline = false
- index = tokens.rindex do |t|
- # traverse first token before last line
- if past_first_newline
- if t.tok.include?("\n")
- true
- end
- elsif t.tok.include?("\n")
- past_first_newline = true
- false
- else
- false
- end
- end
-
- if index
- first_token = nil
- last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
- last_line_tokens.each do |t|
- unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
- first_token = t
- break
- end
- end
-
- if first_token && first_token.state != Ripper::EXPR_DOT
- tokens_without_last_line = tokens[0..index]
- code_without_last_line = tokens_without_last_line.map(&:tok).join
- opens_without_last_line = NestingParser.open_tokens(tokens_without_last_line)
- if code_terminated?(code_without_last_line, tokens_without_last_line, opens_without_last_line, local_variables: local_variables)
- return last_line_tokens.map(&:tok).join
- end
- end
- end
- false
- end
- end
- # :startdoc:
-end
-
-RubyLex = IRB::RubyLex
-Object.deprecate_constant(:RubyLex)
diff --git a/lib/irb/ruby_logo.aa b/lib/irb/ruby_logo.aa
deleted file mode 100644
index d0143a448b..0000000000
--- a/lib/irb/ruby_logo.aa
+++ /dev/null
@@ -1,118 +0,0 @@
-TYPE: ASCII_LARGE
-
- ,,,;;;;;;;;;;;;;;;;;;;;;;,,
- ,,,;;;;;;;;;,, ,;;;' ''';;,
- ,,;;;''' ';;;, ,,;;'' '';,
- ,;;'' ;;;;;;;;,,,,,, ';;
- ,;;'' ;;;;';;;'''';;;;;;;;;,,,;;
- ,,;'' ;;;; ';;, ''''';;,
- ,;;' ;;;' ';;, ;;
- ,;;' ,;;; '';,, ;;
- ,;;' ;;; ';;, ,;;
- ;;' ;;;' '';,, ;;;
- ,;' ;;;; ';;, ;;'
- ,;;' ,;;;;' ,,,,,,,,,,,,;;;;;
- ,;' ,;;;;;;;;;;;;;;;;;;;;'''''''';;;
- ;;' ,;;;;;;;;;,, ;;;;
- ;;' ,;;;'' ;;, ';;,, ,;;;;
- ;;' ,;;;' ;; '';;, ,;';;;
- ;;' ,;;;' ;;, '';;,, ,;',;;;
- ,;;; ,;;;' ;; '';;,, ,;' ;;;'
- ;;;; ,,;;;' ;;, ';;;' ;;;
-,;;; ,;;;;' ;; ,;;; ;;;
-;;;;; ,,;;;;;' ;;, ,;';; ;;;
-;;;;;, ,,;;;;;;;' ;; ,;;' ;;; ;;;
-;;;;;;;,,,,,,,;;;;;;;;;;;;;;,,, ;;, ,;' ;; ;;;
-;;' ;;;;;;;;;;'''' ,;';; ''';;;;,,, ;; ,;; ;; ;;;
-;; ;;;'' ;; ';; ''';;;;,,,, ;;, ,;;' ;;, ;;
-;; ;;;;, ;;' ';; ''';;;;,,;;;;' ';; ;;
-;;;;;;';, ,;; ;; '';;;;, ;;,;;
-;;; ;; ;;, ;; ;; ,;;' ';;, ;;;;;
-;; ;;; ;;, ;;' ;; ,,;'' ';;, ;;;;;
-;; ;; ;; ;; ;; ,;;' '';, ;;;;
-;;,;; ;; ;;' ;; ,;;'' ';,, ;;;'
- ;;;; ';; ,;; ;;,,;;'' ';;, ;;;
- ';;; ';; ;; ,;;;;;;;;;;;;;,,,,,,,,,,,, ';;;;;
- ';, ';,;;' ,,,;;'' '''''''';;;;;;;;;;;;;;;;;;;
- ';;,,, ;;;; ,,,,;;;;;;,,,,,;;;;;;;;;;;;;;;;;;;''''''''''''''
- ''';;;;;;;;;;;;;;'''''''''''''''
-TYPE: ASCII
- ,,,;;;;''''';;;'';,
- ,,;'' ';;,;;; ',
- ,,'' ;;'';'''';;;;;;
- ,;' ;; ',, ;
- ,;' ,;' ';, ;
- ;' ,;; ',,,;
- ,' ,;;,,,,,,,,,,,;;;;
- ;' ;;';;;; ,;;
- ;' ,;' ;; '',, ,;;;
- ;; ,;' ; '';, ,; ;'
-;; ,;;' ;; ;; ;;
-;;, ,,;;' ; ;'; ;;
-;';;,,,,;;;;;;;,,, ;; ,' ; ;;
-; ;;''' ,;'; ''';,,, ; ,;' ;;;;
-;;;;, ; '; ''';;;' ';;;
-;'; ;, ;' '; ,;' ', ;;;
-;;; ; ,; '; ,,' ',, ;;
-;;; '; ;' ';,,'' ';,;;
- '; ';,; ,,;''''''''';;;;;;,,;;;
- ';,,;;,,;;;;;;;;;;''''''''''''''
-TYPE: UNICODE_LARGE
-
- ⣀⣤⣴⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⣄⡀
- ⢀⣀⣤⣴⣾⣿⣿⣿⠿⣿⣿⣿⣿⣦⣀ ⢀⣤⣶⣿⠿⠛⠁⠈⠉⠙⠻⢿⣷⣦⡀
- ⢀⣠⣴⣾⡿⠿⠛⠉⠉ ⠈⠙⢿⣿⣷⣤⡀ ⣠⣴⣾⡿⠟⠉ ⠉⠻⣿⣦
- ⢀⣤⣶⣿⠟⠋⠁ ⢿⣿⣿⣿⣿⣿⣿⣧⣤⣤⣤⣀⣀⣀⡀ ⠘⢿⣷⡀
- ⢀⣠⣾⡿⠟⠉ ⢸⣿⣿⣿⠟⢿⣿⣯⡙⠛⠛⠛⠿⠿⠿⢿⣿⣿⣶⣶⣶⣦⣤⣬⣿⣧
- ⣠⣴⣿⠟⠋ ⢸⣿⣿⡿ ⠈⠻⣿⣶⣄ ⠉⠉⠉⠙⠛⢻⣿⡆
- ⣠⣾⡿⠛⠁ ⣼⣿⣿⠃ ⠈⠙⢿⣷⣤⡀ ⠈⣿⡇
- ⣠⣾⡿⠋ ⢠⣿⣿⡏ ⠙⠻⣿⣦⣀ ⣿⡇
- ⣠⣾⡿⠋ ⢀⣿⣿⣿ ⠈⠛⢿⣷⣄⡀ ⢠⣿⡇
- ⢀⣾⡿⠋ ⢀⣾⣿⣿⠇ ⠙⠻⣿⣦⣀ ⢸⣿⡇
- ⢀⣴⣿⠟⠁ ⢀⣾⣿⣿⡟ ⠈⠻⢿⣷⣄ ⣾⣿⠇
- ⢠⣾⡿⠃ ⣠⣿⣿⣿⣿⠃ ⣀⣀⣀⣀⣀⣀⣀⣀⣤⣤⣤⣤⣽⣿⣿⣿⣿
- ⣰⣿⠟ ⣴⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠛⠛⠛⠛⠛⠛⠛⣿⣿⣿
- ⣼⣿⠏ ⢠⣾⣿⣿⣿⡿⣿⣿⢿⣷⣦⣄ ⣼⣿⣿⣿
- ⣼⣿⠃ ⢀⣴⣿⣿⣿⠟⠋ ⢸⣿⡆⠈⠛⠿⣿⣦⣄⡀ ⣰⣿⣿⣿⡇
- ⢀⣾⣿⠃ ⢀⣴⣿⣿⣿⠟⠁ ⣿⣷ ⠈⠙⠻⣿⣶⣄⡀ ⣰⣿⠟⣿⣿⡇
- ⢀⣾⣿⠇ ⢀⣴⣿⣿⣿⠟⠁ ⢸⣿⡆ ⠙⠻⢿⣷⣤⣀ ⣰⣿⠏⢠⣿⣿⡇
- ⢠⣿⣿⡟ ⢀⣴⣿⣿⡿⠛⠁ ⣿⣷ ⠉⠻⢿⣷⣦⣀ ⣴⣿⠏ ⢸⣿⣿⠃
- ⣿⣿⣿⡇ ⣠⣴⣿⣿⡿⠋ ⢸⣿⡆ ⠈⠛⢿⣿⣿⠃ ⢸⣿⣿
-⢠⣿⣿⣿ ⢀⣴⣾⣿⣿⡿⠋ ⠈⣿⣧ ⢠⣾⣿⣿ ⢸⣿⣿
-⢸⣿⣿⣿⡇ ⣀⣴⣾⣿⣿⣿⡿⠋ ⢹⣿⡆ ⣴⣿⠟⢹⣿⡀ ⢸⣿⡿
-⢸⣿⡟⣿⣿⣄ ⣀⣤⣶⣿⣿⣿⣿⣿⡟⠉ ⠈⣿⣷ ⢠⣾⡿⠋ ⢸⣿⡇ ⣼⣿⡇
-⢸⣿⡇⢹⣿⣿⣷⣦⣤⣤⣤⣤⣤⣴⣶⣾⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣷⣶⣤⣤⣀⡀ ⢹⣿⡆ ⢀⣴⣿⠟ ⣿⣧ ⣿⣿⡇
-⢸⣿⠃ ⢿⣿⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠉⠉⠁ ⢰⣿⠟⣿⣷⡀⠉⠙⠛⠿⢿⣿⣶⣦⣤⣀⡀ ⠈⣿⣷ ⣠⣿⡿⠁ ⢿⣿ ⣿⣿⡇
-⢸⣿ ⢀⣾⣿⣿⠋⠉⠁ ⢀⣿⡿ ⠘⣿⣷⡀ ⠉⠙⠛⠿⠿⣿⣶⣦⣤⣄⣀ ⢹⣿⡄ ⣠⣾⡿⠋ ⢸⣿⡆ ⣿⣿
-⣸⣿⢀⣾⣿⣿⣿⣆ ⣸⣿⠃ ⠘⢿⣷⡀ ⠈⠉⠛⠻⠿⣿⣷⣶⣤⣌⣿⣷⣾⡿⠋ ⠘⣿⡇ ⣿⣿
-⣿⣿⣾⡿⣿⡿⠹⣿⡆ ⢠⣿⡏ ⠈⢿⣷⡀ ⠈⠉⠙⣻⣿⣿⣿⣀ ⣿⣷⢰⣿⣿
-⣿⣿⡿⢁⣿⡇ ⢻⣿⡄ ⣾⣿ ⠈⢿⣷⡀ ⢀⣤⣾⡿⠋⠈⠻⢿⣷⣄ ⢻⣿⢸⣿⡟
-⣿⣿⠁⢸⣿⡇ ⢻⣿⡄ ⢸⣿⠇ ⠈⢿⣷⡀ ⣀⣴⣿⠟⠋ ⠙⢿⣷⣤⡀ ⢸⣿⣿⣿⡇
-⣿⣿ ⢸⣿⠁ ⠈⢿⣷⡀ ⢀⣿⡟ ⠈⢿⣷⡀ ⢀⣤⣾⡿⠛⠁ ⠙⠻⣿⣦⡀ ⠈⣿⣿⣿⡇
-⢸⣿⡄⣿⣿ ⠈⣿⣷⡀ ⣼⣿⠃ ⠈⢿⣷⡀ ⢀⣠⣶⣿⠟⠋ ⠈⠻⣿⣦⣄ ⣿⣿⣿⠇
-⠈⣿⣷⣿⡿ ⠘⣿⣧ ⢠⣿⡏ ⠈⢿⣷⣄⣤⣶⣿⠟⠋ ⠈⠛⢿⣷⣄ ⢸⣿⣿
- ⠘⣿⣿⡇ ⠘⣿⣧ ⣾⣿ ⢀⣠⣼⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣶⣶⣤⣤⣤⣤⣤⣤⣀⣀⣀⣀⣀⣀⡀ ⠙⢿⣷⣼⣿⣿
- ⠈⠻⣿⣦⡀ ⠹⣿⣆⢸⣿⠇ ⣀⣠⣴⣾⡿⠟⠋⠁ ⠉⠉⠉⠉⠉⠉⠛⠛⣛⣛⣛⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⡿
- ⠈⠻⢿⣷⣦⣄⣀⡀ ⢹⣿⣿⡟ ⢀⣀⣀⣤⣤⣶⣾⣿⣿⣿⣯⣥⣤⣤⣤⣤⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠟⠛⠛⠛⠛⠛⠛⠛⠉⠉⠉⠉⠉⠉
- ⠉⠙⠛⠿⠿⠿⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠛⠛⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠉
-TYPE: UNICODE
- ⣀⣤⣴⣾⣿⣿⣿⡛⠛⠛⠛⠛⣻⣿⠿⠛⠛⠶⣤⡀
- ⣀⣴⠾⠛⠉⠁ ⠙⣿⣶⣤⣶⣟⣉ ⠈⠻⣦
- ⣀⣴⠟⠋ ⢸⣿⠟⠻⣯⡙⠛⠛⠛⠶⠶⠶⢶⣽⣇
- ⣠⡾⠋⠁ ⣾⡿ ⠈⠛⢦⣄ ⣿
- ⣠⡾⠋ ⣰⣿⠃ ⠙⠷⣤⡀ ⣿
- ⢀⡾⠋ ⣰⣿⡏ ⠈⠻⣦⣄⢠⣿
- ⣰⠟⠁ ⣴⣿⣿⣁⣀⣠⣤⣤⣤⣤⣤⣤⣤⣴⠶⠿⣿⡏
- ⣼⠏ ⢀⣾⣿⠟⣿⠿⣯⣍⠁ ⣰⣿⡇
- ⢀⣼⠋ ⢀⣴⣿⠟⠁ ⢸⡇ ⠙⠻⢦⣄⡀ ⢠⡿⣿⡇
-⢀⣾⡏ ⢀⣴⣿⠟⠁ ⣿ ⠉⠻⢶⣄⡀⣰⡟ ⣿⠃
-⣾⣿⠁ ⣠⣶⡿⠋⠁ ⢹⡇ ⠈⣿⡏ ⢸⣿
-⣿⣿⡆ ⢀⣠⣴⣿⡿⠋ ⠈⣿ ⢀⡾⠋⣿ ⢸⣿
-⣿⠸⣿⣶⣤⣤⣤⣤⣶⣾⠿⠿⣿⣿⠶⣤⣤⣀⡀ ⢹⡇ ⣴⠟⠁ ⣿⡀⢸⣿
-⣿⢀⣿⣟⠛⠋⠉⠁ ⢰⡟⠹⣧ ⠈⠉⠛⠻⠶⢦⣤⣀⡀ ⠈⣿ ⣠⡾⠃ ⢸⡇⢸⡇
-⣿⣾⣿⢿⡄ ⣿⠁ ⠘⣧ ⠉⠙⠛⠷⣿⣿⡋ ⠸⣇⣸⡇
-⣿⠃⣿⠈⢿⡄ ⣸⠇ ⠘⣧ ⢀⣤⠾⠋⠈⠻⣦⡀ ⣿⣿⡇
-⣿⢸⡏ ⠈⣷⡀ ⢠⡿ ⠘⣧⡀ ⣠⡴⠟⠁ ⠈⠻⣦⣀ ⢿⣿⠁
-⢻⣾⡇ ⠘⣷ ⣼⠃ ⠘⣷⣠⣴⠟⠋ ⠙⢷⣄⢸⣿
- ⠻⣧⡀ ⠘⣧⣰⡏ ⢀⣠⣤⠶⠛⠉⠛⠛⠛⠛⠛⠛⠻⢶⣶⣶⣶⣶⣶⣤⣤⣽⣿⣿
- ⠈⠛⠷⢦⣤⣽⣿⣥⣤⣶⣶⡿⠿⠿⠶⠶⠶⠶⠾⠛⠛⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠁
diff --git a/lib/irb/source_finder.rb b/lib/irb/source_finder.rb
deleted file mode 100644
index 6e1e58069f..0000000000
--- a/lib/irb/source_finder.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "ruby-lex"
-
-module IRB
- class SourceFinder
- class EvaluationError < StandardError; end
-
- class Source
- attr_reader :file, :line
- def initialize(file, line, ast_source = nil)
- @file = file
- @line = line
- @ast_source = ast_source
- end
-
- def file_exist?
- File.exist?(@file)
- end
-
- def binary_file?
- # If the line is zero, it means that the target's source is probably in a binary file.
- @line.zero?
- end
-
- def file_content
- @file_content ||= File.read(@file)
- end
-
- def colorized_content
- if !binary_file? && file_exist?
- end_line = find_end
- # To correctly colorize, we need to colorize full content and extract the relevant lines.
- colored = IRB::Color.colorize_code(file_content)
- colored.lines[@line - 1...end_line].join
- elsif @ast_source
- IRB::Color.colorize_code(@ast_source)
- end
- end
-
- private
-
- def find_end
- lex = RubyLex.new
- code = file_content
- lines = code.lines[(@line - 1)..-1]
- tokens = RubyLex.ripper_lex_without_warning(lines.join)
- prev_tokens = []
-
- # chunk with line number
- tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
- code = lines[0..lnum].join
- prev_tokens.concat chunk
- continue = lex.should_continue?(prev_tokens)
- syntax = lex.check_code_syntax(code, local_variables: [])
- if !continue && syntax == :valid
- return @line + lnum
- end
- end
- @line
- end
- end
-
- private_constant :Source
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- def find_source(signature, super_level = 0)
- case signature
- when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
- eval_receiver_or_owner(signature) # trigger autoload
- *parts, name = signature.split('::', -1)
- base =
- if parts.empty? # ConstName
- find_const_owner(name)
- elsif parts == [''] # ::ConstName
- Object
- else # ConstPath::ConstName
- eval_receiver_or_owner(parts.join('::'))
- end
- file, line = base.const_source_location(name)
- when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
- owner = eval_receiver_or_owner(Regexp.last_match[:owner])
- method = Regexp.last_match[:method]
- return unless owner.respond_to?(:instance_method)
- method = method_target(owner, super_level, method, "owner")
- file, line = method&.source_location
- when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
- receiver = eval_receiver_or_owner(Regexp.last_match[:receiver] || 'self')
- method = Regexp.last_match[:method]
- return unless receiver.respond_to?(method, true)
- method = method_target(receiver, super_level, method, "receiver")
- file, line = method&.source_location
- end
- return unless file && line
-
- if File.exist?(file)
- Source.new(file, line)
- elsif method
- # Method defined with eval, probably in IRB session
- source = RubyVM::InstructionSequence.of(method)&.script_lines&.join rescue nil
- Source.new(file, line, source)
- end
- rescue EvaluationError
- nil
- end
-
- private
-
- def method_target(owner_receiver, super_level, method, type)
- case type
- when "owner"
- target_method = owner_receiver.instance_method(method)
- when "receiver"
- target_method = owner_receiver.method(method)
- end
- super_level.times do |s|
- target_method = target_method.super_method if target_method
- end
- target_method
- rescue NameError
- nil
- end
-
- def eval_receiver_or_owner(code)
- @irb_context.workspace.binding.eval(code)
- rescue Exception
- raise EvaluationError
- end
-
- def find_const_owner(name)
- module_nesting = @irb_context.workspace.binding.eval('::Module.nesting')
- module_nesting.find { |mod| mod.const_defined?(name, false) } || module_nesting.find { |mod| mod.const_defined?(name) } || Object
- end
- end
-end
diff --git a/lib/irb/statement.rb b/lib/irb/statement.rb
deleted file mode 100644
index 6a959995d1..0000000000
--- a/lib/irb/statement.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- class Statement
- attr_reader :code
-
- def is_assignment?
- raise NotImplementedError
- end
-
- def suppresses_echo?
- raise NotImplementedError
- end
-
- def should_be_handled_by_debugger?
- raise NotImplementedError
- end
-
- class EmptyInput < Statement
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- true
- end
-
- # Debugger takes empty input to repeat the last command
- def should_be_handled_by_debugger?
- true
- end
-
- def code
- ""
- end
- end
-
- class Expression < Statement
- def initialize(code, is_assignment)
- @code = code
- @is_assignment = is_assignment
- end
-
- def suppresses_echo?
- @code.match?(/;\s*\z/)
- end
-
- def should_be_handled_by_debugger?
- true
- end
-
- def is_assignment?
- @is_assignment
- end
- end
-
- class IncorrectAlias < Statement
- attr_reader :message
-
- def initialize(message)
- @code = ""
- @message = message
- end
-
- def should_be_handled_by_debugger?
- false
- end
-
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- true
- end
- end
-
- class Command < Statement
- attr_reader :command_class, :arg
-
- def initialize(original_code, command_class, arg)
- @code = original_code
- @command_class = command_class
- @arg = arg
- end
-
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- true
- end
-
- def should_be_handled_by_debugger?
- require_relative 'command/debug'
- IRB::Command::DebugCommand > @command_class
- end
- end
- end
-end
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
deleted file mode 100644
index b195956fe0..0000000000
--- a/lib/irb/version.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/version.rb - irb version definition file
-# by Keiju ISHITSUKA([email protected])
-#
-
-module IRB # :nodoc:
- VERSION = "1.15.1"
- @RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2025-01-22"
-end
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
deleted file mode 100644
index ced9d78663..0000000000
--- a/lib/irb/workspace.rb
+++ /dev/null
@@ -1,171 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/workspace-binding.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-require_relative "helper_method"
-
-IRB::TOPLEVEL_BINDING = binding
-module IRB # :nodoc:
- class WorkSpace
- # Creates a new workspace.
- #
- # set self to main if specified, otherwise
- # inherit main from TOPLEVEL_BINDING.
- def initialize(*main)
- if Binding === main[0]
- @binding = main.shift
- elsif IRB.conf[:SINGLE_IRB]
- @binding = TOPLEVEL_BINDING
- else
- case IRB.conf[:CONTEXT_MODE]
- when 0 # binding in proc on TOPLEVEL_BINDING
- @binding = eval("proc{binding}.call",
- TOPLEVEL_BINDING,
- __FILE__,
- __LINE__)
- when 1 # binding in loaded file
- require "tempfile"
- f = Tempfile.open("irb-binding")
- f.print <<EOF
- $binding = binding
-EOF
- f.close
- load f.path
- @binding = $binding
-
- when 2 # binding in loaded file(thread use)
- unless defined? BINDING_QUEUE
- IRB.const_set(:BINDING_QUEUE, Thread::SizedQueue.new(1))
- Thread.abort_on_exception = true
- Thread.start do
- eval "require \"irb/ws-for-case-2\"", TOPLEVEL_BINDING, __FILE__, __LINE__
- end
- Thread.pass
- end
- @binding = BINDING_QUEUE.pop
-
- when 3 # binding in function on TOPLEVEL_BINDING
- @binding = eval("self.class.remove_method(:irb_binding) if defined?(irb_binding); private; def irb_binding; binding; end; irb_binding",
- TOPLEVEL_BINDING,
- __FILE__,
- __LINE__ - 3)
- when 4 # binding is a copy of TOPLEVEL_BINDING (default)
- # Note that this will typically be IRB::TOPLEVEL_BINDING
- # This is to avoid RubyGems' local variables (see issue #17623)
- @binding = TOPLEVEL_BINDING.dup
- end
- end
-
- if main.empty?
- @main = eval("self", @binding)
- else
- @main = main[0]
- end
- IRB.conf[:__MAIN__] = @main
-
- unless main.empty?
- case @main
- when Module
- @binding = eval("::IRB.conf[:__MAIN__].module_eval('::Kernel.binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
- else
- begin
- @binding = eval("::IRB.conf[:__MAIN__].instance_eval('::Kernel.binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
- rescue TypeError
- fail CantChangeBinding, @main.inspect
- end
- end
- end
-
- @binding.local_variable_set(:_, nil)
- end
-
- # The Binding of this workspace
- attr_reader :binding
- # The top-level workspace of this context, also available as
- # <code>IRB.conf[:__MAIN__]</code>
- attr_reader :main
-
- def load_helper_methods_to_main
- # Do not load helper methods to frozen objects and BasicObject
- return unless Object === @main && [email protected]?
-
- ancestors = class<<main;ancestors;end
- main.extend ExtendCommandBundle if !ancestors.include?(ExtendCommandBundle)
- main.extend HelpersContainer if !ancestors.include?(HelpersContainer)
- end
-
- # Evaluate the given +statements+ within the context of this workspace.
- def evaluate(statements, file = __FILE__, line = __LINE__)
- eval(statements, @binding, file, line)
- end
-
- def local_variable_set(name, value)
- @binding.local_variable_set(name, value)
- end
-
- def local_variable_get(name)
- @binding.local_variable_get(name)
- end
-
- # error message manipulator
- # WARN: Rails patches this method to filter its own backtrace. Be cautious when changing it.
- # See: https://github.com/rails/rails/blob/main/railties/lib/rails/commands/console/console_command.rb#L8:~:text=def,filter_backtrace
- def filter_backtrace(bt)
- return nil if bt =~ /\/irb\/.*\.rb/
- return nil if bt =~ /\/irb\.rb/
- return nil if bt =~ /tool\/lib\/.*\.rb|runner\.rb/ # for tests in Ruby repository
- case IRB.conf[:CONTEXT_MODE]
- when 1
- return nil if bt =~ %r!/tmp/irb-binding!
- when 3
- bt = bt.sub(/:\s*in `irb_binding'/, '')
- end
- bt
- end
-
- def code_around_binding
- file, pos = @binding.source_location
-
- if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file]
- code = ::SCRIPT_LINES__[file].join('')
- else
- begin
- code = File.read(file)
- rescue SystemCallError
- return
- end
- end
-
- lines = Color.colorize_code(code).lines
- pos -= 1
-
- start_pos = [pos - 5, 0].max
- end_pos = [pos + 5, lines.size - 1].min
-
- line_number_fmt = Color.colorize("%#{end_pos.to_s.length}d", [:BLUE, :BOLD])
- fmt = " %2s #{line_number_fmt}: %s"
-
- body = (start_pos..end_pos).map do |current_pos|
- sprintf(fmt, pos == current_pos ? '=>' : '', current_pos + 1, lines[current_pos])
- end.join("")
-
- "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
- end
- end
-
- module HelpersContainer
- class << self
- def install_helper_methods
- HelperMethod.helper_methods.each do |name, helper_method_class|
- define_method name do |*args, **opts, &block|
- helper_method_class.instance.execute(*args, **opts, &block)
- end unless method_defined?(name)
- end
- end
- end
-
- install_helper_methods
- end
-end
diff --git a/lib/irb/ws-for-case-2.rb b/lib/irb/ws-for-case-2.rb
deleted file mode 100644
index 03f42d73d9..0000000000
--- a/lib/irb/ws-for-case-2.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/ws-for-case-2.rb -
-# by Keiju ISHITSUKA([email protected])
-#
-
-while true
- IRB::BINDING_QUEUE.push _ = binding
-end
diff --git a/lib/irb/xmp.rb b/lib/irb/xmp.rb
deleted file mode 100644
index b1bc53283e..0000000000
--- a/lib/irb/xmp.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-# frozen_string_literal: true
-#
-# xmp.rb - irb version of gotoken xmp
-# by Keiju ISHITSUKA(Nippon Rational Inc.)
-#
-
-require_relative "../irb"
-require_relative "frame"
-
-# An example printer for irb.
-#
-# It's much like the standard library PrettyPrint, that shows the value of each
-# expression as it runs.
-#
-# In order to use this library, you must first require it:
-#
-# require 'irb/xmp'
-#
-# Now, you can take advantage of the Object#xmp convenience method.
-#
-# xmp <<END
-# foo = "bar"
-# baz = 42
-# END
-# #=> foo = "bar"
-# #==>"bar"
-# #=> baz = 42
-# #==>42
-#
-# You can also create an XMP object, with an optional binding to print
-# expressions in the given binding:
-#
-# ctx = binding
-# x = XMP.new ctx
-# x.puts
-# #=> today = "a good day"
-# #==>"a good day"
-# ctx.eval 'today # is what?'
-# #=> "a good day"
-class XMP
-
- # Creates a new XMP object.
- #
- # The top-level binding or, optional +bind+ parameter will be used when
- # creating the workspace. See WorkSpace.new for more information.
- #
- # This uses the +:XMP+ prompt mode.
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
- def initialize(bind = nil)
- IRB.init_config(nil)
-
- IRB.conf[:PROMPT_MODE] = :XMP
-
- bind = IRB::Frame.top(1) unless bind
- ws = IRB::WorkSpace.new(bind)
- @io = StringInputMethod.new
- @irb = IRB::Irb.new(ws, @io)
- @irb.context.ignore_sigint = false
-
- IRB.conf[:MAIN_CONTEXT] = @irb.context
- end
-
- # Evaluates the given +exps+, for example:
- #
- # require 'irb/xmp'
- # x = XMP.new
- #
- # x.puts '{:a => 1, :b => 2, :c => 3}'
- # #=> {:a => 1, :b => 2, :c => 3}
- # # ==>{:a=>1, :b=>2, :c=>3}
- # x.puts 'foo = "bar"'
- # # => foo = "bar"
- # # ==>"bar"
- def puts(exps)
- @io.puts exps
-
- if @irb.context.ignore_sigint
- begin
- trap_proc_b = trap("SIGINT"){@irb.signal_handle}
- catch(:IRB_EXIT) do
- @irb.eval_input
- end
- ensure
- trap("SIGINT", trap_proc_b)
- end
- else
- catch(:IRB_EXIT) do
- @irb.eval_input
- end
- end
- end
-
- # A custom InputMethod class used by XMP for evaluating string io.
- class StringInputMethod < IRB::InputMethod
- # Creates a new StringInputMethod object
- def initialize
- super
- @exps = []
- end
-
- # Whether there are any expressions left in this printer.
- def eof?
- @exps.empty?
- end
-
- # Reads the next expression from this printer.
- #
- # See IO#gets for more information.
- def gets
- while l = @exps.shift
- next if /^\s+$/ =~ l
- l.concat "\n"
- print @prompt, l
- break
- end
- l
- end
-
- # Concatenates all expressions in this printer, separated by newlines.
- #
- # An Encoding::CompatibilityError is raised of the given +exps+'s encoding
- # doesn't match the previous expression evaluated.
- def puts(exps)
- if @encoding and exps.encoding != @encoding
- enc = Encoding.compatible?(@exps.join("\n"), exps)
- if enc.nil?
- raise Encoding::CompatibilityError, "Encoding in which the passed expression is encoded is not compatible to the preceding's one"
- else
- @encoding = enc
- end
- else
- @encoding = exps.encoding
- end
- @exps.concat exps.split(/\n/)
- end
-
- # Returns the encoding of last expression printed by #puts.
- attr_reader :encoding
- end
-end
-
-# A convenience method that's only available when the you require the IRB::XMP standard library.
-#
-# Creates a new XMP object, using the given expressions as the +exps+
-# parameter, and optional binding as +bind+ or uses the top-level binding. Then
-# evaluates the given expressions using the +:XMP+ prompt mode.
-#
-# For example:
-#
-# require 'irb/xmp'
-# ctx = binding
-# xmp 'foo = "bar"', ctx
-# #=> foo = "bar"
-# #==>"bar"
-# ctx.eval 'foo'
-# #=> "bar"
-#
-# See XMP.new for more information.
-def xmp(exps, bind = nil)
- bind = IRB::Frame.top(1) unless bind
- xmp = XMP.new(bind)
- xmp.puts exps
- xmp
-end
diff --git a/lib/readline.gemspec b/lib/readline.gemspec
deleted file mode 100644
index 9221c29263..0000000000
--- a/lib/readline.gemspec
+++ /dev/null
@@ -1,33 +0,0 @@
-Gem::Specification.new do |spec|
- spec.name = 'readline'
- spec.version = '0.0.4'
- spec.authors = ['aycabta']
- spec.email = ['[email protected]']
-
- spec.summary = %q{Loader for "readline".}
- spec.description = <<~EOD
- This is just a loader for "readline". If Ruby has the "readline-ext" gem
- that is a native extension, this gem will load it. If Ruby does not have
- the "readline-ext" gem this gem will load "reline", a library that is
- compatible with the "readline-ext" gem and implemented in pure Ruby.
- EOD
- spec.homepage = 'https://github.com/ruby/readline'
- spec.license = 'Ruby'
-
- spec.files = Dir['BSDL', 'COPYING', 'README.md', 'lib/readline.rb']
- spec.require_paths = ['lib']
-
- spec.post_install_message = <<~EOM
- +---------------------------------------------------------------------------+
- | This is just a loader for "readline". If Ruby has the "readline-ext" gem |
- | that is a native extension, this gem will load it. If Ruby does not have |
- | the "readline-ext" gem this gem will load "reline", a library that is |
- | compatible with the "readline-ext" gem and implemented in pure Ruby. |
- | |
- | If you intend to use GNU Readline by `require 'readline'`, please install |
- | the "readline-ext" gem. |
- +---------------------------------------------------------------------------+
- EOM
-
- spec.add_runtime_dependency 'reline'
-end
diff --git a/lib/readline.rb b/lib/readline.rb
deleted file mode 100644
index d1c9d3a955..0000000000
--- a/lib/readline.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-begin
- require "readline.#{RbConfig::CONFIG["DLEXT"]}"
-rescue LoadError
- require 'reline' unless defined? Reline
- Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
- Readline = Reline
-end
diff --git a/lib/reline.rb b/lib/reline.rb
deleted file mode 100644
index 5d1fcbf8e8..0000000000
--- a/lib/reline.rb
+++ /dev/null
@@ -1,518 +0,0 @@
-require 'io/console'
-require 'forwardable'
-require 'reline/version'
-require 'reline/config'
-require 'reline/key_actor'
-require 'reline/key_stroke'
-require 'reline/line_editor'
-require 'reline/history'
-require 'reline/io'
-require 'reline/face'
-require 'rbconfig'
-
-module Reline
- # NOTE: For making compatible with the rb-readline gem
- FILENAME_COMPLETION_PROC = nil
- USERNAME_COMPLETION_PROC = nil
-
- class ConfigEncodingConversionError < StandardError; end
-
- # EOF key: { char: nil, method_symbol: nil }
- # Other key: { char: String, method_symbol: Symbol }
- Key = Struct.new(:char, :method_symbol, :unused_boolean) do
- # For dialog_proc `key.match?(dialog.name)`
- def match?(sym)
- method_symbol && method_symbol == sym
- end
- end
- CursorPos = Struct.new(:x, :y)
- DialogRenderInfo = Struct.new(
- :pos,
- :contents,
- :face,
- :bg_color, # For the time being, this line should stay here for the compatibility with IRB.
- :width,
- :height,
- :scrollbar,
- keyword_init: true
- )
-
- class Core
- ATTR_READER_NAMES = %i(
- completion_append_character
- basic_word_break_characters
- completer_word_break_characters
- basic_quote_characters
- completer_quote_characters
- filename_quote_characters
- special_prefixes
- completion_proc
- output_modifier_proc
- prompt_proc
- auto_indent_proc
- pre_input_hook
- dig_perfect_match_proc
- ).each(&method(:attr_reader))
-
- attr_accessor :config
- attr_accessor :key_stroke
- attr_accessor :line_editor
- attr_accessor :last_incremental_search
- attr_reader :output
-
- extend Forwardable
- def_delegators :config,
- :autocompletion,
- :autocompletion=
-
- def initialize
- self.output = STDOUT
- @mutex = Mutex.new
- @dialog_proc_list = {}
- yield self
- @completion_quote_character = nil
- end
-
- def io_gate
- Reline::IOGate
- end
-
- def encoding
- io_gate.encoding
- end
-
- def completion_append_character=(val)
- if val.nil?
- @completion_append_character = nil
- elsif val.size == 1
- @completion_append_character = val.encode(encoding)
- elsif val.size > 1
- @completion_append_character = val[0].encode(encoding)
- else
- @completion_append_character = nil
- end
- end
-
- def basic_word_break_characters=(v)
- @basic_word_break_characters = v.encode(encoding)
- end
-
- def completer_word_break_characters=(v)
- @completer_word_break_characters = v.encode(encoding)
- end
-
- def basic_quote_characters=(v)
- @basic_quote_characters = v.encode(encoding)
- end
-
- def completer_quote_characters=(v)
- @completer_quote_characters = v.encode(encoding)
- end
-
- def filename_quote_characters=(v)
- @filename_quote_characters = v.encode(encoding)
- end
-
- def special_prefixes=(v)
- @special_prefixes = v.encode(encoding)
- end
-
- def completion_case_fold=(v)
- @config.completion_ignore_case = v
- end
-
- def completion_case_fold
- @config.completion_ignore_case
- end
-
- def completion_quote_character
- @completion_quote_character
- end
-
- def completion_proc=(p)
- raise ArgumentError unless p.respond_to?(:call) or p.nil?
- @completion_proc = p
- end
-
- def output_modifier_proc=(p)
- raise ArgumentError unless p.respond_to?(:call) or p.nil?
- @output_modifier_proc = p
- end
-
- def prompt_proc=(p)
- raise ArgumentError unless p.respond_to?(:call) or p.nil?
- @prompt_proc = p
- end
-
- def auto_indent_proc=(p)
- raise ArgumentError unless p.respond_to?(:call) or p.nil?
- @auto_indent_proc = p
- end
-
- def pre_input_hook=(p)
- @pre_input_hook = p
- end
-
- def dig_perfect_match_proc=(p)
- raise ArgumentError unless p.respond_to?(:call) or p.nil?
- @dig_perfect_match_proc = p
- end
-
- DialogProc = Struct.new(:dialog_proc, :context)
- def add_dialog_proc(name_sym, p, context = nil)
- raise ArgumentError unless name_sym.instance_of?(Symbol)
- if p.nil?
- @dialog_proc_list.delete(name_sym)
- else
- raise ArgumentError unless p.respond_to?(:call)
- @dialog_proc_list[name_sym] = DialogProc.new(p, context)
- end
- end
-
- def dialog_proc(name_sym)
- @dialog_proc_list[name_sym]
- end
-
- def input=(val)
- raise TypeError unless val.respond_to?(:getc) or val.nil?
- if val.respond_to?(:getc) && io_gate.respond_to?(:input=)
- io_gate.input = val
- end
- end
-
- def output=(val)
- raise TypeError unless val.respond_to?(:write) or val.nil?
- @output = val
- io_gate.output = val
- end
-
- def vi_editing_mode
- config.editing_mode = :vi_insert
- nil
- end
-
- def emacs_editing_mode
- config.editing_mode = :emacs
- nil
- end
-
- def vi_editing_mode?
- config.editing_mode_is?(:vi_insert, :vi_command)
- end
-
- def emacs_editing_mode?
- config.editing_mode_is?(:emacs)
- end
-
- def get_screen_size
- io_gate.get_screen_size
- end
-
- Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
- # autocomplete
- return unless config.autocompletion
-
- journey_data = completion_journey_data
- return unless journey_data
-
- target = journey_data.list.first
- completed = journey_data.list[journey_data.pointer]
- result = journey_data.list.drop(1)
- pointer = journey_data.pointer - 1
- return if completed.empty? || (result == [completed] && pointer < 0)
-
- target_width = Reline::Unicode.calculate_width(target)
- completed_width = Reline::Unicode.calculate_width(completed)
- if cursor_pos.x <= completed_width - target_width
- # When target is rendered on the line above cursor position
- x = screen_width - completed_width
- y = -1
- else
- x = [cursor_pos.x - completed_width, 0].max
- y = 0
- end
- cursor_pos_to_render = Reline::CursorPos.new(x, y)
- if context and context.is_a?(Array)
- context.clear
- context.push(cursor_pos_to_render, result, pointer, dialog)
- end
- dialog.pointer = pointer
- DialogRenderInfo.new(
- pos: cursor_pos_to_render,
- contents: result,
- scrollbar: true,
- height: [15, preferred_dialog_height].min,
- face: :completion_dialog
- )
- }
- Reline::DEFAULT_DIALOG_CONTEXT = Array.new
-
- def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
- @mutex.synchronize do
- unless confirm_multiline_termination
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
- end
-
- io_gate.with_raw_input do
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
- end
-
- whole_buffer = line_editor.whole_buffer.dup
- whole_buffer.taint if RUBY_VERSION < '2.7'
- if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
- Reline::HISTORY << whole_buffer
- end
-
- if line_editor.eof?
- line_editor.reset_line
- # Return nil if the input is aborted by C-d.
- nil
- else
- whole_buffer
- end
- end
- end
-
- def readline(prompt = '', add_hist = false)
- @mutex.synchronize do
- io_gate.with_raw_input do
- inner_readline(prompt, add_hist, false)
- end
-
- line = line_editor.line.dup
- line.taint if RUBY_VERSION < '2.7'
- if add_hist and line and line.chomp("\n").size > 0
- Reline::HISTORY << line.chomp("\n")
- end
-
- line_editor.reset_line if line_editor.line.nil?
- line
- end
- end
-
- private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
- if ENV['RELINE_STDERR_TTY']
- if io_gate.win?
- $stderr = File.open(ENV['RELINE_STDERR_TTY'], 'a')
- else
- $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
- end
- $stderr.sync = true
- $stderr.puts "Reline is used by #{Process.pid}"
- end
- unless config.test_mode or config.loaded?
- config.read
- io_gate.set_default_key_bindings(config)
- end
- otio = io_gate.prep
-
- may_req_ambiguous_char_width
- key_stroke.encoding = encoding
- line_editor.reset(prompt)
- if multiline
- line_editor.multiline_on
- if block_given?
- line_editor.confirm_multiline_termination_proc = confirm_multiline_termination
- end
- else
- line_editor.multiline_off
- end
- line_editor.completion_proc = completion_proc
- line_editor.completion_append_character = completion_append_character
- line_editor.output_modifier_proc = output_modifier_proc
- line_editor.prompt_proc = prompt_proc
- line_editor.auto_indent_proc = auto_indent_proc
- line_editor.dig_perfect_match_proc = dig_perfect_match_proc
-
- # Readline calls pre_input_hook just after printing the first prompt.
- line_editor.print_nomultiline_prompt
- pre_input_hook&.call
-
- unless Reline::IOGate.dumb?
- @dialog_proc_list.each_pair do |name_sym, d|
- line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
- end
- end
-
- line_editor.update_dialogs
- line_editor.rerender
-
- begin
- line_editor.set_signal_handlers
- loop do
- read_io(config.keyseq_timeout) { |inputs|
- inputs.each do |key|
- case key.method_symbol
- when :bracketed_paste_start
- # io_gate is Reline::ANSI because the key :bracketed_paste_start is only assigned in Reline::ANSI
- key = Reline::Key.new(io_gate.read_bracketed_paste, :insert_multiline_text)
- when :quoted_insert, :ed_quoted_insert
- key = Reline::Key.new(io_gate.read_single_char(config.keyseq_timeout), :insert_raw_char)
- end
- line_editor.set_pasting_state(io_gate.in_pasting?)
- line_editor.update(key)
- end
- }
- if line_editor.finished?
- line_editor.render_finished
- break
- else
- line_editor.rerender
- end
- end
- io_gate.move_cursor_column(0)
- rescue Errno::EIO
- # Maybe the I/O has been closed.
- ensure
- line_editor.finalize
- io_gate.deprep(otio)
- end
- end
-
- # GNU Readline watis for "keyseq-timeout" milliseconds when the input is
- # ambiguous whether it is matching or matched.
- # If the next character does not arrive within the specified timeout, input
- # is considered as matched.
- # `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
- # `ESC char` or part of CSI sequence (matching).
- private def read_io(keyseq_timeout, &block)
- buffer = []
- status = KeyStroke::MATCHING
- loop do
- timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
- c = io_gate.getc(timeout)
- if c.nil? || c == -1
- if status == KeyStroke::MATCHING_MATCHED
- status = KeyStroke::MATCHED
- elsif buffer.empty?
- # io_gate is closed and reached EOF
- block.call([Key.new(nil, nil, false)])
- return
- else
- status = KeyStroke::UNMATCHED
- end
- else
- buffer << c
- status = key_stroke.match_status(buffer)
- end
-
- if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
- expanded, rest_bytes = key_stroke.expand(buffer)
- rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
- block.call(expanded)
- return
- end
- end
- end
-
- def ambiguous_width
- may_req_ambiguous_char_width unless defined? @ambiguous_width
- @ambiguous_width
- end
-
- private def may_req_ambiguous_char_width
- @ambiguous_width = 1 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
- return if defined? @ambiguous_width
- io_gate.move_cursor_column(0)
- begin
- output.write "\u{25bd}"
- rescue Encoding::UndefinedConversionError
- # LANG=C
- @ambiguous_width = 1
- else
- @ambiguous_width = io_gate.cursor_pos.x == 2 ? 2 : 1
- end
- io_gate.move_cursor_column(0)
- io_gate.erase_after_cursor
- end
- end
-
- extend Forwardable
- extend SingleForwardable
-
- #--------------------------------------------------------
- # Documented API
- #--------------------------------------------------------
-
- (Core::ATTR_READER_NAMES).each { |name|
- def_single_delegators :core, :"#{name}", :"#{name}="
- }
- def_single_delegators :core, :input=, :output=
- def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
- def_single_delegators :core, :readline
- def_single_delegators :core, :completion_case_fold, :completion_case_fold=
- def_single_delegators :core, :completion_quote_character
- def_instance_delegators self, :readline
- private :readline
-
-
- #--------------------------------------------------------
- # Undocumented API
- #--------------------------------------------------------
-
- # Testable in original
- def_single_delegators :core, :get_screen_size
- def_single_delegators :line_editor, :eof?
- def_instance_delegators self, :eof?
- def_single_delegators :line_editor, :delete_text
- def_single_delegator :line_editor, :line, :line_buffer
- def_single_delegator :line_editor, :byte_pointer, :point
- def_single_delegator :line_editor, :byte_pointer=, :point=
-
- def self.insert_text(text)
- line_editor.insert_multiline_text(text)
- self
- end
-
- # Untestable in original
- def_single_delegator :line_editor, :rerender, :redisplay
- def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
- def_single_delegators :core, :ambiguous_width
- def_single_delegators :core, :last_incremental_search
- def_single_delegators :core, :last_incremental_search=
- def_single_delegators :core, :add_dialog_proc
- def_single_delegators :core, :dialog_proc
- def_single_delegators :core, :autocompletion, :autocompletion=
-
- def_single_delegators :core, :readmultiline
- def_instance_delegators self, :readmultiline
- private :readmultiline
-
- def self.encoding_system_needs
- self.core.encoding
- end
-
- def self.core
- @core ||= Core.new { |core|
- core.config = Reline::Config.new
- core.key_stroke = Reline::KeyStroke.new(core.config, core.encoding)
- core.line_editor = Reline::LineEditor.new(core.config)
-
- core.basic_word_break_characters = " \t\n`><=;|&{("
- core.completer_word_break_characters = " \t\n`><=;|&{("
- core.basic_quote_characters = '"\''
- core.completer_quote_characters = '"\''
- core.filename_quote_characters = ""
- core.special_prefixes = ""
- core.add_dialog_proc(:autocomplete, Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE, Reline::DEFAULT_DIALOG_CONTEXT)
- }
- end
-
- def self.ungetc(c)
- core.io_gate.ungetc(c)
- end
-
- def self.line_editor
- core.line_editor
- end
-end
-
-
-Reline::IOGate = Reline::IO.decide_io_gate
-
-# Deprecated
-Reline::GeneralIO = Reline::Dumb.new
-
-Reline::Face.load_initial_configs
-
-Reline::HISTORY = Reline::History.new(Reline.core.config)
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
deleted file mode 100644
index e0fc37fc68..0000000000
--- a/lib/reline/config.rb
+++ /dev/null
@@ -1,373 +0,0 @@
-class Reline::Config
- attr_reader :test_mode
-
- KEYSEQ_PATTERN = /\\(?:C|Control)-[A-Za-z_]|\\(?:M|Meta)-[0-9A-Za-z_]|\\(?:C|Control)-\\(?:M|Meta)-[A-Za-z_]|\\(?:M|Meta)-\\(?:C|Control)-[A-Za-z_]|\\e|\\[\\\"\'abdfnrtv]|\\\d{1,3}|\\x\h{1,2}|./
-
- class InvalidInputrc < RuntimeError
- attr_accessor :file, :lineno
- end
-
- VARIABLE_NAMES = %w{
- completion-ignore-case
- convert-meta
- disable-completion
- history-size
- keyseq-timeout
- show-all-if-ambiguous
- show-mode-in-prompt
- vi-cmd-mode-string
- vi-ins-mode-string
- emacs-mode-string
- enable-bracketed-paste
- isearch-terminators
- }
- VARIABLE_NAME_SYMBOLS = VARIABLE_NAMES.map { |v| :"#{v.tr(?-, ?_)}" }
- VARIABLE_NAME_SYMBOLS.each do |v|
- attr_accessor v
- end
-
- attr_accessor :autocompletion
-
- def initialize
- reset_variables
- end
-
- def reset
- if editing_mode_is?(:vi_command)
- @editing_mode_label = :vi_insert
- end
- @oneshot_key_bindings.clear
- end
-
- def reset_variables
- @additional_key_bindings = { # from inputrc
- emacs: Reline::KeyActor::Base.new,
- vi_insert: Reline::KeyActor::Base.new,
- vi_command: Reline::KeyActor::Base.new
- }
- @oneshot_key_bindings = Reline::KeyActor::Base.new
- @editing_mode_label = :emacs
- @keymap_label = :emacs
- @keymap_prefix = []
- @default_key_bindings = {
- emacs: Reline::KeyActor::Base.new(Reline::KeyActor::EMACS_MAPPING),
- vi_insert: Reline::KeyActor::Base.new(Reline::KeyActor::VI_INSERT_MAPPING),
- vi_command: Reline::KeyActor::Base.new(Reline::KeyActor::VI_COMMAND_MAPPING)
- }
- @vi_cmd_mode_string = '(cmd)'
- @vi_ins_mode_string = '(ins)'
- @emacs_mode_string = '@'
- # https://tiswww.case.edu/php/chet/readline/readline.html#IDX25
- @history_size = -1 # unlimited
- @keyseq_timeout = 500
- @test_mode = false
- @autocompletion = false
- @convert_meta = seven_bit_encoding?(Reline::IOGate.encoding)
- @loaded = false
- @enable_bracketed_paste = true
- @show_mode_in_prompt = false
- @default_inputrc_path = nil
- end
-
- def editing_mode
- @default_key_bindings[@editing_mode_label]
- end
-
- def editing_mode=(val)
- @editing_mode_label = val
- end
-
- def editing_mode_is?(*val)
- val.any?(@editing_mode_label)
- end
-
- def keymap
- @default_key_bindings[@keymap_label]
- end
-
- def loaded?
- @loaded
- end
-
- def inputrc_path
- case ENV['INPUTRC']
- when nil, ''
- else
- return File.expand_path(ENV['INPUTRC'])
- end
-
- # In the XDG Specification, if ~/.config/readline/inputrc exists, then
- # ~/.inputrc should not be read, but for compatibility with GNU Readline,
- # if ~/.inputrc exists, then it is given priority.
- home_rc_path = File.expand_path('~/.inputrc')
- return home_rc_path if File.exist?(home_rc_path)
-
- case path = ENV['XDG_CONFIG_HOME']
- when nil, ''
- else
- path = File.join(path, 'readline/inputrc')
- return path if File.exist?(path) and path == File.expand_path(path)
- end
-
- path = File.expand_path('~/.config/readline/inputrc')
- return path if File.exist?(path)
-
- return home_rc_path
- end
-
- private def default_inputrc_path
- @default_inputrc_path ||= inputrc_path
- end
-
- def read(file = nil)
- @loaded = true
- file ||= default_inputrc_path
- begin
- if file.respond_to?(:readlines)
- lines = file.readlines
- else
- lines = File.readlines(file)
- end
- rescue Errno::ENOENT
- return nil
- end
-
- read_lines(lines, file)
- self
- rescue InvalidInputrc => e
- warn e.message
- nil
- end
-
- def key_bindings
- # The key bindings for each editing mode will be overwritten by the user-defined ones.
- Reline::KeyActor::Composite.new([@oneshot_key_bindings, @additional_key_bindings[@editing_mode_label], @default_key_bindings[@editing_mode_label]])
- end
-
- def add_oneshot_key_binding(keystroke, target)
- # IRB sets invalid keystroke [Reline::Key]. We should ignore it.
- return unless keystroke.all? { |c| c.is_a?(Integer) }
-
- @oneshot_key_bindings.add(keystroke, target)
- end
-
- def reset_oneshot_key_bindings
- @oneshot_key_bindings.clear
- end
-
- def add_default_key_binding_by_keymap(keymap, keystroke, target)
- @default_key_bindings[keymap].add(keystroke, target)
- end
-
- def add_default_key_binding(keystroke, target)
- add_default_key_binding_by_keymap(@keymap_label, keystroke, target)
- end
-
- def read_lines(lines, file = nil)
- if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
- begin
- lines = lines.map do |l|
- l.encode(Reline.encoding_system_needs)
- rescue Encoding::UndefinedConversionError
- mes = "The inputrc encoded in #{lines.first.encoding.name} can't be converted to the locale #{Reline.encoding_system_needs.name}."
- raise Reline::ConfigEncodingConversionError.new(mes)
- end
- end
- end
- if_stack = []
-
- lines.each_with_index do |line, no|
- next if line.match(/\A\s*#/)
-
- no += 1
-
- line = line.chomp.lstrip
- if line.start_with?('$')
- handle_directive(line[1..-1], file, no, if_stack)
- next
- end
-
- next if if_stack.any? { |_no, skip| skip }
-
- case line
- when /^set +([^ ]+) +(.+)/i
- # value ignores everything after a space, raw_value does not.
- var, value, raw_value = $1.downcase, $2.partition(' ').first, $2
- bind_variable(var, value, raw_value)
- when /^\s*(?:M|Meta)-([a-zA-Z_])\s*:\s*(.*)\s*$/o
- bind_key("\"\\M-#$1\"", $2)
- when /^\s*(?:C|Control)-([a-zA-Z_])\s*:\s*(.*)\s*$/o
- bind_key("\"\\C-#$1\"", $2)
- when /^\s*(?:(?:C|Control)-(?:M|Meta)|(?:M|Meta)-(?:C|Control))-([a-zA-Z_])\s*:\s*(.*)\s*$/o
- bind_key("\"\\M-\\C-#$1\"", $2)
- when /^\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
- bind_key($1, $2)
- end
- end
- unless if_stack.empty?
- raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
- end
- end
-
- def handle_directive(directive, file, no, if_stack)
- directive, args = directive.split(' ')
- case directive
- when 'if'
- condition = false
- case args
- when /^mode=(vi|emacs)$/i
- mode = $1.downcase
- # NOTE: mode=vi means vi-insert mode
- mode = 'vi_insert' if mode == 'vi'
- if @editing_mode_label == mode.to_sym
- condition = true
- end
- when 'term'
- when 'version'
- else # application name
- condition = true if args == 'Ruby'
- condition = true if args == 'Reline'
- end
- if_stack << [no, !condition]
- when 'else'
- if if_stack.empty?
- raise InvalidInputrc, "#{file}:#{no}: unmatched else"
- end
- if_stack.last[1] = !if_stack.last[1]
- when 'endif'
- if if_stack.empty?
- raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
- end
- if_stack.pop
- when 'include'
- read(File.expand_path(args))
- end
- end
-
- def bind_variable(name, value, raw_value)
- case name
- when 'history-size'
- begin
- @history_size = Integer(value)
- rescue ArgumentError
- @history_size = 500
- end
- when 'isearch-terminators'
- @isearch_terminators = retrieve_string(raw_value)
- when 'editing-mode'
- case value
- when 'emacs'
- @editing_mode_label = :emacs
- @keymap_label = :emacs
- @keymap_prefix = []
- when 'vi'
- @editing_mode_label = :vi_insert
- @keymap_label = :vi_insert
- @keymap_prefix = []
- end
- when 'keymap'
- case value
- when 'emacs', 'emacs-standard'
- @keymap_label = :emacs
- @keymap_prefix = []
- when 'emacs-ctlx'
- @keymap_label = :emacs
- @keymap_prefix = [?\C-x.ord]
- when 'emacs-meta'
- @keymap_label = :emacs
- @keymap_prefix = [?\e.ord]
- when 'vi', 'vi-move', 'vi-command'
- @keymap_label = :vi_command
- @keymap_prefix = []
- when 'vi-insert'
- @keymap_label = :vi_insert
- @keymap_prefix = []
- end
- when 'keyseq-timeout'
- @keyseq_timeout = value.to_i
- when 'show-mode-in-prompt'
- case value
- when 'off'
- @show_mode_in_prompt = false
- when 'on'
- @show_mode_in_prompt = true
- else
- @show_mode_in_prompt = false
- end
- when 'vi-cmd-mode-string'
- @vi_cmd_mode_string = retrieve_string(raw_value)
- when 'vi-ins-mode-string'
- @vi_ins_mode_string = retrieve_string(raw_value)
- when 'emacs-mode-string'
- @emacs_mode_string = retrieve_string(raw_value)
- when *VARIABLE_NAMES then
- variable_name = :"@#{name.tr(?-, ?_)}"
- instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
- end
- end
-
- def retrieve_string(str)
- str = $1 if str =~ /\A"(.*)"\z/
- parse_keyseq(str).map { |c| c.chr(Reline.encoding_system_needs) }.join
- end
-
- def bind_key(key, value)
- keystroke, func = parse_key_binding(key, value)
- @additional_key_bindings[@keymap_label].add(@keymap_prefix + keystroke, func) if keystroke
- end
-
- def parse_key_binding(key, func_name)
- if key =~ /\A"(.*)"\z/
- keyseq = parse_keyseq($1)
- else
- keyseq = nil
- end
- if func_name =~ /"(.*)"/
- func = parse_keyseq($1)
- else
- func = func_name.split.first.tr(?-, ?_).to_sym # It must be macro.
- end
- [keyseq, func]
- end
-
- def key_notation_to_code(notation)
- case notation
- when /(?:\\(?:C|Control)-\\(?:M|Meta)|\\(?:M|Meta)-\\(?:C|Control))-([A-Za-z_])/
- [?\e.ord, $1.ord % 32]
- when /\\(?:C|Control)-([A-Za-z_])/
- ($1.upcase.ord % 32)
- when /\\(?:M|Meta)-([0-9A-Za-z_])/
- [?\e.ord, $1.ord]
- when /\\(\d{1,3})/ then $1.to_i(8) # octal
- when /\\x(\h{1,2})/ then $1.to_i(16) # hexadecimal
- when "\\e" then ?\e.ord
- when "\\\\" then ?\\.ord
- when "\\\"" then ?".ord
- when "\\'" then ?'.ord
- when "\\a" then ?\a.ord
- when "\\b" then ?\b.ord
- when "\\d" then ?\d.ord
- when "\\f" then ?\f.ord
- when "\\n" then ?\n.ord
- when "\\r" then ?\r.ord
- when "\\t" then ?\t.ord
- when "\\v" then ?\v.ord
- else notation.ord
- end
- end
-
- def parse_keyseq(str)
- str.scan(KEYSEQ_PATTERN).flat_map do |notation|
- key_notation_to_code(notation)
- end
- end
-
- def reload
- reset_variables
- read
- end
-
- private def seven_bit_encoding?(encoding)
- encoding == Encoding::US_ASCII
- end
-end
diff --git a/lib/reline/face.rb b/lib/reline/face.rb
deleted file mode 100644
index 5b4464a623..0000000000
--- a/lib/reline/face.rb
+++ /dev/null
@@ -1,199 +0,0 @@
-# frozen_string_literal: true
-
-class Reline::Face
- SGR_PARAMETERS = {
- foreground: {
- black: 30,
- red: 31,
- green: 32,
- yellow: 33,
- blue: 34,
- magenta: 35,
- cyan: 36,
- white: 37,
- bright_black: 90,
- gray: 90,
- bright_red: 91,
- bright_green: 92,
- bright_yellow: 93,
- bright_blue: 94,
- bright_magenta: 95,
- bright_cyan: 96,
- bright_white: 97
- },
- background: {
- black: 40,
- red: 41,
- green: 42,
- yellow: 43,
- blue: 44,
- magenta: 45,
- cyan: 46,
- white: 47,
- bright_black: 100,
- gray: 100,
- bright_red: 101,
- bright_green: 102,
- bright_yellow: 103,
- bright_blue: 104,
- bright_magenta: 105,
- bright_cyan: 106,
- bright_white: 107,
- },
- style: {
- reset: 0,
- bold: 1,
- faint: 2,
- italicized: 3,
- underlined: 4,
- slowly_blinking: 5,
- blinking: 5,
- rapidly_blinking: 6,
- negative: 7,
- concealed: 8,
- crossed_out: 9
- }
- }.freeze
-
- class Config
- ESSENTIAL_DEFINE_NAMES = %i(default enhanced scrollbar).freeze
- RESET_SGR = "\e[0m".freeze
-
- def initialize(name, &block)
- @definition = {}
- block.call(self)
- ESSENTIAL_DEFINE_NAMES.each do |name|
- @definition[name] ||= { style: :reset, escape_sequence: RESET_SGR }
- end
- end
-
- attr_reader :definition
-
- def define(name, **values)
- values[:escape_sequence] = format_to_sgr(values.to_a).freeze
- @definition[name] = values
- end
-
- def reconfigure
- @definition.each_value do |values|
- values.delete(:escape_sequence)
- values[:escape_sequence] = format_to_sgr(values.to_a).freeze
- end
- end
-
- def [](name)
- @definition.dig(name, :escape_sequence) or raise ArgumentError, "unknown face: #{name}"
- end
-
- private
-
- def sgr_rgb(key, value)
- return nil unless rgb_expression?(value)
- if Reline::Face.truecolor?
- sgr_rgb_truecolor(key, value)
- else
- sgr_rgb_256color(key, value)
- end
- end
-
- def sgr_rgb_truecolor(key, value)
- case key
- when :foreground
- "38;2;"
- when :background
- "48;2;"
- end + value[1, 6].scan(/../).map(&:hex).join(";")
- end
-
- def sgr_rgb_256color(key, value)
- # 256 colors are
- # 0..15: standard colors, high intensity colors
- # 16..232: 216 colors (R, G, B each 6 steps)
- # 233..255: grayscale colors (24 steps)
- # This methods converts rgb_expression to 216 colors
- rgb = value[1, 6].scan(/../).map(&:hex)
- # Color steps are [0, 95, 135, 175, 215, 255]
- r, g, b = rgb.map { |v| v <= 95 ? v / 48 : (v - 35) / 40 }
- color = (16 + 36 * r + 6 * g + b)
- case key
- when :foreground
- "38;5;#{color}"
- when :background
- "48;5;#{color}"
- end
- end
-
- def format_to_sgr(ordered_values)
- sgr = "\e[" + ordered_values.map do |key_value|
- key, value = key_value
- case key
- when :foreground, :background
- case value
- when Symbol
- SGR_PARAMETERS[key][value]
- when String
- sgr_rgb(key, value)
- end
- when :style
- [ value ].flatten.map do |style_name|
- SGR_PARAMETERS[:style][style_name]
- end.then do |sgr_parameters|
- sgr_parameters.include?(nil) ? nil : sgr_parameters
- end
- end.then do |rendition_expression|
- unless rendition_expression
- raise ArgumentError, "invalid SGR parameter: #{value.inspect}"
- end
- rendition_expression
- end
- end.join(';') + "m"
- sgr == RESET_SGR ? RESET_SGR : RESET_SGR + sgr
- end
-
- def rgb_expression?(color)
- color.respond_to?(:match?) and color.match?(/\A#[0-9a-fA-F]{6}\z/)
- end
- end
-
- private_constant :SGR_PARAMETERS, :Config
-
- def self.truecolor?
- @force_truecolor || %w[truecolor 24bit].include?(ENV['COLORTERM'])
- end
-
- def self.force_truecolor
- @force_truecolor = true
- @configs&.each_value(&:reconfigure)
- end
-
- def self.[](name)
- @configs[name]
- end
-
- def self.config(name, &block)
- @configs ||= {}
- @configs[name] = Config.new(name, &block)
- end
-
- def self.configs
- @configs.transform_values(&:definition)
- end
-
- def self.load_initial_configs
- config(:default) do |conf|
- conf.define :default, style: :reset
- conf.define :enhanced, style: :reset
- conf.define :scrollbar, style: :reset
- end
- config(:completion_dialog) do |conf|
- conf.define :default, foreground: :bright_white, background: :gray
- conf.define :enhanced, foreground: :black, background: :white
- conf.define :scrollbar, foreground: :white, background: :gray
- end
- end
-
- def self.reset_to_initial_configs
- @configs = {}
- load_initial_configs
- end
-end
diff --git a/lib/reline/history.rb b/lib/reline/history.rb
deleted file mode 100644
index 47c68ba774..0000000000
--- a/lib/reline/history.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-class Reline::History < Array
- def initialize(config)
- @config = config
- end
-
- def to_s
- 'HISTORY'
- end
-
- def delete_at(index)
- index = check_index(index)
- super(index)
- end
-
- def [](index)
- index = check_index(index) unless index.is_a?(Range)
- super(index)
- end
-
- def []=(index, val)
- index = check_index(index)
- super(index, Reline::Unicode.safe_encode(val, Reline.encoding_system_needs))
- end
-
- def concat(*val)
- val.each do |v|
- push(*v)
- end
- end
-
- def push(*val)
- # If history_size is zero, all histories are dropped.
- return self if @config.history_size.zero?
- # If history_size is negative, history size is unlimited.
- if @config.history_size.positive?
- diff = size + val.size - @config.history_size
- if diff > 0
- if diff <= size
- shift(diff)
- else
- diff -= size
- clear
- val.shift(diff)
- end
- end
- end
- super(*(val.map{ |v|
- Reline::Unicode.safe_encode(v, Reline.encoding_system_needs)
- }))
- end
-
- def <<(val)
- # If history_size is zero, all histories are dropped.
- return self if @config.history_size.zero?
- # If history_size is negative, history size is unlimited.
- if @config.history_size.positive?
- shift if size + 1 > @config.history_size
- end
- super(Reline::Unicode.safe_encode(val, Reline.encoding_system_needs))
- end
-
- private def check_index(index)
- index += size if index < 0
- if index < -2147483648 or 2147483647 < index
- raise RangeError.new("integer #{index} too big to convert to 'int'")
- end
- # If history_size is negative, history size is unlimited.
- if @config.history_size.positive?
- if index < [email protected]_size or @config.history_size < index
- raise RangeError.new("index=<#{index}>")
- end
- end
- raise IndexError.new("index=<#{index}>") if index < 0 or size <= index
- index
- end
-end
diff --git a/lib/reline/io.rb b/lib/reline/io.rb
deleted file mode 100644
index 0f48f53b82..0000000000
--- a/lib/reline/io.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-
-module Reline
- class IO
- RESET_COLOR = "\e[0m"
-
- def self.decide_io_gate
- if ENV['TERM'] == 'dumb'
- Reline::Dumb.new
- else
- require 'reline/io/ansi'
-
- case RbConfig::CONFIG['host_os']
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- require 'reline/io/windows'
- io = Reline::Windows.new
- if io.msys_tty?
- Reline::ANSI.new
- else
- io
- end
- else
- Reline::ANSI.new
- end
- end
- end
-
- def dumb?
- false
- end
-
- def win?
- false
- end
-
- def reset_color_sequence
- self.class::RESET_COLOR
- end
-
- # Read a single encoding valid character from the input.
- def read_single_char(keyseq_timeout)
- buffer = String.new(encoding: Encoding::ASCII_8BIT)
- loop do
- timeout = buffer.empty? ? Float::INFINITY : keyseq_timeout
- c = getc(timeout)
- return unless c
-
- buffer << c
- encoded = buffer.dup.force_encoding(encoding)
- return encoded if encoded.valid_encoding?
- end
- end
- end
-end
-
-require 'reline/io/dumb'
diff --git a/lib/reline/io/ansi.rb b/lib/reline/io/ansi.rb
deleted file mode 100644
index 1d20719779..0000000000
--- a/lib/reline/io/ansi.rb
+++ /dev/null
@@ -1,332 +0,0 @@
-require 'io/console'
-require 'io/wait'
-
-class Reline::ANSI < Reline::IO
- CAPNAME_KEY_BINDINGS = {
- 'khome' => :ed_move_to_beg,
- 'kend' => :ed_move_to_end,
- 'kdch1' => :key_delete,
- 'kpp' => :ed_search_prev_history,
- 'knp' => :ed_search_next_history,
- 'kcuu1' => :ed_prev_history,
- 'kcud1' => :ed_next_history,
- 'kcuf1' => :ed_next_char,
- 'kcub1' => :ed_prev_char,
- }
-
- ANSI_CURSOR_KEY_BINDINGS = {
- # Up
- 'A' => [:ed_prev_history, {}],
- # Down
- 'B' => [:ed_next_history, {}],
- # Right
- 'C' => [:ed_next_char, { ctrl: :em_next_word, meta: :em_next_word }],
- # Left
- 'D' => [:ed_prev_char, { ctrl: :ed_prev_word, meta: :ed_prev_word }],
- # End
- 'F' => [:ed_move_to_end, {}],
- # Home
- 'H' => [:ed_move_to_beg, {}],
- }
-
- attr_writer :input, :output
-
- def initialize
- @input = STDIN
- @output = STDOUT
- @buf = []
- @output_buffer = nil
- @old_winch_handler = nil
- end
-
- def encoding
- @input.external_encoding || Encoding.default_external
- rescue IOError
- # STDIN.external_encoding raises IOError in Ruby <= 3.0 when STDIN is closed
- Encoding.default_external
- end
-
- def set_default_key_bindings(config)
- set_bracketed_paste_key_bindings(config)
- set_default_key_bindings_ansi_cursor(config)
- set_default_key_bindings_comprehensive_list(config)
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- end
- {
- # default bindings
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
- end
-
- def set_bracketed_paste_key_bindings(config)
- [:emacs, :vi_insert, :vi_command].each do |keymap|
- config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
- end
- end
-
- def set_default_key_bindings_ansi_cursor(config)
- ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
- bindings = [
- ["\e[#{char}", default_func], # CSI + char
- ["\eO#{char}", default_func] # SS3 + char, application cursor key mode
- ]
- if modifiers[:ctrl]
- # CSI + ctrl_key_modifier + char
- bindings << ["\e[1;5#{char}", modifiers[:ctrl]]
- end
- if modifiers[:meta]
- # CSI + meta_key_modifier + char
- bindings << ["\e[1;3#{char}", modifiers[:meta]]
- # Meta(ESC) + CSI + char
- bindings << ["\e\e[#{char}", modifiers[:meta]]
- end
- bindings.each do |sequence, func|
- key = sequence.bytes
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
- end
-
- def set_default_key_bindings_comprehensive_list(config)
- {
- # xterm
- [27, 91, 51, 126] => :key_delete, # kdch1
- [27, 91, 53, 126] => :ed_search_prev_history, # kpp
- [27, 91, 54, 126] => :ed_search_next_history, # knp
-
- # Console (80x25)
- [27, 91, 49, 126] => :ed_move_to_beg, # Home
- [27, 91, 52, 126] => :ed_move_to_end, # End
-
- # urxvt / exoterm
- [27, 91, 55, 126] => :ed_move_to_beg, # Home
- [27, 91, 56, 126] => :ed_move_to_end, # End
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
-
- def with_raw_input
- if @input.tty?
- @input.raw(intr: true) { yield }
- else
- yield
- end
- end
-
- def inner_getc(timeout_second)
- unless @buf.empty?
- return @buf.shift
- end
- until @input.wait_readable(0.01)
- timeout_second -= 0.01
- return nil if timeout_second <= 0
-
- Reline.core.line_editor.handle_signal
- end
- c = @input.getbyte
- (c == 0x16 && @input.tty? && @input.raw(min: 0, time: 0, &:getbyte)) || c
- rescue Errno::EIO
- # Maybe the I/O has been closed.
- nil
- end
-
- START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
- END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
- def read_bracketed_paste
- buffer = String.new(encoding: Encoding::ASCII_8BIT)
- until buffer.end_with?(END_BRACKETED_PASTE)
- c = inner_getc(Float::INFINITY)
- break unless c
- buffer << c
- end
- string = buffer.delete_suffix(END_BRACKETED_PASTE).force_encoding(encoding)
- string.valid_encoding? ? string : ''
- end
-
- # if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
- def getc(timeout_second)
- inner_getc(timeout_second)
- end
-
- def in_pasting?
- not empty_buffer?
- end
-
- def empty_buffer?
- unless @buf.empty?
- return false
- end
- [email protected]_readable(0)
- end
-
- def ungetc(c)
- @buf.unshift(c)
- end
-
- def retrieve_keybuffer
- begin
- return unless @input.wait_readable(0.001)
- str = @input.read_nonblock(1024)
- str.bytes.each do |c|
- @buf.push(c)
- end
- rescue EOFError
- end
- end
-
- def get_screen_size
- 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, Errno::ENODEV
- [24, 80]
- end
-
- def set_screen_size(rows, columns)
- @input.winsize = [rows, columns]
- self
- rescue Errno::ENOTTY, Errno::ENODEV
- self
- end
-
- private def cursor_pos_internal(timeout:)
- match = nil
- @input.raw do |stdin|
- @output << "\e[6n"
- @output.flush
- timeout_at = Time.now + timeout
- buf = +''
- while (wait = timeout_at - Time.now) > 0 && stdin.wait_readable(wait)
- buf << stdin.readpartial(1024)
- if (match = buf.match(/\e\[(?<row>\d+);(?<column>\d+)R/))
- buf = match.pre_match + match.post_match
- break
- end
- end
- buf.chars.reverse_each do |ch|
- stdin.ungetc ch
- end
- end
- [match[:column].to_i - 1, match[:row].to_i - 1] if match
- end
-
- def cursor_pos
- col, row = cursor_pos_internal(timeout: 0.5) if both_tty?
- Reline::CursorPos.new(col || 0, row || 0)
- end
-
- def both_tty?
- @input.tty? && @output.tty?
- end
-
- def write(string)
- if @output_buffer
- @output_buffer << string
- else
- @output.write(string)
- end
- end
-
- def buffered_output
- @output_buffer = +''
- yield
- @output.write(@output_buffer)
- ensure
- @output_buffer = nil
- end
-
- def move_cursor_column(x)
- write "\e[#{x + 1}G"
- end
-
- def move_cursor_up(x)
- if x > 0
- write "\e[#{x}A"
- elsif x < 0
- move_cursor_down(-x)
- end
- end
-
- def move_cursor_down(x)
- if x > 0
- write "\e[#{x}B"
- elsif x < 0
- move_cursor_up(-x)
- end
- end
-
- def hide_cursor
- write "\e[?25l"
- end
-
- def show_cursor
- write "\e[?25h"
- end
-
- def erase_after_cursor
- write "\e[K"
- end
-
- # This only works when the cursor is at the bottom of the scroll range
- # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
- def scroll_down(x)
- return if x.zero?
- # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
- write "\n" * x
- end
-
- def clear_screen
- write "\e[2J"
- write "\e[1;1H"
- end
-
- def set_winch_handler(&handler)
- @old_winch_handler = Signal.trap('WINCH') do |arg|
- handler.call
- @old_winch_handler.call(arg) if @old_winch_handler.respond_to?(:call)
- end
- @old_cont_handler = Signal.trap('CONT') do |arg|
- @input.raw!(intr: true) if @input.tty?
- # Rerender the screen. Note that screen size might be changed while suspended.
- handler.call
- @old_cont_handler.call(arg) if @old_cont_handler.respond_to?(:call)
- end
- rescue ArgumentError
- # Signal.trap may raise an ArgumentError if the platform doesn't support the signal.
- end
-
- def read_single_char(keyseq_timeout)
- # Disable intr to read `C-c` `C-z` `C-\` for quoted insert
- @input.raw(intr: false) do
- super
- end
- end
-
- def prep
- # Enable bracketed paste
- write "\e[?2004h" if Reline.core.config.enable_bracketed_paste && both_tty?
- retrieve_keybuffer
- nil
- end
-
- def deprep(otio)
- # Disable bracketed paste
- write "\e[?2004l" if Reline.core.config.enable_bracketed_paste && both_tty?
- Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler
- Signal.trap('CONT', @old_cont_handler) if @old_cont_handler
- end
-end
diff --git a/lib/reline/io/dumb.rb b/lib/reline/io/dumb.rb
deleted file mode 100644
index 0c04c755d2..0000000000
--- a/lib/reline/io/dumb.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-require 'io/wait'
-
-class Reline::Dumb < Reline::IO
- RESET_COLOR = '' # Do not send color reset sequence
-
- attr_writer :output
-
- def initialize(encoding: nil)
- @input = STDIN
- @output = STDOUT
- @buf = []
- @pasting = false
- @encoding = encoding
- @screen_size = [24, 80]
- end
-
- def dumb?
- true
- end
-
- def encoding
- if @encoding
- @encoding
- elsif RUBY_PLATFORM =~ /mswin|mingw/
- Encoding::UTF_8
- else
- @input.external_encoding || Encoding.default_external
- end
- rescue IOError
- # STDIN.external_encoding raises IOError in Ruby <= 3.0 when STDIN is closed
- Encoding.default_external
- end
-
- def set_default_key_bindings(_)
- end
-
- def input=(val)
- @input = val
- end
-
- def with_raw_input
- yield
- end
-
- def write(string)
- @output.write(string)
- end
-
- def buffered_output
- yield
- end
-
- def getc(_timeout_second)
- unless @buf.empty?
- return @buf.shift
- end
- c = nil
- loop do
- Reline.core.line_editor.handle_signal
- result = @input.wait_readable(0.1)
- next if result.nil?
- c = @input.read(1)
- break
- end
- c&.ord
- end
-
- def ungetc(c)
- @buf.unshift(c)
- end
-
- def get_screen_size
- @screen_size
- end
-
- def cursor_pos
- Reline::CursorPos.new(0, 0)
- end
-
- def hide_cursor
- end
-
- def show_cursor
- end
-
- def move_cursor_column(val)
- end
-
- def move_cursor_up(val)
- end
-
- def move_cursor_down(val)
- end
-
- def erase_after_cursor
- end
-
- def scroll_down(val)
- end
-
- def clear_screen
- end
-
- def set_screen_size(rows, columns)
- @screen_size = [rows, columns]
- end
-
- def set_winch_handler(&handler)
- end
-
- def in_pasting?
- @pasting
- end
-
- def prep
- end
-
- def deprep(otio)
- end
-end
diff --git a/lib/reline/io/windows.rb b/lib/reline/io/windows.rb
deleted file mode 100644
index 5c1ab6d080..0000000000
--- a/lib/reline/io/windows.rb
+++ /dev/null
@@ -1,530 +0,0 @@
-require 'fiddle/import'
-
-class Reline::Windows < Reline::IO
-
- attr_writer :output
-
- def initialize
- @input_buf = []
- @output_buf = []
-
- @output = STDOUT
- @hsg = nil
- @getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
- @kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
- @GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
- @GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
- @SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
- @GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
- @FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
- @ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
- @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
- @hConsoleInputHandle = @GetStdHandle.call(STD_INPUT_HANDLE)
- @GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
- @ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
- @GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
- @GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
- @FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
- @SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
-
- @GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
- @SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
- @WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
-
- @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
- end
-
- def encoding
- Encoding::UTF_8
- end
-
- def win?
- true
- end
-
- def win_legacy_console?
- @legacy_console
- end
-
- def set_default_key_bindings(config)
- {
- [224, 72] => :ed_prev_history, # ↑
- [224, 80] => :ed_next_history, # ↓
- [224, 77] => :ed_next_char, # →
- [224, 75] => :ed_prev_char, # ←
- [224, 83] => :key_delete, # Del
- [224, 71] => :ed_move_to_beg, # Home
- [224, 79] => :ed_move_to_end, # End
- [ 0, 72] => :ed_prev_history, # ↑
- [ 0, 80] => :ed_next_history, # ↓
- [ 0, 77] => :ed_next_char, # →
- [ 0, 75] => :ed_prev_char, # ←
- [ 0, 83] => :key_delete, # Del
- [ 0, 71] => :ed_move_to_beg, # Home
- [ 0, 79] => :ed_move_to_end # End
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
-
- {
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
-
- # Emulate ANSI key sequence.
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- end
- end
-
- if defined? JRUBY_VERSION
- require 'win32api'
- else
- class Win32API
- DLL = {}
- TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
- POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
-
- WIN32_TYPES = "VPpNnLlIi"
- DL_TYPES = "0SSI"
-
- def initialize(dllname, func, import, export = "0", calltype = :stdcall)
- @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
- import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
- export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
- calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
-
- handle = DLL[dllname] ||=
- begin
- Fiddle.dlopen(dllname)
- rescue Fiddle::DLError
- raise unless File.extname(dllname).empty?
- Fiddle.dlopen(dllname + ".dll")
- end
-
- @func = Fiddle::Function.new(handle[func], import, export, calltype)
- rescue Fiddle::DLError => e
- raise LoadError, e.message, e.backtrace
- end
-
- def call(*args)
- import = @proto.split("")
- args.each_with_index do |x, i|
- args[i], = [x == 0 ? nil : +x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
- args[i], = [x].pack("I").unpack("i") if import[i] == "I"
- end
- ret, = @func.call(*args)
- return ret || 0
- end
- end
- end
-
- VK_RETURN = 0x0D
- VK_MENU = 0x12 # ALT key
- VK_LMENU = 0xA4
- VK_CONTROL = 0x11
- VK_SHIFT = 0x10
- VK_DIVIDE = 0x6F
-
- KEY_EVENT = 0x01
- WINDOW_BUFFER_SIZE_EVENT = 0x04
-
- CAPSLOCK_ON = 0x0080
- ENHANCED_KEY = 0x0100
- LEFT_ALT_PRESSED = 0x0002
- LEFT_CTRL_PRESSED = 0x0008
- NUMLOCK_ON = 0x0020
- RIGHT_ALT_PRESSED = 0x0001
- RIGHT_CTRL_PRESSED = 0x0004
- SCROLLLOCK_ON = 0x0040
- SHIFT_PRESSED = 0x0010
-
- VK_TAB = 0x09
- VK_END = 0x23
- VK_HOME = 0x24
- VK_LEFT = 0x25
- VK_UP = 0x26
- VK_RIGHT = 0x27
- VK_DOWN = 0x28
- VK_DELETE = 0x2E
-
- STD_INPUT_HANDLE = -10
- STD_OUTPUT_HANDLE = -11
- FILE_TYPE_PIPE = 0x0003
- FILE_NAME_INFO = 2
- ENABLE_WRAP_AT_EOL_OUTPUT = 2
- ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
-
- # Calling Win32API with console handle is reported to fail after executing some external command.
- # We need to refresh console handle and retry the call again.
- private def call_with_console_handle(win32func, *args)
- val = win32func.call(@hConsoleHandle, *args)
- return val if val != 0
-
- @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
- win32func.call(@hConsoleHandle, *args)
- end
-
- private def getconsolemode
- mode = +"\0\0\0\0"
- call_with_console_handle(@GetConsoleMode, mode)
- mode.unpack1('L')
- end
-
- private def setconsolemode(mode)
- call_with_console_handle(@SetConsoleMode, mode)
- end
-
- #if @legacy_console
- # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- # @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- #end
-
- def 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].unpack1("L")
- 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
-
- KEY_MAP = [
- # It's treated as Meta+Enter on Windows.
- [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
- [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
-
- # It's treated as Meta+Space on Windows.
- [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
-
- # Emulate getwch() key sequences.
- [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
- [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
- [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
- [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
- [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
- [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
- [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
-
- # Emulate ANSI key sequence.
- [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
- ]
-
- def process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
-
- # high-surrogate
- if 0xD800 <= char_code and char_code <= 0xDBFF
- @hsg = char_code
- return
- end
- # low-surrogate
- if 0xDC00 <= char_code and char_code <= 0xDFFF
- if @hsg
- char_code = 0x10000 + (@hsg - 0xD800) * 0x400 + char_code - 0xDC00
- @hsg = nil
- else
- # no high-surrogate. ignored.
- return
- end
- else
- # ignore high-surrogate without low-surrogate if there
- @hsg = nil
- end
-
- key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
-
- match = KEY_MAP.find { |args,| key.match?(**args) }
- unless match.nil?
- @output_buf.concat(match.last)
- return
- end
-
- # no char, only control keys
- return if key.char_code == 0 and key.control_keys.any?
-
- @output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
-
- @output_buf.concat(key.char.bytes)
- end
-
- def check_input_event
- num_of_events = 0.chr * 8
- while @output_buf.empty?
- Reline.core.line_editor.handle_signal
- if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
- # prevent for background consolemode change
- @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
- next
- end
- next if @GetNumberOfConsoleInputEvents.(@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
- input_records = 0.chr * 20 * 80
- read_event = 0.chr * 4
- if @ReadConsoleInputW.(@hConsoleInputHandle, input_records, 80, read_event) != 0
- read_events = read_event.unpack1('L')
- 0.upto(read_events) do |idx|
- input_record = input_records[idx * 20, 20]
- event = input_record[0, 2].unpack1('s*')
- case event
- when WINDOW_BUFFER_SIZE_EVENT
- @winch_handler.()
- when KEY_EVENT
- key_down = input_record[4, 4].unpack1('l*')
- repeat_count = input_record[8, 2].unpack1('s*')
- virtual_key_code = input_record[10, 2].unpack1('s*')
- virtual_scan_code = input_record[12, 2].unpack1('s*')
- char_code = input_record[14, 2].unpack1('S*')
- control_key_state = input_record[16, 2].unpack1('S*')
- is_key_down = key_down.zero? ? false : true
- if is_key_down
- process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
- end
- end
- end
- end
- end
- end
-
- def with_raw_input
- yield
- end
-
- def write(string)
- @output.write(string)
- end
-
- def buffered_output
- yield
- end
-
- def getc(_timeout_second)
- check_input_event
- @output_buf.shift
- end
-
- def ungetc(c)
- @output_buf.unshift(c)
- end
-
- def in_pasting?
- not empty_buffer?
- end
-
- def empty_buffer?
- if not @output_buf.empty?
- false
- elsif @kbhit.call == 0
- true
- else
- false
- end
- end
-
- def get_console_screen_buffer_info
- # CONSOLE_SCREEN_BUFFER_INFO
- # [ 0,2] dwSize.X
- # [ 2,2] dwSize.Y
- # [ 4,2] dwCursorPositions.X
- # [ 6,2] dwCursorPositions.Y
- # [ 8,2] wAttributes
- # [10,2] srWindow.Left
- # [12,2] srWindow.Top
- # [14,2] srWindow.Right
- # [16,2] srWindow.Bottom
- # [18,2] dwMaximumWindowSize.X
- # [20,2] dwMaximumWindowSize.Y
- csbi = 0.chr * 22
- if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) != 0
- # returns [width, height, x, y, attributes, left, top, right, bottom]
- csbi.unpack("s9")
- else
- return nil
- end
- end
-
- ALTERNATIVE_CSBI = [80, 24, 0, 0, 7, 0, 0, 79, 23].freeze
-
- def get_screen_size
- width, _, _, _, _, _, top, _, bottom = get_console_screen_buffer_info || ALTERNATIVE_CSBI
- [bottom - top + 1, width]
- end
-
- def cursor_pos
- _, _, x, y, _, _, top, = get_console_screen_buffer_info || ALTERNATIVE_CSBI
- Reline::CursorPos.new(x, y - top)
- end
-
- def move_cursor_column(val)
- _, _, _, y, = get_console_screen_buffer_info
- call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + val) if y
- end
-
- def move_cursor_up(val)
- if val > 0
- _, _, x, y, _, _, top, = get_console_screen_buffer_info
- return unless y
- y = (y - top) - val
- y = 0 if y < 0
- call_with_console_handle(@SetConsoleCursorPosition, (y + top) * 65536 + x)
- elsif val < 0
- move_cursor_down(-val)
- end
- end
-
- def move_cursor_down(val)
- if val > 0
- _, _, x, y, _, _, top, _, bottom = get_console_screen_buffer_info
- return unless y
- screen_height = bottom - top
- y = (y - top) + val
- y = screen_height if y > screen_height
- call_with_console_handle(@SetConsoleCursorPosition, (y + top) * 65536 + x)
- elsif val < 0
- move_cursor_up(-val)
- end
- end
-
- def erase_after_cursor
- width, _, x, y, attributes, = get_console_screen_buffer_info
- return unless x
- written = 0.chr * 4
- call_with_console_handle(@FillConsoleOutputCharacter, 0x20, width - x, y * 65536 + x, written)
- call_with_console_handle(@FillConsoleOutputAttribute, attributes, width - x, y * 65536 + x, written)
- end
-
- # This only works when the cursor is at the bottom of the scroll range
- # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
- def scroll_down(x)
- return if x.zero?
- # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
- @output.write "\n" * x
- end
-
- def clear_screen
- if @legacy_console
- width, _, _, _, attributes, _, top, _, bottom = get_console_screen_buffer_info
- return unless width
- fill_length = width * (bottom - top + 1)
- screen_topleft = top * 65536
- written = 0.chr * 4
- call_with_console_handle(@FillConsoleOutputCharacter, 0x20, fill_length, screen_topleft, written)
- call_with_console_handle(@FillConsoleOutputAttribute, attributes, fill_length, screen_topleft, written)
- call_with_console_handle(@SetConsoleCursorPosition, screen_topleft)
- else
- @output.write "\e[2J" "\e[H"
- end
- end
-
- def set_screen_size(rows, columns)
- raise NotImplementedError
- end
-
- def hide_cursor
- size = 100
- visible = 0 # 0 means false
- cursor_info = [size, visible].pack('Li')
- call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
- end
-
- def show_cursor
- size = 100
- visible = 1 # 1 means true
- cursor_info = [size, visible].pack('Li')
- call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
- end
-
- def set_winch_handler(&handler)
- @winch_handler = handler
- end
-
- def prep
- # do nothing
- nil
- end
-
- def deprep(otio)
- # do nothing
- end
-
- def disable_auto_linewrap(setting = true, &block)
- mode = getconsolemode
- if 0 == (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- if block
- begin
- setconsolemode(mode & ~ENABLE_WRAP_AT_EOL_OUTPUT)
- block.call
- ensure
- setconsolemode(mode | ENABLE_WRAP_AT_EOL_OUTPUT)
- end
- else
- if setting
- setconsolemode(mode & ~ENABLE_WRAP_AT_EOL_OUTPUT)
- else
- setconsolemode(mode | ENABLE_WRAP_AT_EOL_OUTPUT)
- end
- end
- else
- block.call if block
- end
- end
-
- class KeyEventRecord
-
- attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
-
- def initialize(virtual_key_code, char_code, control_key_state)
- @virtual_key_code = virtual_key_code
- @char_code = char_code
- @control_key_state = control_key_state
- @enhanced = control_key_state & ENHANCED_KEY != 0
-
- (@control_keys = []).tap do |control_keys|
- # symbols must be sorted to make comparison is easier later on
- control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
- control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
- control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
- end.freeze
- end
-
- def char
- @char_code.chr(Encoding::UTF_8)
- end
-
- def enhanced?
- @enhanced
- end
-
- # Verifies if the arguments match with this key event.
- # Nil arguments are ignored, but at least one must be passed as non-nil.
- # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
- def match?(control_keys: nil, virtual_key_code: nil, char_code: nil)
- raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
-
- (control_keys.nil? || [*control_keys].sort == @control_keys) &&
- (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
- (char_code.nil? || char_code == @char_code)
- end
-
- end
-end
diff --git a/lib/reline/key_actor.rb b/lib/reline/key_actor.rb
deleted file mode 100644
index 0ac7604556..0000000000
--- a/lib/reline/key_actor.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-module Reline::KeyActor
-end
-
-require 'reline/key_actor/base'
-require 'reline/key_actor/composite'
-require 'reline/key_actor/emacs'
-require 'reline/key_actor/vi_command'
-require 'reline/key_actor/vi_insert'
diff --git a/lib/reline/key_actor/base.rb b/lib/reline/key_actor/base.rb
deleted file mode 100644
index 5bd8609cdf..0000000000
--- a/lib/reline/key_actor/base.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class Reline::KeyActor::Base
- def initialize(mappings = nil)
- @matching_bytes = {}
- @key_bindings = {}
- add_mappings(mappings) if mappings
- end
-
- def add_mappings(mappings)
- add([27], :ed_ignore)
- 128.times do |key|
- func = mappings[key]
- meta_func = mappings[key | 0b10000000]
- add([key], func) if func
- add([27, key], meta_func) if meta_func
- end
- end
-
- def add(key, func)
- (1...key.size).each do |size|
- @matching_bytes[key.take(size)] = true
- end
- @key_bindings[key] = func
- end
-
- def matching?(key)
- @matching_bytes[key]
- end
-
- def get(key)
- @key_bindings[key]
- end
-
- def clear
- @matching_bytes.clear
- @key_bindings.clear
- end
-end
diff --git a/lib/reline/key_actor/composite.rb b/lib/reline/key_actor/composite.rb
deleted file mode 100644
index 37e94ce6cf..0000000000
--- a/lib/reline/key_actor/composite.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class Reline::KeyActor::Composite
- def initialize(key_actors)
- @key_actors = key_actors
- end
-
- def matching?(key)
- @key_actors.any? { |key_actor| key_actor.matching?(key) }
- end
-
- def get(key)
- @key_actors.each do |key_actor|
- func = key_actor.get(key)
- return func if func
- end
- nil
- end
-end
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
deleted file mode 100644
index 1ed4af7684..0000000000
--- a/lib/reline/key_actor/emacs.rb
+++ /dev/null
@@ -1,517 +0,0 @@
-module Reline::KeyActor
- EMACS_MAPPING = [
- # 0 ^@
- :em_set_mark,
- # 1 ^A
- :ed_move_to_beg,
- # 2 ^B
- :ed_prev_char,
- # 3 ^C
- :ed_ignore,
- # 4 ^D
- :em_delete,
- # 5 ^E
- :ed_move_to_end,
- # 6 ^F
- :ed_next_char,
- # 7 ^G
- nil,
- # 8 ^H
- :em_delete_prev_char,
- # 9 ^I
- :complete,
- # 10 ^J
- :ed_newline,
- # 11 ^K
- :ed_kill_line,
- # 12 ^L
- :ed_clear_screen,
- # 13 ^M
- :ed_newline,
- # 14 ^N
- :ed_next_history,
- # 15 ^O
- :ed_ignore,
- # 16 ^P
- :ed_prev_history,
- # 17 ^Q
- :ed_quoted_insert,
- # 18 ^R
- :vi_search_prev,
- # 19 ^S
- :vi_search_next,
- # 20 ^T
- :ed_transpose_chars,
- # 21 ^U
- :unix_line_discard,
- # 22 ^V
- :ed_quoted_insert,
- # 23 ^W
- :em_kill_region,
- # 24 ^X
- nil,
- # 25 ^Y
- :em_yank,
- # 26 ^Z
- :ed_ignore,
- # 27 ^[
- nil,
- # 28 ^\
- :ed_ignore,
- # 29 ^]
- :ed_ignore,
- # 30 ^^
- nil,
- # 31 ^_
- :undo,
- # 32 SPACE
- :ed_insert,
- # 33 !
- :ed_insert,
- # 34 "
- :ed_insert,
- # 35 #
- :ed_insert,
- # 36 $
- :ed_insert,
- # 37 %
- :ed_insert,
- # 38 &
- :ed_insert,
- # 39 '
- :ed_insert,
- # 40 (
- :ed_insert,
- # 41 )
- :ed_insert,
- # 42 *
- :ed_insert,
- # 43 +
- :ed_insert,
- # 44 ,
- :ed_insert,
- # 45 -
- :ed_insert,
- # 46 .
- :ed_insert,
- # 47 /
- :ed_insert,
- # 48 0
- :ed_digit,
- # 49 1
- :ed_digit,
- # 50 2
- :ed_digit,
- # 51 3
- :ed_digit,
- # 52 4
- :ed_digit,
- # 53 5
- :ed_digit,
- # 54 6
- :ed_digit,
- # 55 7
- :ed_digit,
- # 56 8
- :ed_digit,
- # 57 9
- :ed_digit,
- # 58 :
- :ed_insert,
- # 59 ;
- :ed_insert,
- # 60 <
- :ed_insert,
- # 61 =
- :ed_insert,
- # 62 >
- :ed_insert,
- # 63 ?
- :ed_insert,
- # 64 @
- :ed_insert,
- # 65 A
- :ed_insert,
- # 66 B
- :ed_insert,
- # 67 C
- :ed_insert,
- # 68 D
- :ed_insert,
- # 69 E
- :ed_insert,
- # 70 F
- :ed_insert,
- # 71 G
- :ed_insert,
- # 72 H
- :ed_insert,
- # 73 I
- :ed_insert,
- # 74 J
- :ed_insert,
- # 75 K
- :ed_insert,
- # 76 L
- :ed_insert,
- # 77 M
- :ed_insert,
- # 78 N
- :ed_insert,
- # 79 O
- :ed_insert,
- # 80 P
- :ed_insert,
- # 81 Q
- :ed_insert,
- # 82 R
- :ed_insert,
- # 83 S
- :ed_insert,
- # 84 T
- :ed_insert,
- # 85 U
- :ed_insert,
- # 86 V
- :ed_insert,
- # 87 W
- :ed_insert,
- # 88 X
- :ed_insert,
- # 89 Y
- :ed_insert,
- # 90 Z
- :ed_insert,
- # 91 [
- :ed_insert,
- # 92 \
- :ed_insert,
- # 93 ]
- :ed_insert,
- # 94 ^
- :ed_insert,
- # 95 _
- :ed_insert,
- # 96 `
- :ed_insert,
- # 97 a
- :ed_insert,
- # 98 b
- :ed_insert,
- # 99 c
- :ed_insert,
- # 100 d
- :ed_insert,
- # 101 e
- :ed_insert,
- # 102 f
- :ed_insert,
- # 103 g
- :ed_insert,
- # 104 h
- :ed_insert,
- # 105 i
- :ed_insert,
- # 106 j
- :ed_insert,
- # 107 k
- :ed_insert,
- # 108 l
- :ed_insert,
- # 109 m
- :ed_insert,
- # 110 n
- :ed_insert,
- # 111 o
- :ed_insert,
- # 112 p
- :ed_insert,
- # 113 q
- :ed_insert,
- # 114 r
- :ed_insert,
- # 115 s
- :ed_insert,
- # 116 t
- :ed_insert,
- # 117 u
- :ed_insert,
- # 118 v
- :ed_insert,
- # 119 w
- :ed_insert,
- # 120 x
- :ed_insert,
- # 121 y
- :ed_insert,
- # 122 z
- :ed_insert,
- # 123 {
- :ed_insert,
- # 124 |
- :ed_insert,
- # 125 }
- :ed_insert,
- # 126 ~
- :ed_insert,
- # 127 ^?
- :em_delete_prev_char,
- # 128 M-^@
- nil,
- # 129 M-^A
- nil,
- # 130 M-^B
- nil,
- # 131 M-^C
- nil,
- # 132 M-^D
- nil,
- # 133 M-^E
- nil,
- # 134 M-^F
- nil,
- # 135 M-^G
- nil,
- # 136 M-^H
- :ed_delete_prev_word,
- # 137 M-^I
- nil,
- # 138 M-^J
- :key_newline,
- # 139 M-^K
- nil,
- # 140 M-^L
- :ed_clear_screen,
- # 141 M-^M
- :key_newline,
- # 142 M-^N
- nil,
- # 143 M-^O
- nil,
- # 144 M-^P
- nil,
- # 145 M-^Q
- nil,
- # 146 M-^R
- nil,
- # 147 M-^S
- nil,
- # 148 M-^T
- nil,
- # 149 M-^U
- nil,
- # 150 M-^V
- nil,
- # 151 M-^W
- nil,
- # 152 M-^X
- nil,
- # 153 M-^Y
- :em_yank_pop,
- # 154 M-^Z
- nil,
- # 155 M-^[
- nil,
- # 156 M-^\
- nil,
- # 157 M-^]
- nil,
- # 158 M-^^
- nil,
- # 159 M-^_
- :redo,
- # 160 M-SPACE
- :em_set_mark,
- # 161 M-!
- nil,
- # 162 M-"
- nil,
- # 163 M-#
- nil,
- # 164 M-$
- nil,
- # 165 M-%
- nil,
- # 166 M-&
- nil,
- # 167 M-'
- nil,
- # 168 M-(
- nil,
- # 169 M-)
- nil,
- # 170 M-*
- nil,
- # 171 M-+
- nil,
- # 172 M-,
- nil,
- # 173 M--
- nil,
- # 174 M-.
- nil,
- # 175 M-/
- nil,
- # 176 M-0
- :ed_argument_digit,
- # 177 M-1
- :ed_argument_digit,
- # 178 M-2
- :ed_argument_digit,
- # 179 M-3
- :ed_argument_digit,
- # 180 M-4
- :ed_argument_digit,
- # 181 M-5
- :ed_argument_digit,
- # 182 M-6
- :ed_argument_digit,
- # 183 M-7
- :ed_argument_digit,
- # 184 M-8
- :ed_argument_digit,
- # 185 M-9
- :ed_argument_digit,
- # 186 M-:
- nil,
- # 187 M-;
- nil,
- # 188 M-<
- nil,
- # 189 M-=
- nil,
- # 190 M->
- nil,
- # 191 M-?
- nil,
- # 192 M-@
- nil,
- # 193 M-A
- nil,
- # 194 M-B
- :ed_prev_word,
- # 195 M-C
- :em_capitol_case,
- # 196 M-D
- :em_delete_next_word,
- # 197 M-E
- nil,
- # 198 M-F
- :em_next_word,
- # 199 M-G
- nil,
- # 200 M-H
- nil,
- # 201 M-I
- nil,
- # 202 M-J
- nil,
- # 203 M-K
- nil,
- # 204 M-L
- :em_lower_case,
- # 205 M-M
- nil,
- # 206 M-N
- :vi_search_next,
- # 207 M-O
- nil,
- # 208 M-P
- :vi_search_prev,
- # 209 M-Q
- nil,
- # 210 M-R
- nil,
- # 211 M-S
- nil,
- # 212 M-T
- nil,
- # 213 M-U
- :em_upper_case,
- # 214 M-V
- nil,
- # 215 M-W
- nil,
- # 216 M-X
- nil,
- # 217 M-Y
- :em_yank_pop,
- # 218 M-Z
- nil,
- # 219 M-[
- nil,
- # 220 M-\
- nil,
- # 221 M-]
- nil,
- # 222 M-^
- nil,
- # 223 M-_
- nil,
- # 224 M-`
- nil,
- # 225 M-a
- nil,
- # 226 M-b
- :ed_prev_word,
- # 227 M-c
- :em_capitol_case,
- # 228 M-d
- :em_delete_next_word,
- # 229 M-e
- nil,
- # 230 M-f
- :em_next_word,
- # 231 M-g
- nil,
- # 232 M-h
- nil,
- # 233 M-i
- nil,
- # 234 M-j
- nil,
- # 235 M-k
- nil,
- # 236 M-l
- :em_lower_case,
- # 237 M-m
- nil,
- # 238 M-n
- :vi_search_next,
- # 239 M-o
- nil,
- # 240 M-p
- :vi_search_prev,
- # 241 M-q
- nil,
- # 242 M-r
- nil,
- # 243 M-s
- nil,
- # 244 M-t
- :ed_transpose_words,
- # 245 M-u
- :em_upper_case,
- # 246 M-v
- nil,
- # 247 M-w
- nil,
- # 248 M-x
- nil,
- # 249 M-y
- nil,
- # 250 M-z
- nil,
- # 251 M-{
- nil,
- # 252 M-|
- nil,
- # 253 M-}
- nil,
- # 254 M-~
- nil,
- # 255 M-^?
- :ed_delete_prev_word
- # EOF
- ]
-end
diff --git a/lib/reline/key_actor/vi_command.rb b/lib/reline/key_actor/vi_command.rb
deleted file mode 100644
index 400f88477a..0000000000
--- a/lib/reline/key_actor/vi_command.rb
+++ /dev/null
@@ -1,518 +0,0 @@
-module Reline::KeyActor
- VI_COMMAND_MAPPING = [
- # 0 ^@
- nil,
- # 1 ^A
- :ed_move_to_beg,
- # 2 ^B
- nil,
- # 3 ^C
- :ed_ignore,
- # 4 ^D
- :vi_end_of_transmission,
- # 5 ^E
- :ed_move_to_end,
- # 6 ^F
- nil,
- # 7 ^G
- nil,
- # 8 ^H
- :ed_prev_char,
- # 9 ^I
- nil,
- # 10 ^J
- :ed_newline,
- # 11 ^K
- :ed_kill_line,
- # 12 ^L
- :ed_clear_screen,
- # 13 ^M
- :ed_newline,
- # 14 ^N
- :ed_next_history,
- # 15 ^O
- :ed_ignore,
- # 16 ^P
- :ed_prev_history,
- # 17 ^Q
- :ed_ignore,
- # 18 ^R
- :vi_search_prev,
- # 19 ^S
- :ed_ignore,
- # 20 ^T
- :ed_transpose_chars,
- # 21 ^U
- :vi_kill_line_prev,
- # 22 ^V
- :ed_quoted_insert,
- # 23 ^W
- :ed_delete_prev_word,
- # 24 ^X
- nil,
- # 25 ^Y
- :em_yank,
- # 26 ^Z
- nil,
- # 27 ^[
- nil,
- # 28 ^\
- :ed_ignore,
- # 29 ^]
- nil,
- # 30 ^^
- nil,
- # 31 ^_
- nil,
- # 32 SPACE
- :ed_next_char,
- # 33 !
- nil,
- # 34 "
- nil,
- # 35 #
- :vi_comment_out,
- # 36 $
- :ed_move_to_end,
- # 37 %
- nil,
- # 38 &
- nil,
- # 39 '
- nil,
- # 40 (
- nil,
- # 41 )
- nil,
- # 42 *
- nil,
- # 43 +
- :ed_next_history,
- # 44 ,
- nil,
- # 45 -
- :ed_prev_history,
- # 46 .
- nil,
- # 47 /
- :vi_search_prev,
- # 48 0
- :vi_zero,
- # 49 1
- :ed_argument_digit,
- # 50 2
- :ed_argument_digit,
- # 51 3
- :ed_argument_digit,
- # 52 4
- :ed_argument_digit,
- # 53 5
- :ed_argument_digit,
- # 54 6
- :ed_argument_digit,
- # 55 7
- :ed_argument_digit,
- # 56 8
- :ed_argument_digit,
- # 57 9
- :ed_argument_digit,
- # 58 :
- nil,
- # 59 ;
- nil,
- # 60 <
- nil,
- # 61 =
- nil,
- # 62 >
- nil,
- # 63 ?
- :vi_search_next,
- # 64 @
- :vi_alias,
- # 65 A
- :vi_add_at_eol,
- # 66 B
- :vi_prev_big_word,
- # 67 C
- :vi_change_to_eol,
- # 68 D
- :ed_kill_line,
- # 69 E
- :vi_end_big_word,
- # 70 F
- :vi_prev_char,
- # 71 G
- :vi_to_history_line,
- # 72 H
- nil,
- # 73 I
- :vi_insert_at_bol,
- # 74 J
- :vi_join_lines,
- # 75 K
- :vi_search_prev,
- # 76 L
- nil,
- # 77 M
- nil,
- # 78 N
- nil,
- # 79 O
- nil,
- # 80 P
- :vi_paste_prev,
- # 81 Q
- nil,
- # 82 R
- nil,
- # 83 S
- nil,
- # 84 T
- :vi_to_prev_char,
- # 85 U
- nil,
- # 86 V
- nil,
- # 87 W
- :vi_next_big_word,
- # 88 X
- :ed_delete_prev_char,
- # 89 Y
- nil,
- # 90 Z
- nil,
- # 91 [
- nil,
- # 92 \
- nil,
- # 93 ]
- nil,
- # 94 ^
- :vi_first_print,
- # 95 _
- nil,
- # 96 `
- nil,
- # 97 a
- :vi_add,
- # 98 b
- :vi_prev_word,
- # 99 c
- :vi_change_meta,
- # 100 d
- :vi_delete_meta,
- # 101 e
- :vi_end_word,
- # 102 f
- :vi_next_char,
- # 103 g
- nil,
- # 104 h
- :ed_prev_char,
- # 105 i
- :vi_insert,
- # 106 j
- :ed_next_history,
- # 107 k
- :ed_prev_history,
- # 108 l
- :ed_next_char,
- # 109 m
- nil,
- # 110 n
- nil,
- # 111 o
- nil,
- # 112 p
- :vi_paste_next,
- # 113 q
- nil,
- # 114 r
- :vi_replace_char,
- # 115 s
- nil,
- # 116 t
- :vi_to_next_char,
- # 117 u
- nil,
- # 118 v
- :vi_histedit,
- # 119 w
- :vi_next_word,
- # 120 x
- :ed_delete_next_char,
- # 121 y
- :vi_yank,
- # 122 z
- nil,
- # 123 {
- nil,
- # 124 |
- :vi_to_column,
- # 125 }
- nil,
- # 126 ~
- nil,
- # 127 ^?
- :em_delete_prev_char,
- # 128 M-^@
- nil,
- # 129 M-^A
- nil,
- # 130 M-^B
- nil,
- # 131 M-^C
- nil,
- # 132 M-^D
- nil,
- # 133 M-^E
- nil,
- # 134 M-^F
- nil,
- # 135 M-^G
- nil,
- # 136 M-^H
- nil,
- # 137 M-^I
- nil,
- # 138 M-^J
- nil,
- # 139 M-^K
- nil,
- # 140 M-^L
- nil,
- # 141 M-^M
- nil,
- # 142 M-^N
- nil,
- # 143 M-^O
- nil,
- # 144 M-^P
- nil,
- # 145 M-^Q
- nil,
- # 146 M-^R
- nil,
- # 147 M-^S
- nil,
- # 148 M-^T
- nil,
- # 149 M-^U
- nil,
- # 150 M-^V
- nil,
- # 151 M-^W
- nil,
- # 152 M-^X
- nil,
- # 153 M-^Y
- nil,
- # 154 M-^Z
- nil,
- # 155 M-^[
- nil,
- # 156 M-^\
- nil,
- # 157 M-^]
- nil,
- # 158 M-^^
- nil,
- # 159 M-^_
- nil,
- # 160 M-SPACE
- nil,
- # 161 M-!
- nil,
- # 162 M-"
- nil,
- # 163 M-#
- nil,
- # 164 M-$
- nil,
- # 165 M-%
- nil,
- # 166 M-&
- nil,
- # 167 M-'
- nil,
- # 168 M-(
- nil,
- # 169 M-)
- nil,
- # 170 M-*
- nil,
- # 171 M-+
- nil,
- # 172 M-,
- nil,
- # 173 M--
- nil,
- # 174 M-.
- nil,
- # 175 M-/
- nil,
- # 176 M-0
- nil,
- # 177 M-1
- nil,
- # 178 M-2
- nil,
- # 179 M-3
- nil,
- # 180 M-4
- nil,
- # 181 M-5
- nil,
- # 182 M-6
- nil,
- # 183 M-7
- nil,
- # 184 M-8
- nil,
- # 185 M-9
- nil,
- # 186 M-:
- nil,
- # 187 M-;
- nil,
- # 188 M-<
- nil,
- # 189 M-=
- nil,
- # 190 M->
- nil,
- # 191 M-?
- nil,
- # 192 M-@
- nil,
- # 193 M-A
- nil,
- # 194 M-B
- nil,
- # 195 M-C
- nil,
- # 196 M-D
- nil,
- # 197 M-E
- nil,
- # 198 M-F
- nil,
- # 199 M-G
- nil,
- # 200 M-H
- nil,
- # 201 M-I
- nil,
- # 202 M-J
- nil,
- # 203 M-K
- nil,
- # 204 M-L
- nil,
- # 205 M-M
- nil,
- # 206 M-N
- nil,
- # 207 M-O
- nil,
- # 208 M-P
- nil,
- # 209 M-Q
- nil,
- # 210 M-R
- nil,
- # 211 M-S
- nil,
- # 212 M-T
- nil,
- # 213 M-U
- nil,
- # 214 M-V
- nil,
- # 215 M-W
- nil,
- # 216 M-X
- nil,
- # 217 M-Y
- nil,
- # 218 M-Z
- nil,
- # 219 M-[
- nil,
- # 220 M-\
- nil,
- # 221 M-]
- nil,
- # 222 M-^
- nil,
- # 223 M-_
- nil,
- # 224 M-`
- nil,
- # 225 M-a
- nil,
- # 226 M-b
- nil,
- # 227 M-c
- nil,
- # 228 M-d
- nil,
- # 229 M-e
- nil,
- # 230 M-f
- nil,
- # 231 M-g
- nil,
- # 232 M-h
- nil,
- # 233 M-i
- nil,
- # 234 M-j
- nil,
- # 235 M-k
- nil,
- # 236 M-l
- nil,
- # 237 M-m
- nil,
- # 238 M-n
- nil,
- # 239 M-o
- nil,
- # 240 M-p
- nil,
- # 241 M-q
- nil,
- # 242 M-r
- nil,
- # 243 M-s
- nil,
- # 244 M-t
- nil,
- # 245 M-u
- nil,
- # 246 M-v
- nil,
- # 247 M-w
- nil,
- # 248 M-x
- nil,
- # 249 M-y
- nil,
- # 250 M-z
- nil,
- # 251 M-{
- nil,
- # 252 M-|
- nil,
- # 253 M-}
- nil,
- # 254 M-~
- nil,
- # 255 M-^?
- nil
- # EOF
- ]
-end
-
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
deleted file mode 100644
index 235b6fdf38..0000000000
--- a/lib/reline/key_actor/vi_insert.rb
+++ /dev/null
@@ -1,517 +0,0 @@
-module Reline::KeyActor
- VI_INSERT_MAPPING = [
- # 0 ^@
- nil,
- # 1 ^A
- :ed_insert,
- # 2 ^B
- :ed_insert,
- # 3 ^C
- :ed_insert,
- # 4 ^D
- :vi_list_or_eof,
- # 5 ^E
- :ed_insert,
- # 6 ^F
- :ed_insert,
- # 7 ^G
- :ed_insert,
- # 8 ^H
- :vi_delete_prev_char,
- # 9 ^I
- :complete,
- # 10 ^J
- :ed_newline,
- # 11 ^K
- :ed_insert,
- # 12 ^L
- :ed_insert,
- # 13 ^M
- :ed_newline,
- # 14 ^N
- :menu_complete,
- # 15 ^O
- :ed_insert,
- # 16 ^P
- :menu_complete_backward,
- # 17 ^Q
- :ed_ignore,
- # 18 ^R
- :vi_search_prev,
- # 19 ^S
- :vi_search_next,
- # 20 ^T
- :ed_transpose_chars,
- # 21 ^U
- :vi_kill_line_prev,
- # 22 ^V
- :ed_quoted_insert,
- # 23 ^W
- :ed_delete_prev_word,
- # 24 ^X
- :ed_insert,
- # 25 ^Y
- :em_yank,
- # 26 ^Z
- :ed_insert,
- # 27 ^[
- :vi_command_mode,
- # 28 ^\
- :ed_ignore,
- # 29 ^]
- :ed_insert,
- # 30 ^^
- :ed_insert,
- # 31 ^_
- :ed_insert,
- # 32 SPACE
- :ed_insert,
- # 33 !
- :ed_insert,
- # 34 "
- :ed_insert,
- # 35 #
- :ed_insert,
- # 36 $
- :ed_insert,
- # 37 %
- :ed_insert,
- # 38 &
- :ed_insert,
- # 39 '
- :ed_insert,
- # 40 (
- :ed_insert,
- # 41 )
- :ed_insert,
- # 42 *
- :ed_insert,
- # 43 +
- :ed_insert,
- # 44 ,
- :ed_insert,
- # 45 -
- :ed_insert,
- # 46 .
- :ed_insert,
- # 47 /
- :ed_insert,
- # 48 0
- :ed_digit,
- # 49 1
- :ed_digit,
- # 50 2
- :ed_digit,
- # 51 3
- :ed_digit,
- # 52 4
- :ed_digit,
- # 53 5
- :ed_digit,
- # 54 6
- :ed_digit,
- # 55 7
- :ed_digit,
- # 56 8
- :ed_digit,
- # 57 9
- :ed_digit,
- # 58 :
- :ed_insert,
- # 59 ;
- :ed_insert,
- # 60 <
- :ed_insert,
- # 61 =
- :ed_insert,
- # 62 >
- :ed_insert,
- # 63 ?
- :ed_insert,
- # 64 @
- :ed_insert,
- # 65 A
- :ed_insert,
- # 66 B
- :ed_insert,
- # 67 C
- :ed_insert,
- # 68 D
- :ed_insert,
- # 69 E
- :ed_insert,
- # 70 F
- :ed_insert,
- # 71 G
- :ed_insert,
- # 72 H
- :ed_insert,
- # 73 I
- :ed_insert,
- # 74 J
- :ed_insert,
- # 75 K
- :ed_insert,
- # 76 L
- :ed_insert,
- # 77 M
- :ed_insert,
- # 78 N
- :ed_insert,
- # 79 O
- :ed_insert,
- # 80 P
- :ed_insert,
- # 81 Q
- :ed_insert,
- # 82 R
- :ed_insert,
- # 83 S
- :ed_insert,
- # 84 T
- :ed_insert,
- # 85 U
- :ed_insert,
- # 86 V
- :ed_insert,
- # 87 W
- :ed_insert,
- # 88 X
- :ed_insert,
- # 89 Y
- :ed_insert,
- # 90 Z
- :ed_insert,
- # 91 [
- :ed_insert,
- # 92 \
- :ed_insert,
- # 93 ]
- :ed_insert,
- # 94 ^
- :ed_insert,
- # 95 _
- :ed_insert,
- # 96 `
- :ed_insert,
- # 97 a
- :ed_insert,
- # 98 b
- :ed_insert,
- # 99 c
- :ed_insert,
- # 100 d
- :ed_insert,
- # 101 e
- :ed_insert,
- # 102 f
- :ed_insert,
- # 103 g
- :ed_insert,
- # 104 h
- :ed_insert,
- # 105 i
- :ed_insert,
- # 106 j
- :ed_insert,
- # 107 k
- :ed_insert,
- # 108 l
- :ed_insert,
- # 109 m
- :ed_insert,
- # 110 n
- :ed_insert,
- # 111 o
- :ed_insert,
- # 112 p
- :ed_insert,
- # 113 q
- :ed_insert,
- # 114 r
- :ed_insert,
- # 115 s
- :ed_insert,
- # 116 t
- :ed_insert,
- # 117 u
- :ed_insert,
- # 118 v
- :ed_insert,
- # 119 w
- :ed_insert,
- # 120 x
- :ed_insert,
- # 121 y
- :ed_insert,
- # 122 z
- :ed_insert,
- # 123 {
- :ed_insert,
- # 124 |
- :ed_insert,
- # 125 }
- :ed_insert,
- # 126 ~
- :ed_insert,
- # 127 ^?
- :vi_delete_prev_char,
- # 128 M-^@
- nil,
- # 129 M-^A
- nil,
- # 130 M-^B
- nil,
- # 131 M-^C
- nil,
- # 132 M-^D
- nil,
- # 133 M-^E
- nil,
- # 134 M-^F
- nil,
- # 135 M-^G
- nil,
- # 136 M-^H
- nil,
- # 137 M-^I
- nil,
- # 138 M-^J
- :key_newline,
- # 139 M-^K
- nil,
- # 140 M-^L
- nil,
- # 141 M-^M
- :key_newline,
- # 142 M-^N
- nil,
- # 143 M-^O
- nil,
- # 144 M-^P
- nil,
- # 145 M-^Q
- nil,
- # 146 M-^R
- nil,
- # 147 M-^S
- nil,
- # 148 M-^T
- nil,
- # 149 M-^U
- nil,
- # 150 M-^V
- nil,
- # 151 M-^W
- nil,
- # 152 M-^X
- nil,
- # 153 M-^Y
- nil,
- # 154 M-^Z
- nil,
- # 155 M-^[
- nil,
- # 156 M-^\
- nil,
- # 157 M-^]
- nil,
- # 158 M-^^
- nil,
- # 159 M-^_
- nil,
- # 160 M-SPACE
- nil,
- # 161 M-!
- nil,
- # 162 M-"
- nil,
- # 163 M-#
- nil,
- # 164 M-$
- nil,
- # 165 M-%
- nil,
- # 166 M-&
- nil,
- # 167 M-'
- nil,
- # 168 M-(
- nil,
- # 169 M-)
- nil,
- # 170 M-*
- nil,
- # 171 M-+
- nil,
- # 172 M-,
- nil,
- # 173 M--
- nil,
- # 174 M-.
- nil,
- # 175 M-/
- nil,
- # 176 M-0
- nil,
- # 177 M-1
- nil,
- # 178 M-2
- nil,
- # 179 M-3
- nil,
- # 180 M-4
- nil,
- # 181 M-5
- nil,
- # 182 M-6
- nil,
- # 183 M-7
- nil,
- # 184 M-8
- nil,
- # 185 M-9
- nil,
- # 186 M-:
- nil,
- # 187 M-;
- nil,
- # 188 M-<
- nil,
- # 189 M-=
- nil,
- # 190 M->
- nil,
- # 191 M-?
- nil,
- # 192 M-@
- nil,
- # 193 M-A
- nil,
- # 194 M-B
- nil,
- # 195 M-C
- nil,
- # 196 M-D
- nil,
- # 197 M-E
- nil,
- # 198 M-F
- nil,
- # 199 M-G
- nil,
- # 200 M-H
- nil,
- # 201 M-I
- nil,
- # 202 M-J
- nil,
- # 203 M-K
- nil,
- # 204 M-L
- nil,
- # 205 M-M
- nil,
- # 206 M-N
- nil,
- # 207 M-O
- nil,
- # 208 M-P
- nil,
- # 209 M-Q
- nil,
- # 210 M-R
- nil,
- # 211 M-S
- nil,
- # 212 M-T
- nil,
- # 213 M-U
- nil,
- # 214 M-V
- nil,
- # 215 M-W
- nil,
- # 216 M-X
- nil,
- # 217 M-Y
- nil,
- # 218 M-Z
- nil,
- # 219 M-[
- nil,
- # 220 M-\
- nil,
- # 221 M-]
- nil,
- # 222 M-^
- nil,
- # 223 M-_
- nil,
- # 224 M-`
- nil,
- # 225 M-a
- nil,
- # 226 M-b
- nil,
- # 227 M-c
- nil,
- # 228 M-d
- nil,
- # 229 M-e
- nil,
- # 230 M-f
- nil,
- # 231 M-g
- nil,
- # 232 M-h
- nil,
- # 233 M-i
- nil,
- # 234 M-j
- nil,
- # 235 M-k
- nil,
- # 236 M-l
- nil,
- # 237 M-m
- nil,
- # 238 M-n
- nil,
- # 239 M-o
- nil,
- # 240 M-p
- nil,
- # 241 M-q
- nil,
- # 242 M-r
- nil,
- # 243 M-s
- nil,
- # 244 M-t
- nil,
- # 245 M-u
- nil,
- # 246 M-v
- nil,
- # 247 M-w
- nil,
- # 248 M-x
- nil,
- # 249 M-y
- nil,
- # 250 M-z
- nil,
- # 251 M-{
- nil,
- # 252 M-|
- nil,
- # 253 M-}
- nil,
- # 254 M-~
- nil,
- # 255 M-^?
- nil
- # EOF
- ]
-end
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
deleted file mode 100644
index 4999225c9b..0000000000
--- a/lib/reline/key_stroke.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-class Reline::KeyStroke
- ESC_BYTE = 27
- CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
- CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
-
- attr_accessor :encoding
-
- def initialize(config, encoding)
- @config = config
- @encoding = encoding
- end
-
- # Input exactly matches to a key sequence
- MATCHING = :matching
- # Input partially matches to a key sequence
- MATCHED = :matched
- # Input matches to a key sequence and the key sequence is a prefix of another key sequence
- MATCHING_MATCHED = :matching_matched
- # Input does not match to any key sequence
- UNMATCHED = :unmatched
-
- def match_status(input)
- matching = key_mapping.matching?(input)
- matched = key_mapping.get(input)
- if matching && matched
- MATCHING_MATCHED
- elsif matching
- MATCHING
- elsif matched
- MATCHED
- elsif input[0] == ESC_BYTE
- match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command))
- else
- s = input.pack('c*').force_encoding(@encoding)
- if s.valid_encoding?
- s.size == 1 ? MATCHED : UNMATCHED
- else
- # Invalid string is MATCHING (part of valid string) or MATCHED (invalid bytes to be ignored)
- MATCHING_MATCHED
- end
- end
- end
-
- def expand(input)
- matched_bytes = nil
- (1..input.size).each do |i|
- bytes = input.take(i)
- status = match_status(bytes)
- matched_bytes = bytes if status == MATCHED || status == MATCHING_MATCHED
- break if status == MATCHED || status == UNMATCHED
- end
- return [[], []] unless matched_bytes
-
- func = key_mapping.get(matched_bytes)
- s = matched_bytes.pack('c*').force_encoding(@encoding)
- if func.is_a?(Array)
- # Perform simple macro expansion for single byte key bindings.
- # Multibyte key bindings and recursive macro expansion are not supported yet.
- macro = func.pack('c*').force_encoding(@encoding)
- keys = macro.chars.map do |c|
- f = key_mapping.get(c.bytes)
- Reline::Key.new(c, f.is_a?(Symbol) ? f : :ed_insert, false)
- end
- elsif func
- keys = [Reline::Key.new(s, func, false)]
- else
- if s.valid_encoding? && s.size == 1
- keys = [Reline::Key.new(s, :ed_insert, false)]
- else
- keys = []
- end
- end
-
- [keys, input.drop(matched_bytes.size)]
- end
-
- private
-
- # returns match status of CSI/SS3 sequence and matched length
- def match_unknown_escape_sequence(input, vi_mode: false)
- idx = 0
- return UNMATCHED unless input[idx] == ESC_BYTE
- idx += 1
- idx += 1 if input[idx] == ESC_BYTE
-
- case input[idx]
- when nil
- if idx == 1 # `ESC`
- return MATCHING_MATCHED
- else # `ESC ESC`
- return MATCHING
- end
- when 91 # == '['.ord
- # CSI sequence `ESC [ ... char`
- idx += 1
- idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx])
- idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx])
- when 79 # == 'O'.ord
- # SS3 sequence `ESC O char`
- idx += 1
- else
- # `ESC char` or `ESC ESC char`
- return UNMATCHED if vi_mode
- end
-
- case input.size
- when idx
- MATCHING
- when idx + 1
- MATCHED
- else
- UNMATCHED
- end
- end
-
- def key_mapping
- @config.key_bindings
- end
-end
diff --git a/lib/reline/kill_ring.rb b/lib/reline/kill_ring.rb
deleted file mode 100644
index 201f6f3ca0..0000000000
--- a/lib/reline/kill_ring.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-class Reline::KillRing
- include Enumerable
-
- module State
- FRESH = :fresh
- CONTINUED = :continued
- PROCESSED = :processed
- YANK = :yank
- end
-
- RingPoint = Struct.new(:backward, :forward, :str) do
- def initialize(str)
- super(nil, nil, str)
- end
-
- def ==(other)
- equal?(other)
- end
- end
-
- class RingBuffer
- attr_reader :size
- attr_reader :head
-
- def initialize(max = 1024)
- @max = max
- @size = 0
- @head = nil # reading head of ring-shaped tape
- end
-
- def <<(point)
- if @size.zero?
- @head = point
- @head.backward = @head
- @head.forward = @head
- @size = 1
- elsif @size >= @max
- tail = @head.forward
- new_tail = tail.forward
- @head.forward = point
- point.backward = @head
- new_tail.backward = point
- point.forward = new_tail
- @head = point
- else
- tail = @head.forward
- @head.forward = point
- point.backward = @head
- tail.backward = point
- point.forward = tail
- @head = point
- @size += 1
- end
- end
-
- def empty?
- @size.zero?
- end
- end
-
- def initialize(max = 1024)
- @ring = RingBuffer.new(max)
- @ring_pointer = nil
- @buffer = nil
- @state = State::FRESH
- end
-
- def append(string, before_p = false)
- case @state
- when State::FRESH, State::YANK
- @ring << RingPoint.new(+string)
- @state = State::CONTINUED
- when State::CONTINUED, State::PROCESSED
- if before_p
- @ring.head.str.prepend(string)
- else
- @ring.head.str.concat(string)
- end
- @state = State::CONTINUED
- end
- end
-
- def process
- case @state
- when State::FRESH
- # nothing to do
- when State::CONTINUED
- @state = State::PROCESSED
- when State::PROCESSED
- @state = State::FRESH
- when State::YANK
- # nothing to do
- end
- end
-
- def yank
- unless @ring.empty?
- @state = State::YANK
- @ring_pointer = @ring.head
- @ring_pointer.str
- else
- nil
- end
- end
-
- def yank_pop
- if @state == State::YANK
- prev_yank = @ring_pointer.str
- @ring_pointer = @ring_pointer.backward
- [@ring_pointer.str, prev_yank]
- else
- nil
- end
- end
-
- def each
- start = head = @ring.head
- loop do
- break if head.nil?
- yield head.str
- head = head.backward
- break if head == start
- end
- end
-end
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
deleted file mode 100644
index 20f10b4897..0000000000
--- a/lib/reline/line_editor.rb
+++ /dev/null
@@ -1,2362 +0,0 @@
-require 'reline/kill_ring'
-require 'reline/unicode'
-
-require 'tempfile'
-
-class Reline::LineEditor
- # TODO: Use "private alias_method" idiom after drop Ruby 2.5.
- attr_reader :byte_pointer
- attr_accessor :confirm_multiline_termination_proc
- attr_accessor :completion_proc
- attr_accessor :completion_append_character
- attr_accessor :output_modifier_proc
- attr_accessor :prompt_proc
- attr_accessor :auto_indent_proc
- attr_accessor :dig_perfect_match_proc
-
- VI_MOTIONS = %i{
- ed_prev_char
- ed_next_char
- vi_zero
- ed_move_to_beg
- ed_move_to_end
- vi_to_column
- vi_next_char
- vi_prev_char
- vi_next_word
- vi_prev_word
- vi_to_next_char
- vi_to_prev_char
- vi_end_word
- vi_next_big_word
- vi_prev_big_word
- vi_end_big_word
- }
-
- module CompletionState
- NORMAL = :normal
- MENU = :menu
- MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
- PERFECT_MATCH = :perfect_match
- end
-
- RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
-
- CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
- NullActionState = [nil, nil].freeze
-
- class MenuInfo
- attr_reader :list
-
- def initialize(list)
- @list = list
- end
-
- def lines(screen_width)
- return [] if @list.empty?
-
- list = @list.sort
- sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
- item_width = sizes.max + 2
- num_cols = [screen_width / item_width, 1].max
- num_rows = list.size.fdiv(num_cols).ceil
- list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
- aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
- aligned.map do |row|
- row.join.rstrip
- end
- end
- end
-
- MINIMUM_SCROLLBAR_HEIGHT = 1
-
- def initialize(config)
- @config = config
- @completion_append_character = ''
- @screen_size = [0, 0] # Should be initialized with actual winsize in LineEditor#reset
- reset_variables
- end
-
- def io_gate
- Reline::IOGate
- end
-
- def encoding
- io_gate.encoding
- end
-
- def set_pasting_state(in_pasting)
- # While pasting, text to be inserted is stored to @continuous_insertion_buffer.
- # After pasting, this buffer should be force inserted.
- process_insert(force: true) if @in_pasting && !in_pasting
- @in_pasting = in_pasting
- end
-
- private def check_mode_string
- if @config.show_mode_in_prompt
- if @config.editing_mode_is?(:vi_command)
- @config.vi_cmd_mode_string
- elsif @config.editing_mode_is?(:vi_insert)
- @config.vi_ins_mode_string
- elsif @config.editing_mode_is?(:emacs)
- @config.emacs_mode_string
- else
- '?'
- end
- end
- end
-
- private def check_multiline_prompt(buffer, mode_string)
- if @vi_arg
- prompt = "(arg: #{@vi_arg}) "
- elsif @searching_prompt
- prompt = @searching_prompt
- else
- prompt = @prompt
- end
- if !@is_multiline
- mode_string = check_mode_string
- prompt = mode_string + prompt if mode_string
- [prompt] + [''] * (buffer.size - 1)
- elsif @prompt_proc
- prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
- prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
- prompt_list = [prompt] if prompt_list.empty?
- prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string
- prompt = prompt_list[@line_index]
- prompt = prompt_list[0] if prompt.nil?
- prompt = prompt_list.last if prompt.nil?
- if buffer.size > prompt_list.size
- (buffer.size - prompt_list.size).times do
- prompt_list << prompt_list.last
- end
- end
- prompt_list
- else
- prompt = mode_string + prompt if mode_string
- [prompt] * buffer.size
- end
- end
-
- def reset(prompt = '')
- @screen_size = Reline::IOGate.get_screen_size
- reset_variables(prompt)
- @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
- if ENV.key?('RELINE_ALT_SCROLLBAR')
- @full_block = '::'
- @upper_half_block = "''"
- @lower_half_block = '..'
- @block_elem_width = 2
- elsif Reline::IOGate.win?
- @full_block = '█'
- @upper_half_block = '▀'
- @lower_half_block = '▄'
- @block_elem_width = 1
- elsif encoding == Encoding::UTF_8
- @full_block = '█'
- @upper_half_block = '▀'
- @lower_half_block = '▄'
- @block_elem_width = Reline::Unicode.calculate_width('█')
- else
- @full_block = '::'
- @upper_half_block = "''"
- @lower_half_block = '..'
- @block_elem_width = 2
- end
- end
-
- def handle_signal
- handle_interrupted
- handle_resized
- end
-
- private def handle_resized
- return unless @resized
-
- @screen_size = Reline::IOGate.get_screen_size
- @resized = false
- scroll_into_view
- Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
- @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
- clear_rendered_screen_cache
- render
- end
-
- private def handle_interrupted
- return unless @interrupted
-
- @interrupted = false
- clear_dialogs
- render
- cursor_to_bottom_offset = @rendered_screen.lines.size - @rendered_screen.cursor_y
- Reline::IOGate.scroll_down cursor_to_bottom_offset
- Reline::IOGate.move_cursor_column 0
- clear_rendered_screen_cache
- case @old_trap
- when 'DEFAULT', 'SYSTEM_DEFAULT'
- raise Interrupt
- when 'IGNORE'
- # Do nothing
- when 'EXIT'
- exit
- else
- @old_trap.call if @old_trap.respond_to?(:call)
- end
- end
-
- def set_signal_handlers
- Reline::IOGate.set_winch_handler do
- @resized = true
- end
- @old_trap = Signal.trap('INT') do
- @interrupted = true
- end
- end
-
- def finalize
- Signal.trap('INT', @old_trap)
- end
-
- def eof?
- @eof
- end
-
- def reset_variables(prompt = '')
- @prompt = prompt.gsub("\n", "\\n")
- @mark_pointer = nil
- @is_multiline = false
- @finished = false
- @history_pointer = nil
- @kill_ring ||= Reline::KillRing.new
- @vi_clipboard = ''
- @vi_arg = nil
- @waiting_proc = nil
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- @completion_journey_state = nil
- @completion_state = CompletionState::NORMAL
- @perfect_matched = nil
- @menu_info = nil
- @searching_prompt = nil
- @just_cursor_moving = false
- @eof = false
- @continuous_insertion_buffer = String.new(encoding: encoding)
- @scroll_partial_screen = 0
- @drop_terminate_spaces = false
- @in_pasting = false
- @auto_indent_proc = nil
- @dialogs = []
- @interrupted = false
- @resized = false
- @cache = {}
- @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
- @input_lines = [[[""], 0, 0]]
- @input_lines_position = 0
- @restoring = false
- @prev_action_state = NullActionState
- @next_action_state = NullActionState
- reset_line
- end
-
- def reset_line
- @byte_pointer = 0
- @buffer_of_lines = [String.new(encoding: encoding)]
- @line_index = 0
- @cache.clear
- @line_backup_in_history = nil
- end
-
- def multiline_on
- @is_multiline = true
- end
-
- def multiline_off
- @is_multiline = false
- end
-
- private def insert_new_line(cursor_line, next_line)
- @buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: encoding))
- @buffer_of_lines[@line_index] = cursor_line
- @line_index += 1
- @byte_pointer = 0
- if @auto_indent_proc && !@in_pasting
- if next_line.empty?
- (
- # For compatibility, use this calculation instead of just `process_auto_indent @line_index - 1, cursor_dependent: false`
- indent1 = @auto_indent_proc.(@buffer_of_lines.take(@line_index - 1).push(''), @line_index - 1, 0, true)
- indent2 = @auto_indent_proc.(@buffer_of_lines.take(@line_index), @line_index - 1, @buffer_of_lines[@line_index - 1].bytesize, false)
- indent = indent2 || indent1
- @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A\s*/, '')
- )
- process_auto_indent @line_index, add_newline: true
- else
- process_auto_indent @line_index - 1, cursor_dependent: false
- process_auto_indent @line_index, add_newline: true # Need for compatibility
- process_auto_indent @line_index, cursor_dependent: false
- end
- end
- end
-
- private def split_line_by_width(str, max_width, offset: 0)
- Reline::Unicode.split_line_by_width(str, max_width, encoding, offset: offset)
- end
-
- def current_byte_pointer_cursor
- calculate_width(current_line.byteslice(0, @byte_pointer))
- end
-
- private def calculate_nearest_cursor(cursor)
- line_to_calc = current_line
- new_cursor_max = calculate_width(line_to_calc)
- new_cursor = 0
- new_byte_pointer = 0
- height = 1
- max_width = screen_width
- if @config.editing_mode_is?(:vi_command)
- last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize)
- if last_byte_size > 0
- last_mbchar = line_to_calc.byteslice(line_to_calc.bytesize - last_byte_size, last_byte_size)
- last_width = Reline::Unicode.get_mbchar_width(last_mbchar)
- end_of_line_cursor = new_cursor_max - last_width
- else
- end_of_line_cursor = new_cursor_max
- end
- else
- end_of_line_cursor = new_cursor_max
- end
- line_to_calc.grapheme_clusters.each do |gc|
- mbchar = gc.encode(Encoding::UTF_8)
- mbchar_width = Reline::Unicode.get_mbchar_width(mbchar)
- now = new_cursor + mbchar_width
- if now > end_of_line_cursor or now > cursor
- break
- end
- new_cursor += mbchar_width
- if new_cursor > max_width * height
- height += 1
- end
- new_byte_pointer += gc.bytesize
- end
- @byte_pointer = new_byte_pointer
- end
-
- def with_cache(key, *deps)
- cached_deps, value = @cache[key]
- if cached_deps != deps
- @cache[key] = [deps, value = yield(*deps, cached_deps, value)]
- end
- value
- end
-
- def modified_lines
- with_cache(__method__, whole_lines, finished?) do |whole, complete|
- modify_lines(whole, complete)
- end
- end
-
- def prompt_list
- with_cache(__method__, whole_lines, check_mode_string, @vi_arg, @searching_prompt) do |lines, mode_string|
- check_multiline_prompt(lines, mode_string)
- end
- end
-
- def screen_height
- @screen_size.first
- end
-
- def screen_width
- @screen_size.last
- end
-
- def screen_scroll_top
- @scroll_partial_screen
- end
-
- def wrapped_prompt_and_input_lines
- with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
- prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
- cached_wraps = {}
- if prev_width == width
- prev_n.times do |i|
- cached_wraps[[prev_prompts[i], prev_lines[i]]] = cached_value[i]
- end
- end
-
- n.times.map do |i|
- prompt = prompts[i] || ''
- line = lines[i] || ''
- if (cached = cached_wraps[[prompt, line]])
- next cached
- end
- *wrapped_prompts, code_line_prompt = split_line_by_width(prompt, width)
- wrapped_lines = split_line_by_width(line, width, offset: calculate_width(code_line_prompt, true))
- wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
- end
- end
- end
-
- def calculate_overlay_levels(overlay_levels)
- levels = []
- overlay_levels.each do |x, w, l|
- levels.fill(l, x, w)
- end
- levels
- end
-
- def render_line_differential(old_items, new_items)
- old_levels = calculate_overlay_levels(old_items.zip(new_items).each_with_index.map {|((x, w, c), (nx, _nw, nc)), i| [x, w, c == nc && x == nx ? i : -1] if x }.compact)
- new_levels = calculate_overlay_levels(new_items.each_with_index.map { |(x, w), i| [x, w, i] if x }.compact).take(screen_width)
- base_x = 0
- new_levels.zip(old_levels).chunk { |n, o| n == o ? :skip : n || :blank }.each do |level, chunk|
- width = chunk.size
- if level == :skip
- # do nothing
- elsif level == :blank
- Reline::IOGate.move_cursor_column base_x
- Reline::IOGate.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
- else
- x, w, content = new_items[level]
- cover_begin = base_x != 0 && new_levels[base_x - 1] == level
- cover_end = new_levels[base_x + width] == level
- pos = 0
- unless x == base_x && w == width
- content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
- end
- Reline::IOGate.move_cursor_column x + pos
- Reline::IOGate.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
- end
- base_x += width
- end
- if old_levels.size > new_levels.size
- Reline::IOGate.move_cursor_column new_levels.size
- Reline::IOGate.erase_after_cursor
- end
- end
-
- # Calculate cursor position in word wrapped content.
- def wrapped_cursor_position
- prompt_width = calculate_width(prompt_list[@line_index], true)
- line_before_cursor = Reline::Unicode.escape_for_print(whole_lines[@line_index].byteslice(0, @byte_pointer))
- wrapped_line_before_cursor = split_line_by_width(' ' * prompt_width + line_before_cursor, screen_width)
- wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
- wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
- [wrapped_cursor_x, wrapped_cursor_y]
- end
-
- def clear_dialogs
- @dialogs.each do |dialog|
- dialog.contents = nil
- dialog.trap_key = nil
- end
- end
-
- def update_dialogs(key = nil)
- wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- @dialogs.each do |dialog|
- dialog.trap_key = nil
- update_each_dialog(dialog, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top, key)
- end
- end
-
- def render_finished
- Reline::IOGate.buffered_output do
- render_differential([], 0, 0)
- lines = @buffer_of_lines.size.times.map do |i|
- line = Reline::Unicode.strip_non_printing_start_end(prompt_list[i]) + modified_lines[i]
- wrapped_lines = split_line_by_width(line, screen_width)
- wrapped_lines.last.empty? ? "#{line} " : line
- end
- Reline::IOGate.write lines.map { |l| "#{l}\r\n" }.join
- end
- end
-
- def print_nomultiline_prompt
- Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
- # Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
- Reline::IOGate.write Reline::Unicode.strip_non_printing_start_end(@prompt) if @prompt && !@is_multiline
- ensure
- Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
- end
-
- def render
- wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
- prompt_width = Reline::Unicode.calculate_width(prompt, true)
- [[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
- end
- if @menu_info
- @menu_info.lines(screen_width).each do |item|
- new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
- end
- @menu_info = nil # TODO: do not change state here
- end
-
- @dialogs.each_with_index do |dialog, index|
- next unless dialog.contents
-
- x_range, y_range = dialog_range dialog, wrapped_cursor_y - screen_scroll_top
- y_range.each do |row|
- next if row < 0 || row >= screen_height
-
- dialog_rows = new_lines[row] ||= []
- # index 0 is for prompt, index 1 is for line, index 2.. is for dialog
- dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
- end
- end
-
- Reline::IOGate.buffered_output do
- render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
- end
- end
-
- # Reflects lines to be rendered and new cursor position to the screen
- # by calculating the difference from the previous render.
-
- private def render_differential(new_lines, new_cursor_x, new_cursor_y)
- Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
- rendered_lines = @rendered_screen.lines
- cursor_y = @rendered_screen.cursor_y
- if new_lines != rendered_lines
- # Hide cursor while rendering to avoid cursor flickering.
- Reline::IOGate.hide_cursor
- num_lines = [[new_lines.size, rendered_lines.size].max, screen_height].min
- if @rendered_screen.base_y + num_lines > screen_height
- Reline::IOGate.scroll_down(num_lines - cursor_y - 1)
- @rendered_screen.base_y = screen_height - num_lines
- cursor_y = num_lines - 1
- end
- num_lines.times do |i|
- rendered_line = rendered_lines[i] || []
- line_to_render = new_lines[i] || []
- next if rendered_line == line_to_render
-
- Reline::IOGate.move_cursor_down i - cursor_y
- cursor_y = i
- unless rendered_lines[i]
- Reline::IOGate.move_cursor_column 0
- Reline::IOGate.erase_after_cursor
- end
- render_line_differential(rendered_line, line_to_render)
- end
- @rendered_screen.lines = new_lines
- Reline::IOGate.show_cursor
- end
- Reline::IOGate.move_cursor_column new_cursor_x
- new_cursor_y = new_cursor_y.clamp(0, screen_height - 1)
- Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
- @rendered_screen.cursor_y = new_cursor_y
- ensure
- Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
- end
-
- private def clear_rendered_screen_cache
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
- end
-
- def upper_space_height(wrapped_cursor_y)
- wrapped_cursor_y - screen_scroll_top
- end
-
- def rest_height(wrapped_cursor_y)
- screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
- end
-
- def rerender
- render unless @in_pasting
- end
-
- class DialogProcScope
- CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
-
- def initialize(line_editor, config, proc_to_exec, context)
- @line_editor = line_editor
- @config = config
- @proc_to_exec = proc_to_exec
- @context = context
- @cursor_pos = Reline::CursorPos.new
- end
-
- def context
- @context
- end
-
- def retrieve_completion_block(_unused = false)
- preposing, target, postposing, _quote = @line_editor.retrieve_completion_block
- [preposing, target, postposing]
- end
-
- def call_completion_proc_with_checking_args(pre, target, post)
- @line_editor.call_completion_proc_with_checking_args(pre, target, post)
- end
-
- def set_dialog(dialog)
- @dialog = dialog
- end
-
- def dialog
- @dialog
- end
-
- def set_cursor_pos(col, row)
- @cursor_pos.x = col
- @cursor_pos.y = row
- end
-
- def set_key(key)
- @key = key
- end
-
- def key
- @key
- end
-
- def cursor_pos
- @cursor_pos
- end
-
- def just_cursor_moving
- @line_editor.instance_variable_get(:@just_cursor_moving)
- end
-
- def screen_width
- @line_editor.screen_width
- end
-
- def screen_height
- @line_editor.screen_height
- end
-
- def preferred_dialog_height
- _wrapped_cursor_x, wrapped_cursor_y = @line_editor.wrapped_cursor_position
- [@line_editor.upper_space_height(wrapped_cursor_y), @line_editor.rest_height(wrapped_cursor_y), (screen_height + 6) / 5].max
- end
-
- def completion_journey_data
- @line_editor.dialog_proc_scope_completion_journey_data
- end
-
- def config
- @config
- end
-
- def call
- instance_exec(&@proc_to_exec)
- end
- end
-
- class Dialog
- attr_reader :name, :contents, :width
- attr_accessor :scroll_top, :pointer, :column, :vertical_offset, :trap_key
-
- def initialize(name, config, proc_scope)
- @name = name
- @config = config
- @proc_scope = proc_scope
- @width = nil
- @scroll_top = 0
- @trap_key = nil
- end
-
- def set_cursor_pos(col, row)
- @proc_scope.set_cursor_pos(col, row)
- end
-
- def width=(v)
- @width = v
- end
-
- def contents=(contents)
- @contents = contents
- if contents and @width.nil?
- @width = contents.map{ |line| Reline::Unicode.calculate_width(line, true) }.max
- end
- end
-
- def call(key)
- @proc_scope.set_dialog(self)
- @proc_scope.set_key(key)
- dialog_render_info = @proc_scope.call
- if @trap_key
- if @trap_key.any?{ |i| i.is_a?(Array) } # multiple trap
- @trap_key.each do |t|
- @config.add_oneshot_key_binding(t, @name)
- end
- else
- @config.add_oneshot_key_binding(@trap_key, @name)
- end
- end
- dialog_render_info
- end
- end
-
- def add_dialog_proc(name, p, context = nil)
- dialog = Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context))
- if index = @dialogs.find_index { |d| d.name == name }
- @dialogs[index] = dialog
- else
- @dialogs << dialog
- end
- end
-
- DIALOG_DEFAULT_HEIGHT = 20
-
- private def dialog_range(dialog, dialog_y)
- x_range = dialog.column...dialog.column + dialog.width
- y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
- [x_range, y_range]
- end
-
- private def update_each_dialog(dialog, cursor_column, cursor_row, key = nil)
- dialog.set_cursor_pos(cursor_column, cursor_row)
- dialog_render_info = dialog.call(key)
- if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
- dialog.contents = nil
- dialog.trap_key = nil
- return
- end
- contents = dialog_render_info.contents
- pointer = dialog.pointer
- if dialog_render_info.width
- dialog.width = dialog_render_info.width
- else
- dialog.width = contents.map { |l| calculate_width(l, true) }.max
- end
- height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
- height = contents.size if contents.size < height
- if contents.size > height
- if dialog.pointer
- if dialog.pointer < 0
- dialog.scroll_top = 0
- elsif (dialog.pointer - dialog.scroll_top) >= (height - 1)
- dialog.scroll_top = dialog.pointer - (height - 1)
- elsif (dialog.pointer - dialog.scroll_top) < 0
- dialog.scroll_top = dialog.pointer
- end
- pointer = dialog.pointer - dialog.scroll_top
- else
- dialog.scroll_top = 0
- end
- contents = contents[dialog.scroll_top, height]
- end
- if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
- bar_max_height = height * 2
- moving_distance = (dialog_render_info.contents.size - height) * 2
- position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
- bar_height = (bar_max_height * ((contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
- bar_height = MINIMUM_SCROLLBAR_HEIGHT if bar_height < MINIMUM_SCROLLBAR_HEIGHT
- scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
- else
- scrollbar_pos = nil
- end
- dialog.column = dialog_render_info.pos.x
- dialog.width += @block_elem_width if scrollbar_pos
- diff = (dialog.column + dialog.width) - screen_width
- if diff > 0
- dialog.column -= diff
- end
- if rest_height(screen_scroll_top + cursor_row) - dialog_render_info.pos.y >= height
- dialog.vertical_offset = dialog_render_info.pos.y + 1
- elsif cursor_row >= height
- dialog.vertical_offset = dialog_render_info.pos.y - height
- else
- dialog.vertical_offset = dialog_render_info.pos.y + 1
- end
- if dialog.column < 0
- dialog.column = 0
- dialog.width = screen_width
- end
- face = Reline::Face[dialog_render_info.face || :default]
- scrollbar_sgr = face[:scrollbar]
- default_sgr = face[:default]
- enhanced_sgr = face[:enhanced]
- dialog.contents = contents.map.with_index do |item, i|
- line_sgr = i == pointer ? enhanced_sgr : default_sgr
- str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
- str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
- colored_content = "#{line_sgr}#{str}"
- if scrollbar_pos
- if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @full_block
- elsif scrollbar_pos <= (i * 2) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @upper_half_block
- elsif scrollbar_pos <= (i * 2 + 1) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @lower_half_block
- else
- colored_content + scrollbar_sgr + ' ' * @block_elem_width
- end
- else
- colored_content
- end
- end
- end
-
- private def modify_lines(before, complete)
- if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
- after.lines("\n").map { |l| l.chomp('') }
- else
- before.map { |l| Reline::Unicode.escape_for_print(l) }
- end
- end
-
- def editing_mode
- @config.editing_mode
- end
-
- private def menu(list)
- @menu_info = MenuInfo.new(list)
- end
-
- private def filter_normalize_candidates(target, list)
- target = target.downcase if @config.completion_ignore_case
- list.select do |item|
- next unless item
- unless Encoding.compatible?(target.encoding, item.encoding)
- # Workaround for Readline test
- if defined?(::Readline) && ::Readline == ::Reline
- raise Encoding::CompatibilityError, "incompatible character encodings: #{target.encoding} and #{item.encoding}"
- end
- end
-
- if @config.completion_ignore_case
- item.downcase.start_with?(target)
- else
- item.start_with?(target)
- end
- end.map do |item|
- item.unicode_normalize
- rescue Encoding::CompatibilityError
- item
- end.uniq
- end
-
- private def perform_completion(preposing, target, postposing, quote, list)
- candidates = filter_normalize_candidates(target, list)
-
- case @completion_state
- when CompletionState::PERFECT_MATCH
- if @dig_perfect_match_proc
- @dig_perfect_match_proc.call(@perfect_matched)
- return
- end
- when CompletionState::MENU
- menu(candidates)
- return
- when CompletionState::MENU_WITH_PERFECT_MATCH
- menu(candidates)
- @completion_state = CompletionState::PERFECT_MATCH
- return
- end
-
- completed = Reline::Unicode.common_prefix(candidates, ignore_case: @config.completion_ignore_case)
- return if completed.empty?
-
- append_character = ''
- if candidates.include?(completed)
- if candidates.one?
- append_character = quote || completion_append_character.to_s
- @completion_state = CompletionState::PERFECT_MATCH
- elsif @config.show_all_if_ambiguous
- menu(candidates)
- @completion_state = CompletionState::PERFECT_MATCH
- else
- @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
- end
- @perfect_matched = completed
- else
- @completion_state = CompletionState::MENU
- menu(candidates) if @config.show_all_if_ambiguous
- end
- @buffer_of_lines[@line_index] = (preposing + completed + append_character + postposing).split("\n")[@line_index] || String.new(encoding: encoding)
- line_to_pointer = (preposing + completed + append_character).split("\n")[@line_index] || String.new(encoding: encoding)
- @byte_pointer = line_to_pointer.bytesize
- end
-
- def dialog_proc_scope_completion_journey_data
- return nil unless @completion_journey_state
- line_index = @completion_journey_state.line_index
- pre_lines = @buffer_of_lines[0...line_index].map { |line| line + "\n" }
- post_lines = @buffer_of_lines[(line_index + 1)..-1].map { |line| line + "\n" }
- DialogProcScope::CompletionJourneyData.new(
- pre_lines.join + @completion_journey_state.pre,
- @completion_journey_state.post + post_lines.join,
- @completion_journey_state.list,
- @completion_journey_state.pointer
- )
- end
-
- private def move_completed_list(direction)
- @completion_journey_state ||= retrieve_completion_journey_state
- return false unless @completion_journey_state
-
- if (delta = { up: -1, down: +1 }[direction])
- @completion_journey_state.pointer = (@completion_journey_state.pointer + delta) % @completion_journey_state.list.size
- end
- completed = @completion_journey_state.list[@completion_journey_state.pointer]
- set_current_line(@completion_journey_state.pre + completed + @completion_journey_state.post, @completion_journey_state.pre.bytesize + completed.bytesize)
- true
- end
-
- private def retrieve_completion_journey_state
- preposing, target, postposing, quote = retrieve_completion_block
- list = call_completion_proc(preposing, target, postposing, quote)
- return unless list.is_a?(Array)
-
- candidates = list.select{ |item| item.start_with?(target) }
- return if candidates.empty?
-
- pre = preposing.split("\n", -1).last || ''
- post = postposing.split("\n", -1).first || ''
- CompletionJourneyState.new(
- @line_index, pre, target, post, [target] + candidates, 0
- )
- end
-
- private def run_for_operators(key, method_symbol)
- # Reject multibyte input (converted to ed_insert) in vi_command mode
- return if method_symbol == :ed_insert && @config.editing_mode_is?(:vi_command) && !@waiting_proc
-
- if ARGUMENT_DIGIT_METHODS.include?(method_symbol) && !@waiting_proc
- wrap_method_call(method_symbol, key, false)
- return
- end
-
- if @vi_waiting_operator
- if @waiting_proc || VI_MOTIONS.include?(method_symbol)
- old_byte_pointer = @byte_pointer
- @vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
- wrap_method_call(method_symbol, key, true)
- unless @waiting_proc
- byte_pointer_diff = @byte_pointer - old_byte_pointer
- @byte_pointer = old_byte_pointer
- __send__(@vi_waiting_operator, byte_pointer_diff)
- cleanup_waiting
- end
- else
- # Ignores operator when not motion is given.
- wrap_method_call(method_symbol, key, false)
- cleanup_waiting
- end
- else
- wrap_method_call(method_symbol, key, false)
- end
- @vi_arg = nil
- @kill_ring.process
- end
-
- private def argumentable?(method_obj)
- method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :arg }
- end
-
- private def inclusive?(method_obj)
- # If a motion method with the keyword argument "inclusive" follows the
- # operator, it must contain the character at the cursor position.
- method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :inclusive }
- end
-
- def wrap_method_call(method_symbol, key, with_operator)
- if @waiting_proc
- @waiting_proc.call(key)
- return
- end
-
- return unless respond_to?(method_symbol, true)
- method_obj = method(method_symbol)
- if @vi_arg and argumentable?(method_obj)
- if inclusive?(method_obj)
- method_obj.(key, arg: @vi_arg, inclusive: with_operator)
- else
- method_obj.(key, arg: @vi_arg)
- end
- else
- if inclusive?(method_obj)
- method_obj.(key, inclusive: with_operator)
- else
- method_obj.(key)
- end
- end
- end
-
- private def cleanup_waiting
- @waiting_proc = nil
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- @searching_prompt = nil
- @drop_terminate_spaces = false
- end
-
- ARGUMENT_DIGIT_METHODS = %i[ed_digit vi_zero ed_argument_digit]
- VI_WAITING_ACCEPT_METHODS = %i[vi_change_meta vi_delete_meta vi_yank ed_insert ed_argument_digit]
-
- private def process_key(key, method_symbol)
- if @waiting_proc
- cleanup_waiting unless key.size == 1
- end
- if @vi_waiting_operator
- cleanup_waiting unless VI_WAITING_ACCEPT_METHODS.include?(method_symbol) || VI_MOTIONS.include?(method_symbol)
- end
-
- process_insert(force: method_symbol != :ed_insert)
-
- run_for_operators(key, method_symbol)
- end
-
- def update(key)
- modified = input_key(key)
- unless @in_pasting
- scroll_into_view
- @just_cursor_moving = !modified
- update_dialogs(key)
- @just_cursor_moving = false
- end
- end
-
- def input_key(key)
- save_old_buffer
- @config.reset_oneshot_key_bindings
- if key.char.nil?
- process_insert(force: true)
- @eof = buffer_empty?
- finish
- return
- end
- return if @dialogs.any? { |dialog| dialog.name == key.method_symbol }
-
- @completion_occurs = false
-
- process_key(key.char, key.method_symbol)
- if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
- byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
- @byte_pointer -= byte_size
- end
-
- @prev_action_state, @next_action_state = @next_action_state, NullActionState
-
- unless @completion_occurs
- @completion_state = CompletionState::NORMAL
- @completion_journey_state = nil
- end
-
- push_input_lines unless @restoring
- @restoring = false
-
- if @in_pasting
- clear_dialogs
- return
- end
-
- modified = @old_buffer_of_lines != @buffer_of_lines
- if !@completion_occurs && modified && [email protected]_completion && @config.autocompletion
- # Auto complete starts only when edited
- process_insert(force: true)
- @completion_journey_state = retrieve_completion_journey_state
- end
- modified
- end
-
- def save_old_buffer
- @old_buffer_of_lines = @buffer_of_lines.dup
- end
-
- def push_input_lines
- if @old_buffer_of_lines == @buffer_of_lines
- @input_lines[@input_lines_position] = [@buffer_of_lines.dup, @byte_pointer, @line_index]
- else
- @input_lines = @input_lines[0..@input_lines_position]
- @input_lines_position += 1
- @input_lines.push([@buffer_of_lines.dup, @byte_pointer, @line_index])
- end
- trim_input_lines
- end
-
- MAX_INPUT_LINES = 100
- def trim_input_lines
- if @input_lines.size > MAX_INPUT_LINES
- @input_lines.shift
- @input_lines_position -= 1
- end
- end
-
- def scroll_into_view
- _wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- if wrapped_cursor_y < screen_scroll_top
- @scroll_partial_screen = wrapped_cursor_y
- end
- if wrapped_cursor_y >= screen_scroll_top + screen_height
- @scroll_partial_screen = wrapped_cursor_y - screen_height + 1
- end
- end
-
- def call_completion_proc(pre, target, post, quote)
- Reline.core.instance_variable_set(:@completion_quote_character, quote)
- result = call_completion_proc_with_checking_args(pre, target, post)
- Reline.core.instance_variable_set(:@completion_quote_character, nil)
- result
- end
-
- def call_completion_proc_with_checking_args(pre, target, post)
- if @completion_proc and target
- argnum = @completion_proc.parameters.inject(0) { |result, item|
- case item.first
- when :req, :opt
- result + 1
- when :rest
- break 3
- end
- }
- case argnum
- when 1
- result = @completion_proc.(target)
- when 2
- result = @completion_proc.(target, pre)
- when 3..Float::INFINITY
- result = @completion_proc.(target, pre, post)
- end
- end
- result
- end
-
- private def process_auto_indent(line_index = @line_index, cursor_dependent: true, add_newline: false)
- return if @in_pasting
- return unless @auto_indent_proc
-
- line = @buffer_of_lines[line_index]
- byte_pointer = cursor_dependent && @line_index == line_index ? @byte_pointer : line.bytesize
- new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
- return unless new_indent
-
- new_line = ' ' * new_indent + line.lstrip
- @buffer_of_lines[line_index] = new_line
- if @line_index == line_index
- indent_diff = new_line.bytesize - line.bytesize
- @byte_pointer = [@byte_pointer + indent_diff, 0].max
- end
- end
-
- def line()
- @buffer_of_lines.join("\n") unless eof?
- end
-
- def current_line
- @buffer_of_lines[@line_index]
- end
-
- def set_current_line(line, byte_pointer = nil)
- cursor = current_byte_pointer_cursor
- @buffer_of_lines[@line_index] = line
- if byte_pointer
- @byte_pointer = byte_pointer
- else
- calculate_nearest_cursor(cursor)
- end
- process_auto_indent
- end
-
- def retrieve_completion_block
- quote_characters = Reline.completer_quote_characters
- before = current_line.byteslice(0, @byte_pointer).grapheme_clusters
- quote = nil
- # Calculate closing quote when cursor is at the end of the line
- if current_line.bytesize == @byte_pointer && !quote_characters.empty?
- escaped = false
- before.each do |c|
- if escaped
- escaped = false
- next
- elsif c == '\\'
- escaped = true
- elsif quote
- quote = nil if c == quote
- elsif quote_characters.include?(c)
- quote = c
- end
- end
- end
-
- word_break_characters = quote_characters + Reline.completer_word_break_characters
- break_index = before.rindex { |c| word_break_characters.include?(c) || quote_characters.include?(c) } || -1
- preposing = before.take(break_index + 1).join
- target = before.drop(break_index + 1).join
- postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
- lines = whole_lines
- if @line_index > 0
- preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
- end
- if (lines.size - 1) > @line_index
- postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
- end
- [preposing.encode(encoding), target.encode(encoding), postposing.encode(encoding), quote&.encode(encoding)]
- end
-
- def confirm_multiline_termination
- temp_buffer = @buffer_of_lines.dup
- @confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
- end
-
- def insert_multiline_text(text)
- pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
- post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
- lines = (pre + Reline::Unicode.safe_encode(text, encoding).gsub(/\r\n?/, "\n") + post).split("\n", -1)
- lines << '' if lines.empty?
- @buffer_of_lines[@line_index, 1] = lines
- @line_index += lines.size - 1
- @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
- end
-
- def insert_text(text)
- if @buffer_of_lines[@line_index].bytesize == @byte_pointer
- @buffer_of_lines[@line_index] += text
- else
- @buffer_of_lines[@line_index] = byteinsert(@buffer_of_lines[@line_index], @byte_pointer, text)
- end
- @byte_pointer += text.bytesize
- process_auto_indent
- end
-
- def delete_text(start = nil, length = nil)
- if start.nil? and length.nil?
- if @buffer_of_lines.size == 1
- @buffer_of_lines[@line_index] = ''
- @byte_pointer = 0
- elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
- @buffer_of_lines.pop
- @line_index -= 1
- @byte_pointer = 0
- elsif @line_index < (@buffer_of_lines.size - 1)
- @buffer_of_lines.delete_at(@line_index)
- @byte_pointer = 0
- end
- elsif not start.nil? and not length.nil?
- if current_line
- before = current_line.byteslice(0, start)
- after = current_line.byteslice(start + length, current_line.bytesize)
- set_current_line(before + after)
- end
- elsif start.is_a?(Range)
- range = start
- first = range.first
- last = range.last
- last = current_line.bytesize - 1 if last > current_line.bytesize
- last += current_line.bytesize if last < 0
- first += current_line.bytesize if first < 0
- range = range.exclude_end? ? first...last : first..last
- line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(encoding)
- set_current_line(line)
- else
- set_current_line(current_line.byteslice(0, start))
- end
- end
-
- def byte_pointer=(val)
- @byte_pointer = val
- end
-
- def whole_lines
- @buffer_of_lines.dup
- end
-
- def whole_buffer
- whole_lines.join("\n")
- end
-
- private def buffer_empty?
- current_line.empty? and @buffer_of_lines.size == 1
- end
-
- def finished?
- @finished
- end
-
- def finish
- @finished = true
- @config.reset
- end
-
- private def byteslice!(str, byte_pointer, size)
- new_str = str.byteslice(0, byte_pointer)
- new_str << str.byteslice(byte_pointer + size, str.bytesize)
- [new_str, str.byteslice(byte_pointer, size)]
- end
-
- private def byteinsert(str, byte_pointer, other)
- new_str = str.byteslice(0, byte_pointer)
- new_str << other
- new_str << str.byteslice(byte_pointer, str.bytesize)
- new_str
- end
-
- private def calculate_width(str, allow_escape_code = false)
- Reline::Unicode.calculate_width(str, allow_escape_code)
- end
-
- private def key_delete(key)
- if @config.editing_mode_is?(:vi_insert)
- ed_delete_next_char(key)
- elsif @config.editing_mode_is?(:emacs)
- em_delete(key)
- end
- end
-
- private def key_newline(key)
- if @is_multiline
- next_line = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
- cursor_line = current_line.byteslice(0, @byte_pointer)
- insert_new_line(cursor_line, next_line)
- end
- end
-
- private def complete(_key)
- return if @config.disable_completion
-
- process_insert(force: true)
- if @config.autocompletion
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(:down)
- else
- @completion_journey_state = nil
- pre, target, post, quote = retrieve_completion_block
- result = call_completion_proc(pre, target, post, quote)
- if result.is_a?(Array)
- @completion_occurs = true
- perform_completion(pre, target, post, quote, result)
- end
- end
- end
-
- private def completion_journey_move(direction)
- return if @config.disable_completion
-
- process_insert(force: true)
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(direction)
- end
-
- private def menu_complete(_key)
- completion_journey_move(:down)
- end
-
- private def menu_complete_backward(_key)
- completion_journey_move(:up)
- end
-
- private def completion_journey_up(_key)
- completion_journey_move(:up) if @config.autocompletion
- end
-
- # Editline:: +ed-unassigned+ This editor command always results in an error.
- # GNU Readline:: There is no corresponding macro.
- private def ed_unassigned(key) end # do nothing
-
- private def process_insert(force: false)
- return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
- insert_text(@continuous_insertion_buffer)
- @continuous_insertion_buffer.clear
- end
-
- # Editline:: +ed-insert+ (vi input: almost all; emacs: printable characters)
- # In insert mode, insert the input character left of the cursor
- # position. In replace mode, overwrite the character at the
- # cursor and move the cursor to the right by one character
- # position. Accept an argument to do this repeatedly. It is an
- # error if the input character is the NUL character (+Ctrl-@+).
- # Failure to enlarge the edit buffer also results in an error.
- # Editline:: +ed-digit+ (emacs: 0 to 9) If in argument input mode, append
- # the input digit to the argument being read. Otherwise, call
- # +ed-insert+. It is an error if the input character is not a
- # digit or if the existing argument is already greater than a
- # million.
- # GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
- private def ed_insert(str)
- begin
- str.encode(Encoding::UTF_8)
- rescue Encoding::UndefinedConversionError
- return
- end
- if @in_pasting
- @continuous_insertion_buffer << str
- return
- elsif not @continuous_insertion_buffer.empty?
- process_insert
- end
-
- insert_text(str)
- end
- alias_method :self_insert, :ed_insert
-
- private def ed_digit(key)
- if @vi_arg
- ed_argument_digit(key)
- else
- ed_insert(key)
- end
- end
-
- private def insert_raw_char(str, arg: 1)
- arg.times do
- if str == "\C-j" or str == "\C-m"
- key_newline(str)
- elsif str != "\0"
- # Ignore NUL.
- ed_insert(str)
- end
- end
- end
-
- private def ed_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- if (@byte_pointer < current_line.bytesize)
- @byte_pointer += byte_size
- elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
- @byte_pointer = 0
- @line_index += 1
- end
- arg -= 1
- ed_next_char(key, arg: arg) if arg > 0
- end
- alias_method :forward_char, :ed_next_char
-
- private def ed_prev_char(key, arg: 1)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- @byte_pointer -= byte_size
- elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
- @line_index -= 1
- @byte_pointer = current_line.bytesize
- end
- arg -= 1
- ed_prev_char(key, arg: arg) if arg > 0
- end
- alias_method :backward_char, :ed_prev_char
-
- private def vi_first_print(key)
- @byte_pointer = Reline::Unicode.vi_first_print(current_line)
- end
-
- private def ed_move_to_beg(key)
- @byte_pointer = 0
- end
- alias_method :beginning_of_line, :ed_move_to_beg
-
- private def vi_zero(key)
- if @vi_arg
- ed_argument_digit(key)
- else
- ed_move_to_beg(key)
- end
- end
-
- private def ed_move_to_end(key)
- @byte_pointer = current_line.bytesize
- end
- alias_method :end_of_line, :ed_move_to_end
-
- private def generate_searcher(search_key)
- search_word = String.new(encoding: encoding)
- hit_pointer = nil
- lambda do |key|
- search_again = false
- case key
- when "\C-h", "\C-?"
- grapheme_clusters = search_word.grapheme_clusters
- if grapheme_clusters.size > 0
- grapheme_clusters.pop
- search_word = grapheme_clusters.join
- end
- when "\C-r", "\C-s"
- search_again = true if search_key == key
- search_key = key
- else
- search_word << key
- end
- hit = nil
- if not search_word.empty? and @line_backup_in_history&.include?(search_word)
- hit_pointer = Reline::HISTORY.size
- hit = @line_backup_in_history
- else
- if search_again
- if search_word.empty? and Reline.last_incremental_search
- search_word = Reline.last_incremental_search
- end
- if @history_pointer
- case search_key
- when "\C-r"
- history_pointer_base = 0
- history = Reline::HISTORY[0..(@history_pointer - 1)]
- when "\C-s"
- history_pointer_base = @history_pointer + 1
- history = Reline::HISTORY[(@history_pointer + 1)..-1]
- end
- else
- history_pointer_base = 0
- history = Reline::HISTORY
- end
- elsif @history_pointer
- case search_key
- when "\C-r"
- history_pointer_base = 0
- history = Reline::HISTORY[0..@history_pointer]
- when "\C-s"
- history_pointer_base = @history_pointer
- history = Reline::HISTORY[@history_pointer..-1]
- end
- else
- history_pointer_base = 0
- history = Reline::HISTORY
- end
- case search_key
- when "\C-r"
- hit_index = history.rindex { |item|
- item.include?(search_word)
- }
- when "\C-s"
- hit_index = history.index { |item|
- item.include?(search_word)
- }
- end
- if hit_index
- hit_pointer = history_pointer_base + hit_index
- hit = Reline::HISTORY[hit_pointer]
- end
- end
- case search_key
- when "\C-r"
- prompt_name = 'reverse-i-search'
- when "\C-s"
- prompt_name = 'i-search'
- end
- prompt_name = "failed #{prompt_name}" unless hit
- [search_word, prompt_name, hit_pointer]
- end
- end
-
- private def incremental_search_history(key)
- backup = @buffer_of_lines.dup, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history
- searcher = generate_searcher(key)
- @searching_prompt = "(reverse-i-search)`': "
- termination_keys = ["\C-j"]
- termination_keys.concat(@config.isearch_terminators.chars) if @config.isearch_terminators
- @waiting_proc = ->(k) {
- if k == "\C-g"
- # cancel search and restore buffer
- @buffer_of_lines, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history = backup
- @searching_prompt = nil
- @waiting_proc = nil
- elsif !termination_keys.include?(k) && (k.match?(/[[:print:]]/) || k == "\C-h" || k == "\C-?" || k == "\C-r" || k == "\C-s")
- search_word, prompt_name, hit_pointer = searcher.call(k)
- Reline.last_incremental_search = search_word
- @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
- @searching_prompt += ': ' unless @is_multiline
- move_history(hit_pointer, line: :end, cursor: :end) if hit_pointer
- else
- # terminaton_keys and other keys will terminalte
- move_history(@history_pointer, line: :end, cursor: :start)
- @searching_prompt = nil
- @waiting_proc = nil
- end
- }
- end
-
- private def vi_search_prev(key)
- incremental_search_history(key)
- end
- alias_method :reverse_search_history, :vi_search_prev
-
- private def vi_search_next(key)
- incremental_search_history(key)
- end
- alias_method :forward_search_history, :vi_search_next
-
- private def search_history(prefix, pointer_range)
- pointer_range.each do |pointer|
- lines = Reline::HISTORY[pointer].split("\n")
- lines.each_with_index do |line, index|
- return [pointer, index] if line.start_with?(prefix)
- end
- end
- nil
- end
-
- private def ed_search_prev_history(key, arg: 1)
- substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
- return if @history_pointer == 0
- return if @history_pointer.nil? && substr.empty? && !current_line.empty?
-
- history_range = 0...(@history_pointer || Reline::HISTORY.size)
- h_pointer, line_index = search_history(substr, history_range.reverse_each)
- return unless h_pointer
- move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
- arg -= 1
- set_next_action_state(:search_history, :empty) if substr.empty?
- ed_search_prev_history(key, arg: arg) if arg > 0
- end
- alias_method :history_search_backward, :ed_search_prev_history
-
- private def ed_search_next_history(key, arg: 1)
- substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
- return if @history_pointer.nil?
-
- history_range = @history_pointer + 1...Reline::HISTORY.size
- h_pointer, line_index = search_history(substr, history_range)
- return if h_pointer.nil? and not substr.empty?
-
- move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
- arg -= 1
- set_next_action_state(:search_history, :empty) if substr.empty?
- ed_search_next_history(key, arg: arg) if arg > 0
- end
- alias_method :history_search_forward, :ed_search_next_history
-
- private def move_history(history_pointer, line:, cursor:)
- history_pointer ||= Reline::HISTORY.size
- return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
- old_history_pointer = @history_pointer || Reline::HISTORY.size
- if old_history_pointer == Reline::HISTORY.size
- @line_backup_in_history = whole_buffer
- else
- Reline::HISTORY[old_history_pointer] = whole_buffer
- end
- if history_pointer == Reline::HISTORY.size
- buf = @line_backup_in_history
- @history_pointer = @line_backup_in_history = nil
- else
- buf = Reline::HISTORY[history_pointer]
- @history_pointer = history_pointer
- end
- @buffer_of_lines = buf.split("\n")
- @buffer_of_lines = [String.new(encoding: encoding)] if @buffer_of_lines.empty?
- @line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
- @byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
- end
-
- private def ed_prev_history(key, arg: 1)
- if @line_index > 0
- cursor = current_byte_pointer_cursor
- @line_index -= 1
- calculate_nearest_cursor(cursor)
- return
- end
- move_history(
- (@history_pointer || Reline::HISTORY.size) - 1,
- line: :end,
- cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
- )
- arg -= 1
- ed_prev_history(key, arg: arg) if arg > 0
- end
- alias_method :previous_history, :ed_prev_history
-
- private def ed_next_history(key, arg: 1)
- if @line_index < (@buffer_of_lines.size - 1)
- cursor = current_byte_pointer_cursor
- @line_index += 1
- calculate_nearest_cursor(cursor)
- return
- end
- move_history(
- (@history_pointer || Reline::HISTORY.size) + 1,
- line: :start,
- cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
- )
- arg -= 1
- ed_next_history(key, arg: arg) if arg > 0
- end
- alias_method :next_history, :ed_next_history
-
- private def ed_newline(key)
- process_insert(force: true)
- if @is_multiline
- if @config.editing_mode_is?(:vi_command)
- if @line_index < (@buffer_of_lines.size - 1)
- ed_next_history(key) # means cursor down
- else
- # should check confirm_multiline_termination to finish?
- finish
- end
- else
- if @line_index == @buffer_of_lines.size - 1 && confirm_multiline_termination
- finish
- else
- key_newline(key)
- end
- end
- else
- finish
- end
- end
-
- private def ed_force_submit(_key)
- process_insert(force: true)
- finish
- end
-
- private def em_delete_prev_char(key, arg: 1)
- arg.times do
- if @byte_pointer == 0 and @line_index > 0
- @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
- @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
- @line_index -= 1
- elsif @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- line, = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
- end
- end
- process_auto_indent
- end
- alias_method :backward_delete_char, :em_delete_prev_char
-
- # Editline:: +ed-kill-line+ (vi command: +D+, +Ctrl-K+; emacs: +Ctrl-K+,
- # +Ctrl-U+) + Kill from the cursor to the end of the line.
- # GNU Readline:: +kill-line+ (+C-k+) Kill the text from point to the end of
- # the line. With a negative numeric argument, kill backward
- # from the cursor to the beginning of the current line.
- private def ed_kill_line(key)
- if current_line.bytesize > @byte_pointer
- line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
- set_current_line(line, line.bytesize)
- @kill_ring.append(deleted)
- elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
- set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
- end
- end
- alias_method :kill_line, :ed_kill_line
-
- # Editline:: +vi_change_to_eol+ (vi command: +C+) + Kill and change from the cursor to the end of the line.
- private def vi_change_to_eol(key)
- ed_kill_line(key)
-
- @config.editing_mode = :vi_insert
- end
-
- # Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
- # beginning of the edit buffer to the cursor and save it to the
- # cut buffer.
- # GNU Readline:: +unix-line-discard+ (+C-u+) Kill backward from the cursor
- # to the beginning of the current line.
- private def vi_kill_line_prev(key)
- if @byte_pointer > 0
- line, deleted = byteslice!(current_line, 0, @byte_pointer)
- set_current_line(line, 0)
- @kill_ring.append(deleted, true)
- end
- end
- alias_method :unix_line_discard, :vi_kill_line_prev
-
- # Editline:: +em-kill-line+ (not bound) Delete the entire contents of the
- # edit buffer and save it to the cut buffer. +vi-kill-line-prev+
- # GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
- # current line, no matter where point is.
- private def em_kill_line(key)
- if current_line.size > 0
- @kill_ring.append(current_line.dup, true)
- set_current_line('', 0)
- end
- end
- alias_method :kill_whole_line, :em_kill_line
-
- private def em_delete(key)
- if buffer_empty? and key == "\C-d"
- @eof = true
- finish
- elsif @byte_pointer < current_line.bytesize
- splitted_last = current_line.byteslice(@byte_pointer, current_line.bytesize)
- mbchar = splitted_last.grapheme_clusters.first
- line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
- set_current_line(line)
- elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
- set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
- end
- end
- alias_method :delete_char, :em_delete
-
- private def em_delete_or_list(key)
- if current_line.empty? or @byte_pointer < current_line.bytesize
- em_delete(key)
- elsif [email protected] # show completed list
- pre, target, post, quote = retrieve_completion_block
- result = call_completion_proc(pre, target, post, quote)
- if result.is_a?(Array)
- candidates = filter_normalize_candidates(target, result)
- menu(candidates)
- end
- end
- end
- alias_method :delete_char_or_list, :em_delete_or_list
-
- private def em_yank(key)
- yanked = @kill_ring.yank
- insert_text(yanked) if yanked
- end
- alias_method :yank, :em_yank
-
- private def em_yank_pop(key)
- yanked, prev_yank = @kill_ring.yank_pop
- if yanked
- line, = byteslice!(current_line, @byte_pointer - prev_yank.bytesize, prev_yank.bytesize)
- set_current_line(line, @byte_pointer - prev_yank.bytesize)
- insert_text(yanked)
- end
- end
- alias_method :yank_pop, :em_yank_pop
-
- private def ed_clear_screen(key)
- Reline::IOGate.clear_screen
- @screen_size = Reline::IOGate.get_screen_size
- @rendered_screen.base_y = 0
- clear_rendered_screen_cache
- end
- alias_method :clear_screen, :ed_clear_screen
-
- private def em_next_word(key)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- @byte_pointer += byte_size
- end
- end
- alias_method :forward_word, :em_next_word
-
- private def ed_prev_word(key)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
- @byte_pointer -= byte_size
- end
- end
- alias_method :backward_word, :ed_prev_word
-
- private def em_delete_next_word(key)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- line, word = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
- @kill_ring.append(word)
- end
- end
- alias_method :kill_word, :em_delete_next_word
-
- private def ed_delete_prev_word(key)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
- line, word = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
- @kill_ring.append(word, true)
- end
- end
- alias_method :backward_kill_word, :ed_delete_prev_word
-
- private def ed_transpose_chars(key)
- if @byte_pointer > 0
- if @byte_pointer < current_line.bytesize
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- @byte_pointer += byte_size
- end
- back1_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- if (@byte_pointer - back1_byte_size) > 0
- back2_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer - back1_byte_size)
- back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size
- line, back2_mbchar = byteslice!(current_line, back2_pointer, back2_byte_size)
- set_current_line(byteinsert(line, @byte_pointer - back2_byte_size, back2_mbchar))
- end
- end
- end
- alias_method :transpose_chars, :ed_transpose_chars
-
- private def ed_transpose_words(key)
- left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(current_line, @byte_pointer)
- before = current_line.byteslice(0, left_word_start)
- left_word = current_line.byteslice(left_word_start, middle_start - left_word_start)
- middle = current_line.byteslice(middle_start, right_word_start - middle_start)
- right_word = current_line.byteslice(right_word_start, after_start - right_word_start)
- after = current_line.byteslice(after_start, current_line.bytesize - after_start)
- return if left_word.empty? or right_word.empty?
- from_head_to_left_word = before + right_word + middle + left_word
- set_current_line(from_head_to_left_word + after, from_head_to_left_word.bytesize)
- end
- alias_method :transpose_words, :ed_transpose_words
-
- private def em_capitol_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
- before = current_line.byteslice(0, @byte_pointer)
- after = current_line.byteslice((@byte_pointer + byte_size)..-1)
- set_current_line(before + new_str + after, @byte_pointer + new_str.bytesize)
- end
- end
- alias_method :capitalize_word, :em_capitol_case
-
- private def em_lower_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
- mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
- }.join
- rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
- line = current_line.byteslice(0, @byte_pointer) + part
- set_current_line(line + rest, line.bytesize)
- end
- end
- alias_method :downcase_word, :em_lower_case
-
- private def em_upper_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
- mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
- }.join
- rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
- line = current_line.byteslice(0, @byte_pointer) + part
- set_current_line(line + rest, line.bytesize)
- end
- end
- alias_method :upcase_word, :em_upper_case
-
- private def em_kill_region(key)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
- line, deleted = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
- @kill_ring.append(deleted, true)
- end
- end
- alias_method :unix_word_rubout, :em_kill_region
-
- private def copy_for_vi(text)
- if @config.editing_mode_is?(:vi_insert) or @config.editing_mode_is?(:vi_command)
- @vi_clipboard = text
- end
- end
-
- private def vi_insert(key)
- @config.editing_mode = :vi_insert
- end
-
- private def vi_add(key)
- @config.editing_mode = :vi_insert
- ed_next_char(key)
- end
-
- private def vi_command_mode(key)
- ed_prev_char(key)
- @config.editing_mode = :vi_command
- end
- alias_method :vi_movement_mode, :vi_command_mode
-
- private def vi_next_word(key, arg: 1)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
- @byte_pointer += byte_size
- end
- arg -= 1
- vi_next_word(key, arg: arg) if arg > 0
- end
-
- private def vi_prev_word(key, arg: 1)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
- @byte_pointer -= byte_size
- end
- arg -= 1
- vi_prev_word(key, arg: arg) if arg > 0
- end
-
- private def vi_end_word(key, arg: 1, inclusive: false)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
- @byte_pointer += byte_size
- end
- arg -= 1
- if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- if byte_size > 0
- @byte_pointer += byte_size
- end
- end
- vi_end_word(key, arg: arg) if arg > 0
- end
-
- private def vi_next_big_word(key, arg: 1)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
- @byte_pointer += byte_size
- end
- arg -= 1
- vi_next_big_word(key, arg: arg) if arg > 0
- end
-
- private def vi_prev_big_word(key, arg: 1)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
- @byte_pointer -= byte_size
- end
- arg -= 1
- vi_prev_big_word(key, arg: arg) if arg > 0
- end
-
- private def vi_end_big_word(key, arg: 1, inclusive: false)
- if current_line.bytesize > @byte_pointer
- byte_size = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
- @byte_pointer += byte_size
- end
- arg -= 1
- if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- if byte_size > 0
- @byte_pointer += byte_size
- end
- end
- vi_end_big_word(key, arg: arg) if arg > 0
- end
-
- private def vi_delete_prev_char(key)
- if @byte_pointer == 0 and @line_index > 0
- @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
- @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
- @line_index -= 1
- process_auto_indent cursor_dependent: false
- elsif @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- @byte_pointer -= byte_size
- line, _ = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
- end
- end
-
- private def vi_insert_at_bol(key)
- ed_move_to_beg(key)
- @config.editing_mode = :vi_insert
- end
-
- private def vi_add_at_eol(key)
- ed_move_to_end(key)
- @config.editing_mode = :vi_insert
- end
-
- private def ed_delete_prev_char(key, arg: 1)
- deleted = +''
- arg.times do
- if @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- @byte_pointer -= byte_size
- line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
- deleted.prepend(mbchar)
- end
- end
- copy_for_vi(deleted)
- end
-
- private def vi_change_meta(key, arg: nil)
- if @vi_waiting_operator
- set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @drop_terminate_spaces = true
- @vi_waiting_operator = :vi_change_meta_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_change_meta_confirm(byte_pointer_diff)
- vi_delete_meta_confirm(byte_pointer_diff)
- @config.editing_mode = :vi_insert
- @drop_terminate_spaces = false
- end
-
- private def vi_delete_meta(key, arg: nil)
- if @vi_waiting_operator
- set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @vi_waiting_operator = :vi_delete_meta_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_delete_meta_confirm(byte_pointer_diff)
- if byte_pointer_diff > 0
- line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- else
- return
- end
- copy_for_vi(cut)
- set_current_line(line, @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
- end
-
- private def vi_yank(key, arg: nil)
- if @vi_waiting_operator
- copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @vi_waiting_operator = :vi_yank_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_yank_confirm(byte_pointer_diff)
- if byte_pointer_diff > 0
- cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- else
- return
- end
- copy_for_vi(cut)
- end
-
- private def vi_list_or_eof(key)
- if buffer_empty?
- @eof = true
- finish
- else
- ed_newline(key)
- end
- end
- alias_method :vi_end_of_transmission, :vi_list_or_eof
- alias_method :vi_eof_maybe, :vi_list_or_eof
-
- private def ed_delete_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- unless current_line.empty? || byte_size == 0
- line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
- copy_for_vi(mbchar)
- if @byte_pointer > 0 && current_line.bytesize == @byte_pointer + byte_size
- byte_size = Reline::Unicode.get_prev_mbchar_size(line, @byte_pointer)
- set_current_line(line, @byte_pointer - byte_size)
- else
- set_current_line(line, @byte_pointer)
- end
- end
- arg -= 1
- ed_delete_next_char(key, arg: arg) if arg > 0
- end
-
- private def vi_to_history_line(key)
- if Reline::HISTORY.empty?
- return
- end
- move_history(0, line: :start, cursor: :start)
- end
-
- private def vi_histedit(key)
- path = Tempfile.open { |fp|
- fp.write whole_lines.join("\n")
- fp.path
- }
- system("#{ENV['EDITOR']} #{path}")
- @buffer_of_lines = File.read(path).split("\n")
- @buffer_of_lines = [String.new(encoding: encoding)] if @buffer_of_lines.empty?
- @line_index = 0
- finish
- end
-
- private def vi_paste_prev(key, arg: 1)
- if @vi_clipboard.size > 0
- cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join
- set_current_line(byteinsert(current_line, @byte_pointer, @vi_clipboard), @byte_pointer + cursor_point.bytesize)
- end
- arg -= 1
- vi_paste_prev(key, arg: arg) if arg > 0
- end
-
- private def vi_paste_next(key, arg: 1)
- if @vi_clipboard.size > 0
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- line = byteinsert(current_line, @byte_pointer + byte_size, @vi_clipboard)
- set_current_line(line, @byte_pointer + @vi_clipboard.bytesize)
- end
- arg -= 1
- vi_paste_next(key, arg: arg) if arg > 0
- end
-
- private def ed_argument_digit(key)
- # key is expected to be `ESC digit` or `digit`
- num = key[/\d/].to_i
- @vi_arg = (@vi_arg || 0) * 10 + num
- end
-
- private def vi_to_column(key, arg: 0)
- # Implementing behavior of vi, not Readline's vi-mode.
- @byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |(total_byte_size, total_width), gc|
- mbchar_width = Reline::Unicode.get_mbchar_width(gc)
- break [total_byte_size, total_width] if (total_width + mbchar_width) >= arg
- [total_byte_size + gc.bytesize, total_width + mbchar_width]
- }
- end
-
- private def vi_replace_char(key, arg: 1)
- @waiting_proc = ->(k) {
- if arg == 1
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- before = current_line.byteslice(0, @byte_pointer)
- remaining_point = @byte_pointer + byte_size
- after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
- set_current_line(before + k + after)
- @waiting_proc = nil
- elsif arg > 1
- byte_size = 0
- arg.times do
- byte_size += Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer + byte_size)
- end
- before = current_line.byteslice(0, @byte_pointer)
- remaining_point = @byte_pointer + byte_size
- after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
- replaced = k * arg
- set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
- @waiting_proc = nil
- end
- }
- end
-
- private def vi_next_char(key, arg: 1, inclusive: false)
- @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, inclusive: inclusive) }
- end
-
- private def vi_to_next_char(key, arg: 1, inclusive: false)
- @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, need_prev_char: true, inclusive: inclusive) }
- end
-
- private def search_next_char(key, arg, need_prev_char: false, inclusive: false)
- prev_total = nil
- total = nil
- found = false
- current_line.byteslice(@byte_pointer..-1).grapheme_clusters.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 key == 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_prev_char and found and total
- byte_size, _ = total
- @byte_pointer += byte_size
- elsif need_prev_char and found and prev_total
- byte_size, _ = prev_total
- @byte_pointer += byte_size
- end
- if inclusive
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- if byte_size > 0
- @byte_pointer += byte_size
- end
- 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)
- prev_total = nil
- total = nil
- found = false
- current_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 key == 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, _ = total
- @byte_pointer -= byte_size
- elsif need_next_char and found and prev_total
- byte_size, _ = prev_total
- @byte_pointer -= byte_size
- end
- @waiting_proc = nil
- end
-
- private def vi_join_lines(key, arg: 1)
- if @buffer_of_lines.size > @line_index + 1
- next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
- set_current_line(current_line + ' ' + next_line, current_line.bytesize)
- end
- arg -= 1
- vi_join_lines(key, arg: arg) if arg > 0
- end
-
- private def em_set_mark(key)
- @mark_pointer = [@byte_pointer, @line_index]
- end
- alias_method :set_mark, :em_set_mark
-
- private def em_exchange_mark(key)
- return unless @mark_pointer
- new_pointer = [@byte_pointer, @line_index]
- @byte_pointer, @line_index = @mark_pointer
- @mark_pointer = new_pointer
- end
- alias_method :exchange_point_and_mark, :em_exchange_mark
-
- private def emacs_editing_mode(key)
- @config.editing_mode = :emacs
- end
-
- private def vi_editing_mode(key)
- @config.editing_mode = :vi_insert
- end
-
- private def move_undo_redo(direction)
- @restoring = true
- return unless (0..@input_lines.size - 1).cover?(@input_lines_position + direction)
-
- @input_lines_position += direction
- buffer_of_lines, byte_pointer, line_index = @input_lines[@input_lines_position]
- @buffer_of_lines = buffer_of_lines.dup
- @line_index = line_index
- @byte_pointer = byte_pointer
- end
-
- private def undo(_key)
- move_undo_redo(-1)
- end
-
- private def redo(_key)
- move_undo_redo(+1)
- end
-
- private def prev_action_state_value(type)
- @prev_action_state[0] == type ? @prev_action_state[1] : nil
- end
-
- private def set_next_action_state(type, value)
- @next_action_state = [type, value]
- end
-
- private def re_read_init_file(_key)
- @config.reload
- end
-end
diff --git a/lib/reline/reline.gemspec b/lib/reline/reline.gemspec
deleted file mode 100644
index dfaf966728..0000000000
--- a/lib/reline/reline.gemspec
+++ /dev/null
@@ -1,30 +0,0 @@
-
-begin
- require_relative 'lib/reline/version'
-rescue LoadError
- require_relative 'version'
-end
-
-Gem::Specification.new do |spec|
- spec.name = 'reline'
- spec.version = Reline::VERSION
- spec.authors = ['aycabta']
- spec.email = ['[email protected]']
-
- spec.summary = %q{Alternative GNU Readline or Editline implementation by pure Ruby.}
- spec.description = %q{Alternative GNU Readline or Editline implementation by pure Ruby.}
- spec.homepage = 'https://github.com/ruby/reline'
- spec.license = 'Ruby'
-
- spec.files = Dir['BSDL', 'COPYING', 'README.md', 'license_of_rb-readline', 'lib/**/*']
- spec.require_paths = ['lib']
- spec.metadata = {
- "bug_tracker_uri" => "https://github.com/ruby/reline/issues",
- "changelog_uri" => "https://github.com/ruby/reline/releases",
- "source_code_uri" => "https://github.com/ruby/reline"
- }
-
- spec.required_ruby_version = Gem::Requirement.new('>= 2.6')
-
- spec.add_dependency 'io-console', '~> 0.5'
-end
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
deleted file mode 100644
index 21e4ea240e..0000000000
--- a/lib/reline/unicode.rb
+++ /dev/null
@@ -1,415 +0,0 @@
-class Reline::Unicode
- EscapedPairs = {
- 0x00 => '^@',
- 0x01 => '^A', # C-a
- 0x02 => '^B',
- 0x03 => '^C',
- 0x04 => '^D',
- 0x05 => '^E',
- 0x06 => '^F',
- 0x07 => '^G',
- 0x08 => '^H', # Backspace
- 0x09 => '^I',
- 0x0A => '^J',
- 0x0B => '^K',
- 0x0C => '^L',
- 0x0D => '^M', # Enter
- 0x0E => '^N',
- 0x0F => '^O',
- 0x10 => '^P',
- 0x11 => '^Q',
- 0x12 => '^R',
- 0x13 => '^S',
- 0x14 => '^T',
- 0x15 => '^U',
- 0x16 => '^V',
- 0x17 => '^W',
- 0x18 => '^X',
- 0x19 => '^Y',
- 0x1A => '^Z', # C-z
- 0x1B => '^[', # C-[ C-3
- 0x1C => '^\\', # C-\
- 0x1D => '^]', # C-]
- 0x1E => '^^', # C-~ C-6
- 0x1F => '^_', # C-_ C-7
- 0x7F => '^?', # C-? C-8
- }
-
- NON_PRINTING_START = "\1"
- NON_PRINTING_END = "\2"
- CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/
- OSC_REGEXP = /\e\]\d+(?:;[^;\a\e]+)*(?:\a|\e\\)/
- WIDTH_SCANNER = /\G(?:(#{NON_PRINTING_START})|(#{NON_PRINTING_END})|(#{CSI_REGEXP})|(#{OSC_REGEXP})|(\X))/o
-
- def self.escape_for_print(str)
- str.chars.map! { |gr|
- case gr
- when -"\n"
- gr
- when -"\t"
- -' '
- else
- EscapedPairs[gr.ord] || gr
- end
- }.join
- end
-
- def self.safe_encode(str, encoding)
- # Reline only supports utf-8 convertible string.
- converted = str.encode(encoding, invalid: :replace, undef: :replace)
- return converted if str.encoding == Encoding::UTF_8 || converted.encoding == Encoding::UTF_8 || converted.ascii_only?
-
- # This code is essentially doing the same thing as
- # `str.encode(utf8, **replace_options).encode(encoding, **replace_options)`
- # but also avoids unnecessary irreversible encoding conversion.
- converted.gsub(/\X/) do |c|
- c.encode(Encoding::UTF_8)
- c
- rescue Encoding::UndefinedConversionError
- '?'
- end
- end
-
- require 'reline/unicode/east_asian_width'
-
- def self.get_mbchar_width(mbchar)
- ord = mbchar.ord
- if ord <= 0x1F # in EscapedPairs
- return 2
- elsif ord <= 0x7E # printable ASCII chars
- return 1
- end
- utf8_mbchar = mbchar.encode(Encoding::UTF_8)
- ord = utf8_mbchar.ord
- chunk_index = EastAsianWidth::CHUNK_LAST.bsearch_index { |o| ord <= o }
- size = EastAsianWidth::CHUNK_WIDTH[chunk_index]
- if size == -1
- Reline.ambiguous_width
- elsif size == 1 && utf8_mbchar.size >= 2
- second_char_ord = utf8_mbchar[1].ord
- # Halfwidth Dakuten Handakuten
- # Only these two character has Letter Modifier category and can be combined in a single grapheme cluster
- (second_char_ord == 0xFF9E || second_char_ord == 0xFF9F) ? 2 : 1
- else
- size
- end
- end
-
- def self.calculate_width(str, allow_escape_code = false)
- if allow_escape_code
- width = 0
- rest = str.encode(Encoding::UTF_8)
- in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
- case
- when non_printing_start
- in_zero_width = true
- when non_printing_end
- in_zero_width = false
- when csi, osc
- when gc
- unless in_zero_width
- width += get_mbchar_width(gc)
- end
- end
- end
- width
- else
- str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc|
- w + get_mbchar_width(gc)
- }
- end
- end
-
- # This method is used by IRB
- def self.split_by_width(str, max_width)
- lines = split_line_by_width(str, max_width)
- [lines, lines.size]
- end
-
- def self.split_line_by_width(str, max_width, encoding = str.encoding, offset: 0)
- lines = [String.new(encoding: encoding)]
- width = offset
- rest = str.encode(Encoding::UTF_8)
- in_zero_width = false
- seq = String.new(encoding: encoding)
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
- case
- when non_printing_start
- in_zero_width = true
- when non_printing_end
- in_zero_width = false
- when csi
- lines.last << csi
- unless in_zero_width
- if csi == -"\e[m" || csi == -"\e[0m"
- seq.clear
- else
- seq << csi
- end
- end
- when osc
- lines.last << osc
- seq << osc unless in_zero_width
- when gc
- unless in_zero_width
- mbchar_width = get_mbchar_width(gc)
- if (width += mbchar_width) > max_width
- width = mbchar_width
- lines << seq.dup
- end
- end
- lines.last << gc
- end
- end
- # The cursor moves to next line in first
- if width == max_width
- lines << String.new(encoding: encoding)
- end
- lines
- end
-
- def self.strip_non_printing_start_end(prompt)
- prompt.gsub(/\x01([^\x02]*)(?:\x02|\z)/) { $1 }
- end
-
- # Take a chunk of a String cut by width with escape sequences.
- def self.take_range(str, start_col, max_width)
- take_mbchar_range(str, start_col, max_width).first
- end
-
- def self.take_mbchar_range(str, start_col, width, cover_begin: false, cover_end: false, padding: false)
- chunk = String.new(encoding: str.encoding)
-
- end_col = start_col + width
- total_width = 0
- rest = str.encode(Encoding::UTF_8)
- in_zero_width = false
- chunk_start_col = nil
- chunk_end_col = nil
- has_csi = false
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
- case
- when non_printing_start
- in_zero_width = true
- when non_printing_end
- in_zero_width = false
- when csi
- has_csi = true
- chunk << csi
- when osc
- chunk << osc
- when gc
- if in_zero_width
- chunk << gc
- next
- end
-
- mbchar_width = get_mbchar_width(gc)
- prev_width = total_width
- total_width += mbchar_width
-
- if (cover_begin || padding ? total_width <= start_col : prev_width < start_col)
- # Current character haven't reached start_col yet
- next
- elsif padding && !cover_begin && prev_width < start_col && start_col < total_width
- # Add preceding padding. This padding might have background color.
- chunk << ' '
- chunk_start_col ||= start_col
- chunk_end_col = total_width
- next
- elsif (cover_end ? prev_width < end_col : total_width <= end_col)
- # Current character is in the range
- chunk << gc
- chunk_start_col ||= prev_width
- chunk_end_col = total_width
- break if total_width >= end_col
- else
- # Current character exceeds end_col
- if padding && end_col < total_width
- # Add succeeding padding. This padding might have background color.
- chunk << ' '
- chunk_start_col ||= prev_width
- chunk_end_col = end_col
- end
- break
- end
- end
- end
- chunk_start_col ||= start_col
- chunk_end_col ||= start_col
- if padding && chunk_end_col < end_col
- # Append padding. This padding should not include background color.
- chunk << "\e[0m" if has_csi
- chunk << ' ' * (end_col - chunk_end_col)
- chunk_end_col = end_col
- end
- [chunk, chunk_start_col, chunk_end_col - chunk_start_col]
- end
-
- def self.get_next_mbchar_size(line, byte_pointer)
- grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
- grapheme ? grapheme.bytesize : 0
- end
-
- def self.get_prev_mbchar_size(line, byte_pointer)
- if byte_pointer.zero?
- 0
- else
- grapheme = line.byteslice(0..(byte_pointer - 1)).grapheme_clusters.last
- grapheme ? grapheme.bytesize : 0
- end
- end
-
- def self.em_forward_word(line, byte_pointer)
- gcs = line.byteslice(byte_pointer..).grapheme_clusters
- nonwords = gcs.take_while { |c| !word_character?(c) }
- words = gcs.drop(nonwords.size).take_while { |c| word_character?(c) }
- nonwords.sum(&:bytesize) + words.sum(&:bytesize)
- end
-
- def self.em_forward_word_with_capitalization(line, byte_pointer)
- gcs = line.byteslice(byte_pointer..).grapheme_clusters
- nonwords = gcs.take_while { |c| !word_character?(c) }
- words = gcs.drop(nonwords.size).take_while { |c| word_character?(c) }
- [nonwords.sum(&:bytesize) + words.sum(&:bytesize), nonwords.join + words.join.capitalize]
- end
-
- def self.em_backward_word(line, byte_pointer)
- gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
- nonwords = gcs.take_while { |c| !word_character?(c) }
- words = gcs.drop(nonwords.size).take_while { |c| word_character?(c) }
- nonwords.sum(&:bytesize) + words.sum(&:bytesize)
- end
-
- def self.em_big_backward_word(line, byte_pointer)
- gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
- spaces = gcs.take_while { |c| space_character?(c) }
- nonspaces = gcs.drop(spaces.size).take_while { |c| !space_character?(c) }
- spaces.sum(&:bytesize) + nonspaces.sum(&:bytesize)
- end
-
- def self.ed_transpose_words(line, byte_pointer)
- gcs = line.byteslice(0, byte_pointer).grapheme_clusters
- pos = gcs.size
- gcs += line.byteslice(byte_pointer..).grapheme_clusters
- pos += 1 while pos < gcs.size && !word_character?(gcs[pos])
- if pos == gcs.size # 'aaa bbb [cursor] '
- pos -= 1 while pos > 0 && !word_character?(gcs[pos - 1])
- second_word_end = gcs.size
- else # 'aaa [cursor]bbb'
- pos += 1 while pos < gcs.size && word_character?(gcs[pos])
- second_word_end = pos
- end
- pos -= 1 while pos > 0 && word_character?(gcs[pos - 1])
- second_word_start = pos
- pos -= 1 while pos > 0 && !word_character?(gcs[pos - 1])
- first_word_end = pos
- pos -= 1 while pos > 0 && word_character?(gcs[pos - 1])
- first_word_start = pos
-
- [first_word_start, first_word_end, second_word_start, second_word_end].map do |idx|
- gcs.take(idx).sum(&:bytesize)
- end
- end
-
- def self.vi_big_forward_word(line, byte_pointer)
- gcs = line.byteslice(byte_pointer..).grapheme_clusters
- nonspaces = gcs.take_while { |c| !space_character?(c) }
- spaces = gcs.drop(nonspaces.size).take_while { |c| space_character?(c) }
- nonspaces.sum(&:bytesize) + spaces.sum(&:bytesize)
- end
-
- def self.vi_big_forward_end_word(line, byte_pointer)
- gcs = line.byteslice(byte_pointer..).grapheme_clusters
- first = gcs.shift(1)
- spaces = gcs.take_while { |c| space_character?(c) }
- nonspaces = gcs.drop(spaces.size).take_while { |c| !space_character?(c) }
- matched = spaces + nonspaces
- matched.pop
- first.sum(&:bytesize) + matched.sum(&:bytesize)
- end
-
- def self.vi_big_backward_word(line, byte_pointer)
- gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
- spaces = gcs.take_while { |c| space_character?(c) }
- nonspaces = gcs.drop(spaces.size).take_while { |c| !space_character?(c) }
- spaces.sum(&:bytesize) + nonspaces.sum(&:bytesize)
- end
-
- def self.vi_forward_word(line, byte_pointer, drop_terminate_spaces = false)
- gcs = line.byteslice(byte_pointer..).grapheme_clusters
- return 0 if gcs.empty?
-
- c = gcs.first
- matched =
- if word_character?(c)
- gcs.take_while { |c| word_character?(c) }
- elsif space_character?(c)
- gcs.take_while { |c| space_character?(c) }
- else
- gcs.take_while { |c| !word_character?(c) && !space_character?(c) }
- end
-
- return matched.sum(&:bytesize) if drop_terminate_spaces
-
- spaces = gcs.drop(matched.size).take_while { |c| space_character?(c) }
- matched.sum(&:bytesize) + spaces.sum(&:bytesize)
- end
-
- def self.vi_forward_end_word(line, byte_pointer)
- gcs = line.byteslice(byte_pointer..).grapheme_clusters
- return 0 if gcs.empty?
- return gcs.first.bytesize if gcs.size == 1
-
- start = gcs.shift
- skips = [start]
- if space_character?(start) || space_character?(gcs.first)
- spaces = gcs.take_while { |c| space_character?(c) }
- skips += spaces
- gcs.shift(spaces.size)
- end
- start_with_word = word_character?(gcs.first)
- matched = gcs.take_while { |c| start_with_word ? word_character?(c) : !word_character?(c) && !space_character?(c) }
- matched.pop
- skips.sum(&:bytesize) + matched.sum(&:bytesize)
- end
-
- def self.vi_backward_word(line, byte_pointer)
- gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
- spaces = gcs.take_while { |c| space_character?(c) }
- gcs.shift(spaces.size)
- start_with_word = word_character?(gcs.first)
- matched = gcs.take_while { |c| start_with_word ? word_character?(c) : !word_character?(c) && !space_character?(c) }
- spaces.sum(&:bytesize) + matched.sum(&:bytesize)
- end
-
- def self.common_prefix(list, ignore_case: false)
- return '' if list.empty?
-
- common_prefix_gcs = list.first.grapheme_clusters
- list.each do |item|
- gcs = item.grapheme_clusters
- common_prefix_gcs = common_prefix_gcs.take_while.with_index do |gc, i|
- ignore_case ? gc.casecmp?(gcs[i]) : gc == gcs[i]
- end
- end
- common_prefix_gcs.join
- end
-
- def self.vi_first_print(line)
- gcs = line.grapheme_clusters
- spaces = gcs.take_while { |c| space_character?(c) }
- spaces.sum(&:bytesize)
- end
-
- def self.word_character?(s)
- s.encode(Encoding::UTF_8).match?(/\p{Word}/) if s
- rescue Encoding::UndefinedConversionError
- false
- end
-
- def self.space_character?(s)
- s.match?(/\s/) if s
- end
-end
diff --git a/lib/reline/unicode/east_asian_width.rb b/lib/reline/unicode/east_asian_width.rb
deleted file mode 100644
index 9c5e42e239..0000000000
--- a/lib/reline/unicode/east_asian_width.rb
+++ /dev/null
@@ -1,1293 +0,0 @@
-class Reline::Unicode::EastAsianWidth
- # This is based on EastAsianWidth.txt
- # UNICODE_VERSION = '16.0.0'
-
- CHUNK_LAST, CHUNK_WIDTH = [
- [0x1f, 2],
- [0x7e, 1],
- [0x7f, 2],
- [0xa0, 1],
- [0xa1, -1],
- [0xa3, 1],
- [0xa4, -1],
- [0xa6, 1],
- [0xa8, -1],
- [0xa9, 1],
- [0xaa, -1],
- [0xac, 1],
- [0xae, -1],
- [0xaf, 1],
- [0xb4, -1],
- [0xb5, 1],
- [0xba, -1],
- [0xbb, 1],
- [0xbf, -1],
- [0xc5, 1],
- [0xc6, -1],
- [0xcf, 1],
- [0xd0, -1],
- [0xd6, 1],
- [0xd8, -1],
- [0xdd, 1],
- [0xe1, -1],
- [0xe5, 1],
- [0xe6, -1],
- [0xe7, 1],
- [0xea, -1],
- [0xeb, 1],
- [0xed, -1],
- [0xef, 1],
- [0xf0, -1],
- [0xf1, 1],
- [0xf3, -1],
- [0xf6, 1],
- [0xfa, -1],
- [0xfb, 1],
- [0xfc, -1],
- [0xfd, 1],
- [0xfe, -1],
- [0x100, 1],
- [0x101, -1],
- [0x110, 1],
- [0x111, -1],
- [0x112, 1],
- [0x113, -1],
- [0x11a, 1],
- [0x11b, -1],
- [0x125, 1],
- [0x127, -1],
- [0x12a, 1],
- [0x12b, -1],
- [0x130, 1],
- [0x133, -1],
- [0x137, 1],
- [0x138, -1],
- [0x13e, 1],
- [0x142, -1],
- [0x143, 1],
- [0x144, -1],
- [0x147, 1],
- [0x14b, -1],
- [0x14c, 1],
- [0x14d, -1],
- [0x151, 1],
- [0x153, -1],
- [0x165, 1],
- [0x167, -1],
- [0x16a, 1],
- [0x16b, -1],
- [0x1cd, 1],
- [0x1ce, -1],
- [0x1cf, 1],
- [0x1d0, -1],
- [0x1d1, 1],
- [0x1d2, -1],
- [0x1d3, 1],
- [0x1d4, -1],
- [0x1d5, 1],
- [0x1d6, -1],
- [0x1d7, 1],
- [0x1d8, -1],
- [0x1d9, 1],
- [0x1da, -1],
- [0x1db, 1],
- [0x1dc, -1],
- [0x250, 1],
- [0x251, -1],
- [0x260, 1],
- [0x261, -1],
- [0x2c3, 1],
- [0x2c4, -1],
- [0x2c6, 1],
- [0x2c7, -1],
- [0x2c8, 1],
- [0x2cb, -1],
- [0x2cc, 1],
- [0x2cd, -1],
- [0x2cf, 1],
- [0x2d0, -1],
- [0x2d7, 1],
- [0x2db, -1],
- [0x2dc, 1],
- [0x2dd, -1],
- [0x2de, 1],
- [0x2df, -1],
- [0x2ff, 1],
- [0x36f, 0],
- [0x390, 1],
- [0x3a1, -1],
- [0x3a2, 1],
- [0x3a9, -1],
- [0x3b0, 1],
- [0x3c1, -1],
- [0x3c2, 1],
- [0x3c9, -1],
- [0x400, 1],
- [0x401, -1],
- [0x40f, 1],
- [0x44f, -1],
- [0x450, 1],
- [0x451, -1],
- [0x482, 1],
- [0x487, 0],
- [0x590, 1],
- [0x5bd, 0],
- [0x5be, 1],
- [0x5bf, 0],
- [0x5c0, 1],
- [0x5c2, 0],
- [0x5c3, 1],
- [0x5c5, 0],
- [0x5c6, 1],
- [0x5c7, 0],
- [0x60f, 1],
- [0x61a, 0],
- [0x64a, 1],
- [0x65f, 0],
- [0x66f, 1],
- [0x670, 0],
- [0x6d5, 1],
- [0x6dc, 0],
- [0x6de, 1],
- [0x6e4, 0],
- [0x6e6, 1],
- [0x6e8, 0],
- [0x6e9, 1],
- [0x6ed, 0],
- [0x710, 1],
- [0x711, 0],
- [0x72f, 1],
- [0x74a, 0],
- [0x7a5, 1],
- [0x7b0, 0],
- [0x7ea, 1],
- [0x7f3, 0],
- [0x7fc, 1],
- [0x7fd, 0],
- [0x815, 1],
- [0x819, 0],
- [0x81a, 1],
- [0x823, 0],
- [0x824, 1],
- [0x827, 0],
- [0x828, 1],
- [0x82d, 0],
- [0x858, 1],
- [0x85b, 0],
- [0x896, 1],
- [0x89f, 0],
- [0x8c9, 1],
- [0x8e1, 0],
- [0x8e2, 1],
- [0x902, 0],
- [0x939, 1],
- [0x93a, 0],
- [0x93b, 1],
- [0x93c, 0],
- [0x940, 1],
- [0x948, 0],
- [0x94c, 1],
- [0x94d, 0],
- [0x950, 1],
- [0x957, 0],
- [0x961, 1],
- [0x963, 0],
- [0x980, 1],
- [0x981, 0],
- [0x9bb, 1],
- [0x9bc, 0],
- [0x9c0, 1],
- [0x9c4, 0],
- [0x9cc, 1],
- [0x9cd, 0],
- [0x9e1, 1],
- [0x9e3, 0],
- [0x9fd, 1],
- [0x9fe, 0],
- [0xa00, 1],
- [0xa02, 0],
- [0xa3b, 1],
- [0xa3c, 0],
- [0xa40, 1],
- [0xa42, 0],
- [0xa46, 1],
- [0xa48, 0],
- [0xa4a, 1],
- [0xa4d, 0],
- [0xa50, 1],
- [0xa51, 0],
- [0xa6f, 1],
- [0xa71, 0],
- [0xa74, 1],
- [0xa75, 0],
- [0xa80, 1],
- [0xa82, 0],
- [0xabb, 1],
- [0xabc, 0],
- [0xac0, 1],
- [0xac5, 0],
- [0xac6, 1],
- [0xac8, 0],
- [0xacc, 1],
- [0xacd, 0],
- [0xae1, 1],
- [0xae3, 0],
- [0xaf9, 1],
- [0xaff, 0],
- [0xb00, 1],
- [0xb01, 0],
- [0xb3b, 1],
- [0xb3c, 0],
- [0xb3e, 1],
- [0xb3f, 0],
- [0xb40, 1],
- [0xb44, 0],
- [0xb4c, 1],
- [0xb4d, 0],
- [0xb54, 1],
- [0xb56, 0],
- [0xb61, 1],
- [0xb63, 0],
- [0xb81, 1],
- [0xb82, 0],
- [0xbbf, 1],
- [0xbc0, 0],
- [0xbcc, 1],
- [0xbcd, 0],
- [0xbff, 1],
- [0xc00, 0],
- [0xc03, 1],
- [0xc04, 0],
- [0xc3b, 1],
- [0xc3c, 0],
- [0xc3d, 1],
- [0xc40, 0],
- [0xc45, 1],
- [0xc48, 0],
- [0xc49, 1],
- [0xc4d, 0],
- [0xc54, 1],
- [0xc56, 0],
- [0xc61, 1],
- [0xc63, 0],
- [0xc80, 1],
- [0xc81, 0],
- [0xcbb, 1],
- [0xcbc, 0],
- [0xcbe, 1],
- [0xcbf, 0],
- [0xcc5, 1],
- [0xcc6, 0],
- [0xccb, 1],
- [0xccd, 0],
- [0xce1, 1],
- [0xce3, 0],
- [0xcff, 1],
- [0xd01, 0],
- [0xd3a, 1],
- [0xd3c, 0],
- [0xd40, 1],
- [0xd44, 0],
- [0xd4c, 1],
- [0xd4d, 0],
- [0xd61, 1],
- [0xd63, 0],
- [0xd80, 1],
- [0xd81, 0],
- [0xdc9, 1],
- [0xdca, 0],
- [0xdd1, 1],
- [0xdd4, 0],
- [0xdd5, 1],
- [0xdd6, 0],
- [0xe30, 1],
- [0xe31, 0],
- [0xe33, 1],
- [0xe3a, 0],
- [0xe46, 1],
- [0xe4e, 0],
- [0xeb0, 1],
- [0xeb1, 0],
- [0xeb3, 1],
- [0xebc, 0],
- [0xec7, 1],
- [0xece, 0],
- [0xf17, 1],
- [0xf19, 0],
- [0xf34, 1],
- [0xf35, 0],
- [0xf36, 1],
- [0xf37, 0],
- [0xf38, 1],
- [0xf39, 0],
- [0xf70, 1],
- [0xf7e, 0],
- [0xf7f, 1],
- [0xf84, 0],
- [0xf85, 1],
- [0xf87, 0],
- [0xf8c, 1],
- [0xf97, 0],
- [0xf98, 1],
- [0xfbc, 0],
- [0xfc5, 1],
- [0xfc6, 0],
- [0x102c, 1],
- [0x1030, 0],
- [0x1031, 1],
- [0x1037, 0],
- [0x1038, 1],
- [0x103a, 0],
- [0x103c, 1],
- [0x103e, 0],
- [0x1057, 1],
- [0x1059, 0],
- [0x105d, 1],
- [0x1060, 0],
- [0x1070, 1],
- [0x1074, 0],
- [0x1081, 1],
- [0x1082, 0],
- [0x1084, 1],
- [0x1086, 0],
- [0x108c, 1],
- [0x108d, 0],
- [0x109c, 1],
- [0x109d, 0],
- [0x10ff, 1],
- [0x115f, 2],
- [0x135c, 1],
- [0x135f, 0],
- [0x1711, 1],
- [0x1714, 0],
- [0x1731, 1],
- [0x1733, 0],
- [0x1751, 1],
- [0x1753, 0],
- [0x1771, 1],
- [0x1773, 0],
- [0x17b3, 1],
- [0x17b5, 0],
- [0x17b6, 1],
- [0x17bd, 0],
- [0x17c5, 1],
- [0x17c6, 0],
- [0x17c8, 1],
- [0x17d3, 0],
- [0x17dc, 1],
- [0x17dd, 0],
- [0x180a, 1],
- [0x180d, 0],
- [0x180e, 1],
- [0x180f, 0],
- [0x1884, 1],
- [0x1886, 0],
- [0x18a8, 1],
- [0x18a9, 0],
- [0x191f, 1],
- [0x1922, 0],
- [0x1926, 1],
- [0x1928, 0],
- [0x1931, 1],
- [0x1932, 0],
- [0x1938, 1],
- [0x193b, 0],
- [0x1a16, 1],
- [0x1a18, 0],
- [0x1a1a, 1],
- [0x1a1b, 0],
- [0x1a55, 1],
- [0x1a56, 0],
- [0x1a57, 1],
- [0x1a5e, 0],
- [0x1a5f, 1],
- [0x1a60, 0],
- [0x1a61, 1],
- [0x1a62, 0],
- [0x1a64, 1],
- [0x1a6c, 0],
- [0x1a72, 1],
- [0x1a7c, 0],
- [0x1a7e, 1],
- [0x1a7f, 0],
- [0x1aaf, 1],
- [0x1abd, 0],
- [0x1abe, 1],
- [0x1ace, 0],
- [0x1aff, 1],
- [0x1b03, 0],
- [0x1b33, 1],
- [0x1b34, 0],
- [0x1b35, 1],
- [0x1b3a, 0],
- [0x1b3b, 1],
- [0x1b3c, 0],
- [0x1b41, 1],
- [0x1b42, 0],
- [0x1b6a, 1],
- [0x1b73, 0],
- [0x1b7f, 1],
- [0x1b81, 0],
- [0x1ba1, 1],
- [0x1ba5, 0],
- [0x1ba7, 1],
- [0x1ba9, 0],
- [0x1baa, 1],
- [0x1bad, 0],
- [0x1be5, 1],
- [0x1be6, 0],
- [0x1be7, 1],
- [0x1be9, 0],
- [0x1bec, 1],
- [0x1bed, 0],
- [0x1bee, 1],
- [0x1bf1, 0],
- [0x1c2b, 1],
- [0x1c33, 0],
- [0x1c35, 1],
- [0x1c37, 0],
- [0x1ccf, 1],
- [0x1cd2, 0],
- [0x1cd3, 1],
- [0x1ce0, 0],
- [0x1ce1, 1],
- [0x1ce8, 0],
- [0x1cec, 1],
- [0x1ced, 0],
- [0x1cf3, 1],
- [0x1cf4, 0],
- [0x1cf7, 1],
- [0x1cf9, 0],
- [0x1dbf, 1],
- [0x1dff, 0],
- [0x200f, 1],
- [0x2010, -1],
- [0x2012, 1],
- [0x2016, -1],
- [0x2017, 1],
- [0x2019, -1],
- [0x201b, 1],
- [0x201d, -1],
- [0x201f, 1],
- [0x2022, -1],
- [0x2023, 1],
- [0x2027, -1],
- [0x202f, 1],
- [0x2030, -1],
- [0x2031, 1],
- [0x2033, -1],
- [0x2034, 1],
- [0x2035, -1],
- [0x203a, 1],
- [0x203b, -1],
- [0x203d, 1],
- [0x203e, -1],
- [0x2073, 1],
- [0x2074, -1],
- [0x207e, 1],
- [0x207f, -1],
- [0x2080, 1],
- [0x2084, -1],
- [0x20ab, 1],
- [0x20ac, -1],
- [0x20cf, 1],
- [0x20dc, 0],
- [0x20e0, 1],
- [0x20e1, 0],
- [0x20e4, 1],
- [0x20f0, 0],
- [0x2102, 1],
- [0x2103, -1],
- [0x2104, 1],
- [0x2105, -1],
- [0x2108, 1],
- [0x2109, -1],
- [0x2112, 1],
- [0x2113, -1],
- [0x2115, 1],
- [0x2116, -1],
- [0x2120, 1],
- [0x2122, -1],
- [0x2125, 1],
- [0x2126, -1],
- [0x212a, 1],
- [0x212b, -1],
- [0x2152, 1],
- [0x2154, -1],
- [0x215a, 1],
- [0x215e, -1],
- [0x215f, 1],
- [0x216b, -1],
- [0x216f, 1],
- [0x2179, -1],
- [0x2188, 1],
- [0x2189, -1],
- [0x218f, 1],
- [0x2199, -1],
- [0x21b7, 1],
- [0x21b9, -1],
- [0x21d1, 1],
- [0x21d2, -1],
- [0x21d3, 1],
- [0x21d4, -1],
- [0x21e6, 1],
- [0x21e7, -1],
- [0x21ff, 1],
- [0x2200, -1],
- [0x2201, 1],
- [0x2203, -1],
- [0x2206, 1],
- [0x2208, -1],
- [0x220a, 1],
- [0x220b, -1],
- [0x220e, 1],
- [0x220f, -1],
- [0x2210, 1],
- [0x2211, -1],
- [0x2214, 1],
- [0x2215, -1],
- [0x2219, 1],
- [0x221a, -1],
- [0x221c, 1],
- [0x2220, -1],
- [0x2222, 1],
- [0x2223, -1],
- [0x2224, 1],
- [0x2225, -1],
- [0x2226, 1],
- [0x222c, -1],
- [0x222d, 1],
- [0x222e, -1],
- [0x2233, 1],
- [0x2237, -1],
- [0x223b, 1],
- [0x223d, -1],
- [0x2247, 1],
- [0x2248, -1],
- [0x224b, 1],
- [0x224c, -1],
- [0x2251, 1],
- [0x2252, -1],
- [0x225f, 1],
- [0x2261, -1],
- [0x2263, 1],
- [0x2267, -1],
- [0x2269, 1],
- [0x226b, -1],
- [0x226d, 1],
- [0x226f, -1],
- [0x2281, 1],
- [0x2283, -1],
- [0x2285, 1],
- [0x2287, -1],
- [0x2294, 1],
- [0x2295, -1],
- [0x2298, 1],
- [0x2299, -1],
- [0x22a4, 1],
- [0x22a5, -1],
- [0x22be, 1],
- [0x22bf, -1],
- [0x2311, 1],
- [0x2312, -1],
- [0x2319, 1],
- [0x231b, 2],
- [0x2328, 1],
- [0x232a, 2],
- [0x23e8, 1],
- [0x23ec, 2],
- [0x23ef, 1],
- [0x23f0, 2],
- [0x23f2, 1],
- [0x23f3, 2],
- [0x245f, 1],
- [0x24e9, -1],
- [0x24ea, 1],
- [0x254b, -1],
- [0x254f, 1],
- [0x2573, -1],
- [0x257f, 1],
- [0x258f, -1],
- [0x2591, 1],
- [0x2595, -1],
- [0x259f, 1],
- [0x25a1, -1],
- [0x25a2, 1],
- [0x25a9, -1],
- [0x25b1, 1],
- [0x25b3, -1],
- [0x25b5, 1],
- [0x25b7, -1],
- [0x25bb, 1],
- [0x25bd, -1],
- [0x25bf, 1],
- [0x25c1, -1],
- [0x25c5, 1],
- [0x25c8, -1],
- [0x25ca, 1],
- [0x25cb, -1],
- [0x25cd, 1],
- [0x25d1, -1],
- [0x25e1, 1],
- [0x25e5, -1],
- [0x25ee, 1],
- [0x25ef, -1],
- [0x25fc, 1],
- [0x25fe, 2],
- [0x2604, 1],
- [0x2606, -1],
- [0x2608, 1],
- [0x2609, -1],
- [0x260d, 1],
- [0x260f, -1],
- [0x2613, 1],
- [0x2615, 2],
- [0x261b, 1],
- [0x261c, -1],
- [0x261d, 1],
- [0x261e, -1],
- [0x262f, 1],
- [0x2637, 2],
- [0x263f, 1],
- [0x2640, -1],
- [0x2641, 1],
- [0x2642, -1],
- [0x2647, 1],
- [0x2653, 2],
- [0x265f, 1],
- [0x2661, -1],
- [0x2662, 1],
- [0x2665, -1],
- [0x2666, 1],
- [0x266a, -1],
- [0x266b, 1],
- [0x266d, -1],
- [0x266e, 1],
- [0x266f, -1],
- [0x267e, 1],
- [0x267f, 2],
- [0x2689, 1],
- [0x268f, 2],
- [0x2692, 1],
- [0x2693, 2],
- [0x269d, 1],
- [0x269f, -1],
- [0x26a0, 1],
- [0x26a1, 2],
- [0x26a9, 1],
- [0x26ab, 2],
- [0x26bc, 1],
- [0x26be, 2],
- [0x26bf, -1],
- [0x26c3, 1],
- [0x26c5, 2],
- [0x26cd, -1],
- [0x26ce, 2],
- [0x26d3, -1],
- [0x26d4, 2],
- [0x26e1, -1],
- [0x26e2, 1],
- [0x26e3, -1],
- [0x26e7, 1],
- [0x26e9, -1],
- [0x26ea, 2],
- [0x26f1, -1],
- [0x26f3, 2],
- [0x26f4, -1],
- [0x26f5, 2],
- [0x26f9, -1],
- [0x26fa, 2],
- [0x26fc, -1],
- [0x26fd, 2],
- [0x26ff, -1],
- [0x2704, 1],
- [0x2705, 2],
- [0x2709, 1],
- [0x270b, 2],
- [0x2727, 1],
- [0x2728, 2],
- [0x273c, 1],
- [0x273d, -1],
- [0x274b, 1],
- [0x274c, 2],
- [0x274d, 1],
- [0x274e, 2],
- [0x2752, 1],
- [0x2755, 2],
- [0x2756, 1],
- [0x2757, 2],
- [0x2775, 1],
- [0x277f, -1],
- [0x2794, 1],
- [0x2797, 2],
- [0x27af, 1],
- [0x27b0, 2],
- [0x27be, 1],
- [0x27bf, 2],
- [0x2b1a, 1],
- [0x2b1c, 2],
- [0x2b4f, 1],
- [0x2b50, 2],
- [0x2b54, 1],
- [0x2b55, 2],
- [0x2b59, -1],
- [0x2cee, 1],
- [0x2cf1, 0],
- [0x2d7e, 1],
- [0x2d7f, 0],
- [0x2ddf, 1],
- [0x2dff, 0],
- [0x2e7f, 1],
- [0x2e99, 2],
- [0x2e9a, 1],
- [0x2ef3, 2],
- [0x2eff, 1],
- [0x2fd5, 2],
- [0x2fef, 1],
- [0x3029, 2],
- [0x302d, 0],
- [0x303e, 2],
- [0x3040, 1],
- [0x3096, 2],
- [0x3098, 1],
- [0x309a, 0],
- [0x30ff, 2],
- [0x3104, 1],
- [0x312f, 2],
- [0x3130, 1],
- [0x318e, 2],
- [0x318f, 1],
- [0x31e5, 2],
- [0x31ee, 1],
- [0x321e, 2],
- [0x321f, 1],
- [0x3247, 2],
- [0x324f, -1],
- [0xa48c, 2],
- [0xa48f, 1],
- [0xa4c6, 2],
- [0xa66e, 1],
- [0xa66f, 0],
- [0xa673, 1],
- [0xa67d, 0],
- [0xa69d, 1],
- [0xa69f, 0],
- [0xa6ef, 1],
- [0xa6f1, 0],
- [0xa801, 1],
- [0xa802, 0],
- [0xa805, 1],
- [0xa806, 0],
- [0xa80a, 1],
- [0xa80b, 0],
- [0xa824, 1],
- [0xa826, 0],
- [0xa82b, 1],
- [0xa82c, 0],
- [0xa8c3, 1],
- [0xa8c5, 0],
- [0xa8df, 1],
- [0xa8f1, 0],
- [0xa8fe, 1],
- [0xa8ff, 0],
- [0xa925, 1],
- [0xa92d, 0],
- [0xa946, 1],
- [0xa951, 0],
- [0xa95f, 1],
- [0xa97c, 2],
- [0xa97f, 1],
- [0xa982, 0],
- [0xa9b2, 1],
- [0xa9b3, 0],
- [0xa9b5, 1],
- [0xa9b9, 0],
- [0xa9bb, 1],
- [0xa9bd, 0],
- [0xa9e4, 1],
- [0xa9e5, 0],
- [0xaa28, 1],
- [0xaa2e, 0],
- [0xaa30, 1],
- [0xaa32, 0],
- [0xaa34, 1],
- [0xaa36, 0],
- [0xaa42, 1],
- [0xaa43, 0],
- [0xaa4b, 1],
- [0xaa4c, 0],
- [0xaa7b, 1],
- [0xaa7c, 0],
- [0xaaaf, 1],
- [0xaab0, 0],
- [0xaab1, 1],
- [0xaab4, 0],
- [0xaab6, 1],
- [0xaab8, 0],
- [0xaabd, 1],
- [0xaabf, 0],
- [0xaac0, 1],
- [0xaac1, 0],
- [0xaaeb, 1],
- [0xaaed, 0],
- [0xaaf5, 1],
- [0xaaf6, 0],
- [0xabe4, 1],
- [0xabe5, 0],
- [0xabe7, 1],
- [0xabe8, 0],
- [0xabec, 1],
- [0xabed, 0],
- [0xabff, 1],
- [0xd7a3, 2],
- [0xdfff, 1],
- [0xf8ff, -1],
- [0xfaff, 2],
- [0xfb1d, 1],
- [0xfb1e, 0],
- [0xfdff, 1],
- [0xfe0f, 0],
- [0xfe19, 2],
- [0xfe1f, 1],
- [0xfe2f, 0],
- [0xfe52, 2],
- [0xfe53, 1],
- [0xfe66, 2],
- [0xfe67, 1],
- [0xfe6b, 2],
- [0xff00, 1],
- [0xff60, 2],
- [0xffdf, 1],
- [0xffe6, 2],
- [0xfffc, 1],
- [0xfffd, -1],
- [0x101fc, 1],
- [0x101fd, 0],
- [0x102df, 1],
- [0x102e0, 0],
- [0x10375, 1],
- [0x1037a, 0],
- [0x10a00, 1],
- [0x10a03, 0],
- [0x10a04, 1],
- [0x10a06, 0],
- [0x10a0b, 1],
- [0x10a0f, 0],
- [0x10a37, 1],
- [0x10a3a, 0],
- [0x10a3e, 1],
- [0x10a3f, 0],
- [0x10ae4, 1],
- [0x10ae6, 0],
- [0x10d23, 1],
- [0x10d27, 0],
- [0x10d68, 1],
- [0x10d6d, 0],
- [0x10eaa, 1],
- [0x10eac, 0],
- [0x10efb, 1],
- [0x10eff, 0],
- [0x10f45, 1],
- [0x10f50, 0],
- [0x10f81, 1],
- [0x10f85, 0],
- [0x11000, 1],
- [0x11001, 0],
- [0x11037, 1],
- [0x11046, 0],
- [0x1106f, 1],
- [0x11070, 0],
- [0x11072, 1],
- [0x11074, 0],
- [0x1107e, 1],
- [0x11081, 0],
- [0x110b2, 1],
- [0x110b6, 0],
- [0x110b8, 1],
- [0x110ba, 0],
- [0x110c1, 1],
- [0x110c2, 0],
- [0x110ff, 1],
- [0x11102, 0],
- [0x11126, 1],
- [0x1112b, 0],
- [0x1112c, 1],
- [0x11134, 0],
- [0x11172, 1],
- [0x11173, 0],
- [0x1117f, 1],
- [0x11181, 0],
- [0x111b5, 1],
- [0x111be, 0],
- [0x111c8, 1],
- [0x111cc, 0],
- [0x111ce, 1],
- [0x111cf, 0],
- [0x1122e, 1],
- [0x11231, 0],
- [0x11233, 1],
- [0x11234, 0],
- [0x11235, 1],
- [0x11237, 0],
- [0x1123d, 1],
- [0x1123e, 0],
- [0x11240, 1],
- [0x11241, 0],
- [0x112de, 1],
- [0x112df, 0],
- [0x112e2, 1],
- [0x112ea, 0],
- [0x112ff, 1],
- [0x11301, 0],
- [0x1133a, 1],
- [0x1133c, 0],
- [0x1133f, 1],
- [0x11340, 0],
- [0x11365, 1],
- [0x1136c, 0],
- [0x1136f, 1],
- [0x11374, 0],
- [0x113ba, 1],
- [0x113c0, 0],
- [0x113cd, 1],
- [0x113ce, 0],
- [0x113cf, 1],
- [0x113d0, 0],
- [0x113d1, 1],
- [0x113d2, 0],
- [0x113e0, 1],
- [0x113e2, 0],
- [0x11437, 1],
- [0x1143f, 0],
- [0x11441, 1],
- [0x11444, 0],
- [0x11445, 1],
- [0x11446, 0],
- [0x1145d, 1],
- [0x1145e, 0],
- [0x114b2, 1],
- [0x114b8, 0],
- [0x114b9, 1],
- [0x114ba, 0],
- [0x114be, 1],
- [0x114c0, 0],
- [0x114c1, 1],
- [0x114c3, 0],
- [0x115b1, 1],
- [0x115b5, 0],
- [0x115bb, 1],
- [0x115bd, 0],
- [0x115be, 1],
- [0x115c0, 0],
- [0x115db, 1],
- [0x115dd, 0],
- [0x11632, 1],
- [0x1163a, 0],
- [0x1163c, 1],
- [0x1163d, 0],
- [0x1163e, 1],
- [0x11640, 0],
- [0x116aa, 1],
- [0x116ab, 0],
- [0x116ac, 1],
- [0x116ad, 0],
- [0x116af, 1],
- [0x116b5, 0],
- [0x116b6, 1],
- [0x116b7, 0],
- [0x1171c, 1],
- [0x1171d, 0],
- [0x1171e, 1],
- [0x1171f, 0],
- [0x11721, 1],
- [0x11725, 0],
- [0x11726, 1],
- [0x1172b, 0],
- [0x1182e, 1],
- [0x11837, 0],
- [0x11838, 1],
- [0x1183a, 0],
- [0x1193a, 1],
- [0x1193c, 0],
- [0x1193d, 1],
- [0x1193e, 0],
- [0x11942, 1],
- [0x11943, 0],
- [0x119d3, 1],
- [0x119d7, 0],
- [0x119d9, 1],
- [0x119db, 0],
- [0x119df, 1],
- [0x119e0, 0],
- [0x11a00, 1],
- [0x11a0a, 0],
- [0x11a32, 1],
- [0x11a38, 0],
- [0x11a3a, 1],
- [0x11a3e, 0],
- [0x11a46, 1],
- [0x11a47, 0],
- [0x11a50, 1],
- [0x11a56, 0],
- [0x11a58, 1],
- [0x11a5b, 0],
- [0x11a89, 1],
- [0x11a96, 0],
- [0x11a97, 1],
- [0x11a99, 0],
- [0x11c2f, 1],
- [0x11c36, 0],
- [0x11c37, 1],
- [0x11c3d, 0],
- [0x11c3e, 1],
- [0x11c3f, 0],
- [0x11c91, 1],
- [0x11ca7, 0],
- [0x11ca9, 1],
- [0x11cb0, 0],
- [0x11cb1, 1],
- [0x11cb3, 0],
- [0x11cb4, 1],
- [0x11cb6, 0],
- [0x11d30, 1],
- [0x11d36, 0],
- [0x11d39, 1],
- [0x11d3a, 0],
- [0x11d3b, 1],
- [0x11d3d, 0],
- [0x11d3e, 1],
- [0x11d45, 0],
- [0x11d46, 1],
- [0x11d47, 0],
- [0x11d8f, 1],
- [0x11d91, 0],
- [0x11d94, 1],
- [0x11d95, 0],
- [0x11d96, 1],
- [0x11d97, 0],
- [0x11ef2, 1],
- [0x11ef4, 0],
- [0x11eff, 1],
- [0x11f01, 0],
- [0x11f35, 1],
- [0x11f3a, 0],
- [0x11f3f, 1],
- [0x11f40, 0],
- [0x11f41, 1],
- [0x11f42, 0],
- [0x11f59, 1],
- [0x11f5a, 0],
- [0x1343f, 1],
- [0x13440, 0],
- [0x13446, 1],
- [0x13455, 0],
- [0x1611d, 1],
- [0x16129, 0],
- [0x1612c, 1],
- [0x1612f, 0],
- [0x16aef, 1],
- [0x16af4, 0],
- [0x16b2f, 1],
- [0x16b36, 0],
- [0x16f4e, 1],
- [0x16f4f, 0],
- [0x16f8e, 1],
- [0x16f92, 0],
- [0x16fdf, 1],
- [0x16fe3, 2],
- [0x16fe4, 0],
- [0x16fef, 1],
- [0x16ff1, 2],
- [0x16fff, 1],
- [0x187f7, 2],
- [0x187ff, 1],
- [0x18cd5, 2],
- [0x18cfe, 1],
- [0x18d08, 2],
- [0x1afef, 1],
- [0x1aff3, 2],
- [0x1aff4, 1],
- [0x1affb, 2],
- [0x1affc, 1],
- [0x1affe, 2],
- [0x1afff, 1],
- [0x1b122, 2],
- [0x1b131, 1],
- [0x1b132, 2],
- [0x1b14f, 1],
- [0x1b152, 2],
- [0x1b154, 1],
- [0x1b155, 2],
- [0x1b163, 1],
- [0x1b167, 2],
- [0x1b16f, 1],
- [0x1b2fb, 2],
- [0x1bc9c, 1],
- [0x1bc9e, 0],
- [0x1ceff, 1],
- [0x1cf2d, 0],
- [0x1cf2f, 1],
- [0x1cf46, 0],
- [0x1d166, 1],
- [0x1d169, 0],
- [0x1d17a, 1],
- [0x1d182, 0],
- [0x1d184, 1],
- [0x1d18b, 0],
- [0x1d1a9, 1],
- [0x1d1ad, 0],
- [0x1d241, 1],
- [0x1d244, 0],
- [0x1d2ff, 1],
- [0x1d356, 2],
- [0x1d35f, 1],
- [0x1d376, 2],
- [0x1d9ff, 1],
- [0x1da36, 0],
- [0x1da3a, 1],
- [0x1da6c, 0],
- [0x1da74, 1],
- [0x1da75, 0],
- [0x1da83, 1],
- [0x1da84, 0],
- [0x1da9a, 1],
- [0x1da9f, 0],
- [0x1daa0, 1],
- [0x1daaf, 0],
- [0x1dfff, 1],
- [0x1e006, 0],
- [0x1e007, 1],
- [0x1e018, 0],
- [0x1e01a, 1],
- [0x1e021, 0],
- [0x1e022, 1],
- [0x1e024, 0],
- [0x1e025, 1],
- [0x1e02a, 0],
- [0x1e08e, 1],
- [0x1e08f, 0],
- [0x1e12f, 1],
- [0x1e136, 0],
- [0x1e2ad, 1],
- [0x1e2ae, 0],
- [0x1e2eb, 1],
- [0x1e2ef, 0],
- [0x1e4eb, 1],
- [0x1e4ef, 0],
- [0x1e5ed, 1],
- [0x1e5ef, 0],
- [0x1e8cf, 1],
- [0x1e8d6, 0],
- [0x1e943, 1],
- [0x1e94a, 0],
- [0x1f003, 1],
- [0x1f004, 2],
- [0x1f0ce, 1],
- [0x1f0cf, 2],
- [0x1f0ff, 1],
- [0x1f10a, -1],
- [0x1f10f, 1],
- [0x1f12d, -1],
- [0x1f12f, 1],
- [0x1f169, -1],
- [0x1f16f, 1],
- [0x1f18d, -1],
- [0x1f18e, 2],
- [0x1f190, -1],
- [0x1f19a, 2],
- [0x1f1ac, -1],
- [0x1f1ff, 1],
- [0x1f202, 2],
- [0x1f20f, 1],
- [0x1f23b, 2],
- [0x1f23f, 1],
- [0x1f248, 2],
- [0x1f24f, 1],
- [0x1f251, 2],
- [0x1f25f, 1],
- [0x1f265, 2],
- [0x1f2ff, 1],
- [0x1f320, 2],
- [0x1f32c, 1],
- [0x1f335, 2],
- [0x1f336, 1],
- [0x1f37c, 2],
- [0x1f37d, 1],
- [0x1f393, 2],
- [0x1f39f, 1],
- [0x1f3ca, 2],
- [0x1f3ce, 1],
- [0x1f3d3, 2],
- [0x1f3df, 1],
- [0x1f3f0, 2],
- [0x1f3f3, 1],
- [0x1f3f4, 2],
- [0x1f3f7, 1],
- [0x1f43e, 2],
- [0x1f43f, 1],
- [0x1f440, 2],
- [0x1f441, 1],
- [0x1f4fc, 2],
- [0x1f4fe, 1],
- [0x1f53d, 2],
- [0x1f54a, 1],
- [0x1f54e, 2],
- [0x1f54f, 1],
- [0x1f567, 2],
- [0x1f579, 1],
- [0x1f57a, 2],
- [0x1f594, 1],
- [0x1f596, 2],
- [0x1f5a3, 1],
- [0x1f5a4, 2],
- [0x1f5fa, 1],
- [0x1f64f, 2],
- [0x1f67f, 1],
- [0x1f6c5, 2],
- [0x1f6cb, 1],
- [0x1f6cc, 2],
- [0x1f6cf, 1],
- [0x1f6d2, 2],
- [0x1f6d4, 1],
- [0x1f6d7, 2],
- [0x1f6db, 1],
- [0x1f6df, 2],
- [0x1f6ea, 1],
- [0x1f6ec, 2],
- [0x1f6f3, 1],
- [0x1f6fc, 2],
- [0x1f7df, 1],
- [0x1f7eb, 2],
- [0x1f7ef, 1],
- [0x1f7f0, 2],
- [0x1f90b, 1],
- [0x1f93a, 2],
- [0x1f93b, 1],
- [0x1f945, 2],
- [0x1f946, 1],
- [0x1f9ff, 2],
- [0x1fa6f, 1],
- [0x1fa7c, 2],
- [0x1fa7f, 1],
- [0x1fa89, 2],
- [0x1fa8e, 1],
- [0x1fac6, 2],
- [0x1facd, 1],
- [0x1fadc, 2],
- [0x1fade, 1],
- [0x1fae9, 2],
- [0x1faef, 1],
- [0x1faf8, 2],
- [0x1ffff, 1],
- [0x2fffd, 2],
- [0x2ffff, 1],
- [0x3fffd, 2],
- [0xe00ff, 1],
- [0xe01ef, 0],
- [0xeffff, 1],
- [0xffffd, -1],
- [0xfffff, 1],
- [0x10fffd, -1],
- [0x7fffffff, 1]
- ].transpose.map(&:freeze)
-end
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
deleted file mode 100644
index 1d0f0d80a1..0000000000
--- a/lib/reline/version.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-module Reline
- VERSION = '0.6.0'
-end
diff --git a/test/irb/command/test_cd.rb b/test/irb/command/test_cd.rb
deleted file mode 100644
index 10f77f6691..0000000000
--- a/test/irb/command/test_cd.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-require "tempfile"
-require_relative "../helper"
-
-module TestIRB
- class CDTest < IntegrationTestCase
- def setup
- super
-
- write_ruby <<~'RUBY'
- class Foo
- class Bar
- def bar
- "this is bar"
- end
- end
-
- def foo
- "this is foo"
- end
- end
-
- class BO < BasicObject
- def baz
- "this is baz"
- end
- end
-
- binding.irb
- RUBY
- end
-
- def test_cd
- out = run_ruby_file do
- type "cd Foo"
- type "ls"
- type "cd Bar"
- type "ls"
- type "cd .."
- type "exit"
- end
-
- assert_match(/irb\(Foo\):002>/, out)
- assert_match(/Foo#methods: foo/, out)
- assert_match(/irb\(Foo::Bar\):004>/, out)
- assert_match(/Bar#methods: bar/, out)
- assert_match(/irb\(Foo\):006>/, out)
- end
-
- def test_cd_basic_object_or_frozen
- out = run_ruby_file do
- type "cd BO.new"
- type "cd 1"
- type "cd Object.new.freeze"
- type "exit"
- end
-
- assert_match(/irb\(#<BO:.+\):002>/, out)
- assert_match(/irb\(1\):003>/, out)
- assert_match(/irb\(#<Object:.+\):004>/, out)
- end
-
- def test_cd_moves_top_level_with_no_args
- out = run_ruby_file do
- type "cd Foo"
- type "cd Bar"
- type "cd"
- type "exit"
- end
-
- assert_match(/irb\(Foo::Bar\):003>/, out)
- assert_match(/irb\(main\):004>/, out)
- end
-
- def test_cd_with_error
- out = run_ruby_file do
- type "cd Baz"
- type "exit"
- end
-
- assert_match(/Error: uninitialized constant Baz/, out)
- assert_match(/irb\(main\):002>/, out) # the context should not change
- end
- end
-end
diff --git a/test/irb/command/test_command_aliasing.rb b/test/irb/command/test_command_aliasing.rb
deleted file mode 100644
index 4ecc88c0aa..0000000000
--- a/test/irb/command/test_command_aliasing.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-require "tempfile"
-require_relative "../helper"
-
-module TestIRB
- class CommandAliasingTest < IntegrationTestCase
- def setup
- super
- write_rc <<~RUBY
- IRB.conf[:COMMAND_ALIASES] = {
- :c => :conf, # alias to helper method
- :f => :foo
- }
- RUBY
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
- end
-
- def test_aliasing_to_helper_method_triggers_warning
- out = run_ruby_file do
- type "c"
- type "exit"
- end
- assert_include(out, "Using command alias `c` for helper method `conf` is not supported.")
- assert_not_include(out, "Maybe IRB bug!")
- end
-
- def test_alias_to_non_existent_command_triggers_warning
- message = "You're trying to use command alias `f` for command `foo`, but `foo` does not exist."
- out = run_ruby_file do
- type "f"
- type "exit"
- end
- assert_include(out, message)
- assert_not_include(out, "Maybe IRB bug!")
-
- # Local variables take precedence over command aliases
- out = run_ruby_file do
- type "f = 123"
- type "f"
- type "exit"
- end
- assert_not_include(out, message)
- assert_not_include(out, "Maybe IRB bug!")
- end
- end
-end
diff --git a/test/irb/command/test_copy.rb b/test/irb/command/test_copy.rb
deleted file mode 100644
index 505812a1de..0000000000
--- a/test/irb/command/test_copy.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-require 'irb'
-
-require_relative "../helper"
-
-module TestIRB
- class CopyTest < IntegrationTestCase
- def setup
- super
- @envs['IRB_COPY_COMMAND'] = "#{EnvUtil.rubybin} -e \"puts 'foo' + STDIN.read\""
- end
-
- def test_copy_with_pbcopy
- write_ruby <<~'ruby'
- class Answer
- def initialize(answer)
- @answer = answer
- end
- end
-
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "copy Answer.new(42)"
- type "exit"
- end
-
- assert_match(/foo#<Answer:0x[0-9a-f]+ @answer=42/, output)
- assert_match(/Copied to system clipboard/, output)
- end
-
- # copy puts 5 should:
- # - Print value to the console
- # - Copy nil to clipboard, since that is what the puts call evaluates to
- def test_copy_when_expression_has_side_effects
- write_ruby <<~'ruby'
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "copy puts 42"
- type "exit"
- end
-
- assert_match(/^42\r\n/, output)
- assert_match(/foonil/, output)
- assert_match(/Copied to system clipboard/, output)
- refute_match(/foo42/, output)
- end
-
- def test_copy_when_copy_command_is_invalid
- @envs['IRB_COPY_COMMAND'] = "lulz"
-
- write_ruby <<~'ruby'
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "copy 42"
- type "exit"
- end
-
- assert_match(/No such file or directory - lulz/, output)
- assert_match(/Is IRB\.conf\[:COPY_COMMAND\] set to a bad value/, output)
- refute_match(/Copied to system clipboard/, output)
- end
- end
-end
diff --git a/test/irb/command/test_custom_command.rb b/test/irb/command/test_custom_command.rb
deleted file mode 100644
index 13f412c210..0000000000
--- a/test/irb/command/test_custom_command.rb
+++ /dev/null
@@ -1,194 +0,0 @@
-# frozen_string_literal: true
-require "irb"
-
-require_relative "../helper"
-
-module TestIRB
- class CustomCommandIntegrationTest < TestIRB::IntegrationTestCase
- def test_command_registration_can_happen_after_irb_require
- write_ruby <<~RUBY
- require "irb"
- require "irb/command"
-
- class PrintCommand < IRB::Command::Base
- category 'CommandTest'
- description 'print_command'
- def execute(*)
- puts "Hello from PrintCommand"
- end
- end
-
- IRB::Command.register(:print!, PrintCommand)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "print!"
- type "exit"
- end
-
- assert_include(output, "Hello from PrintCommand")
- end
-
- def test_command_registration_accepts_string_too
- write_ruby <<~RUBY
- require "irb/command"
-
- class PrintCommand < IRB::Command::Base
- category 'CommandTest'
- description 'print_command'
- def execute(*)
- puts "Hello from PrintCommand"
- end
- end
-
- IRB::Command.register("print!", PrintCommand)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "print!"
- type "exit"
- end
-
- assert_include(output, "Hello from PrintCommand")
- end
-
- def test_arguments_propagation
- write_ruby <<~RUBY
- require "irb/command"
-
- class PrintArgCommand < IRB::Command::Base
- category 'CommandTest'
- description 'print_command_arg'
- def execute(arg)
- $nth_execution ||= 0
- puts "\#{$nth_execution} arg=\#{arg.inspect}"
- $nth_execution += 1
- end
- end
-
- IRB::Command.register(:print_arg, PrintArgCommand)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "print_arg"
- type "print_arg \n"
- type "print_arg a r g"
- type "print_arg a r g \n"
- type "exit"
- end
-
- assert_include(output, "0 arg=\"\"")
- assert_include(output, "1 arg=\"\"")
- assert_include(output, "2 arg=\"a r g\"")
- assert_include(output, "3 arg=\"a r g\"")
- end
-
- def test_def_extend_command_still_works
- write_ruby <<~RUBY
- require "irb"
-
- class FooBarCommand < IRB::Command::Base
- category 'FooBarCategory'
- description 'foobar_description'
- def execute(*)
- $nth_execution ||= 1
- puts "\#{$nth_execution} FooBar executed"
- $nth_execution += 1
- end
- end
-
- IRB::ExtendCommandBundle.def_extend_command(:foobar, FooBarCommand, nil, [:fbalias, IRB::Command::OVERRIDE_ALL])
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "foobar"
- type "fbalias"
- type "help foobar"
- type "exit"
- end
-
- assert_include(output, "1 FooBar executed")
- assert_include(output, "2 FooBar executed")
- assert_include(output, "foobar_description")
- end
-
- def test_no_meta_command_also_works
- write_ruby <<~RUBY
- require "irb/command"
-
- class NoMetaCommand < IRB::Command::Base
- def execute(*)
- puts "This command does not override meta attributes"
- end
- end
-
- IRB::Command.register(:no_meta, NoMetaCommand)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "no_meta"
- type "help no_meta"
- type "exit"
- end
-
- assert_include(output, "This command does not override meta attributes")
- assert_include(output, "No description provided.")
- assert_not_include(output, "Maybe IRB bug")
- end
-
- def test_command_name_local_variable
- write_ruby <<~RUBY
- require "irb/command"
-
- class FooBarCommand < IRB::Command::Base
- category 'CommandTest'
- description 'test'
- def execute(arg)
- puts "arg=\#{arg.inspect}"
- end
- end
-
- IRB::Command.register(:foo_bar, FooBarCommand)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "binding.irb"
- type "foo_bar == 1 || 1"
- type "foo_bar =~ /2/ || 2"
- type "exit"
- type "binding.irb"
- type "foo_bar = '3'; foo_bar"
- type "foo_bar == 4 || '4'"
- type "foo_bar =~ /5/ || '5'"
- type "exit"
- type "binding.irb"
- type "foo_bar ||= '6'; foo_bar"
- type "foo_bar == 7 || '7'"
- type "foo_bar =~ /8/ || '8'"
- type "exit"
- type "exit"
- end
-
- assert_include(output, 'arg="== 1 || 1"')
- assert_include(output, 'arg="=~ /2/ || 2"')
- assert_include(output, '=> "3"')
- assert_include(output, '=> "4"')
- assert_include(output, '=> "5"')
- assert_include(output, '=> "6"')
- assert_include(output, '=> "7"')
- assert_include(output, '=> "8"')
- end
- end
-end
diff --git a/test/irb/command/test_disable_irb.rb b/test/irb/command/test_disable_irb.rb
deleted file mode 100644
index 14a20043d5..0000000000
--- a/test/irb/command/test_disable_irb.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: false
-require 'irb'
-
-require_relative "../helper"
-
-module TestIRB
- class DisableIRBTest < IntegrationTestCase
- def test_disable_irb_disable_further_irb_breakpoints
- write_ruby <<~'ruby'
- puts "First line"
- puts "Second line"
- binding.irb
- puts "Third line"
- binding.irb
- puts "Fourth line"
- ruby
-
- output = run_ruby_file do
- type "disable_irb"
- end
-
- assert_match(/First line\r\n/, output)
- assert_match(/Second line\r\n/, output)
- assert_match(/Third line\r\n/, output)
- assert_match(/Fourth line\r\n/, output)
- end
- end
-end
diff --git a/test/irb/command/test_force_exit.rb b/test/irb/command/test_force_exit.rb
deleted file mode 100644
index 191a786872..0000000000
--- a/test/irb/command/test_force_exit.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: false
-require 'irb'
-
-require_relative "../helper"
-
-module TestIRB
- class ForceExitTest < IntegrationTestCase
- def test_forced_exit_finishes_process_immediately
- write_ruby <<~'ruby'
- puts "First line"
- puts "Second line"
- binding.irb
- puts "Third line"
- binding.irb
- puts "Fourth line"
- ruby
-
- output = run_ruby_file do
- type "123"
- type "456"
- type "exit!"
- end
-
- assert_match(/First line\r\n/, output)
- assert_match(/Second line\r\n/, output)
- assert_match(/irb\(main\):001> 123/, output)
- assert_match(/irb\(main\):002> 456/, output)
- refute_match(/Third line\r\n/, output)
- refute_match(/Fourth line\r\n/, output)
- end
-
- def test_forced_exit_in_nested_sessions
- write_ruby <<~'ruby'
- def foo
- binding.irb
- end
-
- binding.irb
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "123"
- type "foo"
- type "exit!"
- end
-
- assert_match(/irb\(main\):001> 123/, output)
- end
- end
-end
diff --git a/test/irb/command/test_help.rb b/test/irb/command/test_help.rb
deleted file mode 100644
index b34832b022..0000000000
--- a/test/irb/command/test_help.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-require "tempfile"
-require_relative "../helper"
-
-module TestIRB
- class HelpTest < IntegrationTestCase
- def setup
- super
-
- write_rc <<~'RUBY'
- IRB.conf[:USE_PAGER] = false
- RUBY
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
- end
-
- def test_help
- out = run_ruby_file do
- type "help"
- type "exit"
- end
-
- assert_match(/List all available commands/, out)
- assert_match(/Start the debugger of debug\.gem/, out)
- end
-
- def test_command_help
- out = run_ruby_file do
- type "help ls"
- type "exit"
- end
-
- assert_match(/Usage: ls \[obj\]/, out)
- end
-
- def test_command_help_not_found
- out = run_ruby_file do
- type "help foo"
- type "exit"
- end
-
- assert_match(/Can't find command `foo`\. Please check the command name and try again\./, out)
- end
-
- def test_show_cmds
- out = run_ruby_file do
- type "help"
- type "exit"
- end
-
- assert_match(/List all available commands/, out)
- assert_match(/Start the debugger of debug\.gem/, out)
- end
-
- def test_help_lists_user_aliases
- out = run_ruby_file do
- type "help"
- type "exit"
- end
-
- assert_match(/\$\s+Alias for `show_source`/, out)
- assert_match(/@\s+Alias for `whereami`/, out)
- end
-
- def test_help_lists_helper_methods
- out = run_ruby_file do
- type "help"
- type "exit"
- end
-
- assert_match(/Helper methods\s+conf\s+Returns the current IRB context/, out)
- end
- end
-end
diff --git a/test/irb/command/test_multi_irb_commands.rb b/test/irb/command/test_multi_irb_commands.rb
deleted file mode 100644
index e313c0c5d2..0000000000
--- a/test/irb/command/test_multi_irb_commands.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require "tempfile"
-require_relative "../helper"
-
-module TestIRB
- class MultiIRBTest < IntegrationTestCase
- def setup
- super
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
- end
-
- def test_jobs_command_with_print_deprecated_warning
- out = run_ruby_file do
- type "jobs"
- type "exit"
- end
-
- assert_match(/Multi-irb commands are deprecated and will be removed in IRB 2\.0\.0\. Please use workspace commands instead\./, out)
- assert_match(%r|If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653|, out)
- assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out)
- end
-
- def test_irb_jobs_and_kill_commands
- out = run_ruby_file do
- type "irb"
- type "jobs"
- type "kill 1"
- type "exit"
- end
-
- assert_match(/#0->irb on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out)
- assert_match(/#1->irb#1 on main \(#<Thread:0x.+ run>: running\)/, out)
- end
-
- def test_irb_fg_jobs_and_kill_commands
- out = run_ruby_file do
- type "irb"
- type "fg 0"
- type "jobs"
- type "kill 1"
- type "exit"
- end
-
- assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out)
- assert_match(/#1->irb#1 on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out)
- end
- end
-end
diff --git a/test/irb/command/test_show_source.rb b/test/irb/command/test_show_source.rb
deleted file mode 100644
index a4227231e4..0000000000
--- a/test/irb/command/test_show_source.rb
+++ /dev/null
@@ -1,410 +0,0 @@
-# frozen_string_literal: false
-require 'irb'
-
-require_relative "../helper"
-
-module TestIRB
- class ShowSourceTest < IntegrationTestCase
- def setup
- super
-
- write_rc <<~'RUBY'
- IRB.conf[:USE_PAGER] = false
- RUBY
- end
-
- def test_show_source
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source IRB.conf"
- type "exit"
- end
-
- assert_match(%r[/irb\/init\.rb], out)
- end
-
- def test_show_source_alias
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "$ IRB.conf"
- type "exit"
- end
-
- assert_match(%r[/irb\/init\.rb], out)
- end
-
- def test_show_source_with_missing_signature
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source foo"
- type "exit"
- end
-
- assert_match(%r[Couldn't locate a definition for foo], out)
- end
-
- def test_show_source_with_missing_constant
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Foo"
- type "exit"
- end
-
- assert_match(%r[Couldn't locate a definition for Foo], out)
- end
-
- def test_show_source_with_eval_error
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source raise(Exception).itself"
- type "exit"
- end
-
- assert_match(%r[Couldn't locate a definition for raise\(Exception\)\.itself], out)
- end
-
- def test_show_source_string
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source 'IRB.conf'"
- type "exit"
- end
-
- assert_match(%r[/irb\/init\.rb], out)
- end
-
- def test_show_source_method_s
- write_ruby <<~RUBY
- class Baz
- def foo
- end
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bar#foo -s"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end\r\n], out)
- end
-
- def test_show_source_method_s_with_incorrect_signature
- write_ruby <<~RUBY
- class Baz
- def foo
- end
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bar#fooo -s"
- type "exit"
- end
-
- assert_match(%r[Error: Couldn't locate a super definition for Bar#fooo], out)
- end
-
- def test_show_source_private_method
- write_ruby <<~RUBY
- class Bar
- private def foo
- end
- end
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bar#foo"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:2\s+private def foo\r\n end\r\n], out)
- end
-
- def test_show_source_private_singleton_method
- write_ruby <<~RUBY
- class Bar
- private def foo
- end
- end
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "bar = Bar.new"
- type "show_source bar.foo"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:2\s+private def foo\r\n end\r\n], out)
- end
-
- def test_show_source_method_multiple_s
- write_ruby <<~RUBY
- class Baz
- def foo
- end
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- class Bob < Bar
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bob#foo -ss"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end\r\n], out)
- end
-
- def test_show_source_method_no_instance_method
- write_ruby <<~RUBY
- class Baz
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bar#foo -s"
- type "exit"
- end
-
- assert_match(%r[Error: Couldn't locate a super definition for Bar#foo], out)
- end
-
- def test_show_source_method_exceeds_super_chain
- write_ruby <<~RUBY
- class Baz
- def foo
- end
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bar#foo -ss"
- type "exit"
- end
-
- assert_match(%r[Error: Couldn't locate a super definition for Bar#foo], out)
- end
-
- def test_show_source_method_accidental_characters
- write_ruby <<~'RUBY'
- class Baz
- def foo
- end
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source Bar#foo -sddddd"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end], out)
- end
-
- def test_show_source_receiver_super
- write_ruby <<~RUBY
- class Baz
- def foo
- end
- end
-
- class Bar < Baz
- def foo
- super
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "bar = Bar.new"
- type "show_source bar.foo -s"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end], out)
- end
-
- def test_show_source_with_double_colons
- write_ruby <<~RUBY
- class Foo
- end
-
- class Foo
- class Bar
- end
- end
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "show_source ::Foo"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:1\s+class Foo\r\nend], out)
-
- out = run_ruby_file do
- type "show_source ::Foo::Bar"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:5\s+class Bar\r\n end], out)
- end
-
- def test_show_source_keep_script_lines
- pend unless defined?(RubyVM.keep_script_lines)
-
- write_ruby <<~RUBY
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "def foo; end"
- type "show_source foo"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}\(irb\):1\s+def foo; end], out)
- end
-
- def test_show_source_unavailable_source
- write_ruby <<~RUBY
- binding.irb
- RUBY
-
- out = run_ruby_file do
- type "RubyVM.keep_script_lines = false if defined?(RubyVM.keep_script_lines)"
- type "def foo; end"
- type "show_source foo"
- type "exit"
- end
- assert_match(%r[#{@ruby_file.to_path}\(irb\):2\s+Source not available], out)
- end
-
- def test_show_source_shows_binary_source
- write_ruby <<~RUBY
- # io-console is an indirect dependency of irb
- require "io/console"
-
- binding.irb
- RUBY
-
- out = run_ruby_file do
- # IO::ConsoleMode is defined in io-console gem's C extension
- type "show_source IO::ConsoleMode"
- type "exit"
- end
-
- # A safeguard to make sure the test subject is actually defined
- refute_match(/NameError/, out)
- assert_match(%r[Defined in binary file:.+io/console], out)
- end
-
- def test_show_source_with_constant_lookup
- write_ruby <<~RUBY
- X = 1
- module M
- Y = 1
- Z = 2
- end
- class A
- Z = 1
- Array = 1
- class B
- include M
- Object.new.instance_eval { binding.irb }
- end
- end
- RUBY
-
- out = run_ruby_file do
- type "show_source X"
- type "show_source Y"
- type "show_source Z"
- type "show_source Array"
- type "exit"
- end
-
- assert_match(%r[#{@ruby_file.to_path}:1\s+X = 1], out)
- assert_match(%r[#{@ruby_file.to_path}:3\s+Y = 1], out)
- assert_match(%r[#{@ruby_file.to_path}:7\s+Z = 1], out)
- assert_match(%r[#{@ruby_file.to_path}:8\s+Array = 1], out)
- end
- end
-end
diff --git a/test/irb/helper.rb b/test/irb/helper.rb
deleted file mode 100644
index ea2c6ef16a..0000000000
--- a/test/irb/helper.rb
+++ /dev/null
@@ -1,234 +0,0 @@
-require "test/unit"
-require "pathname"
-require "rubygems"
-
-begin
- require_relative "../lib/helper"
- require_relative "../lib/envutil"
-rescue LoadError # ruby/ruby defines helpers differently
-end
-
-begin
- require "pty"
-rescue LoadError # some platforms don't support PTY
-end
-
-module IRB
- class InputMethod; end
-end
-
-module TestIRB
- RUBY_3_4 = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0.dev")
- class TestCase < Test::Unit::TestCase
- class TestInputMethod < ::IRB::InputMethod
- attr_reader :list, :line_no
-
- def initialize(list = [])
- @line_no = 0
- @list = list
- end
-
- def gets
- @list[@line_no]&.tap {@line_no += 1}
- end
-
- def eof?
- @line_no >= @list.size
- end
-
- def encoding
- Encoding.default_external
- end
-
- def reset
- @line_no = 0
- end
- end
-
- def ruby_core?
- !Pathname(__dir__).join("../../", "irb.gemspec").exist?
- end
-
- def setup_envs(home:)
- @backup_home = ENV["HOME"]
- ENV["HOME"] = home
- @backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME")
- @backup_irbrc = ENV.delete("IRBRC")
- end
-
- def teardown_envs
- ENV["HOME"] = @backup_home
- ENV["XDG_CONFIG_HOME"] = @backup_xdg_config_home
- ENV["IRBRC"] = @backup_irbrc
- end
-
- def save_encodings
- @default_encoding = [Encoding.default_external, Encoding.default_internal]
- @stdio_encodings = [STDIN, STDOUT, STDERR].map {|io| [io.external_encoding, io.internal_encoding] }
- end
-
- def restore_encodings
- EnvUtil.suppress_warning do
- Encoding.default_external, Encoding.default_internal = *@default_encoding
- [STDIN, STDOUT, STDERR].zip(@stdio_encodings) do |io, encs|
- io.set_encoding(*encs)
- end
- end
- end
-
- def without_rdoc(&block)
- ::Kernel.send(:alias_method, :irb_original_require, :require)
-
- ::Kernel.define_method(:require) do |name|
- raise LoadError, "cannot load such file -- rdoc (test)" if name.match?("rdoc") || name.match?(/^rdoc\/.*/)
- ::Kernel.send(:irb_original_require, name)
- end
-
- yield
- ensure
- EnvUtil.suppress_warning {
- ::Kernel.send(:alias_method, :require, :irb_original_require)
- ::Kernel.undef_method :irb_original_require
- }
- end
- end
-
- class IntegrationTestCase < TestCase
- LIB = File.expand_path("../../lib", __dir__)
- TIMEOUT_SEC = 3
-
- def setup
- @envs = {}
- @tmpfiles = []
-
- unless defined?(PTY)
- omit "Integration tests require PTY."
- end
-
- if ruby_core?
- omit "This test works only under ruby/irb"
- end
-
- write_rc <<~RUBY
- IRB.conf[:USE_PAGER] = false
- RUBY
- end
-
- def teardown
- @tmpfiles.each do |tmpfile|
- File.unlink(tmpfile)
- end
- end
-
- def run_ruby_file(&block)
- cmd = [EnvUtil.rubybin, "-I", LIB, @ruby_file.to_path]
- tmp_dir = Dir.mktmpdir
-
- @commands = []
- lines = []
-
- yield
-
- # Test should not depend on user's irbrc file
- @envs["HOME"] ||= tmp_dir
- @envs["XDG_CONFIG_HOME"] ||= tmp_dir
- @envs["IRBRC"] = nil unless @envs.key?("IRBRC")
-
- envs_for_spawn = @envs.merge('TERM' => 'dumb', 'TEST_IRB_FORCE_INTERACTIVE' => 'true')
-
- PTY.spawn(envs_for_spawn, *cmd) do |read, write, pid|
- Timeout.timeout(TIMEOUT_SEC) do
- while line = safe_gets(read)
- lines << line
-
- # means the breakpoint is triggered
- if line.match?(/binding\.irb/)
- while command = @commands.shift
- write.puts(command)
- end
- end
- end
- end
- ensure
- read.close
- write.close
- kill_safely(pid)
- end
-
- lines.join
- rescue Timeout::Error
- message = <<~MSG
- Test timedout.
-
- #{'=' * 30} OUTPUT #{'=' * 30}
- #{lines.map { |l| " #{l}" }.join}
- #{'=' * 27} END OF OUTPUT #{'=' * 27}
- MSG
- assert_block(message) { false }
- ensure
- FileUtils.remove_entry tmp_dir
- end
-
- # read.gets could raise exceptions on some platforms
- # https://github.com/ruby/ruby/blob/master/ext/pty/pty.c#L721-L728
- def safe_gets(read)
- read.gets
- rescue Errno::EIO
- nil
- end
-
- def kill_safely pid
- return if wait_pid pid, TIMEOUT_SEC
-
- Process.kill :TERM, pid
- return if wait_pid pid, 0.2
-
- Process.kill :KILL, pid
- Process.waitpid(pid)
- rescue Errno::EPERM, Errno::ESRCH
- end
-
- def wait_pid pid, sec
- total_sec = 0.0
- wait_sec = 0.001 # 1ms
-
- while total_sec < sec
- if Process.waitpid(pid, Process::WNOHANG) == pid
- return true
- end
- sleep wait_sec
- total_sec += wait_sec
- wait_sec *= 2
- end
-
- false
- rescue Errno::ECHILD
- true
- end
-
- def type(command)
- @commands << command
- end
-
- def write_ruby(program)
- @ruby_file = Tempfile.create(%w{irbtest- .rb})
- @tmpfiles << @ruby_file
- @ruby_file.write(program)
- @ruby_file.close
- end
-
- def write_rc(content)
- # Append irbrc content if a tempfile for it already exists
- if @irbrc
- @irbrc = File.open(@irbrc, "a")
- else
- @irbrc = Tempfile.new('irbrc')
- @tmpfiles << @irbrc
- end
-
- @irbrc.write(content)
- @irbrc.close
- @envs['IRBRC'] = @irbrc.path
- end
- end
-end
diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb
deleted file mode 100644
index 5529e29042..0000000000
--- a/test/irb/test_color.rb
+++ /dev/null
@@ -1,275 +0,0 @@
-# frozen_string_literal: false
-require 'irb/color'
-require 'stringio'
-
-require_relative "helper"
-
-module TestIRB
- class ColorTest < TestCase
- CLEAR = "\e[0m"
- BOLD = "\e[1m"
- UNDERLINE = "\e[4m"
- REVERSE = "\e[7m"
- RED = "\e[31m"
- GREEN = "\e[32m"
- YELLOW = "\e[33m"
- BLUE = "\e[34m"
- MAGENTA = "\e[35m"
- CYAN = "\e[36m"
-
- def setup
- super
- if IRB.respond_to?(:conf)
- @colorize, IRB.conf[:USE_COLORIZE] = IRB.conf[:USE_COLORIZE], true
- end
- end
-
- def teardown
- if instance_variable_defined?(:@colorize)
- IRB.conf[:USE_COLORIZE] = @colorize
- end
- super
- end
-
- def test_colorize
- text = "text"
- {
- [:BOLD] => "#{BOLD}#{text}#{CLEAR}",
- [:UNDERLINE] => "#{UNDERLINE}#{text}#{CLEAR}",
- [:REVERSE] => "#{REVERSE}#{text}#{CLEAR}",
- [:RED] => "#{RED}#{text}#{CLEAR}",
- [:GREEN] => "#{GREEN}#{text}#{CLEAR}",
- [:YELLOW] => "#{YELLOW}#{text}#{CLEAR}",
- [:BLUE] => "#{BLUE}#{text}#{CLEAR}",
- [:MAGENTA] => "#{MAGENTA}#{text}#{CLEAR}",
- [:CYAN] => "#{CYAN}#{text}#{CLEAR}",
- }.each do |seq, result|
- assert_equal_with_term(result, text, seq: seq)
-
- assert_equal_with_term(text, text, seq: seq, tty: false)
- assert_equal_with_term(text, text, seq: seq, colorable: false)
- assert_equal_with_term(result, text, seq: seq, tty: false, colorable: true)
- end
- end
-
- def test_colorize_code
- # Common behaviors. Warn parser error, but do not warn compile error.
- tests = {
- "1" => "#{BLUE}#{BOLD}1#{CLEAR}",
- "2.3" => "#{MAGENTA}#{BOLD}2.3#{CLEAR}",
- "7r" => "#{BLUE}#{BOLD}7r#{CLEAR}",
- "8i" => "#{BLUE}#{BOLD}8i#{CLEAR}",
- "['foo', :bar]" => "[#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}bar#{CLEAR}]",
- "class A; end" => "#{GREEN}class#{CLEAR} #{BLUE}#{BOLD}#{UNDERLINE}A#{CLEAR}; #{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})",
- "# comment" => "#{BLUE}#{BOLD}# comment#{CLEAR}",
- "def f;yield(hello);end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}f#{CLEAR};#{GREEN}yield#{CLEAR}(hello);#{GREEN}end#{CLEAR}",
- '"##@var]"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}\##{CLEAR}#{RED}\##{CLEAR}@var#{RED}]#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
- '"foo#{a} #{b}"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}a#{RED}}#{CLEAR}#{RED} #{CLEAR}#{RED}\#{#{CLEAR}b#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
- '/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e#{RED}}#{CLEAR}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
- "'a\nb'" => "#{RED}#{BOLD}'#{CLEAR}#{RED}a#{CLEAR}\n#{RED}b#{CLEAR}#{RED}#{BOLD}'#{CLEAR}",
- "%[str]" => "#{RED}#{BOLD}%[#{CLEAR}#{RED}str#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%Q[str]" => "#{RED}#{BOLD}%Q[#{CLEAR}#{RED}str#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%q[str]" => "#{RED}#{BOLD}%q[#{CLEAR}#{RED}str#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%x[cmd]" => "#{RED}#{BOLD}%x[#{CLEAR}#{RED}cmd#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%r[reg]" => "#{RED}#{BOLD}%r[#{CLEAR}#{RED}reg#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%w[a b]" => "#{RED}#{BOLD}%w[#{CLEAR}#{RED}a#{CLEAR} #{RED}b#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%W[a b]" => "#{RED}#{BOLD}%W[#{CLEAR}#{RED}a#{CLEAR} #{RED}b#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "%s[a b]" => "#{YELLOW}%s[#{CLEAR}#{YELLOW}a b#{CLEAR}#{YELLOW}]#{CLEAR}",
- "%i[c d]" => "#{YELLOW}%i[#{CLEAR}#{YELLOW}c#{CLEAR}#{YELLOW} #{CLEAR}#{YELLOW}d#{CLEAR}#{YELLOW}]#{CLEAR}",
- "%I[c d]" => "#{YELLOW}%I[#{CLEAR}#{YELLOW}c#{CLEAR}#{YELLOW} #{CLEAR}#{YELLOW}d#{CLEAR}#{YELLOW}]#{CLEAR}",
- "{'a': 1}" => "{#{RED}#{BOLD}'#{CLEAR}#{RED}a#{CLEAR}#{RED}#{BOLD}':#{CLEAR} #{BLUE}#{BOLD}1#{CLEAR}}",
- ":Struct" => "#{YELLOW}:#{CLEAR}#{YELLOW}Struct#{CLEAR}",
- '"#{}"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR}#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
- ':"a#{}b"' => "#{YELLOW}:\"#{CLEAR}#{YELLOW}a#{CLEAR}#{YELLOW}\#{#{CLEAR}#{YELLOW}}#{CLEAR}#{YELLOW}b#{CLEAR}#{YELLOW}\"#{CLEAR}",
- ':"a#{ def b; end; \'c\' + "#{ :d }" }e"' => "#{YELLOW}:\"#{CLEAR}#{YELLOW}a#{CLEAR}#{YELLOW}\#{#{CLEAR} #{GREEN}def#{CLEAR} #{BLUE}#{BOLD}b#{CLEAR}; #{GREEN}end#{CLEAR}; #{RED}#{BOLD}'#{CLEAR}#{RED}c#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR} #{YELLOW}:#{CLEAR}#{YELLOW}d#{CLEAR} #{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR} #{YELLOW}}#{CLEAR}#{YELLOW}e#{CLEAR}#{YELLOW}\"#{CLEAR}",
- "[__FILE__, __LINE__, __ENCODING__]" => "[#{CYAN}#{BOLD}__FILE__#{CLEAR}, #{CYAN}#{BOLD}__LINE__#{CLEAR}, #{CYAN}#{BOLD}__ENCODING__#{CLEAR}]",
- ":self" => "#{YELLOW}:#{CLEAR}#{YELLOW}self#{CLEAR}",
- ":class" => "#{YELLOW}:#{CLEAR}#{YELLOW}class#{CLEAR}",
- "[:end, 2]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}end#{CLEAR}, #{BLUE}#{BOLD}2#{CLEAR}]",
- "[:>, 3]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}>#{CLEAR}, #{BLUE}#{BOLD}3#{CLEAR}]",
- "[:`, 4]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}`#{CLEAR}, #{BLUE}#{BOLD}4#{CLEAR}]",
- ":Hello ? world : nil" => "#{YELLOW}:#{CLEAR}#{YELLOW}Hello#{CLEAR} ? world : #{CYAN}#{BOLD}nil#{CLEAR}",
- 'raise "foo#{bar}baz"' => "raise #{RED}#{BOLD}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}bar#{RED}}#{CLEAR}#{RED}baz#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
- '["#{obj.inspect}"]' => "[#{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR}obj.inspect#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}]",
- 'URI.parse "#{}"' => "#{BLUE}#{BOLD}#{UNDERLINE}URI#{CLEAR}.parse #{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR}#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}",
- "begin\nrescue\nend" => "#{GREEN}begin#{CLEAR}\n#{GREEN}rescue#{CLEAR}\n#{GREEN}end#{CLEAR}",
- "foo %w[bar]" => "foo #{RED}#{BOLD}%w[#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD}]#{CLEAR}",
- "foo %i[bar]" => "foo #{YELLOW}%i[#{CLEAR}#{YELLOW}bar#{CLEAR}#{YELLOW}]#{CLEAR}",
- "foo :@bar, baz, :@@qux, :$quux" => "foo #{YELLOW}:#{CLEAR}#{YELLOW}@bar#{CLEAR}, baz, #{YELLOW}:#{CLEAR}#{YELLOW}@@qux#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}$quux#{CLEAR}",
- "`echo`" => "#{RED}#{BOLD}`#{CLEAR}#{RED}echo#{CLEAR}#{RED}#{BOLD}`#{CLEAR}",
- "\t" => Reline::Unicode.escape_for_print("\t") == ' ' ? ' ' : "\t", # not ^I
- "foo(*%W(bar))" => "foo(*#{RED}#{BOLD}%W(#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD})#{CLEAR})",
- "$stdout" => "#{GREEN}#{BOLD}$stdout#{CLEAR}",
- "$&" => "#{GREEN}#{BOLD}$&#{CLEAR}",
- "__END__" => "#{GREEN}__END__#{CLEAR}",
- "foo\n__END__\nbar" => "foo\n#{GREEN}__END__#{CLEAR}\nbar",
- "foo\n<<A\0\0bar\nA\nbaz" => "foo\n#{RED}<<A#{CLEAR}^@^@bar\n#{RED}A#{CLEAR}\nbaz",
- "<<A+1\nA" => "#{RED}<<A#{CLEAR}+#{BLUE}#{BOLD}1#{CLEAR}\n#{RED}A#{CLEAR}",
- }
-
- tests.merge!({
- "4.5.6" => "#{MAGENTA}#{BOLD}4.5#{CLEAR}#{RED}#{REVERSE}.6#{CLEAR}",
- "\e[0m\n" => "#{RED}#{REVERSE}^[#{CLEAR}[#{BLUE}#{BOLD}0#{CLEAR}#{RED}#{REVERSE}m#{CLEAR}\n",
- "<<EOS\nhere\nEOS" => "#{RED}<<EOS#{CLEAR}\n#{RED}here#{CLEAR}\n#{RED}EOS#{CLEAR}",
- })
-
- # specific to Ruby 3.0+
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0')
- tests.merge!({
- "[1]]]\u0013" => "[#{BLUE}#{BOLD}1#{CLEAR}]#{RED}#{REVERSE}]#{CLEAR}#{RED}#{REVERSE}]#{CLEAR}#{RED}#{REVERSE}^S#{CLEAR}",
- })
- tests.merge!({
- "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}) #{RED}#{REVERSE}end#{CLEAR}",
- "nil = 1" => "#{RED}#{REVERSE}nil#{CLEAR} = #{BLUE}#{BOLD}1#{CLEAR}",
- "alias $x $1" => "#{GREEN}alias#{CLEAR} #{GREEN}#{BOLD}$x#{CLEAR} #{RED}#{REVERSE}$1#{CLEAR}",
- "class bad; end" => "#{GREEN}class#{CLEAR} #{RED}#{REVERSE}bad#{CLEAR}; #{GREEN}end#{CLEAR}",
- "def req(@a) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}@a#{CLEAR}) #{GREEN}end#{CLEAR}",
- })
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.2.0')
- tests.merge!({
- "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}#{RED}#{REVERSE})#{CLEAR} #{RED}#{REVERSE}end#{CLEAR}",
- })
- end
- else
- tests.merge!({
- "[1]]]\u0013" => "[#{BLUE}#{BOLD}1#{CLEAR}]#{RED}#{REVERSE}]#{CLEAR}]^S",
- "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}) end",
- "nil = 1" => "#{CYAN}#{BOLD}nil#{CLEAR} = #{BLUE}#{BOLD}1#{CLEAR}",
- "alias $x $1" => "#{GREEN}alias#{CLEAR} #{GREEN}#{BOLD}$x#{CLEAR} #{GREEN}#{BOLD}$1#{CLEAR}",
- "class bad; end" => "#{GREEN}class#{CLEAR} bad; #{GREEN}end#{CLEAR}",
- "def req(@a) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(@a) #{GREEN}end#{CLEAR}",
- })
- end
-
- tests.each do |code, result|
- assert_equal_with_term(result, code, complete: true)
- assert_equal_with_term(result, code, complete: false)
-
- assert_equal_with_term(code, code, complete: true, tty: false)
- assert_equal_with_term(code, code, complete: false, tty: false)
-
- assert_equal_with_term(code, code, complete: true, colorable: false)
-
- assert_equal_with_term(code, code, complete: false, colorable: false)
-
- assert_equal_with_term(result, code, complete: true, tty: false, colorable: true)
-
- assert_equal_with_term(result, code, complete: false, tty: false, colorable: true)
- end
- end
-
- def test_colorize_code_with_local_variables
- code = "a /(b +1)/i"
- result_without_lvars = "a #{RED}#{BOLD}/#{CLEAR}#{RED}(b +1)#{CLEAR}#{RED}#{BOLD}/i#{CLEAR}"
- result_with_lvar = "a /(b #{BLUE}#{BOLD}+1#{CLEAR})/i"
- result_with_lvars = "a /(b +#{BLUE}#{BOLD}1#{CLEAR})/i"
-
- assert_equal_with_term(result_without_lvars, code)
- assert_equal_with_term(result_with_lvar, code, local_variables: ['a'])
- assert_equal_with_term(result_with_lvars, code, local_variables: ['a', 'b'])
- end
-
- def test_colorize_code_complete_true
- # `complete: true` behaviors. Warn end-of-file.
- {
- "'foo' + 'bar" => "#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}'#{CLEAR}#{RED}#{REVERSE}bar#{CLEAR}",
- "('foo" => "(#{RED}#{BOLD}'#{CLEAR}#{RED}#{REVERSE}foo#{CLEAR}",
- }.each do |code, result|
- assert_equal_with_term(result, code, complete: true)
-
- assert_equal_with_term(code, code, complete: true, tty: false)
-
- assert_equal_with_term(code, code, complete: true, colorable: false)
-
- assert_equal_with_term(result, code, complete: true, tty: false, colorable: true)
- end
- end
-
- def test_colorize_code_complete_false
- # `complete: false` behaviors. Do not warn end-of-file.
- {
- "'foo' + 'bar" => "#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}'#{CLEAR}#{RED}bar#{CLEAR}",
- "('foo" => "(#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}",
- }.each do |code, result|
- assert_equal_with_term(result, code, complete: false)
-
- assert_equal_with_term(code, code, complete: false, tty: false)
-
- assert_equal_with_term(code, code, complete: false, colorable: false)
-
- assert_equal_with_term(result, code, complete: false, tty: false, colorable: true)
- end
- end
-
- def test_inspect_colorable
- {
- 1 => true,
- 2.3 => true,
- ['foo', :bar] => true,
- (a = []; a << a; a) => false,
- (h = {}; h[h] = h; h) => false,
- { a: 4 } => true,
- /reg/ => true,
- (1..3) => true,
- Object.new => false,
- Struct => true,
- Test => true,
- Struct.new(:a) => false,
- Struct.new(:a).new(1) => false,
- }.each do |object, result|
- assert_equal(result, IRB::Color.inspect_colorable?(object), "Case: inspect_colorable?(#{object.inspect})")
- end
- end
-
- private
-
- def with_term(tty: true)
- stdout = $stdout
- io = StringIO.new
- def io.tty?; true; end if tty
- $stdout = io
-
- env = ENV.to_h.dup
- ENV['TERM'] = 'xterm-256color'
-
- yield
- ensure
- $stdout = stdout
- ENV.replace(env) if env
- end
-
- def assert_equal_with_term(result, code, seq: nil, tty: true, **opts)
- actual = with_term(tty: tty) do
- if seq
- IRB::Color.colorize(code, seq, **opts)
- else
- IRB::Color.colorize_code(code, **opts)
- end
- end
- message = -> {
- args = [code.dump]
- args << seq.inspect if seq
- opts.each {|kwd, val| args << "#{kwd}: #{val}"}
- "Case: colorize#{seq ? "" : "_code"}(#{args.join(', ')})\nResult: #{humanized_literal(actual)}"
- }
- assert_equal(result, actual, message)
- end
-
- def humanized_literal(str)
- str
- .gsub(CLEAR, '@@@{CLEAR}')
- .gsub(BOLD, '@@@{BOLD}')
- .gsub(UNDERLINE, '@@@{UNDERLINE}')
- .gsub(REVERSE, '@@@{REVERSE}')
- .gsub(RED, '@@@{RED}')
- .gsub(GREEN, '@@@{GREEN}')
- .gsub(YELLOW, '@@@{YELLOW}')
- .gsub(BLUE, '@@@{BLUE}')
- .gsub(MAGENTA, '@@@{MAGENTA}')
- .gsub(CYAN, '@@@{CYAN}')
- .dump.gsub(/@@@/, '#')
- end
- end
-end
diff --git a/test/irb/test_color_printer.rb b/test/irb/test_color_printer.rb
deleted file mode 100644
index 95d08e19e3..0000000000
--- a/test/irb/test_color_printer.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: false
-require 'irb/color_printer'
-require 'stringio'
-
-require_relative "helper"
-
-module TestIRB
- class ColorPrinterTest < TestCase
- CLEAR = "\e[0m"
- BOLD = "\e[1m"
- RED = "\e[31m"
- GREEN = "\e[32m"
- BLUE = "\e[34m"
- CYAN = "\e[36m"
-
- def setup
- super
- if IRB.respond_to?(:conf)
- @colorize, IRB.conf[:USE_COLORIZE] = IRB.conf[:USE_COLORIZE], true
- end
- @get_screen_size = Reline.method(:get_screen_size)
- Reline.instance_eval { undef :get_screen_size }
- def Reline.get_screen_size
- [36, 80]
- end
- end
-
- def teardown
- Reline.instance_eval { undef :get_screen_size }
- Reline.define_singleton_method(:get_screen_size, @get_screen_size)
- if instance_variable_defined?(:@colorize)
- IRB.conf[:USE_COLORIZE] = @colorize
- end
- super
- end
-
- IRBTestColorPrinter = Struct.new(:a)
-
- def test_color_printer
- {
- 1 => "#{BLUE}#{BOLD}1#{CLEAR}\n",
- "a\nb" => %[#{RED}#{BOLD}"#{CLEAR}#{RED}a\\nb#{CLEAR}#{RED}#{BOLD}"#{CLEAR}\n],
- IRBTestColorPrinter.new('test') => "#{GREEN}#<struct TestIRB::ColorPrinterTest::IRBTestColorPrinter#{CLEAR} a#{GREEN}=#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}#{RED}test#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}#{GREEN}>#{CLEAR}\n",
- Ripper::Lexer.new('1').scan => "[#{GREEN}#<Ripper::Lexer::Elem:#{CLEAR} on_int@1:0 END token: #{RED}#{BOLD}\"#{CLEAR}#{RED}1#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}#{GREEN}>#{CLEAR}]\n",
- Class.new{define_method(:pretty_print){|q| q.text("[__FILE__, __LINE__, __ENCODING__]")}}.new => "[#{CYAN}#{BOLD}__FILE__#{CLEAR}, #{CYAN}#{BOLD}__LINE__#{CLEAR}, #{CYAN}#{BOLD}__ENCODING__#{CLEAR}]\n",
- }.each do |object, result|
- actual = with_term { IRB::ColorPrinter.pp(object, '') }
- assert_equal(result, actual, "Case: IRB::ColorPrinter.pp(#{object.inspect}, '')")
- end
- end
-
- def test_colorization_disabled
- {
- 1 => "1\n",
- "a\nb" => %["a\\nb"\n],
- IRBTestColorPrinter.new('test') => "#<struct TestIRB::ColorPrinterTest::IRBTestColorPrinter a=\"test\">\n",
- Ripper::Lexer.new('1').scan => "[#<Ripper::Lexer::Elem: on_int@1:0 END token: \"1\">]\n",
- Class.new{define_method(:pretty_print){|q| q.text("[__FILE__, __LINE__, __ENCODING__]")}}.new => "[__FILE__, __LINE__, __ENCODING__]\n",
- }.each do |object, result|
- actual = with_term { IRB::ColorPrinter.pp(object, '', colorize: false) }
- assert_equal(result, actual, "Case: IRB::ColorPrinter.pp(#{object.inspect}, '')")
- end
- end
-
- private
-
- def with_term
- stdout = $stdout
- io = StringIO.new
- def io.tty?; true; end
- $stdout = io
-
- env = ENV.to_h.dup
- ENV['TERM'] = 'xterm-256color'
-
- yield
- ensure
- $stdout = stdout
- ENV.replace(env) if env
- end
- end
-end
diff --git a/test/irb/test_command.rb b/test/irb/test_command.rb
deleted file mode 100644
index ec2d1f92df..0000000000
--- a/test/irb/test_command.rb
+++ /dev/null
@@ -1,1001 +0,0 @@
-# frozen_string_literal: false
-require "irb"
-
-require_relative "helper"
-
-module TestIRB
- # In case when RDoc becomes a bundled gem, we may not be able to load it when running tests
- # in ruby/ruby
- HAS_RDOC = begin
- require "rdoc"
- true
- rescue LoadError
- false
- end
-
- class CommandTestCase < TestCase
- def setup
- @pwd = Dir.pwd
- @tmpdir = File.join(Dir.tmpdir, "test_reline_config_#{$$}")
- begin
- Dir.mkdir(@tmpdir)
- rescue Errno::EEXIST
- FileUtils.rm_rf(@tmpdir)
- Dir.mkdir(@tmpdir)
- end
- Dir.chdir(@tmpdir)
- setup_envs(home: @tmpdir)
- save_encodings
- IRB.instance_variable_get(:@CONF).clear
- IRB.instance_variable_set(:@existing_rc_name_generators, nil)
- @is_win = (RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/)
- end
-
- def teardown
- teardown_envs
- Dir.chdir(@pwd)
- FileUtils.rm_rf(@tmpdir)
- restore_encodings
- end
-
- def execute_lines(*lines, conf: {}, main: self, irb_path: nil)
- capture_output do
- IRB.init_config(nil)
- IRB.conf[:VERBOSE] = false
- IRB.conf[:PROMPT_MODE] = :SIMPLE
- IRB.conf[:USE_PAGER] = false
- IRB.conf.merge!(conf)
- input = TestInputMethod.new(lines)
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
- irb.context.return_format = "=> %s\n"
- irb.context.irb_path = irb_path if irb_path
- IRB.conf[:MAIN_CONTEXT] = irb.context
- irb.eval_input
- end
- end
- end
-
- class FrozenObjectTest < CommandTestCase
- def test_calling_command_on_a_frozen_main
- main = Object.new.freeze
-
- out, err = execute_lines(
- "irb_info",
- main: main
- )
- assert_empty(err)
- assert_match(/RUBY_PLATFORM/, out)
- end
- end
-
- class InfoTest < CommandTestCase
- def setup
- super
- @locals_backup = ENV.delete("LANG"), ENV.delete("LC_ALL")
- end
-
- def teardown
- super
- ENV["LANG"], ENV["LC_ALL"] = @locals_backup
- end
-
- def test_irb_info_multiline
- FileUtils.touch("#{@tmpdir}/.inputrc")
- FileUtils.touch("#{@tmpdir}/.irbrc")
- FileUtils.touch("#{@tmpdir}/_irbrc")
-
- out, err = execute_lines(
- "irb_info",
- conf: { USE_MULTILINE: true, USE_SINGLELINE: false }
- )
-
- expected = %r{
- Ruby\sversion:\s.+\n
- IRB\sversion:\sirb\s.+\n
- InputMethod:\sAbstract\sInputMethod\n
- Completion: .+\n
- \.irbrc\spaths:.*\.irbrc.*_irbrc\n
- RUBY_PLATFORM:\s.+\n
- East\sAsian\sAmbiguous\sWidth:\s\d\n
- #{@is_win ? 'Code\spage:\s\d+\n' : ''}
- }x
-
- assert_empty err
- assert_match expected, out
- end
-
- def test_irb_info_singleline
- FileUtils.touch("#{@tmpdir}/.inputrc")
- FileUtils.touch("#{@tmpdir}/.irbrc")
-
- out, err = execute_lines(
- "irb_info",
- conf: { USE_MULTILINE: false, USE_SINGLELINE: true }
- )
-
- expected = %r{
- Ruby\sversion:\s.+\n
- IRB\sversion:\sirb\s.+\n
- InputMethod:\sAbstract\sInputMethod\n
- Completion: .+\n
- \.irbrc\spaths:\s.+\n
- RUBY_PLATFORM:\s.+\n
- East\sAsian\sAmbiguous\sWidth:\s\d\n
- #{@is_win ? 'Code\spage:\s\d+\n' : ''}
- }x
-
- assert_empty err
- assert_match expected, out
- end
-
- def test_irb_info_multiline_without_rc_files
- inputrc_backup = ENV["INPUTRC"]
- ENV["INPUTRC"] = "unknown_inpurc"
- ext_backup = IRB::IRBRC_EXT
- IRB.__send__(:remove_const, :IRBRC_EXT)
- IRB.const_set(:IRBRC_EXT, "unknown_ext")
-
- out, err = execute_lines(
- "irb_info",
- conf: { USE_MULTILINE: true, USE_SINGLELINE: false }
- )
-
- expected = %r{
- Ruby\sversion:\s.+\n
- IRB\sversion:\sirb\s.+\n
- InputMethod:\sAbstract\sInputMethod\n
- Completion: .+\n
- RUBY_PLATFORM:\s.+\n
- East\sAsian\sAmbiguous\sWidth:\s\d\n
- #{@is_win ? 'Code\spage:\s\d+\n' : ''}
- }x
-
- assert_empty err
- assert_match expected, out
- ensure
- ENV["INPUTRC"] = inputrc_backup
- IRB.__send__(:remove_const, :IRBRC_EXT)
- IRB.const_set(:IRBRC_EXT, ext_backup)
- end
-
- def test_irb_info_singleline_without_rc_files
- inputrc_backup = ENV["INPUTRC"]
- ENV["INPUTRC"] = "unknown_inpurc"
- ext_backup = IRB::IRBRC_EXT
- IRB.__send__(:remove_const, :IRBRC_EXT)
- IRB.const_set(:IRBRC_EXT, "unknown_ext")
-
- out, err = execute_lines(
- "irb_info",
- conf: { USE_MULTILINE: false, USE_SINGLELINE: true }
- )
-
- expected = %r{
- Ruby\sversion:\s.+\n
- IRB\sversion:\sirb\s.+\n
- InputMethod:\sAbstract\sInputMethod\n
- Completion: .+\n
- RUBY_PLATFORM:\s.+\n
- East\sAsian\sAmbiguous\sWidth:\s\d\n
- #{@is_win ? 'Code\spage:\s\d+\n' : ''}
- }x
-
- assert_empty err
- assert_match expected, out
- ensure
- ENV["INPUTRC"] = inputrc_backup
- IRB.__send__(:remove_const, :IRBRC_EXT)
- IRB.const_set(:IRBRC_EXT, ext_backup)
- end
-
- def test_irb_info_lang
- FileUtils.touch("#{@tmpdir}/.inputrc")
- FileUtils.touch("#{@tmpdir}/.irbrc")
- ENV["LANG"] = "ja_JP.UTF-8"
- ENV["LC_ALL"] = "en_US.UTF-8"
-
- out, err = execute_lines(
- "irb_info",
- conf: { USE_MULTILINE: true, USE_SINGLELINE: false }
- )
-
- expected = %r{
- Ruby\sversion: .+\n
- IRB\sversion:\sirb .+\n
- InputMethod:\sAbstract\sInputMethod\n
- Completion: .+\n
- \.irbrc\spaths: .+\n
- RUBY_PLATFORM: .+\n
- LANG\senv:\sja_JP\.UTF-8\n
- LC_ALL\senv:\sen_US\.UTF-8\n
- East\sAsian\sAmbiguous\sWidth:\s\d\n
- }x
-
- assert_empty err
- assert_match expected, out
- end
- end
-
- class MeasureTest < CommandTestCase
- def test_measure
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: false
- }
-
- c = Class.new(Object)
- out, err = execute_lines(
- "measure\n",
- "3\n",
- "measure :off\n",
- "3\n",
- "measure :on\n",
- "3\n",
- "measure :off\n",
- "3\n",
- conf: conf,
- main: c
- )
-
- assert_empty err
- assert_match(/\A(TIME is added\.\nprocessing time: .+\n=> 3\n=> 3\n){2}/, out)
- assert_empty(c.class_variables)
- end
-
- def test_measure_keeps_previous_value
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: false
- }
-
- c = Class.new(Object)
- out, err = execute_lines(
- "measure\n",
- "3\n",
- "_\n",
- conf: conf,
- main: c
- )
-
- assert_empty err
- assert_match(/\ATIME is added\.\nprocessing time: .+\n=> 3\nprocessing time: .+\n=> 3/, out)
- assert_empty(c.class_variables)
- end
-
- def test_measure_enabled_by_rc
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: true
- }
-
- out, err = execute_lines(
- "3\n",
- "measure :off\n",
- "3\n",
- conf: conf,
- )
-
- assert_empty err
- assert_match(/\Aprocessing time: .+\n=> 3\n=> 3\n/, out)
- end
-
- def test_measure_enabled_by_rc_with_custom
- measuring_proc = proc { |line, line_no, &block|
- time = Time.now
- result = block.()
- puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE]
- result
- }
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: true,
- MEASURE_PROC: { CUSTOM: measuring_proc }
- }
-
- out, err = execute_lines(
- "3\n",
- "measure :off\n",
- "3\n",
- conf: conf,
- )
- assert_empty err
- assert_match(/\Acustom processing time: .+\n=> 3\n=> 3\n/, out)
- end
-
- def test_measure_with_custom
- measuring_proc = proc { |line, line_no, &block|
- time = Time.now
- result = block.()
- puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE]
- result
- }
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: false,
- MEASURE_PROC: { CUSTOM: measuring_proc }
- }
- out, err = execute_lines(
- "3\n",
- "measure\n",
- "3\n",
- "measure :off\n",
- "3\n",
- conf: conf
- )
-
- assert_empty err
- assert_match(/\A=> 3\nCUSTOM is added\.\ncustom processing time: .+\n=> 3\n=> 3\n/, out)
- end
-
- def test_measure_toggle
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: false,
- MEASURE_PROC: {
- FOO: proc { |&block| puts 'foo'; block.call },
- BAR: proc { |&block| puts 'bar'; block.call }
- }
- }
- out, err = execute_lines(
- "measure :foo\n",
- "1\n",
- "measure :on, :bar\n",
- "2\n",
- "measure :off, :foo\n",
- "3\n",
- "measure :off, :bar\n",
- "4\n",
- conf: conf
- )
-
- assert_empty err
- assert_match(/\AFOO is added\.\nfoo\n=> 1\nBAR is added\.\nbar\nfoo\n=> 2\nbar\n=> 3\n=> 4\n/, out)
- end
-
- def test_measure_with_proc_warning
- conf = {
- PROMPT: {
- DEFAULT: {
- PROMPT_I: '> ',
- PROMPT_S: '> ',
- PROMPT_C: '> '
- }
- },
- PROMPT_MODE: :DEFAULT,
- MEASURE: false,
- }
- c = Class.new(Object)
- out, err = execute_lines(
- "3\n",
- "measure do\n",
- "3\n",
- conf: conf,
- main: c
- )
-
- assert_match(/to add custom measure/, err)
- assert_match(/\A=> 3\n=> 3\n/, out)
- assert_empty(c.class_variables)
- end
- end
-
- class IrbSourceTest < CommandTestCase
- def test_irb_source
- File.write("#{@tmpdir}/a.rb", "a = 'hi'\n")
- out, err = execute_lines(
- "a = 'bug17564'\n",
- "a\n",
- "irb_source '#{@tmpdir}/a.rb'\n",
- "a\n",
- )
- assert_empty err
- assert_pattern_list([
- /=> "bug17564"\n/,
- /=> "bug17564"\n/,
- / => "hi"\n/,
- / => "hi"\n/,
- ], out)
- end
-
- def test_irb_source_without_argument
- out, err = execute_lines(
- "irb_source\n",
- )
- assert_empty err
- assert_match(/Please specify the file name./, out)
- end
- end
-
- class IrbLoadTest < CommandTestCase
- def test_irb_load
- File.write("#{@tmpdir}/a.rb", "a = 'hi'\n")
- out, err = execute_lines(
- "a = 'bug17564'\n",
- "a\n",
- "irb_load '#{@tmpdir}/a.rb'\n",
- "a\n",
- )
- assert_empty err
- assert_pattern_list([
- /=> "bug17564"\n/,
- /=> "bug17564"\n/,
- / => "hi"\n/,
- / => "bug17564"\n/,
- ], out)
- end
-
- def test_irb_load_without_argument
- out, err = execute_lines(
- "irb_load\n",
- )
-
- assert_empty err
- assert_match(/Please specify the file name./, out)
- end
- end
-
- class WorkspaceCommandTestCase < CommandTestCase
- def setup
- super
- # create Foo under the test class's namespace so it doesn't pollute global namespace
- self.class.class_eval <<~RUBY
- class Foo; end
- RUBY
- end
- end
-
- class CwwsTest < WorkspaceCommandTestCase
- def test_cwws_returns_the_current_workspace_object
- out, err = execute_lines(
- "cwws"
- )
-
- assert_empty err
- assert_include(out, "Current workspace: #{self}")
- end
- end
-
- class PushwsTest < WorkspaceCommandTestCase
- def test_pushws_switches_to_new_workspace_and_pushes_the_current_one_to_the_stack
- out, err = execute_lines(
- "pushws #{self.class}::Foo.new",
- "self.class",
- "popws",
- "self.class"
- )
- assert_empty err
-
- assert_match(/=> #{self.class}::Foo\n/, out)
- assert_match(/=> #{self.class}\n$/, out)
- end
-
- def test_pushws_extends_the_new_workspace_with_command_bundle
- out, err = execute_lines(
- "pushws Object.new",
- "self.singleton_class.ancestors"
- )
- assert_empty err
- assert_include(out, "IRB::ExtendCommandBundle")
- end
-
- def test_pushws_prints_workspace_stack_when_no_arg_is_given
- out, err = execute_lines(
- "pushws",
- )
- assert_empty err
- assert_include(out, "[#<TestIRB::PushwsTe...>]")
- end
-
- def test_pushws_without_argument_swaps_the_top_two_workspaces
- out, err = execute_lines(
- "pushws #{self.class}::Foo.new",
- "self.class",
- "pushws",
- "self.class"
- )
- assert_empty err
- assert_match(/=> #{self.class}::Foo\n/, out)
- assert_match(/=> #{self.class}\n$/, out)
- end
- end
-
- class WorkspacesTest < WorkspaceCommandTestCase
- def test_workspaces_returns_the_stack_of_workspaces
- out, err = execute_lines(
- "pushws #{self.class}::Foo.new\n",
- "workspaces",
- )
-
- assert_empty err
- assert_match(/\[#<TestIRB::Workspac...>, #<TestIRB::Workspac...>\]\n/, out)
- end
- end
-
- class PopwsTest < WorkspaceCommandTestCase
- def test_popws_replaces_the_current_workspace_with_the_previous_one
- out, err = execute_lines(
- "pushws Foo.new\n",
- "popws\n",
- "cwws\n",
- "self.class",
- )
- assert_empty err
- assert_include(out, "=> #{self.class}")
- end
-
- def test_popws_prints_help_message_if_the_workspace_is_empty
- out, err = execute_lines(
- "popws\n",
- )
- assert_empty err
- assert_match(/\[#<TestIRB::PopwsTes...>\]\n/, out)
- end
- end
-
- class ChwsTest < WorkspaceCommandTestCase
- def test_chws_replaces_the_current_workspace
- out, err = execute_lines(
- "chws #{self.class}::Foo.new\n",
- "cwws\n",
- "self.class\n"
- )
- assert_empty err
- assert_include(out, "Current workspace: #<#{self.class.name}::Foo")
- assert_include(out, "=> #{self.class}::Foo")
- end
-
- def test_chws_does_nothing_when_receiving_no_argument
- out, err = execute_lines(
- "chws\n",
- )
- assert_empty err
- assert_include(out, "Current workspace: #{self}")
- end
- end
-
- class WhereamiTest < CommandTestCase
- def test_whereami
- out, err = execute_lines(
- "whereami\n",
- )
- assert_empty err
- assert_match(/^From: .+ @ line \d+ :\n/, out)
- end
-
- def test_whereami_alias
- out, err = execute_lines(
- "@\n",
- )
- assert_empty err
- assert_match(/^From: .+ @ line \d+ :\n/, out)
- end
- end
-
- class LsTest < CommandTestCase
- def test_ls
- out, err = execute_lines(
- "class P\n",
- " def m() end\n",
- " def m2() end\n",
- "end\n",
-
- "class C < P\n",
- " def m1() end\n",
- " def m2() end\n",
- "end\n",
-
- "module M\n",
- " def m1() end\n",
- " def m3() end\n",
- "end\n",
-
- "module M2\n",
- " include M\n",
- " def m4() end\n",
- "end\n",
-
- "obj = C.new\n",
- "obj.instance_variable_set(:@a, 1)\n",
- "obj.extend M2\n",
- "def obj.m5() end\n",
- "ls obj\n",
- )
-
- assert_empty err
- assert_match(/^instance variables:\s+@a\n/m, out)
- assert_match(/P#methods:\s+m\n/m, out)
- assert_match(/C#methods:\s+m2\n/m, out)
- assert_match(/M#methods:\s+m1\s+m3\n/m, out)
- assert_match(/M2#methods:\s+m4\n/m, out)
- assert_match(/C.methods:\s+m5\n/m, out)
- end
-
- def test_ls_class
- out, err = execute_lines(
- "module M1\n",
- " def m2; end\n",
- " def m3; end\n",
- "end\n",
-
- "class C1\n",
- " def m1; end\n",
- " def m2; end\n",
- "end\n",
-
- "class C2 < C1\n",
- " include M1\n",
- " def m3; end\n",
- " def m4; end\n",
- " def self.m3; end\n",
- " def self.m5; end\n",
- "end\n",
- "ls C2"
- )
-
- assert_empty err
- assert_match(/C2.methods:\s+m3\s+m5\n/, out)
- assert_match(/C2#methods:\s+m3\s+m4\n.*M1#methods:\s+m2\n.*C1#methods:\s+m1\n/, out)
- assert_not_match(/Module#methods/, out)
- assert_not_match(/Class#methods/, out)
- end
-
- def test_ls_module
- out, err = execute_lines(
- "module M1\n",
- " def m1; end\n",
- " def m2; end\n",
- "end\n",
-
- "module M2\n",
- " include M1\n",
- " def m1; end\n",
- " def m3; end\n",
- " def self.m4; end\n",
- "end\n",
- "ls M2"
- )
-
- assert_empty err
- assert_match(/M2\.methods:\s+m4\n/, out)
- assert_match(/M2#methods:\s+m1\s+m3\n.*M1#methods:\s+m2\n/, out)
- assert_not_match(/Module#methods/, out)
- end
-
- def test_ls_instance
- out, err = execute_lines(
- "class Foo; def bar; end; end\n",
- "ls Foo.new"
- )
-
- assert_empty err
- assert_match(/Foo#methods:\s+bar/, out)
- # don't duplicate
- assert_not_match(/Foo#methods:\s+bar\n.*Foo#methods/, out)
- end
-
- def test_ls_grep
- out, err = execute_lines("ls 42\n")
- assert_empty err
- assert_match(/times/, out)
- assert_match(/polar/, out)
-
- [
- "ls 42, grep: /times/\n",
- "ls 42 -g times\n",
- "ls 42 -G times\n",
- ].each do |line|
- out, err = execute_lines(line)
- assert_empty err
- assert_match(/times/, out)
- assert_not_match(/polar/, out)
- end
- end
-
- def test_ls_grep_empty
- out, err = execute_lines("ls\n")
- assert_empty err
- assert_match(/assert/, out)
- assert_match(/refute/, out)
-
- [
- "ls grep: /assert/\n",
- "ls -g assert\n",
- "ls -G assert\n",
- ].each do |line|
- out, err = execute_lines(line)
- assert_empty err
- assert_match(/assert/, out)
- assert_not_match(/refute/, out)
- end
- end
-
- def test_ls_with_eval_error
- [
- "ls raise(Exception,'foo')\n",
- "ls raise(Exception,'foo'), grep: /./\n",
- "ls Integer, grep: raise(Exception,'foo')\n",
- ].each do |line|
- out, err = execute_lines(line)
- assert_empty err
- assert_match(/Exception: foo/, out)
- assert_not_match(/Maybe IRB bug!/, out)
- end
- end
-
- def test_ls_with_no_singleton_class
- out, err = execute_lines(
- "ls 42",
- )
- assert_empty err
- assert_match(/Comparable#methods:\s+/, out)
- assert_match(/Numeric#methods:\s+/, out)
- assert_match(/Integer#methods:\s+/, out)
- end
- end
-
- class ShowDocTest < CommandTestCase
- if HAS_RDOC
- def test_show_doc
- out, err = execute_lines("show_doc String#gsub")
-
- # the former is what we'd get without document content installed, like on CI
- # the latter is what we may get locally
- possible_rdoc_output = [/Nothing known about String#gsub/, /gsub\(pattern\)/]
- assert_not_include err, "[Deprecation]"
- assert(possible_rdoc_output.any? { |output| output.match?(out) }, "Expect the `show_doc` command to match one of the possible outputs. Got:\n#{out}")
- ensure
- # this is the only way to reset the redefined method without coupling the test with its implementation
- EnvUtil.suppress_warning { load "irb/command/help.rb" }
- end
-
- def test_ri
- out, err = execute_lines("ri String#gsub")
-
- # the former is what we'd get without document content installed, like on CI
- # the latter is what we may get locally
- possible_rdoc_output = [/Nothing known about String#gsub/, /gsub\(pattern\)/]
- assert_not_include err, "[Deprecation]"
- assert(possible_rdoc_output.any? { |output| output.match?(out) }, "Expect the `ri` command to match one of the possible outputs. Got:\n#{out}")
- ensure
- # this is the only way to reset the redefined method without coupling the test with its implementation
- EnvUtil.suppress_warning { load "irb/command/help.rb" }
- end
- end
-
- def test_show_doc_without_rdoc
- _, err = without_rdoc do
- execute_lines("show_doc String#gsub")
- end
-
- assert_include(err, "Can't display document because `rdoc` is not installed.\n")
- ensure
- # this is the only way to reset the redefined method without coupling the test with its implementation
- EnvUtil.suppress_warning { load "irb/command/help.rb" }
- end
- end
-
- class EditTest < CommandTestCase
- def setup
- @original_visual = ENV["VISUAL"]
- @original_editor = ENV["EDITOR"]
- # noop the command so nothing gets executed
- ENV["VISUAL"] = ": code"
- ENV["EDITOR"] = ": code2"
- end
-
- def teardown
- ENV["VISUAL"] = @original_visual
- ENV["EDITOR"] = @original_editor
- end
-
- def test_edit_without_arg
- out, err = execute_lines(
- "edit",
- irb_path: __FILE__
- )
-
- assert_empty err
- assert_match("path: #{__FILE__}", out)
- assert_match("command: ': code'", out)
- end
-
- def test_edit_without_arg_and_non_existing_irb_path
- out, err = execute_lines(
- "edit",
- irb_path: '/path/to/file.rb(irb)'
- )
-
- assert_empty err
- assert_match(/Can not find file: \/path\/to\/file\.rb\(irb\)/, out)
- end
-
- def test_edit_with_path
- out, err = execute_lines(
- "edit #{__FILE__}"
- )
-
- assert_empty err
- assert_match("path: #{__FILE__}", out)
- assert_match("command: ': code'", out)
- end
-
- def test_edit_with_non_existing_path
- out, err = execute_lines(
- "edit test_cmd_non_existing_path.rb"
- )
-
- assert_empty err
- assert_match(/Can not find file: test_cmd_non_existing_path\.rb/, out)
- end
-
- def test_edit_with_constant
- out, err = execute_lines(
- "edit IRB::Irb"
- )
-
- assert_empty err
- assert_match(/path: .*\/lib\/irb\.rb/, out)
- assert_match("command: ': code'", out)
- end
-
- def test_edit_with_class_method
- out, err = execute_lines(
- "edit IRB.start"
- )
-
- assert_empty err
- assert_match(/path: .*\/lib\/irb\.rb/, out)
- assert_match("command: ': code'", out)
- end
-
- def test_edit_with_instance_method
- out, err = execute_lines(
- "edit IRB::Irb#run"
- )
-
- assert_empty err
- assert_match(/path: .*\/lib\/irb\.rb/, out)
- assert_match("command: ': code'", out)
- end
-
- def test_edit_with_editor_env_var
- ENV.delete("VISUAL")
-
- out, err = execute_lines(
- "edit",
- irb_path: __FILE__
- )
-
- assert_empty err
- assert_match("path: #{__FILE__}", out)
- assert_match("command: ': code2'", out)
- end
- end
-
- class HistoryCmdTest < CommandTestCase
- def teardown
- TestInputMethod.send(:remove_const, "HISTORY") if defined?(TestInputMethod::HISTORY)
- super
- end
-
- def test_history
- TestInputMethod.const_set("HISTORY", %w[foo bar baz])
-
- out, err = without_rdoc do
- execute_lines("history")
- end
-
- assert_include(out, <<~EOF)
- 2: baz
- 1: bar
- 0: foo
- EOF
- assert_empty err
- end
-
- def test_multiline_history_with_truncation
- TestInputMethod.const_set("HISTORY", ["foo", "bar", <<~INPUT])
- [].each do |x|
- puts x
- end
- INPUT
-
- out, err = without_rdoc do
- execute_lines("hist")
- end
-
- assert_include(out, <<~EOF)
- 2: [].each do |x|
- puts x
- ...
- 1: bar
- 0: foo
- EOF
- assert_empty err
- end
-
- def test_history_grep
- TestInputMethod.const_set("HISTORY", ["foo", "bar", <<~INPUT])
- [].each do |x|
- puts x
- end
- INPUT
-
- out, err = without_rdoc do
- execute_lines("hist -g each\n")
- end
-
- assert_include(out, <<~EOF)
- 2: [].each do |x|
- puts x
- ...
- EOF
- assert_not_include(out, <<~EOF)
- foo
- EOF
- assert_not_include(out, <<~EOF)
- bar
- EOF
- assert_empty err
- end
-
- end
-
- class HelperMethodInsallTest < CommandTestCase
- def test_helper_method_install
- IRB::ExtendCommandBundle.module_eval do
- def foobar
- "test_helper_method_foobar"
- end
- end
-
- out, err = execute_lines("foobar.upcase")
- assert_empty err
- assert_include(out, '=> "TEST_HELPER_METHOD_FOOBAR"')
- ensure
- IRB::ExtendCommandBundle.remove_method :foobar
- end
- end
-end
diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb
deleted file mode 100644
index c9a0eafa3d..0000000000
--- a/test/irb/test_completion.rb
+++ /dev/null
@@ -1,317 +0,0 @@
-# frozen_string_literal: false
-require "pathname"
-require "irb"
-
-require_relative "helper"
-
-module TestIRB
- class CompletionTest < TestCase
- def completion_candidates(target, bind)
- IRB::RegexpCompletor.new.completion_candidates('', target, '', bind: bind)
- end
-
- def doc_namespace(target, bind)
- IRB::RegexpCompletor.new.doc_namespace('', target, '', bind: bind)
- end
-
- class CommandCompletionTest < CompletionTest
- def test_command_completion
- completor = IRB::RegexpCompletor.new
- binding.eval("some_var = 1")
- # completion for help command's argument should only include command names
- assert_include(completor.completion_candidates('help ', 's', '', bind: binding), 'show_source')
- assert_not_include(completor.completion_candidates('help ', 's', '', bind: binding), 'some_var')
-
- assert_include(completor.completion_candidates('', 'show_s', '', bind: binding), 'show_source')
- assert_not_include(completor.completion_candidates(';', 'show_s', '', bind: binding), 'show_source')
- end
- end
-
- class MethodCompletionTest < CompletionTest
- def test_complete_string
- assert_include(completion_candidates("'foo'.up", binding), "'foo'.upcase")
- # completing 'foo bar'.up
- assert_include(completion_candidates("bar'.up", binding), "bar'.upcase")
- assert_equal("String.upcase", doc_namespace("'foo'.upcase", binding))
- end
-
- def test_complete_regexp
- assert_include(completion_candidates("/foo/.ma", binding), "/foo/.match")
- # completing /foo bar/.ma
- assert_include(completion_candidates("bar/.ma", binding), "bar/.match")
- assert_equal("Regexp.match", doc_namespace("/foo/.match", binding))
- end
-
- def test_complete_array
- assert_include(completion_candidates("[].an", binding), "[].any?")
- assert_equal("Array.any?", doc_namespace("[].any?", binding))
- end
-
- def test_complete_hash_and_proc
- # hash
- assert_include(completion_candidates("{}.an", binding), "{}.any?")
- assert_equal(["Hash.any?", "Proc.any?"], doc_namespace("{}.any?", binding))
-
- # proc
- assert_include(completion_candidates("{}.bin", binding), "{}.binding")
- assert_equal(["Hash.binding", "Proc.binding"], doc_namespace("{}.binding", binding))
- end
-
- def test_complete_numeric
- assert_include(completion_candidates("1.positi", binding), "1.positive?")
- assert_equal("Integer.positive?", doc_namespace("1.positive?", binding))
-
- assert_include(completion_candidates("1r.positi", binding), "1r.positive?")
- assert_equal("Rational.positive?", doc_namespace("1r.positive?", binding))
-
- assert_include(completion_candidates("0xFFFF.positi", binding), "0xFFFF.positive?")
- assert_equal("Integer.positive?", doc_namespace("0xFFFF.positive?", binding))
-
- assert_empty(completion_candidates("1i.positi", binding))
- end
-
- def test_complete_symbol
- assert_include(completion_candidates(":foo.to_p", binding), ":foo.to_proc")
- assert_equal("Symbol.to_proc", doc_namespace(":foo.to_proc", binding))
- end
-
- def test_complete_class
- assert_include(completion_candidates("String.ne", binding), "String.new")
- assert_equal("String.new", doc_namespace("String.new", binding))
- end
- end
-
- class RequireComepletionTest < CompletionTest
- def test_complete_require
- candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
- %w['irb/init 'irb/ruby-lex].each do |word|
- assert_include candidates, word
- end
- # Test cache
- candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
- %w['irb/init 'irb/ruby-lex].each do |word|
- assert_include candidates, word
- end
- # Test string completion not disturbed by require completion
- candidates = IRB::RegexpCompletor.new.completion_candidates("'string ", "'.", "", bind: binding)
- assert_include candidates, "'.upcase"
- end
-
- def test_complete_require_with_pathname_in_load_path
- temp_dir = Dir.mktmpdir
- File.write(File.join(temp_dir, "foo.rb"), "test")
- test_path = Pathname.new(temp_dir)
- $LOAD_PATH << test_path
-
- candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
- assert_include candidates, "'foo"
- ensure
- $LOAD_PATH.pop if test_path
- FileUtils.remove_entry(temp_dir) if temp_dir
- end
-
- def test_complete_require_with_string_convertable_in_load_path
- temp_dir = Dir.mktmpdir
- File.write(File.join(temp_dir, "foo.rb"), "test")
- object = Object.new
- object.define_singleton_method(:to_s) { temp_dir }
- $LOAD_PATH << object
-
- candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
- assert_include candidates, "'foo"
- ensure
- $LOAD_PATH.pop if object
- FileUtils.remove_entry(temp_dir) if temp_dir
- end
-
- def test_complete_require_with_malformed_object_in_load_path
- object = Object.new
- def object.to_s; raise; end
- $LOAD_PATH << object
-
- assert_nothing_raised do
- IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
- end
- ensure
- $LOAD_PATH.pop if object
- end
-
- def test_complete_require_library_name_first
- # Test that library name is completed first with subdirectories
- candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
- assert_equal "'irb", candidates.first
- end
-
- def test_complete_require_relative
- candidates = Dir.chdir(__dir__ + "/../..") do
- IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding)
- end
- %w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
- assert_include candidates, word
- end
- # Test cache
- candidates = Dir.chdir(__dir__ + "/../..") do
- IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding)
- end
- %w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
- assert_include candidates, word
- end
- end
- end
-
- class VariableCompletionTest < CompletionTest
- def test_complete_variable
- # Bug fix issues https://github.com/ruby/irb/issues/368
- # Variables other than `str_example` and `@str_example` are defined to ensure that irb completion does not cause unintended behavior
- str_example = ''
- @str_example = ''
- private_methods = ''
- methods = ''
- global_variables = ''
- local_variables = ''
- instance_variables = ''
-
- # suppress "assigned but unused variable" warning
- str_example.clear
- @str_example.clear
- private_methods.clear
- methods.clear
- global_variables.clear
- local_variables.clear
- instance_variables.clear
-
- assert_include(completion_candidates("str_examp", binding), "str_example")
- assert_equal("String", doc_namespace("str_example", binding))
- assert_equal("String.to_s", doc_namespace("str_example.to_s", binding))
-
- assert_include(completion_candidates("@str_examp", binding), "@str_example")
- assert_equal("String", doc_namespace("@str_example", binding))
- assert_equal("String.to_s", doc_namespace("@str_example.to_s", binding))
- end
-
- def test_complete_sort_variables
- xzy, xzy_1, xzy2 = '', '', ''
-
- xzy.clear
- xzy_1.clear
- xzy2.clear
-
- candidates = completion_candidates("xz", binding)
- assert_equal(%w[xzy xzy2 xzy_1], candidates)
- end
- end
-
- class ConstantCompletionTest < CompletionTest
- class Foo
- B3 = 1
- B1 = 1
- B2 = 1
- end
-
- def test_complete_constants
- assert_equal(["Foo"], completion_candidates("Fo", binding))
- assert_equal(["Foo::B1", "Foo::B2", "Foo::B3"], completion_candidates("Foo::B", binding))
- assert_equal(["Foo::B1.positive?"], completion_candidates("Foo::B1.pos", binding))
-
- assert_equal(["::Forwardable"], completion_candidates("::Fo", binding))
- assert_equal("Forwardable", doc_namespace("::Forwardable", binding))
- end
- end
-
- def test_not_completing_empty_string
- assert_equal([], completion_candidates("", binding))
- assert_equal([], completion_candidates(" ", binding))
- assert_equal([], completion_candidates("\t", binding))
- assert_equal(nil, doc_namespace("", binding))
- end
-
- def test_complete_symbol
- symbols = %w"UTF-16LE UTF-7".map do |enc|
- "K".force_encoding(enc).to_sym
- rescue
- end
- symbols += [:aiueo, :"aiu eo"]
- candidates = completion_candidates(":a", binding)
- assert_include(candidates, ":aiueo")
- assert_not_include(candidates, ":aiu eo")
- assert_empty(completion_candidates(":irb_unknown_symbol_abcdefg", binding))
- # Do not complete empty symbol for performance reason
- assert_empty(completion_candidates(":", binding))
- end
-
- def test_complete_invalid_three_colons
- assert_empty(completion_candidates(":::A", binding))
- assert_empty(completion_candidates(":::", binding))
- end
-
- def test_complete_absolute_constants_with_special_characters
- assert_empty(completion_candidates("::A:", binding))
- assert_empty(completion_candidates("::A.", binding))
- assert_empty(completion_candidates("::A(", binding))
- assert_empty(completion_candidates("::A)", binding))
- assert_empty(completion_candidates("::A[", binding))
- end
-
- def test_complete_reserved_words
- candidates = completion_candidates("de", binding)
- %w[def defined?].each do |word|
- assert_include candidates, word
- end
-
- candidates = completion_candidates("__", binding)
- %w[__ENCODING__ __LINE__ __FILE__].each do |word|
- assert_include candidates, word
- end
- end
-
- def test_complete_methods
- obj = Object.new
- obj.singleton_class.class_eval {
- def public_hoge; end
- private def private_hoge; end
-
- # Support for overriding #methods etc.
- def methods; end
- def private_methods; end
- def global_variables; end
- def local_variables; end
- def instance_variables; end
- }
- bind = obj.instance_exec { binding }
-
- assert_include(completion_candidates("public_hog", bind), "public_hoge")
- assert_include(doc_namespace("public_hoge", bind), "public_hoge")
-
- assert_include(completion_candidates("private_hog", bind), "private_hoge")
- assert_include(doc_namespace("private_hoge", bind), "private_hoge")
- end
- end
-
- class DeprecatedInputCompletorTest < TestCase
- def setup
- save_encodings
- @verbose, $VERBOSE = $VERBOSE, nil
- IRB.init_config(nil)
- IRB.conf[:VERBOSE] = false
- IRB.conf[:MAIN_CONTEXT] = IRB::Context.new(IRB::WorkSpace.new(binding))
- end
-
- def teardown
- restore_encodings
- $VERBOSE = @verbose
- end
-
- def test_completion_proc
- assert_include(IRB::InputCompletor::CompletionProc.call('1.ab'), '1.abs')
- assert_include(IRB::InputCompletor::CompletionProc.call('1.ab', '', ''), '1.abs')
- end
-
- def test_retrieve_completion_data
- assert_include(IRB::InputCompletor.retrieve_completion_data('1.ab'), '1.abs')
- assert_equal(IRB::InputCompletor.retrieve_completion_data('1.abs', doc_namespace: true), 'Integer.abs')
- bind = eval('a = 1; binding')
- assert_include(IRB::InputCompletor.retrieve_completion_data('a.ab', bind: bind), 'a.abs')
- assert_equal(IRB::InputCompletor.retrieve_completion_data('a.abs', bind: bind, doc_namespace: true), 'Integer.abs')
- end
- end
-end
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
deleted file mode 100644
index c44c8e0573..0000000000
--- a/test/irb/test_context.rb
+++ /dev/null
@@ -1,737 +0,0 @@
-# frozen_string_literal: false
-require 'tempfile'
-require 'irb'
-
-require_relative "helper"
-
-module TestIRB
- class ContextTest < TestCase
- def setup
- IRB.init_config(nil)
- IRB.conf[:USE_SINGLELINE] = false
- IRB.conf[:VERBOSE] = false
- IRB.conf[:USE_PAGER] = false
- workspace = IRB::WorkSpace.new(Object.new)
- @context = IRB::Context.new(nil, workspace, TestInputMethod.new)
-
- @get_screen_size = Reline.method(:get_screen_size)
- Reline.instance_eval { undef :get_screen_size }
- def Reline.get_screen_size
- [36, 80]
- end
- save_encodings
- end
-
- def teardown
- Reline.instance_eval { undef :get_screen_size }
- Reline.define_singleton_method(:get_screen_size, @get_screen_size)
- restore_encodings
- end
-
- def test_eval_input
- verbose, $VERBOSE = $VERBOSE, nil
- input = TestInputMethod.new([
- "raise 'Foo'\n",
- "_\n",
- "0\n",
- "_\n",
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
-
- expected_output =
- if RUBY_3_4
- [
- :*, /\(irb\):1:in '<main>': Foo \(RuntimeError\)\n/,
- :*, /#<RuntimeError: Foo>\n/,
- :*, /0$/,
- :*, /0$/,
- /\s*/
- ]
- else
- [
- :*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/,
- :*, /#<RuntimeError: Foo>\n/,
- :*, /0$/,
- :*, /0$/,
- /\s*/
- ]
- end
-
- assert_pattern_list(expected_output, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_eval_input_raise2x
- input = TestInputMethod.new([
- "raise 'Foo'\n",
- "raise 'Bar'\n",
- "_\n",
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- expected_output =
- if RUBY_3_4
- [
- :*, /\(irb\):1:in '<main>': Foo \(RuntimeError\)\n/,
- :*, /\(irb\):2:in '<main>': Bar \(RuntimeError\)\n/,
- :*, /#<RuntimeError: Bar>\n/,
- ]
- else
- [
- :*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/,
- :*, /\(irb\):2:in `<main>': Bar \(RuntimeError\)\n/,
- :*, /#<RuntimeError: Bar>\n/,
- ]
- end
- assert_pattern_list(expected_output, out)
- end
-
- def test_prompt_n_deprecation
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new)
-
- _, err = capture_output do
- irb.context.prompt_n = "foo"
- irb.context.prompt_n
- end
-
- assert_include err, "IRB::Context#prompt_n is deprecated"
- assert_include err, "IRB::Context#prompt_n= is deprecated"
- end
-
- def test_output_to_pipe
- require 'stringio'
- input = TestInputMethod.new(["n=1"])
- input.instance_variable_set(:@stdout, StringIO.new)
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- irb.context.echo_on_assignment = :truncate
- irb.context.prompt_mode = :DEFAULT
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal "=> 1\n", out
- end
-
- {
- successful: [
- [false, "class Foo < Struct.new(:bar); end; Foo.new(123)\n", /#<struct bar=123>/],
- [:p, "class Foo < Struct.new(:bar); end; Foo.new(123)\n", /#<struct bar=123>/],
- [true, "class Foo < Struct.new(:bar); end; Foo.new(123)\n", /#<struct #<Class:.*>::Foo bar=123>/],
- [:yaml, "123", /--- 123\n/],
- [:marshal, "123", Marshal.dump(123)],
- ],
- failed: [
- [false, "BasicObject.new", /#<NoMethodError: undefined method (`|')to_s' for/],
- [:p, "class Foo; undef inspect ;end; Foo.new", /#<NoMethodError: undefined method (`|')inspect' for/],
- [:yaml, "BasicObject.new", /#<NoMethodError: undefined method (`|')inspect' for/],
- [:marshal, "[Object.new, Class.new]", /#<TypeError: can't dump anonymous class #<Class:/]
- ]
- }.each do |scenario, cases|
- cases.each do |inspect_mode, input, expected|
- define_method "test_#{inspect_mode}_inspect_mode_#{scenario}" do
- verbose, $VERBOSE = $VERBOSE, nil
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new([input]))
- irb.context.inspect_mode = inspect_mode
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_match(expected, out)
- ensure
- $VERBOSE = verbose
- end
- end
- end
-
- def test_object_inspection_handles_basic_object
- verbose, $VERBOSE = $VERBOSE, nil
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new(["BasicObject.new"]))
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_not_match(/NoMethodError/, out)
- assert_match(/#<BasicObject:.*>/, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_object_inspection_falls_back_to_kernel_inspect_when_errored
- verbose, $VERBOSE = $VERBOSE, nil
- main = Object.new
- main.singleton_class.module_eval <<~RUBY
- class Foo
- def inspect
- raise "foo"
- end
- end
- RUBY
-
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new(["Foo.new"]))
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_match(/An error occurred when inspecting the object: #<RuntimeError: foo>/, out)
- assert_match(/Result of Kernel#inspect: #<#<Class:.*>::Foo:/, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_object_inspection_prints_useful_info_when_kernel_inspect_also_errored
- verbose, $VERBOSE = $VERBOSE, nil
- main = Object.new
- main.singleton_class.module_eval <<~RUBY
- class Foo
- def initialize
- # Kernel#inspect goes through instance variables with #inspect
- # So this will cause Kernel#inspect to fail
- @foo = BasicObject.new
- end
-
- def inspect
- raise "foo"
- end
- end
- RUBY
-
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new(["Foo.new"]))
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_match(/An error occurred when inspecting the object: #<RuntimeError: foo>/, out)
- assert_match(/An error occurred when running Kernel#inspect: #<NoMethodError: undefined method (`|')inspect' for/, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_default_config
- assert_equal(true, @context.use_autocomplete?)
- end
-
- def test_echo_on_assignment
- input = TestInputMethod.new([
- "a = 1\n",
- "a\n",
- "a, b = 2, 3\n",
- "a\n",
- "b\n",
- "b = 4\n",
- "_\n"
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- irb.context.return_format = "=> %s\n"
-
- # The default
- irb.context.echo = true
- irb.context.echo_on_assignment = false
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> 1\n=> 2\n=> 3\n=> 4\n", out)
-
- # Everything is output, like before echo_on_assignment was introduced
- input.reset
- irb.context.echo = true
- irb.context.echo_on_assignment = true
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> 1\n=> 1\n=> [2, 3]\n=> 2\n=> 3\n=> 4\n=> 4\n", out)
-
- # Nothing is output when echo is false
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = false
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
-
- # Nothing is output when echo is false even if echo_on_assignment is true
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = true
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
- end
-
- def test_omit_on_assignment
- input = TestInputMethod.new([
- "a = [1] * 100\n",
- "a\n",
- ])
- value = [1] * 100
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- irb.context.return_format = "=> %s\n"
-
- irb.context.echo = true
- irb.context.echo_on_assignment = false
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> \n#{value.pretty_inspect}", out)
-
- input.reset
- irb.context.echo = true
- irb.context.echo_on_assignment = :truncate
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> \n#{value.pretty_inspect[0..3]}...\n=> \n#{value.pretty_inspect}", out)
-
- input.reset
- irb.context.echo = true
- irb.context.echo_on_assignment = true
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> \n#{value.pretty_inspect}=> \n#{value.pretty_inspect}", out)
-
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = false
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
-
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = :truncate
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
-
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = true
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
- end
-
- def test_omit_multiline_on_assignment
- without_colorize do
- input = TestInputMethod.new([
- "class A; def inspect; ([?* * 1000] * 3).join(%{\\n}); end; end; a = A.new\n",
- "a\n"
- ])
- value = ([?* * 1000] * 3).join(%{\n})
- value_first_line = (?* * 1000).to_s
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- irb.context.return_format = "=> %s\n"
-
- irb.context.echo = true
- irb.context.echo_on_assignment = false
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> \n#{value}\n", out)
- irb.context.evaluate_expression('A.remove_method(:inspect)', 0)
-
- input.reset
- irb.context.echo = true
- irb.context.echo_on_assignment = :truncate
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> \n#{value_first_line[0, input.winsize.last]}...\n=> \n#{value}\n", out)
- irb.context.evaluate_expression('A.remove_method(:inspect)', 0)
-
- input.reset
- irb.context.echo = true
- irb.context.echo_on_assignment = true
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> \n#{value}\n=> \n#{value}\n", out)
- irb.context.evaluate_expression('A.remove_method(:inspect)', 0)
-
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = false
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
- irb.context.evaluate_expression('A.remove_method(:inspect)', 0)
-
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = :truncate
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
- irb.context.evaluate_expression('A.remove_method(:inspect)', 0)
-
- input.reset
- irb.context.echo = false
- irb.context.echo_on_assignment = true
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("", out)
- irb.context.evaluate_expression('A.remove_method(:inspect)', 0)
- end
- end
-
- def test_echo_on_assignment_conf
- # Default
- IRB.conf[:ECHO] = nil
- IRB.conf[:ECHO_ON_ASSIGNMENT] = nil
- without_colorize do
- input = TestInputMethod.new()
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
-
- assert(irb.context.echo?, "echo? should be true by default")
- assert_equal(:truncate, irb.context.echo_on_assignment?, "echo_on_assignment? should be :truncate by default")
-
- # Explicitly set :ECHO to false
- IRB.conf[:ECHO] = false
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
-
- refute(irb.context.echo?, "echo? should be false when IRB.conf[:ECHO] is set to false")
- assert_equal(:truncate, irb.context.echo_on_assignment?, "echo_on_assignment? should be :truncate by default")
-
- # Explicitly set :ECHO_ON_ASSIGNMENT to true
- IRB.conf[:ECHO] = nil
- IRB.conf[:ECHO_ON_ASSIGNMENT] = false
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
-
- assert(irb.context.echo?, "echo? should be true by default")
- refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to false")
- end
- end
-
- def test_multiline_output_on_default_inspector
- main = Object.new
- def main.inspect
- "abc\ndef"
- end
-
- without_colorize do
- 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_output 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_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("=> abc\ndef\n", out)
- end
- end
-
- def test_default_return_format
- IRB.conf[:PROMPT][:MY_PROMPT] = {
- :PROMPT_I => "%03n> ",
- :PROMPT_S => "%03n> ",
- :PROMPT_C => "%03n> "
- # without :RETURN
- # :RETURN => "%s\n"
- }
- IRB.conf[:PROMPT_MODE] = :MY_PROMPT
- input = TestInputMethod.new([
- "3"
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_equal("3\n",
- out)
- end
-
- def test_eval_input_with_exception
- pend if RUBY_ENGINE == 'truffleruby'
- verbose, $VERBOSE = $VERBOSE, nil
- input = TestInputMethod.new([
- "def hoge() fuga; end; def fuga() raise; end; hoge\n",
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- expected_output =
- if RUBY_3_4
- [
- :*, /\(irb\):1:in 'fuga': unhandled exception\n/,
- :*, /\tfrom \(irb\):1:in 'hoge'\n/,
- :*, /\tfrom \(irb\):1:in '<main>'\n/,
- :*
- ]
- elsif RUBY_VERSION < '3.0.0' && STDOUT.tty?
- [
- :*, /Traceback \(most recent call last\):\n/,
- :*, /\t 2: from \(irb\):1:in `<main>'\n/,
- :*, /\t 1: from \(irb\):1:in `hoge'\n/,
- :*, /\(irb\):1:in `fuga': unhandled exception\n/,
- ]
- else
- [
- :*, /\(irb\):1:in `fuga': unhandled exception\n/,
- :*, /\tfrom \(irb\):1:in `hoge'\n/,
- :*, /\tfrom \(irb\):1:in `<main>'\n/,
- :*
- ]
- end
- assert_pattern_list(expected_output, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_eval_input_with_invalid_byte_sequence_exception
- verbose, $VERBOSE = $VERBOSE, nil
- input = TestInputMethod.new([
- %Q{def hoge() fuga; end; def fuga() raise "A\\xF3B"; end; hoge\n},
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- expected_output =
- if RUBY_3_4
- [
- :*, /\(irb\):1:in 'fuga': A\\xF3B \(RuntimeError\)\n/,
- :*, /\tfrom \(irb\):1:in 'hoge'\n/,
- :*, /\tfrom \(irb\):1:in '<main>'\n/,
- :*
- ]
- elsif RUBY_VERSION < '3.0.0' && STDOUT.tty?
- [
- :*, /Traceback \(most recent call last\):\n/,
- :*, /\t 2: from \(irb\):1:in `<main>'\n/,
- :*, /\t 1: from \(irb\):1:in `hoge'\n/,
- :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/,
- ]
- else
- [
- :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/,
- :*, /\tfrom \(irb\):1:in `hoge'\n/,
- :*, /\tfrom \(irb\):1:in `<main>'\n/,
- :*
- ]
- end
-
- assert_pattern_list(expected_output, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_eval_input_with_long_exception
- pend if RUBY_ENGINE == 'truffleruby'
- verbose, $VERBOSE = $VERBOSE, nil
- nesting = 20
- generated_code = ''
- nesting.times do |i|
- generated_code << "def a#{i}() a#{i + 1}; end; "
- end
- generated_code << "def a#{nesting}() raise; end; a0\n"
- input = TestInputMethod.new([
- generated_code
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- if RUBY_VERSION < '3.0.0' && STDOUT.tty?
- expected = [
- :*, /Traceback \(most recent call last\):\n/,
- :*, /\t... \d+ levels...\n/,
- :*, /\t16: from \(irb\):1:in (`|')a4'\n/,
- :*, /\t15: from \(irb\):1:in (`|')a5'\n/,
- :*, /\t14: from \(irb\):1:in (`|')a6'\n/,
- :*, /\t13: from \(irb\):1:in (`|')a7'\n/,
- :*, /\t12: from \(irb\):1:in (`|')a8'\n/,
- :*, /\t11: from \(irb\):1:in (`|')a9'\n/,
- :*, /\t10: from \(irb\):1:in (`|')a10'\n/,
- :*, /\t 9: from \(irb\):1:in (`|')a11'\n/,
- :*, /\t 8: from \(irb\):1:in (`|')a12'\n/,
- :*, /\t 7: from \(irb\):1:in (`|')a13'\n/,
- :*, /\t 6: from \(irb\):1:in (`|')a14'\n/,
- :*, /\t 5: from \(irb\):1:in (`|')a15'\n/,
- :*, /\t 4: from \(irb\):1:in (`|')a16'\n/,
- :*, /\t 3: from \(irb\):1:in (`|')a17'\n/,
- :*, /\t 2: from \(irb\):1:in (`|')a18'\n/,
- :*, /\t 1: from \(irb\):1:in (`|')a19'\n/,
- :*, /\(irb\):1:in (`|')a20': unhandled exception\n/,
- ]
- else
- expected = [
- :*, /\(irb\):1:in (`|')a20': unhandled exception\n/,
- :*, /\tfrom \(irb\):1:in (`|')a19'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a18'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a17'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a16'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a15'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a14'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a13'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a12'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a11'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a10'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a9'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a8'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a7'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a6'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a5'\n/,
- :*, /\tfrom \(irb\):1:in (`|')a4'\n/,
- :*, /\t... \d+ levels...\n/,
- ]
- end
- assert_pattern_list(expected, out)
- ensure
- $VERBOSE = verbose
- end
-
- def test_prompt_main_escape
- main = Struct.new(:to_s).new("main\a\t\r\n")
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
- assert_equal("irb(main )>", irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1))
- end
-
- def test_prompt_main_inspect_escape
- main = Struct.new(:inspect).new("main\\n\nmain")
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
- assert_equal("irb(main\\n main)>", irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
- end
-
- def test_prompt_main_truncate
- main = Struct.new(:to_s).new("a" * 100)
- def main.inspect; to_s.inspect; end
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
- assert_equal('irb(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa...)>', irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1))
- assert_equal('irb("aaaaaaaaaaaaaaaaaaaaaaaaaaaa...)>', irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
- end
-
- def test_prompt_main_basic_object
- main = BasicObject.new
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
- assert_match(/irb\(#<BasicObject:.+\)/, irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1))
- assert_match(/irb\(#<BasicObject:.+\)/, irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
- end
-
- def test_prompt_main_raise
- main = Object.new
- def main.to_s; raise TypeError; end
- def main.inspect; raise ArgumentError; end
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
- assert_equal("irb(!TypeError)>", irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1))
- assert_equal("irb(!ArgumentError)>", irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
- end
-
- def test_prompt_format
- main = 'main'
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
- assert_equal('%% main %m %main %%m >', irb.send(:format_prompt, '%%%% %m %%m %%%m %%%%m %l', '>', 1, 1))
- assert_equal('42,%i, 42,%3i,042,%03i', irb.send(:format_prompt, '%i,%%i,%3i,%%3i,%03i,%%03i', nil, 42, 1))
- assert_equal('42,%n, 42,%3n,042,%03n', irb.send(:format_prompt, '%n,%%n,%3n,%%3n,%03n,%%03n', nil, 1, 42))
- end
-
- def test_lineno
- input = TestInputMethod.new([
- "\n",
- "__LINE__\n",
- "__LINE__\n",
- "\n",
- "\n",
- "__LINE__\n",
- ])
- irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
- out, err = capture_output do
- irb.eval_input
- end
- assert_empty err
- assert_pattern_list([
- :*, /\b2\n/,
- :*, /\b3\n/,
- :*, /\b6\n/,
- ], out)
- end
-
- def test_irb_path_setter
- @context.irb_path = __FILE__
- assert_equal(__FILE__, @context.irb_path)
- assert_equal("#{__FILE__}(irb)", @context.instance_variable_get(:@eval_path))
- @context.irb_path = 'file/does/not/exist'
- assert_equal('file/does/not/exist', @context.irb_path)
- assert_equal('file/does/not/exist', @context.instance_variable_get(:@eval_path))
- @context.irb_path = "#{__FILE__}(irb)"
- assert_equal("#{__FILE__}(irb)", @context.irb_path)
- assert_equal("#{__FILE__}(irb)", @context.instance_variable_get(:@eval_path))
- end
-
- def test_build_completor
- verbose, $VERBOSE = $VERBOSE, nil
- original_completor = IRB.conf[:COMPLETOR]
- IRB.conf[:COMPLETOR] = nil
- assert_match(/IRB::(Regexp|Type)Completor/, @context.send(:build_completor).class.name)
- IRB.conf[:COMPLETOR] = :regexp
- assert_equal 'IRB::RegexpCompletor', @context.send(:build_completor).class.name
- IRB.conf[:COMPLETOR] = :unknown
- assert_equal 'IRB::RegexpCompletor', @context.send(:build_completor).class.name
- # :type is tested in test_type_completor.rb
- ensure
- $VERBOSE = verbose
- IRB.conf[:COMPLETOR] = original_completor
- end
-
- private
-
- def without_colorize
- original_value = IRB.conf[:USE_COLORIZE]
- IRB.conf[:USE_COLORIZE] = false
- yield
- ensure
- IRB.conf[:USE_COLORIZE] = original_value
- end
- end
-end
diff --git a/test/irb/test_debugger_integration.rb b/test/irb/test_debugger_integration.rb
deleted file mode 100644
index 45ffb2a52e..0000000000
--- a/test/irb/test_debugger_integration.rb
+++ /dev/null
@@ -1,513 +0,0 @@
-# frozen_string_literal: true
-
-require "tempfile"
-require "tmpdir"
-
-require_relative "helper"
-
-module TestIRB
- class DebuggerIntegrationTest < IntegrationTestCase
- def setup
- super
-
- if RUBY_ENGINE == 'truffleruby'
- omit "This test runs with ruby/debug, which doesn't work with truffleruby"
- end
-
- @envs.merge!("NO_COLOR" => "true", "RUBY_DEBUG_HISTORY_FILE" => '')
- end
-
- def test_backtrace
- write_ruby <<~'RUBY'
- def foo
- binding.irb
- end
- foo
- RUBY
-
- output = run_ruby_file do
- type "backtrace"
- type "exit!"
- end
-
- assert_match(/irb\(main\):001> backtrace/, output)
- assert_match(/Object#foo at #{@ruby_file.to_path}/, output)
- end
-
- def test_debug
- write_ruby <<~'ruby'
- binding.irb
- puts "hello"
- ruby
-
- output = run_ruby_file do
- type "debug"
- type "next"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> debug/, output)
- assert_match(/irb:rdbg\(main\):002> next/, output)
- assert_match(/=> 2\| puts "hello"/, output)
- end
-
- def test_debug_command_only_runs_once
- write_ruby <<~'ruby'
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "debug"
- type "debug"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> debug/, output)
- assert_match(/irb:rdbg\(main\):002> debug/, output)
- assert_match(/IRB is already running with a debug session/, output)
- end
-
- def test_debug_command_can_only_be_called_from_binding_irb
- write_ruby <<~'ruby'
- require "irb"
- # trick test framework
- puts "binding.irb"
- IRB.start
- ruby
-
- output = run_ruby_file do
- type "debug"
- type "exit"
- end
-
- assert_include(output, "Debugging commands are only available when IRB is started with binding.irb")
- end
-
- def test_next
- write_ruby <<~'ruby'
- binding.irb
- puts "hello"
- ruby
-
- output = run_ruby_file do
- type "next"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> next/, output)
- assert_match(/=> 2\| puts "hello"/, output)
- end
-
- def test_break
- write_ruby <<~'RUBY'
- binding.irb
- puts "Hello"
- RUBY
-
- output = run_ruby_file do
- type "break 2"
- type "continue"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> break/, output)
- assert_match(/=> 2\| puts "Hello"/, output)
- end
-
- def test_delete
- write_ruby <<~'RUBY'
- binding.irb
- puts "Hello"
- binding.irb
- puts "World"
- RUBY
-
- output = run_ruby_file do
- type "break 4"
- type "continue"
- type "delete 0"
- type "continue"
- end
-
- assert_match(/irb:rdbg\(main\):003> delete/, output)
- assert_match(/deleted: #0 BP - Line/, output)
- end
-
- def test_step
- write_ruby <<~'RUBY'
- def foo
- puts "Hello"
- end
- binding.irb
- foo
- RUBY
-
- output = run_ruby_file do
- type "step"
- type "step"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> step/, output)
- assert_match(/=> 5\| foo/, output)
- assert_match(/=> 2\| puts "Hello"/, output)
- end
-
- def test_long_stepping
- write_ruby <<~'RUBY'
- class Foo
- def foo(num)
- bar(num + 10)
- end
-
- def bar(num)
- num
- end
- end
-
- binding.irb
- Foo.new.foo(100)
- RUBY
-
- output = run_ruby_file do
- type "step"
- type "step"
- type "step"
- type "step"
- type "num"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> step/, output)
- assert_match(/irb:rdbg\(main\):002> step/, output)
- assert_match(/irb:rdbg\(#<Foo:.*>\):003> step/, output)
- assert_match(/irb:rdbg\(#<Foo:.*>\):004> step/, output)
- assert_match(/irb:rdbg\(#<Foo:.*>\):005> num/, output)
- assert_match(/=> 110/, output)
- end
-
- def test_continue
- write_ruby <<~'RUBY'
- binding.irb
- puts "Hello"
- binding.irb
- puts "World"
- RUBY
-
- output = run_ruby_file do
- type "continue"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> continue/, output)
- assert_match(/=> 3: binding.irb/, output)
- assert_match(/irb:rdbg\(main\):002> continue/, output)
- end
-
- def test_finish
- write_ruby <<~'RUBY'
- def foo
- binding.irb
- puts "Hello"
- end
- foo
- RUBY
-
- output = run_ruby_file do
- type "finish"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> finish/, output)
- assert_match(/=> 4\| end/, output)
- end
-
- def test_info
- write_ruby <<~'RUBY'
- def foo
- a = "He" + "llo"
- binding.irb
- end
- foo
- RUBY
-
- output = run_ruby_file do
- type "info"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> info/, output)
- assert_match(/%self = main/, output)
- assert_match(/a = "Hello"/, output)
- end
-
- def test_catch
- write_ruby <<~'RUBY'
- binding.irb
- 1 / 0
- RUBY
-
- output = run_ruby_file do
- type "catch ZeroDivisionError"
- type "continue"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> catch/, output)
- assert_match(/Stop by #0 BP - Catch "ZeroDivisionError"/, output)
- end
-
- def test_exit
- write_ruby <<~'RUBY'
- binding.irb
- puts "he" + "llo"
- RUBY
-
- output = run_ruby_file do
- type "debug"
- type "exit"
- end
-
- assert_match(/irb:rdbg\(main\):002>/, output)
- assert_match(/hello/, output)
- end
-
- def test_force_exit
- write_ruby <<~'RUBY'
- binding.irb
- puts "he" + "llo"
- RUBY
-
- output = run_ruby_file do
- type "debug"
- type "exit!"
- end
-
- assert_match(/irb:rdbg\(main\):002>/, output)
- assert_not_match(/hello/, output)
- end
-
- def test_quit
- write_ruby <<~'RUBY'
- binding.irb
- puts "he" + "llo"
- RUBY
-
- output = run_ruby_file do
- type "debug"
- type "quit!"
- end
-
- assert_match(/irb:rdbg\(main\):002>/, output)
- assert_not_match(/hello/, output)
- end
-
- def test_prompt_line_number_continues
- write_ruby <<~'ruby'
- binding.irb
- puts "Hello"
- puts "World"
- ruby
-
- output = run_ruby_file do
- type "123"
- type "456"
- type "next"
- type "info"
- type "next"
- type "continue"
- end
-
- assert_match(/irb\(main\):003> next/, output)
- assert_match(/irb:rdbg\(main\):004> info/, output)
- assert_match(/irb:rdbg\(main\):005> next/, output)
- end
-
- def test_prompt_irb_name_is_kept
- write_rc <<~RUBY
- IRB.conf[:IRB_NAME] = "foo"
- RUBY
-
- write_ruby <<~'ruby'
- binding.irb
- puts "Hello"
- ruby
-
- output = run_ruby_file do
- type "next"
- type "continue"
- end
-
- assert_match(/foo\(main\):001> next/, output)
- assert_match(/foo:rdbg\(main\):002> continue/, output)
- end
-
- def test_irb_commands_are_available_after_moving_around_with_the_debugger
- write_ruby <<~'ruby'
- class Foo
- def bar
- puts "bar"
- end
- end
-
- binding.irb
- Foo.new.bar
- ruby
-
- output = run_ruby_file do
- # Due to the way IRB defines its commands, moving into the Foo instance from main is necessary for proper testing.
- type "next"
- type "step"
- type "irb_info"
- type "continue"
- end
-
- assert_include(output, "InputMethod: RelineInputMethod")
- end
-
- def test_irb_command_can_check_local_variables
- write_ruby <<~'ruby'
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "debug"
- type 'foobar = IRB'
- type "show_source foobar.start"
- type "show_source = 'Foo'"
- type "show_source + 'Bar'"
- type "continue"
- end
- assert_include(output, "def start(ap_path = nil)")
- assert_include(output, '"FooBar"')
- end
-
- def test_help_command_is_delegated_to_the_debugger
- write_ruby <<~'ruby'
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "debug"
- type "help"
- type "continue"
- end
-
- assert_include(output, "### Frame control")
- end
-
- def test_help_display_different_content_when_debugger_is_enabled
- write_ruby <<~'ruby'
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "debug"
- type "help"
- type "continue"
- end
-
- # IRB's commands should still be listed
- assert_match(/help\s+List all available commands/, output)
- # debug gem's commands should be appended at the end
- assert_match(/Debugging \(from debug\.gem\)\s+### Control flow/, output)
- end
-
- def test_input_is_evaluated_in_the_context_of_the_current_thread
- write_ruby <<~'ruby'
- current_thread = Thread.current
- binding.irb
- ruby
-
- output = run_ruby_file do
- type "debug"
- type '"Threads match: #{current_thread == Thread.current}"'
- type "continue"
- end
-
- assert_match(/irb\(main\):001> debug/, output)
- assert_match(/Threads match: true/, output)
- end
-
- def test_irb_switches_debugger_interface_if_debug_was_already_activated
- write_ruby <<~'ruby'
- require 'debug'
- class Foo
- def bar
- puts "bar"
- end
- end
-
- binding.irb
- Foo.new.bar
- ruby
-
- output = run_ruby_file do
- # Due to the way IRB defines its commands, moving into the Foo instance from main is necessary for proper testing.
- type "next"
- type "step"
- type 'irb_info'
- type "continue"
- end
-
- assert_match(/irb\(main\):001> next/, output)
- assert_include(output, "InputMethod: RelineInputMethod")
- end
-
- def test_debugger_cant_be_activated_while_multi_irb_is_active
- write_ruby <<~'ruby'
- binding.irb
- a = 1
- ruby
-
- output = run_ruby_file do
- type "jobs"
- type "next"
- type "exit"
- end
-
- assert_match(/irb\(main\):001> jobs/, output)
- assert_include(output, "Can't start the debugger when IRB is running in a multi-IRB session.")
- end
-
- def test_multi_irb_commands_are_not_available_after_activating_the_debugger
- write_ruby <<~'ruby'
- binding.irb
- a = 1
- ruby
-
- output = run_ruby_file do
- type "next"
- type "jobs"
- type "continue"
- end
-
- assert_match(/irb\(main\):001> next/, output)
- assert_include(output, "Multi-IRB commands are not available when the debugger is enabled.")
- end
-
- def test_irb_passes_empty_input_to_debugger_to_repeat_the_last_command
- write_ruby <<~'ruby'
- binding.irb
- puts "foo"
- puts "bar"
- puts "baz"
- ruby
-
- output = run_ruby_file do
- type "next"
- type ""
- # Test that empty input doesn't repeat expressions
- type "123"
- type ""
- type "next"
- type ""
- type ""
- end
-
- assert_include(output, "=> 2\| puts \"foo\"")
- assert_include(output, "=> 3\| puts \"bar\"")
- assert_include(output, "=> 4\| puts \"baz\"")
- end
- end
-end
diff --git a/test/irb/test_eval_history.rb b/test/irb/test_eval_history.rb
deleted file mode 100644
index 54913ceff5..0000000000
--- a/test/irb/test_eval_history.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-require "irb"
-
-require_relative "helper"
-
-module TestIRB
- class EvalHistoryTest < TestCase
- def setup
- save_encodings
- IRB.instance_variable_get(:@CONF).clear
- end
-
- def teardown
- restore_encodings
- end
-
- def execute_lines(*lines, conf: {}, main: self, irb_path: nil)
- IRB.init_config(nil)
- IRB.conf[:VERBOSE] = false
- IRB.conf[:PROMPT_MODE] = :SIMPLE
- IRB.conf[:USE_PAGER] = false
- IRB.conf.merge!(conf)
- input = TestInputMethod.new(lines)
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
- irb.context.return_format = "=> %s\n"
- irb.context.irb_path = irb_path if irb_path
- IRB.conf[:MAIN_CONTEXT] = irb.context
- capture_output do
- irb.eval_input
- end
- end
-
- def test_eval_history_is_disabled_by_default
- out, err = execute_lines(
- "a = 1",
- "__"
- )
-
- assert_empty(err)
- assert_match(/undefined local variable or method (`|')__'/, out)
- end
-
- def test_eval_history_can_be_retrieved_with_double_underscore
- out, err = execute_lines(
- "a = 1",
- "__",
- conf: { EVAL_HISTORY: 5 }
- )
-
- assert_empty(err)
- assert_match("=> 1\n" + "=> 1 1\n", out)
- end
-
- def test_eval_history_respects_given_limit
- out, err = execute_lines(
- "'foo'\n",
- "'bar'\n",
- "'baz'\n",
- "'xyz'\n",
- "__",
- conf: { EVAL_HISTORY: 4 }
- )
-
- assert_empty(err)
- # Because eval_history injects `__` into the history AND decide to ignore it, we only get <limit> - 1 results
- assert_match("2 \"bar\"\n" + "3 \"baz\"\n" + "4 \"xyz\"\n", out)
- end
- end
-end
diff --git a/test/irb/test_evaluation.rb b/test/irb/test_evaluation.rb
deleted file mode 100644
index adb69b2067..0000000000
--- a/test/irb/test_evaluation.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require "tempfile"
-
-require_relative "helper"
-
-module TestIRB
- class EchoingTest < IntegrationTestCase
- def test_irb_echos_by_default
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "123123"
- type "exit"
- end
-
- assert_include(output, "=> 123123")
- end
-
- def test_irb_doesnt_echo_line_with_semicolon
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "123123;"
- type "123123 ;"
- type "123123; "
- type <<~RUBY
- if true
- 123123
- end;
- RUBY
- type "'evaluation ends'"
- type "exit"
- end
-
- assert_include(output, "=> \"evaluation ends\"")
- assert_not_include(output, "=> 123123")
- end
- end
-end
diff --git a/test/irb/test_helper_method.rb b/test/irb/test_helper_method.rb
deleted file mode 100644
index a3e2c43b2f..0000000000
--- a/test/irb/test_helper_method.rb
+++ /dev/null
@@ -1,135 +0,0 @@
-# frozen_string_literal: true
-require "irb"
-
-require_relative "helper"
-
-module TestIRB
- class HelperMethodTestCase < TestCase
- def setup
- $VERBOSE = nil
- @verbosity = $VERBOSE
- save_encodings
- IRB.instance_variable_get(:@CONF).clear
- end
-
- def teardown
- $VERBOSE = @verbosity
- restore_encodings
- end
-
- def execute_lines(*lines, conf: {}, main: self, irb_path: nil)
- IRB.init_config(nil)
- IRB.conf[:VERBOSE] = false
- IRB.conf[:PROMPT_MODE] = :SIMPLE
- IRB.conf.merge!(conf)
- input = TestInputMethod.new(lines)
- irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
- irb.context.return_format = "=> %s\n"
- irb.context.irb_path = irb_path if irb_path
- IRB.conf[:MAIN_CONTEXT] = irb.context
- IRB.conf[:USE_PAGER] = false
- capture_output do
- irb.eval_input
- end
- end
- end
-
- module TestHelperMethod
- class ConfTest < HelperMethodTestCase
- def test_conf_returns_the_context_object
- out, err = execute_lines("conf.ap_name")
-
- assert_empty err
- assert_include out, "=> \"irb\""
- end
- end
- end
-
- class HelperMethodIntegrationTest < IntegrationTestCase
- def test_arguments_propogation
- write_ruby <<~RUBY
- require "irb/helper_method"
-
- class MyHelper < IRB::HelperMethod::Base
- description "This is a test helper"
-
- def execute(
- required_arg, optional_arg = nil, *splat_arg, required_keyword_arg:,
- optional_keyword_arg: nil, **double_splat_arg, &block_arg
- )
- puts [required_arg, optional_arg, splat_arg, required_keyword_arg, optional_keyword_arg, double_splat_arg, block_arg.call].to_s
- end
- end
-
- IRB::HelperMethod.register(:my_helper, MyHelper)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type <<~INPUT
- my_helper(
- "required", "optional", "splat", required_keyword_arg: "required",
- optional_keyword_arg: "optional", a: 1, b: 2
- ) { "block" }
- INPUT
- type "exit"
- end
-
- optional = {a: 1, b: 2}
- assert_include(output, %[["required", "optional", ["splat"], "required", "optional", #{optional.inspect}, "block"]])
- end
-
- def test_helper_method_injection_can_happen_after_irb_require
- write_ruby <<~RUBY
- require "irb"
-
- class MyHelper < IRB::HelperMethod::Base
- description "This is a test helper"
-
- def execute
- puts "Hello from MyHelper"
- end
- end
-
- IRB::HelperMethod.register(:my_helper, MyHelper)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "my_helper"
- type "exit"
- end
-
- assert_include(output, 'Hello from MyHelper')
- end
-
- def test_helper_method_instances_are_memoized
- write_ruby <<~RUBY
- require "irb/helper_method"
-
- class MyHelper < IRB::HelperMethod::Base
- description "This is a test helper"
-
- def execute(val)
- @val ||= val
- end
- end
-
- IRB::HelperMethod.register(:my_helper, MyHelper)
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "my_helper(100)"
- type "my_helper(200)"
- type "exit"
- end
-
- assert_include(output, '=> 100')
- assert_not_include(output, '=> 200')
- end
- end
-end
diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb
deleted file mode 100644
index 0171bb0eca..0000000000
--- a/test/irb/test_history.rb
+++ /dev/null
@@ -1,573 +0,0 @@
-# frozen_string_literal: false
-require 'irb'
-require 'readline'
-require "tempfile"
-
-require_relative "helper"
-
-return if RUBY_PLATFORM.match?(/solaris|mswin|mingw/i)
-
-module TestIRB
- class HistoryTest < TestCase
- def setup
- @conf_backup = IRB.conf.dup
- @original_verbose, $VERBOSE = $VERBOSE, nil
- @tmpdir = Dir.mktmpdir("test_irb_history_")
- setup_envs(home: @tmpdir)
- IRB.conf[:LC_MESSAGES] = IRB::Locale.new
- save_encodings
- IRB.instance_variable_set(:@existing_rc_name_generators, nil)
- end
-
- def teardown
- IRB.conf.replace(@conf_backup)
- IRB.instance_variable_set(:@existing_rc_name_generators, nil)
- teardown_envs
- restore_encodings
- $VERBOSE = @original_verbose
- FileUtils.rm_rf(@tmpdir)
- end
-
- class TestInputMethodWithRelineHistory < TestInputMethod
- # When IRB.conf[:USE_MULTILINE] is true, IRB::RelineInputMethod uses Reline::History
- HISTORY = Reline::History.new(Reline.core.config)
-
- include IRB::HistorySavingAbility
- end
-
- class TestInputMethodWithReadlineHistory < TestInputMethod
- # When IRB.conf[:USE_MULTILINE] is false, IRB::ReadlineInputMethod uses Readline::HISTORY
- HISTORY = Readline::HISTORY
-
- include IRB::HistorySavingAbility
- end
-
- def test_history_dont_save
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = nil
- assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
- 1
- 2
- EXPECTED_HISTORY
- 1
- 2
- INITIAL_HISTORY
- 3
- exit
- INPUT
- end
-
- def test_history_save_1
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = 1
- assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
- exit
- EXPECTED_HISTORY
- 1
- 2
- 3
- 4
- INITIAL_HISTORY
- 5
- exit
- INPUT
- end
-
- def test_history_save_100
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = 100
- assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
- 1
- 2
- 3
- 4
- 5
- exit
- EXPECTED_HISTORY
- 1
- 2
- 3
- 4
- INITIAL_HISTORY
- 5
- exit
- INPUT
- end
-
- def test_history_save_bignum
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = 10 ** 19
- assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
- 1
- 2
- 3
- 4
- 5
- exit
- EXPECTED_HISTORY
- 1
- 2
- 3
- 4
- INITIAL_HISTORY
- 5
- exit
- INPUT
- end
-
- def test_history_save_minus_as_infinity
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = -1 # infinity
- assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
- 1
- 2
- 3
- 4
- 5
- exit
- EXPECTED_HISTORY
- 1
- 2
- 3
- 4
- INITIAL_HISTORY
- 5
- exit
- INPUT
- end
-
- def test_history_concurrent_use_reline
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = 1
- history_concurrent_use_for_input_method(TestInputMethodWithRelineHistory)
- end
-
- def test_history_concurrent_use_readline
- omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
- IRB.conf[:SAVE_HISTORY] = 1
- history_concurrent_use_for_input_method(TestInputMethodWithReadlineHistory)
- end
-
- def test_history_concurrent_use_not_present
- IRB.conf[:SAVE_HISTORY] = 1
- io = TestInputMethodWithRelineHistory.new
- io.class::HISTORY.clear
- io.load_history
- io.class::HISTORY << 'line1'
- io.class::HISTORY << 'line2'
-
- history_file = IRB.rc_file("_history")
- assert_not_send [File, :file?, history_file]
- File.write(history_file, "line0\n")
- io.save_history
- assert_equal(%w"line0 line1 line2", File.read(history_file).split)
- end
-
- def test_history_different_encodings
- IRB.conf[:SAVE_HISTORY] = 2
- IRB.conf[:LC_MESSAGES] = IRB::Locale.new("en_US.ASCII")
- IRB.__send__(:set_encoding, Encoding::US_ASCII.name, override: false)
- assert_history(<<~EXPECTED_HISTORY.encode(Encoding::US_ASCII), <<~INITIAL_HISTORY.encode(Encoding::UTF_8), <<~INPUT)
- ????
- exit
- EXPECTED_HISTORY
- 😀
- INITIAL_HISTORY
- exit
- INPUT
- end
-
- def test_history_does_not_raise_when_history_file_directory_does_not_exist
- backup_history_file = IRB.conf[:HISTORY_FILE]
- IRB.conf[:SAVE_HISTORY] = 1
- IRB.conf[:HISTORY_FILE] = "fake/fake/fake/history_file"
- io = TestInputMethodWithRelineHistory.new
-
- assert_warn(/ensure the folder exists/i) do
- io.save_history
- end
-
- # assert_warn reverts $VERBOSE to EnvUtil.original_verbose, which is true in some cases
- # We want to keep $VERBOSE as nil until teardown is called
- # TODO: check if this is an assert_warn issue
- $VERBOSE = nil
- ensure
- IRB.conf[:HISTORY_FILE] = backup_history_file
- end
-
- def test_no_home_no_history_file_does_not_raise_history_save
- ENV['HOME'] = nil
- io = TestInputMethodWithRelineHistory.new
- assert_nil(IRB.rc_file('_history'))
- assert_nothing_raised do
- io.load_history
- io.save_history
- end
- end
-
- private
-
- def history_concurrent_use_for_input_method(input_method)
- assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT, input_method) do |history_file|
- exit
- 5
- exit
- EXPECTED_HISTORY
- 1
- 2
- 3
- 4
- INITIAL_HISTORY
- 5
- exit
- INPUT
- assert_history(<<~EXPECTED_HISTORY2, <<~INITIAL_HISTORY2, <<~INPUT2, input_method)
- exit
- EXPECTED_HISTORY2
- 1
- 2
- 3
- 4
- INITIAL_HISTORY2
- 5
- exit
- INPUT2
- File.utime(File.atime(history_file), File.mtime(history_file) + 2, history_file)
- end
- end
-
- def assert_history(expected_history, initial_irb_history, input, input_method = TestInputMethodWithRelineHistory)
- actual_history = nil
- history_file = IRB.rc_file("_history")
- ENV["HOME"] = @tmpdir
- File.open(history_file, "w") do |f|
- f.write(initial_irb_history)
- end
-
- io = input_method.new
- io.class::HISTORY.clear
- io.load_history
- if block_given?
- previous_history = []
- io.class::HISTORY.each { |line| previous_history << line }
- yield history_file
- io.class::HISTORY.clear
- previous_history.each { |line| io.class::HISTORY << line }
- end
- input.split.each { |line| io.class::HISTORY << line }
- io.save_history
-
- io.load_history
- File.open(history_file, "r") do |f|
- actual_history = f.read
- end
- assert_equal(expected_history, actual_history, <<~MESSAGE)
- expected:
- #{expected_history}
- but actual:
- #{actual_history}
- MESSAGE
- end
-
- def with_temp_stdio
- Tempfile.create("test_readline_stdin") do |stdin|
- Tempfile.create("test_readline_stdout") do |stdout|
- yield stdin, stdout
- end
- end
- end
- end
-
- class IRBHistoryIntegrationTest < IntegrationTestCase
- def test_history_saving_can_be_disabled_with_false
- write_history ""
- write_rc <<~RUBY
- IRB.conf[:SAVE_HISTORY] = false
- RUBY
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "puts 'foo' + 'bar'"
- type "exit"
- end
-
- assert_include(output, "foobar")
- assert_equal "", @history_file.open.read
- end
-
- def test_history_saving_accepts_true
- write_history ""
- write_rc <<~RUBY
- IRB.conf[:SAVE_HISTORY] = true
- RUBY
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "puts 'foo' + 'bar'"
- type "exit"
- end
-
- assert_include(output, "foobar")
- assert_equal <<~HISTORY, @history_file.open.read
- puts 'foo' + 'bar'
- exit
- HISTORY
- end
-
- def test_history_saving_with_debug
- write_history ""
-
- write_ruby <<~'RUBY'
- def foo
- end
-
- binding.irb
-
- foo
- RUBY
-
- output = run_ruby_file do
- type "'irb session'"
- type "next"
- type "'irb:debug session'"
- type "step"
- type "irb_info"
- type "puts Reline::HISTORY.to_a.to_s"
- type "q!"
- end
-
- assert_include(output, "InputMethod: RelineInputMethod")
- # check that in-memory history is preserved across sessions
- assert_include output, %q(
- ["'irb session'", "next", "'irb:debug session'", "step", "irb_info", "puts Reline::HISTORY.to_a.to_s"]
- ).strip
-
- assert_equal <<~HISTORY, @history_file.open.read
- 'irb session'
- next
- 'irb:debug session'
- step
- irb_info
- puts Reline::HISTORY.to_a.to_s
- q!
- HISTORY
- end
-
- def test_history_saving_with_debug_without_prior_history
- tmpdir = Dir.mktmpdir("test_irb_history_")
- # Intentionally not creating the file so we test the reset counter logic
- history_file = File.join(tmpdir, "irb_history")
-
- write_rc <<~RUBY
- IRB.conf[:HISTORY_FILE] = "#{history_file}"
- RUBY
-
- write_ruby <<~'RUBY'
- def foo
- end
-
- binding.irb
-
- foo
- RUBY
-
- output = run_ruby_file do
- type "'irb session'"
- type "next"
- type "'irb:debug session'"
- type "step"
- type "irb_info"
- type "puts Reline::HISTORY.to_a.to_s"
- type "q!"
- end
-
- assert_include(output, "InputMethod: RelineInputMethod")
- # check that in-memory history is preserved across sessions
- assert_include output, %q(
- ["'irb session'", "next", "'irb:debug session'", "step", "irb_info", "puts Reline::HISTORY.to_a.to_s"]
- ).strip
-
- assert_equal <<~HISTORY, File.read(history_file)
- 'irb session'
- next
- 'irb:debug session'
- step
- irb_info
- puts Reline::HISTORY.to_a.to_s
- q!
- HISTORY
- ensure
- FileUtils.rm_rf(tmpdir)
- end
-
- def test_history_saving_with_nested_sessions
- write_history ""
-
- write_ruby <<~'RUBY'
- def foo
- binding.irb
- end
-
- binding.irb
- RUBY
-
- run_ruby_file do
- type "'outer session'"
- type "foo"
- type "'inner session'"
- type "exit"
- type "'outer session again'"
- type "exit"
- end
-
- assert_equal <<~HISTORY, @history_file.open.read
- 'outer session'
- foo
- 'inner session'
- exit
- 'outer session again'
- exit
- HISTORY
- end
-
- def test_nested_history_saving_from_inner_session_with_exit!
- write_history ""
-
- write_ruby <<~'RUBY'
- def foo
- binding.irb
- end
-
- binding.irb
- RUBY
-
- run_ruby_file do
- type "'outer session'"
- type "foo"
- type "'inner session'"
- type "exit!"
- end
-
- assert_equal <<~HISTORY, @history_file.open.read
- 'outer session'
- foo
- 'inner session'
- exit!
- HISTORY
- end
-
- def test_nested_history_saving_from_outer_session_with_exit!
- write_history ""
-
- write_ruby <<~'RUBY'
- def foo
- binding.irb
- end
-
- binding.irb
- RUBY
-
- run_ruby_file do
- type "'outer session'"
- type "foo"
- type "'inner session'"
- type "exit"
- type "'outer session again'"
- type "exit!"
- end
-
- assert_equal <<~HISTORY, @history_file.open.read
- 'outer session'
- foo
- 'inner session'
- exit
- 'outer session again'
- exit!
- HISTORY
- end
-
- def test_history_saving_with_nested_sessions_and_prior_history
- write_history <<~HISTORY
- old_history_1
- old_history_2
- old_history_3
- HISTORY
-
- write_ruby <<~'RUBY'
- def foo
- binding.irb
- end
-
- binding.irb
- RUBY
-
- run_ruby_file do
- type "'outer session'"
- type "foo"
- type "'inner session'"
- type "exit"
- type "'outer session again'"
- type "exit"
- end
-
- assert_equal <<~HISTORY, @history_file.open.read
- old_history_1
- old_history_2
- old_history_3
- 'outer session'
- foo
- 'inner session'
- exit
- 'outer session again'
- exit
- HISTORY
- end
-
- def test_direct_debug_session_loads_history
- @envs['RUBY_DEBUG_IRB_CONSOLE'] = "1"
- write_history <<~HISTORY
- old_history_1
- old_history_2
- old_history_3
- HISTORY
-
- write_ruby <<~'RUBY'
- require 'debug'
- debugger
- binding.irb # needed to satisfy run_ruby_file
- RUBY
-
- output = run_ruby_file do
- type "history"
- type "puts 'foo'"
- type "history"
- type "exit!"
- end
-
- assert_include(output, "irb:rdbg(main):002") # assert that we're in an irb:rdbg session
- assert_include(output, "5: history")
- assert_include(output, "4: puts 'foo'")
- assert_include(output, "3: history")
- assert_include(output, "2: old_history_3")
- assert_include(output, "1: old_history_2")
- assert_include(output, "0: old_history_1")
- end
-
- private
-
- def write_history(history)
- @history_file = Tempfile.new('irb_history')
- @history_file.write(history)
- @history_file.close
- write_rc <<~RUBY
- IRB.conf[:HISTORY_FILE] = "#{@history_file.path}"
- RUBY
- end
- end
-end
diff --git a/test/irb/test_init.rb b/test/irb/test_init.rb
deleted file mode 100644
index f34f692f09..0000000000
--- a/test/irb/test_init.rb
+++ /dev/null
@@ -1,408 +0,0 @@
-# frozen_string_literal: false
-require "irb"
-require "fileutils"
-
-require_relative "helper"
-
-module TestIRB
- class InitTest < TestCase
- def setup
- # IRBRC is for RVM...
- @backup_env = %w[HOME XDG_CONFIG_HOME IRBRC].each_with_object({}) do |env, hash|
- hash[env] = ENV.delete(env)
- end
- ENV["HOME"] = @tmpdir = File.realpath(Dir.mktmpdir("test_irb_init_#{$$}"))
- end
-
- def reset_rc_name_generators
- IRB.instance_variable_set(:@existing_rc_name_generators, nil)
- end
-
- def teardown
- ENV.update(@backup_env)
- FileUtils.rm_rf(@tmpdir)
- IRB.conf.delete(:SCRIPT)
- reset_rc_name_generators
- end
-
- def test_setup_with_argv_preserves_global_argv
- argv = ["foo", "bar"]
- with_argv(argv) do
- IRB.setup(eval("__FILE__"), argv: %w[-f])
- assert_equal argv, ARGV
- end
- end
-
- def test_setup_with_minimum_argv_does_not_change_dollar0
- orig = $0.dup
- IRB.setup(eval("__FILE__"), argv: %w[-f])
- assert_equal orig, $0
- end
-
- def test_rc_files
- tmpdir = @tmpdir
- Dir.chdir(tmpdir) do
- home = ENV['HOME'] = "#{tmpdir}/home"
- xdg_config_home = ENV['XDG_CONFIG_HOME'] = "#{tmpdir}/xdg"
- reset_rc_name_generators
- assert_empty(IRB.irbrc_files)
- assert_equal("#{home}/.irb_history", IRB.rc_file('_history'))
- FileUtils.mkdir_p(home)
- FileUtils.mkdir_p("#{xdg_config_home}/irb")
- FileUtils.mkdir_p("#{home}/.config/irb")
- reset_rc_name_generators
- assert_empty(IRB.irbrc_files)
- assert_equal("#{xdg_config_home}/irb/irb_history", IRB.rc_file('_history'))
- home_irbrc = "#{home}/.irbrc"
- config_irbrc = "#{home}/.config/irb/irbrc"
- xdg_config_irbrc = "#{xdg_config_home}/irb/irbrc"
- [home_irbrc, config_irbrc, xdg_config_irbrc].each do |file|
- FileUtils.touch(file)
- end
- current_dir_irbrcs = %w[.irbrc irbrc _irbrc $irbrc].map { |file| "#{tmpdir}/#{file}" }
- current_dir_irbrcs.each { |file| FileUtils.touch(file) }
- reset_rc_name_generators
- assert_equal([xdg_config_irbrc, home_irbrc, *current_dir_irbrcs], IRB.irbrc_files)
- assert_equal(xdg_config_irbrc.sub(/rc$/, '_history'), IRB.rc_file('_history'))
- ENV['XDG_CONFIG_HOME'] = nil
- reset_rc_name_generators
- assert_equal([home_irbrc, config_irbrc, *current_dir_irbrcs], IRB.irbrc_files)
- assert_equal(home_irbrc.sub(/rc$/, '_history'), IRB.rc_file('_history'))
- ENV['XDG_CONFIG_HOME'] = ''
- reset_rc_name_generators
- assert_equal([home_irbrc, config_irbrc] + current_dir_irbrcs, IRB.irbrc_files)
- assert_equal(home_irbrc.sub(/rc$/, '_history'), IRB.rc_file('_history'))
- ENV['XDG_CONFIG_HOME'] = xdg_config_home
- ENV['IRBRC'] = "#{tmpdir}/.irbrc"
- reset_rc_name_generators
- assert_equal([ENV['IRBRC'], xdg_config_irbrc, home_irbrc] + (current_dir_irbrcs - [ENV['IRBRC']]), IRB.irbrc_files)
- assert_equal(ENV['IRBRC'] + '_history', IRB.rc_file('_history'))
- ENV['IRBRC'] = ENV['HOME'] = ENV['XDG_CONFIG_HOME'] = nil
- reset_rc_name_generators
- assert_equal(current_dir_irbrcs, IRB.irbrc_files)
- assert_nil(IRB.rc_file('_history'))
- end
- end
-
- def test_duplicated_rc_files
- tmpdir = @tmpdir
- Dir.chdir(tmpdir) do
- ENV['XDG_CONFIG_HOME'] = "#{ENV['HOME']}/.config"
- FileUtils.mkdir_p("#{ENV['XDG_CONFIG_HOME']}/irb")
- env_irbrc = ENV['IRBRC'] = "#{tmpdir}/_irbrc"
- xdg_config_irbrc = "#{ENV['XDG_CONFIG_HOME']}/irb/irbrc"
- home_irbrc = "#{ENV['HOME']}/.irbrc"
- current_dir_irbrc = "#{tmpdir}/irbrc"
- [env_irbrc, xdg_config_irbrc, home_irbrc, current_dir_irbrc].each do |file|
- FileUtils.touch(file)
- end
- reset_rc_name_generators
- assert_equal([env_irbrc, xdg_config_irbrc, home_irbrc, current_dir_irbrc], IRB.irbrc_files)
- end
- end
-
- def test_sigint_restore_default
- pend "This test gets stuck on Solaris for unknown reason; contribution is welcome" if RUBY_PLATFORM =~ /solaris/
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- # IRB should restore SIGINT handler
- status = assert_in_out_err(bundle_exec + %w[-W0 -rirb -e Signal.trap("SIGINT","DEFAULT");binding.irb;loop{Process.kill("SIGINT",$$)} -- -f --], "exit\n", //, //)
- Process.kill("SIGKILL", status.pid) if !status.exited? && !status.stopped? && !status.signaled?
- end
-
- def test_sigint_restore_block
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- # IRB should restore SIGINT handler
- status = assert_in_out_err(bundle_exec + %w[-W0 -rirb -e x=false;Signal.trap("SIGINT"){x=true};binding.irb;loop{Process.kill("SIGINT",$$);if(x);break;end} -- -f --], "exit\n", //, //)
- Process.kill("SIGKILL", status.pid) if !status.exited? && !status.stopped? && !status.signaled?
- end
-
- def test_no_color_environment_variable
- orig_no_color = ENV['NO_COLOR']
- orig_use_colorize = IRB.conf[:USE_COLORIZE]
- IRB.conf[:USE_COLORIZE] = true
-
- assert IRB.conf[:USE_COLORIZE]
-
- ENV['NO_COLOR'] = 'true'
- IRB.setup(__FILE__)
- refute IRB.conf[:USE_COLORIZE]
-
- ENV['NO_COLOR'] = ''
- IRB.setup(__FILE__)
- assert IRB.conf[:USE_COLORIZE]
-
- ENV['NO_COLOR'] = nil
- IRB.setup(__FILE__)
- assert IRB.conf[:USE_COLORIZE]
- ensure
- ENV['NO_COLOR'] = orig_no_color
- IRB.conf[:USE_COLORIZE] = orig_use_colorize
- end
-
- def test_use_autocomplete_environment_variable
- orig_use_autocomplete_env = ENV['IRB_USE_AUTOCOMPLETE']
- orig_use_autocomplete_conf = IRB.conf[:USE_AUTOCOMPLETE]
-
- ENV['IRB_USE_AUTOCOMPLETE'] = nil
- IRB.setup(__FILE__)
- assert IRB.conf[:USE_AUTOCOMPLETE]
-
- ENV['IRB_USE_AUTOCOMPLETE'] = ''
- IRB.setup(__FILE__)
- assert IRB.conf[:USE_AUTOCOMPLETE]
-
- ENV['IRB_USE_AUTOCOMPLETE'] = 'false'
- IRB.setup(__FILE__)
- refute IRB.conf[:USE_AUTOCOMPLETE]
-
- ENV['IRB_USE_AUTOCOMPLETE'] = 'true'
- IRB.setup(__FILE__)
- assert IRB.conf[:USE_AUTOCOMPLETE]
- ensure
- ENV["IRB_USE_AUTOCOMPLETE"] = orig_use_autocomplete_env
- IRB.conf[:USE_AUTOCOMPLETE] = orig_use_autocomplete_conf
- end
-
- def test_copy_command_environment_variable
- orig_copy_command_env = ENV['IRB_COPY_COMMAND']
- orig_copy_command_conf = IRB.conf[:COPY_COMMAND]
-
- ENV['IRB_COPY_COMMAND'] = nil
- IRB.setup(__FILE__)
- refute IRB.conf[:COPY_COMMAND]
-
- ENV['IRB_COPY_COMMAND'] = ''
- IRB.setup(__FILE__)
- assert_equal('', IRB.conf[:COPY_COMMAND])
-
- ENV['IRB_COPY_COMMAND'] = 'blah'
- IRB.setup(__FILE__)
- assert_equal('blah', IRB.conf[:COPY_COMMAND])
- ensure
- ENV['IRB_COPY_COMMAND'] = orig_copy_command_env
- IRB.conf[:COPY_COMMAND] = orig_copy_command_conf
- end
-
- def test_completor_environment_variable
- orig_use_autocomplete_env = ENV['IRB_COMPLETOR']
- orig_use_autocomplete_conf = IRB.conf[:COMPLETOR]
-
- # Default value is nil: auto-detect
- ENV['IRB_COMPLETOR'] = nil
- IRB.setup(__FILE__)
- assert_equal(nil, IRB.conf[:COMPLETOR])
-
- ENV['IRB_COMPLETOR'] = 'regexp'
- IRB.setup(__FILE__)
- assert_equal(:regexp, IRB.conf[:COMPLETOR])
-
- ENV['IRB_COMPLETOR'] = 'type'
- IRB.setup(__FILE__)
- assert_equal(:type, IRB.conf[:COMPLETOR])
-
- ENV['IRB_COMPLETOR'] = 'regexp'
- IRB.setup(__FILE__, argv: ['--type-completor'])
- assert_equal :type, IRB.conf[:COMPLETOR]
-
- ENV['IRB_COMPLETOR'] = 'type'
- IRB.setup(__FILE__, argv: ['--regexp-completor'])
- assert_equal :regexp, IRB.conf[:COMPLETOR]
- ensure
- ENV['IRB_COMPLETOR'] = orig_use_autocomplete_env
- IRB.conf[:COMPLETOR] = orig_use_autocomplete_conf
- end
-
- def test_completor_setup_with_argv
- orig_completor_conf = IRB.conf[:COMPLETOR]
- orig_completor_env = ENV['IRB_COMPLETOR']
- ENV['IRB_COMPLETOR'] = nil
-
- # Default value is nil: auto-detect
- IRB.setup(__FILE__, argv: [])
- assert_equal nil, IRB.conf[:COMPLETOR]
-
- IRB.setup(__FILE__, argv: ['--type-completor'])
- assert_equal :type, IRB.conf[:COMPLETOR]
-
- IRB.setup(__FILE__, argv: ['--regexp-completor'])
- assert_equal :regexp, IRB.conf[:COMPLETOR]
- ensure
- IRB.conf[:COMPLETOR] = orig_completor_conf
- ENV['IRB_COMPLETOR'] = orig_completor_env
- end
-
- def test_noscript
- argv = %w[--noscript -- -f]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_nil IRB.conf[:SCRIPT]
- assert_equal(['-f'], argv)
-
- argv = %w[--noscript -- a]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_nil IRB.conf[:SCRIPT]
- assert_equal(['a'], argv)
-
- argv = %w[--noscript a]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_nil IRB.conf[:SCRIPT]
- assert_equal(['a'], argv)
-
- argv = %w[--script --noscript a]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_nil IRB.conf[:SCRIPT]
- assert_equal(['a'], argv)
-
- argv = %w[--noscript --script a]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_equal('a', IRB.conf[:SCRIPT])
- assert_equal([], argv)
- end
-
- def test_dash
- argv = %w[-]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_equal('-', IRB.conf[:SCRIPT])
- assert_equal([], argv)
-
- argv = %w[-- -]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_equal('-', IRB.conf[:SCRIPT])
- assert_equal([], argv)
-
- argv = %w[-- - -f]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_equal('-', IRB.conf[:SCRIPT])
- assert_equal(['-f'], argv)
- end
-
- def test_option_tracer
- argv = %w[--tracer]
- IRB.setup(eval("__FILE__"), argv: argv)
- assert_equal(true, IRB.conf[:USE_TRACER])
- end
-
- private
-
- def with_argv(argv)
- orig = ARGV.dup
- ARGV.replace(argv)
- yield
- ensure
- ARGV.replace(orig)
- end
- end
-
- class ConfigValidationTest < TestCase
- def setup
- # To prevent the test from using the user's .irbrc file
- @home = Dir.mktmpdir
- setup_envs(home: @home)
- super
- end
-
- def teardown
- super
- teardown_envs
- File.unlink(@irbrc)
- Dir.rmdir(@home)
- IRB.instance_variable_set(:@existing_rc_name_generators, nil)
- end
-
- def test_irb_name_converts_non_string_values_to_string
- assert_no_irb_validation_error(<<~'RUBY')
- IRB.conf[:IRB_NAME] = :foo
- RUBY
-
- assert_equal "foo", IRB.conf[:IRB_NAME]
- end
-
- def test_irb_rc_name_only_takes_callable_objects
- assert_irb_validation_error(<<~'RUBY', "IRB.conf[:IRB_RC] should be a callable object. Got :foo.")
- IRB.conf[:IRB_RC] = :foo
- RUBY
- end
-
- def test_back_trace_limit_only_accepts_integers
- assert_irb_validation_error(<<~'RUBY', "IRB.conf[:BACK_TRACE_LIMIT] should be an integer. Got \"foo\".")
- IRB.conf[:BACK_TRACE_LIMIT] = "foo"
- RUBY
- end
-
- def test_prompt_only_accepts_hash
- assert_irb_validation_error(<<~'RUBY', "IRB.conf[:PROMPT] should be a Hash. Got \"foo\".")
- IRB.conf[:PROMPT] = "foo"
- RUBY
- end
-
- def test_eval_history_only_accepts_integers
- assert_irb_validation_error(<<~'RUBY', "IRB.conf[:EVAL_HISTORY] should be an integer. Got \"foo\".")
- IRB.conf[:EVAL_HISTORY] = "foo"
- RUBY
- end
-
- private
-
- def assert_irb_validation_error(rc_content, error_message)
- write_rc rc_content
-
- assert_raise_with_message(TypeError, error_message) do
- IRB.setup(__FILE__)
- end
- end
-
- def assert_no_irb_validation_error(rc_content)
- write_rc rc_content
-
- assert_nothing_raised do
- IRB.setup(__FILE__)
- end
- end
-
- def write_rc(content)
- @irbrc = Tempfile.new('irbrc')
- @irbrc.write(content)
- @irbrc.close
- ENV['IRBRC'] = @irbrc.path
- end
- end
-
- class InitIntegrationTest < IntegrationTestCase
- def setup
- super
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
- end
-
- def test_load_error_in_rc_file_is_warned
- write_rc <<~'IRBRC'
- require "file_that_does_not_exist"
- IRBRC
-
- output = run_ruby_file do
- type "'foobar'"
- type "exit"
- end
-
- # IRB session should still be started
- assert_includes output, "foobar"
- assert_includes output, 'cannot load such file -- file_that_does_not_exist (LoadError)'
- end
-
- def test_normal_errors_in_rc_file_is_warned
- write_rc <<~'IRBRC'
- raise "I'm an error"
- IRBRC
-
- output = run_ruby_file do
- type "'foobar'"
- type "exit"
- end
-
- # IRB session should still be started
- assert_includes output, "foobar"
- assert_includes output, 'I\'m an error (RuntimeError)'
- end
- end
-end
diff --git a/test/irb/test_input_method.rb b/test/irb/test_input_method.rb
deleted file mode 100644
index bd107551df..0000000000
--- a/test/irb/test_input_method.rb
+++ /dev/null
@@ -1,195 +0,0 @@
-# frozen_string_literal: false
-
-require "irb"
-begin
- require "rdoc"
-rescue LoadError
-end
-require_relative "helper"
-
-module TestIRB
- class InputMethodTest < TestCase
- def setup
- @conf_backup = IRB.conf.dup
- IRB.init_config(nil)
- IRB.conf[:LC_MESSAGES] = IRB::Locale.new
- save_encodings
- end
-
- def teardown
- IRB.conf.replace(@conf_backup)
- restore_encodings
- # Reset Reline configuration overridden by RelineInputMethod.
- Reline.instance_variable_set(:@core, nil)
- end
- end
-
- class RelineInputMethodTest < InputMethodTest
- def test_initialization
- Reline.completion_proc = nil
- Reline.dig_perfect_match_proc = nil
- IRB::RelineInputMethod.new(IRB::RegexpCompletor.new)
-
- assert_nil Reline.completion_append_character
- assert_equal '', Reline.completer_quote_characters
- assert_equal IRB::InputMethod::BASIC_WORD_BREAK_CHARACTERS, Reline.basic_word_break_characters
- assert_not_nil Reline.completion_proc
- assert_not_nil Reline.dig_perfect_match_proc
- end
-
- def test_colorize
- IRB.conf[:USE_COLORIZE] = true
- IRB.conf[:VERBOSE] = false
- original_colorable = IRB::Color.method(:colorable?)
- IRB::Color.instance_eval { undef :colorable? }
- IRB::Color.define_singleton_method(:colorable?) { true }
- workspace = IRB::WorkSpace.new(binding)
- input_method = IRB::RelineInputMethod.new(IRB::RegexpCompletor.new)
- IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new(workspace, input_method).context
- assert_equal "\e[1m$\e[0m\e[m", Reline.output_modifier_proc.call('$', complete: false)
- assert_equal "\e[1m$\e[0m\e[m \e[34m\e[1m1\e[0m + \e[34m\e[1m2\e[0m", Reline.output_modifier_proc.call('$ 1 + 2', complete: false)
- assert_equal "\e[32m\e[1m$a\e[0m", Reline.output_modifier_proc.call('$a', complete: false)
- ensure
- IRB::Color.instance_eval { undef :colorable? }
- IRB::Color.define_singleton_method(:colorable?, original_colorable)
- end
-
- def test_initialization_without_use_autocomplete
- original_show_doc_proc = Reline.dialog_proc(:show_doc)&.dialog_proc
- empty_proc = Proc.new {}
- Reline.add_dialog_proc(:show_doc, empty_proc)
-
- IRB.conf[:USE_AUTOCOMPLETE] = false
-
- IRB::RelineInputMethod.new(IRB::RegexpCompletor.new)
-
- refute Reline.autocompletion
- assert_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc
- ensure
- Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
- end
-
- def test_initialization_with_use_autocomplete
- omit 'This test requires RDoc' unless defined?(RDoc)
- original_show_doc_proc = Reline.dialog_proc(:show_doc)&.dialog_proc
- empty_proc = Proc.new {}
- Reline.add_dialog_proc(:show_doc, empty_proc)
-
- IRB.conf[:USE_AUTOCOMPLETE] = true
-
- IRB::RelineInputMethod.new(IRB::RegexpCompletor.new)
-
- assert Reline.autocompletion
- assert_not_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc
- ensure
- Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
- end
-
- def test_initialization_with_use_autocomplete_but_without_rdoc
- original_show_doc_proc = Reline.dialog_proc(:show_doc)&.dialog_proc
- empty_proc = Proc.new {}
- Reline.add_dialog_proc(:show_doc, empty_proc)
-
- IRB.conf[:USE_AUTOCOMPLETE] = true
-
- without_rdoc do
- IRB::RelineInputMethod.new(IRB::RegexpCompletor.new)
- end
-
- assert Reline.autocompletion
- # doesn't register show_doc dialog
- assert_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc
- ensure
- Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
- end
- end
-
- class DisplayDocumentTest < InputMethodTest
- def setup
- super
- @driver = RDoc::RI::Driver.new(use_stdout: true)
- end
-
- def display_document(target, bind, driver = nil)
- input_method = IRB::RelineInputMethod.new(IRB::RegexpCompletor.new)
- input_method.instance_variable_set(:@rdoc_ri_driver, driver) if driver
- input_method.instance_variable_set(:@completion_params, ['', target, '', bind])
- input_method.display_document(target)
- end
-
- def test_perfectly_matched_namespace_triggers_document_display
- omit unless has_rdoc_content?
-
- out, err = capture_output do
- display_document("String", binding, @driver)
- end
-
- assert_empty(err)
-
- assert_include(out, " S\bSt\btr\bri\bin\bng\bg")
- end
-
- def test_perfectly_matched_multiple_namespaces_triggers_document_display
- result = nil
- out, err = capture_output do
- result = display_document("{}.nil?", binding, @driver)
- end
-
- assert_empty(err)
-
- # check if there're rdoc contents (e.g. CI doesn't generate them)
- if has_rdoc_content?
- # if there's rdoc content, we can verify by checking stdout
- # rdoc generates control characters for formatting method names
- assert_include(out, "P\bPr\bro\boc\bc.\b.n\bni\bil\bl?\b?") # Proc.nil?
- assert_include(out, "H\bHa\bas\bsh\bh.\b.n\bni\bil\bl?\b?") # Hash.nil?
- else
- # this is a hacky way to verify the rdoc rendering code path because CI doesn't have rdoc content
- # if there are multiple namespaces to be rendered, PerfectMatchedProc renders the result with a document
- # which always returns the bytes rendered, even if it's 0
- assert_equal(0, result)
- end
- end
-
- def test_not_matched_namespace_triggers_nothing
- result = nil
- out, err = capture_output do
- result = display_document("Stri", binding, @driver)
- end
-
- assert_empty(err)
- assert_empty(out)
- assert_nil(result)
- end
-
- def test_perfect_matching_stops_without_rdoc
- result = nil
-
- out, err = capture_output do
- without_rdoc do
- result = display_document("String", binding)
- end
- end
-
- assert_empty(err)
- assert_not_match(/from ruby core/, out)
- assert_nil(result)
- end
-
- def test_perfect_matching_handles_nil_namespace
- out, err = capture_output do
- # symbol literal has `nil` doc namespace so it's a good test subject
- assert_nil(display_document(":aiueo", binding, @driver))
- end
-
- assert_empty(err)
- assert_empty(out)
- end
-
- private
-
- def has_rdoc_content?
- File.exist?(RDoc::RI::Paths::BASE)
- end
- end if defined?(RDoc)
-end
diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb
deleted file mode 100644
index 617e9c9614..0000000000
--- a/test/irb/test_irb.rb
+++ /dev/null
@@ -1,936 +0,0 @@
-# frozen_string_literal: true
-require "irb"
-
-require_relative "helper"
-
-module TestIRB
- class InputTest < IntegrationTestCase
- def test_symbol_aliases_are_handled_correctly
- write_ruby <<~'RUBY'
- class Foo
- end
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "$ Foo"
- type "exit!"
- end
-
- assert_include output, "From: #{@ruby_file.path}:1"
- end
-
- def test_symbol_aliases_are_handled_correctly_with_singleline_mode
- write_rc <<~RUBY
- IRB.conf[:USE_SINGLELINE] = true
- RUBY
-
- write_ruby <<~'RUBY'
- class Foo
- end
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "irb_info"
- type "$ Foo"
- type "exit!"
- end
-
- # Make sure it's tested in singleline mode
- assert_include output, "InputMethod: ReadlineInputMethod"
- assert_include output, "From: #{@ruby_file.path}:1"
- end
-
- def test_underscore_stores_last_result
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "1 + 1"
- type "_ + 10"
- type "exit!"
- end
-
- assert_include output, "=> 12"
- end
-
- def test_commands_dont_override_stored_last_result
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "1 + 1"
- type "ls"
- type "_ + 10"
- type "exit!"
- end
-
- assert_include output, "=> 12"
- end
-
- def test_evaluate_with_encoding_error_without_lineno
- if RUBY_ENGINE == 'truffleruby'
- omit "Remove me after https://github.com/ruby/prism/issues/2129 is addressed and adopted in TruffleRuby"
- end
-
- if RUBY_VERSION >= "3.3."
- omit "Now raises SyntaxError"
- end
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type %q[:"\xAE"]
- type "exit!"
- end
-
- assert_include output, 'invalid symbol in encoding UTF-8 :"\xAE"'
- # EncodingError would be wrapped with ANSI escape sequences, so we assert it separately
- assert_include output, "EncodingError"
- end
-
- def test_evaluate_still_emits_warning
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type %q[def foo; END {}; end]
- type "exit!"
- end
-
- assert_include output, '(irb):1: warning: END in method; use at_exit'
- end
-
- def test_symbol_aliases_dont_affect_ruby_syntax
- write_ruby <<~'RUBY'
- $foo = "It's a foo"
- @bar = "It's a bar"
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "$foo"
- type "@bar"
- type "exit!"
- end
-
- assert_include output, "=> \"It's a foo\""
- assert_include output, "=> \"It's a bar\""
- end
-
- def test_empty_input_echoing_behaviour
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type ""
- type " "
- type "exit"
- end
-
- assert_not_match(/irb\(main\):001> (\r*\n)?=> nil/, output)
- assert_match(/irb\(main\):002> (\r*\n)?=> nil/, output)
- end
- end
-
- class NestedBindingIrbTest < IntegrationTestCase
- def test_current_context_restore
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type '$ctx = IRB.CurrentContext'
- type 'binding.irb'
- type 'p context_changed: IRB.CurrentContext != $ctx'
- type 'exit'
- type 'p context_restored: IRB.CurrentContext == $ctx'
- type 'exit'
- end
-
- assert_include output, {context_changed: true}.inspect
- assert_include output, {context_restored: true}.inspect
- end
- end
-
- class IrbIOConfigurationTest < TestCase
- Row = Struct.new(:content, :current_line_spaces, :new_line_spaces, :indent_level)
-
- class MockIO_AutoIndent
- attr_reader :calculated_indent
-
- def initialize(*params)
- @params = params
- end
-
- def auto_indent(&block)
- @calculated_indent = block.call(*@params)
- end
- end
-
- class MockIO_DynamicPrompt
- attr_reader :prompt_list
-
- def initialize(params, &assertion)
- @params = params
- end
-
- def dynamic_prompt(&block)
- @prompt_list = block.call(@params)
- end
- end
-
- def setup
- save_encodings
- @irb = build_irb
- end
-
- def teardown
- restore_encodings
- end
-
- class AutoIndentationTest < IrbIOConfigurationTest
- def test_auto_indent
- input_with_correct_indents = [
- [%q(def each_top_level_statement), 0, 2],
- [%q( initialize_input), 2, 2],
- [%q( catch(:TERM_INPUT) do), 2, 4],
- [%q( loop do), 4, 6],
- [%q( begin), 6, 8],
- [%q( prompt), 8, 8],
- [%q( unless l = lex), 8, 10],
- [%q( throw :TERM_INPUT if @line == ''), 10, 10],
- [%q( else), 8, 10],
- [%q( @line_no += l.count("\n")), 10, 10],
- [%q( next if l == "\n"), 10, 10],
- [%q( @line.concat l), 10, 10],
- [%q( if @code_block_open or @ltype or @continue or @indent > 0), 10, 12],
- [%q( next), 12, 12],
- [%q( end), 10, 10],
- [%q( end), 8, 8],
- [%q( if @line != "\n"), 8, 10],
- [%q( @line.force_encoding(@io.encoding)), 10, 10],
- [%q( yield @line, @exp_line_no), 10, 10],
- [%q( end), 8, 8],
- [%q( break if @io.eof?), 8, 8],
- [%q( @line = ''), 8, 8],
- [%q( @exp_line_no = @line_no), 8, 8],
- [%q( ), nil, 8],
- [%q( @indent = 0), 8, 8],
- [%q( rescue TerminateLineInput), 6, 8],
- [%q( initialize_input), 8, 8],
- [%q( prompt), 8, 8],
- [%q( end), 6, 6],
- [%q( end), 4, 4],
- [%q( end), 2, 2],
- [%q(end), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_braces_on_their_own_line
- input_with_correct_indents = [
- [%q(if true), 0, 2],
- [%q( [), 2, 4],
- [%q( ]), 2, 2],
- [%q(end), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_multiple_braces_in_a_line
- input_with_correct_indents = [
- [%q([[[), 0, 6],
- [%q( ]), 4, 4],
- [%q( ]), 2, 2],
- [%q(]), 0, 0],
- [%q([<<FOO]), 0, 0],
- [%q(hello), 0, 0],
- [%q(FOO), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_a_closed_brace_and_not_closed_brace_in_a_line
- input_with_correct_indents = [
- [%q(p() {), 0, 2],
- [%q(}), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_symbols
- input_with_correct_indents = [
- [%q(:a), 0, 0],
- [%q(:A), 0, 0],
- [%q(:+), 0, 0],
- [%q(:@@a), 0, 0],
- [%q(:@a), 0, 0],
- [%q(:$a), 0, 0],
- [%q(:def), 0, 0],
- [%q(:`), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_incomplete_coding_magic_comment
- input_with_correct_indents = [
- [%q(#coding:u), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_incomplete_encoding_magic_comment
- input_with_correct_indents = [
- [%q(#encoding:u), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_incomplete_emacs_coding_magic_comment
- input_with_correct_indents = [
- [%q(# -*- coding: u), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_incomplete_vim_coding_magic_comment
- input_with_correct_indents = [
- [%q(# vim:set fileencoding=u), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_mixed_rescue
- input_with_correct_indents = [
- [%q(def m), 0, 2],
- [%q( begin), 2, 4],
- [%q( begin), 4, 6],
- [%q( x = a rescue 4), 6, 6],
- [%q( y = [(a rescue 5)]), 6, 6],
- [%q( [x, y]), 6, 6],
- [%q( rescue => e), 4, 6],
- [%q( raise e rescue 8), 6, 6],
- [%q( end), 4, 4],
- [%q( rescue), 2, 4],
- [%q( raise rescue 11), 4, 4],
- [%q( end), 2, 2],
- [%q(rescue => e), 0, 2],
- [%q( raise e rescue 14), 2, 2],
- [%q(end), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_oneliner_method_definition
- input_with_correct_indents = [
- [%q(class A), 0, 2],
- [%q( def foo0), 2, 4],
- [%q( 3), 4, 4],
- [%q( end), 2, 2],
- [%q( def foo1()), 2, 4],
- [%q( 3), 4, 4],
- [%q( end), 2, 2],
- [%q( def foo2(a, b)), 2, 4],
- [%q( a + b), 4, 4],
- [%q( end), 2, 2],
- [%q( def foo3 a, b), 2, 4],
- [%q( a + b), 4, 4],
- [%q( end), 2, 2],
- [%q( def bar0() = 3), 2, 2],
- [%q( def bar1(a) = a), 2, 2],
- [%q( def bar2(a, b) = a + b), 2, 2],
- [%q( def bar3() = :s), 2, 2],
- [%q( def bar4() = Time.now), 2, 2],
- [%q(end), 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents)
- end
-
- def test_tlambda
- input_with_correct_indents = [
- [%q(if true), 0, 2, 1],
- [%q( -> {), 2, 4, 2],
- [%q( }), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_corresponding_syntax_to_keyword_do_in_class
- input_with_correct_indents = [
- [%q(class C), 0, 2, 1],
- [%q( while method_name do), 2, 4, 2],
- [%q( 3), 4, 4, 2],
- [%q( end), 2, 2, 1],
- [%q( foo do), 2, 4, 2],
- [%q( 3), 4, 4, 2],
- [%q( end), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_corresponding_syntax_to_keyword_do
- input_with_correct_indents = [
- [%q(while i > 0), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while true), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while ->{i > 0}.call), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while ->{true}.call), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while i > 0 do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while true do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while ->{i > 0}.call do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(while ->{true}.call do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(foo do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(foo true do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(foo ->{true} do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(foo ->{i > 0} do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_corresponding_syntax_to_keyword_for
- input_with_correct_indents = [
- [%q(for i in [1]), 0, 2, 1],
- [%q( puts i), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_corresponding_syntax_to_keyword_for_with_do
- input_with_correct_indents = [
- [%q(for i in [1] do), 0, 2, 1],
- [%q( puts i), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_typing_incomplete_include_interpreted_as_keyword_in
- input_with_correct_indents = [
- [%q(module E), 0, 2, 1],
- [%q(end), 0, 0, 0],
- [%q(class A), 0, 2, 1],
- [%q( in), 2, 2, 1] # scenario typing `include E`
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
-
- end
-
- def test_bracket_corresponding_to_times
- input_with_correct_indents = [
- [%q(3.times { |i|), 0, 2, 1],
- [%q( puts i), 2, 2, 1],
- [%q(}), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_do_corresponding_to_times
- input_with_correct_indents = [
- [%q(3.times do |i|), 0, 2, 1],
- [%q( puts i), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_bracket_corresponding_to_loop
- input_with_correct_indents = [
- ['loop {', 0, 2, 1],
- [' 3', 2, 2, 1],
- ['}', 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_do_corresponding_to_loop
- input_with_correct_indents = [
- [%q(loop do), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_embdoc_indent
- input_with_correct_indents = [
- [%q(=begin), 0, 0, 0],
- [%q(a), 0, 0, 0],
- [%q( b), 1, 1, 0],
- [%q(=end), 0, 0, 0],
- [%q(if 1), 0, 2, 1],
- [%q( 2), 2, 2, 1],
- [%q(=begin), 0, 0, 0],
- [%q(a), 0, 0, 0],
- [%q( b), 1, 1, 0],
- [%q(=end), 0, 2, 1],
- [%q( 3), 2, 2, 1],
- [%q(end), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_heredoc_with_indent
- input_with_correct_indents = [
- [%q(<<~Q+<<~R), 0, 2, 1],
- [%q(a), 2, 2, 1],
- [%q(a), 2, 2, 1],
- [%q( b), 2, 2, 1],
- [%q( b), 2, 2, 1],
- [%q( Q), 0, 2, 1],
- [%q( c), 4, 4, 1],
- [%q( c), 4, 4, 1],
- [%q( R), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_oneliner_def_in_multiple_lines
- input_with_correct_indents = [
- [%q(def a()=[), 0, 2, 1],
- [%q( 1,), 2, 2, 1],
- [%q(].), 0, 0, 0],
- [%q(to_s), 0, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_broken_heredoc
- input_with_correct_indents = [
- [%q(def foo), 0, 2, 1],
- [%q( <<~Q), 2, 4, 2],
- [%q( Qend), 4, 4, 2],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_pasted_code_keep_base_indent_spaces
- input_with_correct_indents = [
- [%q( def foo), 0, 6, 1],
- [%q( if bar), 6, 10, 2],
- [%q( [1), 10, 12, 3],
- [%q( ]+[["a), 10, 14, 4],
- [%q(b" + `c), 0, 14, 4],
- [%q(d` + /e), 0, 14, 4],
- [%q(f/ + :"g), 0, 14, 4],
- [%q(h".tap do), 0, 16, 5],
- [%q( 1), 16, 16, 5],
- [%q( end), 14, 14, 4],
- [%q( ]), 12, 12, 3],
- [%q( ]), 10, 10, 2],
- [%q( end), 8, 6, 1],
- [%q( end), 4, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_pasted_code_keep_base_indent_spaces_with_heredoc
- input_with_correct_indents = [
- [%q( def foo), 0, 6, 1],
- [%q( if bar), 6, 10, 2],
- [%q( [1), 10, 12, 3],
- [%q( ]+[["a), 10, 14, 4],
- [%q(b" + <<~A + <<-B + <<C), 0, 16, 5],
- [%q( a#{), 16, 18, 6],
- [%q( 1), 18, 18, 6],
- [%q( }), 16, 16, 5],
- [%q( A), 14, 16, 5],
- [%q( b#{), 16, 18, 6],
- [%q( 1), 18, 18, 6],
- [%q( }), 16, 16, 5],
- [%q( B), 14, 0, 0],
- [%q(c#{), 0, 2, 1],
- [%q(1), 2, 2, 1],
- [%q(}), 0, 0, 0],
- [%q(C), 0, 14, 4],
- [%q( ]), 12, 12, 3],
- [%q( ]), 10, 10, 2],
- [%q( end), 8, 6, 1],
- [%q( end), 4, 0, 0],
- ]
-
- assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true)
- end
-
- def test_heredoc_keep_indent_spaces
- (1..4).each do |indent|
- row = Row.new(' ' * indent, nil, [4, indent].max, 2)
- lines = ['def foo', ' <<~Q', row.content]
- assert_row_indenting(lines, row)
- assert_indent_level(lines, row.indent_level)
- end
- end
-
- private
-
- def assert_row_indenting(lines, row)
- actual_current_line_spaces = calculate_indenting(lines, false)
-
- error_message = <<~MSG
- Incorrect spaces calculation for line:
-
- ```
- > #{lines.last}
- ```
-
- All lines:
-
- ```
- #{lines.join("\n")}
- ```
- MSG
- assert_equal(row.current_line_spaces, actual_current_line_spaces, error_message)
-
- error_message = <<~MSG
- Incorrect spaces calculation for line after the current line:
-
- ```
- #{lines.last}
- >
- ```
-
- All lines:
-
- ```
- #{lines.join("\n")}
- ```
- MSG
- actual_next_line_spaces = calculate_indenting(lines, true)
- assert_equal(row.new_line_spaces, actual_next_line_spaces, error_message)
- end
-
- def assert_rows_with_correct_indents(rows_with_spaces, assert_indent_level: false)
- lines = []
- rows_with_spaces.map do |row|
- row = Row.new(*row)
- lines << row.content
- assert_row_indenting(lines, row)
-
- if assert_indent_level
- assert_indent_level(lines, row.indent_level)
- end
- end
- end
-
- def assert_indent_level(lines, expected)
- code = lines.map { |l| "#{l}\n" }.join # code should end with "\n"
- _tokens, opens, _ = @irb.scanner.check_code_state(code, local_variables: [])
- indent_level = @irb.scanner.calc_indent_level(opens)
- error_message = "Calculated the wrong number of indent level for:\n #{lines.join("\n")}"
- assert_equal(expected, indent_level, error_message)
- end
-
- def calculate_indenting(lines, add_new_line)
- lines = lines + [""] if add_new_line
- last_line_index = lines.length - 1
- byte_pointer = lines.last.length
-
- mock_io = MockIO_AutoIndent.new(lines, last_line_index, byte_pointer, add_new_line)
- @irb.context.auto_indent_mode = true
- @irb.context.io = mock_io
- @irb.configure_io
-
- mock_io.calculated_indent
- end
- end
-
- class DynamicPromptTest < IrbIOConfigurationTest
- def test_endless_range_at_end_of_line
- input_with_prompt = [
- ['001:0: :> ', %q(a = 3..)],
- ['002:0: :> ', %q()],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_heredoc_with_embexpr
- input_with_prompt = [
- ['001:0:":* ', %q(<<A+%W[#{<<B)],
- ['002:0:":* ', %q(#{<<C+%W[)],
- ['003:0:":* ', %q(a)],
- ['004:2:]:* ', %q(C)],
- ['005:2:]:* ', %q(a)],
- ['006:0:":* ', %q(]})],
- ['007:0:":* ', %q(})],
- ['008:0:":* ', %q(A)],
- ['009:2:]:* ', %q(B)],
- ['010:1:]:* ', %q(})],
- ['011:0: :> ', %q(])],
- ['012:0: :> ', %q()],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_heredoc_prompt_with_quotes
- input_with_prompt = [
- ["001:1:':* ", %q(<<~'A')],
- ["002:1:':* ", %q(#{foobar})],
- ["003:0: :> ", %q(A)],
- ["004:1:`:* ", %q(<<~`A`)],
- ["005:1:`:* ", %q(whoami)],
- ["006:0: :> ", %q(A)],
- ['007:1:":* ', %q(<<~"A")],
- ['008:1:":* ', %q(foobar)],
- ['009:0: :> ', %q(A)],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_backtick_method
- input_with_prompt = [
- ['001:0: :> ', %q(self.`(arg))],
- ['002:0: :> ', %q()],
- ['003:0: :> ', %q(def `(); end)],
- ['004:0: :> ', %q()],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_dynamic_prompt
- input_with_prompt = [
- ['001:1: :* ', %q(def hoge)],
- ['002:1: :* ', %q( 3)],
- ['003:0: :> ', %q(end)],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_dynamic_prompt_with_double_newline_breaking_code
- input_with_prompt = [
- ['001:1: :* ', %q(if true)],
- ['002:2: :* ', %q(%)],
- ['003:1: :* ', %q(;end)],
- ['004:1: :* ', %q(;hello)],
- ['005:0: :> ', %q(end)],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_dynamic_prompt_with_multiline_literal
- input_with_prompt = [
- ['001:1: :* ', %q(if true)],
- ['002:2:]:* ', %q( %w[)],
- ['003:2:]:* ', %q( a)],
- ['004:1: :* ', %q( ])],
- ['005:1: :* ', %q( b)],
- ['006:2:]:* ', %q( %w[)],
- ['007:2:]:* ', %q( c)],
- ['008:1: :* ', %q( ])],
- ['009:0: :> ', %q(end)],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def test_dynamic_prompt_with_blank_line
- input_with_prompt = [
- ['001:1:]:* ', %q(%w[)],
- ['002:1:]:* ', %q()],
- ['003:0: :> ', %q(])],
- ]
-
- assert_dynamic_prompt(input_with_prompt)
- end
-
- def assert_dynamic_prompt(input_with_prompt)
- expected_prompt_list, lines = input_with_prompt.transpose
- def @irb.generate_prompt(opens, continue, line_offset)
- ltype = @scanner.ltype_from_open_tokens(opens)
- indent = @scanner.calc_indent_level(opens)
- continue = opens.any? || continue
- line_no = @line_no + line_offset
- '%03d:%01d:%1s:%s ' % [line_no, indent, ltype, continue ? '*' : '>']
- end
- io = MockIO_DynamicPrompt.new(lines)
- @irb.context.io = io
- @irb.configure_io
-
- error_message = <<~EOM
- Expected dynamic prompt:
- #{expected_prompt_list.join("\n")}
-
- Actual dynamic prompt:
- #{io.prompt_list.join("\n")}
- EOM
- assert_equal(expected_prompt_list, io.prompt_list, error_message)
- end
- end
-
- private
-
- def build_binding
- Object.new.instance_eval { binding }
- end
-
- def build_irb
- IRB.init_config(nil)
- workspace = IRB::WorkSpace.new(build_binding)
-
- IRB.conf[:VERBOSE] = false
- IRB::Irb.new(workspace, TestInputMethod.new)
- end
- end
-
- class BacktraceFilteringTest < TestIRB::IntegrationTestCase
- def setup
- super
- # These tests are sensitive to warnings, so we disable them
- original_rubyopt = [ENV["RUBYOPT"], @envs["RUBYOPT"]].compact.join(" ")
- @envs["RUBYOPT"] = original_rubyopt + " -W0"
- end
-
- def test_backtrace_filtering
- write_ruby <<~'RUBY'
- def foo
- raise "error"
- end
-
- def bar
- foo
- end
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "bar"
- type "exit"
- end
-
- assert_match(/irbtest-.*\.rb:2:in (`|'Object#)foo': error \(RuntimeError\)/, output)
- frame_traces = output.split("\n").select { |line| line.strip.match?(/from /) }.map(&:strip)
-
- expected_traces = if RUBY_VERSION >= "3.3.0"
- [
- /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/,
- /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/,
- /from <internal:kernel>:\d+:in (`|'Kernel#)loop'/,
- /from <internal:prelude>:\d+:in (`|'Binding#)irb'/,
- /from .*\/irbtest-.*.rb:9:in [`']<main>'/
- ]
- else
- [
- /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/,
- /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/,
- /from <internal:prelude>:\d+:in (`|'Binding#)irb'/,
- /from .*\/irbtest-.*.rb:9:in [`']<main>'/
- ]
- end
-
- expected_traces.reverse! if RUBY_VERSION < "3.0.0"
-
- expected_traces.each_with_index do |expected_trace, index|
- assert_match(expected_trace, frame_traces[index])
- end
- end
-
- def test_backtrace_filtering_with_backtrace_filter
- write_rc <<~'RUBY'
- class TestBacktraceFilter
- def self.call(backtrace)
- backtrace.reject { |line| line.include?("internal") }
- end
- end
-
- IRB.conf[:BACKTRACE_FILTER] = TestBacktraceFilter
- RUBY
-
- write_ruby <<~'RUBY'
- def foo
- raise "error"
- end
-
- def bar
- foo
- end
-
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "bar"
- type "exit"
- end
-
- assert_match(/irbtest-.*\.rb:2:in (`|'Object#)foo': error \(RuntimeError\)/, output)
- frame_traces = output.split("\n").select { |line| line.strip.match?(/from /) }.map(&:strip)
-
- expected_traces = [
- /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/,
- /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/,
- /from .*\/irbtest-.*.rb:9:in [`']<main>'/
- ]
-
- expected_traces.reverse! if RUBY_VERSION < "3.0.0"
-
- expected_traces.each_with_index do |expected_trace, index|
- assert_match(expected_trace, frame_traces[index])
- end
- end
- end
-end
diff --git a/test/irb/test_locale.rb b/test/irb/test_locale.rb
deleted file mode 100644
index 930a38834c..0000000000
--- a/test/irb/test_locale.rb
+++ /dev/null
@@ -1,118 +0,0 @@
-require "irb"
-require "stringio"
-
-require_relative "helper"
-
-module TestIRB
- class LocaleTestCase < TestCase
- def test_initialize_with_en
- locale = IRB::Locale.new("en_US.UTF-8")
-
- assert_equal("en", locale.lang)
- assert_equal("US", locale.territory)
- assert_equal("UTF-8", locale.encoding.name)
- assert_equal(nil, locale.modifier)
- end
-
- def test_initialize_with_ja
- locale = IRB::Locale.new("ja_JP.UTF-8")
-
- assert_equal("ja", locale.lang)
- assert_equal("JP", locale.territory)
- assert_equal("UTF-8", locale.encoding.name)
- assert_equal(nil, locale.modifier)
- end
-
- def test_initialize_with_legacy_ja_encoding_ujis
- original_stderr = $stderr
- $stderr = StringIO.new
-
- locale = IRB::Locale.new("ja_JP.ujis")
-
- assert_equal("ja", locale.lang)
- assert_equal("JP", locale.territory)
- assert_equal(Encoding::EUC_JP, locale.encoding)
- assert_equal(nil, locale.modifier)
-
- assert_include $stderr.string, "ja_JP.ujis is obsolete. use ja_JP.EUC-JP"
- ensure
- $stderr = original_stderr
- end
-
- def test_initialize_with_legacy_ja_encoding_euc
- original_stderr = $stderr
- $stderr = StringIO.new
-
- locale = IRB::Locale.new("ja_JP.euc")
-
- assert_equal("ja", locale.lang)
- assert_equal("JP", locale.territory)
- assert_equal(Encoding::EUC_JP, locale.encoding)
- assert_equal(nil, locale.modifier)
-
- assert_include $stderr.string, "ja_JP.euc is obsolete. use ja_JP.EUC-JP"
- ensure
- $stderr = original_stderr
- end
-
- %w(IRB_LANG LC_MESSAGES LC_ALL LANG).each do |env_var|
- define_method "test_initialize_with_#{env_var.downcase}" do
- original_values = {
- "IRB_LANG" => ENV["IRB_LANG"],
- "LC_MESSAGES" => ENV["LC_MESSAGES"],
- "LC_ALL" => ENV["LC_ALL"],
- "LANG" => ENV["LANG"],
- }
-
- ENV["IRB_LANG"] = ENV["LC_MESSAGES"] = ENV["LC_ALL"] = ENV["LANG"] = nil
- ENV[env_var] = "zh_TW.UTF-8"
-
- locale = IRB::Locale.new
-
- assert_equal("zh", locale.lang)
- assert_equal("TW", locale.territory)
- assert_equal("UTF-8", locale.encoding.name)
- assert_equal(nil, locale.modifier)
- ensure
- original_values.each do |key, value|
- ENV[key] = value
- end
- end
- end
-
- def test_load
- # reset Locale's internal cache
- IRB::Locale.class_variable_set(:@@loaded, [])
- # Because error.rb files define the same class, loading them causes method redefinition warnings.
- original_verbose = $VERBOSE
- $VERBOSE = nil
-
- jp_local = IRB::Locale.new("ja_JP.UTF-8")
- jp_local.load("irb/error.rb")
- msg = IRB::CantReturnToNormalMode.new.message
- assert_equal("Normalモードに戻れません.", msg)
-
- # reset Locale's internal cache
- IRB::Locale.class_variable_set(:@@loaded, [])
-
- en_local = IRB::Locale.new("en_US.UTF-8")
- en_local.load("irb/error.rb")
- msg = IRB::CantReturnToNormalMode.new.message
- assert_equal("Can't return to normal mode.", msg)
- ensure
- # before turning warnings back on, load the error.rb file again to avoid warnings in other tests
- IRB::Locale.new.load("irb/error.rb")
- $VERBOSE = original_verbose
- end
-
- def test_find
- jp_local = IRB::Locale.new("ja_JP.UTF-8")
- path = jp_local.find("irb/error.rb")
- assert_include(path, "/lib/irb/lc/ja/error.rb")
-
- en_local = IRB::Locale.new("en_US.UTF-8")
- path = en_local.find("irb/error.rb")
- assert_include(path, "/lib/irb/lc/error.rb")
- end
- end
-end
diff --git a/test/irb/test_nesting_parser.rb b/test/irb/test_nesting_parser.rb
deleted file mode 100644
index 6b4f54ee21..0000000000
--- a/test/irb/test_nesting_parser.rb
+++ /dev/null
@@ -1,339 +0,0 @@
-# frozen_string_literal: false
-require 'irb'
-
-require_relative "helper"
-
-module TestIRB
- class NestingParserTest < TestCase
- def setup
- save_encodings
- end
-
- def teardown
- restore_encodings
- end
-
- def parse_by_line(code)
- IRB::NestingParser.parse_by_line(IRB::RubyLex.ripper_lex_without_warning(code))
- end
-
- def test_open_tokens
- code = <<~'EOS'
- class A
- def f
- if true
- tap do
- {
- x: "
- #{p(1, 2, 3
- EOS
- opens = IRB::NestingParser.open_tokens(IRB::RubyLex.ripper_lex_without_warning(code))
- assert_equal(%w[class def if do { " #{ (], opens.map(&:tok))
- end
-
- def test_parse_by_line
- code = <<~EOS
- (((((1+2
- ).to_s())).tap do (((
- EOS
- _tokens, prev_opens, next_opens, min_depth = parse_by_line(code).last
- assert_equal(%w[( ( ( ( (], prev_opens.map(&:tok))
- assert_equal(%w[( ( do ( ( (], next_opens.map(&:tok))
- assert_equal(2, min_depth)
- end
-
- def test_ruby_syntax
- code = <<~'EOS'
- class A
- 1 if 2
- 1 while 2
- 1 until 2
- 1 unless 2
- 1 rescue 2
- begin; rescue; ensure; end
- tap do; rescue; ensure; end
- class B; end
- module C; end
- def f; end
- def `; end
- def f() = 1
- %(); %w[]; %q(); %r{}; %i[]
- "#{1}"; ''; /#{1}/; `#{1}`
- p(``); p ``; p x: ``; p 1, ``;
- :sym; :"sym"; :+; :`; :if
- [1, 2, 3]
- { x: 1, y: 2 }
- (a, (*b, c), d), e = 1, 2, 3
- ->(a){}; ->(a) do end
- -> a = -> b = :do do end do end
- if 1; elsif 2; else; end
- unless 1; end
- while 1; end
- until 1; end
- for i in j; end
- case 1; when 2; end
- puts(1, 2, 3)
- loop{|i|}
- loop do |i| end
- end
- EOS
- line_results = parse_by_line(code)
- assert_equal(code.lines.size, line_results.size)
- class_open, *inner_line_results, class_close = line_results
- assert_equal(['class'], class_open[2].map(&:tok))
- inner_line_results.each {|result| assert_equal(['class'], result[2].map(&:tok)) }
- assert_equal([], class_close[2].map(&:tok))
- end
-
- def test_multiline_string
- code = <<~EOS
- "
- aaa
- bbb
- "
- <<A
- aaa
- bbb
- A
- EOS
- line_results = parse_by_line(code)
- assert_equal(code.lines.size, line_results.size)
- string_content_line, string_opens = line_results[1]
- assert_equal("\naaa\nbbb\n", string_content_line.first.first.tok)
- assert_equal("aaa\n", string_content_line.first.last)
- assert_equal(['"'], string_opens.map(&:tok))
- heredoc_content_line, heredoc_opens = line_results[6]
- assert_equal("aaa\nbbb\n", heredoc_content_line.first.first.tok)
- assert_equal("bbb\n", heredoc_content_line.first.last)
- assert_equal(['<<A'], heredoc_opens.map(&:tok))
- _line, _prev_opens, next_opens, _min_depth = line_results.last
- assert_equal([], next_opens)
- end
-
- def test_backslash_continued_nested_symbol
- code = <<~'EOS'
- x = <<A, :\
- heredoc #{
- here
- }
- A
- =begin
- embdoc
- =end
- # comment
-
- if # this is symbol :if
- while
- EOS
- line_results = parse_by_line(code)
- assert_equal(%w[: <<A #{], line_results[2][2].map(&:tok))
- assert_equal(%w[while], line_results.last[2].map(&:tok))
- end
-
- def test_oneliner_def
- code = <<~EOC
- if true
- # normal oneliner def
- def f = 1
- def f() = 1
- def f(*) = 1
- # keyword, backtick, op
- def * = 1
- def ` = 1
- def if = 1
- def *() = 1
- def `() = 1
- def if() = 1
- # oneliner def with receiver
- def a.* = 1
- def $a.* = 1
- def @a.` = 1
- def A.` = 1
- def ((a;b;c)).*() = 1
- def ((a;b;c)).if() = 1
- def ((a;b;c)).end() = 1
- # multiline oneliner def
- def f =
- 1
- def f()
- =
- 1
- # oneliner def with comment and embdoc
- def # comment
- =begin
- embdoc
- =end
- ((a;b;c))
- . # comment
- =begin
- embdoc
- =end
- f (*) # comment
- =begin
- embdoc
- =end
- =
- 1
- # nested oneliner def
- def f(x = def f() = 1) = def f() = 1
- EOC
- _tokens, _prev_opens, next_opens, min_depth = parse_by_line(code).last
- assert_equal(['if'], next_opens.map(&:tok))
- assert_equal(1, min_depth)
- end
-
- def test_heredoc_embexpr
- code = <<~'EOS'
- <<A+<<B+<<C+(<<D+(<<E)
- #{
- <<~F+"#{<<~G}
- #{
- here
- }
- F
- G
- "
- }
- A
- B
- C
- D
- E
- )
- EOS
- line_results = parse_by_line(code)
- last_opens = line_results.last[-2]
- assert_equal([], last_opens)
- _tokens, _prev_opens, next_opens, _min_depth = line_results[4]
- assert_equal(%w[( <<E <<D <<C <<B <<A #{ " <<~G <<~F #{], next_opens.map(&:tok))
- end
-
- def test_for_in
- code = <<~EOS
- for i in j
- here
- end
- for i in j do
- here
- end
- for i in
- j do
- here
- end
- for
- # comment
- i in j do
- here
- end
- for (a;b;c).d in (a;b;c) do
- here
- end
- for i in :in + :do do
- here
- end
- for i in -> do end do
- here
- end
- EOS
- line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') }
- assert_equal(7, line_results.size)
- line_results.each do |_tokens, _prev_opens, next_opens, _min_depth|
- assert_equal(['for'], next_opens.map(&:tok))
- end
- end
-
- def test_while_until
- base_code = <<~'EOS'
- while_or_until true
- here
- end
- while_or_until a < c
- here
- end
- while_or_until true do
- here
- end
- while_or_until
- # comment
- (a + b) <
- # comment
- c do
- here
- end
- while_or_until :\
- do do
- here
- end
- while_or_until def do; end == :do do
- here
- end
- while_or_until -> do end do
- here
- end
- EOS
- %w[while until].each do |keyword|
- code = base_code.gsub('while_or_until', keyword)
- line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') }
- assert_equal(7, line_results.size)
- line_results.each do |_tokens, _prev_opens, next_opens, _min_depth|
- assert_equal([keyword], next_opens.map(&:tok) )
- end
- end
- end
-
- def test_undef_alias
- codes = [
- 'undef foo',
- 'alias foo bar',
- 'undef !',
- 'alias + -',
- 'alias $a $b',
- 'undef do',
- 'alias do do',
- 'undef :do',
- 'alias :do :do',
- 'undef :"#{alias do do}"',
- 'alias :"#{undef do}" do',
- 'alias do :"#{undef do}"'
- ]
- code_with_comment = <<~EOS
- undef #
- #
- do #
- alias #
- #
- do #
- #
- do #
- EOS
- code_with_heredoc = <<~EOS
- <<~A; alias
- A
- :"#{<<~A}"
- A
- do
- EOS
- [*codes, code_with_comment, code_with_heredoc].each do |code|
- opens = IRB::NestingParser.open_tokens(IRB::RubyLex.ripper_lex_without_warning('(' + code + "\nif"))
- assert_equal(%w[( if], opens.map(&:tok))
- end
- end
-
- def test_case_in
- code = <<~EOS
- case 1
- in 1
- here
- in
- 2
- here
- end
- EOS
- line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') }
- assert_equal(2, line_results.size)
- line_results.each do |_tokens, _prev_opens, next_opens, _min_depth|
- assert_equal(['in'], next_opens.map(&:tok))
- end
- end
- end
-end
diff --git a/test/irb/test_option.rb b/test/irb/test_option.rb
deleted file mode 100644
index fec31f384f..0000000000
--- a/test/irb/test_option.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: false
-require_relative "helper"
-
-module TestIRB
- class OptionTest < TestCase
- def test_end_of_option
- bug4117 = '[ruby-core:33574]'
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- status = assert_in_out_err(bundle_exec + %w[-W0 -rirb -e IRB.start(__FILE__) -- -f --], "", //, [], bug4117)
- assert(status.success?, bug4117)
- end
- end
-end
diff --git a/test/irb/test_pager.rb b/test/irb/test_pager.rb
deleted file mode 100644
index 0fad94da30..0000000000
--- a/test/irb/test_pager.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: false
-require 'irb/pager'
-
-require_relative 'helper'
-
-module TestIRB
- class PagerTest < TestCase
- def test_take_first_page
- assert_equal ['a' * 40, true], IRB::Pager.take_first_page(10, 4) {|io| io.puts 'a' * 41; raise 'should not reach here' }
- assert_equal ["a\nb\na\nb\n", true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.puts "a\nb\n" } }
- assert_equal ["a\n\n\na\n", true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.puts "a\n\n\n" } }
- assert_equal ["11\n" * 4, true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.write 1; io.puts 1 } }
- assert_equal ["\n" * 4, true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.write nil; io.puts nil } }
- assert_equal ['a' * 39, false], IRB::Pager.take_first_page(10, 4) {|io| io.write 'a' * 39 }
- assert_equal ['a' * 39 + 'b', false], IRB::Pager.take_first_page(10, 4) {|io| io.write 'a' * 39 + 'b' }
- assert_equal ['a' * 39 + 'b', true], IRB::Pager.take_first_page(10, 4) {|io| io.write 'a' * 39 + 'bc' }
- assert_equal ["a\nb\nc\nd\n", false], IRB::Pager.take_first_page(10, 4) {|io| io.write "a\nb\nc\nd\n" }
- assert_equal ["a\nb\nc\nd\n", true], IRB::Pager.take_first_page(10, 4) {|io| io.write "a\nb\nc\nd\ne" }
- assert_equal ['a' * 15 + "\n" + 'b' * 20, true], IRB::Pager.take_first_page(10, 4) {|io| io.puts 'a' * 15; io.puts 'b' * 30 }
- assert_equal ["\e[31mA\e[0m" * 10 + 'x' * 30, true], IRB::Pager.take_first_page(10, 4) {|io| io.puts "\e[31mA\e[0m" * 10 + 'x' * 31 }
- text, overflow = IRB::Pager.take_first_page(10, 4) {|io| 41.times { io.write "\e[31mA\e[0m" } }
- assert_equal ['A' * 40, true], [text.gsub(/\e\[\d+m/, ''), overflow]
- text, overflow = IRB::Pager.take_first_page(10, 4) {|io| 41.times { io.write "\e[31mAAA\e[0m" } }
- assert_equal ['A' * 40, true], [text.gsub(/\e\[\d+m/, ''), overflow]
- end
- end
-
- class PageOverflowIOTest < TestCase
- def test_overflow
- actual_events = []
- overflow_callback = ->(lines) do
- actual_events << [:callback_called, lines]
- end
- out = IRB::Pager::PageOverflowIO.new(10, 4, overflow_callback)
- out.puts 'a' * 15
- out.write 'b' * 15
-
- actual_events << :before_write
- out.write 'c' * 1000
- actual_events << :after_write
-
- out.puts 'd' * 1000
- out.write 'e' * 1000
-
- expected_events = [
- :before_write,
- [:callback_called, ['a' * 10, 'a' * 5 + "\n", 'b' * 10, 'b' * 5 + 'c' * 5]],
- :after_write,
- ]
- assert_equal expected_events, actual_events
-
- expected_whole_content = 'a' * 15 + "\n" + 'b' * 15 + 'c' * 1000 + 'd' * 1000 + "\n" + 'e' * 1000
- assert_equal expected_whole_content, out.string
- end
-
- def test_callback_delay
- actual_events = []
- overflow_callback = ->(lines) do
- actual_events << [:callback_called, lines]
- end
- out = IRB::Pager::PageOverflowIO.new(10, 4, overflow_callback, delay: 0.2)
- out.write 'a' * 1000
- assert_equal ['a' * 10] * 4, out.first_page_lines
- out.write 'b'
- actual_events << :before_delay
- sleep 0.2
- out.write 'c'
- actual_events << :after_delay
- out.write 'd'
- assert_equal 'a' * 1000 + 'bcd', out.string
- assert_equal [:before_delay, [:callback_called, ['a' * 10] * 4], :after_delay], actual_events
- end
- end
-end
diff --git a/test/irb/test_raise_exception.rb b/test/irb/test_raise_exception.rb
deleted file mode 100644
index 44a5ae87e1..0000000000
--- a/test/irb/test_raise_exception.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: false
-require "tmpdir"
-
-require_relative "helper"
-
-module TestIRB
- class RaiseExceptionTest < TestCase
- def test_raise_exception_with_nil_backtrace
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, /#<Exception: foo>/, [])
- raise Exception.new("foo").tap {|e| def e.backtrace; nil; end }
-IRB
- end
-
- def test_raise_exception_with_message_exception
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- expected = /#<Exception: foo>\nbacktraces are hidden because bar was raised when processing them/
- assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, expected, [])
- e = Exception.new("foo")
- def e.message; raise 'bar'; end
- raise e
-IRB
- end
-
- def test_raise_exception_with_message_inspect_exception
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- expected = /Uninspectable exception occurred/
- assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, expected, [])
- e = Exception.new("foo")
- def e.message; raise; end
- def e.inspect; raise; end
- raise e
-IRB
- end
-
- def test_raise_exception_with_invalid_byte_sequence
- pend if RUBY_ENGINE == 'truffleruby' || /mswin|mingw/ =~ RUBY_PLATFORM
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<~IRB, /A\\xF3B \(StandardError\)/, [])
- raise StandardError, "A\\xf3B"
- IRB
- end
-
- def test_raise_exception_with_different_encoding_containing_invalid_byte_sequence
- backup_home = ENV["HOME"]
- Dir.mktmpdir("test_irb_raise_no_backtrace_exception_#{$$}") do |tmpdir|
- ENV["HOME"] = tmpdir
-
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- File.open("#{tmpdir}/euc.rb", 'w') do |f|
- f.write(<<~EOF)
- # encoding: euc-jp
-
- def raise_euc_with_invalid_byte_sequence
- raise "\xA4\xA2\\xFF"
- end
- EOF
- end
- env = {}
- %w(LC_MESSAGES LC_ALL LC_CTYPE LANG).each {|n| env[n] = "ja_JP.UTF-8" }
- # TruffleRuby warns when the locale does not exist
- env['TRUFFLERUBYOPT'] = "#{ENV['TRUFFLERUBYOPT']} --log.level=SEVERE" if RUBY_ENGINE == 'truffleruby'
- args = [env] + bundle_exec + %W[-rirb -C #{tmpdir} -W0 -e IRB.start(__FILE__) -- -f --]
- error = /raise_euc_with_invalid_byte_sequence': あ\\xFF \(RuntimeError\)/
- assert_in_out_err(args, <<~IRB, error, [], encoding: "UTF-8")
- require_relative 'euc'
- raise_euc_with_invalid_byte_sequence
- IRB
- end
- ensure
- ENV["HOME"] = backup_home
- end
- end
-end
diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb
deleted file mode 100644
index 4e406a8ce0..0000000000
--- a/test/irb/test_ruby_lex.rb
+++ /dev/null
@@ -1,242 +0,0 @@
-# frozen_string_literal: true
-require "irb"
-
-require_relative "helper"
-
-module TestIRB
- class RubyLexTest < TestCase
- def setup
- save_encodings
- end
-
- def teardown
- restore_encodings
- end
-
- def test_interpolate_token_with_heredoc_and_unclosed_embexpr
- code = <<~'EOC'
- ①+<<A-②
- #{③*<<B/④
- #{⑤&<<C|⑥
- EOC
- ripper_tokens = Ripper.tokenize(code)
- rubylex_tokens = IRB::RubyLex.ripper_lex_without_warning(code)
- # Assert no missing part
- assert_equal(code, rubylex_tokens.map(&:tok).join)
- # Assert ripper tokens are not removed
- ripper_tokens.each do |tok|
- assert(rubylex_tokens.any? { |t| t.tok == tok && t.tok != :on_ignored_by_ripper })
- end
- # Assert interpolated token position
- rubylex_tokens.each do |t|
- row, col = t.pos
- assert_equal t.tok, code.lines[row - 1].byteslice(col, t.tok.bytesize)
- end
- end
-
- def test_local_variables_dependent_code
- lines = ["a /1#/ do", "2"]
- assert_indent_level(lines, 1)
- assert_code_block_open(lines, true)
- assert_indent_level(lines, 0, local_variables: ['a'])
- assert_code_block_open(lines, false, local_variables: ['a'])
- end
-
- def test_literal_ends_with_space
- assert_code_block_open(['% a'], true)
- assert_code_block_open(['% a '], false)
- end
-
- def test_literal_ends_with_newline
- assert_code_block_open(['%'], true)
- assert_code_block_open(['%', ''], false)
- end
-
- def test_should_continue
- assert_should_continue(['a'], false)
- assert_should_continue(['/a/'], false)
- assert_should_continue(['a;'], false)
- assert_should_continue(['<<A', 'A'], false)
- assert_should_continue(['a...'], false)
- assert_should_continue(['a\\'], true)
- assert_should_continue(['a.'], true)
- assert_should_continue(['a+'], true)
- assert_should_continue(['a; #comment', '', '=begin', 'embdoc', '=end', ''], false)
- assert_should_continue(['a+ #comment', '', '=begin', 'embdoc', '=end', ''], true)
- end
-
- def test_code_block_open_with_should_continue
- # syntax ok
- assert_code_block_open(['a'], false) # continue: false
- assert_code_block_open(['a\\'], true) # continue: true
-
- # recoverable syntax error code is not terminated
- assert_code_block_open(['a+'], true)
-
- # unrecoverable syntax error code is terminated
- assert_code_block_open(['.; a+'], false)
-
- # other syntax error that failed to determine if it is recoverable or not
- assert_code_block_open(['@; a'], false)
- assert_code_block_open(['@; a+'], true)
- assert_code_block_open(['@; (a'], true)
- end
-
- def test_broken_percent_literal
- tokens = IRB::RubyLex.ripper_lex_without_warning('%wwww')
- pos_to_index = {}
- tokens.each_with_index { |t, i|
- assert_nil(pos_to_index[t.pos], "There is already another token in the position of #{t.inspect}.")
- pos_to_index[t.pos] = i
- }
- end
-
- def test_broken_percent_literal_in_method
- tokens = IRB::RubyLex.ripper_lex_without_warning(<<~EOC.chomp)
- def foo
- %wwww
- end
- EOC
- pos_to_index = {}
- tokens.each_with_index { |t, i|
- assert_nil(pos_to_index[t.pos], "There is already another token in the position of #{t.inspect}.")
- pos_to_index[t.pos] = i
- }
- end
-
- def test_unterminated_code
- ['do', '<<A'].each do |code|
- tokens = IRB::RubyLex.ripper_lex_without_warning(code)
- assert_equal(code, tokens.map(&:tok).join, "Cannot reconstruct code from tokens")
- error_tokens = tokens.map(&:event).grep(/error/)
- assert_empty(error_tokens, 'Error tokens must be ignored if there is corresponding non-error token')
- end
- end
-
- def test_unterminated_heredoc_string_literal
- ['<<A;<<B', "<<A;<<B\n", "%W[\#{<<A;<<B", "%W[\#{<<A;<<B\n"].each do |code|
- tokens = IRB::RubyLex.ripper_lex_without_warning(code)
- string_literal = IRB::NestingParser.open_tokens(tokens).last
- assert_equal('<<A', string_literal&.tok)
- end
- end
-
- def test_indent_level_with_heredoc_and_embdoc
- reference_code = <<~EOC.chomp
- if true
- hello
- p(
- )
- EOC
- code_with_heredoc = <<~EOC.chomp
- if true
- <<~A
- A
- p(
- )
- EOC
- code_with_embdoc = <<~EOC.chomp
- if true
- =begin
- =end
- p(
- )
- EOC
- expected = 1
- assert_indent_level(reference_code.lines, expected)
- assert_indent_level(code_with_heredoc.lines, expected)
- assert_indent_level(code_with_embdoc.lines, expected)
- end
-
- def test_assignment_expression
- ruby_lex = IRB::RubyLex.new
-
- [
- "foo = bar",
- "@foo = bar",
- "$foo = bar",
- "@@foo = bar",
- "::Foo = bar",
- "a::Foo = bar",
- "Foo = bar",
- "foo.bar = 1",
- "foo[1] = bar",
- "foo += bar",
- "foo -= bar",
- "foo ||= bar",
- "foo &&= bar",
- "foo, bar = 1, 2",
- "foo.bar=(1)",
- "foo; foo = bar",
- "foo; foo = bar; ;\n ;",
- "foo\nfoo = bar",
- ].each do |exp|
- assert(
- ruby_lex.assignment_expression?(exp, local_variables: []),
- "#{exp.inspect}: should be an assignment expression"
- )
- end
-
- [
- "foo",
- "foo.bar",
- "foo[0]",
- "foo = bar; foo",
- "foo = bar\nfoo",
- ].each do |exp|
- refute(
- ruby_lex.assignment_expression?(exp, local_variables: []),
- "#{exp.inspect}: should not be an assignment expression"
- )
- end
- end
-
- def test_assignment_expression_with_local_variable
- ruby_lex = IRB::RubyLex.new
- code = "a /1;x=1#/"
- refute(ruby_lex.assignment_expression?(code, local_variables: []), "#{code}: should not be an assignment expression")
- assert(ruby_lex.assignment_expression?(code, local_variables: [:a]), "#{code}: should be an assignment expression")
- refute(ruby_lex.assignment_expression?("", local_variables: [:a]), "empty code should not be an assignment expression")
- end
-
- def test_initialising_the_old_top_level_ruby_lex
- assert_in_out_err(["--disable-gems", "-W:deprecated"], <<~RUBY, [], /warning: constant ::RubyLex is deprecated/)
- require "irb"
- ::RubyLex.new(nil)
- RUBY
- end
-
- private
-
- def assert_indent_level(lines, expected, local_variables: [])
- indent_level, _continue, _code_block_open = check_state(lines, local_variables: local_variables)
- error_message = "Calculated the wrong number of indent level for:\n #{lines.join("\n")}"
- assert_equal(expected, indent_level, error_message)
- end
-
- def assert_should_continue(lines, expected, local_variables: [])
- _indent_level, continue, _code_block_open = check_state(lines, local_variables: local_variables)
- error_message = "Wrong result of should_continue for:\n #{lines.join("\n")}"
- assert_equal(expected, continue, error_message)
- end
-
- def assert_code_block_open(lines, expected, local_variables: [])
- if RUBY_ENGINE == 'truffleruby'
- omit "Remove me after https://github.com/ruby/prism/issues/2129 is addressed and adopted in TruffleRuby"
- end
-
- _indent_level, _continue, code_block_open = check_state(lines, local_variables: local_variables)
- error_message = "Wrong result of code_block_open for:\n #{lines.join("\n")}"
- assert_equal(expected, code_block_open, error_message)
- end
-
- def check_state(lines, local_variables: [])
- code = lines.map { |l| "#{l}\n" }.join # code should end with "\n"
- ruby_lex = IRB::RubyLex.new
- tokens, opens, terminated = ruby_lex.check_code_state(code, local_variables: local_variables)
- indent_level = ruby_lex.calc_indent_level(opens)
- continue = ruby_lex.should_continue?(tokens)
- [indent_level, continue, !terminated]
- end
- end
-end
diff --git a/test/irb/test_tracer.rb b/test/irb/test_tracer.rb
deleted file mode 100644
index 540f8be131..0000000000
--- a/test/irb/test_tracer.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-# frozen_string_literal: false
-require 'tempfile'
-require 'irb'
-
-require_relative "helper"
-
-module TestIRB
- class ContextWithTracerIntegrationTest < IntegrationTestCase
- def setup
- super
-
- omit "Tracer gem is not available when running on TruffleRuby" if RUBY_ENGINE == "truffleruby"
-
- @envs.merge!("NO_COLOR" => "true")
- end
-
- def example_ruby_file
- <<~'RUBY'
- class Foo
- def self.foo
- 100
- end
- end
-
- def bar(obj)
- obj.foo
- end
-
- binding.irb
- RUBY
- end
-
- def test_use_tracer_enabled_when_gem_is_unavailable
- write_rc <<~RUBY
- # Simulate the absence of the tracer gem
- ::Kernel.send(:alias_method, :irb_original_require, :require)
-
- ::Kernel.define_method(:require) do |name|
- raise LoadError, "cannot load such file -- tracer (test)" if name.match?("tracer")
- ::Kernel.send(:irb_original_require, name)
- end
-
- IRB.conf[:USE_TRACER] = true
- RUBY
-
- write_ruby example_ruby_file
-
- output = run_ruby_file do
- type "bar(Foo)"
- type "exit"
- end
-
- assert_include(output, "Tracer extension of IRB is enabled but tracer gem wasn't found.")
- end
-
- def test_use_tracer_enabled_when_gem_is_available
- write_rc <<~RUBY
- IRB.conf[:USE_TRACER] = true
- RUBY
-
- write_ruby example_ruby_file
-
- output = run_ruby_file do
- type "bar(Foo)"
- type "exit"
- end
-
- assert_include(output, "Object#bar at")
- assert_include(output, "Foo.foo at")
- assert_include(output, "Foo.foo #=> 100")
- assert_include(output, "Object#bar #=> 100")
-
- # Test that the tracer output does not include IRB's own files
- assert_not_include(output, "irb/workspace.rb")
- end
-
- def test_use_tracer_is_disabled_by_default
- write_ruby example_ruby_file
-
- output = run_ruby_file do
- type "bar(Foo)"
- type "exit"
- end
-
- assert_not_include(output, "#depth:")
- assert_not_include(output, "Foo.foo")
- end
-
- end
-end
diff --git a/test/irb/test_type_completor.rb b/test/irb/test_type_completor.rb
deleted file mode 100644
index 3d0e25d19e..0000000000
--- a/test/irb/test_type_completor.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-# frozen_string_literal: true
-
-# Run test only when Ruby >= 3.0 and repl_type_completor is available
-return unless RUBY_VERSION >= '3.0.0'
-return if RUBY_ENGINE == 'truffleruby' # needs endless method definition
-begin
- require 'repl_type_completor'
-rescue LoadError
- return
-end
-
-require 'irb'
-require 'tempfile'
-require_relative './helper'
-
-module TestIRB
- class TypeCompletorTest < TestCase
- DummyContext = Struct.new(:irb_path)
-
- def setup
- ReplTypeCompletor.load_rbs unless ReplTypeCompletor.rbs_loaded?
- context = DummyContext.new('(irb)')
- @completor = IRB::TypeCompletor.new(context)
- end
-
- def empty_binding
- binding
- end
-
- def test_build_completor
- IRB.init_config(nil)
- verbose, $VERBOSE = $VERBOSE, nil
- original_completor = IRB.conf[:COMPLETOR]
- workspace = IRB::WorkSpace.new(Object.new)
- @context = IRB::Context.new(nil, workspace, TestInputMethod.new)
- IRB.conf[:COMPLETOR] = nil
- expected_default_completor = RUBY_VERSION >= '3.4' ? 'IRB::TypeCompletor' : 'IRB::RegexpCompletor'
- assert_equal expected_default_completor, @context.send(:build_completor).class.name
- IRB.conf[:COMPLETOR] = :type
- assert_equal 'IRB::TypeCompletor', @context.send(:build_completor).class.name
- ensure
- $VERBOSE = verbose
- IRB.conf[:COMPLETOR] = original_completor
- end
-
- def assert_completion(preposing, target, binding: empty_binding, include: nil, exclude: nil)
- raise ArgumentError if include.nil? && exclude.nil?
- candidates = @completor.completion_candidates(preposing, target, '', bind: binding)
- assert ([*include] - candidates).empty?, "Expected #{candidates} to include #{include}" if include
- assert (candidates & [*exclude]).empty?, "Expected #{candidates} not to include #{exclude}" if exclude
- end
-
- def assert_doc_namespace(preposing, target, namespace, binding: empty_binding)
- @completor.completion_candidates(preposing, target, '', bind: binding)
- assert_equal namespace, @completor.doc_namespace(preposing, target, '', bind: binding)
- end
-
- def test_type_completion
- bind = eval('num = 1; binding')
- assert_completion('num.times.map(&:', 'ab', binding: bind, include: 'abs')
- assert_doc_namespace('num.chr.', 'upcase', 'String#upcase', binding: bind)
- end
-
- def test_inspect
- assert_match(/\AReplTypeCompletor.*\z/, @completor.inspect)
- end
-
- def test_empty_completion
- candidates = @completor.completion_candidates('(', ')', '', bind: binding)
- assert_equal [], candidates
- assert_doc_namespace('(', ')', nil)
- end
-
- def test_command_completion
- binding.eval("some_var = 1")
- # completion for help command's argument should only include command names
- assert_include(@completor.completion_candidates('help ', 's', '', bind: binding), 'show_source')
- assert_not_include(@completor.completion_candidates('help ', 's', '', bind: binding), 'some_var')
-
- assert_include(@completor.completion_candidates('', 'show_s', '', bind: binding), 'show_source')
- assert_not_include(@completor.completion_candidates(';', 'show_s', '', bind: binding), 'show_source')
- end
- end
-
- class TypeCompletorIntegrationTest < IntegrationTestCase
- def test_type_completor
- write_rc <<~RUBY
- IRB.conf[:COMPLETOR] = :type
- RUBY
-
- write_ruby <<~'RUBY'
- binding.irb
- RUBY
-
- output = run_ruby_file do
- type "irb_info"
- type "sleep 0.01 until ReplTypeCompletor.rbs_loaded?"
- type "completor = IRB.CurrentContext.io.instance_variable_get(:@completor);"
- type "n = 10"
- type "puts completor.completion_candidates 'a = n.abs;', 'a.b', '', bind: binding"
- type "puts completor.doc_namespace 'a = n.chr;', 'a.encoding', '', bind: binding"
- type "exit!"
- end
- assert_match(/Completion: Autocomplete, ReplTypeCompletor/, output)
- assert_match(/a\.bit_length/, output)
- assert_match(/String#encoding/, output)
- end
- end
-end
diff --git a/test/irb/test_workspace.rb b/test/irb/test_workspace.rb
deleted file mode 100644
index ad515f91df..0000000000
--- a/test/irb/test_workspace.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-# frozen_string_literal: false
-require 'tempfile'
-require 'irb'
-require 'irb/workspace'
-require 'irb/color'
-
-require_relative "helper"
-
-module TestIRB
- class WorkSpaceTest < TestCase
- def test_code_around_binding
- IRB.conf[:USE_COLORIZE] = false
- Tempfile.create('irb') do |f|
- code = <<~RUBY
- # 1
- # 2
- IRB::WorkSpace.new(binding) # 3
- # 4
- # 5
- RUBY
- f.print(code)
- f.close
-
- workspace = eval(code, binding, f.path)
- assert_equal(<<~EOS, without_term { workspace.code_around_binding })
-
- From: #{f.path} @ line 3 :
-
- 1: # 1
- 2: # 2
- => 3: IRB::WorkSpace.new(binding) # 3
- 4: # 4
- 5: # 5
-
- EOS
- end
- ensure
- IRB.conf.delete(:USE_COLORIZE)
- end
-
- def test_code_around_binding_with_existing_unreadable_file
- pend 'chmod cannot make file unreadable on windows' if windows?
- pend 'skipped in root privilege' if Process.uid == 0
-
- Tempfile.create('irb') do |f|
- code = "IRB::WorkSpace.new(binding)\n"
- f.print(code)
- f.close
-
- File.chmod(0, f.path)
-
- workspace = eval(code, binding, f.path)
- assert_equal(nil, workspace.code_around_binding)
- end
- end
-
- def test_code_around_binding_with_script_lines__
- IRB.conf[:USE_COLORIZE] = false
- with_script_lines do |script_lines|
- Tempfile.create('irb') do |f|
- code = "IRB::WorkSpace.new(binding)\n"
- script_lines[f.path] = code.split(/^/)
-
- workspace = eval(code, binding, f.path)
- assert_equal(<<~EOS, without_term { workspace.code_around_binding })
-
- From: #{f.path} @ line 1 :
-
- => 1: IRB::WorkSpace.new(binding)
-
- EOS
- end
- end
- ensure
- IRB.conf.delete(:USE_COLORIZE)
- end
-
- def test_code_around_binding_on_irb
- workspace = eval("IRB::WorkSpace.new(binding)", binding, "(irb)")
- assert_equal(nil, workspace.code_around_binding)
- end
-
- def test_toplevel_binding_local_variables
- bug17623 = '[ruby-core:102468]'
- bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
- top_srcdir = "#{__dir__}/../.."
- irb_path = nil
- %w[exe libexec].find do |dir|
- irb_path = "#{top_srcdir}/#{dir}/irb"
- File.exist?(irb_path)
- end or omit 'irb command not found'
- assert_in_out_err(bundle_exec + ['-W0', "-C#{top_srcdir}", '-e', <<~RUBY, '--', '-f', '--'], 'binding.local_variables', /\[:_\]/, [], bug17623)
- version = 'xyz' # typical rubygems loading file
- load('#{irb_path}')
- RUBY
- end
-
- private
-
- def with_script_lines
- script_lines = nil
- debug_lines = {}
- Object.class_eval do
- if defined?(SCRIPT_LINES__)
- script_lines = SCRIPT_LINES__
- remove_const :SCRIPT_LINES__
- end
- const_set(:SCRIPT_LINES__, debug_lines)
- end
- yield debug_lines
- ensure
- Object.class_eval do
- remove_const :SCRIPT_LINES__
- const_set(:SCRIPT_LINES__, script_lines) if script_lines
- end
- end
-
- def without_term
- env = ENV.to_h.dup
- ENV.delete('TERM')
- yield
- ensure
- ENV.replace(env)
- end
- end
-end
diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb
deleted file mode 100644
index c1bc81241c..0000000000
--- a/test/irb/yamatanooroti/test_rendering.rb
+++ /dev/null
@@ -1,494 +0,0 @@
-require 'irb'
-
-begin
- require 'yamatanooroti'
-rescue LoadError, NameError
- # On Ruby repository, this test suite doesn't run because Ruby repo doesn't
- # have the yamatanooroti gem.
- return
-end
-
-class IRB::RenderingTest < Yamatanooroti::TestCase
- def setup
- @original_term = ENV['TERM']
- @home_backup = ENV['HOME']
- @xdg_config_home_backup = ENV['XDG_CONFIG_HOME']
- ENV['TERM'] = "xterm-256color"
- @pwd = Dir.pwd
- suffix = '%010d' % Random.rand(0..65535)
- @tmpdir = File.join(File.expand_path(Dir.tmpdir), "test_irb_#{$$}_#{suffix}")
- begin
- Dir.mkdir(@tmpdir)
- rescue Errno::EEXIST
- FileUtils.rm_rf(@tmpdir)
- Dir.mkdir(@tmpdir)
- end
- @irbrc_backup = ENV['IRBRC']
- @irbrc_file = ENV['IRBRC'] = File.join(@tmpdir, 'temporaty_irbrc')
- File.unlink(@irbrc_file) if File.exist?(@irbrc_file)
- ENV['HOME'] = File.join(@tmpdir, 'home')
- ENV['XDG_CONFIG_HOME'] = File.join(@tmpdir, 'xdg_config_home')
- end
-
- def teardown
- FileUtils.rm_rf(@tmpdir)
- ENV['IRBRC'] = @irbrc_backup
- ENV['TERM'] = @original_term
- ENV['HOME'] = @home_backup
- ENV['XDG_CONFIG_HOME'] = @xdg_config_home_backup
- end
-
- def test_launch
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- 'Hello, World!'
- EOC
- assert_screen(<<~EOC)
- irb(main):001> 'Hello, World!'
- => "Hello, World!"
- irb(main):002>
- EOC
- close
- end
-
- def test_configuration_file_is_skipped_with_dash_f
- write_irbrc <<~'LINES'
- puts '.irbrc file should be ignored when -f is used'
- LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- 'Hello, World!'
- EOC
- assert_screen(<<~EOC)
- irb(main):001> 'Hello, World!'
- => "Hello, World!"
- irb(main):002>
- EOC
- close
- end
-
- def test_configuration_file_is_skipped_with_dash_f_for_nested_sessions
- write_irbrc <<~'LINES'
- puts '.irbrc file should be ignored when -f is used'
- LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- 'Hello, World!'
- binding.irb
- exit!
- EOC
- assert_screen(<<~EOC)
- irb(main):001> 'Hello, World!'
- => "Hello, World!"
- irb(main):002> binding.irb
- irb(main):003> exit!
- irb(main):001>
- EOC
- close
- end
-
- def test_nomultiline
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb --nomultiline}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- if true
- if false
- a = "hello
- world"
- puts a
- end
- end
- EOC
- assert_screen(<<~EOC)
- irb(main):001> if true
- irb(main):002* if false
- irb(main):003* a = "hello
- irb(main):004" world"
- irb(main):005* puts a
- irb(main):006* end
- irb(main):007* end
- => nil
- irb(main):008>
- EOC
- close
- end
-
- def test_multiline_paste
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- class A
- def inspect; '#<A>'; end
- def a; self; end
- def b; true; end
- end
-
- a = A.new
-
- a
- .a
- .b
- .itself
- EOC
- assert_screen(<<~EOC)
- irb(main):001* class A
- irb(main):002* def inspect; '#<A>'; end
- irb(main):003* def a; self; end
- irb(main):004* def b; true; end
- irb(main):005> end
- => :b
- irb(main):006>
- irb(main):007> a = A.new
- => #<A>
- irb(main):008>
- irb(main):009> a
- irb(main):010> .a
- irb(main):011> .b
- irb(main):012> .itself
- => true
- irb(main):013>
- EOC
- close
- end
-
- def test_evaluate_each_toplevel_statement_by_multiline_paste
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- class A
- def inspect; '#<A>'; end
- def b; self; end
- def c; true; end
- end
-
- a = A.new
-
- a
- .b
- # aaa
- .c
-
- (a)
- &.b()
-
- class A def b; self; end; def c; true; end; end;
- a = A.new
- a
- .b
- # aaa
- .c
- (a)
- &.b()
- .itself
- EOC
- assert_screen(<<~EOC)
- irb(main):001* class A
- irb(main):002* def inspect; '#<A>'; end
- irb(main):003* def b; self; end
- irb(main):004* def c; true; end
- irb(main):005> end
- => :c
- irb(main):006>
- irb(main):007> a = A.new
- => #<A>
- irb(main):008>
- irb(main):009> a
- irb(main):010> .b
- irb(main):011> # aaa
- irb(main):012> .c
- => true
- irb(main):013>
- irb(main):014> (a)
- irb(main):015> &.b()
- => #<A>
- irb(main):016>
- irb(main):017> class A def b; self; end; def c; true; end; end;
- irb(main):018> a = A.new
- => #<A>
- irb(main):019> a
- irb(main):020> .b
- irb(main):021> # aaa
- irb(main):022> .c
- => true
- irb(main):023> (a)
- irb(main):024> &.b()
- irb(main):025> .itself
- => #<A>
- irb(main):026>
- EOC
- close
- end
-
- def test_symbol_with_backtick
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write(<<~EOC)
- :`
- EOC
- assert_screen(<<~EOC)
- irb(main):001> :`
- => :`
- irb(main):002>
- EOC
- close
- end
-
- def test_autocomplete_with_multiple_doc_namespaces
- start_terminal(3, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("{}.__id_")
- write("\C-i")
- assert_screen(/irb\(main\):001> {}\.__id__\n }\.__id__(?:Press )?/)
- close
- end
-
- def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right
- rdoc_dir = File.join(@tmpdir, 'rdoc')
- system("bundle exec rdoc lib -r -o #{rdoc_dir}")
- write_irbrc <<~LINES
- IRB.conf[:EXTRA_DOC_DIRS] = ['#{rdoc_dir}']
- IRB.conf[:PROMPT][:MY_PROMPT] = {
- :PROMPT_I => "%03n> ",
- :PROMPT_S => "%03n> ",
- :PROMPT_C => "%03n> "
- }
- IRB.conf[:PROMPT_MODE] = :MY_PROMPT
- LINES
- start_terminal(4, 19, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /001>/)
- write("IR")
- write("\C-i")
-
- # This is because on macOS we display different shortcut for displaying the full doc
- # 'O' is for 'Option' and 'A' is for 'Alt'
- if RUBY_PLATFORM =~ /darwin/
- assert_screen(<<~EOC)
- 001> IRB
- IRBPress Opti
- IRB
- EOC
- else
- assert_screen(<<~EOC)
- 001> IRB
- IRBPress Alt+
- IRB
- EOC
- end
- close
- end
-
- def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left
- rdoc_dir = File.join(@tmpdir, 'rdoc')
- system("bundle exec rdoc lib -r -o #{rdoc_dir}")
- write_irbrc <<~LINES
- IRB.conf[:EXTRA_DOC_DIRS] = ['#{rdoc_dir}']
- IRB.conf[:PROMPT][:MY_PROMPT] = {
- :PROMPT_I => "%03n> ",
- :PROMPT_S => "%03n> ",
- :PROMPT_C => "%03n> "
- }
- IRB.conf[:PROMPT_MODE] = :MY_PROMPT
- LINES
- start_terminal(4, 12, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /001>/)
- write("IR")
- write("\C-i")
- assert_screen(<<~EOC)
- 001> IRB
- PressIRB
- IRB
- EOC
- close
- end
-
- def test_assignment_expression_truncate
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- # Assignment expression code that turns into non-assignment expression after evaluation
- code = "a /'/i if false; a=1; x=1000.times.to_a#'.size"
- write(code + "\n")
- assert_screen(<<~EOC)
- irb(main):001> #{code}
- =>
- [0,
- ...
- irb(main):002>
- EOC
- close
- end
-
- def test_ctrl_c_is_handled
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- # Assignment expression code that turns into non-assignment expression after evaluation
- write("\C-c")
- assert_screen(<<~EOC)
- irb(main):001>
- ^C
- irb(main):001>
- EOC
- close
- end
-
- def test_show_cmds_with_pager_can_quit_with_ctrl_c
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("help\n")
- write("G") # move to the end of the screen
- write("\C-c") # quit pager
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
-
- # IRB should resume
- assert_screen(/foobar/)
- # IRB::Abort should be rescued
- assert_screen(/\A(?!IRB::Abort)/)
- close
- end
-
- def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_total_length
- write_irbrc <<~'LINES'
- require "irb/pager"
- LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("IRB::Pager.page_content('a' * (80 * 8))\n")
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
-
- assert_screen(/a{80}/)
- # because pager is invoked, foobar will not be evaluated
- assert_screen(/\A(?!foobar)/)
- close
- end
-
- def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_screen_height
- write_irbrc <<~'LINES'
- require "irb/pager"
- LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("IRB::Pager.page_content('a\n' * 8)\n")
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
-
- assert_screen(/(a\n){8}/)
- # because pager is invoked, foobar will not be evaluated
- assert_screen(/\A(?!foobar)/)
- close
- end
-
- def test_pager_page_content_doesnt_page_output_when_it_fits_in_the_screen
- write_irbrc <<~'LINES'
- require "irb/pager"
- LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("IRB::Pager.page_content('a' * (80 * 7))\n")
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
-
- assert_screen(/a{80}/)
- # because pager is not invoked, foobar will be evaluated
- assert_screen(/foobar/)
- close
- end
-
- def test_long_evaluation_output_is_paged
- write_irbrc <<~'LINES'
- require "irb/pager"
- LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("'a' * 80 * 11\n")
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
-
- assert_screen(/"a{79}\n(a{80}\n){7}/)
- # because pager is invoked, foobar will not be evaluated
- assert_screen(/\A(?!foobar)/)
- close
- end
-
- def test_pretty_print_preview_with_slow_inspect
- write_irbrc <<~'LINES'
- require "irb/pager"
- LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("o1 = Object.new; def o1.inspect; 'INSPECT'; end\n")
- write("o2 = Object.new; def o2.inspect; sleep 0.1; 'SLOW'; end\n")
- # preview should be shown even if pretty_print is not completed.
- write("[o1] * 20 + [o2] * 100\n")
- assert_screen(/=>\n\[INSPECT,\n( INSPECT,\n){6}Preparing full inspection value\.\.\./)
- write("\C-c") # abort pretty_print
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- assert_screen(/foobar/)
- close
- end
-
- def test_long_evaluation_output_is_preserved_after_paging
- write_irbrc <<~'LINES'
- require "irb/pager"
- LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
- write("'a' * 80 * 11\n")
- write("q") # quit pager
- write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
-
- # confirm pager has exited
- assert_screen(/foobar/)
- # confirm output is preserved
- assert_screen(/(a{80}\n){6}/)
- close
- end
-
- def test_debug_integration_hints_debugger_commands
- write_irbrc <<~'LINES'
- IRB.conf[:USE_COLORIZE] = false
- LINES
- script = Tempfile.create(["debug", ".rb"])
- script.write <<~RUBY
- binding.irb
- RUBY
- script.close
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: /irb\(main\)/)
- write("debug\n")
- write("pp 1\n")
- write("pp 1")
-
- # submitted input shouldn't contain hint
- assert_screen(/irb:rdbg\(main\):002> pp 1\n/)
- # unsubmitted input should contain hint
- assert_screen(/irb:rdbg\(main\):003> pp 1 # debug command\n/)
- close
- ensure
- File.unlink(script) if script
- end
-
- def test_debug_integration_doesnt_hint_non_debugger_commands
- write_irbrc <<~'LINES'
- IRB.conf[:USE_COLORIZE] = false
- LINES
- script = Tempfile.create(["debug", ".rb"])
- script.write <<~RUBY
- binding.irb
- RUBY
- script.close
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: /irb\(main\)/)
- write("debug\n")
- write("foo")
- assert_screen(/irb:rdbg\(main\):002> foo\n/)
- close
- ensure
- File.unlink(script) if script
- end
-
- def test_debug_integration_doesnt_hint_debugger_commands_in_nomultiline_mode
- write_irbrc <<~'LINES'
- IRB.conf[:USE_SINGLELINE] = true
- LINES
- script = Tempfile.create(["debug", ".rb"])
- script.write <<~RUBY
- puts 'start IRB'
- binding.irb
- RUBY
- script.close
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: 'start IRB')
- write("debug\n")
- write("pp 1")
- # submitted input shouldn't contain hint
- assert_screen(/irb:rdbg\(main\):002> pp 1\n/)
- close
- ensure
- File.unlink(script) if script
- end
-
- private
-
- def write_irbrc(content)
- File.open(@irbrc_file, 'w') do |f|
- f.write content
- end
- end
-end
diff --git a/test/reline/helper.rb b/test/reline/helper.rb
deleted file mode 100644
index 6f470a617f..0000000000
--- a/test/reline/helper.rb
+++ /dev/null
@@ -1,158 +0,0 @@
-$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
-
-ENV['TERM'] = 'xterm' # for some CI environments
-
-require 'reline'
-require 'test/unit'
-
-begin
- require 'rbconfig'
-rescue LoadError
-end
-
-begin
- # This should exist and available in load path when this file is mirrored to ruby/ruby and running at there
- if File.exist?(File.expand_path('../../tool/lib/envutil.rb', __dir__))
- require 'envutil'
- end
-rescue LoadError
-end
-
-module Reline
- class << self
- def test_mode(ansi: false)
- @original_iogate = IOGate
-
- if defined?(RELINE_TEST_ENCODING)
- encoding = RELINE_TEST_ENCODING
- else
- encoding = Encoding::UTF_8
- end
-
- if ansi
- new_io_gate = ANSI.new
- # Setting ANSI gate's screen size through set_screen_size will also change the tester's stdin's screen size
- # Let's avoid that side-effect by stubbing the get_screen_size method
- new_io_gate.define_singleton_method(:get_screen_size) do
- [24, 80]
- end
- new_io_gate.define_singleton_method(:encoding) do
- encoding
- end
- else
- new_io_gate = Dumb.new(encoding: encoding)
- end
-
- remove_const('IOGate')
- const_set('IOGate', new_io_gate)
- core.config.instance_variable_set(:@test_mode, true)
- core.config.reset
- end
-
- def test_reset
- remove_const('IOGate')
- const_set('IOGate', @original_iogate)
- Reline.instance_variable_set(:@core, nil)
- end
-
- # Return a executable name to spawn Ruby process. In certain build configuration,
- # "ruby" may not be available.
- def test_rubybin
- # When this test suite is running in ruby/ruby, prefer EnvUtil result over original implementation
- if const_defined?(:EnvUtil)
- return EnvUtil.rubybin
- end
-
- # The following is a simplified port of EnvUtil.rubybin in ruby/ruby
- if ruby = ENV["RUBY"]
- return ruby
- end
- ruby = "ruby"
- exeext = RbConfig::CONFIG["EXEEXT"]
- rubyexe = (ruby + exeext if exeext and !exeext.empty?)
- if File.exist? ruby and File.executable? ruby and !File.directory? ruby
- return File.expand_path(ruby)
- end
- if rubyexe and File.exist? rubyexe and File.executable? rubyexe
- return File.expand_path(rubyexe)
- end
- if defined?(RbConfig.ruby)
- RbConfig.ruby
- else
- "ruby"
- end
- end
- end
-end
-
-class Reline::TestCase < Test::Unit::TestCase
- private def convert_str(input)
- input.encode(@line_editor.encoding, Encoding::UTF_8)
- end
-
- def omit_unless_utf8
- omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8
- end
-
- def input_key_by_symbol(method_symbol, char: nil, csi: false)
- char ||= csi ? "\e[A" : "\C-a"
- @line_editor.input_key(Reline::Key.new(char, method_symbol, false))
- end
-
- def input_keys(input)
- input = convert_str(input)
-
- key_stroke = Reline::KeyStroke.new(@config, @encoding)
- input_bytes = input.bytes
- until input_bytes.empty?
- expanded, input_bytes = key_stroke.expand(input_bytes)
- expanded.each do |key|
- @line_editor.input_key(key)
- end
- end
- end
-
- def set_line_around_cursor(before, after)
- input_keys("\C-a\C-k")
- input_keys(after)
- input_keys("\C-a")
- input_keys(before)
- end
-
- def assert_line_around_cursor(before, after)
- before = convert_str(before)
- after = convert_str(after)
- line = @line_editor.current_line
- byte_pointer = @line_editor.instance_variable_get(:@byte_pointer)
- actual_before = line.byteslice(0, byte_pointer)
- actual_after = line.byteslice(byte_pointer..)
- assert_equal([before, after], [actual_before, actual_after])
- end
-
- def assert_byte_pointer_size(expected)
- expected = convert_str(expected)
- byte_pointer = @line_editor.instance_variable_get(:@byte_pointer)
- chunk = @line_editor.line.byteslice(0, byte_pointer)
- assert_equal(
- expected.bytesize, byte_pointer,
- <<~EOM)
- <#{expected.inspect} (#{expected.encoding.inspect})> expected but was
- <#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::Dumb.new.encoding.inspect}>
- EOM
- end
-
- def assert_line_index(expected)
- assert_equal(expected, @line_editor.instance_variable_get(:@line_index))
- end
-
- def assert_whole_lines(expected)
- assert_equal(expected, @line_editor.whole_lines)
- end
-
- def assert_key_binding(input, method_symbol, editing_modes = [:emacs, :vi_insert, :vi_command])
- editing_modes.each do |editing_mode|
- @config.editing_mode = editing_mode
- assert_equal(method_symbol, @config.editing_mode.get(input.bytes))
- end
- end
-end
diff --git a/test/reline/test_ansi.rb b/test/reline/test_ansi.rb
deleted file mode 100644
index 5e28e72b06..0000000000
--- a/test/reline/test_ansi.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-require_relative 'helper'
-require 'reline'
-
-class Reline::ANSITest < Reline::TestCase
- def setup
- Reline.send(:test_mode, ansi: true)
- @config = Reline::Config.new
- Reline.core.io_gate.set_default_key_bindings(@config)
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_home
- assert_key_binding("\e[1~", :ed_move_to_beg) # Console (80x25)
- assert_key_binding("\e[H", :ed_move_to_beg) # KDE
- assert_key_binding("\e[7~", :ed_move_to_beg) # urxvt / exoterm
- assert_key_binding("\eOH", :ed_move_to_beg) # GNOME
- end
-
- def test_end
- assert_key_binding("\e[4~", :ed_move_to_end) # Console (80x25)
- assert_key_binding("\e[F", :ed_move_to_end) # KDE
- assert_key_binding("\e[8~", :ed_move_to_end) # urxvt / exoterm
- assert_key_binding("\eOF", :ed_move_to_end) # GNOME
- end
-
- def test_delete
- assert_key_binding("\e[3~", :key_delete)
- end
-
- def test_up_arrow
- assert_key_binding("\e[A", :ed_prev_history) # Console (80x25)
- assert_key_binding("\eOA", :ed_prev_history)
- end
-
- def test_down_arrow
- assert_key_binding("\e[B", :ed_next_history) # Console (80x25)
- assert_key_binding("\eOB", :ed_next_history)
- end
-
- def test_right_arrow
- assert_key_binding("\e[C", :ed_next_char) # Console (80x25)
- assert_key_binding("\eOC", :ed_next_char)
- end
-
- def test_left_arrow
- assert_key_binding("\e[D", :ed_prev_char) # Console (80x25)
- assert_key_binding("\eOD", :ed_prev_char)
- end
-
- # Ctrl+arrow and Meta+arrow
- def test_extended
- assert_key_binding("\e[1;5C", :em_next_word) # Ctrl+→
- assert_key_binding("\e[1;5D", :ed_prev_word) # Ctrl+←
- assert_key_binding("\e[1;3C", :em_next_word) # Meta+→
- assert_key_binding("\e[1;3D", :ed_prev_word) # Meta+←
- assert_key_binding("\e\e[C", :em_next_word) # Meta+→
- assert_key_binding("\e\e[D", :ed_prev_word) # Meta+←
- end
-
- def test_shift_tab
- assert_key_binding("\e[Z", :completion_journey_up, [:emacs, :vi_insert])
- end
-
- # A few emacs bindings that are always mapped
- def test_more_emacs
- assert_key_binding("\e ", :em_set_mark, [:emacs])
- assert_key_binding("\C-x\C-x", :em_exchange_mark, [:emacs])
- end
-end
diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb
deleted file mode 100644
index 3c9094eece..0000000000
--- a/test/reline/test_config.rb
+++ /dev/null
@@ -1,616 +0,0 @@
-require_relative 'helper'
-
-class Reline::Config::Test < Reline::TestCase
- def setup
- @pwd = Dir.pwd
- @tmpdir = File.join(Dir.tmpdir, "test_reline_config_#{$$}")
- begin
- Dir.mkdir(@tmpdir)
- rescue Errno::EEXIST
- FileUtils.rm_rf(@tmpdir)
- Dir.mkdir(@tmpdir)
- end
- Dir.chdir(@tmpdir)
- Reline.test_mode
- @config = Reline::Config.new
- @inputrc_backup = ENV['INPUTRC']
- end
-
- def teardown
- Dir.chdir(@pwd)
- FileUtils.rm_rf(@tmpdir)
- Reline.test_reset
- @config.reset
- ENV['INPUTRC'] = @inputrc_backup
- end
-
- def get_config_variable(variable)
- @config.instance_variable_get(variable)
- end
-
- def additional_key_bindings(keymap_label)
- get_config_variable(:@additional_key_bindings)[keymap_label].instance_variable_get(:@key_bindings)
- end
-
- def registered_key_bindings(keys)
- key_bindings = @config.key_bindings
- keys.to_h { |key| [key, key_bindings.get(key)] }
- end
-
- def test_read_lines
- @config.read_lines(<<~LINES.lines)
- set show-mode-in-prompt on
- LINES
-
- assert_equal true, get_config_variable(:@show_mode_in_prompt)
- end
-
- def test_read_lines_with_variable
- @config.read_lines(<<~LINES.lines)
- set disable-completion on
- LINES
-
- assert_equal true, get_config_variable(:@disable_completion)
- end
-
- def test_string_value
- @config.read_lines(<<~LINES.lines)
- set show-mode-in-prompt on
- set emacs-mode-string Emacs
- LINES
-
- assert_equal 'Emacs', get_config_variable(:@emacs_mode_string)
- end
-
- def test_string_value_with_brackets
- @config.read_lines(<<~LINES.lines)
- set show-mode-in-prompt on
- set emacs-mode-string [Emacs]
- LINES
-
- assert_equal '[Emacs]', get_config_variable(:@emacs_mode_string)
- end
-
- def test_string_value_with_brackets_and_quotes
- @config.read_lines(<<~LINES.lines)
- set show-mode-in-prompt on
- set emacs-mode-string "[Emacs]"
- LINES
-
- assert_equal '[Emacs]', get_config_variable(:@emacs_mode_string)
- end
-
- def test_string_value_with_parens
- @config.read_lines(<<~LINES.lines)
- set show-mode-in-prompt on
- set emacs-mode-string (Emacs)
- LINES
-
- assert_equal '(Emacs)', get_config_variable(:@emacs_mode_string)
- end
-
- def test_string_value_with_parens_and_quotes
- @config.read_lines(<<~LINES.lines)
- set show-mode-in-prompt on
- set emacs-mode-string "(Emacs)"
- LINES
-
- assert_equal '(Emacs)', get_config_variable(:@emacs_mode_string)
- end
-
- def test_encoding_is_ascii
- @config.reset
- Reline.core.io_gate.instance_variable_set(:@encoding, Encoding::US_ASCII)
- @config = Reline::Config.new
-
- assert_equal true, @config.convert_meta
- end
-
- def test_encoding_is_not_ascii
- @config = Reline::Config.new
-
- assert_equal false, @config.convert_meta
- end
-
- def test_invalid_keystroke
- @config.read_lines(<<~LINES.lines)
- #"a": comment
- a: error
- "b": no-error
- LINES
- key_bindings = additional_key_bindings(:emacs)
- assert_not_include key_bindings, 'a'.bytes
- assert_not_include key_bindings, nil
- assert_not_include key_bindings, []
- assert_include key_bindings, 'b'.bytes
- end
-
- def test_bind_key
- assert_equal ['input'.bytes, 'abcde'.bytes], @config.parse_key_binding('"input"', '"abcde"')
- end
-
- def test_bind_key_with_macro
-
- assert_equal ['input'.bytes, :abcde], @config.parse_key_binding('"input"', 'abcde')
- end
-
- def test_bind_key_with_escaped_chars
- assert_equal ['input'.bytes, "\e \\ \" ' \a \b \d \f \n \r \t \v".bytes], @config.parse_key_binding('"input"', '"\\e \\\\ \\" \\\' \\a \\b \\d \\f \\n \\r \\t \\v"')
- end
-
- def test_bind_key_with_ctrl_chars
- assert_equal ['input'.bytes, "\C-h\C-h\C-_".bytes], @config.parse_key_binding('"input"', '"\C-h\C-H\C-_"')
- assert_equal ['input'.bytes, "\C-h\C-h\C-_".bytes], @config.parse_key_binding('"input"', '"\Control-h\Control-H\Control-_"')
- end
-
- def test_bind_key_with_meta_chars
- assert_equal ['input'.bytes, "\eh\eH\e_".bytes], @config.parse_key_binding('"input"', '"\M-h\M-H\M-_"')
- assert_equal ['input'.bytes, "\eh\eH\e_".bytes], @config.parse_key_binding('"input"', '"\Meta-h\Meta-H\M-_"')
- end
-
- def test_bind_key_with_ctrl_meta_chars
- assert_equal ['input'.bytes, "\e\C-h\e\C-h\e\C-_".bytes], @config.parse_key_binding('"input"', '"\M-\C-h\C-\M-H\M-\C-_"')
- assert_equal ['input'.bytes, "\e\C-h\e\C-_".bytes], @config.parse_key_binding('"input"', '"\Meta-\Control-h\Control-\Meta-_"')
- end
-
- def test_bind_key_with_octal_number
- input = %w{i n p u t}.map(&:ord)
- assert_equal [input, "\1".bytes], @config.parse_key_binding('"input"', '"\1"')
- assert_equal [input, "\12".bytes], @config.parse_key_binding('"input"', '"\12"')
- assert_equal [input, "\123".bytes], @config.parse_key_binding('"input"', '"\123"')
- assert_equal [input, "\123".bytes + '4'.bytes], @config.parse_key_binding('"input"', '"\1234"')
- end
-
- def test_bind_key_with_hexadecimal_number
- input = %w{i n p u t}.map(&:ord)
- assert_equal [input, "\x4".bytes], @config.parse_key_binding('"input"', '"\x4"')
- assert_equal [input, "\x45".bytes], @config.parse_key_binding('"input"', '"\x45"')
- assert_equal [input, "\x45".bytes + '6'.bytes], @config.parse_key_binding('"input"', '"\x456"')
- end
-
- def test_include
- File.open('included_partial', 'wt') do |f|
- f.write(<<~PARTIAL_LINES)
- set show-mode-in-prompt on
- PARTIAL_LINES
- end
- @config.read_lines(<<~LINES.lines)
- $include included_partial
- LINES
-
- assert_equal true, get_config_variable(:@show_mode_in_prompt)
- end
-
- def test_include_expand_path
- home_backup = ENV['HOME']
- File.open('included_partial', 'wt') do |f|
- f.write(<<~PARTIAL_LINES)
- set show-mode-in-prompt on
- PARTIAL_LINES
- end
- ENV['HOME'] = Dir.pwd
- @config.read_lines(<<~LINES.lines)
- $include ~/included_partial
- LINES
-
- assert_equal true, get_config_variable(:@show_mode_in_prompt)
- ensure
- ENV['HOME'] = home_backup
- end
-
- def test_if
- @config.read_lines(<<~LINES.lines)
- $if Ruby
- set vi-cmd-mode-string (cmd)
- $else
- set vi-cmd-mode-string [cmd]
- $endif
- LINES
-
- assert_equal '(cmd)', get_config_variable(:@vi_cmd_mode_string)
- end
-
- def test_if_with_false
- @config.read_lines(<<~LINES.lines)
- $if Python
- set vi-cmd-mode-string (cmd)
- $else
- set vi-cmd-mode-string [cmd]
- $endif
- LINES
-
- assert_equal '[cmd]', get_config_variable(:@vi_cmd_mode_string)
- end
-
- def test_if_with_indent
- %w[Ruby Reline].each do |cond|
- @config.read_lines(<<~LINES.lines)
- set vi-cmd-mode-string {cmd}
- $if #{cond}
- set vi-cmd-mode-string (cmd)
- $else
- set vi-cmd-mode-string [cmd]
- $endif
- LINES
-
- assert_equal '(cmd)', get_config_variable(:@vi_cmd_mode_string)
- end
- end
-
- def test_nested_if_else
- @config.read_lines(<<~LINES.lines)
- $if Ruby
- "\x1": "O"
- $if NotRuby
- "\x2": "X"
- $else
- "\x3": "O"
- $if Ruby
- "\x4": "O"
- $else
- "\x5": "X"
- $endif
- "\x6": "O"
- $endif
- "\x7": "O"
- $else
- "\x8": "X"
- $if NotRuby
- "\x9": "X"
- $else
- "\xA": "X"
- $endif
- "\xB": "X"
- $endif
- "\xC": "O"
- LINES
- keys = [0x1, 0x3, 0x4, 0x6, 0x7, 0xC]
- key_bindings = keys.to_h { |k| [[k], ['O'.ord]] }
- assert_equal(key_bindings, additional_key_bindings(:emacs))
- end
-
- def test_unclosed_if
- e = assert_raise(Reline::Config::InvalidInputrc) do
- @config.read_lines(<<~LINES.lines, "INPUTRC")
- $if Ruby
- LINES
- end
- assert_equal "INPUTRC:1: unclosed if", e.message
- end
-
- def test_unmatched_else
- e = assert_raise(Reline::Config::InvalidInputrc) do
- @config.read_lines(<<~LINES.lines, "INPUTRC")
- $else
- LINES
- end
- assert_equal "INPUTRC:1: unmatched else", e.message
- end
-
- def test_unmatched_endif
- e = assert_raise(Reline::Config::InvalidInputrc) do
- @config.read_lines(<<~LINES.lines, "INPUTRC")
- $endif
- LINES
- end
- assert_equal "INPUTRC:1: unmatched endif", e.message
- end
-
- def test_if_with_mode
- @config.read_lines(<<~LINES.lines)
- $if mode=emacs
- "\C-e": history-search-backward # comment
- $else
- "\C-f": history-search-forward
- $endif
- LINES
-
- assert_equal({[5] => :history_search_backward}, additional_key_bindings(:emacs))
- assert_equal({}, additional_key_bindings(:vi_insert))
- assert_equal({}, additional_key_bindings(:vi_command))
- end
-
- def test_else
- @config.read_lines(<<~LINES.lines)
- $if mode=vi
- "\C-e": history-search-backward # comment
- $else
- "\C-f": history-search-forward
- $endif
- LINES
-
- assert_equal({[6] => :history_search_forward}, additional_key_bindings(:emacs))
- assert_equal({}, additional_key_bindings(:vi_insert))
- assert_equal({}, additional_key_bindings(:vi_command))
- end
-
- def test_if_with_invalid_mode
- @config.read_lines(<<~LINES.lines)
- $if mode=vim
- "\C-e": history-search-backward
- $else
- "\C-f": history-search-forward # comment
- $endif
- LINES
-
- assert_equal({[6] => :history_search_forward}, additional_key_bindings(:emacs))
- assert_equal({}, additional_key_bindings(:vi_insert))
- assert_equal({}, additional_key_bindings(:vi_command))
- end
-
- def test_mode_label_differs_from_keymap_label
- @config.read_lines(<<~LINES.lines)
- # Sets mode_label and keymap_label to vi
- set editing-mode vi
- # Change keymap_label to emacs. mode_label is still vi.
- set keymap emacs
- # condition=true because current mode_label is vi
- $if mode=vi
- # sets keybinding to current keymap_label=emacs
- "\C-e": history-search-backward
- $endif
- LINES
- assert_equal({[5] => :history_search_backward}, additional_key_bindings(:emacs))
- assert_equal({}, additional_key_bindings(:vi_insert))
- assert_equal({}, additional_key_bindings(:vi_command))
- end
-
- def test_if_without_else_condition
- @config.read_lines(<<~LINES.lines)
- set editing-mode vi
- $if mode=vi
- "\C-e": history-search-backward
- $endif
- LINES
-
- assert_equal({}, additional_key_bindings(:emacs))
- assert_equal({[5] => :history_search_backward}, additional_key_bindings(:vi_insert))
- assert_equal({}, additional_key_bindings(:vi_command))
- end
-
- def test_default_key_bindings
- @config.add_default_key_binding('abcd'.bytes, 'EFGH'.bytes)
- @config.read_lines(<<~'LINES'.lines)
- "abcd": "ABCD"
- "ijkl": "IJKL"
- LINES
-
- expected = { 'abcd'.bytes => 'ABCD'.bytes, 'ijkl'.bytes => 'IJKL'.bytes }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_additional_key_bindings
- @config.read_lines(<<~'LINES'.lines)
- "ef": "EF"
- "gh": "GH"
- LINES
-
- expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_unquoted_additional_key_bindings
- @config.read_lines(<<~'LINES'.lines)
- Meta-a: "Ma"
- Control-b: "Cb"
- Meta-Control-c: "MCc"
- Control-Meta-d: "CMd"
- M-C-e: "MCe"
- C-M-f: "CMf"
- LINES
-
- expected = { "\ea".bytes => 'Ma'.bytes, "\C-b".bytes => 'Cb'.bytes, "\e\C-c".bytes => 'MCc'.bytes, "\e\C-d".bytes => 'CMd'.bytes, "\e\C-e".bytes => 'MCe'.bytes, "\e\C-f".bytes => 'CMf'.bytes }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_additional_key_bindings_with_nesting_and_comment_out
- @config.read_lines(<<~'LINES'.lines)
- #"ab": "AB"
- #"cd": "cd"
- "ef": "EF"
- "gh": "GH"
- LINES
-
- expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_additional_key_bindings_for_other_keymap
- @config.read_lines(<<~'LINES'.lines)
- set keymap vi-command
- "ab": "AB"
- set keymap vi-insert
- "cd": "CD"
- set keymap emacs
- "ef": "EF"
- set editing-mode vi # keymap changes to be vi-insert
- LINES
-
- expected = { 'cd'.bytes => 'CD'.bytes }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_additional_key_bindings_for_auxiliary_emacs_keymaps
- @config.read_lines(<<~'LINES'.lines)
- set keymap emacs
- "ab": "AB"
- set keymap emacs-standard
- "cd": "CD"
- set keymap emacs-ctlx
- "ef": "EF"
- set keymap emacs-meta
- "gh": "GH"
- set editing-mode emacs # keymap changes to be emacs
- LINES
-
- expected = {
- 'ab'.bytes => 'AB'.bytes,
- 'cd'.bytes => 'CD'.bytes,
- "\C-xef".bytes => 'EF'.bytes,
- "\egh".bytes => 'GH'.bytes,
- }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_key_bindings_with_reset
- # @config.reset is called after each readline.
- # inputrc file is read once, so key binding shouldn't be cleared by @config.reset
- @config.add_default_key_binding('default'.bytes, 'DEFAULT'.bytes)
- @config.read_lines(<<~'LINES'.lines)
- "additional": "ADDITIONAL"
- LINES
- @config.reset
- expected = { 'default'.bytes => 'DEFAULT'.bytes, 'additional'.bytes => 'ADDITIONAL'.bytes }
- assert_equal expected, registered_key_bindings(expected.keys)
- end
-
- def test_history_size
- @config.read_lines(<<~LINES.lines)
- set history-size 5000
- LINES
-
- assert_equal 5000, get_config_variable(:@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
- ensure
- ENV['INPUTRC'] = inputrc_backup
- end
-
- def test_inputrc
- inputrc_backup = ENV['INPUTRC']
- expected = "#{@tmpdir}/abcde"
- ENV['INPUTRC'] = expected
- assert_equal expected, @config.inputrc_path
- ensure
- ENV['INPUTRC'] = inputrc_backup
- end
-
- def test_inputrc_raw_value
- @config.read_lines(<<~'LINES'.lines)
- set editing-mode vi ignored-string
- set vi-ins-mode-string aaa aaa
- set vi-cmd-mode-string bbb ccc # comment
- LINES
- assert_equal :vi_insert, get_config_variable(:@editing_mode_label)
- assert_equal 'aaa aaa', @config.vi_ins_mode_string
- assert_equal 'bbb ccc # comment', @config.vi_cmd_mode_string
- end
-
- def test_inputrc_with_utf8
- # This file is encoded by UTF-8 so this heredoc string is also UTF-8.
- @config.read_lines(<<~'LINES'.lines)
- set editing-mode vi
- set vi-cmd-mode-string 🍸
- set vi-ins-mode-string 🍶
- LINES
- assert_equal '🍸', @config.vi_cmd_mode_string
- assert_equal '🍶', @config.vi_ins_mode_string
- rescue Reline::ConfigEncodingConversionError
- # do nothing
- end
-
- def test_inputrc_with_eucjp
- @config.read_lines(<<~"LINES".encode(Encoding::EUC_JP).lines)
- set editing-mode vi
- set vi-cmd-mode-string ォャッ
- set vi-ins-mode-string 能
- LINES
- assert_equal 'ォャッ'.encode(Reline.encoding_system_needs), @config.vi_cmd_mode_string
- assert_equal '能'.encode(Reline.encoding_system_needs), @config.vi_ins_mode_string
- rescue Reline::ConfigEncodingConversionError
- # do nothing
- end
-
- def test_empty_inputrc
- assert_nothing_raised do
- @config.read_lines([])
- end
- end
-
- def test_xdg_config_home
- home_backup = ENV['HOME']
- xdg_config_home_backup = ENV['XDG_CONFIG_HOME']
- inputrc_backup = ENV['INPUTRC']
- xdg_config_home = File.expand_path("#{@tmpdir}/.config/example_dir")
- expected = File.expand_path("#{xdg_config_home}/readline/inputrc")
- FileUtils.mkdir_p(File.dirname(expected))
- FileUtils.touch(expected)
- ENV['HOME'] = @tmpdir
- ENV['XDG_CONFIG_HOME'] = xdg_config_home
- ENV['INPUTRC'] = ''
- assert_equal expected, @config.inputrc_path
- ensure
- FileUtils.rm(expected)
- ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup
- ENV['HOME'] = home_backup
- ENV['INPUTRC'] = inputrc_backup
- end
-
- def test_empty_xdg_config_home
- home_backup = ENV['HOME']
- xdg_config_home_backup = ENV['XDG_CONFIG_HOME']
- inputrc_backup = ENV['INPUTRC']
- ENV['HOME'] = @tmpdir
- ENV['XDG_CONFIG_HOME'] = ''
- ENV['INPUTRC'] = ''
- expected = File.expand_path('~/.config/readline/inputrc')
- FileUtils.mkdir_p(File.dirname(expected))
- FileUtils.touch(expected)
- assert_equal expected, @config.inputrc_path
- ensure
- FileUtils.rm(expected)
- ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup
- ENV['HOME'] = home_backup
- ENV['INPUTRC'] = inputrc_backup
- end
-
- def test_relative_xdg_config_home
- home_backup = ENV['HOME']
- xdg_config_home_backup = ENV['XDG_CONFIG_HOME']
- inputrc_backup = ENV['INPUTRC']
- ENV['HOME'] = @tmpdir
- ENV['INPUTRC'] = ''
- expected = File.expand_path('~/.config/readline/inputrc')
- FileUtils.mkdir_p(File.dirname(expected))
- FileUtils.touch(expected)
- result = Dir.chdir(@tmpdir) do
- xdg_config_home = ".config/example_dir"
- ENV['XDG_CONFIG_HOME'] = xdg_config_home
- inputrc = "#{xdg_config_home}/readline/inputrc"
- FileUtils.mkdir_p(File.dirname(inputrc))
- FileUtils.touch(inputrc)
- @config.inputrc_path
- end
- assert_equal expected, result
- FileUtils.rm(expected)
- ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup
- ENV['HOME'] = home_backup
- ENV['INPUTRC'] = inputrc_backup
- end
-
- def test_reload
- inputrc = "#{@tmpdir}/inputrc"
- ENV['INPUTRC'] = inputrc
-
- File.write(inputrc, "set emacs-mode-string !")
- @config.read
- assert_equal '!', @config.emacs_mode_string
-
- File.write(inputrc, "set emacs-mode-string ?")
- @config.reload
- assert_equal '?', @config.emacs_mode_string
-
- File.write(inputrc, "")
- @config.reload
- assert_equal '@', @config.emacs_mode_string
- end
-end
diff --git a/test/reline/test_face.rb b/test/reline/test_face.rb
deleted file mode 100644
index 8fa2be8fa4..0000000000
--- a/test/reline/test_face.rb
+++ /dev/null
@@ -1,257 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'helper'
-
-class Reline::Face::Test < Reline::TestCase
- RESET_SGR = "\e[0m"
-
- def setup
- @colorterm_backup = ENV['COLORTERM']
- ENV['COLORTERM'] = 'truecolor'
- end
-
- def teardown
- Reline::Face.reset_to_initial_configs
- ENV['COLORTERM'] = @colorterm_backup
- end
-
- class WithInsufficientSetupTest < self
- def setup
- super
- Reline::Face.config(:my_insufficient_config) do |face|
- end
- @face = Reline::Face[:my_insufficient_config]
- end
-
- def test_my_insufficient_config_line
- assert_equal RESET_SGR, @face[:default]
- assert_equal RESET_SGR, @face[:enhanced]
- assert_equal RESET_SGR, @face[:scrollbar]
- end
-
- def test_my_insufficient_configs
- my_configs = Reline::Face.configs[:my_insufficient_config]
- assert_equal(
- {
- default: { style: :reset, escape_sequence: RESET_SGR },
- enhanced: { style: :reset, escape_sequence: RESET_SGR },
- scrollbar: { style: :reset, escape_sequence: RESET_SGR }
- },
- my_configs
- )
- end
- end
-
- class WithSetupTest < self
- def setup
- super
- Reline::Face.config(:my_config) do |face|
- face.define :default, foreground: :blue
- face.define :enhanced, foreground: "#FF1020", background: :black, style: [:bold, :underlined]
- end
- Reline::Face.config(:another_config) do |face|
- face.define :another_label, foreground: :red
- end
- @face = Reline::Face[:my_config]
- end
-
- def test_now_there_are_four_configs
- assert_equal %i(default completion_dialog my_config another_config), Reline::Face.configs.keys
- end
-
- def test_resetting_config_discards_user_defined_configs
- Reline::Face.reset_to_initial_configs
- assert_equal %i(default completion_dialog), Reline::Face.configs.keys
- end
-
- def test_my_configs
- my_configs = Reline::Face.configs[:my_config]
- assert_equal(
- {
- default: {
- escape_sequence: "#{RESET_SGR}\e[34m", foreground: :blue
- },
- enhanced: {
- background: :black,
- foreground: "#FF1020",
- style: [:bold, :underlined],
- escape_sequence: "\e[0m\e[38;2;255;16;32;40;1;4m"
- },
- scrollbar: {
- style: :reset,
- escape_sequence: "\e[0m"
- }
- },
- my_configs
- )
- end
-
- def test_my_config_line
- assert_equal "#{RESET_SGR}\e[34m", @face[:default]
- end
-
- def test_my_config_enhanced
- assert_equal "#{RESET_SGR}\e[38;2;255;16;32;40;1;4m", @face[:enhanced]
- end
-
- def test_not_respond_to_another_label
- assert_equal false, @face.respond_to?(:another_label)
- end
- end
-
- class WithoutSetupTest < self
- def test_my_config_default
- Reline::Face.config(:my_config) do |face|
- # do nothing
- end
- face = Reline::Face[:my_config]
- assert_equal RESET_SGR, face[:default]
- end
-
- def test_style_does_not_exist
- face = Reline::Face[:default]
- assert_raise ArgumentError do
- face[:style_does_not_exist]
- end
- end
-
- def test_invalid_keyword
- assert_raise ArgumentError do
- Reline::Face.config(:invalid_config) do |face|
- face.define :default, invalid_keyword: :red
- end
- end
- end
-
- def test_invalid_foreground_name
- assert_raise ArgumentError do
- Reline::Face.config(:invalid_config) do |face|
- face.define :default, foreground: :invalid_name
- end
- end
- end
-
- def test_invalid_background_name
- assert_raise ArgumentError do
- Reline::Face.config(:invalid_config) do |face|
- face.define :default, background: :invalid_name
- end
- end
- end
-
- def test_invalid_style_name
- assert_raise ArgumentError do
- Reline::Face.config(:invalid_config) do |face|
- face.define :default, style: :invalid_name
- end
- end
- end
-
- def test_private_constants
- [:SGR_PARAMETER, :Config, :CONFIGS].each do |name|
- assert_equal false, Reline::Face.constants.include?(name)
- end
- end
- end
-
- class ConfigTest < self
- def setup
- super
- @config = Reline::Face.const_get(:Config).new(:my_config) { }
- end
-
- def teardown
- super
- Reline::Face.instance_variable_set(:@force_truecolor, nil)
- end
-
- def test_rgb?
- assert_equal true, @config.send(:rgb_expression?, "#FFFFFF")
- end
-
- def test_invalid_rgb?
- assert_equal false, @config.send(:rgb_expression?, "FFFFFF")
- assert_equal false, @config.send(:rgb_expression?, "#FFFFF")
- end
-
- def test_format_to_sgr_preserves_order
- assert_equal(
- "#{RESET_SGR}\e[37;41;1;3m",
- @config.send(:format_to_sgr, foreground: :white, background: :red, style: [:bold, :italicized])
- )
-
- assert_equal(
- "#{RESET_SGR}\e[37;1;3;41m",
- @config.send(:format_to_sgr, foreground: :white, style: [:bold, :italicized], background: :red)
- )
- end
-
- def test_format_to_sgr_with_reset
- assert_equal(
- RESET_SGR,
- @config.send(:format_to_sgr, style: :reset)
- )
- assert_equal(
- "#{RESET_SGR}\e[37;0;41m",
- @config.send(:format_to_sgr, foreground: :white, style: :reset, background: :red)
- )
- end
-
- def test_format_to_sgr_with_single_style
- assert_equal(
- "#{RESET_SGR}\e[37;41;1m",
- @config.send(:format_to_sgr, foreground: :white, background: :red, style: :bold)
- )
- end
-
- def test_truecolor
- ENV['COLORTERM'] = 'truecolor'
- assert_equal true, Reline::Face.truecolor?
- ENV['COLORTERM'] = '24bit'
- assert_equal true, Reline::Face.truecolor?
- ENV['COLORTERM'] = nil
- assert_equal false, Reline::Face.truecolor?
- Reline::Face.force_truecolor
- assert_equal true, Reline::Face.truecolor?
- end
-
- def test_sgr_rgb_truecolor
- ENV['COLORTERM'] = 'truecolor'
- assert_equal "38;2;255;255;255", @config.send(:sgr_rgb, :foreground, "#ffffff")
- assert_equal "48;2;18;52;86", @config.send(:sgr_rgb, :background, "#123456")
- end
-
- def test_sgr_rgb_256color
- ENV['COLORTERM'] = nil
- assert_equal '38;5;231', @config.send(:sgr_rgb, :foreground, '#ffffff')
- assert_equal '48;5;16', @config.send(:sgr_rgb, :background, '#000000')
- # Color steps are [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
- assert_equal '38;5;24', @config.send(:sgr_rgb, :foreground, '#005f87')
- assert_equal '38;5;67', @config.send(:sgr_rgb, :foreground, '#5f87af')
- assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#87afd7')
- assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#afd7ff')
- # Boundary values are [0x30, 0x73, 0x9b, 0xc3, 0xeb]
- assert_equal '38;5;24', @config.send(:sgr_rgb, :foreground, '#2f729a')
- assert_equal '38;5;67', @config.send(:sgr_rgb, :foreground, '#30739b')
- assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#9ac2ea')
- assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#9bc3eb')
- end
-
- def test_force_truecolor_reconfigure
- ENV['COLORTERM'] = nil
-
- Reline::Face.config(:my_config) do |face|
- face.define :default, foreground: '#005f87'
- face.define :enhanced, background: '#afd7ff'
- end
-
- assert_equal "\e[0m\e[38;5;24m", Reline::Face[:my_config][:default]
- assert_equal "\e[0m\e[48;5;153m", Reline::Face[:my_config][:enhanced]
-
- Reline::Face.force_truecolor
-
- assert_equal "\e[0m\e[38;2;0;95;135m", Reline::Face[:my_config][:default]
- assert_equal "\e[0m\e[48;2;175;215;255m", Reline::Face[:my_config][:enhanced]
- end
- end
-end
diff --git a/test/reline/test_history.rb b/test/reline/test_history.rb
deleted file mode 100644
index ea902b0653..0000000000
--- a/test/reline/test_history.rb
+++ /dev/null
@@ -1,317 +0,0 @@
-require_relative 'helper'
-require "reline/history"
-
-class Reline::History::Test < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_ancestors
- assert_equal(Reline::History.ancestors.include?(Array), true)
- end
-
- def test_to_s
- history = history_new
- expected = "HISTORY"
- assert_equal(expected, history.to_s)
- end
-
- def test_get
- history, lines = lines = history_new_and_push_history(5)
- lines.each_with_index do |s, i|
- assert_external_string_equal(s, history[i])
- end
- end
-
- def test_get__negative
- history, lines = lines = history_new_and_push_history(5)
- (1..5).each do |i|
- assert_equal(lines[-i], history[-i])
- end
- end
-
- def test_get__out_of_range
- history, _ = history_new_and_push_history(5)
- invalid_indexes = [5, 6, 100, -6, -7, -100]
- invalid_indexes.each do |i|
- assert_raise(IndexError, "i=<#{i}>") do
- history[i]
- end
- end
-
- invalid_indexes = [100_000_000_000_000_000_000,
- -100_000_000_000_000_000_000]
- invalid_indexes.each do |i|
- assert_raise(RangeError, "i=<#{i}>") do
- history[i]
- end
- end
- end
-
- def test_set
- begin
- history, _ = history_new_and_push_history(5)
- 5.times do |i|
- expected = "set: #{i}"
- history[i] = expected
- assert_external_string_equal(expected, history[i])
- end
- rescue NotImplementedError
- end
- end
-
- def test_set__out_of_range
- history = history_new
- assert_raise(IndexError, NotImplementedError, "index=<0>") do
- history[0] = "set: 0"
- end
-
- history, _ = history_new_and_push_history(5)
- invalid_indexes = [5, 6, 100, -6, -7, -100]
- invalid_indexes.each do |i|
- assert_raise(IndexError, NotImplementedError, "index=<#{i}>") do
- history[i] = "set: #{i}"
- end
- end
-
- invalid_indexes = [100_000_000_000_000_000_000,
- -100_000_000_000_000_000_000]
- invalid_indexes.each do |i|
- assert_raise(RangeError, NotImplementedError, "index=<#{i}>") do
- history[i] = "set: #{i}"
- end
- end
- end
-
- def test_push
- history = history_new
- 5.times do |i|
- s = i.to_s
- assert_equal(history, history.push(s))
- assert_external_string_equal(s, history[i])
- end
- assert_equal(5, history.length)
- end
-
- def test_push__operator
- history = history_new
- 5.times do |i|
- s = i.to_s
- assert_equal(history, history << s)
- assert_external_string_equal(s, history[i])
- end
- assert_equal(5, history.length)
- end
-
- def test_push__plural
- history = history_new
- assert_equal(history, history.push("0", "1", "2", "3", "4"))
- (0..4).each do |i|
- assert_external_string_equal(i.to_s, history[i])
- end
- assert_equal(5, history.length)
-
- assert_equal(history, history.push("5", "6", "7", "8", "9"))
- (5..9).each do |i|
- assert_external_string_equal(i.to_s, history[i])
- end
- assert_equal(10, history.length)
- end
-
- def test_pop
- history = history_new
- begin
- assert_equal(nil, history.pop)
-
- history, lines = lines = history_new_and_push_history(5)
- (1..5).each do |i|
- assert_external_string_equal(lines[-i], history.pop)
- assert_equal(lines.length - i, history.length)
- end
-
- assert_equal(nil, history.pop)
- rescue NotImplementedError
- end
- end
-
- def test_shift
- history = history_new
- begin
- assert_equal(nil, history.shift)
-
- history, lines = lines = history_new_and_push_history(5)
- (0..4).each do |i|
- assert_external_string_equal(lines[i], history.shift)
- assert_equal(lines.length - (i + 1), history.length)
- end
-
- assert_equal(nil, history.shift)
- rescue NotImplementedError
- end
- end
-
- def test_each
- history = history_new
- e = history.each do |s|
- assert(false) # not reachable
- end
- assert_equal(history, e)
- history, lines = lines = history_new_and_push_history(5)
- i = 0
- e = history.each do |s|
- assert_external_string_equal(history[i], s)
- assert_external_string_equal(lines[i], s)
- i += 1
- end
- assert_equal(history, e)
- end
-
- def test_each__enumerator
- history = history_new
- e = history.each
- assert_instance_of(Enumerator, e)
- end
-
- def test_length
- history = history_new
- assert_equal(0, history.length)
- push_history(history, 1)
- assert_equal(1, history.length)
- push_history(history, 4)
- assert_equal(5, history.length)
- history.clear
- assert_equal(0, history.length)
- end
-
- def test_empty_p
- history = history_new
- 2.times do
- assert(history.empty?)
- history.push("s")
- assert_equal(false, history.empty?)
- history.clear
- assert(history.empty?)
- end
- end
-
- def test_delete_at
- begin
- history, lines = lines = history_new_and_push_history(5)
- (0..4).each do |i|
- assert_external_string_equal(lines[i], history.delete_at(0))
- end
- assert(history.empty?)
-
- history, lines = lines = history_new_and_push_history(5)
- (1..5).each do |i|
- assert_external_string_equal(lines[lines.length - i], history.delete_at(-1))
- end
- assert(history.empty?)
-
- history, lines = lines = history_new_and_push_history(5)
- assert_external_string_equal(lines[0], history.delete_at(0))
- assert_external_string_equal(lines[4], history.delete_at(3))
- assert_external_string_equal(lines[1], history.delete_at(0))
- assert_external_string_equal(lines[3], history.delete_at(1))
- assert_external_string_equal(lines[2], history.delete_at(0))
- assert(history.empty?)
- rescue NotImplementedError
- end
- end
-
- def test_delete_at__out_of_range
- history = history_new
- assert_raise(IndexError, NotImplementedError, "index=<0>") do
- history.delete_at(0)
- end
-
- history, _ = history_new_and_push_history(5)
- invalid_indexes = [5, 6, 100, -6, -7, -100]
- invalid_indexes.each do |i|
- assert_raise(IndexError, NotImplementedError, "index=<#{i}>") do
- history.delete_at(i)
- end
- end
-
- invalid_indexes = [100_000_000_000_000_000_000,
- -100_000_000_000_000_000_000]
- invalid_indexes.each do |i|
- assert_raise(RangeError, NotImplementedError, "index=<#{i}>") do
- history.delete_at(i)
- end
- end
- end
-
- def test_history_size_zero
- history = history_new(history_size: 0)
- assert_equal 0, history.size
- history << 'aa'
- history << 'bb'
- assert_equal 0, history.size
- history.push(*%w{aa bb cc})
- assert_equal 0, history.size
- end
-
- def test_history_size_negative_unlimited
- history = history_new(history_size: -1)
- assert_equal 0, history.size
- history << 'aa'
- history << 'bb'
- assert_equal 2, history.size
- history.push(*%w{aa bb cc})
- assert_equal 5, history.size
- end
-
- def test_history_encoding_conversion
- history = history_new
- text1 = String.new("a\u{65535}b\xFFc", encoding: Encoding::UTF_8)
- text2 = String.new("d\xFFe", encoding: Encoding::Shift_JIS)
- history.push(text1.dup, text2.dup)
- expected = [text1, text2].map { |s| s.encode(Reline.encoding_system_needs, invalid: :replace, undef: :replace) }
- assert_equal(expected, history.to_a)
- end
-
- private
-
- def history_new(history_size: 10)
- Reline::History.new(Struct.new(:history_size).new(history_size))
- end
-
- def push_history(history, num)
- lines = []
- num.times do |i|
- s = "a"
- i.times do
- s = s.succ
- end
- lines.push("#{i + 1}:#{s}")
- end
- history.push(*lines)
- return history, lines
- end
-
- def history_new_and_push_history(num)
- history = history_new(history_size: 100)
- return push_history(history, num)
- end
-
- def assert_external_string_equal(expected, actual)
- assert_equal(expected, actual)
- mes = "Encoding of #{actual.inspect} is expected #{get_default_internal_encoding.inspect} but #{actual.encoding}"
- assert_equal(get_default_internal_encoding, actual.encoding, mes)
- end
-
- def get_default_internal_encoding
- if encoding = Reline.core.encoding
- encoding
- elsif RUBY_PLATFORM =~ /mswin|mingw/
- Encoding.default_internal || Encoding::UTF_8
- else
- Encoding.default_internal || Encoding.find("locale")
- end
- end
-end
diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb
deleted file mode 100644
index 78b4c936b9..0000000000
--- a/test/reline/test_key_actor_emacs.rb
+++ /dev/null
@@ -1,1743 +0,0 @@
-require_relative 'helper'
-
-class Reline::KeyActor::EmacsTest < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- @prompt = '> '
- @config = Reline::Config.new # Emacs mode is default
- @config.autocompletion = false
- Reline::HISTORY.instance_variable_set(:@config, @config)
- Reline::HISTORY.clear
- @encoding = Reline.core.encoding
- @line_editor = Reline::LineEditor.new(@config)
- @line_editor.reset(@prompt)
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_ed_insert_one
- input_keys('a')
- assert_line_around_cursor('a', '')
- end
-
- def test_ed_insert_two
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- end
-
- def test_ed_insert_mbchar_one
- input_keys('か')
- assert_line_around_cursor('か', '')
- end
-
- def test_ed_insert_mbchar_two
- input_keys('かき')
- assert_line_around_cursor('かき', '')
- end
-
- def test_ed_insert_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099")
- assert_line_around_cursor("か\u3099", '')
- end
-
- def test_ed_insert_for_plural_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099")
- assert_line_around_cursor("か\u3099き\u3099", '')
- end
-
- def test_move_next_and_prev
- input_keys('abd')
- assert_line_around_cursor('abd', '')
- input_keys("\C-b")
- assert_line_around_cursor('ab', 'd')
- input_keys("\C-b")
- assert_line_around_cursor('a', 'bd')
- input_keys("\C-f")
- assert_line_around_cursor('ab', 'd')
- input_keys('c')
- assert_line_around_cursor('abc', 'd')
- end
-
- def test_move_next_and_prev_for_mbchar
- input_keys('かきけ')
- assert_line_around_cursor('かきけ', '')
- input_keys("\C-b")
- assert_line_around_cursor('かき', 'け')
- input_keys("\C-b")
- assert_line_around_cursor('か', 'きけ')
- input_keys("\C-f")
- assert_line_around_cursor('かき', 'け')
- input_keys('く')
- assert_line_around_cursor('かきく', 'け')
- end
-
- def test_move_next_and_prev_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099け\u3099")
- assert_line_around_cursor("か\u3099き\u3099け\u3099", '')
- input_keys("\C-b")
- assert_line_around_cursor("か\u3099き\u3099", "け\u3099")
- input_keys("\C-b")
- assert_line_around_cursor("か\u3099", "き\u3099け\u3099")
- input_keys("\C-f")
- assert_line_around_cursor("か\u3099き\u3099", "け\u3099")
- input_keys("く\u3099")
- assert_line_around_cursor("か\u3099き\u3099く\u3099", "け\u3099")
- end
-
- def test_move_to_beg_end
- input_keys('bcd')
- assert_line_around_cursor('bcd', '')
- input_keys("\C-a")
- assert_line_around_cursor('', 'bcd')
- input_keys('a')
- assert_line_around_cursor('a', 'bcd')
- input_keys("\C-e")
- assert_line_around_cursor('abcd', '')
- input_keys('e')
- assert_line_around_cursor('abcde', '')
- end
-
- def test_ed_newline_with_cr
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- refute(@line_editor.finished?)
- input_keys("\C-m")
- assert_line_around_cursor('ab', '')
- assert(@line_editor.finished?)
- end
-
- def test_ed_newline_with_lf
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- refute(@line_editor.finished?)
- input_keys("\C-j")
- assert_line_around_cursor('ab', '')
- assert(@line_editor.finished?)
- end
-
- def test_em_delete_prev_char
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- input_keys("\C-h")
- assert_line_around_cursor('a', '')
- end
-
- def test_em_delete_prev_char_for_mbchar
- input_keys('かき')
- assert_line_around_cursor('かき', '')
- input_keys("\C-h")
- assert_line_around_cursor('か', '')
- end
-
- def test_em_delete_prev_char_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099")
- assert_line_around_cursor("か\u3099き\u3099", '')
- input_keys("\C-h")
- assert_line_around_cursor("か\u3099", '')
- end
-
- def test_bracketed_paste_insert
- set_line_around_cursor('A', 'Z')
- input_key_by_symbol(:insert_multiline_text, char: "abc\n\C-abc")
- assert_whole_lines(['Aabc', "\C-abcZ"])
- assert_line_around_cursor("\C-abc", 'Z')
- end
-
- def test_ed_quoted_insert
- set_line_around_cursor('A', 'Z')
- input_key_by_symbol(:insert_raw_char, char: "\C-a")
- assert_line_around_cursor("A\C-a", 'Z')
- end
-
- def test_ed_quoted_insert_with_vi_arg
- input_keys("a\C-[3")
- input_key_by_symbol(:insert_raw_char, char: "\C-a")
- input_keys("b\C-[4")
- input_key_by_symbol(:insert_raw_char, char: '1')
- assert_line_around_cursor("a\C-a\C-a\C-ab1111", '')
- end
-
- def test_ed_kill_line
- input_keys("\C-k")
- assert_line_around_cursor('', '')
- input_keys('abc')
- assert_line_around_cursor('abc', '')
- input_keys("\C-k")
- assert_line_around_cursor('abc', '')
- input_keys("\C-b\C-k")
- assert_line_around_cursor('ab', '')
- end
-
- def test_em_kill_line
- input_key_by_symbol(:em_kill_line)
- assert_line_around_cursor('', '')
- input_keys('abc')
- input_key_by_symbol(:em_kill_line)
- assert_line_around_cursor('', '')
- input_keys('abc')
- input_keys("\C-b")
- input_key_by_symbol(:em_kill_line)
- assert_line_around_cursor('', '')
- input_keys('abc')
- input_keys("\C-a")
- input_key_by_symbol(:em_kill_line)
- assert_line_around_cursor('', '')
- end
-
- def test_ed_move_to_beg
- input_keys('abd')
- assert_line_around_cursor('abd', '')
- input_keys("\C-b")
- assert_line_around_cursor('ab', 'd')
- input_keys('c')
- assert_line_around_cursor('abc', 'd')
- input_keys("\C-a")
- assert_line_around_cursor('', 'abcd')
- input_keys('012')
- assert_line_around_cursor('012', 'abcd')
- input_keys("\C-a")
- assert_line_around_cursor('', '012abcd')
- input_keys('ABC')
- assert_line_around_cursor('ABC', '012abcd')
- input_keys("\C-f" * 10 + "\C-a")
- assert_line_around_cursor('', 'ABC012abcd')
- input_keys('a')
- assert_line_around_cursor('a', 'ABC012abcd')
- end
-
- def test_ed_move_to_beg_with_blank
- input_keys(' abc')
- assert_line_around_cursor(' abc', '')
- input_keys("\C-a")
- assert_line_around_cursor('', ' abc')
- end
-
- def test_ed_move_to_end
- input_keys('abd')
- assert_line_around_cursor('abd', '')
- input_keys("\C-b")
- assert_line_around_cursor('ab', 'd')
- input_keys('c')
- assert_line_around_cursor('abc', 'd')
- input_keys("\C-e")
- assert_line_around_cursor('abcd', '')
- input_keys('012')
- assert_line_around_cursor('abcd012', '')
- input_keys("\C-e")
- assert_line_around_cursor('abcd012', '')
- input_keys('ABC')
- assert_line_around_cursor('abcd012ABC', '')
- input_keys("\C-b" * 10 + "\C-e")
- assert_line_around_cursor('abcd012ABC', '')
- input_keys('a')
- assert_line_around_cursor('abcd012ABCa', '')
- end
-
- def test_em_delete
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- input_keys("\C-a")
- assert_line_around_cursor('', 'ab')
- input_keys("\C-d")
- assert_line_around_cursor('', 'b')
- end
-
- def test_em_delete_for_mbchar
- input_keys('かき')
- assert_line_around_cursor('かき', '')
- input_keys("\C-a")
- assert_line_around_cursor('', 'かき')
- input_keys("\C-d")
- assert_line_around_cursor('', 'き')
- end
-
- def test_em_delete_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099")
- assert_line_around_cursor("か\u3099き\u3099", '')
- input_keys("\C-a")
- assert_line_around_cursor('', "か\u3099き\u3099")
- input_keys("\C-d")
- assert_line_around_cursor('', "き\u3099")
- end
-
- def test_em_delete_ends_editing
- input_keys("\C-d") # quit from inputing
- assert_nil(@line_editor.line)
- assert(@line_editor.finished?)
- end
-
- def test_ed_clear_screen
- @line_editor.instance_variable_get(:@rendered_screen).lines = [[]]
- input_keys("\C-l")
- assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines)
- end
-
- def test_ed_clear_screen_with_inputted
- input_keys('abc')
- input_keys("\C-b")
- @line_editor.instance_variable_get(:@rendered_screen).lines = [[]]
- assert_line_around_cursor('ab', 'c')
- input_keys("\C-l")
- assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines)
- assert_line_around_cursor('ab', 'c')
- end
-
- def test_key_delete
- input_keys('abc')
- assert_line_around_cursor('abc', '')
- input_key_by_symbol(:key_delete)
- assert_line_around_cursor('abc', '')
- end
-
- def test_key_delete_does_not_end_editing
- input_key_by_symbol(:key_delete)
- assert_line_around_cursor('', '')
- refute(@line_editor.finished?)
- end
-
- def test_key_delete_preserves_cursor
- input_keys('abc')
- input_keys("\C-b")
- assert_line_around_cursor('ab', 'c')
- input_key_by_symbol(:key_delete)
- assert_line_around_cursor('ab', '')
- end
-
- def test_em_next_word
- assert_line_around_cursor('', '')
- input_keys('abc def{bbb}ccc')
- input_keys("\C-a\eF")
- assert_line_around_cursor('abc', ' def{bbb}ccc')
- input_keys("\eF")
- assert_line_around_cursor('abc def', '{bbb}ccc')
- input_keys("\eF")
- assert_line_around_cursor('abc def{bbb', '}ccc')
- input_keys("\eF")
- assert_line_around_cursor('abc def{bbb}ccc', '')
- input_keys("\eF")
- assert_line_around_cursor('abc def{bbb}ccc', '')
- end
-
- def test_em_next_word_for_mbchar
- assert_line_around_cursor('', '')
- input_keys('あいう かきく{さしす}たちつ')
- input_keys("\C-a\eF")
- assert_line_around_cursor('あいう', ' かきく{さしす}たちつ')
- input_keys("\eF")
- assert_line_around_cursor('あいう かきく', '{さしす}たちつ')
- input_keys("\eF")
- assert_line_around_cursor('あいう かきく{さしす', '}たちつ')
- input_keys("\eF")
- assert_line_around_cursor('あいう かきく{さしす}たちつ', '')
- input_keys("\eF")
- assert_line_around_cursor('あいう かきく{さしす}たちつ', '')
- end
-
- def test_em_next_word_for_mbchar_by_plural_code_points
- omit_unless_utf8
- assert_line_around_cursor("", "")
- input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\C-a\eF")
- assert_line_around_cursor("あいう", " か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\eF")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099", "{さしす}たちつ")
- input_keys("\eF")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす", "}たちつ")
- input_keys("\eF")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "")
- input_keys("\eF")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "")
- end
-
- def test_em_prev_word
- input_keys('abc def{bbb}ccc')
- assert_line_around_cursor('abc def{bbb}ccc', '')
- input_keys("\eB")
- assert_line_around_cursor('abc def{bbb}', 'ccc')
- input_keys("\eB")
- assert_line_around_cursor('abc def{', 'bbb}ccc')
- input_keys("\eB")
- assert_line_around_cursor('abc ', 'def{bbb}ccc')
- input_keys("\eB")
- assert_line_around_cursor('', 'abc def{bbb}ccc')
- input_keys("\eB")
- assert_line_around_cursor('', 'abc def{bbb}ccc')
- end
-
- def test_em_prev_word_for_mbchar
- input_keys('あいう かきく{さしす}たちつ')
- assert_line_around_cursor('あいう かきく{さしす}たちつ', '')
- input_keys("\eB")
- assert_line_around_cursor('あいう かきく{さしす}', 'たちつ')
- input_keys("\eB")
- assert_line_around_cursor('あいう かきく{', 'さしす}たちつ')
- input_keys("\eB")
- assert_line_around_cursor('あいう ', 'かきく{さしす}たちつ')
- input_keys("\eB")
- assert_line_around_cursor('', 'あいう かきく{さしす}たちつ')
- input_keys("\eB")
- assert_line_around_cursor('', 'あいう かきく{さしす}たちつ')
- end
-
- def test_em_prev_word_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "")
- input_keys("\eB")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", "たちつ")
- input_keys("\eB")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", "さしす}たちつ")
- input_keys("\eB")
- assert_line_around_cursor("あいう ", "か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\eB")
- assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\eB")
- assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- end
-
- def test_em_delete_next_word
- input_keys('abc def{bbb}ccc')
- input_keys("\C-a")
- assert_line_around_cursor('', 'abc def{bbb}ccc')
- input_keys("\ed")
- assert_line_around_cursor('', ' def{bbb}ccc')
- input_keys("\ed")
- assert_line_around_cursor('', '{bbb}ccc')
- input_keys("\ed")
- assert_line_around_cursor('', '}ccc')
- input_keys("\ed")
- assert_line_around_cursor('', '')
- end
-
- def test_em_delete_next_word_for_mbchar
- input_keys('あいう かきく{さしす}たちつ')
- input_keys("\C-a")
- assert_line_around_cursor('', 'あいう かきく{さしす}たちつ')
- input_keys("\ed")
- assert_line_around_cursor('', ' かきく{さしす}たちつ')
- input_keys("\ed")
- assert_line_around_cursor('', '{さしす}たちつ')
- input_keys("\ed")
- assert_line_around_cursor('', '}たちつ')
- input_keys("\ed")
- assert_line_around_cursor('', '')
- end
-
- def test_em_delete_next_word_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\C-a")
- assert_line_around_cursor('', "あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\ed")
- assert_line_around_cursor('', " か\u3099き\u3099く\u3099{さしす}たちつ")
- input_keys("\ed")
- assert_line_around_cursor('', '{さしす}たちつ')
- input_keys("\ed")
- assert_line_around_cursor('', '}たちつ')
- input_keys("\ed")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_delete_prev_word
- input_keys('abc def{bbb}ccc')
- assert_line_around_cursor('abc def{bbb}ccc', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('abc def{bbb}', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('abc def{', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('abc ', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_delete_prev_word_for_mbchar
- input_keys('あいう かきく{さしす}たちつ')
- assert_line_around_cursor('あいう かきく{さしす}たちつ', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('あいう かきく{さしす}', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('あいう かきく{', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('あいう ', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_delete_prev_word_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '')
- input_keys("\e\C-H")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '')
- input_keys("\e\C-H")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '')
- input_keys("\e\C-H")
- assert_line_around_cursor('あいう ', '')
- input_keys("\e\C-H")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_transpose_chars
- input_keys('abc')
- input_keys("\C-a")
- assert_line_around_cursor('', 'abc')
- input_keys("\C-t")
- assert_line_around_cursor('', 'abc')
- input_keys("\C-f\C-t")
- assert_line_around_cursor('ba', 'c')
- input_keys("\C-t")
- assert_line_around_cursor('bca', '')
- input_keys("\C-t")
- assert_line_around_cursor('bac', '')
- end
-
- def test_ed_transpose_chars_for_mbchar
- input_keys('あかさ')
- input_keys("\C-a")
- assert_line_around_cursor('', 'あかさ')
- input_keys("\C-t")
- assert_line_around_cursor('', 'あかさ')
- input_keys("\C-f\C-t")
- assert_line_around_cursor('かあ', 'さ')
- input_keys("\C-t")
- assert_line_around_cursor('かさあ', '')
- input_keys("\C-t")
- assert_line_around_cursor('かあさ', '')
- end
-
- def test_ed_transpose_chars_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("あか\u3099さ")
- input_keys("\C-a")
- assert_line_around_cursor('', "あか\u3099さ")
- input_keys("\C-t")
- assert_line_around_cursor('', "あか\u3099さ")
- input_keys("\C-f\C-t")
- assert_line_around_cursor("か\u3099あ", 'さ')
- input_keys("\C-t")
- assert_line_around_cursor("か\u3099さあ", '')
- input_keys("\C-t")
- assert_line_around_cursor("か\u3099あさ", '')
- end
-
- def test_ed_transpose_words
- input_keys('abc def')
- assert_line_around_cursor('abc def', '')
- input_keys("\et")
- assert_line_around_cursor('def abc', '')
- input_keys("\C-a\C-k")
- input_keys(' abc def ')
- input_keys("\C-b" * 4)
- assert_line_around_cursor(' abc de', 'f ')
- input_keys("\et")
- assert_line_around_cursor(' def abc', ' ')
- input_keys("\C-a\C-k")
- input_keys(' abc def ')
- input_keys("\C-b" * 6)
- assert_line_around_cursor(' abc ', 'def ')
- input_keys("\et")
- assert_line_around_cursor(' def abc', ' ')
- input_keys("\et")
- assert_line_around_cursor(' abc def', '')
- end
-
- def test_ed_transpose_words_for_mbchar
- input_keys('あいう かきく')
- assert_line_around_cursor('あいう かきく', '')
- input_keys("\et")
- assert_line_around_cursor('かきく あいう', '')
- input_keys("\C-a\C-k")
- input_keys(' あいう かきく ')
- input_keys("\C-b" * 4)
- assert_line_around_cursor(' あいう かき', 'く ')
- input_keys("\et")
- assert_line_around_cursor(' かきく あいう', ' ')
- input_keys("\C-a\C-k")
- input_keys(' あいう かきく ')
- input_keys("\C-b" * 6)
- assert_line_around_cursor(' あいう ', 'かきく ')
- input_keys("\et")
- assert_line_around_cursor(' かきく あいう', ' ')
- input_keys("\et")
- assert_line_around_cursor(' あいう かきく', '')
- end
-
- def test_ed_transpose_words_with_one_word
- input_keys('abc ')
- assert_line_around_cursor('abc ', '')
- input_keys("\et")
- assert_line_around_cursor('abc ', '')
- input_keys("\C-b")
- assert_line_around_cursor('abc ', ' ')
- input_keys("\et")
- assert_line_around_cursor('abc ', ' ')
- input_keys("\C-b" * 2)
- assert_line_around_cursor('ab', 'c ')
- input_keys("\et")
- assert_line_around_cursor('ab', 'c ')
- input_keys("\et")
- assert_line_around_cursor('ab', 'c ')
- end
-
- def test_ed_transpose_words_with_one_word_for_mbchar
- input_keys('あいう ')
- assert_line_around_cursor('あいう ', '')
- input_keys("\et")
- assert_line_around_cursor('あいう ', '')
- input_keys("\C-b")
- assert_line_around_cursor('あいう ', ' ')
- input_keys("\et")
- assert_line_around_cursor('あいう ', ' ')
- input_keys("\C-b" * 2)
- assert_line_around_cursor('あい', 'う ')
- input_keys("\et")
- assert_line_around_cursor('あい', 'う ')
- input_keys("\et")
- assert_line_around_cursor('あい', 'う ')
- end
-
- def test_ed_digit
- input_keys('0123')
- assert_line_around_cursor('0123', '')
- end
-
- def test_ed_next_and_prev_char
- input_keys('abc')
- assert_line_around_cursor('abc', '')
- input_keys("\C-b")
- assert_line_around_cursor('ab', 'c')
- input_keys("\C-b")
- assert_line_around_cursor('a', 'bc')
- input_keys("\C-b")
- assert_line_around_cursor('', 'abc')
- input_keys("\C-b")
- assert_line_around_cursor('', 'abc')
- input_keys("\C-f")
- assert_line_around_cursor('a', 'bc')
- input_keys("\C-f")
- assert_line_around_cursor('ab', 'c')
- input_keys("\C-f")
- assert_line_around_cursor('abc', '')
- input_keys("\C-f")
- assert_line_around_cursor('abc', '')
- end
-
- def test_ed_next_and_prev_char_for_mbchar
- input_keys('あいう')
- assert_line_around_cursor('あいう', '')
- input_keys("\C-b")
- assert_line_around_cursor('あい', 'う')
- input_keys("\C-b")
- assert_line_around_cursor('あ', 'いう')
- input_keys("\C-b")
- assert_line_around_cursor('', 'あいう')
- input_keys("\C-b")
- assert_line_around_cursor('', 'あいう')
- input_keys("\C-f")
- assert_line_around_cursor('あ', 'いう')
- input_keys("\C-f")
- assert_line_around_cursor('あい', 'う')
- input_keys("\C-f")
- assert_line_around_cursor('あいう', '')
- input_keys("\C-f")
- assert_line_around_cursor('あいう', '')
- end
-
- def test_ed_next_and_prev_char_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099く\u3099")
- assert_line_around_cursor("か\u3099き\u3099く\u3099", '')
- input_keys("\C-b")
- assert_line_around_cursor("か\u3099き\u3099", "く\u3099")
- input_keys("\C-b")
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099")
- input_keys("\C-b")
- assert_line_around_cursor('', "か\u3099き\u3099く\u3099")
- input_keys("\C-b")
- assert_line_around_cursor('', "か\u3099き\u3099く\u3099")
- input_keys("\C-f")
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099")
- input_keys("\C-f")
- assert_line_around_cursor("か\u3099き\u3099", "く\u3099")
- input_keys("\C-f")
- assert_line_around_cursor("か\u3099き\u3099く\u3099", '')
- input_keys("\C-f")
- assert_line_around_cursor("か\u3099き\u3099く\u3099", '')
- end
-
- def test_em_capitol_case
- input_keys('abc def{bbb}ccc')
- input_keys("\C-a\ec")
- assert_line_around_cursor('Abc', ' def{bbb}ccc')
- input_keys("\ec")
- assert_line_around_cursor('Abc Def', '{bbb}ccc')
- input_keys("\ec")
- assert_line_around_cursor('Abc Def{Bbb', '}ccc')
- input_keys("\ec")
- assert_line_around_cursor('Abc Def{Bbb}Ccc', '')
- end
-
- def test_em_capitol_case_with_complex_example
- input_keys('{}#* AaA!!!cCc ')
- input_keys("\C-a\ec")
- assert_line_around_cursor('{}#* Aaa', '!!!cCc ')
- input_keys("\ec")
- assert_line_around_cursor('{}#* Aaa!!!Ccc', ' ')
- input_keys("\ec")
- assert_line_around_cursor('{}#* Aaa!!!Ccc ', '')
- end
-
- def test_em_lower_case
- input_keys('AbC def{bBb}CCC')
- input_keys("\C-a\el")
- assert_line_around_cursor('abc', ' def{bBb}CCC')
- input_keys("\el")
- assert_line_around_cursor('abc def', '{bBb}CCC')
- input_keys("\el")
- assert_line_around_cursor('abc def{bbb', '}CCC')
- input_keys("\el")
- assert_line_around_cursor('abc def{bbb}ccc', '')
- end
-
- def test_em_lower_case_with_complex_example
- input_keys('{}#* AaA!!!cCc ')
- input_keys("\C-a\el")
- assert_line_around_cursor('{}#* aaa', '!!!cCc ')
- input_keys("\el")
- assert_line_around_cursor('{}#* aaa!!!ccc', ' ')
- input_keys("\el")
- assert_line_around_cursor('{}#* aaa!!!ccc ', '')
- end
-
- def test_em_upper_case
- input_keys('AbC def{bBb}CCC')
- input_keys("\C-a\eu")
- assert_line_around_cursor('ABC', ' def{bBb}CCC')
- input_keys("\eu")
- assert_line_around_cursor('ABC DEF', '{bBb}CCC')
- input_keys("\eu")
- assert_line_around_cursor('ABC DEF{BBB', '}CCC')
- input_keys("\eu")
- assert_line_around_cursor('ABC DEF{BBB}CCC', '')
- end
-
- def test_em_upper_case_with_complex_example
- input_keys('{}#* AaA!!!cCc ')
- input_keys("\C-a\eu")
- assert_line_around_cursor('{}#* AAA', '!!!cCc ')
- input_keys("\eu")
- assert_line_around_cursor('{}#* AAA!!!CCC', ' ')
- input_keys("\eu")
- assert_line_around_cursor('{}#* AAA!!!CCC ', '')
- end
-
- def test_em_delete_or_list
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_foo
- foo_bar
- foo_baz
- qux
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('fooo')
- assert_line_around_cursor('fooo', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-b")
- assert_line_around_cursor('foo', 'o')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_key_by_symbol(:em_delete_or_list)
- assert_line_around_cursor('foo', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_key_by_symbol(:em_delete_or_list)
- assert_line_around_cursor('foo', '')
- assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
- end
-
- def test_completion_duplicated_list
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_foo
- foo_foo
- foo_bar
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('foo_')
- assert_line_around_cursor('foo_', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list)
- end
-
- def test_completion
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_foo
- foo_bar
- foo_baz
- qux
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('fo')
- assert_line_around_cursor('fo', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
- input_keys('a')
- input_keys("\C-i")
- assert_line_around_cursor('foo_a', '')
- input_keys("\C-h")
- input_keys('b')
- input_keys("\C-i")
- assert_line_around_cursor('foo_ba', '')
- input_keys("\C-h")
- input_key_by_symbol(:complete)
- assert_line_around_cursor('foo_ba', '')
- input_keys("\C-h")
- input_key_by_symbol(:menu_complete)
- assert_line_around_cursor('foo_bar', '')
- input_key_by_symbol(:menu_complete)
- assert_line_around_cursor('foo_baz', '')
- input_keys("\C-h")
- input_key_by_symbol(:menu_complete_backward)
- assert_line_around_cursor('foo_baz', '')
- input_key_by_symbol(:menu_complete_backward)
- assert_line_around_cursor('foo_bar', '')
- end
-
- def test_autocompletion
- @config.autocompletion = true
- @line_editor.completion_proc = proc { |word|
- %w{
- Readline
- Regexp
- RegexpError
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('Re')
- assert_line_around_cursor('Re', '')
- input_keys("\C-i")
- assert_line_around_cursor('Readline', '')
- input_keys("\C-i")
- assert_line_around_cursor('Regexp', '')
- input_key_by_symbol(:completion_journey_up)
- assert_line_around_cursor('Readline', '')
- input_key_by_symbol(:complete)
- assert_line_around_cursor('Regexp', '')
- input_key_by_symbol(:menu_complete_backward)
- assert_line_around_cursor('Readline', '')
- input_key_by_symbol(:menu_complete)
- assert_line_around_cursor('Regexp', '')
- ensure
- @config.autocompletion = false
- 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_line_around_cursor(' fo', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor(' foo_', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor(' foo_', '')
- assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
- end
-
- def test_completion_with_perfect_match
- @line_editor.completion_proc = proc { |word|
- %w{
- foo
- foo_bar
- }.map { |i|
- i.encode(@encoding)
- }
- }
- matched = nil
- @line_editor.dig_perfect_match_proc = proc { |m|
- matched = m
- }
- input_keys('fo')
- assert_line_around_cursor('fo', '')
- assert_equal(Reline::LineEditor::CompletionState::NORMAL, @line_editor.instance_variable_get(:@completion_state))
- assert_equal(nil, matched)
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- assert_equal(Reline::LineEditor::CompletionState::MENU_WITH_PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state))
- assert_equal(nil, matched)
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state))
- assert_equal(nil, matched)
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state))
- assert_equal('foo', matched)
- matched = nil
- input_keys('_')
- input_keys("\C-i")
- assert_line_around_cursor('foo_bar', '')
- assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state))
- assert_equal(nil, matched)
- input_keys("\C-i")
- assert_line_around_cursor('foo_bar', '')
- assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state))
- assert_equal('foo_bar', matched)
- end
-
- def test_continuous_completion_with_perfect_match
- @line_editor.completion_proc = proc { |word|
- word == 'f' ? ['foo'] : %w[foobar foobaz]
- }
- input_keys('f')
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- input_keys("\C-i")
- assert_line_around_cursor('fooba', '')
- end
-
- def test_continuous_completion_disabled_with_perfect_match
- @line_editor.completion_proc = proc { |word|
- word == 'f' ? ['foo'] : %w[foobar foobaz]
- }
- @line_editor.dig_perfect_match_proc = proc {}
- input_keys('f')
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- end
-
- def test_completion_append_character
- @line_editor.completion_proc = proc { |word|
- %w[foo_ foo_foo foo_bar].select { |s| s.start_with? word }
- }
- @line_editor.completion_append_character = 'X'
- input_keys('f')
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- input_keys('f')
- input_keys("\C-i")
- assert_line_around_cursor('foo_fooX', '')
- input_keys(' foo_bar')
- input_keys("\C-i")
- assert_line_around_cursor('foo_fooX foo_barX', '')
- end
-
- def test_completion_with_quote_append
- @line_editor.completion_proc = proc { |word|
- %w[foo bar baz].select { |s| s.start_with? word }
- }
- set_line_around_cursor('x = "b', '')
- input_keys("\C-i")
- assert_line_around_cursor('x = "ba', '')
- set_line_around_cursor('x = "f', ' ')
- input_keys("\C-i")
- assert_line_around_cursor('x = "foo', ' ')
- set_line_around_cursor("x = 'f", '')
- input_keys("\C-i")
- assert_line_around_cursor("x = 'foo'", '')
- set_line_around_cursor('"a "f', '')
- input_keys("\C-i")
- assert_line_around_cursor('"a "foo', '')
- set_line_around_cursor('"a\\" "f', '')
- input_keys("\C-i")
- assert_line_around_cursor('"a\\" "foo', '')
- set_line_around_cursor('"a" "f', '')
- input_keys("\C-i")
- assert_line_around_cursor('"a" "foo"', '')
- end
-
- def test_completion_with_completion_ignore_case
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_foo
- foo_bar
- Foo_baz
- qux
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('fo')
- assert_line_around_cursor('fo', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list)
- @config.completion_ignore_case = true
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
- input_keys('a')
- input_keys("\C-i")
- assert_line_around_cursor('foo_a', '')
- input_keys("\C-h")
- input_keys('b')
- input_keys("\C-i")
- assert_line_around_cursor('foo_ba', '')
- input_keys('Z')
- input_keys("\C-i")
- assert_line_around_cursor('Foo_baz', '')
- end
-
- def test_completion_in_middle_of_line
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_foo
- foo_bar
- foo_baz
- qux
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('abcde fo ABCDE')
- assert_line_around_cursor('abcde fo ABCDE', '')
- input_keys("\C-b" * 6 + "\C-i")
- assert_line_around_cursor('abcde foo_', ' ABCDE')
- input_keys("\C-b" * 2 + "\C-i")
- assert_line_around_cursor('abcde foo_', 'o_ ABCDE')
- end
-
- def test_completion_with_nil_value
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_foo
- foo_bar
- Foo_baz
- qux
- }.map { |i|
- i.encode(@encoding)
- }.prepend(nil)
- }
- @config.completion_ignore_case = true
- input_keys('fo')
- assert_line_around_cursor('fo', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(nil, @line_editor.instance_variable_get(:@menu_info))
- input_keys("\C-i")
- assert_line_around_cursor('foo_', '')
- assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list)
- input_keys('a')
- input_keys("\C-i")
- assert_line_around_cursor('foo_a', '')
- input_keys("\C-h")
- input_keys('b')
- input_keys("\C-i")
- assert_line_around_cursor('foo_ba', '')
- end
-
- def test_em_kill_region
- input_keys('abc def{bbb}ccc ddd ')
- assert_line_around_cursor('abc def{bbb}ccc ddd ', '')
- input_keys("\C-w")
- assert_line_around_cursor('abc def{bbb}ccc ', '')
- input_keys("\C-w")
- assert_line_around_cursor('abc ', '')
- input_keys("\C-w")
- assert_line_around_cursor('', '')
- input_keys("\C-w")
- assert_line_around_cursor('', '')
- end
-
- def test_em_kill_region_mbchar
- input_keys('あ い う{う}う ')
- assert_line_around_cursor('あ い う{う}う ', '')
- input_keys("\C-w")
- assert_line_around_cursor('あ い ', '')
- input_keys("\C-w")
- assert_line_around_cursor('あ ', '')
- input_keys("\C-w")
- assert_line_around_cursor('', '')
- end
-
- def test_vi_search_prev
- Reline::HISTORY.concat(%w{abc 123 AAA})
- assert_line_around_cursor('', '')
- input_keys("\C-ra\C-j")
- assert_line_around_cursor('', 'abc')
- end
-
- def test_larger_histories_than_history_size
- history_size = @config.history_size
- @config.history_size = 2
- Reline::HISTORY.concat(%w{abc 123 AAA})
- assert_line_around_cursor('', '')
- input_keys("\C-p")
- assert_line_around_cursor('AAA', '')
- input_keys("\C-p")
- assert_line_around_cursor('123', '')
- input_keys("\C-p")
- assert_line_around_cursor('123', '')
- ensure
- @config.history_size = history_size
- end
-
- def test_search_history_to_back
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-r123")
- assert_line_around_cursor('1234', '')
- input_keys("\C-ha")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-h3")
- assert_line_around_cursor('1235', '')
- end
-
- def test_search_history_to_front
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-s123")
- assert_line_around_cursor('1235', '')
- input_keys("\C-ha")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-h3")
- assert_line_around_cursor('1234', '')
- end
-
- def test_search_history_front_and_back
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-s12")
- assert_line_around_cursor('1235', '')
- input_keys("\C-s")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-r")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-r")
- assert_line_around_cursor('1235', '')
- end
-
- def test_search_history_back_and_front
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-r12")
- assert_line_around_cursor('1234', '')
- input_keys("\C-r")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-s")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-s")
- assert_line_around_cursor('1234', '')
- end
-
- def test_search_history_to_back_in_the_middle_of_histories
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-p\C-p")
- assert_line_around_cursor('12aa', '')
- input_keys("\C-r123")
- assert_line_around_cursor('1235', '')
- end
-
- def test_search_history_twice
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-r123")
- assert_line_around_cursor('1234', '')
- input_keys("\C-r")
- assert_line_around_cursor('1235', '')
- end
-
- def test_search_history_by_last_determined
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-r123")
- assert_line_around_cursor('1234', '')
- input_keys("\C-j")
- assert_line_around_cursor('', '1234')
- input_keys("\C-k") # delete
- assert_line_around_cursor('', '')
- input_keys("\C-r")
- assert_line_around_cursor('', '')
- input_keys("\C-r")
- assert_line_around_cursor('1235', '')
- end
-
- def test_search_history_with_isearch_terminator
- @config.read_lines(<<~LINES.split(/(?<=\n)/))
- set isearch-terminators "XYZ"
- LINES
- Reline::HISTORY.concat([
- '1235', # old
- '12aa',
- '1234' # new
- ])
- assert_line_around_cursor('', '')
- input_keys("\C-r12a")
- assert_line_around_cursor('12aa', '')
- input_keys('Y')
- assert_line_around_cursor('', '12aa')
- input_keys('x')
- assert_line_around_cursor('x', '12aa')
- end
-
- def test_em_set_mark_and_em_exchange_mark
- input_keys('aaa bbb ccc ddd')
- assert_line_around_cursor('aaa bbb ccc ddd', '')
- input_keys("\C-a\eF\eF")
- assert_line_around_cursor('aaa bbb', ' ccc ddd')
- assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer))
- input_keys("\x00") # C-Space
- assert_line_around_cursor('aaa bbb', ' ccc ddd')
- assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer))
- input_keys("\C-a")
- assert_line_around_cursor('', 'aaa bbb ccc ddd')
- assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer))
- input_key_by_symbol(:em_exchange_mark)
- assert_line_around_cursor('aaa bbb', ' ccc ddd')
- assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer))
- end
-
- def test_em_exchange_mark_without_mark
- input_keys('aaa bbb ccc ddd')
- assert_line_around_cursor('aaa bbb ccc ddd', '')
- input_keys("\C-a\ef")
- assert_line_around_cursor('aaa', ' bbb ccc ddd')
- assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer))
- input_key_by_symbol(:em_exchange_mark)
- assert_line_around_cursor('aaa', ' bbb ccc ddd')
- assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer))
- end
-
- def test_modify_lines_with_wrong_rs
- verbose, $VERBOSE = $VERBOSE, nil
- original_global_slash = $/
- $/ = 'b'
- $VERBOSE = verbose
- @line_editor.output_modifier_proc = proc { |output| Reline::Unicode.escape_for_print(output) }
- input_keys("abcdef\n")
- result = @line_editor.__send__(:modify_lines, @line_editor.whole_lines, @line_editor.finished?)
- $/ = nil
- assert_equal(['abcdef'], result)
- ensure
- $VERBOSE = nil
- $/ = original_global_slash
- $VERBOSE = verbose
- end
-
- def test_ed_search_prev_history
- Reline::HISTORY.concat([
- '12356', # old
- '12aaa',
- '12345' # new
- ])
- input_keys('123')
- # The ed_search_prev_history doesn't have default binding
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('123', '45')
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('123', '56')
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('123', '56')
- end
-
- def test_ed_search_prev_history_with_empty
- Reline::HISTORY.concat([
- '12356', # old
- '12aaa',
- '12345' # new
- ])
- # The ed_search_prev_history doesn't have default binding
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12345', '')
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12aaa', '')
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12356', '')
- input_key_by_symbol(:ed_search_next_history)
- assert_line_around_cursor('12aaa', '')
- input_key_by_symbol(:ed_prev_char)
- input_key_by_symbol(:ed_next_char)
- assert_line_around_cursor('12aaa', '')
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12aaa', '')
- 3.times { input_key_by_symbol(:ed_prev_char) }
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12', '356')
- end
-
- def test_ed_search_prev_history_without_match
- Reline::HISTORY.concat([
- '12356', # old
- '12aaa',
- '12345' # new
- ])
- input_keys('ABC')
- # The ed_search_prev_history doesn't have default binding
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('ABC', '')
- end
-
- def test_ed_search_next_history
- Reline::HISTORY.concat([
- '12356', # old
- '12aaa',
- '12345' # new
- ])
- input_keys('123')
- # The ed_search_prev_history and ed_search_next_history doesn't have default binding
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('123', '45')
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('123', '56')
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_around_cursor('123', '56')
- @line_editor.__send__(:ed_search_next_history, "\C-n".ord)
- assert_line_around_cursor('123', '45')
- @line_editor.__send__(:ed_search_next_history, "\C-n".ord)
- assert_line_around_cursor('123', '45')
- end
-
- def test_ed_search_next_history_with_empty
- Reline::HISTORY.concat([
- '12356', # old
- '12aaa',
- '12345' # new
- ])
- # The ed_search_prev_history and ed_search_next_history doesn't have default binding
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12345', '')
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12aaa', '')
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12356', '')
- input_key_by_symbol(:ed_search_next_history)
- assert_line_around_cursor('12aaa', '')
- input_key_by_symbol(:ed_search_next_history)
- assert_line_around_cursor('12345', '')
- input_key_by_symbol(:ed_search_prev_history)
- assert_line_around_cursor('12aaa', '')
- input_key_by_symbol(:ed_prev_char)
- input_key_by_symbol(:ed_next_char)
- input_key_by_symbol(:ed_search_next_history)
- assert_line_around_cursor('12aaa', '')
- 3.times { input_key_by_symbol(:ed_prev_char) }
- input_key_by_symbol(:ed_search_next_history)
- assert_line_around_cursor('12', '345')
- end
-
- def test_incremental_search_history_cancel_by_symbol_key
- # ed_prev_char should move cursor left and cancel incremental search
- input_keys("abc\C-r")
- input_key_by_symbol(:ed_prev_char, csi: true)
- input_keys('d')
- assert_line_around_cursor('abd', 'c')
- end
-
- def test_incremental_search_history_saves_and_restores_last_input
- Reline::HISTORY.concat(['abc', '123'])
- input_keys("abcd")
- # \C-j: terminate incremental search
- input_keys("\C-r12\C-j")
- assert_line_around_cursor('', '123')
- input_key_by_symbol(:ed_next_history)
- assert_line_around_cursor('abcd', '')
- # Most non-printable keys also terminates incremental search
- input_keys("\C-r12\C-i")
- assert_line_around_cursor('', '123')
- input_key_by_symbol(:ed_next_history)
- assert_line_around_cursor('abcd', '')
- # \C-g: cancel incremental search and restore input, cursor position and history index
- input_key_by_symbol(:ed_prev_history)
- input_keys("\C-b\C-b")
- assert_line_around_cursor('1', '23')
- input_keys("\C-rab\C-g")
- assert_line_around_cursor('1', '23')
- input_key_by_symbol(:ed_next_history)
- assert_line_around_cursor('abcd', '')
- end
-
- # Unicode emoji test
- def test_ed_insert_for_include_zwj_emoji
- omit_unless_utf8
- # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨‍👩‍👧‍👦"
- input_keys("\u{1F468}") # U+1F468 is man "👨"
- assert_line_around_cursor('👨', '')
- input_keys("\u200D") # U+200D is ZERO WIDTH JOINER
- assert_line_around_cursor('👨‍', '')
- input_keys("\u{1F469}") # U+1F469 is woman "👩"
- assert_line_around_cursor('👨‍👩', '')
- input_keys("\u200D") # U+200D is ZERO WIDTH JOINER
- assert_line_around_cursor('👨‍👩‍', '')
- input_keys("\u{1F467}") # U+1F467 is girl "👧"
- assert_line_around_cursor('👨‍👩‍👧', '')
- input_keys("\u200D") # U+200D is ZERO WIDTH JOINER
- assert_line_around_cursor('👨‍👩‍👧‍', '')
- input_keys("\u{1F466}") # U+1F466 is boy "👦"
- assert_line_around_cursor('👨‍👩‍👧‍👦', '')
- # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨‍👩‍👧‍👦"
- input_keys("\u{1F468 200D 1F469 200D 1F467 200D 1F466}")
- assert_line_around_cursor('👨‍👩‍👧‍👦👨‍👩‍👧‍👦', '')
- end
-
- def test_ed_insert_for_include_valiation_selector
- omit_unless_utf8
- # U+0030 U+FE00 is DIGIT ZERO + VARIATION SELECTOR-1 "0︀"
- input_keys("\u0030") # U+0030 is DIGIT ZERO
- assert_line_around_cursor('0', '')
- input_keys("\uFE00") # U+FE00 is VARIATION SELECTOR-1
- assert_line_around_cursor('0︀', '')
- end
-
- def test_em_yank_pop
- input_keys("def hoge\C-w\C-b\C-f\C-w")
- assert_line_around_cursor('', '')
- input_keys("\C-y")
- assert_line_around_cursor('def ', '')
- input_keys("\e\C-y")
- assert_line_around_cursor('hoge', '')
- end
-
- def test_em_kill_region_with_kill_ring
- input_keys("def hoge\C-b\C-b\C-b\C-b")
- assert_line_around_cursor('def ', 'hoge')
- input_keys("\C-k\C-w")
- assert_line_around_cursor('', '')
- input_keys("\C-y")
- assert_line_around_cursor('def hoge', '')
- end
-
- def test_ed_search_prev_next_history_in_multibyte
- Reline::HISTORY.concat([
- "def hoge\n 67890\n 12345\nend", # old
- "def aiu\n 0xDEADBEEF\nend",
- "def foo\n 12345\nend" # new
- ])
- @line_editor.multiline_on
- input_keys(' 123')
- # The ed_search_prev_history doesn't have default binding
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_whole_lines(['def foo', ' 12345', 'end'])
- assert_line_index(1)
- assert_whole_lines(['def foo', ' 12345', 'end'])
- assert_line_around_cursor(' 123', '45')
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_index(2)
- assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end'])
- assert_line_around_cursor(' 123', '45')
- @line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
- assert_line_index(2)
- assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end'])
- assert_line_around_cursor(' 123', '45')
- @line_editor.__send__(:ed_search_next_history, "\C-n".ord)
- assert_line_index(1)
- assert_whole_lines(['def foo', ' 12345', 'end'])
- assert_line_around_cursor(' 123', '45')
- @line_editor.__send__(:ed_search_next_history, "\C-n".ord)
- assert_line_index(1)
- assert_whole_lines(['def foo', ' 12345', 'end'])
- assert_line_around_cursor(' 123', '45')
- end
-
- def test_ignore_NUL_by_ed_quoted_insert
- input_keys('"')
- input_key_by_symbol(:insert_raw_char, char: 0.chr)
- input_keys('"')
- assert_line_around_cursor('""', '')
- end
-
- def test_ed_argument_digit_by_meta_num
- input_keys('abcdef')
- assert_line_around_cursor('abcdef', '')
- input_keys("\e2")
- input_keys("\C-h")
- assert_line_around_cursor('abcd', '')
- end
-
- def test_ed_digit_with_ed_argument_digit
- input_keys('1' * 30)
- assert_line_around_cursor('1' * 30, '')
- input_keys("\e2")
- input_keys('3')
- input_keys("\C-h")
- input_keys('4')
- assert_line_around_cursor('1' * 7 + '4', '')
- end
-
- def test_halfwidth_kana_width_dakuten
- omit_unless_utf8
- input_keys('ガギゲゴ')
- assert_line_around_cursor('ガギゲゴ', '')
- input_keys("\C-b\C-b")
- assert_line_around_cursor('ガギ', 'ゲゴ')
- input_keys('グ')
- assert_line_around_cursor('ガギグ', 'ゲゴ')
- end
-
- def test_input_unknown_char
- omit_unless_utf8
- input_keys('͸') # U+0378 (unassigned)
- assert_line_around_cursor('͸', '')
- end
-
- def test_unix_line_discard
- input_keys("\C-u")
- assert_line_around_cursor('', '')
- input_keys('abc')
- assert_line_around_cursor('abc', '')
- input_keys("\C-b\C-u")
- assert_line_around_cursor('', 'c')
- input_keys("\C-f\C-u")
- assert_line_around_cursor('', '')
- end
-
- def test_vi_editing_mode
- @line_editor.__send__(:vi_editing_mode, nil)
- assert(@config.editing_mode_is?(:vi_insert))
- end
-
- def test_undo
- input_keys("\C-_")
- assert_line_around_cursor('', '')
- input_keys("aあb\C-h\C-h\C-h")
- assert_line_around_cursor('', '')
- input_keys("\C-_")
- assert_line_around_cursor('a', '')
- input_keys("\C-_")
- assert_line_around_cursor('aあ', '')
- input_keys("\C-_")
- assert_line_around_cursor('aあb', '')
- input_keys("\C-_")
- assert_line_around_cursor('aあ', '')
- input_keys("\C-_")
- assert_line_around_cursor('a', '')
- input_keys("\C-_")
- assert_line_around_cursor('', '')
- end
-
- def test_undo_with_cursor_position
- input_keys("abc\C-b\C-h")
- assert_line_around_cursor('a', 'c')
- input_keys("\C-_")
- assert_line_around_cursor('ab', 'c')
- input_keys("あいう\C-b\C-h")
- assert_line_around_cursor('abあ', 'うc')
- input_keys("\C-_")
- assert_line_around_cursor('abあい', 'うc')
- end
-
- def test_undo_with_multiline
- @line_editor.multiline_on
- @line_editor.confirm_multiline_termination_proc = proc {}
- input_keys("1\n2\n3")
- assert_whole_lines(["1", "2", "3"])
- assert_line_index(2)
- assert_line_around_cursor('3', '')
- input_keys("\C-p\C-h\C-h")
- assert_whole_lines(["1", "3"])
- assert_line_index(0)
- assert_line_around_cursor('1', '')
- input_keys("\C-_")
- assert_whole_lines(["1", "", "3"])
- assert_line_index(1)
- assert_line_around_cursor('', '')
- input_keys("\C-_")
- assert_whole_lines(["1", "2", "3"])
- assert_line_index(1)
- assert_line_around_cursor('2', '')
- input_keys("\C-_")
- assert_whole_lines(["1", "2", ""])
- assert_line_index(2)
- assert_line_around_cursor('', '')
- input_keys("\C-_")
- assert_whole_lines(["1", "2"])
- assert_line_index(1)
- assert_line_around_cursor('2', '')
- end
-
- def test_undo_with_many_times
- str = "a" + "b" * 99
- input_keys(str)
- 100.times { input_keys("\C-_") }
- assert_line_around_cursor('a', '')
- input_keys("\C-_")
- assert_line_around_cursor('a', '')
- end
-
- def test_redo
- input_keys("aあb")
- assert_line_around_cursor('aあb', '')
- input_keys("\e\C-_")
- assert_line_around_cursor('aあb', '')
- input_keys("\C-_")
- assert_line_around_cursor('aあ', '')
- input_keys("\C-_")
- assert_line_around_cursor('a', '')
- input_keys("\e\C-_")
- assert_line_around_cursor('aあ', '')
- input_keys("\e\C-_")
- assert_line_around_cursor('aあb', '')
- input_keys("\C-_")
- assert_line_around_cursor('aあ', '')
- input_keys("c")
- assert_line_around_cursor('aあc', '')
- input_keys("\e\C-_")
- assert_line_around_cursor('aあc', '')
- end
-
- def test_redo_with_cursor_position
- input_keys("abc\C-b\C-h")
- assert_line_around_cursor('a', 'c')
- input_keys("\e\C-_")
- assert_line_around_cursor('a', 'c')
- input_keys("\C-_")
- assert_line_around_cursor('ab', 'c')
- input_keys("\e\C-_")
- assert_line_around_cursor('a', 'c')
- end
-
- def test_redo_with_multiline
- @line_editor.multiline_on
- @line_editor.confirm_multiline_termination_proc = proc {}
- input_keys("1\n2\n3")
- assert_whole_lines(["1", "2", "3"])
- assert_line_index(2)
- assert_line_around_cursor('3', '')
-
- input_keys("\C-_")
- assert_whole_lines(["1", "2", ""])
- assert_line_index(2)
- assert_line_around_cursor('', '')
-
- input_keys("\C-_")
- assert_whole_lines(["1", "2"])
- assert_line_index(1)
- assert_line_around_cursor('2', '')
-
- input_keys("\e\C-_")
- assert_whole_lines(["1", "2", ""])
- assert_line_index(2)
- assert_line_around_cursor('', '')
-
- input_keys("\e\C-_")
- assert_whole_lines(["1", "2", "3"])
- assert_line_index(2)
- assert_line_around_cursor('3', '')
-
- input_keys("\C-p\C-h\C-h")
- assert_whole_lines(["1", "3"])
- assert_line_index(0)
- assert_line_around_cursor('1', '')
-
- input_keys("\C-n")
- assert_whole_lines(["1", "3"])
- assert_line_index(1)
- assert_line_around_cursor('3', '')
-
- input_keys("\C-_")
- assert_whole_lines(["1", "", "3"])
- assert_line_index(1)
- assert_line_around_cursor('', '')
-
- input_keys("\C-_")
- assert_whole_lines(["1", "2", "3"])
- assert_line_index(1)
- assert_line_around_cursor('2', '')
-
- input_keys("\e\C-_")
- assert_whole_lines(["1", "", "3"])
- assert_line_index(1)
- assert_line_around_cursor('', '')
-
- input_keys("\e\C-_")
- assert_whole_lines(["1", "3"])
- assert_line_index(1)
- assert_line_around_cursor('3', '')
- end
-
- def test_undo_redo_restores_indentation
- @line_editor.multiline_on
- @line_editor.confirm_multiline_termination_proc = proc {}
- input_keys(" 1")
- assert_whole_lines([' 1'])
- input_keys("2")
- assert_whole_lines([' 12'])
- @line_editor.auto_indent_proc = proc { 2 }
- input_keys("\C-_")
- assert_whole_lines([' 1'])
- input_keys("\e\C-_")
- assert_whole_lines([' 12'])
- end
-
- def test_redo_with_many_times
- str = "a" + "b" * 98 + "c"
- input_keys(str)
- 100.times { input_keys("\C-_") }
- assert_line_around_cursor('a', '')
- input_keys("\C-_")
- assert_line_around_cursor('a', '')
- 100.times { input_keys("\e\C-_") }
- assert_line_around_cursor(str, '')
- input_keys("\e\C-_")
- assert_line_around_cursor(str, '')
- end
-end
diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb
deleted file mode 100644
index 083433f9a8..0000000000
--- a/test/reline/test_key_actor_vi.rb
+++ /dev/null
@@ -1,967 +0,0 @@
-require_relative 'helper'
-
-class Reline::ViInsertTest < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- @prompt = '> '
- @config = Reline::Config.new
- @config.read_lines(<<~LINES.split(/(?<=\n)/))
- set editing-mode vi
- LINES
- @encoding = Reline.core.encoding
- @line_editor = Reline::LineEditor.new(@config)
- @line_editor.reset(@prompt)
- end
-
- def editing_mode_label
- @config.instance_variable_get(:@editing_mode_label)
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_vi_command_mode
- input_keys("\C-[")
- assert_equal(:vi_command, editing_mode_label)
- end
-
- def test_vi_command_mode_with_input
- input_keys("abc\C-[")
- assert_equal(:vi_command, editing_mode_label)
- assert_line_around_cursor('ab', 'c')
- end
-
- def test_vi_insert
- assert_equal(:vi_insert, editing_mode_label)
- input_keys('i')
- assert_line_around_cursor('i', '')
- assert_equal(:vi_insert, editing_mode_label)
- input_keys("\C-[")
- assert_line_around_cursor('', 'i')
- assert_equal(:vi_command, editing_mode_label)
- input_keys('i')
- assert_line_around_cursor('', 'i')
- assert_equal(:vi_insert, editing_mode_label)
- end
-
- def test_vi_add
- assert_equal(:vi_insert, editing_mode_label)
- input_keys('a')
- assert_line_around_cursor('a', '')
- assert_equal(:vi_insert, editing_mode_label)
- input_keys("\C-[")
- assert_line_around_cursor('', 'a')
- assert_equal(:vi_command, editing_mode_label)
- input_keys('a')
- assert_line_around_cursor('a', '')
- assert_equal(:vi_insert, editing_mode_label)
- end
-
- def test_vi_insert_at_bol
- input_keys('I')
- assert_line_around_cursor('I', '')
- assert_equal(:vi_insert, editing_mode_label)
- input_keys("12345\C-[hh")
- assert_line_around_cursor('I12', '345')
- assert_equal(:vi_command, editing_mode_label)
- input_keys('I')
- assert_line_around_cursor('', 'I12345')
- assert_equal(:vi_insert, editing_mode_label)
- end
-
- def test_vi_add_at_eol
- input_keys('A')
- assert_line_around_cursor('A', '')
- assert_equal(:vi_insert, editing_mode_label)
- input_keys("12345\C-[hh")
- assert_line_around_cursor('A12', '345')
- assert_equal(:vi_command, editing_mode_label)
- input_keys('A')
- assert_line_around_cursor('A12345', '')
- assert_equal(:vi_insert, editing_mode_label)
- end
-
- def test_ed_insert_one
- input_keys('a')
- assert_line_around_cursor('a', '')
- end
-
- def test_ed_insert_two
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- end
-
- def test_ed_insert_mbchar_one
- input_keys('か')
- assert_line_around_cursor('か', '')
- end
-
- def test_ed_insert_mbchar_two
- input_keys('かき')
- assert_line_around_cursor('かき', '')
- end
-
- def test_ed_insert_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099")
- assert_line_around_cursor("か\u3099", '')
- end
-
- def test_ed_insert_for_plural_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099")
- assert_line_around_cursor("か\u3099き\u3099", '')
- end
-
- def test_ed_insert_ignore_in_vi_command
- input_keys("\C-[")
- chars_to_be_ignored = "\C-Oあ=".chars
- input_keys(chars_to_be_ignored.join)
- assert_line_around_cursor('', '')
- input_keys(chars_to_be_ignored.map {|c| "5#{c}" }.join)
- assert_line_around_cursor('', '')
- input_keys('iい')
- assert_line_around_cursor("い", '')
- end
-
- def test_ed_next_char
- input_keys("abcdef\C-[0")
- assert_line_around_cursor('', 'abcdef')
- input_keys('l')
- assert_line_around_cursor('a', 'bcdef')
- input_keys('2l')
- assert_line_around_cursor('abc', 'def')
- end
-
- def test_ed_prev_char
- input_keys("abcdef\C-[")
- assert_line_around_cursor('abcde', 'f')
- input_keys('h')
- assert_line_around_cursor('abcd', 'ef')
- input_keys('2h')
- assert_line_around_cursor('ab', 'cdef')
- end
-
- def test_history
- Reline::HISTORY.concat(%w{abc 123 AAA})
- input_keys("\C-[")
- assert_line_around_cursor('', '')
- input_keys('k')
- assert_line_around_cursor('', 'AAA')
- input_keys('2k')
- assert_line_around_cursor('', 'abc')
- input_keys('j')
- assert_line_around_cursor('', '123')
- input_keys('2j')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_paste_prev
- input_keys("abcde\C-[3h")
- assert_line_around_cursor('a', 'bcde')
- input_keys('P')
- assert_line_around_cursor('a', 'bcde')
- input_keys('d$')
- assert_line_around_cursor('', 'a')
- input_keys('P')
- assert_line_around_cursor('bcd', 'ea')
- input_keys('2P')
- assert_line_around_cursor('bcdbcdbcd', 'eeea')
- end
-
- def test_vi_paste_next
- input_keys("abcde\C-[3h")
- assert_line_around_cursor('a', 'bcde')
- input_keys('p')
- assert_line_around_cursor('a', 'bcde')
- input_keys('d$')
- assert_line_around_cursor('', 'a')
- input_keys('p')
- assert_line_around_cursor('abcd', 'e')
- input_keys('2p')
- assert_line_around_cursor('abcdebcdebcd', 'e')
- end
-
- def test_vi_paste_prev_for_mbchar
- input_keys("あいうえお\C-[3h")
- assert_line_around_cursor('あ', 'いうえお')
- input_keys('P')
- assert_line_around_cursor('あ', 'いうえお')
- input_keys('d$')
- assert_line_around_cursor('', 'あ')
- input_keys('P')
- assert_line_around_cursor('いうえ', 'おあ')
- input_keys('2P')
- assert_line_around_cursor('いうえいうえいうえ', 'おおおあ')
- end
-
- def test_vi_paste_next_for_mbchar
- input_keys("あいうえお\C-[3h")
- assert_line_around_cursor('あ', 'いうえお')
- input_keys('p')
- assert_line_around_cursor('あ', 'いうえお')
- input_keys('d$')
- assert_line_around_cursor('', 'あ')
- input_keys('p')
- assert_line_around_cursor('あいうえ', 'お')
- input_keys('2p')
- assert_line_around_cursor('あいうえおいうえおいうえ', 'お')
- end
-
- def test_vi_paste_prev_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h")
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099")
- input_keys('P')
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099")
- input_keys('d$')
- assert_line_around_cursor('', "か\u3099")
- input_keys('P')
- assert_line_around_cursor("き\u3099く\u3099け\u3099", "こ\u3099か\u3099")
- input_keys('2P')
- assert_line_around_cursor("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099", "こ\u3099こ\u3099こ\u3099か\u3099")
- end
-
- def test_vi_paste_next_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h")
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099")
- input_keys('p')
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099")
- input_keys('d$')
- assert_line_around_cursor('', "か\u3099")
- input_keys('p')
- assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099", "こ\u3099")
- input_keys('2p')
- assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099", "こ\u3099")
- end
-
- def test_vi_prev_next_word
- input_keys("aaa b{b}b ccc\C-[0")
- assert_line_around_cursor('', 'aaa b{b}b ccc')
- input_keys('w')
- assert_line_around_cursor('aaa ', 'b{b}b ccc')
- input_keys('w')
- assert_line_around_cursor('aaa b', '{b}b ccc')
- input_keys('w')
- assert_line_around_cursor('aaa b{', 'b}b ccc')
- input_keys('w')
- assert_line_around_cursor('aaa b{b', '}b ccc')
- input_keys('w')
- assert_line_around_cursor('aaa b{b}', 'b ccc')
- input_keys('w')
- assert_line_around_cursor('aaa b{b}b ', 'ccc')
- input_keys('w')
- assert_line_around_cursor('aaa b{b}b cc', 'c')
- input_keys('b')
- assert_line_around_cursor('aaa b{b}b ', 'ccc')
- input_keys('b')
- assert_line_around_cursor('aaa b{b}', 'b ccc')
- input_keys('b')
- assert_line_around_cursor('aaa b{b', '}b ccc')
- input_keys('b')
- assert_line_around_cursor('aaa b{', 'b}b ccc')
- input_keys('b')
- assert_line_around_cursor('aaa b', '{b}b ccc')
- input_keys('b')
- assert_line_around_cursor('aaa ', 'b{b}b ccc')
- input_keys('b')
- assert_line_around_cursor('', 'aaa b{b}b ccc')
- input_keys('3w')
- assert_line_around_cursor('aaa b{', 'b}b ccc')
- input_keys('3w')
- assert_line_around_cursor('aaa b{b}b ', 'ccc')
- input_keys('3w')
- assert_line_around_cursor('aaa b{b}b cc', 'c')
- input_keys('3b')
- assert_line_around_cursor('aaa b{b', '}b ccc')
- input_keys('3b')
- assert_line_around_cursor('aaa ', 'b{b}b ccc')
- input_keys('3b')
- assert_line_around_cursor('', 'aaa b{b}b ccc')
- end
-
- def test_vi_end_word
- input_keys("aaa b{b}}}b ccc\C-[0")
- assert_line_around_cursor('', 'aaa b{b}}}b ccc')
- input_keys('e')
- assert_line_around_cursor('aa', 'a b{b}}}b ccc')
- input_keys('e')
- assert_line_around_cursor('aaa ', 'b{b}}}b ccc')
- input_keys('e')
- assert_line_around_cursor('aaa b', '{b}}}b ccc')
- input_keys('e')
- assert_line_around_cursor('aaa b{', 'b}}}b ccc')
- input_keys('e')
- assert_line_around_cursor('aaa b{b}}', '}b ccc')
- input_keys('e')
- assert_line_around_cursor('aaa b{b}}}', 'b ccc')
- input_keys('e')
- assert_line_around_cursor('aaa b{b}}}b cc', 'c')
- input_keys('e')
- assert_line_around_cursor('aaa b{b}}}b cc', 'c')
- input_keys('03e')
- assert_line_around_cursor('aaa b', '{b}}}b ccc')
- input_keys('3e')
- assert_line_around_cursor('aaa b{b}}}', 'b ccc')
- input_keys('3e')
- assert_line_around_cursor('aaa b{b}}}b cc', 'c')
- end
-
- def test_vi_prev_next_big_word
- input_keys("aaa b{b}b ccc\C-[0")
- assert_line_around_cursor('', 'aaa b{b}b ccc')
- input_keys('W')
- assert_line_around_cursor('aaa ', 'b{b}b ccc')
- input_keys('W')
- assert_line_around_cursor('aaa b{b}b ', 'ccc')
- input_keys('W')
- assert_line_around_cursor('aaa b{b}b cc', 'c')
- input_keys('B')
- assert_line_around_cursor('aaa b{b}b ', 'ccc')
- input_keys('B')
- assert_line_around_cursor('aaa ', 'b{b}b ccc')
- input_keys('B')
- assert_line_around_cursor('', 'aaa b{b}b ccc')
- input_keys('2W')
- assert_line_around_cursor('aaa b{b}b ', 'ccc')
- input_keys('2W')
- assert_line_around_cursor('aaa b{b}b cc', 'c')
- input_keys('2B')
- assert_line_around_cursor('aaa ', 'b{b}b ccc')
- input_keys('2B')
- assert_line_around_cursor('', 'aaa b{b}b ccc')
- end
-
- def test_vi_end_big_word
- input_keys("aaa b{b}}}b ccc\C-[0")
- assert_line_around_cursor('', 'aaa b{b}}}b ccc')
- input_keys('E')
- assert_line_around_cursor('aa', 'a b{b}}}b ccc')
- input_keys('E')
- assert_line_around_cursor('aaa b{b}}}', 'b ccc')
- input_keys('E')
- assert_line_around_cursor('aaa b{b}}}b cc', 'c')
- input_keys('E')
- assert_line_around_cursor('aaa b{b}}}b cc', 'c')
- end
-
- def test_ed_quoted_insert
- input_keys('ab')
- input_key_by_symbol(:insert_raw_char, char: "\C-a")
- assert_line_around_cursor("ab\C-a", '')
- end
-
- def test_ed_quoted_insert_with_vi_arg
- input_keys("ab\C-[3")
- input_key_by_symbol(:insert_raw_char, char: "\C-a")
- input_keys('4')
- input_key_by_symbol(:insert_raw_char, char: '1')
- assert_line_around_cursor("a\C-a\C-a\C-a1111", 'b')
- end
-
- def test_vi_replace_char
- input_keys("abcdef\C-[03l")
- assert_line_around_cursor('abc', 'def')
- input_keys('rz')
- assert_line_around_cursor('abc', 'zef')
- input_keys('2rx')
- assert_line_around_cursor('abcxx', 'f')
- end
-
- def test_vi_replace_char_with_mbchar
- input_keys("あいうえお\C-[0l")
- assert_line_around_cursor('あ', 'いうえお')
- input_keys('rx')
- assert_line_around_cursor('あ', 'xうえお')
- input_keys('l2ry')
- assert_line_around_cursor('あxyy', 'お')
- end
-
- def test_vi_next_char
- input_keys("abcdef\C-[0")
- assert_line_around_cursor('', 'abcdef')
- input_keys('fz')
- assert_line_around_cursor('', 'abcdef')
- input_keys('fe')
- assert_line_around_cursor('abcd', 'ef')
- end
-
- def test_vi_to_next_char
- input_keys("abcdef\C-[0")
- assert_line_around_cursor('', 'abcdef')
- input_keys('tz')
- assert_line_around_cursor('', 'abcdef')
- input_keys('te')
- assert_line_around_cursor('abc', 'def')
- end
-
- def test_vi_prev_char
- input_keys("abcdef\C-[")
- assert_line_around_cursor('abcde', 'f')
- input_keys('Fz')
- assert_line_around_cursor('abcde', 'f')
- input_keys('Fa')
- assert_line_around_cursor('', 'abcdef')
- end
-
- def test_vi_to_prev_char
- input_keys("abcdef\C-[")
- assert_line_around_cursor('abcde', 'f')
- input_keys('Tz')
- assert_line_around_cursor('abcde', 'f')
- input_keys('Ta')
- assert_line_around_cursor('a', 'bcdef')
- end
-
- def test_vi_delete_next_char
- input_keys("abc\C-[h")
- assert_line_around_cursor('a', 'bc')
- input_keys('x')
- assert_line_around_cursor('a', 'c')
- input_keys('x')
- assert_line_around_cursor('', 'a')
- input_keys('x')
- assert_line_around_cursor('', '')
- input_keys('x')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_delete_next_char_for_mbchar
- input_keys("あいう\C-[h")
- assert_line_around_cursor('あ', 'いう')
- input_keys('x')
- assert_line_around_cursor('あ', 'う')
- input_keys('x')
- assert_line_around_cursor('', 'あ')
- input_keys('x')
- assert_line_around_cursor('', '')
- input_keys('x')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_delete_next_char_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099く\u3099\C-[h")
- assert_line_around_cursor("か\u3099", "き\u3099く\u3099")
- input_keys('x')
- assert_line_around_cursor("か\u3099", "く\u3099")
- input_keys('x')
- assert_line_around_cursor('', "か\u3099")
- input_keys('x')
- assert_line_around_cursor('', '')
- input_keys('x')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_delete_prev_char
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- input_keys("\C-h")
- assert_line_around_cursor('a', '')
- end
-
- def test_vi_delete_prev_char_for_mbchar
- input_keys('かき')
- assert_line_around_cursor('かき', '')
- input_keys("\C-h")
- assert_line_around_cursor('か', '')
- end
-
- def test_vi_delete_prev_char_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("か\u3099き\u3099")
- assert_line_around_cursor("か\u3099き\u3099", '')
- input_keys("\C-h")
- assert_line_around_cursor("か\u3099", '')
- end
-
- def test_ed_delete_prev_char
- input_keys("abcdefg\C-[h")
- assert_line_around_cursor('abcde', 'fg')
- input_keys('X')
- assert_line_around_cursor('abcd', 'fg')
- input_keys('3X')
- assert_line_around_cursor('a', 'fg')
- input_keys('p')
- assert_line_around_cursor('afbc', 'dg')
- end
-
- def test_ed_delete_prev_word
- input_keys('abc def{bbb}ccc')
- assert_line_around_cursor('abc def{bbb}ccc', '')
- input_keys("\C-w")
- assert_line_around_cursor('abc def{bbb}', '')
- input_keys("\C-w")
- assert_line_around_cursor('abc def{', '')
- input_keys("\C-w")
- assert_line_around_cursor('abc ', '')
- input_keys("\C-w")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_delete_prev_word_for_mbchar
- input_keys('あいう かきく{さしす}たちつ')
- assert_line_around_cursor('あいう かきく{さしす}たちつ', '')
- input_keys("\C-w")
- assert_line_around_cursor('あいう かきく{さしす}', '')
- input_keys("\C-w")
- assert_line_around_cursor('あいう かきく{', '')
- input_keys("\C-w")
- assert_line_around_cursor('あいう ', '')
- input_keys("\C-w")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_delete_prev_word_for_mbchar_by_plural_code_points
- omit_unless_utf8
- input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '')
- input_keys("\C-w")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '')
- input_keys("\C-w")
- assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '')
- input_keys("\C-w")
- assert_line_around_cursor('あいう ', '')
- input_keys("\C-w")
- assert_line_around_cursor('', '')
- end
-
- def test_ed_newline_with_cr
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- refute(@line_editor.finished?)
- input_keys("\C-m")
- assert_line_around_cursor('ab', '')
- assert(@line_editor.finished?)
- end
-
- def test_ed_newline_with_lf
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- refute(@line_editor.finished?)
- input_keys("\C-j")
- assert_line_around_cursor('ab', '')
- assert(@line_editor.finished?)
- end
-
- def test_vi_list_or_eof
- input_keys("\C-d") # quit from inputing
- assert_nil(@line_editor.line)
- assert(@line_editor.finished?)
- end
-
- def test_vi_list_or_eof_with_non_empty_line
- input_keys('ab')
- assert_line_around_cursor('ab', '')
- refute(@line_editor.finished?)
- input_keys("\C-d")
- assert_line_around_cursor('ab', '')
- assert(@line_editor.finished?)
- end
-
- def test_completion_journey
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_bar
- foo_bar_baz
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('foo')
- assert_line_around_cursor('foo', '')
- input_keys("\C-n")
- assert_line_around_cursor('foo_bar', '')
- input_keys("\C-n")
- assert_line_around_cursor('foo_bar_baz', '')
- input_keys("\C-n")
- assert_line_around_cursor('foo', '')
- input_keys("\C-n")
- assert_line_around_cursor('foo_bar', '')
- input_keys("_\C-n")
- assert_line_around_cursor('foo_bar_baz', '')
- input_keys("\C-n")
- assert_line_around_cursor('foo_bar_', '')
- end
-
- def test_completion_journey_reverse
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_bar
- foo_bar_baz
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('foo')
- assert_line_around_cursor('foo', '')
- input_keys("\C-p")
- assert_line_around_cursor('foo_bar_baz', '')
- input_keys("\C-p")
- assert_line_around_cursor('foo_bar', '')
- input_keys("\C-p")
- assert_line_around_cursor('foo', '')
- input_keys("\C-p")
- assert_line_around_cursor('foo_bar_baz', '')
- input_keys("\C-h\C-p")
- assert_line_around_cursor('foo_bar_baz', '')
- input_keys("\C-p")
- assert_line_around_cursor('foo_bar_ba', '')
- end
-
- def test_completion_journey_in_middle_of_line
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_bar
- foo_bar_baz
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('abcde fo ABCDE')
- assert_line_around_cursor('abcde fo ABCDE', '')
- input_keys("\C-[" + 'h' * 5 + "i\C-n")
- assert_line_around_cursor('abcde foo_bar', ' ABCDE')
- input_keys("\C-n")
- assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE')
- input_keys("\C-n")
- assert_line_around_cursor('abcde fo', ' ABCDE')
- input_keys("\C-n")
- assert_line_around_cursor('abcde foo_bar', ' ABCDE')
- input_keys("_\C-n")
- assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE')
- input_keys("\C-n")
- assert_line_around_cursor('abcde foo_bar_', ' ABCDE')
- input_keys("\C-n")
- assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE')
- end
-
- def test_completion
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_bar
- foo_bar_baz
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('foo')
- assert_line_around_cursor('foo', '')
- input_keys("\C-i")
- assert_line_around_cursor('foo_bar', '')
- end
-
- def test_autocompletion_with_upward_navigation
- @config.autocompletion = true
- @line_editor.completion_proc = proc { |word|
- %w{
- Readline
- Regexp
- RegexpError
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('Re')
- assert_line_around_cursor('Re', '')
- input_keys("\C-i")
- assert_line_around_cursor('Readline', '')
- input_keys("\C-i")
- assert_line_around_cursor('Regexp', '')
- input_key_by_symbol(:completion_journey_up)
- assert_line_around_cursor('Readline', '')
- ensure
- @config.autocompletion = false
- end
-
- def test_autocompletion_with_upward_navigation_and_menu_complete_backward
- @config.autocompletion = true
- @line_editor.completion_proc = proc { |word|
- %w{
- Readline
- Regexp
- RegexpError
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('Re')
- assert_line_around_cursor('Re', '')
- input_keys("\C-i")
- assert_line_around_cursor('Readline', '')
- input_keys("\C-i")
- assert_line_around_cursor('Regexp', '')
- input_key_by_symbol(:menu_complete_backward)
- assert_line_around_cursor('Readline', '')
- ensure
- @config.autocompletion = false
- end
-
- def test_completion_with_disable_completion
- @config.disable_completion = true
- @line_editor.completion_proc = proc { |word|
- %w{
- foo_bar
- foo_bar_baz
- }.map { |i|
- i.encode(@encoding)
- }
- }
- input_keys('foo')
- assert_line_around_cursor('foo', '')
- input_keys("\C-i")
- assert_line_around_cursor('foo', '')
- end
-
- def test_vi_first_print
- input_keys("abcde\C-[^")
- assert_line_around_cursor('', 'abcde')
- input_keys("0\C-ki")
- input_keys(" abcde\C-[^")
- assert_line_around_cursor(' ', 'abcde')
- input_keys("0\C-ki")
- input_keys(" abcde ABCDE \C-[^")
- assert_line_around_cursor(' ', 'abcde ABCDE ')
- end
-
- def test_ed_move_to_beg
- input_keys("abcde\C-[0")
- assert_line_around_cursor('', 'abcde')
- input_keys("0\C-ki")
- input_keys(" abcde\C-[0")
- assert_line_around_cursor('', ' abcde')
- input_keys("0\C-ki")
- input_keys(" abcde ABCDE \C-[0")
- assert_line_around_cursor('', ' abcde ABCDE ')
- end
-
- def test_vi_to_column
- input_keys("a一二三\C-[0")
- input_keys('1|')
- assert_line_around_cursor('', 'a一二三')
- input_keys('2|')
- assert_line_around_cursor('a', '一二三')
- input_keys('3|')
- assert_line_around_cursor('a', '一二三')
- input_keys('4|')
- assert_line_around_cursor('a一', '二三')
- input_keys('9|')
- assert_line_around_cursor('a一二', '三')
- end
-
- def test_vi_delete_meta
- input_keys("aaa bbb ccc ddd eee\C-[02w")
- assert_line_around_cursor('aaa bbb ', 'ccc ddd eee')
- input_keys('dw')
- assert_line_around_cursor('aaa bbb ', 'ddd eee')
- input_keys('db')
- assert_line_around_cursor('aaa ', 'ddd eee')
- end
-
- def test_vi_delete_meta_nothing
- input_keys("foo\C-[0")
- assert_line_around_cursor('', 'foo')
- input_keys('dhp')
- assert_line_around_cursor('', 'foo')
- end
-
- def test_vi_delete_meta_with_vi_next_word_at_eol
- input_keys("foo bar\C-[0w")
- assert_line_around_cursor('foo ', 'bar')
- input_keys('w')
- assert_line_around_cursor('foo ba', 'r')
- input_keys('0dw')
- assert_line_around_cursor('', 'bar')
- input_keys('dw')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_delete_meta_with_vi_next_char
- input_keys("aaa bbb ccc ___ ddd\C-[02w")
- assert_line_around_cursor('aaa bbb ', 'ccc ___ ddd')
- input_keys('df_')
- assert_line_around_cursor('aaa bbb ', '__ ddd')
- end
-
- def test_vi_delete_meta_with_arg
- input_keys("aaa bbb ccc ddd\C-[03w")
- assert_line_around_cursor('aaa bbb ccc ', 'ddd')
- input_keys('2dl')
- assert_line_around_cursor('aaa bbb ccc ', 'd')
- input_keys('d2h')
- assert_line_around_cursor('aaa bbb cc', 'd')
- input_keys('2d3h')
- assert_line_around_cursor('aaa ', 'd')
- input_keys('dd')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_change_meta
- input_keys("aaa bbb ccc ddd eee\C-[02w")
- assert_line_around_cursor('aaa bbb ', 'ccc ddd eee')
- input_keys('cwaiueo')
- assert_line_around_cursor('aaa bbb aiueo', ' ddd eee')
- input_keys("\C-[")
- assert_line_around_cursor('aaa bbb aiue', 'o ddd eee')
- input_keys('cb')
- assert_line_around_cursor('aaa bbb ', 'o ddd eee')
- end
-
- def test_vi_change_meta_with_vi_next_word
- input_keys("foo bar baz\C-[0w")
- assert_line_around_cursor('foo ', 'bar baz')
- input_keys('cwhoge')
- assert_line_around_cursor('foo hoge', ' baz')
- input_keys("\C-[")
- assert_line_around_cursor('foo hog', 'e baz')
- end
-
- def test_vi_waiting_operator_with_waiting_proc
- input_keys("foo foo foo foo foo\C-[0")
- input_keys('2d3fo')
- assert_line_around_cursor('', ' foo foo')
- input_keys('fo')
- assert_line_around_cursor(' f', 'oo foo')
- end
-
- def test_waiting_operator_arg_including_zero
- input_keys("a111111111111222222222222\C-[0")
- input_keys('10df1')
- assert_line_around_cursor('', '11222222222222')
- input_keys('d10f2')
- assert_line_around_cursor('', '22')
- end
-
- def test_vi_waiting_operator_cancel
- input_keys("aaa bbb ccc\C-[02w")
- assert_line_around_cursor('aaa bbb ', 'ccc')
- # dc dy should cancel delete_meta
- input_keys('dch')
- input_keys('dyh')
- # cd cy should cancel change_meta
- input_keys('cdh')
- input_keys('cyh')
- # yd yc should cancel yank_meta
- # P should not paste yanked text because yank_meta is canceled
- input_keys('ydhP')
- input_keys('ychP')
- assert_line_around_cursor('aa', 'a bbb ccc')
- end
-
- def test_cancel_waiting_with_symbol_key
- input_keys("aaa bbb lll\C-[0")
- assert_line_around_cursor('', 'aaa bbb lll')
- # ed_next_char should move cursor right and cancel vi_next_char
- input_keys('f')
- input_key_by_symbol(:ed_next_char, csi: true)
- input_keys('l')
- assert_line_around_cursor('aa', 'a bbb lll')
- # vi_delete_meta + ed_next_char should delete character
- input_keys('d')
- input_key_by_symbol(:ed_next_char, csi: true)
- input_keys('l')
- assert_line_around_cursor('aa ', 'bbb lll')
- end
-
- def test_unimplemented_vi_command_should_be_no_op
- input_keys("abc\C-[h")
- assert_line_around_cursor('a', 'bc')
- input_keys('@')
- assert_line_around_cursor('a', 'bc')
- end
-
- def test_vi_yank
- input_keys("foo bar\C-[2h")
- assert_line_around_cursor('foo ', 'bar')
- input_keys('y3l')
- assert_line_around_cursor('foo ', 'bar')
- input_keys('P')
- assert_line_around_cursor('foo ba', 'rbar')
- input_keys('3h3yhP')
- assert_line_around_cursor('foofo', 'o barbar')
- input_keys('yyP')
- assert_line_around_cursor('foofofoofoo barba', 'ro barbar')
- end
-
- def test_vi_yank_nothing
- input_keys("foo\C-[0")
- assert_line_around_cursor('', 'foo')
- input_keys('yhp')
- assert_line_around_cursor('', 'foo')
- end
-
- def test_vi_end_word_with_operator
- input_keys("foo bar\C-[0")
- assert_line_around_cursor('', 'foo bar')
- input_keys('de')
- assert_line_around_cursor('', ' bar')
- input_keys('de')
- assert_line_around_cursor('', '')
- input_keys('de')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_end_big_word_with_operator
- input_keys("aaa b{b}}}b\C-[0")
- assert_line_around_cursor('', 'aaa b{b}}}b')
- input_keys('dE')
- assert_line_around_cursor('', ' b{b}}}b')
- input_keys('dE')
- assert_line_around_cursor('', '')
- input_keys('dE')
- assert_line_around_cursor('', '')
- end
-
- def test_vi_next_char_with_operator
- input_keys("foo bar\C-[0")
- assert_line_around_cursor('', 'foo bar')
- input_keys('df ')
- assert_line_around_cursor('', 'bar')
- end
-
- def test_ed_delete_next_char_at_eol
- input_keys('"あ"')
- assert_line_around_cursor('"あ"', '')
- input_keys("\C-[")
- assert_line_around_cursor('"あ', '"')
- input_keys('xa"')
- assert_line_around_cursor('"あ"', '')
- end
-
- def test_vi_kill_line_prev
- input_keys("\C-u")
- assert_line_around_cursor('', '')
- input_keys('abc')
- assert_line_around_cursor('abc', '')
- input_keys("\C-u")
- assert_line_around_cursor('', '')
- input_keys('abc')
- input_keys("\C-[\C-u")
- assert_line_around_cursor('', 'c')
- input_keys("\C-u")
- assert_line_around_cursor('', 'c')
- end
-
- def test_vi_change_to_eol
- input_keys("abcdef\C-[2hC")
- assert_line_around_cursor('abc', '')
- input_keys("\C-[0C")
- assert_line_around_cursor('', '')
- assert_equal(:vi_insert, editing_mode_label)
- end
-
- def test_vi_motion_operators
- assert_equal(:vi_insert, editing_mode_label)
-
- assert_nothing_raised do
- input_keys("test = { foo: bar }\C-[BBBldt}b")
- end
- end
-
- def test_emacs_editing_mode
- @line_editor.__send__(:emacs_editing_mode, nil)
- assert(@config.editing_mode_is?(:emacs))
- end
-end
diff --git a/test/reline/test_key_stroke.rb b/test/reline/test_key_stroke.rb
deleted file mode 100644
index fb2cb1c8b8..0000000000
--- a/test/reline/test_key_stroke.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require_relative 'helper'
-
-class Reline::KeyStroke::Test < Reline::TestCase
- def encoding
- Reline.core.encoding
- end
-
- def test_match_status
- config = Reline::Config.new
- {
- 'a' => 'xx',
- 'ab' => 'y',
- 'abc' => 'z',
- 'x' => 'rr'
- }.each_pair do |key, func|
- config.add_default_key_binding(key.bytes, func.bytes)
- end
- stroke = Reline::KeyStroke.new(config, encoding)
- assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status("a".bytes))
- assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status("ab".bytes))
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("abc".bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("abz".bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("abcx".bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("aa".bytes))
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("x".bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("xa".bytes))
- end
-
- def test_match_unknown
- config = Reline::Config.new
- config.add_default_key_binding("\e[9abc".bytes, 'x')
- stroke = Reline::KeyStroke.new(config, encoding)
- sequences = [
- "\e[9abc",
- "\e[9d",
- "\e[A", # Up
- "\e[1;1R", # Cursor position report
- "\e[15~", # F5
- "\eOP", # F1
- "\e\e[A", # Option+Up
- "\eX",
- "\e\eX"
- ]
- sequences.each do |seq|
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status(seq.bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(seq.bytes + [32]))
- (2...seq.size).each do |i|
- assert_equal(Reline::KeyStroke::MATCHING, stroke.match_status(seq.bytes.take(i)))
- end
- end
- end
-
- def test_expand
- config = Reline::Config.new
- {
- 'abc' => 'AB',
- 'ab' => "1\C-a"
- }.each_pair do |key, func|
- config.add_default_key_binding(key.bytes, func.bytes)
- end
- stroke = Reline::KeyStroke.new(config, encoding)
- assert_equal([[Reline::Key.new('A', :ed_insert, false), Reline::Key.new('B', :ed_insert, false)], 'de'.bytes], stroke.expand('abcde'.bytes))
- assert_equal([[Reline::Key.new('1', :ed_digit, false), Reline::Key.new("\C-a", :ed_move_to_beg, false)], 'de'.bytes], stroke.expand('abde'.bytes))
- # CSI sequence
- assert_equal([[], 'bc'.bytes], stroke.expand("\e[1;2;3;4;5abc".bytes))
- assert_equal([[], 'BC'.bytes], stroke.expand("\e\e[ABC".bytes))
- # SS3 sequence
- assert_equal([[], 'QR'.bytes], stroke.expand("\eOPQR".bytes))
- end
-
- def test_oneshot_key_bindings
- config = Reline::Config.new
- {
- 'abc'.bytes => '123',
- # IRB version <= 1.13.1 wrongly uses Reline::Key with wrong argument. It should be ignored without error.
- [Reline::Key.new(nil, 0xE4, true)] => '012',
- "\eda".bytes => 'abc', # Alt+d a
- [195, 164] => 'def'
- }.each_pair do |key, func|
- config.add_oneshot_key_binding(key, func.bytes)
- end
- stroke = Reline::KeyStroke.new(config, encoding)
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status('zzz'.bytes))
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status('abc'.bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status('da'.bytes))
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("\eda".bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(" \eda".bytes))
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status([195, 164]))
- end
-
- def test_multibyte_matching
- begin
- char = 'あ'.encode(encoding)
- rescue Encoding::UndefinedConversionError
- omit
- end
- config = Reline::Config.new
- stroke = Reline::KeyStroke.new(config, encoding)
- key = Reline::Key.new(char, :ed_insert, false)
- bytes = char.bytes
- assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status(bytes))
- assert_equal([[key], []], stroke.expand(bytes))
- assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(bytes * 2))
- assert_equal([[key], bytes], stroke.expand(bytes * 2))
- (1...bytes.size).each do |i|
- partial_bytes = bytes.take(i)
- assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status(partial_bytes))
- assert_equal([[], []], stroke.expand(partial_bytes))
- end
- end
-end
diff --git a/test/reline/test_kill_ring.rb b/test/reline/test_kill_ring.rb
deleted file mode 100644
index 9f6e0c3e74..0000000000
--- a/test/reline/test_kill_ring.rb
+++ /dev/null
@@ -1,268 +0,0 @@
-require_relative 'helper'
-
-class Reline::KillRing::Test < Reline::TestCase
- def setup
- @prompt = '> '
- @kill_ring = Reline::KillRing.new
- end
-
- def test_append_one
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('a', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('a', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['a', 'a'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['a', 'a'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_two
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('b', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('b', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['a', 'b'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['b', 'a'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_three
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('c')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('c', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('c', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['b', 'c'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['a', 'b'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['c', 'a'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_three_with_max_two
- @kill_ring = Reline::KillRing.new(2)
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('c')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('c', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('c', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['b', 'c'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['c', 'b'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['b', 'c'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_four_with_max_two
- @kill_ring = Reline::KillRing.new(2)
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('c')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('d')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('d', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('d', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['c', 'd'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['d', 'c'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['c', 'd'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_after
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('ab', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('ab', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['ab', 'ab'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['ab', 'ab'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_before
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b', true)
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('ba', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('ba', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['ba', 'ba'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['ba', 'ba'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_chain_two
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('c')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('d')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('cd', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('cd', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['ab', 'cd'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['cd', 'ab'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_append_complex_chain
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('c')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('d')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('b', true)
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('e')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('a', true)
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('A')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.append('B')
- assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state))
- @kill_ring.process
- assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state))
- assert_equal('AB', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal('AB', @kill_ring.yank)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['abcde', 'AB'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- assert_equal(['AB', 'abcde'], @kill_ring.yank_pop)
- assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state))
- end
-
- def test_enumerable
- @kill_ring.append('a')
- @kill_ring.process
- @kill_ring.process
- @kill_ring.append('b')
- @kill_ring.process
- @kill_ring.process
- @kill_ring.append('c')
- @kill_ring.process
- assert_equal(%w{c b a}, @kill_ring.to_a)
- end
-end
diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb
deleted file mode 100644
index 28fcbfa6df..0000000000
--- a/test/reline/test_line_editor.rb
+++ /dev/null
@@ -1,271 +0,0 @@
-require_relative 'helper'
-require 'reline/line_editor'
-require 'stringio'
-
-class Reline::LineEditor
-
- class CompletionBlockTest < Reline::TestCase
- def setup
- @original_quote_characters = Reline.completer_quote_characters
- @original_word_break_characters = Reline.completer_word_break_characters
- @line_editor = Reline::LineEditor.new(nil)
- end
-
- def retrieve_completion_block(lines, line_index, byte_pointer)
- @line_editor.instance_variable_set(:@buffer_of_lines, lines)
- @line_editor.instance_variable_set(:@line_index, line_index)
- @line_editor.instance_variable_set(:@byte_pointer, byte_pointer)
- @line_editor.retrieve_completion_block
- end
-
- def retrieve_completion_quote(line)
- _, _, _, quote = retrieve_completion_block([line], 0, line.bytesize)
- quote
- end
-
- def teardown
- Reline.completer_quote_characters = @original_quote_characters
- Reline.completer_word_break_characters = @original_word_break_characters
- end
-
- def test_retrieve_completion_block
- Reline.completer_word_break_characters = ' ([{'
- Reline.completer_quote_characters = ''
- assert_equal(['', '', 'foo', nil], retrieve_completion_block(['foo'], 0, 0))
- assert_equal(['', 'f', 'oo', nil], retrieve_completion_block(['foo'], 0, 1))
- assert_equal(['foo ', 'ba', 'r baz', nil], retrieve_completion_block(['foo bar baz'], 0, 6))
- assert_equal(['foo([', 'b', 'ar])baz', nil], retrieve_completion_block(['foo([bar])baz'], 0, 6))
- assert_equal(['foo([{', '', '}])baz', nil], retrieve_completion_block(['foo([{}])baz'], 0, 6))
- assert_equal(["abc\nfoo ", 'ba', "r baz\ndef", nil], retrieve_completion_block(['abc', 'foo bar baz', 'def'], 1, 6))
- end
-
- def test_retrieve_completion_block_with_quote_characters
- Reline.completer_word_break_characters = ' ([{'
- Reline.completer_quote_characters = ''
- assert_equal(['"" ', '"wo', 'rd', nil], retrieve_completion_block(['"" "word'], 0, 6))
- Reline.completer_quote_characters = '"'
- assert_equal(['"" "', 'wo', 'rd', nil], retrieve_completion_block(['"" "word'], 0, 6))
- end
-
- def test_retrieve_completion_quote
- Reline.completer_quote_characters = '"\''
- assert_equal('"', retrieve_completion_quote('"\''))
- assert_equal(nil, retrieve_completion_quote('""'))
- assert_equal("'", retrieve_completion_quote('""\'"'))
- assert_equal(nil, retrieve_completion_quote('""\'\''))
- assert_equal('"', retrieve_completion_quote('"\\"'))
- assert_equal(nil, retrieve_completion_quote('"\\""'))
- assert_equal(nil, retrieve_completion_quote('"\\\\"'))
- end
- end
-
- class CursorPositionTest < Reline::TestCase
- def setup
- @line_editor = Reline::LineEditor.new(nil)
- @line_editor.instance_variable_set(:@config, Reline::Config.new)
- end
-
- def test_cursor_position_with_escaped_input
- @line_editor.instance_variable_set(:@screen_size, [4, 16])
- @line_editor.instance_variable_set(:@prompt, "\e[1mprompt\e[0m> ")
- @line_editor.instance_variable_set(:@buffer_of_lines, ["\e[1m\0\1\2\3\4\5\6\7abcd"])
- @line_editor.instance_variable_set(:@line_index, 0)
- # prompt> ^[[1m^@^
- # A^B^C^D^E^F^Gabc
- # d
- @line_editor.instance_variable_set(:@byte_pointer, 0)
- assert_equal [8, 0], @line_editor.wrapped_cursor_position
- @line_editor.instance_variable_set(:@byte_pointer, 5)
- assert_equal [15, 0], @line_editor.wrapped_cursor_position
- @line_editor.instance_variable_set(:@byte_pointer, 6)
- assert_equal [1, 1], @line_editor.wrapped_cursor_position
- @line_editor.instance_variable_set(:@byte_pointer, 14)
- assert_equal [15, 1], @line_editor.wrapped_cursor_position
- @line_editor.instance_variable_set(:@byte_pointer, 15)
- assert_equal [0, 2], @line_editor.wrapped_cursor_position
- @line_editor.instance_variable_set(:@byte_pointer, 16)
- assert_equal [1, 2], @line_editor.wrapped_cursor_position
- end
- end
-
- class RenderLineDifferentialTest < Reline::TestCase
- class TestIO < Reline::IO
- def write(string)
- @output << string
- end
-
- def move_cursor_column(col)
- @output << "[COL_#{col}]"
- end
-
- def erase_after_cursor
- @output << '[ERASE]'
- end
- end
-
- def setup
- verbose, $VERBOSE = $VERBOSE, nil
- @line_editor = Reline::LineEditor.new(nil)
- @original_iogate = Reline::IOGate
- @output = StringIO.new
- @line_editor.instance_variable_set(:@screen_size, [24, 80])
- Reline.send(:remove_const, :IOGate)
- Reline.const_set(:IOGate, TestIO.new)
- Reline::IOGate.instance_variable_set(:@output, @output)
- ensure
- $VERBOSE = verbose
- end
-
- def assert_output(expected)
- @output.reopen(+'')
- yield
- actual = @output.string
- assert_equal(expected, actual.gsub("\e[0m", ''))
- end
-
- def teardown
- Reline.send(:remove_const, :IOGate)
- Reline.const_set(:IOGate, @original_iogate)
- end
-
- def test_line_increase_decrease
- assert_output '[COL_0]bb' do
- @line_editor.render_line_differential([[0, 1, 'a']], [[0, 2, 'bb']])
- end
-
- assert_output '[COL_0]b[COL_1][ERASE]' do
- @line_editor.render_line_differential([[0, 2, 'aa']], [[0, 1, 'b']])
- end
- end
-
- def test_dialog_appear_disappear
- assert_output '[COL_3]dialog' do
- @line_editor.render_line_differential([[0, 1, 'a']], [[0, 1, 'a'], [3, 6, 'dialog']])
- end
-
- assert_output '[COL_3]dialog' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10]], [[0, 10, 'a' * 10], [3, 6, 'dialog']])
- end
-
- assert_output '[COL_1][ERASE]' do
- @line_editor.render_line_differential([[0, 1, 'a'], [3, 6, 'dialog']], [[0, 1, 'a']])
- end
-
- assert_output '[COL_3]aaaaaa' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10]])
- end
- end
-
- def test_dialog_change
- assert_output '[COL_3]DIALOG' do
- @line_editor.render_line_differential([[0, 2, 'a'], [3, 6, 'dialog']], [[0, 2, 'a'], [3, 6, 'DIALOG']])
- end
-
- assert_output '[COL_3]DIALOG' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10], [3, 6, 'DIALOG']])
- end
- end
-
- def test_update_under_dialog
- assert_output '[COL_0]b[COL_1] ' do
- @line_editor.render_line_differential([[0, 2, 'aa'], [4, 6, 'dialog']], [[0, 1, 'b'], [4, 6, 'dialog']])
- end
-
- assert_output '[COL_0]bbb[COL_9]b' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'b' * 10], [3, 6, 'dialog']])
- end
-
- assert_output '[COL_0]b[COL_1] [COL_9][ERASE]' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 1, 'b'], [3, 6, 'dialog']])
- end
- end
-
- def test_dialog_move
- assert_output '[COL_3]dialog[COL_9][ERASE]' do
- @line_editor.render_line_differential([[0, 1, 'a'], [4, 6, 'dialog']], [[0, 1, 'a'], [3, 6, 'dialog']])
- end
-
- assert_output '[COL_4] [COL_5]dialog' do
- @line_editor.render_line_differential([[0, 1, 'a'], [4, 6, 'dialog']], [[0, 1, 'a'], [5, 6, 'dialog']])
- end
-
- assert_output '[COL_2]dialog[COL_8]a' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10], [2, 6, 'dialog']])
- end
-
- assert_output '[COL_2]a[COL_3]dialog' do
- @line_editor.render_line_differential([[0, 10, 'a' * 10], [2, 6, 'dialog']], [[0, 10, 'a' * 10], [3, 6, 'dialog']])
- end
- end
-
- def test_multibyte
- base = [0, 12, '一二三一二三']
- left = [0, 3, 'LLL']
- right = [9, 3, 'RRR']
- front = [3, 6, 'FFFFFF']
- # 一 FFFFFF 三
- # 一二三一二三
- assert_output '[COL_2]二三一二' do
- @line_editor.render_line_differential([base, front], [base, nil])
- end
-
- # LLLFFFFFF 三
- # LLL 三一二三
- assert_output '[COL_3] 三一二' do
- @line_editor.render_line_differential([base, left, front], [base, left, nil])
- end
-
- # 一 FFFFFFRRR
- # 一二三一 RRR
- assert_output '[COL_2]二三一 ' do
- @line_editor.render_line_differential([base, right, front], [base, right, nil])
- end
-
- # LLLFFFFFFRRR
- # LLL 三一 RRR
- assert_output '[COL_3] 三一 ' do
- @line_editor.render_line_differential([base, left, right, front], [base, left, right, nil])
- end
- end
-
- def test_complicated
- state_a = [nil, [19, 7, 'bbbbbbb'], [15, 8, 'cccccccc'], [10, 5, 'ddddd'], [18, 4, 'eeee'], [1, 3, 'fff'], [17, 2, 'gg'], [7, 1, 'h']]
- state_b = [[5, 9, 'aaaaaaaaa'], nil, [15, 8, 'cccccccc'], nil, [18, 4, 'EEEE'], [25, 4, 'ffff'], [17, 2, 'gg'], [2, 2, 'hh']]
- # state_a: " fff h dddddccggeeecbbb"
- # state_b: " hh aaaaaaaaa ccggEEEc ffff"
-
- assert_output '[COL_1] [COL_2]hh[COL_5]aaaaaaaaa[COL_14] [COL_19]EEE[COL_23] [COL_25]ffff' do
- @line_editor.render_line_differential(state_a, state_b)
- end
-
- assert_output '[COL_1]fff[COL_5] [COL_7]h[COL_8] [COL_10]ddddd[COL_19]eee[COL_23]bbb[COL_26][ERASE]' do
- @line_editor.render_line_differential(state_b, state_a)
- end
- end
- end
-
- def test_menu_info_format
- list = %w[aa b c d e f g hhh i j k]
- col3 = [
- 'aa e i',
- 'b f j',
- 'c g k',
- 'd hhh'
- ]
- col2 = [
- 'aa g',
- 'b hhh',
- 'c i',
- 'd j',
- 'e k',
- 'f'
- ]
- assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(19))
- assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(15))
- assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(14))
- assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(10))
- assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(9))
- assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(0))
- assert_equal([], Reline::LineEditor::MenuInfo.new([]).lines(10))
- end
-end
diff --git a/test/reline/test_macro.rb b/test/reline/test_macro.rb
deleted file mode 100644
index cacdb76c60..0000000000
--- a/test/reline/test_macro.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative 'helper'
-
-class Reline::MacroTest < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- @config = Reline::Config.new
- @encoding = Reline.core.encoding
- @line_editor = Reline::LineEditor.new(@config)
- @output = Reline::IOGate.output = File.open(IO::NULL, "w")
- end
-
- def teardown
- @output.close
- Reline.test_reset
- end
-
- def input_key(char, method_symbol = :ed_insert)
- @line_editor.input_key(Reline::Key.new(char, method_symbol, false))
- end
-
- def input(str)
- str.each_char {|c| input_key(c)}
- end
-
- def test_simple_input
- input('abc')
- assert_equal 'abc', @line_editor.line
- end
-
- def test_alias
- class << @line_editor
- alias delete_char ed_delete_prev_char
- end
- input('abc')
- assert_nothing_raised(ArgumentError) {
- input_key('x', :delete_char)
- }
- assert_equal 'ab', @line_editor.line
- end
-end
diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb
deleted file mode 100644
index 691ed9ffda..0000000000
--- a/test/reline/test_reline.rb
+++ /dev/null
@@ -1,487 +0,0 @@
-require_relative 'helper'
-require 'reline'
-require 'stringio'
-begin
- require "pty"
-rescue LoadError # some platforms don't support PTY
-end
-
-class Reline::Test < Reline::TestCase
- class DummyCallbackObject
- def call; end
- end
-
- def setup
- Reline.send(:test_mode)
- Reline.output_modifier_proc = nil
- Reline.completion_proc = nil
- Reline.prompt_proc = nil
- Reline.auto_indent_proc = nil
- Reline.pre_input_hook = nil
- Reline.dig_perfect_match_proc = nil
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_completion_append_character
- completion_append_character = Reline.completion_append_character
-
- assert_equal(nil, Reline.completion_append_character)
-
- Reline.completion_append_character = ""
- assert_equal(nil, Reline.completion_append_character)
-
- Reline.completion_append_character = "a".encode(Encoding::ASCII)
- assert_equal("a", Reline.completion_append_character)
- assert_equal(get_reline_encoding, Reline.completion_append_character.encoding)
-
- Reline.completion_append_character = "ba".encode(Encoding::ASCII)
- assert_equal("b", Reline.completion_append_character)
- assert_equal(get_reline_encoding, Reline.completion_append_character.encoding)
-
- Reline.completion_append_character = "cba".encode(Encoding::ASCII)
- assert_equal("c", Reline.completion_append_character)
- assert_equal(get_reline_encoding, Reline.completion_append_character.encoding)
-
- Reline.completion_append_character = nil
- assert_equal(nil, Reline.completion_append_character)
- ensure
- Reline.completion_append_character = completion_append_character
- end
-
- def test_basic_word_break_characters
- basic_word_break_characters = Reline.basic_word_break_characters
-
- assert_equal(" \t\n`><=;|&{(", Reline.basic_word_break_characters)
-
- Reline.basic_word_break_characters = "[".encode(Encoding::ASCII)
- assert_equal("[", Reline.basic_word_break_characters)
- assert_equal(get_reline_encoding, Reline.basic_word_break_characters.encoding)
- ensure
- Reline.basic_word_break_characters = basic_word_break_characters
- end
-
- def test_completer_word_break_characters
- completer_word_break_characters = Reline.completer_word_break_characters
-
- assert_equal(" \t\n`><=;|&{(", Reline.completer_word_break_characters)
-
- Reline.completer_word_break_characters = "[".encode(Encoding::ASCII)
- assert_equal("[", Reline.completer_word_break_characters)
- assert_equal(get_reline_encoding, Reline.completer_word_break_characters.encoding)
-
- assert_nothing_raised { Reline.completer_word_break_characters = '' }
- ensure
- Reline.completer_word_break_characters = completer_word_break_characters
- end
-
- def test_basic_quote_characters
- basic_quote_characters = Reline.basic_quote_characters
-
- assert_equal('"\'', Reline.basic_quote_characters)
-
- Reline.basic_quote_characters = "`".encode(Encoding::ASCII)
- assert_equal("`", Reline.basic_quote_characters)
- assert_equal(get_reline_encoding, Reline.basic_quote_characters.encoding)
- ensure
- Reline.basic_quote_characters = basic_quote_characters
- end
-
- def test_completer_quote_characters
- completer_quote_characters = Reline.completer_quote_characters
-
- assert_equal('"\'', Reline.completer_quote_characters)
-
- Reline.completer_quote_characters = "`".encode(Encoding::ASCII)
- assert_equal("`", Reline.completer_quote_characters)
- assert_equal(get_reline_encoding, Reline.completer_quote_characters.encoding)
-
- assert_nothing_raised { Reline.completer_quote_characters = '' }
- ensure
- Reline.completer_quote_characters = completer_quote_characters
- end
-
- def test_filename_quote_characters
- filename_quote_characters = Reline.filename_quote_characters
-
- assert_equal('', Reline.filename_quote_characters)
-
- Reline.filename_quote_characters = "\'".encode(Encoding::ASCII)
- assert_equal("\'", Reline.filename_quote_characters)
- assert_equal(get_reline_encoding, Reline.filename_quote_characters.encoding)
- ensure
- Reline.filename_quote_characters = filename_quote_characters
- end
-
- def test_special_prefixes
- special_prefixes = Reline.special_prefixes
-
- assert_equal('', Reline.special_prefixes)
-
- Reline.special_prefixes = "\'".encode(Encoding::ASCII)
- assert_equal("\'", Reline.special_prefixes)
- assert_equal(get_reline_encoding, Reline.special_prefixes.encoding)
- ensure
- Reline.special_prefixes = special_prefixes
- end
-
- def test_completion_case_fold
- completion_case_fold = Reline.completion_case_fold
-
- assert_equal(nil, Reline.completion_case_fold)
-
- Reline.completion_case_fold = true
- assert_equal(true, Reline.completion_case_fold)
-
- Reline.completion_case_fold = "hoge".encode(Encoding::ASCII)
- assert_equal("hoge", Reline.completion_case_fold)
- ensure
- Reline.completion_case_fold = completion_case_fold
- end
-
- def test_completion_proc
- omit unless Reline.completion_proc == nil
- # Another test can set Reline.completion_proc
-
- # assert_equal(nil, Reline.completion_proc)
-
- dummy_proc = proc {}
- Reline.completion_proc = dummy_proc
- assert_equal(dummy_proc, Reline.completion_proc)
-
- l = lambda {}
- Reline.completion_proc = l
- assert_equal(l, Reline.completion_proc)
-
- assert_raise(ArgumentError) { Reline.completion_proc = 42 }
- assert_raise(ArgumentError) { Reline.completion_proc = "hoge" }
-
- dummy = DummyCallbackObject.new
- Reline.completion_proc = dummy
- assert_equal(dummy, Reline.completion_proc)
- end
-
- def test_output_modifier_proc
- assert_equal(nil, Reline.output_modifier_proc)
-
- dummy_proc = proc {}
- Reline.output_modifier_proc = dummy_proc
- assert_equal(dummy_proc, Reline.output_modifier_proc)
-
- l = lambda {}
- Reline.output_modifier_proc = l
- assert_equal(l, Reline.output_modifier_proc)
-
- assert_raise(ArgumentError) { Reline.output_modifier_proc = 42 }
- assert_raise(ArgumentError) { Reline.output_modifier_proc = "hoge" }
-
- dummy = DummyCallbackObject.new
- Reline.output_modifier_proc = dummy
- assert_equal(dummy, Reline.output_modifier_proc)
- end
-
- def test_prompt_proc
- assert_equal(nil, Reline.prompt_proc)
-
- dummy_proc = proc {}
- Reline.prompt_proc = dummy_proc
- assert_equal(dummy_proc, Reline.prompt_proc)
-
- l = lambda {}
- Reline.prompt_proc = l
- assert_equal(l, Reline.prompt_proc)
-
- assert_raise(ArgumentError) { Reline.prompt_proc = 42 }
- assert_raise(ArgumentError) { Reline.prompt_proc = "hoge" }
-
- dummy = DummyCallbackObject.new
- Reline.prompt_proc = dummy
- assert_equal(dummy, Reline.prompt_proc)
- end
-
- def test_auto_indent_proc
- assert_equal(nil, Reline.auto_indent_proc)
-
- dummy_proc = proc {}
- Reline.auto_indent_proc = dummy_proc
- assert_equal(dummy_proc, Reline.auto_indent_proc)
-
- l = lambda {}
- Reline.auto_indent_proc = l
- assert_equal(l, Reline.auto_indent_proc)
-
- assert_raise(ArgumentError) { Reline.auto_indent_proc = 42 }
- assert_raise(ArgumentError) { Reline.auto_indent_proc = "hoge" }
-
- dummy = DummyCallbackObject.new
- Reline.auto_indent_proc = dummy
- assert_equal(dummy, Reline.auto_indent_proc)
- end
-
- def test_pre_input_hook
- assert_equal(nil, Reline.pre_input_hook)
-
- dummy_proc = proc {}
- Reline.pre_input_hook = dummy_proc
- assert_equal(dummy_proc, Reline.pre_input_hook)
-
- l = lambda {}
- Reline.pre_input_hook = l
- assert_equal(l, Reline.pre_input_hook)
- end
-
- def test_dig_perfect_match_proc
- assert_equal(nil, Reline.dig_perfect_match_proc)
-
- dummy_proc = proc {}
- Reline.dig_perfect_match_proc = dummy_proc
- assert_equal(dummy_proc, Reline.dig_perfect_match_proc)
-
- l = lambda {}
- Reline.dig_perfect_match_proc = l
- assert_equal(l, Reline.dig_perfect_match_proc)
-
- assert_raise(ArgumentError) { Reline.dig_perfect_match_proc = 42 }
- assert_raise(ArgumentError) { Reline.dig_perfect_match_proc = "hoge" }
-
- dummy = DummyCallbackObject.new
- Reline.dig_perfect_match_proc = dummy
- assert_equal(dummy, Reline.dig_perfect_match_proc)
- end
-
- def test_insert_text
- assert_equal('', Reline.line_buffer)
- assert_equal(0, Reline.point)
- Reline.insert_text('abc')
- assert_equal('abc', Reline.line_buffer)
- assert_equal(3, Reline.point)
- end
-
- def test_delete_text
- assert_equal('', Reline.line_buffer)
- assert_equal(0, Reline.point)
- Reline.insert_text('abc')
- assert_equal('abc', Reline.line_buffer)
- assert_equal(3, Reline.point)
- Reline.delete_text()
- assert_equal('', Reline.line_buffer)
- assert_equal(0, Reline.point)
- Reline.insert_text('abc')
- Reline.delete_text(1)
- assert_equal('a', Reline.line_buffer)
- assert_equal(1, Reline.point)
- Reline.insert_text('defghi')
- Reline.delete_text(2, 2)
- assert_equal('adghi', Reline.line_buffer)
- assert_equal(5, Reline.point)
- end
-
- def test_set_input_and_output
- assert_raise(TypeError) do
- Reline.input = "This is not a file."
- end
- assert_raise(TypeError) do
- Reline.output = "This is not a file."
- end
-
- input, to_write = IO.pipe
- to_read, output = IO.pipe
- unless Reline.__send__(:input=, input)
- omit "Setting to input is not effective on #{Reline.core.io_gate}"
- end
- Reline.output = output
-
- to_write.write "a\n"
- result = Reline.readline
- to_write.close
- read_text = to_read.read_nonblock(100)
- assert_equal('a', result)
- refute(read_text.empty?)
- ensure
- input&.close
- output&.close
- to_read&.close
- end
-
- def test_vi_editing_mode
- Reline.vi_editing_mode
- assert_equal(:vi_insert, Reline.core.config.instance_variable_get(:@editing_mode_label))
- end
-
- def test_emacs_editing_mode
- Reline.emacs_editing_mode
- assert_equal(:emacs, Reline.core.config.instance_variable_get(:@editing_mode_label))
- end
-
- def test_add_dialog_proc
- dummy_proc = proc {}
- Reline.add_dialog_proc(:test_proc, dummy_proc)
- d = Reline.dialog_proc(:test_proc)
- assert_equal(dummy_proc, d.dialog_proc)
-
- dummy_proc_2 = proc {}
- Reline.add_dialog_proc(:test_proc, dummy_proc_2)
- d = Reline.dialog_proc(:test_proc)
- assert_equal(dummy_proc_2, d.dialog_proc)
-
- Reline.add_dialog_proc(:test_proc, nil)
- assert_nil(Reline.dialog_proc(:test_proc))
-
- l = lambda {}
- Reline.add_dialog_proc(:test_lambda, l)
- d = Reline.dialog_proc(:test_lambda)
- assert_equal(l, d.dialog_proc)
-
- assert_equal(nil, Reline.dialog_proc(:test_nothing))
-
- assert_raise(ArgumentError) { Reline.add_dialog_proc(:error, 42) }
- assert_raise(ArgumentError) { Reline.add_dialog_proc(:error, 'hoge') }
- assert_raise(ArgumentError) { Reline.add_dialog_proc('error', proc {} ) }
-
- dummy = DummyCallbackObject.new
- Reline.add_dialog_proc(:dummy, dummy)
- d = Reline.dialog_proc(:dummy)
- assert_equal(dummy, d.dialog_proc)
- end
-
- def test_add_dialog_proc_with_context
- dummy_proc = proc {}
- array = Array.new
- Reline.add_dialog_proc(:test_proc, dummy_proc, array)
- d = Reline.dialog_proc(:test_proc)
- assert_equal(dummy_proc, d.dialog_proc)
- assert_equal(array, d.context)
-
- Reline.add_dialog_proc(:test_proc, dummy_proc, nil)
- d = Reline.dialog_proc(:test_proc)
- assert_equal(dummy_proc, d.dialog_proc)
- assert_equal(nil, d.context)
- end
-
- def test_readmultiline
- # readmultiline is module function
- assert_include(Reline.methods, :readmultiline)
- assert_include(Reline.private_instance_methods, :readmultiline)
- end
-
- def test_readline
- # readline is module function
- assert_include(Reline.methods, :readline)
- assert_include(Reline.private_instance_methods, :readline)
- end
-
- def test_read_io
- # TODO in Reline::Core
- end
-
- def test_dumb_terminal
- lib = File.expand_path("../../lib", __dir__)
- out = IO.popen([{"TERM"=>"dumb"}, Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", "p Reline.core.io_gate"], &:read)
- assert_match(/#<Reline::Dumb/, out.chomp)
- end
-
- def test_print_prompt_before_everything_else
- pend if win?
- lib = File.expand_path("../../lib", __dir__)
- code = "p Reline::IOGate.class; p Reline.readline 'prompt> '"
- out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io|
- io.write "abc\n"
- io.close_write
- io.read
- end
- assert_match(/\AReline::ANSI\nprompt> /, out)
- end
-
- def test_read_eof_returns_input
- pend if win?
- lib = File.expand_path("../../lib", __dir__)
- code = "p result: Reline.readline"
- out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io|
- io.write "a\C-a"
- io.close_write
- io.read
- end
- assert_include(out, { result: 'a' }.inspect)
- end
-
- def test_read_eof_returns_nil_if_empty
- pend if win?
- lib = File.expand_path("../../lib", __dir__)
- code = "p result: Reline.readline"
- out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io|
- io.write "a\C-h"
- io.close_write
- io.read
- end
- assert_include(out, { result: nil }.inspect)
- end
-
- def test_require_reline_should_not_trigger_winsize
- pend if win?
- lib = File.expand_path("../../lib", __dir__)
- code = <<~RUBY
- require "io/console"
- def STDIN.tty?; true; end
- def STDOUT.tty?; true; end
- def STDIN.winsize; raise; end
- require("reline") && p(Reline.core.io_gate)
- RUBY
- out = IO.popen([{}, Reline.test_rubybin, "-I#{lib}", "-e", code], &:read)
- assert_include(out.chomp, "Reline::ANSI")
- end
-
- def win?
- /mswin|mingw/.match?(RUBY_PLATFORM)
- end
-
- def test_tty_amibuous_width
- omit unless defined?(PTY)
- ruby_file = Tempfile.create('rubyfile')
- ruby_file.write(<<~RUBY)
- require 'reline'
- Thread.new { sleep 2; puts 'timeout'; exit }
- p [Reline.ambiguous_width, gets.chomp]
- RUBY
- ruby_file.close
- lib = File.expand_path('../../lib', __dir__)
- cmd = [{ 'TERM' => 'xterm' }, Reline.test_rubybin, '-I', lib, ruby_file.to_path]
-
- # Calculate ambiguous width from cursor position
- [1, 2].each do |ambiguous_width|
- PTY.spawn(*cmd) do |r, w, pid|
- loop { break if r.readpartial(1024).include?("\e[6n") }
- w.puts "hello\e[10;#{ambiguous_width + 1}Rworld"
- assert_include(r.gets, [ambiguous_width, 'helloworld'].inspect)
- ensure
- r.close
- w.close
- Process.waitpid pid
- end
- end
-
- # Ambiguous width = 1 when cursor pos timed out
- PTY.spawn(*cmd) do |r, w, pid|
- loop { break if r.readpartial(1024).include?("\e[6n") }
- w.puts "hello\e[10;2Sworld"
- assert_include(r.gets, [1, "hello\e[10;2Sworld"].inspect)
- ensure
- r.close
- w.close
- Process.waitpid pid
- end
- ensure
- File.delete(ruby_file.path) if ruby_file
- end
-
- def get_reline_encoding
- if encoding = Reline.core.encoding
- encoding
- elsif win?
- Encoding::UTF_8
- else
- Encoding::default_external
- end
- end
-end
diff --git a/test/reline/test_reline_key.rb b/test/reline/test_reline_key.rb
deleted file mode 100644
index b6260d57d6..0000000000
--- a/test/reline/test_reline_key.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative 'helper'
-require "reline"
-
-class Reline::TestKey < Reline::TestCase
- def test_match_symbol
- assert(Reline::Key.new('a', :key1, false).match?(:key1))
- refute(Reline::Key.new('a', :key1, false).match?(:key2))
- refute(Reline::Key.new('a', :key1, false).match?(nil))
- end
-end
diff --git a/test/reline/test_string_processing.rb b/test/reline/test_string_processing.rb
deleted file mode 100644
index a105be9aba..0000000000
--- a/test/reline/test_string_processing.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require_relative 'helper'
-
-class Reline::LineEditor::StringProcessingTest < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- @prompt = '> '
- @config = Reline::Config.new
- Reline::HISTORY.instance_variable_set(:@config, @config)
- @line_editor = Reline::LineEditor.new(@config)
- @line_editor.reset(@prompt)
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_calculate_width
- width = @line_editor.send(:calculate_width, 'Ruby string')
- assert_equal('Ruby string'.size, width)
- end
-
- def test_calculate_width_with_escape_sequence
- width = @line_editor.send(:calculate_width, "\1\e[31m\2RubyColor\1\e[34m\2 default string \1\e[m\2>", true)
- assert_equal('RubyColor default string >'.size, width)
- end
-
- def test_completion_proc_with_preposing_and_postposing
- buf = ['def hoge', ' puts :aaa', 'end']
-
- @line_editor.instance_variable_set(:@is_multiline, true)
- @line_editor.instance_variable_set(:@buffer_of_lines, buf)
- @line_editor.instance_variable_set(:@byte_pointer, 6)
- @line_editor.instance_variable_set(:@line_index, 1)
- completion_proc_called = false
- @line_editor.instance_variable_set(:@completion_proc, proc { |target, pre, post|
- assert_equal('puts', target)
- assert_equal("def hoge\n ", pre)
- assert_equal(" :aaa\nend", post)
- completion_proc_called = true
- })
-
- assert_equal(["def hoge\n ", 'puts', " :aaa\nend", nil], @line_editor.retrieve_completion_block)
- @line_editor.__send__(:call_completion_proc, "def hoge\n ", 'puts', " :aaa\nend", nil)
- assert(completion_proc_called)
- end
-end
diff --git a/test/reline/test_unicode.rb b/test/reline/test_unicode.rb
deleted file mode 100644
index 0778306c32..0000000000
--- a/test/reline/test_unicode.rb
+++ /dev/null
@@ -1,286 +0,0 @@
-require_relative 'helper'
-require "reline/unicode"
-
-class Reline::Unicode::Test < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- end
-
- def teardown
- Reline.test_reset
- end
-
- def test_get_mbchar_width
- assert_equal Reline.ambiguous_width, Reline::Unicode.get_mbchar_width('é')
- end
-
- def test_ambiguous_width
- assert_equal 1, Reline::Unicode.calculate_width('√', true)
- end
-
- def test_csi_regexp
- csi_sequences = ["\e[m", "\e[1m", "\e[12;34m", "\e[12;34H"]
- assert_equal(csi_sequences, "text#{csi_sequences.join('text')}text".scan(Reline::Unicode::CSI_REGEXP))
- end
-
- def test_osc_regexp
- osc_sequences = ["\e]1\a", "\e]0;OSC\a", "\e]1\e\\", "\e]0;OSC\e\\"]
- separator = "text\atext"
- assert_equal(osc_sequences, "#{separator}#{osc_sequences.join(separator)}#{separator}".scan(Reline::Unicode::OSC_REGEXP))
- end
-
- def test_split_by_width
- # IRB uses this method.
- assert_equal [['abc', 'de'], 2], Reline::Unicode.split_by_width('abcde', 3)
- end
-
- def test_split_line_by_width
- assert_equal ['abc', 'de'], Reline::Unicode.split_line_by_width('abcde', 3)
- assert_equal ['abc', 'def', ''], Reline::Unicode.split_line_by_width('abcdef', 3)
- assert_equal ['ab', 'あd', 'ef'], Reline::Unicode.split_line_by_width('abあdef', 3)
- assert_equal ['ab[zero]c', 'def', ''], Reline::Unicode.split_line_by_width("ab\1[zero]\2cdef", 3)
- assert_equal ["\e[31mabc", "\e[31md\e[42mef", "\e[31m\e[42mg"], Reline::Unicode.split_line_by_width("\e[31mabcd\e[42mefg", 3)
- assert_equal ["ab\e]0;1\ac", "\e]0;1\ad"], Reline::Unicode.split_line_by_width("ab\e]0;1\acd", 3)
- end
-
- def test_split_line_by_width_csi_reset_sgr_optimization
- assert_equal ["\e[1ma\e[mb\e[2mc", "\e[2md\e[0me\e[3mf", "\e[3mg"], Reline::Unicode.split_line_by_width("\e[1ma\e[mb\e[2mcd\e[0me\e[3mfg", 3)
- assert_equal ["\e[1ma\e[mzero\e[0m\e[2mb", "\e[1m\e[2mc"], Reline::Unicode.split_line_by_width("\e[1ma\1\e[mzero\e[0m\2\e[2mbc", 2)
- end
-
- def test_take_range
- assert_equal 'cdef', Reline::Unicode.take_range('abcdefghi', 2, 4)
- assert_equal 'あde', Reline::Unicode.take_range('abあdef', 2, 4)
- assert_equal '[zero]cdef', Reline::Unicode.take_range("ab\1[zero]\2cdef", 2, 4)
- assert_equal 'b[zero]cde', Reline::Unicode.take_range("ab\1[zero]\2cdef", 1, 4)
- assert_equal "\e[31mcd\e[42mef", Reline::Unicode.take_range("\e[31mabcd\e[42mefg", 2, 4)
- assert_equal "\e]0;1\acd", Reline::Unicode.take_range("ab\e]0;1\acd", 2, 3)
- assert_equal 'いう', Reline::Unicode.take_range('あいうえお', 2, 4)
- end
-
- def test_nonprinting_start_end
- # \1 and \2 should be removed
- assert_equal 'ab[zero]cd', Reline::Unicode.take_range("ab\1[zero]\2cdef", 0, 4)
- assert_equal ['ab[zero]cd', 'ef'], Reline::Unicode.split_line_by_width("ab\1[zero]\2cdef", 4)
- # CSI between \1 and \2 does not need to be applied to the sebsequent line
- assert_equal ["\e[31mab\e[32mcd", "\e[31mef"], Reline::Unicode.split_line_by_width("\e[31mab\1\e[32m\2cdef", 4)
- end
-
- def test_strip_non_printing_start_end
- assert_equal "ab[zero]cd[ze\1ro]ef[zero]", Reline::Unicode.strip_non_printing_start_end("ab\1[zero]\2cd\1[ze\1ro]\2ef\1[zero]")
- end
-
- def test_calculate_width
- assert_equal 9, Reline::Unicode.calculate_width('abcdefghi')
- assert_equal 9, Reline::Unicode.calculate_width('abcdefghi', true)
- assert_equal 7, Reline::Unicode.calculate_width('abあdef')
- assert_equal 7, Reline::Unicode.calculate_width('abあdef', true)
- assert_equal 16, Reline::Unicode.calculate_width("ab\1[zero]\2cdef")
- assert_equal 6, Reline::Unicode.calculate_width("ab\1[zero]\2cdef", true)
- assert_equal 19, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg")
- assert_equal 7, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg", true)
- assert_equal 12, Reline::Unicode.calculate_width("ab\e]0;1\acd")
- assert_equal 4, Reline::Unicode.calculate_width("ab\e]0;1\acd", true)
- assert_equal 10, Reline::Unicode.calculate_width('あいうえお')
- assert_equal 10, Reline::Unicode.calculate_width('あいうえお', true)
- end
-
- def test_take_mbchar_range
- assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4)
- assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, padding: true)
- assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_begin: true)
- assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_end: true)
- assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4)
- assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, padding: true)
- assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_begin: true)
- assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_end: true)
- assert_equal ['う', 4, 2], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4)
- assert_equal [' う ', 3, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, padding: true)
- assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true)
- assert_equal ['うえ', 4, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true)
- assert_equal ['いう ', 2, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true, padding: true)
- assert_equal [' うえ', 3, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true, padding: true)
- assert_equal [' うえお ', 3, 10], Reline::Unicode.take_mbchar_range('あいうえお', 3, 10, padding: true)
- assert_equal [" \e[41mうえお\e[0m ", 3, 10], Reline::Unicode.take_mbchar_range("あい\e[41mうえお", 3, 10, padding: true)
- assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true)
- assert_equal ["\e[31mc[ABC]d\e[0mef", 2, 4], Reline::Unicode.take_mbchar_range("\e[31mabc\1[ABC]\2d\e[0mefghi", 2, 4)
- assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true)
- end
-
- def test_common_prefix
- assert_equal('', Reline::Unicode.common_prefix([]))
- assert_equal('abc', Reline::Unicode.common_prefix(['abc']))
- assert_equal('12', Reline::Unicode.common_prefix(['123', '123️⃣']))
- assert_equal('', Reline::Unicode.common_prefix(['abc', 'xyz']))
- assert_equal('ab', Reline::Unicode.common_prefix(['abcd', 'abc', 'abx', 'abcd']))
- assert_equal('A', Reline::Unicode.common_prefix(['AbcD', 'ABC', 'AbX', 'AbCD']))
- assert_equal('Ab', Reline::Unicode.common_prefix(['AbcD', 'ABC', 'AbX', 'AbCD'], ignore_case: true))
- end
-
- def test_encoding_conversion
- texts = [
- String.new("invalid\xFFutf8", encoding: 'utf-8'),
- String.new("invalid\xFFsjis", encoding: 'sjis'),
- "utf8#{33111.chr('sjis')}convertible",
- "utf8#{33222.chr('sjis')}inconvertible",
- "sjis->utf8->sjis#{60777.chr('sjis')}irreversible"
- ]
- utf8_texts = [
- 'invalid�utf8',
- 'invalid�sjis',
- 'utf8仝convertible',
- 'utf8�inconvertible',
- 'sjis->utf8->sjis劦irreversible'
- ]
- sjis_texts = [
- 'invalid?utf8',
- 'invalid?sjis',
- "utf8#{33111.chr('sjis')}convertible",
- 'utf8?inconvertible',
- "sjis->utf8->sjis#{60777.chr('sjis')}irreversible"
- ]
- assert_equal(utf8_texts, texts.map { |s| Reline::Unicode.safe_encode(s, 'utf-8') })
- assert_equal(utf8_texts, texts.map { |s| Reline::Unicode.safe_encode(s, Encoding::UTF_8) })
- assert_equal(sjis_texts, texts.map { |s| Reline::Unicode.safe_encode(s, 'sjis') })
- assert_equal(sjis_texts, texts.map { |s| Reline::Unicode.safe_encode(s, Encoding::Windows_31J) })
- end
-
- def test_em_forward_word
- assert_equal(12, Reline::Unicode.em_forward_word('abc---fooあbar-baz', 3))
- assert_equal(11, Reline::Unicode.em_forward_word('abc---fooあbar-baz'.encode('sjis'), 3))
- assert_equal(3, Reline::Unicode.em_forward_word('abcfoo', 3))
- assert_equal(3, Reline::Unicode.em_forward_word('abc---', 3))
- assert_equal(0, Reline::Unicode.em_forward_word('abc', 3))
- end
-
- def test_em_forward_word_with_capitalization
- assert_equal([12, '---Fooあbar'], Reline::Unicode.em_forward_word_with_capitalization('abc---foOあBar-baz', 3))
- assert_equal([11, '---Fooあbar'.encode('sjis')], Reline::Unicode.em_forward_word_with_capitalization('abc---foOあBar-baz'.encode('sjis'), 3))
- assert_equal([3, 'Foo'], Reline::Unicode.em_forward_word_with_capitalization('abcfOo', 3))
- assert_equal([3, '---'], Reline::Unicode.em_forward_word_with_capitalization('abc---', 3))
- assert_equal([0, ''], Reline::Unicode.em_forward_word_with_capitalization('abc', 3))
- assert_equal([6, 'Ii̇i̇'], Reline::Unicode.em_forward_word_with_capitalization('ıİİ', 0))
- end
-
- def test_em_backward_word
- assert_equal(12, Reline::Unicode.em_backward_word('abc foo-barあbaz--- xyz', 20))
- assert_equal(11, Reline::Unicode.em_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 19))
- assert_equal(2, Reline::Unicode.em_backward_word(' ', 2))
- assert_equal(2, Reline::Unicode.em_backward_word('ab', 2))
- assert_equal(0, Reline::Unicode.em_backward_word('ab', 0))
- end
-
- def test_em_big_backward_word
- assert_equal(16, Reline::Unicode.em_big_backward_word('abc foo-barあbaz--- xyz', 20))
- assert_equal(15, Reline::Unicode.em_big_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 19))
- assert_equal(2, Reline::Unicode.em_big_backward_word(' ', 2))
- assert_equal(2, Reline::Unicode.em_big_backward_word('ab', 2))
- assert_equal(0, Reline::Unicode.em_big_backward_word('ab', 0))
- end
-
- def test_ed_transpose_words
- # any value that does not trigger transpose
- assert_equal([0, 0, 0, 2], Reline::Unicode.ed_transpose_words('aa bb cc ', 1))
-
- assert_equal([0, 2, 3, 5], Reline::Unicode.ed_transpose_words('aa bb cc ', 2))
- assert_equal([0, 2, 3, 5], Reline::Unicode.ed_transpose_words('aa bb cc ', 4))
- assert_equal([3, 5, 6, 8], Reline::Unicode.ed_transpose_words('aa bb cc ', 5))
- assert_equal([3, 5, 6, 8], Reline::Unicode.ed_transpose_words('aa bb cc ', 7))
- assert_equal([3, 5, 6, 10], Reline::Unicode.ed_transpose_words('aa bb cc ', 8))
- assert_equal([3, 5, 6, 10], Reline::Unicode.ed_transpose_words('aa bb cc ', 9))
- ['sjis', 'utf-8'].each do |encoding|
- texts = ['fooあ', 'barあbaz', 'aaa -', '- -', '- bbb']
- word1, word2, left, middle, right = texts.map { |text| text.encode(encoding) }
- expected = [left.bytesize, (left + word1).bytesize, (left + word1 + middle).bytesize, (left + word1 + middle + word2).bytesize]
- assert_equal(expected, Reline::Unicode.ed_transpose_words(left + word1 + middle + word2 + right, left.bytesize + word1.bytesize))
- assert_equal(expected, Reline::Unicode.ed_transpose_words(left + word1 + middle + word2 + right, left.bytesize + word1.bytesize + middle.bytesize))
- assert_equal(expected, Reline::Unicode.ed_transpose_words(left + word1 + middle + word2 + right, left.bytesize + word1.bytesize + middle.bytesize + word2.bytesize - 1))
- end
- end
-
- def test_vi_big_forward_word
- assert_equal(18, Reline::Unicode.vi_big_forward_word('abc---fooあbar-baz xyz', 3))
- assert_equal(8, Reline::Unicode.vi_big_forward_word('abcfooあ --', 3))
- assert_equal(7, Reline::Unicode.vi_big_forward_word('abcfooあ --'.encode('sjis'), 3))
- assert_equal(6, Reline::Unicode.vi_big_forward_word('abcfooあ', 3))
- assert_equal(3, Reline::Unicode.vi_big_forward_word('abc- ', 3))
- assert_equal(0, Reline::Unicode.vi_big_forward_word('abc', 3))
- end
-
- def test_vi_big_forward_end_word
- assert_equal(4, Reline::Unicode.vi_big_forward_end_word('a bb c', 0))
- assert_equal(4, Reline::Unicode.vi_big_forward_end_word('- bb c', 0))
- assert_equal(1, Reline::Unicode.vi_big_forward_end_word('-a b', 0))
- assert_equal(1, Reline::Unicode.vi_big_forward_end_word('a- b', 0))
- assert_equal(1, Reline::Unicode.vi_big_forward_end_word('aa b', 0))
- assert_equal(3, Reline::Unicode.vi_big_forward_end_word(' aa b', 0))
- assert_equal(15, Reline::Unicode.vi_big_forward_end_word('abc---fooあbar-baz xyz', 3))
- assert_equal(14, Reline::Unicode.vi_big_forward_end_word('abc---fooあbar-baz xyz'.encode('sjis'), 3))
- assert_equal(3, Reline::Unicode.vi_big_forward_end_word('abcfooあ --', 3))
- assert_equal(3, Reline::Unicode.vi_big_forward_end_word('abcfooあ', 3))
- assert_equal(2, Reline::Unicode.vi_big_forward_end_word('abc- ', 3))
- assert_equal(0, Reline::Unicode.vi_big_forward_end_word('abc', 3))
- end
-
- def test_vi_big_backward_word
- assert_equal(16, Reline::Unicode.vi_big_backward_word('abc foo-barあbaz--- xyz', 20))
- assert_equal(15, Reline::Unicode.vi_big_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 19))
- assert_equal(2, Reline::Unicode.vi_big_backward_word(' ', 2))
- assert_equal(2, Reline::Unicode.vi_big_backward_word('ab', 2))
- assert_equal(0, Reline::Unicode.vi_big_backward_word('ab', 0))
- end
-
- def test_vi_forward_word
- assert_equal(3, Reline::Unicode.vi_forward_word('abc---fooあbar-baz', 3))
- assert_equal(9, Reline::Unicode.vi_forward_word('abc---fooあbar-baz', 6))
- assert_equal(8, Reline::Unicode.vi_forward_word('abc---fooあbar-baz'.encode('sjis'), 6))
- assert_equal(6, Reline::Unicode.vi_forward_word('abcfooあ', 3))
- assert_equal(3, Reline::Unicode.vi_forward_word('abc---', 3))
- assert_equal(0, Reline::Unicode.vi_forward_word('abc', 3))
- assert_equal(2, Reline::Unicode.vi_forward_word('abc def', 1, true))
- assert_equal(5, Reline::Unicode.vi_forward_word('abc def', 1, false))
- end
-
- def test_vi_forward_end_word
- assert_equal(2, Reline::Unicode.vi_forward_end_word('abc---fooあbar-baz', 3))
- assert_equal(8, Reline::Unicode.vi_forward_end_word('abc---fooあbar-baz', 6))
- assert_equal(7, Reline::Unicode.vi_forward_end_word('abc---fooあbar-baz'.encode('sjis'), 6))
- assert_equal(3, Reline::Unicode.vi_forward_end_word('abcfooあ', 3))
- assert_equal(2, Reline::Unicode.vi_forward_end_word('abc---', 3))
- assert_equal(0, Reline::Unicode.vi_forward_end_word('abc', 3))
- end
-
- def test_vi_backward_word
- assert_equal(3, Reline::Unicode.vi_backward_word('abc foo-barあbaz--- xyz', 20))
- assert_equal(9, Reline::Unicode.vi_backward_word('abc foo-barあbaz--- xyz', 17))
- assert_equal(8, Reline::Unicode.vi_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 16))
- assert_equal(2, Reline::Unicode.vi_backward_word(' ', 2))
- assert_equal(2, Reline::Unicode.vi_backward_word('ab', 2))
- assert_equal(0, Reline::Unicode.vi_backward_word('ab', 0))
- end
-
- def test_vi_first_print
- assert_equal(3, Reline::Unicode.vi_first_print(' abcdefg'))
- assert_equal(3, Reline::Unicode.vi_first_print(' '))
- assert_equal(0, Reline::Unicode.vi_first_print('abc'))
- assert_equal(0, Reline::Unicode.vi_first_print('あ'))
- assert_equal(0, Reline::Unicode.vi_first_print('あ'.encode('sjis')))
- assert_equal(0, Reline::Unicode.vi_first_print(''))
- end
-
- def test_character_type
- assert(Reline::Unicode.word_character?('a'))
- assert(Reline::Unicode.word_character?('あ'))
- assert(Reline::Unicode.word_character?('あ'.encode('sjis')))
- refute(Reline::Unicode.word_character?(33345.chr('sjis')))
- refute(Reline::Unicode.word_character?('-'))
- refute(Reline::Unicode.word_character?(nil))
-
- assert(Reline::Unicode.space_character?(' '))
- refute(Reline::Unicode.space_character?('あ'))
- refute(Reline::Unicode.space_character?('あ'.encode('sjis')))
- refute(Reline::Unicode.space_character?(33345.chr('sjis')))
- refute(Reline::Unicode.space_character?('-'))
- refute(Reline::Unicode.space_character?(nil))
- end
-end
diff --git a/test/reline/test_within_pipe.rb b/test/reline/test_within_pipe.rb
deleted file mode 100644
index e5d0c12b9c..0000000000
--- a/test/reline/test_within_pipe.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require_relative 'helper'
-
-class Reline::WithinPipeTest < Reline::TestCase
- def setup
- Reline.send(:test_mode)
- @encoding = Reline.core.encoding
- @input_reader, @writer = IO.pipe(@encoding)
- Reline.input = @input_reader
- @reader, @output_writer = IO.pipe(@encoding)
- @output = Reline.output = @output_writer
- @config = Reline.core.config
- @config.keyseq_timeout *= 600 if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # for --jit-wait CI
- @line_editor = Reline.core.line_editor
- end
-
- def teardown
- Reline.input = STDIN
- Reline.output = STDOUT
- Reline.point = 0
- Reline.delete_text
- @input_reader.close
- @writer.close
- @reader.close
- @output_writer.close
- @config.reset
- Reline.test_reset
- end
-
- def test_simple_input
- @writer.write("abc\n")
- assert_equal 'abc', Reline.readmultiline(&proc{ true })
- end
-
- def test_unknown_macro
- @config.add_default_key_binding('abc'.bytes, :unknown_macro)
- @writer.write("abcd\n")
- assert_equal 'd', Reline.readmultiline(&proc{ true })
- end
-
- def test_macro_commands_for_moving
- @config.add_default_key_binding("\C-x\C-a".bytes, :beginning_of_line)
- @config.add_default_key_binding("\C-x\C-e".bytes, :end_of_line)
- @config.add_default_key_binding("\C-x\C-f".bytes, :forward_char)
- @config.add_default_key_binding("\C-x\C-b".bytes, :backward_char)
- @config.add_default_key_binding("\C-x\ef".bytes, :forward_word)
- @config.add_default_key_binding("\C-x\eb".bytes, :backward_word)
- @writer.write(" def\C-x\C-aabc\C-x\C-e ghi\C-x\C-a\C-x\C-f\C-x\C-f_\C-x\C-b\C-x\C-b_\C-x\C-f\C-x\C-f\C-x\C-f\C-x\ef_\C-x\eb\n")
- assert_equal 'a_b_c def_ ghi', Reline.readmultiline(&proc{ true })
- end
-
- def test_macro_commands_for_editing
- @config.add_default_key_binding("\C-x\C-d".bytes, :delete_char)
- @config.add_default_key_binding("\C-x\C-h".bytes, :backward_delete_char)
- @config.add_default_key_binding("\C-x\C-v".bytes, :quoted_insert)
- #@config.add_default_key_binding("\C-xa".bytes, :self_insert)
- @config.add_default_key_binding("\C-x\C-t".bytes, :transpose_chars)
- @config.add_default_key_binding("\C-x\et".bytes, :transpose_words)
- @config.add_default_key_binding("\C-x\eu".bytes, :upcase_word)
- @config.add_default_key_binding("\C-x\el".bytes, :downcase_word)
- @config.add_default_key_binding("\C-x\ec".bytes, :capitalize_word)
- @writer.write("abcde\C-b\C-b\C-b\C-x\C-d\C-x\C-h\C-x\C-v\C-a\C-f\C-f EF\C-x\C-t gh\C-x\et\C-b\C-b\C-b\C-b\C-b\C-b\C-b\C-b\C-x\eu\C-x\el\C-x\ec\n")
- assert_equal "a\C-aDE gh Fe", Reline.readmultiline(&proc{ true })
- end
-
- def test_delete_text_in_multiline
- @writer.write("abc\ndef\nxyz\n")
- result = Reline.readmultiline(&proc{ |str|
- if str.include?('xyz')
- Reline.delete_text
- true
- else
- false
- end
- })
- assert_equal "abc\ndef", result
- end
-end
diff --git a/test/reline/windows/test_key_event_record.rb b/test/reline/windows/test_key_event_record.rb
deleted file mode 100644
index 25c860606a..0000000000
--- a/test/reline/windows/test_key_event_record.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../helper'
-return unless Reline.const_defined?(:Windows)
-
-class Reline::Windows
- class KeyEventRecord::Test < Reline::TestCase
-
- def setup
- # Ctrl+A
- @key = Reline::Windows::KeyEventRecord.new(0x41, 1, Reline::Windows::LEFT_CTRL_PRESSED)
- end
-
- def test_matches__with_no_arguments_raises_error
- assert_raise(ArgumentError) { @key.match? }
- end
-
- def test_matches_char_code
- assert @key.match?(char_code: 0x1)
- end
-
- def test_matches_virtual_key_code
- assert @key.match?(virtual_key_code: 0x41)
- end
-
- def test_matches_control_keys
- assert @key.match?(control_keys: :CTRL)
- end
-
- def test_doesnt_match_alt
- refute @key.match?(control_keys: :ALT)
- end
-
- def test_doesnt_match_empty_control_key
- refute @key.match?(control_keys: [])
- end
-
- def test_matches_control_keys_and_virtual_key_code
- assert @key.match?(control_keys: :CTRL, virtual_key_code: 0x41)
- end
-
- end
-end
diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl
deleted file mode 100755
index 8b82be60f4..0000000000
--- a/test/reline/yamatanooroti/multiline_repl
+++ /dev/null
@@ -1,257 +0,0 @@
-#!/usr/bin/env ruby
-
-
-require 'bundler'
-Bundler.require
-
-require 'reline'
-require 'optparse'
-require_relative 'termination_checker'
-
-opt = OptionParser.new
-opt.on('--dynamic-prompt') {
- Reline.prompt_proc = proc { |lines|
- lines.each_with_index.map { |l, i|
- "\e[1m[%04d]>\e[m " % i
- }
- }
-}
-opt.on('--broken-dynamic-prompt') {
- Reline.prompt_proc = proc { |lines|
- range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0)
- lines[range].each_with_index.map { |l, i|
- '[%04d]> ' % i
- }
- }
-}
-opt.on('--dynamic-prompt-returns-empty') {
- Reline.prompt_proc = proc { |l| [] }
-}
-opt.on('--dynamic-prompt-with-newline') {
- Reline.prompt_proc = proc { |lines|
- range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0)
- lines[range].each_with_index.map { |l, i|
- '[%04d\n]> ' % i
- }
- }
-}
-opt.on('--broken-dynamic-prompt-assert-no-escape-sequence') {
- Reline.prompt_proc = proc { |lines|
- has_escape_sequence = lines.join.include?("\e")
- (lines.size + 1).times.map { |i|
- has_escape_sequence ? 'error>' : '[%04d]> ' % i
- }
- }
-}
-opt.on('--color-bold') {
- Reline.output_modifier_proc = ->(output, complete:){
- output.gsub(/./) { |c| "\e[1m#{c}\e[0m" }
- }
-}
-opt.on('--dynamic-prompt-show-line') {
- Reline.prompt_proc = proc { |lines|
- lines.map { |l|
- '[%4.4s]> ' % l
- }
- }
-}
-
-def assert_auto_indent_params(lines, line_index, byte_pointer, is_newline)
- raise 'Wrong lines type' unless lines.all?(String)
-
- line = lines[line_index]
- raise 'Wrong line_index value' unless line
-
- # The condition `byte_pointer <= line.bytesize` is not satisfied. Maybe bug.
- # Instead, loose constraint `byte_pointer <= line.bytesize + 1` seems to be satisfied when is_newline is false.
- return if is_newline
-
- raise 'byte_pointer out of bounds' unless byte_pointer <= line.bytesize + 1
- raise 'Invalid byte_pointer' unless line.byteslice(0, byte_pointer).valid_encoding?
-end
-
-opt.on('--auto-indent') {
- Reline.auto_indent_proc = lambda do |lines, line_index, byte_pointer, is_newline|
- assert_auto_indent_params(lines, line_index, byte_pointer, is_newline)
- AutoIndent.calculate_indent(lines, line_index, byte_pointer, is_newline)
- end
-}
-opt.on('--dialog VAL') { |v|
- Reline.add_dialog_proc(:simple_dialog, lambda {
- return nil if v.include?('nil')
- if v.include?('simple')
- contents = <<~RUBY.split("\n")
- Ruby is...
- A dynamic, open source programming
- language with a focus on simplicity
- and productivity. It has an elegant
- syntax that is natural to read and
- easy to write.
- RUBY
- elsif v.include?('long')
- contents = <<~RUBY.split("\n")
- Ruby is...
- A dynamic, open
- source programming
- language with a
- focus on simplicity
- and productivity.
- It has an elegant
- syntax that is
- natural to read
- and easy to write.
- RUBY
- elsif v.include?('fullwidth')
- contents = <<~RUBY.split("\n")
- Rubyとは...
-
- オープンソースの動的なプログラミン
- グ言語で、シンプルさと高い生産性を
- 備えています。エレガントな文法を持
- ち、自然に読み書きができます。
- RUBY
- end
- if v.include?('scrollkey')
- dialog.trap_key = nil
- if key and key.match?(dialog.name)
- if dialog.pointer.nil?
- dialog.pointer = 0
- elsif dialog.pointer >= (contents.size - 1)
- dialog.pointer = 0
- else
- dialog.pointer += 1
- end
- end
- dialog.trap_key = [?j.ord]
- height = 4
- end
- scrollbar = false
- if v.include?('scrollbar')
- scrollbar = true
- end
- if v.include?('alt-scrollbar')
- scrollbar = true
- end
- Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar, face: :completion_dialog)
- })
- if v.include?('alt-scrollbar')
- ENV['RELINE_ALT_SCROLLBAR'] = '1'
- end
-}
-opt.on('--complete') {
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- %w{String ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
- }
-}
-opt.on('--complete-menu-with-perfect-match') {
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- %w{abs abs2}.select{ |c| c.start_with?(target) }
- }
-}
-opt.on('--autocomplete') {
- Reline.autocompletion = true
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- %w{String Struct Symbol ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
- }
-}
-opt.on('--autocomplete-empty') {
- Reline.autocompletion = true
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| [] }
-}
-opt.on('--autocomplete-long') {
- Reline.autocompletion = true
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- %w{
- String
- Struct
- Symbol
- StopIteration
- SystemCallError
- SystemExit
- SystemStackError
- ScriptError
- SyntaxError
- Signal
- SizedQueue
- Set
- SecureRandom
- Socket
- StringIO
- StringScanner
- Shellwords
- Syslog
- Singleton
- SDBM
- }.select{ |c| c.start_with?(target) }
- }
-}
-opt.on('--autocomplete-super-long') {
- Reline.autocompletion = true
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- c = +'A'
- 2000.times.map{ s = "Str_#{c}"; c.succ!; s }.select{ |c| c.start_with?(target) }
- }
-}
-
-opt.on('--autocomplete-width-long') {
- Reline.autocompletion = true
- Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
- %w{
- remove_instance_variable
- respond_to?
- ruby2_keywords
- rand
- readline
- readlines
- require
- require_relative
- raise
- respond_to_missing?
- redo
- rescue
- retry
- return
- }.select{ |c| c.start_with?(target) }
- }
-}
-opt.parse!(ARGV)
-
-begin
- stty_save = `stty -g`.chomp
-rescue
-end
-
-begin
- prompt = ENV['RELINE_TEST_PROMPT'] || "\e[1mprompt>\e[m "
- puts 'Multiline REPL.'
- while code = Reline.readmultiline(prompt, true) { |code| TerminationChecker.terminated?(code) }
- case code.chomp
- when 'exit', 'quit', 'q'
- exit 0
- when ''
- # NOOP
- else
- begin
- result = eval(code)
- puts "=> #{result.inspect}"
- rescue ScriptError, StandardError => e
- puts "Traceback (most recent call last):"
- e.backtrace.reverse_each do |f|
- puts " #{f}"
- end
- puts e.message
- end
- end
- end
-rescue Interrupt
- puts '^C'
- `stty #{stty_save}` if stty_save
- exit 0
-ensure
- `stty #{stty_save}` if stty_save
-end
-begin
- puts
-rescue Errno::EIO
- # Maybe the I/O has been closed.
-end
diff --git a/test/reline/yamatanooroti/termination_checker.rb b/test/reline/yamatanooroti/termination_checker.rb
deleted file mode 100644
index b97c798c59..0000000000
--- a/test/reline/yamatanooroti/termination_checker.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require 'ripper'
-
-module TerminationChecker
- def self.terminated?(code)
- Ripper.sexp(code) ? true : false
- end
-end
-
-module AutoIndent
- def self.calculate_indent(lines, line_index, byte_pointer, is_newline)
- if is_newline
- 2 * nesting_level(lines[0..line_index - 1])
- else
- lines = lines.dup
- lines[line_index] = lines[line_index]&.byteslice(0, byte_pointer)
- prev_level = nesting_level(lines[0..line_index - 1])
- level = nesting_level(lines[0..line_index])
- 2 * level if level < prev_level
- end
- end
-
- def self.nesting_level(lines)
- code = lines.join("\n")
- code.scan(/if|def|\(|\[|\{/).size - code.scan(/end|\)|\]|\}/).size
- end
-end
diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb
deleted file mode 100644
index aff5c0462b..0000000000
--- a/test/reline/yamatanooroti/test_rendering.rb
+++ /dev/null
@@ -1,1915 +0,0 @@
-require 'reline'
-
-begin
- require 'yamatanooroti'
-
- class Reline::RenderingTest < Yamatanooroti::TestCase
-
- FACE_CONFIGS = { no_config: "", valid_config: <<~VALID_CONFIG, incomplete_config: <<~INCOMPLETE_CONFIG }
- require "reline"
- Reline::Face.config(:completion_dialog) do |face|
- face.define :default, foreground: :white, background: :blue
- face.define :enhanced, foreground: :white, background: :magenta
- face.define :scrollbar, foreground: :white, background: :blue
- end
- VALID_CONFIG
- require "reline"
- Reline::Face.config(:completion_dialog) do |face|
- face.define :default, foreground: :white, background: :black
- face.define :scrollbar, foreground: :white, background: :cyan
- end
- INCOMPLETE_CONFIG
-
- def iterate_over_face_configs(&block)
- FACE_CONFIGS.each do |config_name, face_config|
- config_file = Tempfile.create(%w{face_config- .rb})
- config_file.write face_config
- block.call(config_name, config_file)
- ensure
- config_file.close
- File.delete(config_file)
- end
- end
-
- def setup
- @pwd = Dir.pwd
- suffix = '%010d' % Random.rand(0..65535)
- @tmpdir = File.join(File.expand_path(Dir.tmpdir), "test_reline_config_#{$$}_#{suffix}")
- begin
- Dir.mkdir(@tmpdir)
- rescue Errno::EEXIST
- FileUtils.rm_rf(@tmpdir)
- Dir.mkdir(@tmpdir)
- end
- @inputrc_backup = ENV['INPUTRC']
- @inputrc_file = ENV['INPUTRC'] = File.join(@tmpdir, 'temporaty_inputrc')
- File.unlink(@inputrc_file) if File.exist?(@inputrc_file)
- end
-
- def teardown
- FileUtils.rm_rf(@tmpdir)
- ENV['INPUTRC'] = @inputrc_backup
- ENV.delete('RELINE_TEST_PROMPT') if ENV['RELINE_TEST_PROMPT']
- end
-
- def test_history_back
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":a\n")
- write("\C-p")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> :a
- => :a
- prompt> :a
- EOC
- close
- end
-
- def test_backspace
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":abc\C-h\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> :ab
- => :ab
- prompt>
- EOC
- close
- end
-
- def test_autowrap
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write('01234567890123456789012')
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> 0123456789012345678901
- 2
- EOC
- close
- end
-
- def test_fullwidth
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":あ\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> :あ
- => :あ
- prompt>
- EOC
- close
- end
-
- def test_two_fullwidth
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":あい\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> :あい
- => :あい
- prompt>
- EOC
- close
- end
-
- def test_finish_autowrapped_line
- start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("[{'user'=>{'email'=>'a@a', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}]\n")
- expected = [{'user'=>{'email'=>'a@a', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}].inspect
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> [{'user'=>{'email'=>'a@a', 'id'=
- >'ABC'}, 'version'=>4, 'status'=>'succee
- ded'}]
- #{fold_multiline("=> " + expected, 40)}
- prompt>
- EOC
- close
- end
-
- def test_finish_autowrapped_line_in_the_middle_of_lines
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("[{'user'=>{'email'=>'abcdef@abcdef', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}]#{"\C-b"*7}")
- write("\n")
- expected = [{'user'=>{'email'=>'abcdef@abcdef', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}].inspect
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> [{'user'=>{'email'=>'a
- bcdef@abcdef', 'id'=>'ABC'}, '
- version'=>4, 'status'=>'succee
- ded'}]
- #{fold_multiline("=> " + expected, 30)}
- prompt>
- EOC
- close
- end
-
- def test_finish_autowrapped_line_in_the_middle_of_multilines
- omit if RUBY_VERSION < '2.7'
- start_terminal(30, 16, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("<<~EOM\n ABCDEFG\nEOM\n")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> <<~EOM
- prompt> ABCDEF
- G
- prompt> EOM
- => "ABCDEFG\n"
- prompt>
- EOC
- close
- end
-
- def test_prompt
- write_inputrc <<~'LINES'
- "abc": "123"
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("abc\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> 123
- => 123
- prompt>
- EOC
- close
- end
-
- def test_mode_string_emacs
- write_inputrc <<~LINES
- set show-mode-in-prompt on
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- assert_screen(<<~EOC)
- Multiline REPL.
- @prompt>
- EOC
- close
- end
-
- def test_mode_string_vi
- write_inputrc <<~LINES
- set editing-mode vi
- set show-mode-in-prompt on
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":a\n\C-[k")
- write("i\n:a")
- write("\C-[h")
- assert_screen(<<~EOC)
- (ins)prompt> :a
- => :a
- (ins)prompt> :a
- => :a
- (cmd)prompt> :a
- EOC
- close
- end
-
- def test_original_mode_string_emacs
- write_inputrc <<~LINES
- set show-mode-in-prompt on
- set emacs-mode-string [emacs]
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- assert_screen(<<~EOC)
- Multiline REPL.
- [emacs]prompt>
- EOC
- close
- end
-
- def test_original_mode_string_with_quote
- write_inputrc <<~LINES
- set show-mode-in-prompt on
- set emacs-mode-string "[emacs]"
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- assert_screen(<<~EOC)
- Multiline REPL.
- [emacs]prompt>
- EOC
- close
- end
-
- def test_original_mode_string_vi
- write_inputrc <<~LINES
- set editing-mode vi
- set show-mode-in-prompt on
- set vi-ins-mode-string "{InS}"
- set vi-cmd-mode-string "{CmD}"
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":a\n\C-[k")
- assert_screen(<<~EOC)
- Multiline REPL.
- {InS}prompt> :a
- => :a
- {CmD}prompt> :a
- EOC
- close
- end
-
- def test_mode_string_vi_changing
- write_inputrc <<~LINES
- set editing-mode vi
- set show-mode-in-prompt on
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":a\C-[ab\C-[ac\C-h\C-h\C-h\C-h:a")
- assert_screen(<<~EOC)
- Multiline REPL.
- (ins)prompt> :a
- EOC
- close
- end
-
- def test_esc_input
- omit if Reline::IOGate.win?
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def\C-aabc")
- write("\e") # single ESC
- sleep 1
- write("A")
- write("B\eAC") # ESC + A (M-A, no key specified in Reline::KeyActor::Emacs)
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> abcABCdef
- EOC
- close
- end
-
- def test_prompt_with_escape_sequence
- ENV['RELINE_TEST_PROMPT'] = "\1\e[30m\2prompt> \1\e[m\2"
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("123\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> 123
- => 123
- prompt>
- EOC
- close
- end
-
- def test_prompt_with_escape_sequence_and_autowrap
- ENV['RELINE_TEST_PROMPT'] = "\1\e[30m\2prompt> \1\e[m\2"
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("1234567890123\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> 123456789012
- 3
- => 1234567890123
- prompt>
- EOC
- close
- end
-
- def test_readline_with_multiline_input
- start_terminal(5, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt}, startup_message: 'Multiline REPL.')
- write("def foo\n bar\nend\n")
- write("Reline.readline('prompt> ')\n")
- write("\C-p\C-p")
- assert_screen(<<~EOC)
- => :foo
- [0000]> Reline.readline('prompt> ')
- prompt> def foo
- bar
- end
- EOC
- close
- end
-
- def test_multiline_and_autowrap
- start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def aaaaaaaaaa\n 33333333\n end\C-a\C-pputs\C-e\e\C-m888888888888888")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def aaaaaaaa
- aa
- prompt> puts 333333
- 33
- prompt> 888888888888
- 888
- prompt> e
- nd
- EOC
- close
- end
-
- def test_multiline_add_new_line_and_autowrap
- start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def aaaaaaaaaa")
- write("\n")
- write(" bbbbbbbbbbbb")
- write("\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def aaaaaaaa
- aa
- prompt> bbbbbbbbbb
- bb
- prompt>
- EOC
- close
- end
-
- def test_clear
- start_terminal(10, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("3\C-l")
- assert_screen(<<~EOC)
- prompt> 3
- EOC
- close
- end
-
- def test_clear_multiline_and_autowrap
- start_terminal(10, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def aaaaaa\n 3\n\C-lend")
- assert_screen(<<~EOC)
- prompt> def aaa
- aaa
- prompt> 3
- prompt> end
- EOC
- close
- end
-
- def test_nearest_cursor
- start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def ああ\n :いい\nend\C-pbb\C-pcc")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def ccああ
- prompt> :bbいい
- prompt> end
- EOC
- close
- end
-
- def test_delete_line
- start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def a\n\nend\C-p\C-h")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def a
- prompt> end
- EOC
- close
- end
-
- def test_last_line_of_screen
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("\n\n\n\n\ndef a\nend")
- assert_screen(<<~EOC)
- prompt>
- prompt>
- prompt>
- prompt> def a
- prompt> end
- EOC
- close
- end
-
- # c17a09b7454352e2aff5a7d8722e80afb73e454b
- def test_autowrap_at_last_line_of_screen
- start_terminal(5, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def a\nend\n\C-p")
- assert_screen(<<~EOC)
- prompt> def a
- prompt> end
- => :a
- prompt> def a
- prompt> end
- EOC
- close
- end
-
- # f002483b27cdb325c5edf9e0fe4fa4e1c71c4b0e
- def test_insert_line_in_the_middle_of_line
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("333\C-b\C-b\e\C-m8")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> 3
- prompt> 833
- EOC
- close
- end
-
- # 9d8978961c5de5064f949d56d7e0286df9e18f43
- def test_insert_line_in_the_middle_of_line_at_last_line_of_screen
- start_terminal(3, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("333333333333333\C-a\C-f\e\C-m")
- assert_screen(<<~EOC)
- prompt> 3
- prompt> 333333333333
- 33
- EOC
- close
- end
-
- def test_insert_after_clear
- start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def a\n 01234\nend\C-l\C-p5678")
- assert_screen(<<~EOC)
- prompt> def a
- prompt> 056781234
- prompt> end
- EOC
- close
- end
-
- def test_foced_newline_insertion
- start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- #write("def a\nend\C-p\C-e\e\C-m 3")
- write("def a\nend\C-p\C-e\e\x0D")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def a
- prompt>
- prompt> end
- EOC
- close
- end
-
- def test_multiline_incremental_search
- start_terminal(6, 25, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def a\n 8\nend\ndef b\n 3\nend\C-s8")
- assert_screen(<<~EOC)
- prompt> 8
- prompt> end
- => :a
- (i-search)`8'def a
- (i-search)`8' 8
- (i-search)`8'end
- EOC
- close
- end
-
- def test_multiline_incremental_search_finish
- start_terminal(6, 25, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def a\n 8\nend\ndef b\n 3\nend\C-r8\C-j")
- assert_screen(<<~EOC)
- prompt> 8
- prompt> end
- => :a
- prompt> def a
- prompt> 8
- prompt> end
- EOC
- close
- end
-
- def test_binding_for_vi_movement_mode
- write_inputrc <<~LINES
- set editing-mode vi
- "\\C-a": vi-movement-mode
- LINES
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(":1234\C-ahhhi0")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> :01234
- EOC
- close
- end
-
- def test_broken_prompt_list
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --broken-dynamic-prompt}, startup_message: 'Multiline REPL.')
- write("def hoge\n 3\nend")
- assert_screen(<<~EOC)
- Multiline REPL.
- [0000]> def hoge
- [0001]> 3
- [0001]> end
- EOC
- close
- end
-
- def test_no_escape_sequence_passed_to_dynamic_prompt
- start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --color-bold --broken-dynamic-prompt-assert-no-escape-sequence}, startup_message: 'Multiline REPL.')
- write("%[ S")
- write("\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- [0000]> %[ S
- [0001]>
- EOC
- close
- end
-
- def test_bracketed_paste
- omit if Reline.core.io_gate.win?
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("\e[200~def hoge\r\t3\rend\e[201~")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt> 3
- prompt> end
- EOC
- write("\e[200~.tap do\r\t4\r\t5\rend\e[201~")
- assert_screen(<<~EOC)
- prompt> 3
- prompt> end.tap do
- prompt> 4
- prompt> 5
- prompt> end
- EOC
- close
- end
-
- def test_bracketed_paste_with_undo_redo
- omit if Reline.core.io_gate.win?
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("abc")
- write("\e[200~def hoge\r\t3\rend\e[201~")
- write("\C-_")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> abc
- EOC
- write("\e\C-_")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> abcdef hoge
- prompt> 3
- prompt> end
- EOC
- close
- end
-
- def test_backspace_until_returns_to_initial
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("ABC")
- write("\C-h\C-h\C-h")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt>
- EOC
- close
- end
-
- def test_longer_than_screen_height
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(<<~EOC.chomp)
- def each_top_level_statement
- initialize_input
- catch(:TERM_INPUT) do
- loop do
- begin
- prompt
- unless l = lex
- throw :TERM_INPUT if @line == ''
- else
- @line_no += l.count("\n")
- next if l == "\n"
- @line.concat l
- if @code_block_open or @ltype or @continue or @indent > 0
- next
- end
- end
- if @line != "\n"
- @line.force_encoding(@io.encoding)
- yield @line, @exp_line_no
- end
- break if @io.eof?
- @line = ''
- @exp_line_no = @line_no
- #
- @indent = 0
- rescue TerminateLineInput
- initialize_input
- prompt
- end
- end
- end
- end
- EOC
- assert_screen(<<~EOC)
- prompt> prompt
- prompt> end
- prompt> end
- prompt> end
- prompt> end
- EOC
- write("\C-p" * 6)
- assert_screen(<<~EOC)
- prompt> rescue Terminate
- LineInput
- prompt> initialize_inp
- ut
- prompt> prompt
- EOC
- write("\C-n" * 4)
- assert_screen(<<~EOC)
- prompt> initialize_inp
- ut
- prompt> prompt
- prompt> end
- prompt> end
- EOC
- close
- end
-
- def test_longer_than_screen_height_nearest_cursor_with_scroll_back
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write(<<~EOC.chomp)
- if 1
- if 2
- if 3
- if 4
- puts
- end
- end
- end
- end
- EOC
- write("\C-p" * 4 + "\C-e" + "\C-p" * 4)
- write("2")
- assert_screen(<<~EOC)
- prompt> if 12
- prompt> if 2
- prompt> if 3
- prompt> if 4
- prompt> puts
- EOC
- close
- end
-
- def test_update_cursor_correctly_when_just_cursor_moving
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def hoge\n 01234678")
- write("\C-p")
- write("\C-b")
- write("\C-n")
- write('5')
- write("\C-e")
- write('9')
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt> 0123456789
- EOC
- close
- end
-
- def test_auto_indent
- start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- "def hoge\nputs(\n1,\n2\n)\nend".lines do |line|
- write line
- end
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt> puts(
- prompt> 1,
- prompt> 2
- prompt> )
- prompt> end
- EOC
- close
- end
-
- def test_auto_indent_when_inserting_line
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write 'aa(bb(cc(dd(ee('
- write "\C-b" * 5 + "\n"
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> aa(bb(cc(d
- prompt> d(ee(
- EOC
- close
- end
-
- def test_auto_indent_multibyte_insert_line
- start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write "if true\n"
- write "あいうえお\n"
- 4.times { write "\C-b\C-b\C-b\C-b\e\r" }
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> if true
- prompt> あ
- prompt> い
- prompt> う
- prompt> え
- prompt> お
- prompt>
- EOC
- close
- end
-
- def test_newline_after_wrong_indent
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write "if 1\n aa"
- write "\n"
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> if 1
- prompt> aa
- prompt>
- EOC
- close
- end
-
- def test_suppress_auto_indent_just_after_pasted
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write("def hoge\n [[\n 3]]\ned")
- write("\C-bn")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt> [[
- prompt> 3]]
- prompt> end
- EOC
- close
- end
-
- def test_suppress_auto_indent_for_adding_newlines_in_pasting
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write("<<~Q\n")
- write("{\n #\n}")
- write("#")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> <<~Q
- prompt> {
- prompt> #
- prompt> }#
- EOC
- close
- end
-
- def test_auto_indent_with_various_spaces
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write "(\n\C-v"
- write "\C-k\n\C-v"
- write "\C-k)"
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> (
- prompt> ^K
- prompt> )
- EOC
- close
- end
-
- def test_autowrap_in_the_middle_of_a_line
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def abcdefg; end\C-b\C-b\C-b\C-b\C-b")
- %w{h i}.each do |c|
- write(c)
- end
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def abcdefgh
- i; end
- EOC
- close
- end
-
- def test_newline_in_the_middle_of_lines
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def hoge\n 1\n 2\n 3\n 4\nend\n")
- write("\C-p\C-p\C-p\C-e\n")
- assert_screen(<<~EOC)
- prompt> def hoge
- prompt> 1
- prompt> 2
- prompt> 3
- prompt>
- EOC
- close
- end
-
- def test_ed_force_submit_in_the_middle_of_lines
- write_inputrc <<~LINES
- "\\C-a": ed_force_submit
- LINES
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def hoge\nend")
- write("\C-p\C-a")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt> end
- => :hoge
- prompt>
- EOC
- close
- end
-
- def test_dynamic_prompt_returns_empty
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-returns-empty}, startup_message: 'Multiline REPL.')
- write("def hoge\nend\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt> end
- => :hoge
- prompt>
- EOC
- close
- end
-
- def test_reset_rest_height_when_clear_screen
- start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("\n\n\n\C-l3\n")
- assert_screen(<<~EOC)
- prompt> 3
- => 3
- prompt>
- EOC
- close
- end
-
- def test_meta_key
- start_terminal(30, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def ge\ebho")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- EOC
- close
- end
-
- def test_not_meta_key
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("おだんご") # "だ" in UTF-8 contains "\xA0"
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> おだんご
- EOC
- close
- end
-
- def test_force_enter
- start_terminal(30, 120, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def hoge\nend\C-p\C-e")
- write("\e\x0D")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> def hoge
- prompt>
- prompt> end
- EOC
- close
- end
-
- def test_nontty
- omit if Reline.core.io_gate.win?
- cmd = %Q{ruby -e 'puts(%Q{ello\C-ah\C-e})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })' | ruby -e 'print STDIN.read'}
- start_terminal(40, 50, ['bash', '-c', cmd])
- assert_screen(<<~'EOC')
- > hello
- "hello"
- EOC
- close
- end
-
- def test_eof_with_newline
- omit if Reline.core.io_gate.win?
- cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
- start_terminal(40, 50, ['bash', '-c', cmd])
- assert_screen(<<~'EOC')
- > abc def
- "abc def "
- EOC
- close
- end
-
- def test_eof_without_newline
- omit if Reline.core.io_gate.win?
- cmd = %Q{ruby -e 'print(%{hello})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'}
- start_terminal(40, 50, ['bash', '-c', cmd])
- assert_screen(<<~'EOC')
- > hello
- "hello"
- EOC
- close
- end
-
- def test_em_set_mark_and_em_exchange_mark
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("aaa bbb ccc ddd\eb\eb\e\x20\eb\C-x\C-xX\C-x\C-xY")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> aaa Ybbb Xccc ddd
- EOC
- close
- end
-
- def test_multiline_completion
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
- write("def hoge\n St\n St\C-p\t")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> def hoge
- prompt> String
- prompt> St
- EOC
- close
- end
-
- def test_completion_journey_2nd_line
- write_inputrc <<~LINES
- set editing-mode vi
- LINES
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
- write("def hoge\n S\C-n")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> def hoge
- prompt> String
- EOC
- close
- end
-
- def test_completion_journey_with_empty_line
- write_inputrc <<~LINES
- set editing-mode vi
- LINES
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
- write("\C-n\C-p")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt>
- EOC
- close
- end
-
- def test_completion_menu_is_displayed_horizontally
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
- write("S\t\t")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> S
- ScriptError String
- Signal SyntaxError
- EOC
- close
- end
-
- def test_show_all_if_ambiguous_on
- write_inputrc <<~LINES
- set show-all-if-ambiguous on
- LINES
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.')
- write("S\t")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> S
- ScriptError String
- Signal SyntaxError
- EOC
- close
- end
-
- def test_show_all_if_ambiguous_on_and_menu_with_perfect_match
- write_inputrc <<~LINES
- set show-all-if-ambiguous on
- LINES
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete-menu-with-perfect-match}, startup_message: 'Multiline REPL.')
- write("a\t")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> abs
- abs abs2
- EOC
- close
- end
-
- def test_simple_dialog
- iterate_over_face_configs do |config_name, config_file|
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
- write('a')
- write('b')
- write('c')
- write("\C-h")
- close
- assert_screen(<<~'EOC', "Failed with `#{config_name}` in Face")
- Multiline REPL.
- prompt> ab
- Ruby is...
- A dynamic, open source programming
- language with a focus on simplicity
- and productivity. It has an elegant
- syntax that is natural to read and
- easy to write.
- EOC
- end
- end
-
- def test_simple_dialog_at_right_edge
- iterate_over_face_configs do |config_name, config_file|
- start_terminal(20, 40, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
- write('a')
- write('b')
- write('c')
- write("\C-h")
- close
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> ab
- Ruby is...
- A dynamic, open source programming
- language with a focus on simplicity
- and productivity. It has an elegant
- syntax that is natural to read and
- easy to write.
- EOC
- end
- end
-
- def test_dialog_scroll_pushup_condition
- iterate_over_face_configs do |config_name, config_file|
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("\n" * 10)
- write("if 1\n sSts\nend")
- write("\C-p\C-h\C-e\C-h")
- assert_screen(<<~'EOC')
- prompt>
- prompt>
- prompt>
- prompt>
- prompt>
- prompt>
- prompt> if 1
- prompt> St
- prompt> enString
- Struct
- EOC
- close
- end
- end
-
- def test_simple_dialog_with_scroll_screen
- iterate_over_face_configs do |config_name, config_file|
- start_terminal(5, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: /prompt>/)
- write("if 1\n 2\n 3\n 4\n 5\n 6")
- write("\C-p\C-n\C-p\C-p\C-p#")
- close
- assert_screen(<<~'EOC')
- prompt> 2
- prompt> 3#
- prompt> 4
- prompt> 5 Ruby is...
- prompt> 6 A dynamic, open source programming
- EOC
- end
- end
-
- def test_autocomplete_at_bottom
- start_terminal(15, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write('def hoge' + "\C-m" * 10 + "end\C-p ")
- write('S')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> def hoge
- prompt>
- prompt>
- prompt> String
- prompt> Struct
- prompt> Symbol
- prompt> ScriptError
- prompt> SyntaxError
- prompt> Signal
- prompt> S
- prompt> end
- EOC
- close
- end
-
- def test_autocomplete_return_to_original
- start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write('S')
- write('t')
- write('r')
- 3.times{ write("\C-i") }
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Str
- String
- Struct
- EOC
- close
- end
-
- def test_autocomplete_target_is_wrapped
- start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write(' ')
- write('S')
- write('t')
- write('r')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> St
- r
- String
- Struct
- EOC
- close
- end
-
- def test_autocomplete_target_at_end_of_line
- start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write(' ')
- write('Str')
- write("\C-i")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Str
- ing String
- Struct
- EOC
- close
- end
-
- def test_autocomplete_completed_input_is_wrapped
- start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write(' ')
- write('Str')
- write("\C-i")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Stri
- ng String
- Struct
- EOC
- close
- end
-
- def test_force_insert_before_autocomplete
- start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write('Sy')
- write(";St\t\t")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Sy;Struct
- String
- Struct
- EOC
- close
- end
-
- def test_simple_dialog_with_scroll_key
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey}, startup_message: 'Multiline REPL.')
- write('a')
- 5.times{ write('j') }
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> a
- A dynamic, open
- source programming
- language with a
- focus on simplicity
- EOC
- close
- end
-
- def test_simple_dialog_scrollbar_with_moving_to_right
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey,scrollbar}, startup_message: 'Multiline REPL.')
- 6.times{ write('j') }
- write('a')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> a
- source programming ▄
- language with a █
- focus on simplicity
- and productivity.
- EOC
- close
- end
-
- def test_simple_dialog_scrollbar_with_moving_to_left
- start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey,scrollbar}, startup_message: 'Multiline REPL.')
- write('a')
- 6.times{ write('j') }
- write("\C-h")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt>
- source programming ▄
- language with a █
- focus on simplicity
- and productivity.
- EOC
- close
- end
-
- def test_dialog_with_fullwidth_chars
- ENV['RELINE_TEST_PROMPT'] = '> '
- start_terminal(20, 5, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.')
- 6.times{ write('j') }
- assert_screen(<<~'EOC')
- Multi
- line
- REPL.
- >
- オー
- グ言▄
- 備え█
- ち、█
- EOC
- close
- end
-
- def test_dialog_with_fullwidth_chars_split
- ENV['RELINE_TEST_PROMPT'] = '> '
- start_terminal(20, 6, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.')
- 6.times{ write('j') }
- assert_screen(<<~'EOC')
- Multil
- ine RE
- PL.
- >
- オー
- グ言 ▄
- 備え █
- ち、 █
- EOC
- close
- end
-
- def test_autocomplete_empty
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write('Street')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Street
- EOC
- close
- end
-
- def test_autocomplete
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write('Str')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Str
- String
- Struct
- EOC
- close
- end
-
- def test_autocomplete_empty_string
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("\C-i")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> String
- String █
- Struct ▀
- Symbol
- EOC
- close
- end
-
- def test_paste_code_with_tab_indent_does_not_fail
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-empty}, startup_message: 'Multiline REPL.')
- write("2.times do\n\tputs\n\tputs\nend")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> 2.times do
- prompt> puts
- prompt> puts
- prompt> end
- EOC
- close
- end
-
- def test_autocomplete_after_2nd_line
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("def hoge\n Str")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> def hoge
- prompt> Str
- String
- Struct
- EOC
- close
- end
-
- def test_autocomplete_rerender_under_dialog
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("def hoge\n\n 123456\n 456789\nend\C-p\C-p\C-p a = Str")
- write('i')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> def hoge
- prompt> a = Stri
- prompt> 1234String
- prompt> 456789
- prompt> end
- EOC
- close
- end
-
- def test_rerender_multiple_dialog
- start_terminal(20, 60, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --dialog simple}, startup_message: 'Multiline REPL.')
- write("if\n abcdef\n 123456\n 456789\nend\C-p\C-p\C-p\C-p Str")
- write("\t")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> if String
- prompt> aStringRuby is...
- prompt> 1StructA dynamic, open source programming
- prompt> 456789 language with a focus on simplicity
- prompt> end and productivity. It has an elegant
- syntax that is natural to read and
- easy to write.
- EOC
- close
- end
-
- def test_autocomplete_long_with_scrollbar
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.')
- write('S')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> S
- String █
- Struct █
- Symbol █
- StopIteration █
- SystemCallError █
- SystemExit █
- SystemStackError█
- ScriptError █
- SyntaxError █
- Signal █
- SizedQueue █
- Set
- SecureRandom
- Socket
- StringIO
- EOC
- write("\C-i" * 16)
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> StringScanner
- Struct ▄
- Symbol █
- StopIteration █
- SystemCallError █
- SystemExit █
- SystemStackError█
- ScriptError █
- SyntaxError █
- Signal █
- SizedQueue █
- Set █
- SecureRandom ▀
- Socket
- StringIO
- StringScanner
- EOC
- close
- end
-
- def test_autocomplete_super_long_scroll_to_bottom
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.')
- shift_tab = [27, 91, 90]
- write('S' + shift_tab.map(&:chr).join)
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Str_BXX
- Str_BXJ
- Str_BXK
- Str_BXL
- Str_BXM
- Str_BXN
- Str_BXO
- Str_BXP
- Str_BXQ
- Str_BXR
- Str_BXS
- Str_BXT
- Str_BXU
- Str_BXV
- Str_BXW
- Str_BXX▄
- EOC
- close
- end
-
- def test_autocomplete_super_long_and_backspace
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.')
- shift_tab = [27, 91, 90]
- write('S' + shift_tab.map(&:chr).join)
- write("\C-h")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> Str_BX
- Str_BX █
- Str_BXA█
- Str_BXB█
- Str_BXC█
- Str_BXD█
- Str_BXE█
- Str_BXF█
- Str_BXG█
- Str_BXH█
- Str_BXI
- Str_BXJ
- Str_BXK
- Str_BXL
- Str_BXM
- Str_BXN
- EOC
- close
- end
-
- def test_dialog_callback_returns_nil
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog nil}, startup_message: 'Multiline REPL.')
- write('a')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> a
- EOC
- close
- end
-
- def test_dialog_narrower_than_screen
- start_terminal(20, 11, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.')
- assert_screen(<<~'EOC')
- Multiline R
- EPL.
- prompt>
- Ruby is...
- A dynamic,
- language wi
- and product
- syntax that
- easy to wri
- EOC
- close
- end
-
- def test_dialog_narrower_than_screen_with_scrollbar
- start_terminal(20, 11, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.')
- write('S' + "\C-i" * 3)
- assert_screen(<<~'EOC')
- Multiline R
- EPL.
- prompt> Sym
- String █
- Struct █
- Symbol █
- StopIterat█
- SystemCall█
- SystemExit█
- SystemStac█
- ScriptErro█
- SyntaxErro█
- Signal █
- SizedQueue█
- Set
- SecureRand
- Socket
- StringIO
- EOC
- close
- end
-
- def test_dialog_with_fullwidth_scrollbar
- start_terminal(20, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple,scrollkey,alt-scrollbar}, startup_message: 'Multiline REPL.')
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt>
- Ruby is... ::
- A dynamic, open source programming ::
- language with a focus on simplicity''
- and productivity. It has an elegant
- EOC
- close
- end
-
- def test_rerender_argument_prompt_after_pasting
- start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write('abcdef')
- write("\e3\C-h")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> abc
- EOC
- close
- end
-
- def test_autocomplete_old_dialog_width_greater_than_dialog_width
- start_terminal(40, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-width-long}, startup_message: 'Multiline REPL.')
- write("0+ \n12345678901234")
- write("\C-p")
- write("r")
- write("a")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> 0+ ra
- prompt> 123rand 901234
- raise
- EOC
- close
- end
-
- def test_scroll_at_bottom_for_dialog
- start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("\n\n\n\n\n\n\n\n\n\n\n")
- write("def hoge\n\nend\C-p\C-e")
- write(" S")
- assert_screen(<<~'EOC')
- prompt>
- prompt>
- prompt>
- prompt>
- prompt>
- prompt> def hoge
- prompt> S
- prompt> enString █
- Struct ▀
- Symbol
- EOC
- close
- end
-
- def test_clear_dialog_in_pasting
- start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("S")
- write("tring ")
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt> String
- EOC
- close
- end
-
- def test_prompt_with_newline
- ENV['RELINE_TEST_PROMPT'] = "::\n> "
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("def hoge\n 3\nend")
- assert_screen(<<~'EOC')
- Multiline REPL.
- ::\n> def hoge
- ::\n> 3
- ::\n> end
- EOC
- close
- end
-
- def test_dynamic_prompt_with_newline
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-with-newline}, startup_message: 'Multiline REPL.')
- write("def hoge\n 3\nend")
- assert_screen(<<~'EOC')
- Multiline REPL.
- [0000\n]> def hoge
- [0001\n]> 3
- [0001\n]> end
- EOC
- close
- end
-
- def test_lines_passed_to_dynamic_prompt
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-show-line}, startup_message: 'Multiline REPL.')
- write("if true")
- write("\n")
- assert_screen(<<~EOC)
- Multiline REPL.
- [if t]> if true
- [ ]>
- EOC
- close
- end
-
- def test_clear_dialog_when_just_move_cursor_at_last_line
- start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("class A\n 3\nend\n\n\n")
- write("\C-p\C-p\C-e; S")
- assert_screen(/String/)
- write("\C-n")
- write(";")
- assert_screen(<<~'EOC')
- prompt> 3
- prompt> end
- => 3
- prompt>
- prompt>
- prompt> class A
- prompt> 3; S
- prompt> end;
- EOC
- close
- end
-
- def test_clear_dialog_when_adding_new_line_to_end_of_buffer
- start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("class A\n def a\n 3\n 3\n end\nend")
- write("\n")
- write("class S")
- write("\n")
- write(" 3")
- assert_screen(<<~'EOC')
- prompt> def a
- prompt> 3
- prompt> 3
- prompt> end
- prompt> end
- => :a
- prompt> class S
- prompt> 3
- EOC
- close
- end
-
- def test_insert_newline_in_the_middle_of_buffer_just_after_dialog
- start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("class A\n def a\n 3\n end\nend")
- write("\n")
- write("\C-p\C-p\C-p\C-p\C-p\C-e\C-hS")
- write("\e\x0D")
- write(" 3")
- assert_screen(<<~'EOC')
- prompt> 3
- prompt> end
- prompt> end
- => :a
- prompt> class S
- prompt> 3
- prompt> def a
- prompt> 3
- prompt> end
- prompt> end
- EOC
- close
- end
-
- def test_incremental_search_on_not_last_line
- start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.')
- write("def abc\nend\n")
- write("def def\nend\n")
- write("\C-p\C-p\C-e")
- write("\C-r")
- write("a")
- write("\n\n")
- assert_screen(<<~'EOC')
- prompt> def abc
- prompt> end
- => :abc
- prompt> def def
- prompt> end
- => :def
- prompt> def abc
- prompt> end
- => :abc
- prompt>
- EOC
- close
- end
-
- def test_bracket_newline_indent
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write("[\n")
- write("1")
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> [
- prompt> 1
- EOC
- close
- end
-
- def test_repeated_input_delete
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write("a\C-h" * 4000)
- assert_screen(<<~'EOC')
- Multiline REPL.
- prompt>
- EOC
- close
- end
-
- def test_exit_with_ctrl_d
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- begin
- write("\C-d")
- close
- rescue EOFError
- # EOFError is raised when process terminated.
- end
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt>
- EOC
- close
- end
-
- def test_quoted_insert_intr_keys
- omit if Reline.core.io_gate.win?
- start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.')
- write '"'
- write "\C-v"
- write "\C-c"
- write "\C-v"
- write "\C-z"
- write "\C-v"
- write "\C-\\"
- write "\".bytes\n"
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> "^C^Z^\\\".bytes
- => [3, 26, 28]
- prompt>
- EOC
- close
- end
-
- def test_print_before_readline
- code = <<~RUBY
- puts 'Multiline REPL.'
- 2.times do
- print 'a' * 10
- Reline.readline '>'
- end
- RUBY
- start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.')
- write "x\n"
- assert_screen(<<~EOC)
- Multiline REPL.
- >x
- >
- EOC
- close
- end
-
- def test_pre_input_hook_with_redisplay
- code = <<~'RUBY'
- puts 'Multiline REPL.'
- Reline.pre_input_hook = -> do
- Reline.insert_text 'abc'
- Reline.redisplay # Reline doesn't need this but Readline requires calling redisplay
- end
- Reline.readline('prompt> ')
- RUBY
- start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.')
- assert_screen(<<~EOC)
- Multiline REPL.
- prompt> abc
- EOC
- close
- end
-
- def test_pre_input_hook_with_multiline_text_insert
- # Frequently used pattern of pre_input_hook
- code = <<~'RUBY'
- puts 'Multiline REPL.'
- Reline.pre_input_hook = -> do
- Reline.insert_text "abc\nef"
- end
- Reline.readline('>')
- RUBY
- start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.')
- write("\C-ad")
- assert_screen(<<~EOC)
- Multiline REPL.
- >abc
- def
- EOC
- close
- end
-
- def test_thread_safe
- start_terminal(6, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.')
- write("[Thread.new{Reline.readline'>'},Thread.new{Reline.readmultiline('>'){true}}].map(&:join).size\n")
- write("exit\n")
- write("exit\n")
- write("42\n")
- assert_screen(<<~EOC)
- >exit
- >exit
- => 2
- prompt> 42
- => 42
- prompt>
- EOC
- close
- end
-
- def test_user_defined_winch
- omit if Reline.core.io_gate.win?
- pidfile = Tempfile.create('pidfile')
- rubyfile = Tempfile.create('rubyfile')
- rubyfile.write <<~RUBY
- File.write(#{pidfile.path.inspect}, Process.pid)
- winch_called = false
- Signal.trap(:WINCH, ->(_arg){ winch_called = true })
- p Reline.readline('>')
- puts "winch: \#{winch_called}"
- RUBY
- rubyfile.close
-
- start_terminal(10, 50, %W{ruby -I#{@pwd}/lib -rreline #{rubyfile.path}})
- assert_screen(/^>/)
- write 'a'
- assert_screen(/^>a/)
- pid = pidfile.tap(&:rewind).read.to_i
- Process.kill(:WINCH, pid) unless pid.zero?
- write "b\n"
- assert_screen(/"ab"\nwinch: true/)
- close
- ensure
- File.delete(rubyfile.path) if rubyfile
- pidfile.close if pidfile
- File.delete(pidfile.path) if pidfile
- end
-
- def test_stop_continue
- omit if Reline.core.io_gate.win?
- pidfile = Tempfile.create('pidfile')
- rubyfile = Tempfile.create('rubyfile')
- rubyfile.write <<~RUBY
- File.write(#{pidfile.path.inspect}, Process.pid)
- cont_called = false
- Signal.trap(:CONT, ->(_arg){ cont_called = true })
- Reline.readmultiline('>'){|input| input.match?(/ghi/) }
- puts "cont: \#{cont_called}"
- RUBY
- rubyfile.close
- start_terminal(10, 50, ['bash'])
- write "ruby -I#{@pwd}/lib -rreline #{rubyfile.path}\n"
- assert_screen(/^>/)
- write "abc\ndef\nhi"
- pid = pidfile.tap(&:rewind).read.to_i
- Process.kill(:STOP, pid) unless pid.zero?
- write "fg\n"
- assert_screen(/fg\n.*>/m)
- write "\ebg"
- assert_screen(/>abc\n>def\n>ghi\n/)
- write "\n"
- assert_screen(/cont: true/)
- close
- ensure
- File.delete(rubyfile.path) if rubyfile
- pidfile.close if pidfile
- File.delete(pidfile.path) if pidfile
- end
-
- def write_inputrc(content)
- File.open(@inputrc_file, 'w') do |f|
- f.write content
- end
- end
-
- def fold_multiline(str, width)
- str.scan(/.{1,#{width}}/).each(&:rstrip!).join("\n")
- end
- end
-rescue LoadError, NameError
- # On Ruby repository, this test suit doesn't run because Ruby repo doesn't
- # have the yamatanooroti gem.
-end