summaryrefslogtreecommitdiff
path: root/lib/irb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/irb')
-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
75 files changed, 0 insertions, 8226 deletions
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