lib/irb.rb in irb-1.1.1 vs lib/irb.rb in irb-1.2.0
- old
+ new
@@ -7,19 +7,20 @@
#
# --
#
#
#
-require "e2mmap"
+require "ripper"
require "irb/init"
require "irb/context"
require "irb/extend-command"
require "irb/ruby-lex"
require "irb/input-method"
require "irb/locale"
+require "irb/color"
require "irb/version"
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
# expressions read from the standard input.
@@ -41,12 +42,12 @@
# irb(main):004:2> print 1
# irb(main):005:2> end
# irb(main):006:1> end
# #=> nil
#
-# The Readline extension module can be used with irb. Use of Readline is
-# default if it's installed.
+# The singleline editor module or multiline editor module can be used with irb.
+# Use of multiline editor is default if it's installed.
#
# == Command line options
#
# Usage: irb.rb [options] [programfile] [arguments]
# -f Suppress read of ~/.irbrc
@@ -57,25 +58,28 @@
# -E enc Same as `ruby -E`
# -w Same as `ruby -w`
# -W[level=2] Same as `ruby -W`
# --inspect Use `inspect' for output (default except for bc mode)
# --noinspect Don't use inspect for output
-# --readline Use Readline extension module
-# --noreadline Don't use Readline extension module
+# --multiline Use multiline editor module
+# --nomultiline Don't use multiline editor module
+# --singleline Use singleline editor module
+# --nosingleline Don't use singleline editor module
+# --colorize Use colorization
+# --nocolorize Don't use colorization
# --prompt prompt-mode
# --prompt-mode prompt-mode
# Switch prompt mode. Pre-defined prompt modes are
# `default', `simple', `xmp' and `inf-ruby'
# --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
-# Suppresses --readline.
+# Suppresses --multiline and --singleline.
# --simple-prompt Simple prompt mode
# --noprompt No prompt mode
# --tracer Display trace for each execution of commands.
# --back-trace-limit n
# Display backtrace top n and tail n. The default
# value is 16.
-# --irb_debug n Set internal debug level to n (not for popular use)
# -v, --version Print the version of irb
#
# == Configuration
#
# IRB reads from <code>~/.irbrc</code> when it's invoked.
@@ -93,52 +97,60 @@
# IRB.conf[:IRB_NAME]="irb"
# IRB.conf[:INSPECT_MODE]=nil
# IRB.conf[:IRB_RC] = nil
# IRB.conf[:BACK_TRACE_LIMIT]=16
# IRB.conf[:USE_LOADER] = false
-# IRB.conf[:USE_READLINE] = nil
+# IRB.conf[:USE_MULTILINE] = nil
+# IRB.conf[:USE_SINGLELINE] = nil
+# IRB.conf[:USE_COLORIZE] = true
# IRB.conf[:USE_TRACER] = false
# IRB.conf[:IGNORE_SIGINT] = true
# IRB.conf[:IGNORE_EOF] = false
# IRB.conf[:PROMPT_MODE] = :DEFAULT
# IRB.conf[:PROMPT] = {...}
-# IRB.conf[:DEBUG_LEVEL]=0
#
# === Auto indentation
#
-# To enable auto-indent mode in irb, add the following to your +.irbrc+:
+# To disable auto-indent mode in irb, add the following to your +.irbrc+:
#
-# IRB.conf[:AUTO_INDENT] = true
+# IRB.conf[:AUTO_INDENT] = false
#
# === Autocompletion
#
# To enable autocompletion for irb, add the following to your +.irbrc+:
#
# require 'irb/completion'
#
# === History
#
-# By default, irb disables history and will not store any commands you used.
+# By default, irb will store the last 1000 commands you used in
+# <code>IRB.conf[:HISTORY_FILE]</code> (<code>~/.irb_history</code> by default).
#
-# If you want to enable history, add the following to your +.irbrc+:
+# If you want to disable history, add the following to your +.irbrc+:
#
-# IRB.conf[:SAVE_HISTORY] = 1000
+# IRB.conf[:SAVE_HISTORY] = nil
#
-# This will now store the last 1000 commands in <code>~/.irb_history</code>.
-#
# See IRB::Context#save_history= for more information.
#
+# The history of _resuls_ of commands evaluated is not stored by default,
+# but can be turned on to be stored with this +.irbrc+ setting:
+#
+# IRB.conf[:EVAL_HISTORY] = <number>
+#
+# See IRB::Context#eval_history= and History class. The history of command
+# results is not permanently saved in any file.
+#
# == Customizing the IRB Prompt
#
# In order to customize the prompt, you can change the following Hash:
#
# IRB.conf[:PROMPT]
#
# This example can be used in your +.irbrc+
#
# IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
-# :AUTO_INDENT => true, # enables auto-indent mode
+# :AUTO_INDENT => false, # disables auto-indent mode
# :PROMPT_I => ">> ", # simple prompt
# :PROMPT_S => nil, # prompt for continuated strings
# :PROMPT_C => nil, # prompt for continuated statement
# :RETURN => " ==>%s\n" # format to return value
# }
@@ -163,10 +175,11 @@
#
# For instance, the default prompt mode is defined as follows:
#
# IRB.conf[:PROMPT_MODE][:DEFAULT] = {
# :PROMPT_I => "%N(%m):%03n:%i> ",
+# :PROMPT_N => "%N(%m):%03n:%i> ",
# :PROMPT_S => "%N(%m):%03n:%i%l ",
# :PROMPT_C => "%N(%m):%03n:%i* ",
# :RETURN => "%s\n" # used to printf
# }
#
@@ -266,11 +279,13 @@
# There are a few variables in every Irb session that can come in handy:
#
# <code>_</code>::
# The value command executed, as a local variable
# <code>__</code>::
-# The history of evaluated commands
+# The history of evaluated commands. Available only if
+# <code>IRB.conf[:EVAL_HISTORY]</code> is not +nil+ (which is the default).
+# See also IRB::Context#eval_history= and IRB::History.
# <code>__[line_no]</code>::
# Returns the evaluation value at the given line number, +line_no+.
# If +line_no+ is a negative, the return value +line_no+ many lines before
# the most recent return value.
#
@@ -403,18 +418,45 @@
raise exception, "abort then interrupt!"
end
end
class Irb
+ 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,
+ ]
+ # Note: instance and index assignment expressions could also be written like:
+ # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former
+ # be parsed as :assign and echo will be suppressed, but the latter is
+ # parsed as a :method_add_arg and the output won't be suppressed
+
# Creates a new irb session
- def initialize(workspace = nil, input_method = nil, output_method = nil)
- @context = Context.new(self, workspace, input_method, output_method)
+ def initialize(workspace = nil, input_method = nil)
+ @context = Context.new(self, workspace, input_method)
@context.main.extend ExtendCommandBundle
@signal_status = :IN_IRB
-
@scanner = RubyLex.new
- @scanner.exception_on_syntax_error = false
end
def run(conf = IRB.conf)
conf[:IRB_RC].call(context) if conf[:IRB_RC]
conf[:MAIN_CONTEXT] = context
@@ -456,18 +498,20 @@
if @context.prompting?
@context.io.prompt = p = prompt(f, ltype, indent, line_no)
else
@context.io.prompt = p = ""
end
- if @context.auto_indent_mode
+ if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
unless ltype
- ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size +
+ prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
+ ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
indent * 2 - p.size
ind += 2 if continue
@context.io.prompt = p + " " * ind if ind > 0
end
end
+ @context.io.prompt
end
@scanner.set_input(@context.io) do
signal_status(:IN_INPUT) do
if l = @context.io.gets
@@ -484,16 +528,18 @@
end
l
end
end
+ @scanner.set_auto_indent(@context) if @context.auto_indent_mode
+
@scanner.each_top_level_statement do |line, line_no|
signal_status(:IN_EVAL) do
begin
- line.untaint
+ line.untaint if RUBY_VERSION < '2.7'
@context.evaluate(line, line_no, exception: exc)
- output_value if @context.echo?
+ output_value if @context.echo? && (@context.echo_on_assignment? || !assignment_expression?(line))
rescue Interrupt => exc
rescue SystemExit, SignalException
raise
rescue Exception => exc
else
@@ -504,11 +550,11 @@
end
end
end
def handle_exception(exc)
- if exc.backtrace && exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
+ if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
!(SyntaxError === exc)
irb_bug = true
else
irb_bug = false
end
@@ -661,14 +707,22 @@
when "M"
@context.main.inspect
when "l"
ltype
when "i"
- if $1
- format("%" + $1 + "d", indent)
+ if indent < 0
+ if $1
+ "-".rjust($1.to_i)
+ else
+ "-"
+ end
else
- indent.to_s
+ if $1
+ format("%" + $1 + "d", indent)
+ else
+ indent.to_s
+ end
end
when "n"
if $1
format("%" + $1 + "d", line_no)
else
@@ -700,10 +754,25 @@
end
end
format("#<%s: %s>", self.class, ary.join(", "))
end
+ def assignment_expression?(line)
+ # Try to parse the line 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 selement 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
+ result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0))
+ $VERBOSE = verbose
+ result
+ end
+
ATTR_TTY = "\e[%sm"
def ATTR_TTY.[](*a) self % a.join(";"); end
ATTR_PLAIN = ""
def ATTR_PLAIN.[](*) self; end
end
@@ -747,12 +816,12 @@
# end
# end
#
# Potato.new
#
- # Running +ruby potato.rb+ will open an IRB session where +binding.irb+ is
- # called, and you will see the following:
+ # Running <code>ruby potato.rb</code> will open an IRB session where
+ # +binding.irb+ is called, and you will see the following:
#
# $ ruby potato.rb
#
# From: potato.rb @ line 4 :
#
@@ -778,21 +847,23 @@
# irb(#<Potato:0x00007feea1916670>):003:0> caller.first
# => ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'"
# irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
# => true
#
- # You can exit the IRB session with the `exit` command. Note that exiting will
+ # You can exit the IRB session with the +exit+ command. Note that exiting will
# resume execution where +binding.irb+ had paused it, as you can see from the
# output printed to standard output in this example:
#
# irb(#<Potato:0x00007feea1916670>):005:0> exit
# Cooked potato: true
#
#
# See IRB@IRB+Usage for more information.
def irb
- IRB.setup(eval("__FILE__"), argv: [])
+ IRB.setup(source_location[0], argv: [])
workspace = IRB::WorkSpace.new(self)
STDOUT.print(workspace.code_around_binding)
- IRB::Irb.new(workspace).run(IRB.conf)
+ binding_irb = IRB::Irb.new(workspace)
+ binding_irb.context.irb_path = File.expand_path(source_location[0])
+ binding_irb.run(IRB.conf)
end
end