diff --git a/lib/irb.rb b/lib/irb.rb index ed2b336b30..e020aa6f30 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -10,6 +10,7 @@ # # require "ripper" +require "reline" require_relative "irb/init" require_relative "irb/context" @@ -538,7 +539,15 @@ module IRB begin line.untaint if RUBY_VERSION < '2.7' @context.evaluate(line, line_no, exception: exc) - output_value if @context.echo? && (@context.echo_on_assignment? || !assignment_expression?(line)) + if @context.echo? + if assignment_expression?(line) + if @context.echo_on_assignment? + output_value(@context.omit_on_assignment?) + end + else + output_value + end + end rescue Interrupt => exc rescue SystemExit, SignalException raise @@ -737,9 +746,22 @@ module IRB p end - def output_value # :nodoc: + def output_value(omit = false) # :nodoc: str = @context.inspect_last_value multiline_p = str.include?("\n") + if omit + if multiline_p + str.gsub!(/(\A.*?\n).*/m, "\\1...") + else + winwidth = @context.io.winsize.last + output_width = Reline::Unicode.calculate_width(@context.return_format % str, true) + diff_size = output_width - Reline::Unicode.calculate_width(str, true) + if diff_size.positive? and output_width > winwidth + lines, _ = Reline::Unicode.split_by_width(str, winwidth - diff_size - 3) + str = "%s...\e[0m" % lines.first + end + end + end if multiline_p && @context.newline_before_multiline_output? printf @context.return_format, "\n#{str}" else diff --git a/lib/irb/context.rb b/lib/irb/context.rb index 4f5460a84c..4f001729e1 100644 --- a/lib/irb/context.rb +++ b/lib/irb/context.rb @@ -131,7 +131,12 @@ module IRB @echo_on_assignment = IRB.conf[:ECHO_ON_ASSIGNMENT] if @echo_on_assignment.nil? - @echo_on_assignment = false + @echo_on_assignment = true + end + + @omit_on_assignment = IRB.conf[:OMIT_ON_ASSIGNMENT] + if @omit_on_assignment.nil? + @omit_on_assignment = true end @newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] @@ -251,13 +256,27 @@ module IRB attr_accessor :echo # Whether to echo for assignment expressions # - # Uses IRB.conf[:ECHO_ON_ASSIGNMENT] if available, or defaults to +false+. + # Uses IRB.conf[:ECHO_ON_ASSIGNMENT] if available, or defaults to +true+. # # a = "omg" - # IRB.CurrentContext.echo_on_assignment = true - # a = "omg" # #=> omg + # IRB.CurrentContext.echo_on_assignment = false + # a = "omg" attr_accessor :echo_on_assignment + # Whether to omit echo for assignment expressions + # + # Uses IRB.conf[:OMIT_ON_ASSIGNMENT] if available, or defaults to +true+. + # + # a = [1] * 10 + # #=> [1, 1, 1, 1, 1, 1, 1, 1, ... + # [1] * 10 + # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + # IRB.CurrentContext.omit_on_assignment = false + # a = [1] * 10 + # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + # [1] * 10 + # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + attr_accessor :omit_on_assignment # Whether a newline is put before multiline output. # # Uses IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if available, @@ -306,6 +325,7 @@ module IRB alias ignore_eof? ignore_eof alias echo? echo alias echo_on_assignment? echo_on_assignment + alias omit_on_assignment? omit_on_assignment alias newline_before_multiline_output? newline_before_multiline_output # Returns whether messages are displayed or not. diff --git a/lib/irb/init.rb b/lib/irb/init.rb index da40bee5e1..44383609bd 100644 --- a/lib/irb/init.rb +++ b/lib/irb/init.rb @@ -52,6 +52,7 @@ module IRB # :nodoc: @CONF[:IGNORE_EOF] = false @CONF[:ECHO] = nil @CONF[:ECHO_ON_ASSIGNMENT] = nil + @CONF[:OMIT_ON_ASSIGNMENT] = nil @CONF[:VERBOSE] = nil @CONF[:EVAL_HISTORY] = nil @@ -177,6 +178,10 @@ module IRB # :nodoc: @CONF[:ECHO_ON_ASSIGNMENT] = true when "--noecho-on-assignment" @CONF[:ECHO_ON_ASSIGNMENT] = false + when "--omit-on-assignment" + @CONF[:OMIT_ON_ASSIGNMENT] = true + when "--noomit-on-assignment" + @CONF[:OMIT_ON_ASSIGNMENT] = false when "--verbose" @CONF[:VERBOSE] = true when "--noverbose" diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index 7cb211354b..6e87488753 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -12,6 +12,7 @@ require_relative 'src_encoding' require_relative 'magic-file' require_relative 'completion' +require 'io/console' require 'reline' module IRB @@ -36,6 +37,14 @@ module IRB end public :gets + def winsize + if instance_variable_defined?(:@stdout) + @stdout.winsize + else + [24, 80] + end + end + # Whether this input method is still readable when there is no more data to # read. # diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb index 55bd6ff63e..3a4c98729e 100644 --- a/test/irb/test_context.rb +++ b/test/irb/test_context.rb @@ -30,6 +30,10 @@ module TestIRB def reset @line_no = 0 end + + def winsize + [10, 20] + end end def setup @@ -213,6 +217,75 @@ module TestIRB assert_equal("", out) end + def test_omit_on_assignment + input = TestInputMethod.new([ + "a = [1] * 100\n", + "a\n", + ]) + value = [1] * 100 + irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) + irb.context.return_format = "=> %s\n" + + irb.context.echo = true + irb.context.echo_on_assignment = false + irb.context.omit_on_assignment = true + out, err = capture_io do + irb.eval_input + end + assert_empty err + assert_equal("=> #{value.inspect}\n", out) + + input.reset + irb.context.echo = true + irb.context.echo_on_assignment = true + irb.context.omit_on_assignment = true + out, err = capture_io do + irb.eval_input + end + assert_empty err + assert_equal("=> #{value.inspect[0..(input.winsize.last - 9)]}...\e[0m\n=> #{value.inspect}\n", out) + + input.reset + irb.context.echo = true + irb.context.echo_on_assignment = true + irb.context.omit_on_assignment = false + out, err = capture_io do + irb.eval_input + end + assert_empty err + assert_equal("=> #{value.inspect}\n=> #{value.inspect}\n", out) + + input.reset + irb.context.echo = false + irb.context.echo_on_assignment = false + irb.context.omit_on_assignment = true + out, err = capture_io do + irb.eval_input + end + assert_empty err + assert_equal("", out) + + input.reset + irb.context.echo = false + irb.context.echo_on_assignment = true + irb.context.omit_on_assignment = true + out, err = capture_io do + irb.eval_input + end + assert_empty err + assert_equal("", out) + + input.reset + irb.context.echo = false + irb.context.echo_on_assignment = true + irb.context.omit_on_assignment = false + out, err = capture_io do + irb.eval_input + end + assert_empty err + assert_equal("", out) + end + def test_echo_on_assignment_conf # Default IRB.conf[:ECHO] = nil @@ -221,22 +294,26 @@ module TestIRB irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) assert(irb.context.echo?, "echo? should be true by default") - refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false by default") + assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true by default") + assert(irb.context.omit_on_assignment?, "omit_on_assignment? should be true by default") # Explicitly set :ECHO to false IRB.conf[:ECHO] = false irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) refute(irb.context.echo?, "echo? should be false when IRB.conf[:ECHO] is set to false") - refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false by default") + assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true by default") + assert(irb.context.omit_on_assignment?, "omit_on_assignment? should be true by default") # Explicitly set :ECHO_ON_ASSIGNMENT to true IRB.conf[:ECHO] = nil - IRB.conf[:ECHO_ON_ASSIGNMENT] = true + IRB.conf[:ECHO_ON_ASSIGNMENT] = false + IRB.conf[:OMIT_ON_ASSIGNMENT] = false irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) assert(irb.context.echo?, "echo? should be true by default") - assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to true") + refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to false") + refute(irb.context.omit_on_assignment?, "omit_on_assignment? should be false when IRB.conf[:OMIT_ON_ASSIGNMENT] is set to false") end def test_multiline_output_on_default_inspector