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.
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(@context)
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
- scanner.increase_line_no(1)
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
- scanner.increase_line_no(input.count("\n") - 1)
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
- @scanner.save_prompt_to_context_io([], false, 0)
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
- @scanner.save_prompt_to_context_io(opens, continue, line_offset)
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), @scanner.line_no
590
+ yield build_statement(code), @line_no
629
591
  end
630
- @scanner.increase_line_no(code.count("\n"))
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
- Statement::Expression.new(code, @scanner.assignment_expression?(code))
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, context: @context)
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
- @scanner.prompt(next_opens, continue, line_num_offset)
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, context: @context)
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
- def @CONF.inspect
979
- IRB.version unless self[:VERSION]
980
-
981
- array = []
982
- for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
983
- case k
984
- when :MAIN_CONTEXT, :__TMP__EHV__
985
- array.push format("CONF[:%s]=...myself...", k.id2name)
986
- when :PROMPT
987
- s = v.collect{
988
- |kk, vv|
989
- ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
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
- array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
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.8.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-09-05 00:00:00.000000000 Z
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.4.10
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).