irb 1.16.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ab1ed5aa7bab885e57c409b5267ae77c02dd4dfce34fe1099bf2407c0f78c82
4
- data.tar.gz: 84b33ebb88359bc8eea1480f08f46b930e2e18e350121f9cf06934d3b51f631e
3
+ metadata.gz: a457883af2f8f76b44bca4458e71fb4260244d033ab119f0cbc828b94bce01b5
4
+ data.tar.gz: 22dca36785746338f9b0928fd0a16d5a36c4766f9360be937869ab7e89e01966
5
5
  SHA512:
6
- metadata.gz: 2ce74e4d4954c7606b2b74f5a7138e5c4e21690a819d63256c21ed2f6f05d077355ab59b9fa91407beec6e5db74d2b117b6dd434805aae53878041fd871c123f
7
- data.tar.gz: d1fcf2223fdda3720fcc2c2d0e6d980e8b16a204ad6c31b503002e19047eb70b4f385b902de2dc6d6a5d7471a731371e8c99e86df1f02a3d975d639e74fda657
6
+ metadata.gz: 284c0962361358e0aed3f0ded870a8f2bacafe1ab52d68df26f6e97e48d92396b75e78ab7a7019fc35d555a2c4016957fe4ac3017828f506d58828d9c83df16c
7
+ data.tar.gz: 8417bb9569aae0a3397db838c2ca51d45be16b473ee2f986fb0c03168c8f8f5c2800d30f13bb92436c0ca6cc4ff22f70abcf33db12f647e2c157772069735e96
data/Gemfile CHANGED
@@ -24,8 +24,14 @@ gem "debug", github: "ruby/debug"
24
24
 
25
25
  gem "rdoc", ">= 6.11.0"
26
26
 
27
+ if ENV['PRISM_VERSION'] == 'latest'
28
+ gem "prism", github: "ruby/prism"
29
+ elsif ENV['PRISM_VERSION']
30
+ gem "prism", ENV['PRISM_VERSION']
31
+ else
32
+ gem "prism", "!= 1.8.0"
33
+ end
34
+
27
35
  if RUBY_VERSION >= "3.0.0" && !is_truffleruby
28
- # TODO: Remove this after rbs is released with tsort in its dependencies
29
- gem "rbs", github: "ruby/rbs" if RUBY_VERSION >= "3.2"
30
36
  gem "repl_type_completor"
31
37
  end
data/lib/irb/color.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'reline'
3
- require 'ripper'
3
+ require 'prism'
4
4
  require_relative 'ruby-lex'
5
5
 
6
6
  module IRB # :nodoc:
@@ -18,65 +18,100 @@ module IRB # :nodoc:
18
18
  CYAN = 36
19
19
  WHITE = 37
20
20
 
21
- TOKEN_KEYWORDS = {
22
- on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__', '__ENCODING__'],
23
- on_const: ['ENV'],
24
- }
25
- private_constant :TOKEN_KEYWORDS
26
-
27
- # A constant of all-bit 1 to match any Ripper's state in #dispatch_seq
28
- ALL = -1
29
- private_constant :ALL
30
-
31
- begin
32
- # Following pry's colors where possible, but sometimes having a compromise like making
33
- # backtick and regexp as red (string's color, because they're sharing tokens).
34
- TOKEN_SEQ_EXPRS = {
35
- on_CHAR: [[BLUE, BOLD], ALL],
36
- on_backtick: [[RED, BOLD], ALL],
37
- on_comment: [[BLUE, BOLD], ALL],
38
- on_const: [[BLUE, BOLD, UNDERLINE], ALL],
39
- on_embexpr_beg: [[RED], ALL],
40
- on_embexpr_end: [[RED], ALL],
41
- on_embvar: [[RED], ALL],
42
- on_float: [[MAGENTA, BOLD], ALL],
43
- on_gvar: [[GREEN, BOLD], ALL],
44
- on_backref: [[GREEN, BOLD], ALL],
45
- on_heredoc_beg: [[RED], ALL],
46
- on_heredoc_end: [[RED], ALL],
47
- on_ident: [[BLUE, BOLD], Ripper::EXPR_ENDFN],
48
- on_imaginary: [[BLUE, BOLD], ALL],
49
- on_int: [[BLUE, BOLD], ALL],
50
- on_kw: [[GREEN], ALL],
51
- on_label: [[MAGENTA], ALL],
52
- on_label_end: [[RED, BOLD], ALL],
53
- on_qsymbols_beg: [[RED, BOLD], ALL],
54
- on_qwords_beg: [[RED, BOLD], ALL],
55
- on_rational: [[BLUE, BOLD], ALL],
56
- on_regexp_beg: [[RED, BOLD], ALL],
57
- on_regexp_end: [[RED, BOLD], ALL],
58
- on_symbeg: [[YELLOW], ALL],
59
- on_symbols_beg: [[RED, BOLD], ALL],
60
- on_tstring_beg: [[RED, BOLD], ALL],
61
- on_tstring_content: [[RED], ALL],
62
- on_tstring_end: [[RED, BOLD], ALL],
63
- on_words_beg: [[RED, BOLD], ALL],
64
- on_parse_error: [[RED, REVERSE], ALL],
65
- compile_error: [[RED, REVERSE], ALL],
66
- on_assign_error: [[RED, REVERSE], ALL],
67
- on_alias_error: [[RED, REVERSE], ALL],
68
- on_class_name_error:[[RED, REVERSE], ALL],
69
- on_param_error: [[RED, REVERSE], ALL],
70
- on___end__: [[GREEN], ALL],
71
- }
72
- rescue NameError
73
- # Give up highlighting Ripper-incompatible older Ruby
74
- TOKEN_SEQ_EXPRS = {}
21
+ # Following pry's colors where possible
22
+ TOKEN_SEQS = {
23
+ KEYWORD_NIL: [CYAN, BOLD],
24
+ KEYWORD_SELF: [CYAN, BOLD],
25
+ KEYWORD_TRUE: [CYAN, BOLD],
26
+ KEYWORD_FALSE: [CYAN, BOLD],
27
+ KEYWORD___FILE__: [CYAN, BOLD],
28
+ KEYWORD___LINE__: [CYAN, BOLD],
29
+ KEYWORD___ENCODING__: [CYAN, BOLD],
30
+ CHARACTER_LITERAL: [BLUE, BOLD],
31
+ BACK_REFERENCE: [GREEN, BOLD],
32
+ BACKTICK: [RED, BOLD],
33
+ COMMENT: [BLUE, BOLD],
34
+ EMBDOC_BEGIN: [BLUE, BOLD],
35
+ EMBDOC_LINE: [BLUE, BOLD],
36
+ EMBDOC_END: [BLUE, BOLD],
37
+ CONSTANT: [BLUE, BOLD, UNDERLINE],
38
+ EMBEXPR_BEGIN: [RED],
39
+ EMBEXPR_END: [RED],
40
+ EMBVAR: [RED],
41
+ FLOAT: [MAGENTA, BOLD],
42
+ GLOBAL_VARIABLE: [GREEN, BOLD],
43
+ HEREDOC_START: [RED],
44
+ HEREDOC_END: [RED],
45
+ FLOAT_IMAGINARY: [BLUE, BOLD],
46
+ INTEGER_IMAGINARY: [BLUE, BOLD],
47
+ FLOAT_RATIONAL_IMAGINARY: [BLUE, BOLD],
48
+ INTEGER_RATIONAL_IMAGINARY: [BLUE, BOLD],
49
+ INTEGER: [BLUE, BOLD],
50
+ INTEGER_RATIONAL: [BLUE, BOLD],
51
+ FLOAT_RATIONAL: [BLUE, BOLD],
52
+ KEYWORD_END: [GREEN],
53
+ KEYWORD_CLASS: [GREEN],
54
+ KEYWORD_MODULE: [GREEN],
55
+ KEYWORD_IF: [GREEN],
56
+ KEYWORD_IF_MODIFIER: [GREEN],
57
+ KEYWORD_UNLESS_MODIFIER: [GREEN],
58
+ KEYWORD_WHILE_MODIFIER: [GREEN],
59
+ KEYWORD_UNTIL_MODIFIER: [GREEN],
60
+ KEYWORD_RESCUE_MODIFIER: [GREEN],
61
+ KEYWORD_THEN: [GREEN],
62
+ KEYWORD_UNLESS: [GREEN],
63
+ KEYWORD_ELSE: [GREEN],
64
+ KEYWORD_ELSIF: [GREEN],
65
+ KEYWORD_WHILE: [GREEN],
66
+ KEYWORD_UNTIL: [GREEN],
67
+ KEYWORD_CASE: [GREEN],
68
+ KEYWORD_WHEN: [GREEN],
69
+ KEYWORD_IN: [GREEN],
70
+ KEYWORD_DEF: [GREEN],
71
+ KEYWORD_DO: [GREEN],
72
+ KEYWORD_DO_LOOP: [GREEN],
73
+ KEYWORD_FOR: [GREEN],
74
+ KEYWORD_BEGIN: [GREEN],
75
+ KEYWORD_RESCUE: [GREEN],
76
+ KEYWORD_ENSURE: [GREEN],
77
+ KEYWORD_ALIAS: [GREEN],
78
+ KEYWORD_UNDEF: [GREEN],
79
+ KEYWORD_BEGIN_UPCASE: [GREEN],
80
+ KEYWORD_END_UPCASE: [GREEN],
81
+ KEYWORD_YIELD: [GREEN],
82
+ KEYWORD_REDO: [GREEN],
83
+ KEYWORD_RETRY: [GREEN],
84
+ KEYWORD_NEXT: [GREEN],
85
+ KEYWORD_BREAK: [GREEN],
86
+ KEYWORD_SUPER: [GREEN],
87
+ KEYWORD_RETURN: [GREEN],
88
+ KEYWORD_DEFINED: [GREEN],
89
+ KEYWORD_NOT: [GREEN],
90
+ KEYWORD_AND: [GREEN],
91
+ KEYWORD_OR: [GREEN],
92
+ LABEL: [MAGENTA],
93
+ LABEL_END: [RED, BOLD],
94
+ NUMBERED_REFERENCE: [GREEN, BOLD],
95
+ PERCENT_UPPER_W: [RED, BOLD],
96
+ PERCENT_LOWER_W: [RED, BOLD],
97
+ PERCENT_LOWER_X: [RED, BOLD],
98
+ REGEXP_BEGIN: [RED, BOLD],
99
+ REGEXP_END: [RED, BOLD],
100
+ STRING_BEGIN: [RED, BOLD],
101
+ STRING_CONTENT: [RED],
102
+ STRING_END: [RED, BOLD],
103
+ __END__: [GREEN],
104
+ # tokens from syntax tree traversal
105
+ method_name: [BLUE, BOLD],
106
+ symbol: [YELLOW],
107
+ # special colorization
108
+ error: [RED, REVERSE],
109
+ const_env: [CYAN, BOLD],
110
+ }.transform_values do |styles|
111
+ styles.map { |style| "\e[#{style}m" }.join
75
112
  end
76
- private_constant :TOKEN_SEQ_EXPRS
77
-
78
- ERROR_TOKENS = TOKEN_SEQ_EXPRS.keys.select { |k| k.to_s.end_with?('error') }
79
- private_constant :ERROR_TOKENS
113
+ CLEAR_SEQ = "\e[#{CLEAR}m"
114
+ private_constant :TOKEN_SEQS, :CLEAR_SEQ
80
115
 
81
116
  class << self
82
117
  def colorable?
@@ -113,14 +148,13 @@ module IRB # :nodoc:
113
148
  end
114
149
 
115
150
  def clear(colorable: colorable?)
116
- return '' unless colorable
117
- "\e[#{CLEAR}m"
151
+ colorable ? CLEAR_SEQ : ''
118
152
  end
119
153
 
120
154
  def colorize(text, seq, colorable: colorable?)
121
155
  return text unless colorable
122
156
  seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('')
123
- "#{seq}#{text}#{clear(colorable: colorable)}"
157
+ "#{seq}#{text}#{CLEAR_SEQ}"
124
158
  end
125
159
 
126
160
  # If `complete` is false (code is incomplete), this does not warn compile_error.
@@ -129,135 +163,132 @@ module IRB # :nodoc:
129
163
  def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?, local_variables: [])
130
164
  return code unless colorable
131
165
 
132
- symbol_state = SymbolState.new
133
- colored = +''
134
- lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
135
- code_with_lvars = lvars_code ? "#{lvars_code}\n#{code}" : code
166
+ result = Prism.parse_lex(code, scopes: [local_variables])
136
167
 
137
- scan(code_with_lvars, allow_last_error: !complete) do |token, str, expr|
138
- # handle uncolorable code
139
- if token.nil?
140
- colored << Reline::Unicode.escape_for_print(str)
141
- next
142
- end
168
+ # IRB::ColorPrinter skips colorizing syntax invalid fragments
169
+ return Reline::Unicode.escape_for_print(code) if ignore_error && !result.success?
170
+
171
+ errors = result.errors
172
+ unless complete
173
+ errors = errors.reject { |error| error.message =~ /\Aexpected a|unexpected end-of-input|unterminated/ }
174
+ end
175
+
176
+ prism_node, prism_tokens = result.value
177
+ visitor = ColorizeVisitor.new
178
+ prism_node.accept(visitor)
179
+
180
+ error_tokens = errors.map { |e| [e.location.start_line, e.location.start_column, 0, e.location.end_line, e.location.end_column, :error, e.location.slice] }
181
+ error_tokens.reject! { |t| t.last.match?(/\A\s*\z/) }
182
+ tokens = prism_tokens.map { |t,| [t.location.start_line, t.location.start_column, 2, t.location.end_line, t.location.end_column, t.type, t.value] }
183
+ tokens.pop if tokens.last&.[](5) == :EOF
143
184
 
144
- # IRB::ColorPrinter skips colorizing fragments with any invalid token
145
- if ignore_error && ERROR_TOKENS.include?(token)
146
- return Reline::Unicode.escape_for_print(code)
185
+ colored = +''
186
+ line_index = 0
187
+ col = 0
188
+ lines = code.lines
189
+ flush = -> next_line_index, next_col {
190
+ return if next_line_index == line_index && next_col == col
191
+ (line_index...[next_line_index, lines.size].min).each do |ln|
192
+ colored << Reline::Unicode.escape_for_print(lines[line_index].byteslice(col..))
193
+ line_index = ln + 1
194
+ col = 0
195
+ end
196
+ unless col == next_col
197
+ colored << Reline::Unicode.escape_for_print(lines[next_line_index].byteslice(col..next_col - 1))
147
198
  end
199
+ }
200
+
201
+ (visitor.tokens + tokens + error_tokens).sort.each do |start_line, start_column, _priority, end_line, end_column, type, value|
202
+ next if start_line - 1 < line_index || (start_line - 1 == line_index && start_column < col)
148
203
 
149
- in_symbol = symbol_state.scan_token(token)
150
- str.each_line do |line|
151
- line = Reline::Unicode.escape_for_print(line)
152
- if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol)
153
- colored << seq.map { |s| "\e[#{s}m" }.join('')
154
- colored << line.sub(/\Z/, clear(colorable: colorable))
155
- else
156
- colored << line
204
+ flush.call(start_line - 1, start_column)
205
+ if type == :CONSTANT && value == 'ENV'
206
+ color = TOKEN_SEQS[:const_env]
207
+ elsif type == :__END__
208
+ color = TOKEN_SEQS[type]
209
+ end_line = start_line
210
+ value = '__END__'
211
+ end_column = start_column + 7
212
+ else
213
+ color = TOKEN_SEQS[type]
214
+ end
215
+ if color
216
+ value.split(/(\n)/).each do |s|
217
+ colored << (s == "\n" ? s : "#{color}#{Reline::Unicode.escape_for_print(s)}#{CLEAR_SEQ}")
157
218
  end
219
+ else
220
+ colored << value
158
221
  end
222
+ line_index = end_line - 1
223
+ col = end_column
159
224
  end
160
-
161
- if lvars_code
162
- raise "#{lvars_code.dump} should have no \\n" if lvars_code.include?("\n")
163
- colored.sub!(/\A.+\n/, '') # delete_prefix lvars_code with colors
164
- end
225
+ flush.call lines.size, 0
165
226
  colored
166
227
  end
167
228
 
168
- private
169
-
170
- def without_circular_ref(obj, seen:, &block)
171
- return false if seen.key?(obj)
172
- seen[obj] = true
173
- block.call
174
- ensure
175
- seen.delete(obj)
176
- end
229
+ class ColorizeVisitor < Prism::Visitor
230
+ attr_reader :tokens
231
+ def initialize
232
+ @tokens = []
233
+ end
177
234
 
178
- def scan(code, allow_last_error:)
179
- verbose, $VERBOSE = $VERBOSE, nil
180
- RubyLex.compile_with_errors_suppressed(code) do |inner_code, line_no|
181
- lexer = Ripper::Lexer.new(inner_code, '(ripper)', line_no)
182
- byte_pos = 0
183
- line_positions = [0]
184
- inner_code.lines.each do |line|
185
- line_positions << line_positions.last + line.bytesize
235
+ def dispatch(location, type)
236
+ if location
237
+ @tokens << [location.start_line, location.start_column, 1, location.end_line, location.end_column, type, location.slice]
186
238
  end
239
+ end
187
240
 
188
- on_scan = proc do |elem|
189
- start_pos = line_positions[elem.pos[0] - 1] + elem.pos[1]
241
+ def visit_array_node(node)
242
+ if node.opening&.match?(/\A%[iI]/)
243
+ dispatch node.opening_loc, :symbol
244
+ dispatch node.closing_loc, :symbol
245
+ end
246
+ super
247
+ end
190
248
 
191
- # yield uncolorable code
192
- if byte_pos < start_pos
193
- yield(nil, inner_code.byteslice(byte_pos...start_pos), nil)
194
- end
249
+ def visit_def_node(node)
250
+ dispatch node.name_loc, :method_name
251
+ super
252
+ end
195
253
 
196
- if byte_pos <= start_pos
197
- str = elem.tok
198
- yield(elem.event, str, elem.state)
199
- byte_pos = start_pos + str.bytesize
254
+ def visit_interpolated_symbol_node(node)
255
+ dispatch node.opening_loc, :symbol
256
+ node.parts.each do |part|
257
+ case part
258
+ when Prism::StringNode
259
+ dispatch part.content_loc, :symbol
260
+ when Prism::EmbeddedStatementsNode
261
+ dispatch part.opening_loc, :symbol
262
+ dispatch part.closing_loc, :symbol
263
+ when Prism::EmbeddedVariableNode
264
+ dispatch part.operator_loc, :symbol
200
265
  end
201
266
  end
267
+ dispatch node.closing_loc, :symbol
268
+ super
269
+ end
202
270
 
203
- lexer.scan.each do |elem|
204
- next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
205
- on_scan.call(elem)
271
+ def visit_symbol_node(node)
272
+ if (node.opening_loc.nil? && node.closing == ':') || node.closing&.match?(/\A['"]:\z/)
273
+ # Colorize { symbol: 1 } and { 'symbol': 1 } as label
274
+ dispatch node.location, :LABEL
275
+ else
276
+ dispatch node.opening_loc, :symbol
277
+ dispatch node.value_loc, :symbol
278
+ dispatch node.closing_loc, :symbol
206
279
  end
207
- # yield uncolorable DATA section
208
- yield(nil, inner_code.byteslice(byte_pos...inner_code.bytesize), nil) if byte_pos < inner_code.bytesize
209
280
  end
210
- ensure
211
- $VERBOSE = verbose
212
281
  end
213
282
 
214
- def dispatch_seq(token, expr, str, in_symbol:)
215
- if ERROR_TOKENS.include?(token)
216
- TOKEN_SEQ_EXPRS[token][0]
217
- elsif in_symbol
218
- [YELLOW]
219
- elsif TOKEN_KEYWORDS.fetch(token, []).include?(str)
220
- [CYAN, BOLD]
221
- elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; (expr & (exprs || 0)) != 0)
222
- seq
223
- else
224
- nil
225
- end
226
- end
227
- end
228
-
229
- # A class to manage a state to know whether the current token is for Symbol or not.
230
- class SymbolState
231
- def initialize
232
- # Push `true` to detect Symbol. `false` to increase the nest level for non-Symbol.
233
- @stack = []
234
- end
283
+ private
235
284
 
236
- # Return true if the token is a part of Symbol.
237
- def scan_token(token)
238
- prev_state = @stack.last
239
- case token
240
- when :on_symbeg, :on_symbols_beg, :on_qsymbols_beg
241
- @stack << true
242
- when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw, :on_backtick
243
- if @stack.last # Pop only when it's Symbol
244
- @stack.pop
245
- return prev_state
246
- end
247
- when :on_tstring_beg
248
- @stack << false
249
- when :on_embexpr_beg
250
- @stack << false
251
- return prev_state
252
- when :on_tstring_end # :on_tstring_end may close Symbol
253
- @stack.pop
254
- return prev_state
255
- when :on_embexpr_end
256
- @stack.pop
257
- end
258
- @stack.last
285
+ def without_circular_ref(obj, seen:, &block)
286
+ return false if seen.key?(obj)
287
+ seen[obj] = true
288
+ block.call
289
+ ensure
290
+ seen.delete(obj)
259
291
  end
260
292
  end
261
- private_constant :SymbolState
262
293
  end
263
294
  end
@@ -54,6 +54,8 @@ module IRB
54
54
  def clipboard_program
55
55
  @clipboard_program ||= if IRB.conf[:COPY_COMMAND]
56
56
  IRB.conf[:COPY_COMMAND]
57
+ elsif executable?("clip.exe")
58
+ "clip.exe"
57
59
  elsif executable?("pbcopy")
58
60
  "pbcopy"
59
61
  elsif executable?("xclip")
@@ -62,12 +64,20 @@ module IRB
62
64
  end
63
65
 
64
66
  def executable?(command)
65
- system("which #{command} > /dev/null 2>&1")
67
+ if windows?
68
+ system("where #{command} > NUL 2>&1")
69
+ else
70
+ system("which #{command} > /dev/null 2>&1")
71
+ end
66
72
  end
67
73
 
68
74
  def clipboard_available?
69
75
  !!clipboard_program
70
76
  end
77
+
78
+ def windows?
79
+ /mingw|mswin/.match?(RUBY_PLATFORM)
80
+ end
71
81
  end
72
82
  end
73
83
  end
data/lib/irb/context.rb CHANGED
@@ -649,7 +649,7 @@ module IRB
649
649
  parsed_input = parse_input(input, false)
650
650
  if parsed_input.is_a?(Statement::Command)
651
651
  name, sep, arg = input.split(/(\s+)/, 2)
652
- arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars)
652
+ arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars) if arg
653
653
  "#{IRB::Color.colorize(name, [:BOLD])}\e[m#{sep}#{arg}"
654
654
  else
655
655
  IRB::Color.colorize_code(input, complete: complete, local_variables: lvars)
data/lib/irb/debug.rb CHANGED
@@ -49,7 +49,7 @@ module IRB
49
49
  def DEBUGGER__.capture_frames(*args)
50
50
  frames = capture_frames_without_irb(*args)
51
51
  frames.reject! do |frame|
52
- frame.realpath&.start_with?(IRB_DIR) || frame.path.start_with?("<internal:")
52
+ frame.realpath&.start_with?(IRB_DIR) || frame.path&.start_with?("<internal:")
53
53
  end
54
54
  frames
55
55
  end
@@ -87,7 +87,7 @@ module IRB
87
87
  module SkipPathHelperForIRB
88
88
  def skip_internal_path?(path)
89
89
  # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
90
- super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
90
+ super || path&.match?(IRB_DIR) || path&.match?('<internal:prelude>')
91
91
  end
92
92
  end
93
93