irb 1.1.0.pre.1 → 1.1.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f66136bc4e18da53d6d29f7b04244c16f4e195012723da1a35de758683092667
4
- data.tar.gz: be8a4c66b1823e4ac852c08a6299523edc6921b5a4ae9313a025d98105ee99e3
3
+ metadata.gz: 81da8e8b11979aca60cc0806c7a679f8a854a2f9f38d215f714d377aaac579ae
4
+ data.tar.gz: 05f6c327f9226f5789498c182c5b5c4cfe2ada443f65fc3daa577c76e5dcad8e
5
5
  SHA512:
6
- metadata.gz: 643216ead68eb3cf7e0b01164067c6f9ab41ad2f849a490e8f4eafbdbf97b4df4e2795cd87c30ae294cf6a9c6aa137fcce71e41700c8f4a0aa40fb47d9f5a779
7
- data.tar.gz: a069be08937a2fc54a31ea7c0ae4447027850b05b03a0f3a47e3ec2689099229666c33a83b593c1c8b0fe7b190dd90598fa22d9f367d5444dbae0cee57ac8365
6
+ metadata.gz: 5ab9d21b32e138399ac7eafee532f15f07b85dadc0acb35eb1cd41814a000cb74c69f98455d90b2f7930d23eb79d708468387dcc5b5efb82ac866720e7227cbe
7
+ data.tar.gz: 2d2836d6c47a4040c7e8b27442b504e9eced9ffd6c2169f7d50dd5439b6534c6f477d51ffa5f5b14fa02c3cecd0f400b9ea8762d399db0d81532b65b2af3ce62
@@ -16,11 +16,12 @@ Gem::Specification.new do |spec|
16
16
  spec.homepage = "https://github.com/ruby/irb"
17
17
  spec.license = "BSD-2-Clause"
18
18
 
19
- spec.files = ["LICENSE.txt", "README.md", "exe/irb", "irb.gemspec", "lib/irb.rb", "lib/irb/cmd/chws.rb", "lib/irb/cmd/fork.rb", "lib/irb/cmd/help.rb", "lib/irb/cmd/load.rb", "lib/irb/cmd/nop.rb", "lib/irb/cmd/pushws.rb", "lib/irb/cmd/subirb.rb", "lib/irb/completion.rb", "lib/irb/context.rb", "lib/irb/ext/change-ws.rb", "lib/irb/ext/history.rb", "lib/irb/ext/loader.rb", "lib/irb/ext/multi-irb.rb", "lib/irb/ext/save-history.rb", "lib/irb/ext/tracer.rb", "lib/irb/ext/use-loader.rb", "lib/irb/ext/workspaces.rb", "lib/irb/extend-command.rb", "lib/irb/frame.rb", "lib/irb/help.rb", "lib/irb/init.rb", "lib/irb/input-method.rb", "lib/irb/inspector.rb", "lib/irb/lc/.document", "lib/irb/lc/error.rb", "lib/irb/lc/help-message", "lib/irb/lc/ja/encoding_aliases.rb", "lib/irb/lc/ja/error.rb", "lib/irb/lc/ja/help-message", "lib/irb/locale.rb", "lib/irb/magic-file.rb", "lib/irb/notifier.rb", "lib/irb/output-method.rb", "lib/irb/ruby-lex.rb", "lib/irb/ruby-token.rb", "lib/irb/slex.rb", "lib/irb/src_encoding.rb", "lib/irb/version.rb", "lib/irb/workspace.rb", "lib/irb/ws-for-case-2.rb", "lib/irb/xmp.rb"]
19
+ spec.files = ["LICENSE.txt", "README.md", "exe/irb", "irb.gemspec", "lib/irb.rb", "lib/irb/cmd/chws.rb", "lib/irb/cmd/fork.rb", "lib/irb/cmd/help.rb", "lib/irb/cmd/load.rb", "lib/irb/cmd/nop.rb", "lib/irb/cmd/pushws.rb", "lib/irb/cmd/subirb.rb", "lib/irb/completion.rb", "lib/irb/context.rb", "lib/irb/color.rb", "lib/irb/ext/change-ws.rb", "lib/irb/ext/history.rb", "lib/irb/ext/loader.rb", "lib/irb/ext/multi-irb.rb", "lib/irb/ext/save-history.rb", "lib/irb/ext/tracer.rb", "lib/irb/ext/use-loader.rb", "lib/irb/ext/workspaces.rb", "lib/irb/extend-command.rb", "lib/irb/frame.rb", "lib/irb/help.rb", "lib/irb/init.rb", "lib/irb/input-method.rb", "lib/irb/inspector.rb", "lib/irb/lc/.document", "lib/irb/lc/error.rb", "lib/irb/lc/help-message", "lib/irb/lc/ja/encoding_aliases.rb", "lib/irb/lc/ja/error.rb", "lib/irb/lc/ja/help-message", "lib/irb/locale.rb", "lib/irb/magic-file.rb", "lib/irb/notifier.rb", "lib/irb/output-method.rb", "lib/irb/ruby-lex.rb", "lib/irb/ruby-token.rb", "lib/irb/slex.rb", "lib/irb/src_encoding.rb", "lib/irb/version.rb", "lib/irb/workspace.rb", "lib/irb/ws-for-case-2.rb", "lib/irb/xmp.rb"]
20
20
  spec.bindir = "exe"
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
+ spec.add_dependency "reline", ">= 0.0.1"
24
25
  spec.add_development_dependency "bundler"
25
26
  spec.add_development_dependency "rake"
26
27
  end
data/lib/irb.rb CHANGED
@@ -110,9 +110,9 @@ require "irb/version"
110
110
  #
111
111
  # === Auto indentation
112
112
  #
113
- # To enable auto-indent mode in irb, add the following to your +.irbrc+:
113
+ # To disable auto-indent mode in irb, add the following to your +.irbrc+:
114
114
  #
115
- # IRB.conf[:AUTO_INDENT] = true
115
+ # IRB.conf[:AUTO_INDENT] = false
116
116
  #
117
117
  # === Autocompletion
118
118
  #
@@ -122,13 +122,12 @@ require "irb/version"
122
122
  #
123
123
  # === History
124
124
  #
125
- # By default, irb disables history and will not store any commands you used.
125
+ # By default, irb will store the last 1000 commands you used in
126
+ # <code>~/.irb_history</code>.
126
127
  #
127
- # If you want to enable history, add the following to your +.irbrc+:
128
+ # If you want to disable history, add the following to your +.irbrc+:
128
129
  #
129
- # IRB.conf[:SAVE_HISTORY] = 1000
130
- #
131
- # This will now store the last 1000 commands in <code>~/.irb_history</code>.
130
+ # IRB.conf[:SAVE_HISTORY] = nil
132
131
  #
133
132
  # See IRB::Context#save_history= for more information.
134
133
  #
@@ -141,7 +140,7 @@ require "irb/version"
141
140
  # This example can be used in your +.irbrc+
142
141
  #
143
142
  # IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
144
- # :AUTO_INDENT => true, # enables auto-indent mode
143
+ # :AUTO_INDENT => false, # disables auto-indent mode
145
144
  # :PROMPT_I => ">> ", # simple prompt
146
145
  # :PROMPT_S => nil, # prompt for continuated strings
147
146
  # :PROMPT_C => nil, # prompt for continuated statement
@@ -170,6 +169,7 @@ require "irb/version"
170
169
  #
171
170
  # IRB.conf[:PROMPT_MODE][:DEFAULT] = {
172
171
  # :PROMPT_I => "%N(%m):%03n:%i> ",
172
+ # :PROMPT_N => "%N(%m):%03n:%i> ",
173
173
  # :PROMPT_S => "%N(%m):%03n:%i%l ",
174
174
  # :PROMPT_C => "%N(%m):%03n:%i* ",
175
175
  # :RETURN => "%s\n" # used to printf
@@ -461,14 +461,16 @@ module IRB
461
461
  else
462
462
  @context.io.prompt = p = ""
463
463
  end
464
- if @context.auto_indent_mode
464
+ if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
465
465
  unless ltype
466
- ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size +
466
+ prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
467
+ ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
467
468
  indent * 2 - p.size
468
469
  ind += 2 if continue
469
470
  @context.io.prompt = p + " " * ind if ind > 0
470
471
  end
471
472
  end
473
+ @context.io.prompt
472
474
  end
473
475
 
474
476
  @scanner.set_input(@context.io) do
@@ -489,6 +491,8 @@ module IRB
489
491
  end
490
492
  end
491
493
 
494
+ @scanner.set_auto_indent(@context) if @context.auto_indent_mode
495
+
492
496
  @scanner.each_top_level_statement do |line, line_no|
493
497
  signal_status(:IN_EVAL) do
494
498
  begin
@@ -666,10 +670,18 @@ module IRB
666
670
  when "l"
667
671
  ltype
668
672
  when "i"
669
- if $1
670
- format("%" + $1 + "d", indent)
673
+ if indent < 0
674
+ if $1
675
+ "-".rjust($1.to_i)
676
+ else
677
+ "-"
678
+ end
671
679
  else
672
- indent.to_s
680
+ if $1
681
+ format("%" + $1 + "d", indent)
682
+ else
683
+ indent.to_s
684
+ end
673
685
  end
674
686
  when "n"
675
687
  if $1
@@ -9,17 +9,18 @@
9
9
  #
10
10
  #
11
11
 
12
- require 'rdoc/ri/driver'
13
-
14
12
  require_relative "nop"
15
13
 
16
14
  # :stopdoc:
17
15
  module IRB
18
16
  module ExtendCommand
19
17
  class Help < Nop
20
- begin
21
- Ri = RDoc::RI::Driver.new
22
- rescue SystemExit
18
+ def execute(*names)
19
+ require 'rdoc/ri/driver'
20
+ IRB::ExtendCommand::Help.const_set(:Ri, RDoc::RI::Driver.new)
21
+ rescue LoadError, SystemExit
22
+ IRB::ExtendCommand::Help.remove_method(:execute)
23
+ # raise NoMethodError in ensure
23
24
  else
24
25
  def execute(*names)
25
26
  if names.empty?
@@ -35,6 +36,9 @@ module IRB
35
36
  end
36
37
  nil
37
38
  end
39
+ nil
40
+ ensure
41
+ execute(*names)
38
42
  end
39
43
  end
40
44
  end
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+ require 'reline'
3
+ require 'ripper'
4
+
5
+ module IRB # :nodoc:
6
+ module Color
7
+ CLEAR = 0
8
+ BOLD = 1
9
+ UNDERLINE = 4
10
+ REVERSE = 7
11
+ RED = 31
12
+ GREEN = 32
13
+ YELLOW = 33
14
+ BLUE = 34
15
+ MAGENTA = 35
16
+ CYAN = 36
17
+
18
+ TOKEN_KEYWORDS = {
19
+ on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__'],
20
+ on_const: ['ENV'],
21
+ }
22
+ private_constant :TOKEN_KEYWORDS
23
+
24
+ # A constant of all-bit 1 to match any Ripper's state in #dispatch_seq
25
+ ALL = -1
26
+ private_constant :ALL
27
+
28
+ begin
29
+ # Following pry's colors where possible, but sometimes having a compromise like making
30
+ # backtick and regexp as red (string's color, because they're sharing tokens).
31
+ TOKEN_SEQ_EXPRS = {
32
+ on_CHAR: [[BLUE, BOLD], ALL],
33
+ on_backtick: [[RED], ALL],
34
+ on_comment: [[BLUE, BOLD], ALL],
35
+ on_const: [[BLUE, BOLD, UNDERLINE], ALL],
36
+ on_embexpr_beg: [[RED], ALL],
37
+ on_embexpr_end: [[RED], ALL],
38
+ on_embvar: [[RED], ALL],
39
+ on_float: [[MAGENTA, BOLD], ALL],
40
+ on_gvar: [[GREEN, BOLD], ALL],
41
+ on_heredoc_beg: [[RED], ALL],
42
+ on_heredoc_end: [[RED], ALL],
43
+ on_ident: [[BLUE, BOLD], Ripper::EXPR_ENDFN],
44
+ on_imaginary: [[BLUE, BOLD], ALL],
45
+ on_int: [[BLUE, BOLD], ALL],
46
+ on_kw: [[GREEN], ALL],
47
+ on_label: [[MAGENTA], ALL],
48
+ on_label_end: [[RED], ALL],
49
+ on_qsymbols_beg: [[RED], ALL],
50
+ on_qwords_beg: [[RED], ALL],
51
+ on_rational: [[BLUE, BOLD], ALL],
52
+ on_regexp_beg: [[RED, BOLD], ALL],
53
+ on_regexp_end: [[RED, BOLD], ALL],
54
+ on_symbeg: [[YELLOW], ALL],
55
+ on_tstring_beg: [[RED], ALL],
56
+ on_tstring_content: [[RED], ALL],
57
+ on_tstring_end: [[RED], ALL],
58
+ on_words_beg: [[RED], ALL],
59
+ on_parse_error: [[RED, REVERSE], ALL],
60
+ compile_error: [[RED, REVERSE], ALL],
61
+ }
62
+ rescue NameError
63
+ # Give up highlighting Ripper-incompatible older Ruby
64
+ TOKEN_SEQ_EXPRS = {}
65
+ end
66
+ private_constant :TOKEN_SEQ_EXPRS
67
+
68
+ class << self
69
+ def colorable?
70
+ $stdout.tty? && supported? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
71
+ end
72
+
73
+ def inspect_colorable?(obj)
74
+ case obj
75
+ when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass
76
+ true
77
+ when Hash
78
+ obj.all? { |k, v| inspect_colorable?(k) && inspect_colorable?(v) }
79
+ when Array
80
+ obj.all? { |o| inspect_colorable?(o) }
81
+ when Range
82
+ inspect_colorable?(obj.begin) && inspect_colorable?(obj.end)
83
+ when Module
84
+ !obj.name.nil?
85
+ else
86
+ false
87
+ end
88
+ end
89
+
90
+ def clear
91
+ return '' unless colorable?
92
+ "\e[#{CLEAR}m"
93
+ end
94
+
95
+ def colorize(text, seq)
96
+ return text unless colorable?
97
+ seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('')
98
+ "#{seq}#{text}#{clear}"
99
+ end
100
+
101
+ # If `complete` is false (code is incomplete), this does not warn compile_error.
102
+ # This option is needed to avoid warning a user when the compile_error is happening
103
+ # because the input is not wrong but just incomplete.
104
+ def colorize_code(code, complete: true)
105
+ return code unless colorable?
106
+
107
+ symbol_state = SymbolState.new
108
+ colored = +''
109
+ length = 0
110
+
111
+ scan(code, allow_last_error: !complete) do |token, str, expr|
112
+ in_symbol = symbol_state.scan_token(token)
113
+ str.each_line do |line|
114
+ line = Reline::Unicode.escape_for_print(line)
115
+ if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol)
116
+ colored << seq.map { |s| "\e[#{s}m" }.join('')
117
+ colored << line.sub(/\Z/, clear)
118
+ else
119
+ colored << line
120
+ end
121
+ end
122
+ length += str.bytesize
123
+ end
124
+
125
+ # give up colorizing incomplete Ripper tokens
126
+ if length != code.bytesize
127
+ return Reline::Unicode.escape_for_print(code)
128
+ end
129
+
130
+ colored
131
+ end
132
+
133
+ private
134
+
135
+ # Ripper::Lexer::Elem#state is supported on Ruby 2.5+
136
+ def supported?
137
+ return @supported if defined?(@supported)
138
+ @supported = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
139
+ end
140
+
141
+ def scan(code, allow_last_error:)
142
+ pos = [1, 0]
143
+
144
+ lexer = Ripper::Lexer.new(code)
145
+ if lexer.respond_to?(:scan) # Ruby 2.7+
146
+ lexer.scan.each do |elem|
147
+ str = elem.tok
148
+ next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
149
+ next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0
150
+
151
+ str.each_line do |line|
152
+ if line.end_with?("\n")
153
+ pos[0] += 1
154
+ pos[1] = 0
155
+ else
156
+ pos[1] += line.bytesize
157
+ end
158
+ end
159
+
160
+ yield(elem.event, str, elem.state)
161
+ end
162
+ else
163
+ lexer.parse.each do |elem|
164
+ yield(elem.event, elem.tok, elem.state)
165
+ end
166
+ end
167
+ end
168
+
169
+ def dispatch_seq(token, expr, str, in_symbol:)
170
+ if token == :on_parse_error or token == :compile_error
171
+ TOKEN_SEQ_EXPRS[token][0]
172
+ elsif in_symbol
173
+ [YELLOW]
174
+ elsif TOKEN_KEYWORDS.fetch(token, []).include?(str)
175
+ [CYAN, BOLD]
176
+ elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; (expr & (exprs || 0)) != 0)
177
+ seq
178
+ else
179
+ nil
180
+ end
181
+ end
182
+ end
183
+
184
+ # A class to manage a state to know whether the current token is for Symbol or not.
185
+ class SymbolState
186
+ def initialize
187
+ # Push `true` to detect Symbol. `false` to increase the nest level for non-Symbol.
188
+ @stack = []
189
+ end
190
+
191
+ # Return true if the token is a part of Symbol.
192
+ def scan_token(token)
193
+ prev_state = @stack.last
194
+ case token
195
+ when :on_symbeg
196
+ @stack << true
197
+ when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw
198
+ if @stack.last # Pop only when it's Symbol
199
+ @stack.pop
200
+ return prev_state
201
+ end
202
+ when :on_tstring_beg
203
+ @stack << false
204
+ when :on_embexpr_beg
205
+ @stack << false
206
+ return prev_state
207
+ when :on_tstring_end # :on_tstring_end may close Symbol
208
+ @stack.pop
209
+ return prev_state
210
+ when :on_embexpr_end
211
+ @stack.pop
212
+ end
213
+ @stack.last
214
+ end
215
+ end
216
+ private_constant :SymbolState
217
+ end
218
+ end
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  require "readline"
11
- require "rdoc"
11
+ autoload :RDoc, "rdoc"
12
12
 
13
13
  module IRB
14
14
  module InputCompletor # :nodoc:
@@ -237,7 +237,7 @@ module IRB
237
237
  candidates.uniq!
238
238
  end
239
239
  if doc_namespace
240
- "#{rec.class.name}#{sep}#{candidates.find{ |i| i == message }}"
240
+ "#{rec.name}#{sep}#{candidates.find{ |i| i == message }}"
241
241
  else
242
242
  select_message(receiver, message, candidates, sep)
243
243
  end
@@ -267,8 +267,8 @@ module IRB
267
267
  end
268
268
  end
269
269
 
270
- RDocRIDriver = RDoc::RI::Driver.new
271
270
  PerfectMatchedProc = ->(matched) {
271
+ RDocRIDriver ||= RDoc::RI::Driver.new
272
272
  if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
273
273
  File.open(File.join(__dir__, 'ruby_logo.aa')) do |f|
274
274
  RDocRIDriver.page do |io|
@@ -194,17 +194,17 @@ module IRB
194
194
  # Can be either the default <code>IRB.conf[:AUTO_INDENT]</code>, or the
195
195
  # mode set by #prompt_mode=
196
196
  #
197
- # To enable auto-indentation in irb:
197
+ # To disable auto-indentation in irb:
198
198
  #
199
- # IRB.conf[:AUTO_INDENT] = true
199
+ # IRB.conf[:AUTO_INDENT] = false
200
200
  #
201
201
  # or
202
202
  #
203
- # irb_context.auto_indent_mode = true
203
+ # irb_context.auto_indent_mode = false
204
204
  #
205
205
  # or
206
206
  #
207
- # IRB.CurrentContext.auto_indent_mode = true
207
+ # IRB.CurrentContext.auto_indent_mode = false
208
208
  #
209
209
  # See IRB@Configuration for more information.
210
210
  attr_accessor :auto_indent_mode
@@ -22,7 +22,7 @@ module IRB # :nodoc:
22
22
  def set_last_value(value)
23
23
  _set_last_value(value)
24
24
 
25
- if @eval_history
25
+ if defined?(@eval_history) && @eval_history
26
26
  @eval_history_values.push @line_no, @last_value
27
27
  @workspace.evaluate self, "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
28
28
  end
@@ -30,6 +30,7 @@ module IRB # :nodoc:
30
30
  @last_value
31
31
  end
32
32
 
33
+ remove_method :eval_history= if method_defined?(:eval_history=)
33
34
  # The command result history limit.
34
35
  attr_reader :eval_history
35
36
  # Sets command result history limit.
@@ -27,7 +27,7 @@ module IRB
27
27
  IRB.conf[:SAVE_HISTORY]
28
28
  end
29
29
 
30
- remove_method :save_history= if respond_to?(:save_history=)
30
+ remove_method :save_history= if method_defined?(:save_history=)
31
31
  # Sets <code>IRB.conf[:SAVE_HISTORY]</code> to the given +val+ and calls
32
32
  # #init_save_history with this context.
33
33
  #
@@ -73,7 +73,15 @@ module IRB
73
73
  history_file = IRB.rc_file("_history") unless history_file
74
74
  if File.exist?(history_file)
75
75
  open(history_file) do |f|
76
- f.each {|l| history << l.chomp}
76
+ f.each { |l|
77
+ l = l.chomp
78
+ if history.last&.end_with?("\\")
79
+ history.last.delete_suffix!("\\")
80
+ history.last << "\n" << l
81
+ else
82
+ history << l
83
+ end
84
+ }
77
85
  end
78
86
  end
79
87
  end
@@ -98,7 +106,14 @@ module IRB
98
106
  end
99
107
 
100
108
  open(history_file, 'w', 0600 ) do |f|
101
- hist = history.to_a
109
+ hist = history.to_a.map { |l|
110
+ split_lines = l.split("\n")
111
+ if split_lines.size == 1
112
+ l
113
+ else
114
+ split_lines.join("\\\n")
115
+ end
116
+ }
102
117
  f.puts(hist[-num..-1] || hist)
103
118
  end
104
119
  end
@@ -20,10 +20,12 @@ end
20
20
 
21
21
  module IRB
22
22
  module ExtendCommandBundle
23
+ remove_method :irb_load if method_defined?(:irb_load)
23
24
  # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
24
25
  def irb_load(*opts, &b)
25
26
  ExtendCommand::Load.execute(irb_context, *opts, &b)
26
27
  end
28
+ remove_method :irb_require if method_defined?(:irb_require)
27
29
  # Loads the given file similarly to Kernel#require
28
30
  def irb_require(*opts, &b)
29
31
  ExtendCommand::Require.execute(irb_context, *opts, &b)
@@ -44,6 +46,7 @@ module IRB
44
46
 
45
47
  alias use_loader? use_loader
46
48
 
49
+ remove_method :use_loader= if method_defined?(:use_loader=)
47
50
  # Sets IRB.conf[:USE_LOADER]
48
51
  #
49
52
  # See #use_loader for more information.
@@ -54,7 +54,7 @@ module IRB # :nodoc:
54
54
  @CONF[:VERBOSE] = nil
55
55
 
56
56
  @CONF[:EVAL_HISTORY] = nil
57
- @CONF[:SAVE_HISTORY] = nil
57
+ @CONF[:SAVE_HISTORY] = 1000
58
58
 
59
59
  @CONF[:BACK_TRACE_LIMIT] = 16
60
60
 
@@ -105,7 +105,7 @@ module IRB # :nodoc:
105
105
  }
106
106
 
107
107
  @CONF[:PROMPT_MODE] = (STDIN.tty? ? :DEFAULT : :NULL)
108
- @CONF[:AUTO_INDENT] = false
108
+ @CONF[:AUTO_INDENT] = true
109
109
 
110
110
  @CONF[:CONTEXT_MODE] = 3 # use binding in function on TOPLEVEL_BINDING
111
111
  @CONF[:SINGLE_IRB] = false
@@ -240,12 +240,22 @@ module IRB
240
240
  @check_termination_proc = block
241
241
  end
242
242
 
243
+ def dynamic_prompt(&block)
244
+ @prompt_proc = block
245
+ end
246
+
247
+ def auto_indent(&block)
248
+ @auto_indent_proc = block
249
+ end
250
+
243
251
  # Reads the next line from this input method.
244
252
  #
245
253
  # See IO#gets for more information.
246
254
  def gets
247
255
  Reline.input = @stdin
248
256
  Reline.output = @stdout
257
+ Reline.prompt_proc = @prompt_proc
258
+ Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
249
259
  if l = readmultiline(@prompt, false, &@check_termination_proc)
250
260
  HISTORY.push(l) if !l.empty?
251
261
  @line[@line_no += 1] = l + "\n"
@@ -22,7 +22,7 @@ Usage: irb.rb [options] [programfile] [arguments]
22
22
  when new workspace was created
23
23
  --echo Show result(default)
24
24
  --noecho Don't show result
25
- --inspect Use `inspect' for output (default except for bc mode)
25
+ --inspect Use `inspect' for output
26
26
  --noinspect Don't use inspect for output
27
27
  --readline Use Readline extension module
28
28
  --noreadline Don't use Readline extension module
@@ -21,7 +21,7 @@ Usage: irb.rb [options] [programfile] [arguments]
21
21
  オブジェクトの作成方法を 0 から 3 のいずれかに設定する.
22
22
  --echo 実行結果を表示する(デフォルト).
23
23
  --noecho 実行結果を表示しない.
24
- --inspect 結果出力にinspectを用いる(bcモード以外はデフォルト).
24
+ --inspect 結果出力にinspectを用いる.
25
25
  --noinspect 結果出力にinspectを用いない.
26
26
  --readline readlineライブラリを利用する.
27
27
  --noreadline readlineライブラリを利用しない.
@@ -33,18 +33,26 @@ class RubyLex
33
33
  if @io.respond_to?(:check_termination)
34
34
  @io.check_termination do |code|
35
35
  code.gsub!(/\s*\z/, '').concat("\n")
36
- @tokens = Ripper.lex(code)
37
- continue = process_continue
38
- code_block_open = check_code_block(code)
39
- indent = process_nesting_level
40
- ltype = process_literal_type
41
- if code_block_open or ltype or continue or indent > 0
36
+ ltype, indent, continue, code_block_open = check_state(code)
37
+ if ltype or indent > 0 or continue or code_block_open
42
38
  false
43
39
  else
44
40
  true
45
41
  end
46
42
  end
47
43
  end
44
+ if @io.respond_to?(:dynamic_prompt)
45
+ @io.dynamic_prompt do |lines|
46
+ lines << '' if lines.empty?
47
+ result = []
48
+ lines.each_index { |i|
49
+ c = lines[0..i].map{ |l| l + "\n" }.join
50
+ ltype, indent, continue, code_block_open = check_state(c)
51
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + i)
52
+ }
53
+ result
54
+ end
55
+ end
48
56
  if p.respond_to?(:call)
49
57
  @input = p
50
58
  elsif block_given?
@@ -63,6 +71,40 @@ class RubyLex
63
71
  end
64
72
  end
65
73
 
74
+ def set_auto_indent(context)
75
+ if @io.respond_to?(:auto_indent) and context.auto_indent_mode
76
+ @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
77
+ if is_newline
78
+ md = lines[line_index - 1].match(/(\A +)/)
79
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
80
+ @tokens = Ripper.lex(lines[0..line_index].join("\n"))
81
+ depth_difference = check_newline_depth_difference
82
+ prev_spaces + depth_difference * 2
83
+ else
84
+ code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
85
+ last_line = lines[line_index]&.byteslice(0, byte_pointer)
86
+ code += last_line if last_line
87
+ @tokens = Ripper.lex(code)
88
+ corresponding_token_depth = check_corresponding_token_depth
89
+ if corresponding_token_depth
90
+ corresponding_token_depth
91
+ else
92
+ nil
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ def check_state(code)
100
+ @tokens = Ripper.lex(code)
101
+ ltype = process_literal_type
102
+ indent = process_nesting_level
103
+ continue = process_continue
104
+ code_block_open = check_code_block(code)
105
+ [ltype, indent, continue, code_block_open]
106
+ end
107
+
66
108
  def prompt
67
109
  if @prompt
68
110
  @prompt.call(@ltype, @indent, @continue, @line_no)
@@ -87,7 +129,7 @@ class RubyLex
87
129
  unless l = lex
88
130
  throw :TERM_INPUT if @line == ''
89
131
  else
90
- @line_no += 1
132
+ @line_no += l.count("\n")
91
133
  next if l == "\n"
92
134
  @line.concat l
93
135
  if @code_block_open or @ltype or @continue or @indent > 0
@@ -127,14 +169,13 @@ class RubyLex
127
169
  end
128
170
 
129
171
  def process_continue
130
- continued_bits = Ripper::EXPR_BEG | Ripper::EXPR_FNAME
131
172
  # last token is always newline
132
173
  if @tokens.size >= 2 and @tokens[-2][1] == :on_regexp_end
133
174
  # end of regexp literal
134
175
  return false
135
176
  elsif @tokens.size >= 2 and @tokens[-2][1] == :on_semicolon
136
177
  return false
137
- elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and (@tokens[-2][2] == 'begin' or @tokens[-2][2] == 'else')
178
+ elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(@tokens[-2][2])
138
179
  return false
139
180
  elsif @tokens.size >= 3 and @tokens[-3][1] == :on_symbeg and @tokens[-2][1] == :on_ivar
140
181
  # This is for :@a or :@1 because :@1 ends with EXPR_FNAME
@@ -149,7 +190,7 @@ class RubyLex
149
190
  return true
150
191
  elsif @tokens.size >= 1 and @tokens[-1][1] == :on_heredoc_end # "EOH\n"
151
192
  return false
152
- elsif @tokens.size >= 2 and @tokens[-2][3].anybits?(continued_bits)
193
+ elsif @tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and @tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
153
194
  # end of literal except for regexp
154
195
  return true
155
196
  end
@@ -221,36 +262,40 @@ class RubyLex
221
262
  $VERBOSE = verbose
222
263
  end
223
264
 
224
- last_lex_state = @tokens.last[3]
225
- if last_lex_state.allbits?(Ripper::EXPR_BEG)
226
- return false
227
- elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
228
- return true
229
- elsif last_lex_state.allbits?(Ripper::EXPR_CLASS)
230
- return true
231
- elsif last_lex_state.allbits?(Ripper::EXPR_FNAME)
232
- return true
233
- elsif last_lex_state.allbits?(Ripper::EXPR_VALUE)
234
- return true
235
- elsif last_lex_state.allbits?(Ripper::EXPR_ARG)
236
- return false
265
+ if defined?(Ripper::EXPR_BEG)
266
+ last_lex_state = @tokens.last[3]
267
+ if last_lex_state.allbits?(Ripper::EXPR_BEG)
268
+ return false
269
+ elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
270
+ return true
271
+ elsif last_lex_state.allbits?(Ripper::EXPR_CLASS)
272
+ return true
273
+ elsif last_lex_state.allbits?(Ripper::EXPR_FNAME)
274
+ return true
275
+ elsif last_lex_state.allbits?(Ripper::EXPR_VALUE)
276
+ return true
277
+ elsif last_lex_state.allbits?(Ripper::EXPR_ARG)
278
+ return false
279
+ end
237
280
  end
238
281
 
239
282
  false
240
283
  end
241
284
 
242
285
  def process_nesting_level
243
- @tokens.inject(0) { |indent, t|
286
+ indent = 0
287
+ @tokens.each_with_index { |t, index|
244
288
  case t[1]
245
289
  when :on_lbracket, :on_lbrace, :on_lparen
246
290
  indent += 1
247
291
  when :on_rbracket, :on_rbrace, :on_rparen
248
292
  indent -= 1
249
293
  when :on_kw
294
+ next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
250
295
  case t[2]
251
296
  when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
252
297
  indent += 1
253
- when 'if', 'unless', 'while', 'until', 'rescue'
298
+ when 'if', 'unless', 'while', 'until'
254
299
  # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
255
300
  indent += 1 unless t[3].allbits?(Ripper::EXPR_LABEL)
256
301
  when 'end'
@@ -258,8 +303,99 @@ class RubyLex
258
303
  end
259
304
  end
260
305
  # percent literals are not indented
261
- indent
262
306
  }
307
+ indent
308
+ end
309
+
310
+ def check_newline_depth_difference
311
+ depth_difference = 0
312
+ @tokens.each_with_index do |t, index|
313
+ case t[1]
314
+ when :on_ignored_nl, :on_nl
315
+ if index != (@tokens.size - 1)
316
+ depth_difference = 0
317
+ end
318
+ next
319
+ when :on_sp
320
+ next
321
+ end
322
+ case t[1]
323
+ when :on_lbracket, :on_lbrace, :on_lparen
324
+ depth_difference += 1
325
+ when :on_rbracket, :on_rbrace, :on_rparen
326
+ depth_difference -= 1
327
+ when :on_kw
328
+ next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
329
+ case t[2]
330
+ when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
331
+ depth_difference += 1
332
+ when 'if', 'unless', 'while', 'until'
333
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
334
+ unless t[3].allbits?(Ripper::EXPR_LABEL)
335
+ depth_difference += 1
336
+ end
337
+ when 'else', 'elsif', 'rescue', 'ensure', 'when', 'in'
338
+ depth_difference += 1
339
+ end
340
+ end
341
+ end
342
+ depth_difference
343
+ end
344
+
345
+ def check_corresponding_token_depth
346
+ corresponding_token_depth = nil
347
+ is_first_spaces_of_line = true
348
+ is_first_printable_of_line = true
349
+ spaces_of_nest = []
350
+ spaces_at_line_head = 0
351
+ @tokens.each_with_index do |t, index|
352
+ corresponding_token_depth = nil
353
+ case t[1]
354
+ when :on_ignored_nl, :on_nl
355
+ spaces_at_line_head = 0
356
+ is_first_spaces_of_line = true
357
+ is_first_printable_of_line = true
358
+ next
359
+ when :on_sp
360
+ spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
361
+ is_first_spaces_of_line = false
362
+ next
363
+ end
364
+ case t[1]
365
+ when :on_lbracket, :on_lbrace, :on_lparen
366
+ spaces_of_nest.push(spaces_at_line_head)
367
+ when :on_rbracket, :on_rbrace, :on_rparen
368
+ if is_first_printable_of_line
369
+ corresponding_token_depth = spaces_of_nest.pop
370
+ else
371
+ spaces_of_nest.pop
372
+ corresponding_token_depth = nil
373
+ end
374
+ when :on_kw
375
+ next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
376
+ case t[2]
377
+ when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
378
+ spaces_of_nest.push(spaces_at_line_head)
379
+ when 'if', 'unless', 'while', 'until'
380
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
381
+ unless t[3].allbits?(Ripper::EXPR_LABEL)
382
+ spaces_of_nest.push(spaces_at_line_head)
383
+ end
384
+ when 'else', 'elsif', 'rescue', 'ensure', 'when', 'in'
385
+ corresponding_token_depth = spaces_of_nest.last
386
+ when 'end'
387
+ if is_first_printable_of_line
388
+ corresponding_token_depth = spaces_of_nest.pop
389
+ else
390
+ spaces_of_nest.pop
391
+ corresponding_token_depth = nil
392
+ end
393
+ end
394
+ end
395
+ is_first_spaces_of_line = false
396
+ is_first_printable_of_line = false
397
+ end
398
+ corresponding_token_depth
263
399
  end
264
400
 
265
401
  def check_string_literal
@@ -11,7 +11,7 @@
11
11
  #
12
12
 
13
13
  module IRB # :nodoc:
14
- VERSION = "1.1.0.pre.1"
14
+ VERSION = "1.1.0.pre.2"
15
15
  @RELEASE_VERSION = VERSION
16
- @LAST_UPDATE_DATE = "2019-05-31"
16
+ @LAST_UPDATE_DATE = "2019-07-15"
17
17
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: irb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0.pre.1
4
+ version: 1.1.0.pre.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keiju ISHITSUKA
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-18 00:00:00.000000000 Z
11
+ date: 2019-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: reline
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.1
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +72,7 @@ files:
58
72
  - lib/irb/cmd/nop.rb
59
73
  - lib/irb/cmd/pushws.rb
60
74
  - lib/irb/cmd/subirb.rb
75
+ - lib/irb/color.rb
61
76
  - lib/irb/completion.rb
62
77
  - lib/irb/context.rb
63
78
  - lib/irb/ext/change-ws.rb