irb 1.8.1 → 1.9.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 +4 -4
- data/Gemfile +7 -0
- data/README.md +102 -1
- data/Rakefile +2 -2
- data/lib/irb/cmd/irb_info.rb +1 -0
- data/lib/irb/cmd/show_source.rb +11 -6
- data/lib/irb/completion.rb +87 -94
- data/lib/irb/context.rb +39 -2
- data/lib/irb/debug/ui.rb +2 -3
- data/lib/irb/debug.rb +2 -5
- data/lib/irb/easter-egg.rb +16 -6
- data/lib/irb/history.rb +3 -1
- data/lib/irb/init.rb +41 -0
- data/lib/irb/input-method.rb +155 -83
- data/lib/irb/lc/help-message +3 -0
- data/lib/irb/lc/ja/help-message +3 -0
- data/lib/irb/ruby-lex.rb +14 -41
- data/lib/irb/ruby_logo.aa +43 -0
- data/lib/irb/source_finder.rb +2 -2
- data/lib/irb/type_completion/completor.rb +235 -0
- data/lib/irb/type_completion/methods.rb +13 -0
- data/lib/irb/type_completion/scope.rb +412 -0
- data/lib/irb/type_completion/type_analyzer.rb +1169 -0
- data/lib/irb/type_completion/types.rb +426 -0
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +103 -142
- data/man/irb.1 +7 -0
- metadata +8 -3
data/lib/irb.rb
CHANGED
@@ -140,6 +140,10 @@ require_relative "irb/debug"
|
|
140
140
|
#
|
141
141
|
# IRB.conf[:USE_AUTOCOMPLETE] = false
|
142
142
|
#
|
143
|
+
# To enable enhanced completion using type information, add the following to your +.irbrc+:
|
144
|
+
#
|
145
|
+
# IRB.conf[:COMPLETOR] = :type
|
146
|
+
#
|
143
147
|
# === History
|
144
148
|
#
|
145
149
|
# By default, irb will store the last 1000 commands you used in
|
@@ -367,24 +371,6 @@ module IRB
|
|
367
371
|
# An exception raised by IRB.irb_abort
|
368
372
|
class Abort < Exception;end
|
369
373
|
|
370
|
-
@CONF = {}
|
371
|
-
# Displays current configuration.
|
372
|
-
#
|
373
|
-
# Modifying the configuration is achieved by sending a message to IRB.conf.
|
374
|
-
#
|
375
|
-
# See IRB@Configuration for more information.
|
376
|
-
def IRB.conf
|
377
|
-
@CONF
|
378
|
-
end
|
379
|
-
|
380
|
-
# Returns the current version of IRB, including release version and last
|
381
|
-
# updated date.
|
382
|
-
def IRB.version
|
383
|
-
if v = @CONF[:VERSION] then return v end
|
384
|
-
|
385
|
-
@CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
|
386
|
-
end
|
387
|
-
|
388
374
|
# The current IRB::Context of the session, see IRB.conf
|
389
375
|
#
|
390
376
|
# irb
|
@@ -431,12 +417,18 @@ module IRB
|
|
431
417
|
PROMPT_MAIN_TRUNCATE_OMISSION = '...'.freeze
|
432
418
|
CONTROL_CHARACTERS_PATTERN = "\x00-\x1F".freeze
|
433
419
|
|
420
|
+
# Returns the current context of this irb session
|
421
|
+
attr_reader :context
|
422
|
+
# The lexer used by this irb session
|
423
|
+
attr_accessor :scanner
|
424
|
+
|
434
425
|
# Creates a new irb session
|
435
426
|
def initialize(workspace = nil, input_method = nil)
|
436
427
|
@context = Context.new(self, workspace, input_method)
|
437
428
|
@context.workspace.load_commands_to_main
|
438
429
|
@signal_status = :IN_IRB
|
439
|
-
@scanner = RubyLex.new
|
430
|
+
@scanner = RubyLex.new
|
431
|
+
@line_no = 1
|
440
432
|
end
|
441
433
|
|
442
434
|
# A hook point for `debug` command's breakpoint after :IRB_EXIT as well as its clean-up
|
@@ -454,7 +446,7 @@ module IRB
|
|
454
446
|
workspace = IRB::WorkSpace.new(binding)
|
455
447
|
context.workspace = workspace
|
456
448
|
context.workspace.load_commands_to_main
|
457
|
-
|
449
|
+
@line_no += 1
|
458
450
|
|
459
451
|
# When users run:
|
460
452
|
# 1. Debugging commands, like `step 2`
|
@@ -476,7 +468,7 @@ module IRB
|
|
476
468
|
end
|
477
469
|
|
478
470
|
if input&.include?("\n")
|
479
|
-
|
471
|
+
@line_no += input.count("\n") - 1
|
480
472
|
end
|
481
473
|
|
482
474
|
input
|
@@ -508,39 +500,8 @@ module IRB
|
|
508
500
|
end
|
509
501
|
end
|
510
502
|
|
511
|
-
# Returns the current context of this irb session
|
512
|
-
attr_reader :context
|
513
|
-
# The lexer used by this irb session
|
514
|
-
attr_accessor :scanner
|
515
|
-
|
516
503
|
# Evaluates input for this session.
|
517
504
|
def eval_input
|
518
|
-
@scanner.set_prompt do
|
519
|
-
|ltype, indent, continue, line_no|
|
520
|
-
if ltype
|
521
|
-
f = @context.prompt_s
|
522
|
-
elsif continue
|
523
|
-
f = @context.prompt_c
|
524
|
-
else
|
525
|
-
f = @context.prompt_i
|
526
|
-
end
|
527
|
-
f = "" unless f
|
528
|
-
if @context.prompting?
|
529
|
-
@context.io.prompt = p = prompt(f, ltype, indent, line_no)
|
530
|
-
else
|
531
|
-
@context.io.prompt = p = ""
|
532
|
-
end
|
533
|
-
if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
|
534
|
-
unless ltype
|
535
|
-
prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
|
536
|
-
ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
|
537
|
-
indent * 2 - p.size
|
538
|
-
@context.io.prompt = p + " " * ind if ind > 0
|
539
|
-
end
|
540
|
-
end
|
541
|
-
@context.io.prompt
|
542
|
-
end
|
543
|
-
|
544
505
|
configure_io
|
545
506
|
|
546
507
|
each_top_level_statement do |statement, line_no|
|
@@ -572,8 +533,9 @@ module IRB
|
|
572
533
|
end
|
573
534
|
end
|
574
535
|
|
575
|
-
def read_input
|
536
|
+
def read_input(prompt)
|
576
537
|
signal_status(:IN_INPUT) do
|
538
|
+
@context.io.prompt = prompt
|
577
539
|
if l = @context.io.gets
|
578
540
|
print l if @context.verbose?
|
579
541
|
else
|
@@ -591,16 +553,16 @@ module IRB
|
|
591
553
|
end
|
592
554
|
|
593
555
|
def readmultiline
|
594
|
-
|
556
|
+
prompt = generate_prompt([], false, 0)
|
595
557
|
|
596
558
|
# multiline
|
597
|
-
return read_input if @context.io.respond_to?(:check_termination)
|
559
|
+
return read_input(prompt) if @context.io.respond_to?(:check_termination)
|
598
560
|
|
599
561
|
# nomultiline
|
600
562
|
code = ''
|
601
563
|
line_offset = 0
|
602
564
|
loop do
|
603
|
-
line = read_input
|
565
|
+
line = read_input(prompt)
|
604
566
|
unless line
|
605
567
|
return code.empty? ? nil : code
|
606
568
|
end
|
@@ -610,12 +572,12 @@ module IRB
|
|
610
572
|
# Accept any single-line input for symbol aliases or commands that transform args
|
611
573
|
return code if single_line_command?(code)
|
612
574
|
|
613
|
-
tokens, opens, terminated = @scanner.check_code_state(code)
|
575
|
+
tokens, opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
|
614
576
|
return code if terminated
|
615
577
|
|
616
578
|
line_offset += 1
|
617
579
|
continue = @scanner.should_continue?(tokens)
|
618
|
-
|
580
|
+
prompt = generate_prompt(opens, continue, line_offset)
|
619
581
|
end
|
620
582
|
end
|
621
583
|
|
@@ -625,9 +587,9 @@ module IRB
|
|
625
587
|
break unless code
|
626
588
|
|
627
589
|
if code != "\n"
|
628
|
-
yield build_statement(code), @
|
590
|
+
yield build_statement(code), @line_no
|
629
591
|
end
|
630
|
-
@
|
592
|
+
@line_no += code.count("\n")
|
631
593
|
rescue RubyLex::TerminateLineInput
|
632
594
|
end
|
633
595
|
end
|
@@ -643,7 +605,8 @@ module IRB
|
|
643
605
|
if command_class
|
644
606
|
Statement::Command.new(code, command, arg, command_class)
|
645
607
|
else
|
646
|
-
|
608
|
+
is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
|
609
|
+
Statement::Expression.new(code, is_assignment_expression)
|
647
610
|
end
|
648
611
|
end
|
649
612
|
|
@@ -656,7 +619,7 @@ module IRB
|
|
656
619
|
if @context.io.respond_to?(:check_termination)
|
657
620
|
@context.io.check_termination do |code|
|
658
621
|
if Reline::IOGate.in_pasting?
|
659
|
-
rest = @scanner.check_termination_in_prev_line(code)
|
622
|
+
rest = @scanner.check_termination_in_prev_line(code, local_variables: @context.local_variables)
|
660
623
|
if rest
|
661
624
|
Reline.delete_text
|
662
625
|
rest.bytes.reverse_each do |c|
|
@@ -670,7 +633,7 @@ module IRB
|
|
670
633
|
# Accept any single-line input for symbol aliases or commands that transform args
|
671
634
|
next true if single_line_command?(code)
|
672
635
|
|
673
|
-
_tokens, _opens, terminated = @scanner.check_code_state(code)
|
636
|
+
_tokens, _opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
|
674
637
|
terminated
|
675
638
|
end
|
676
639
|
end
|
@@ -678,7 +641,7 @@ module IRB
|
|
678
641
|
if @context.io.respond_to?(:dynamic_prompt)
|
679
642
|
@context.io.dynamic_prompt do |lines|
|
680
643
|
lines << '' if lines.empty?
|
681
|
-
tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join,
|
644
|
+
tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, local_variables: @context.local_variables)
|
682
645
|
line_results = IRB::NestingParser.parse_by_line(tokens)
|
683
646
|
tokens_until_line = []
|
684
647
|
line_results.map.with_index do |(line_tokens, _prev_opens, next_opens, _min_depth), line_num_offset|
|
@@ -687,7 +650,7 @@ module IRB
|
|
687
650
|
tokens_until_line << token if token != tokens_until_line.last
|
688
651
|
end
|
689
652
|
continue = @scanner.should_continue?(tokens_until_line)
|
690
|
-
|
653
|
+
generate_prompt(next_opens, continue, line_num_offset)
|
691
654
|
end
|
692
655
|
end
|
693
656
|
end
|
@@ -698,7 +661,7 @@ module IRB
|
|
698
661
|
next nil if !is_newline && lines[line_index]&.byteslice(0, byte_pointer)&.match?(/\A\s*\z/)
|
699
662
|
|
700
663
|
code = lines[0..line_index].map { |l| "#{l}\n" }.join
|
701
|
-
tokens = RubyLex.ripper_lex_without_warning(code,
|
664
|
+
tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
|
702
665
|
@scanner.process_indent_level(tokens, lines, line_index, is_newline)
|
703
666
|
end
|
704
667
|
end
|
@@ -828,16 +791,6 @@ module IRB
|
|
828
791
|
end
|
829
792
|
end
|
830
793
|
|
831
|
-
# Evaluates the given block using the given +context+ as the Context.
|
832
|
-
def suspend_context(context)
|
833
|
-
@context, back_context = context, @context
|
834
|
-
begin
|
835
|
-
yield back_context
|
836
|
-
ensure
|
837
|
-
@context = back_context
|
838
|
-
end
|
839
|
-
end
|
840
|
-
|
841
794
|
# Handler for the signal SIGINT, see Kernel#trap for more information.
|
842
795
|
def signal_handle
|
843
796
|
unless @context.ignore_sigint?
|
@@ -873,54 +826,6 @@ module IRB
|
|
873
826
|
end
|
874
827
|
end
|
875
828
|
|
876
|
-
def truncate_prompt_main(str) # :nodoc:
|
877
|
-
str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
|
878
|
-
if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
|
879
|
-
str
|
880
|
-
else
|
881
|
-
str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
|
882
|
-
end
|
883
|
-
end
|
884
|
-
|
885
|
-
def prompt(prompt, ltype, indent, line_no) # :nodoc:
|
886
|
-
p = prompt.dup
|
887
|
-
p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
|
888
|
-
case $2
|
889
|
-
when "N"
|
890
|
-
@context.irb_name
|
891
|
-
when "m"
|
892
|
-
truncate_prompt_main(@context.main.to_s)
|
893
|
-
when "M"
|
894
|
-
truncate_prompt_main(@context.main.inspect)
|
895
|
-
when "l"
|
896
|
-
ltype
|
897
|
-
when "i"
|
898
|
-
if indent < 0
|
899
|
-
if $1
|
900
|
-
"-".rjust($1.to_i)
|
901
|
-
else
|
902
|
-
"-"
|
903
|
-
end
|
904
|
-
else
|
905
|
-
if $1
|
906
|
-
format("%" + $1 + "d", indent)
|
907
|
-
else
|
908
|
-
indent.to_s
|
909
|
-
end
|
910
|
-
end
|
911
|
-
when "n"
|
912
|
-
if $1
|
913
|
-
format("%" + $1 + "d", line_no)
|
914
|
-
else
|
915
|
-
line_no.to_s
|
916
|
-
end
|
917
|
-
when "%"
|
918
|
-
"%"
|
919
|
-
end
|
920
|
-
end
|
921
|
-
p
|
922
|
-
end
|
923
|
-
|
924
829
|
def output_value(omit = false) # :nodoc:
|
925
830
|
str = @context.inspect_last_value
|
926
831
|
multiline_p = str.include?("\n")
|
@@ -973,28 +878,84 @@ module IRB
|
|
973
878
|
end
|
974
879
|
format("#<%s: %s>", self.class, ary.join(", "))
|
975
880
|
end
|
976
|
-
end
|
977
881
|
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
format(":%s=>{%s}", kk.id2name, ss.join(", "))
|
991
|
-
}
|
992
|
-
array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
|
882
|
+
private
|
883
|
+
|
884
|
+
def generate_prompt(opens, continue, line_offset)
|
885
|
+
ltype = @scanner.ltype_from_open_tokens(opens)
|
886
|
+
indent = @scanner.calc_indent_level(opens)
|
887
|
+
continue = opens.any? || continue
|
888
|
+
line_no = @line_no + line_offset
|
889
|
+
|
890
|
+
if ltype
|
891
|
+
f = @context.prompt_s
|
892
|
+
elsif continue
|
893
|
+
f = @context.prompt_c
|
993
894
|
else
|
994
|
-
|
895
|
+
f = @context.prompt_i
|
896
|
+
end
|
897
|
+
f = "" unless f
|
898
|
+
if @context.prompting?
|
899
|
+
p = format_prompt(f, ltype, indent, line_no)
|
900
|
+
else
|
901
|
+
p = ""
|
902
|
+
end
|
903
|
+
if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
|
904
|
+
unless ltype
|
905
|
+
prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
|
906
|
+
ind = format_prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
|
907
|
+
indent * 2 - p.size
|
908
|
+
p += " " * ind if ind > 0
|
909
|
+
end
|
910
|
+
end
|
911
|
+
p
|
912
|
+
end
|
913
|
+
|
914
|
+
def truncate_prompt_main(str) # :nodoc:
|
915
|
+
str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
|
916
|
+
if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
|
917
|
+
str
|
918
|
+
else
|
919
|
+
str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
923
|
+
def format_prompt(format, ltype, indent, line_no) # :nodoc:
|
924
|
+
format.gsub(/%([0-9]+)?([a-zA-Z])/) do
|
925
|
+
case $2
|
926
|
+
when "N"
|
927
|
+
@context.irb_name
|
928
|
+
when "m"
|
929
|
+
truncate_prompt_main(@context.main.to_s)
|
930
|
+
when "M"
|
931
|
+
truncate_prompt_main(@context.main.inspect)
|
932
|
+
when "l"
|
933
|
+
ltype
|
934
|
+
when "i"
|
935
|
+
if indent < 0
|
936
|
+
if $1
|
937
|
+
"-".rjust($1.to_i)
|
938
|
+
else
|
939
|
+
"-"
|
940
|
+
end
|
941
|
+
else
|
942
|
+
if $1
|
943
|
+
format("%" + $1 + "d", indent)
|
944
|
+
else
|
945
|
+
indent.to_s
|
946
|
+
end
|
947
|
+
end
|
948
|
+
when "n"
|
949
|
+
if $1
|
950
|
+
format("%" + $1 + "d", line_no)
|
951
|
+
else
|
952
|
+
line_no.to_s
|
953
|
+
end
|
954
|
+
when "%"
|
955
|
+
"%"
|
956
|
+
end
|
995
957
|
end
|
996
958
|
end
|
997
|
-
array.join("\n")
|
998
959
|
end
|
999
960
|
end
|
1000
961
|
|
data/man/irb.1
CHANGED
@@ -140,6 +140,13 @@ Use autocompletion.
|
|
140
140
|
Don't use autocompletion.
|
141
141
|
.Pp
|
142
142
|
.Pp
|
143
|
+
.It Fl -regexp-completor
|
144
|
+
Use regexp based completion.
|
145
|
+
.Pp
|
146
|
+
.It Fl -type-completor
|
147
|
+
Use type based completion.
|
148
|
+
.Pp
|
149
|
+
.Pp
|
143
150
|
.It Fl -verbose
|
144
151
|
Show details.
|
145
152
|
.Pp
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: irb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: reline
|
@@ -118,6 +118,11 @@ files:
|
|
118
118
|
- lib/irb/ruby_logo.aa
|
119
119
|
- lib/irb/source_finder.rb
|
120
120
|
- lib/irb/statement.rb
|
121
|
+
- lib/irb/type_completion/completor.rb
|
122
|
+
- lib/irb/type_completion/methods.rb
|
123
|
+
- lib/irb/type_completion/scope.rb
|
124
|
+
- lib/irb/type_completion/type_analyzer.rb
|
125
|
+
- lib/irb/type_completion/types.rb
|
121
126
|
- lib/irb/version.rb
|
122
127
|
- lib/irb/workspace.rb
|
123
128
|
- lib/irb/ws-for-case-2.rb
|
@@ -147,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
152
|
- !ruby/object:Gem::Version
|
148
153
|
version: '0'
|
149
154
|
requirements: []
|
150
|
-
rubygems_version: 3.
|
155
|
+
rubygems_version: 3.5.0.dev
|
151
156
|
signing_key:
|
152
157
|
specification_version: 4
|
153
158
|
summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).
|