irb 1.8.1 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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).
|