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