diff --git a/lib/irb.rb b/lib/irb.rb index 773d0d07a49a13..1badb9b394ae26 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -60,6 +60,8 @@ # -W[level=2] Same as `ruby -W` # --inspect Use `inspect' for output (default except for bc mode) # --noinspect Don't use inspect for output +# --reidline Use Reidline extension module +# --noreidline Don't use Reidline extension module # --readline Use Readline extension module # --noreadline Don't use Readline extension module # --colorize Use colorization @@ -69,7 +71,7 @@ # 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 --reidline and --readline. # --simple-prompt Simple prompt mode # --noprompt No prompt mode # --tracer Display trace for each execution of commands. @@ -97,6 +99,7 @@ # IRB.conf[:IRB_RC] = nil # IRB.conf[:BACK_TRACE_LIMIT]=16 # IRB.conf[:USE_LOADER] = false +# IRB.conf[:USE_REIDLINE] = nil # IRB.conf[:USE_READLINE] = nil # IRB.conf[:USE_COLORIZE] = true # IRB.conf[:USE_TRACER] = false @@ -412,7 +415,6 @@ def initialize(workspace = nil, input_method = nil, output_method = nil) @context = Context.new(self, workspace, input_method, output_method) @context.main.extend ExtendCommandBundle @signal_status = :IN_IRB - @scanner = RubyLex.new end diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index 390e7254ddbdf7..289180a3b288f0 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -35,6 +35,8 @@ def defined do yield ] + BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{(" + CompletionProc = proc { |input| bind = IRB.conf[:MAIN_CONTEXT].workspace.binding @@ -236,9 +238,3 @@ def self.ignored_modules end end end - -if Readline.respond_to?("basic_word_break_characters=") - Readline.basic_word_break_characters= " \t\n`><=;|&{(" -end -Readline.completion_append_character = nil -Readline.completion_proc = IRB::InputCompletor::CompletionProc diff --git a/lib/irb/context.rb b/lib/irb/context.rb index 7037b2bd668d8a..571df2c21a2bc7 100644 --- a/lib/irb/context.rb +++ b/lib/irb/context.rb @@ -22,7 +22,7 @@ class Context # # The optional +input_method+ argument: # - # +nil+:: uses stdin or Readline + # +nil+:: uses stdin or Reidline or Readline # +String+:: uses a File # +other+:: uses this as InputMethod def initialize(irb, workspace = nil, input_method = nil, output_method = nil) @@ -40,6 +40,7 @@ def initialize(irb, workspace = nil, input_method = nil, output_method = nil) @load_modules = IRB.conf[:LOAD_MODULES] @use_readline = IRB.conf[:USE_READLINE] + @use_reidline = IRB.conf[:USE_REIDLINE] @use_colorize = IRB.conf[:USE_COLORIZE] @verbose = IRB.conf[:VERBOSE] @io = nil @@ -65,23 +66,41 @@ def initialize(irb, workspace = nil, input_method = nil, output_method = nil) case input_method when nil - case use_readline? + @io = nil + case use_reidline? when nil - if (defined?(ReadlineInputMethod) && STDIN.tty? && - IRB.conf[:PROMPT_MODE] != :INF_RUBY) - @io = ReadlineInputMethod.new + if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_readline? + @io = ReidlineInputMethod.new else - @io = StdioInputMethod.new + @io = nil end when false - @io = StdioInputMethod.new + @io = nil when true - if defined?(ReadlineInputMethod) - @io = ReadlineInputMethod.new + @io = ReidlineInputMethod.new + end + unless @io + case use_readline? + when nil + if (defined?(ReadlineInputMethod) && STDIN.tty? && + 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 = StdioInputMethod.new + @io = nil end end + @io = StdioInputMethod.new unless @io when String @io = FileInputMethod.new(input_method) @@ -117,9 +136,9 @@ def main attr_reader :thread # The current input method # - # Can be either StdioInputMethod, ReadlineInputMethod, FileInputMethod or - # other specified when the context is created. See ::new for more - # information on +input_method+. + # Can be either StdioInputMethod, ReadlineInputMethod, + # ReidlineInputMethod, FileInputMethod or other specified when the + # context is created. See ::new for more # information on +input_method+. attr_accessor :io # Current irb session @@ -137,6 +156,12 @@ def main # +input_method+ passed to Context.new attr_accessor :irb_path + # Whether +Reidline+ is enabled or not. + # + # A copy of the default IRB.conf[:USE_REIDLINE] + # + # See #use_reidline= for more information. + attr_reader :use_reidline # Whether +Readline+ is enabled or not. # # A copy of the default IRB.conf[:USE_READLINE] @@ -225,6 +250,8 @@ def main # See IRB@Command+line+options for more command line options. attr_accessor :back_trace_limit + # Alias for #use_reidline + alias use_reidline? use_reidline # Alias for #use_readline alias use_readline? use_readline # Alias for #use_colorize @@ -238,7 +265,9 @@ def main # Returns whether messages are displayed or not. def verbose? if @verbose.nil? - if defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod) + if @io.kind_of?(ReidlineInputMethod) + false + elsif defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod) false elsif !STDIN.tty? or @io.kind_of?(FileInputMethod) true @@ -251,9 +280,11 @@ def verbose? end # Whether #verbose? is +true+, and +input_method+ is either - # StdioInputMethod or ReadlineInputMethod, see #io for more information. + # StdioInputMethod or ReidlineInputMethod or ReadlineInputMethod, see #io + # for more information. def prompting? verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) || + @io.kind_of?(ReidlineInputMethod) || (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod))) end diff --git a/lib/irb/init.rb b/lib/irb/init.rb index d2e325b86e80f1..50a4d7b3bbfa57 100644 --- a/lib/irb/init.rb +++ b/lib/irb/init.rb @@ -164,6 +164,10 @@ def IRB.parse_opts(argv: ::ARGV) @CONF[:USE_READLINE] = true when "--noreadline" @CONF[:USE_READLINE] = false + when "--reidline" + @CONF[:USE_REIDLINE] = true + when "--noreidline" + @CONF[:USE_REIDLINE] = false when "--echo" @CONF[:ECHO] = true when "--noecho" diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index f491d5a760d29c..bb0930495f7659 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -11,6 +11,8 @@ # require_relative 'src_encoding' require_relative 'magic-file' +require_relative 'completion' +require 'reline' module IRB STDIN_FILE_NAME = "(line)" # :nodoc: @@ -140,6 +142,12 @@ def initialize @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 => "-") + + if Readline.respond_to?("basic_word_break_characters=") + Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS + end + Readline.completion_append_character = nil + Readline.completion_proc = IRB::InputCompletor::CompletionProc end # Reads the next line from this input method. @@ -186,7 +194,83 @@ def line(line_no) def encoding @stdin.external_encoding end + + if Readline.respond_to?("basic_word_break_characters=") + Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS + end + Readline.completion_append_character = nil + Readline.completion_proc = IRB::InputCompletor::CompletionProc end rescue LoadError end + + class ReidlineInputMethod < InputMethod + include Reline + # Creates a new input method object using Readline + def initialize + super + + @line_no = 0 + @line = [] + @eof = false + + @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 => "-") + + if Reline.respond_to?("basic_word_break_characters=") + Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS + end + Reline.completion_append_character = nil + Reline.completion_proc = IRB::InputCompletor::CompletionProc + end + + def check_termination(&block) + @check_termination_proc = block + end + + # Reads the next line from this input method. + # + # See IO#gets for more information. + def gets + Reline.input = @stdin + Reline.output = @stdout + if l = readmultiline(@prompt, false, &@check_termination_proc) + 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 + + # 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 + + # 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 + end end diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index 7b933662f922a2..71d69348fbeebf 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -32,6 +32,7 @@ def set_input(io, p = nil, &block) @io = io if @io.respond_to?(:check_termination) @io.check_termination do |code| + code.gsub!(/\s*\z/, '').concat("\n") @tokens = Ripper.lex(code) continue = process_continue code_block_open = check_code_block(code) @@ -116,7 +117,7 @@ def lex return line # multiline end code = @line + (line.nil? ? '' : line) - code.gsub!(/\n*$/, '').concat("\n") + code.gsub!(/\s*\z/, '').concat("\n") @tokens = Ripper.lex(code) @continue = process_continue @code_block_open = check_code_block(code)