katakata_irb 0.1.3 → 0.1.4

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: fb7e44af7218463a13dd4e072748d5880924a3b5678f8c30200f3e5bfde391cd
4
- data.tar.gz: c0a6c33286b4a8197ad594f16baa87892448ea487e2faa153cac4d8f48d4208f
3
+ metadata.gz: 6e13d1b43d98e8be7595125b4e1e27533d83da1ee4d87df0dfb613d8fb8adee4
4
+ data.tar.gz: ae508bc65cd1049100fe4811b1d2b27036b30131cab13821d52b637e91e2ed41
5
5
  SHA512:
6
- metadata.gz: c79ea66192ad0c3f671a8cbaa9cf2d497b6b662482615a6f497e9a86ad6f797cc4d7b8d228bd44afd4c0968736a1ea83630311d2056b3bd4ae4befc1d2c94609
7
- data.tar.gz: d3cde5bdd7a966ecf6a06e82bdd9f276664e513999902e37e3abd1a0870452e4eb8265c43949ce8c7f110e6786980a79e4b07abaf0dd7880c37dee39a27865c3
6
+ metadata.gz: be9ed49c8de27772f7ec154df136134e9d5319a851fe392656a67d3c49069ed040a41b2af8deb6e81577c0c59c6d5bc0918a8165e09ccab2bce15fd6f09abba8
7
+ data.tar.gz: 8d9554e6532488742e156d39e7ee63c3c2461900db42badfd0d49990e35769b1e0f34a8cd746d5aab57839d3f31e894a081ec42389cd2383dafab5043d3fa578
data/Gemfile.lock CHANGED
@@ -1,15 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- katakata_irb (0.1.3)
4
+ katakata_irb (0.1.4)
5
+ irb (>= 1.4.0)
5
6
  rbs
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
11
+ io-console (0.6.0)
12
+ irb (1.6.2)
13
+ reline (>= 0.3.0)
10
14
  minitest (5.16.3)
11
15
  rake (13.0.6)
12
16
  rbs (2.7.0)
17
+ reline (0.3.2)
18
+ io-console (~> 0.5)
13
19
 
14
20
  PLATFORMS
15
21
  x86_64-darwin-20
@@ -20,4 +26,4 @@ DEPENDENCIES
20
26
  rake (~> 13.0)
21
27
 
22
28
  BUNDLED WITH
23
- 2.4.0.dev
29
+ 2.4.5
data/README.md CHANGED
@@ -9,9 +9,15 @@ gem install katakata_irb
9
9
  ```
10
10
  ## Usage
11
11
 
12
+ Just require katakata_irb or write it to your `.irbrc` file.
13
+ ```ruby
14
+ require 'katakata_irb'
15
+ ```
16
+
12
17
  ```
13
- % kirb
14
- irb(main):001:0> [1,'a'].sample.a█
18
+ irb(main):001:0> require 'katakata_irb'
19
+ => true
20
+ irb(main):002:0> [1,'a'].sample.a█
15
21
  |[1,'a'].sample.abs |
16
22
  |[1,'a'].sample.abs2 |
17
23
  |[1,'a'].sample.allbits? |
@@ -22,30 +28,14 @@ irb(main):001:0> [1,'a'].sample.a█
22
28
  ```
23
29
 
24
30
  ```
25
- % kirb
26
- irb(main):001:0> a = 10
31
+ irb(main):001:0> require 'katakata_irb'
32
+ => true
33
+ irb(main):002:0> a = 10
27
34
  => 10
28
- irb(main):002:1* if true
29
- irb(main):003:2* b = a.times.map do
30
- irb(main):004:2* _1.to_s
31
- irb(main):005:1* end
32
- irb(main):006:1* b[0].a█
35
+ irb(main):003:1* if true
36
+ irb(main):004:2* b = a.times.map do
37
+ irb(main):005:2* _1.to_s
38
+ irb(main):006:1* end
39
+ irb(main):007:1* b[0].a█
33
40
  |b[0].ascii_only?|
34
41
  ```
35
-
36
- ```ruby
37
- require 'katakata_irb/completor'
38
- KatakataIrb::Completor.setup
39
- 10.times do |i|
40
- binding.irb
41
- end
42
- ```
43
-
44
- ## Options
45
-
46
- ### `kirb --debug-output`
47
- Show debug output if it meets unimplemented syntax or something
48
-
49
- ### `kirb --without-patch`
50
- `kirb` will apply some patches to reline and irb/ruby-lex.rb by default. This option will disable it.
51
- See `lib/katakata_irb/ruby_lex_patch.rb` and `lib/katakata_irb/reline_patches/*.patch`
data/bin/console CHANGED
@@ -1,10 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require_relative '../lib/katakata_irb'
3
- require_relative '../lib/katakata_irb/reline_patch'
4
- KatakataIrb.log_output = STDERR
5
- KatakataIrb::RelinePatch.require_patched_reline
6
2
  require 'bundler/setup'
7
3
  require 'katakata_irb'
8
- require 'katakata_irb/ruby_lex_patch'
9
- KatakataIrb::RubyLexPatch.patch_to_ruby_lex
10
- KatakataIrb.repl
4
+ KatakataIrb.log_output = STDERR
5
+ IRB.start(__FILE__)
data/katakata_irb.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "IRB with Typed Completion"
13
13
  spec.homepage = "http://github.com/tompng/katakata_irb"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 3.1.0"
15
+ spec.required_ruby_version = ">= 3.0.0" # recommend >= 3.1.0
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = "http://github.com/tompng/katakata_irb"
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ["lib"]
30
30
 
31
31
  # Uncomment to register a new dependency of your gem
32
+ spec.add_dependency 'irb', '>= 1.4.0'
32
33
  spec.add_dependency 'rbs'
33
34
 
34
35
  # For more information and examples about making a new gem, check out our
@@ -1,4 +1,4 @@
1
- require_relative 'trex'
1
+ require_relative 'nesting_parser'
2
2
  require_relative 'type_simulator'
3
3
  require 'rbs'
4
4
  require 'rbs/cli'
@@ -6,15 +6,17 @@ require 'irb'
6
6
 
7
7
  module KatakataIrb::Completor
8
8
  using KatakataIrb::TypeSimulator::LexerElemMatcher
9
-
10
9
  HIDDEN_METHODS = %w[Namespace TypeName] # defined by rbs, should be hidden
10
+ singleton_class.attr_accessor :prev_analyze_result
11
11
 
12
12
  def self.setup
13
13
  completion_proc = ->(target, preposing = nil, postposing = nil) do
14
14
  code = "#{preposing}#{target}"
15
15
  irb_context = IRB.conf[:MAIN_CONTEXT]
16
16
  binding = irb_context.workspace.binding
17
- candidates = case analyze code, binding
17
+ result = analyze code, binding
18
+ KatakataIrb::Completor.prev_analyze_result = result
19
+ candidates = case result
18
20
  in [:require | :require_relative => method, name]
19
21
  if method == :require
20
22
  IRB::InputCompletor.retrieve_files_to_require_from_load_path
@@ -57,6 +59,44 @@ module KatakataIrb::Completor
57
59
  KatakataIrb.log_puts "#{e.inspect} stored to $error"
58
60
  KatakataIrb.log_puts
59
61
  end
62
+
63
+ IRB::InputCompletor.singleton_class.prepend Module.new{
64
+ def retrieve_completion_data(input, _bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
65
+ return super unless doc_namespace
66
+ name = input[/[a-zA-Z_0-9]+[!?=]?\z/]
67
+ method_doc = -> type do
68
+ type = type.types.find { _1.all_methods.include? name.to_sym }
69
+ if type in KatakataIrb::Types::SingletonType
70
+ "#{type.module_or_class.name}.#{name}"
71
+ elsif type in KatakataIrb::Types::InstanceType
72
+ "#{type.klass.name}##{name}"
73
+ end
74
+ end
75
+ call_or_const_doc = -> type do
76
+ if name =~ /\A[A-Z]/
77
+ type = type.types.grep(KatakataIrb::Types::SingletonType).find { _1.module_or_class.const_defined?(name) }
78
+ type.module_or_class == Object ? name : "#{type.module_or_class.name}::#{name}" if type
79
+ else
80
+ method_doc.call(type)
81
+ end
82
+ end
83
+
84
+ case KatakataIrb::Completor.prev_analyze_result
85
+ in [:call_or_const, type, _name, _self_call]
86
+ call_or_const_doc.call type
87
+ in [:const, type, _name]
88
+ # when prev_analyze_result is const, current analyze result might be call
89
+ call_or_const_doc.call type
90
+ in [:gvar, _name]
91
+ name
92
+ in [:call, type, _name, _self_call]
93
+ method_doc.call type
94
+ in [:lvar_or_method, _name, scope]
95
+ method_doc.call scope.self_type unless scope.local_variables.include?(name)
96
+ else
97
+ end
98
+ end
99
+ }
60
100
  end
61
101
 
62
102
  def self.analyze(code, binding = Kernel.binding)
@@ -65,8 +105,8 @@ module KatakataIrb::Completor
65
105
  end.join + "nil;\n"
66
106
  code = lvars_code + code
67
107
  tokens = RubyLex.ripper_lex_without_warning code
68
- tokens = KatakataIrb::TRex.interpolate_ripper_ignored_tokens code, tokens
69
- last_opens = KatakataIrb::TRex.parse(tokens)
108
+ tokens = KatakataIrb::NestingParser.interpolate_ripper_ignored_tokens code, tokens
109
+ last_opens = KatakataIrb::NestingParser.parse(tokens)
70
110
  closings = last_opens.map do |t|
71
111
  case t.tok
72
112
  when /\A%.[<>]\z/
@@ -89,7 +129,6 @@ module KatakataIrb::Completor
89
129
  end
90
130
  end
91
131
 
92
- return if code =~ /[!?]\z/
93
132
  case tokens.last
94
133
  in { event: :on_ignored_by_ripper, tok: '.' }
95
134
  suffix = 'method'
@@ -1,5 +1,4 @@
1
- module KatakataIrb; end
2
- module KatakataIrb::TRex
1
+ module KatakataIrb::NestingParser
3
2
  def self.interpolate_ripper_ignored_tokens(code, tokens)
4
3
  line_positions = code.lines.reduce([0]) { _1 << _1.last + _2.bytesize }
5
4
  prev_byte_pos = 0
@@ -31,13 +30,17 @@ module KatakataIrb::TRex
31
30
  opens = []
32
31
  pending_heredocs = []
33
32
  first_token_on_line = true
34
- tokens.each_with_index do |t, index|
33
+ tokens.each do |t|
35
34
  skip = false
36
35
  last_tok, state, args = opens.last
37
36
  case state
38
37
  when :in_unquoted_symbol
39
- opens.pop
40
- skip = true if %i[on_ident on_const on_op on_cvar on_ivar on_gvar on_kw on_int on_backtick].include?(t.event)
38
+ unless t.event == :on_sp
39
+ opens.pop
40
+ skip = true
41
+ end
42
+ when :in_lambda_head
43
+ opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
41
44
  when :in_method_head
42
45
  unless %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end].include?(t.event)
43
46
  next_args = []
@@ -160,6 +163,8 @@ module KatakataIrb::TRex
160
163
  opens << [t, nil]
161
164
  end
162
165
  end
166
+ when :on_tlambda
167
+ opens << [t, :in_lambda_head]
163
168
  when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
164
169
  opens << [t, nil]
165
170
  when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
@@ -188,10 +193,10 @@ module KatakataIrb::TRex
188
193
  first_token_on_line = false
189
194
  end
190
195
  if pending_heredocs.any? && t.tok.include?("\n")
191
- pending_heredocs.reverse_each { opens << [_1, nil] }
196
+ pending_heredocs.reverse_each { |t| opens << [t, nil] }
192
197
  pending_heredocs = []
193
198
  end
194
- yield t, index, opens if block_given?
199
+ yield t, opens if block_given?
195
200
  end
196
201
  opens.map(&:first) + pending_heredocs.reverse
197
202
  end
@@ -201,7 +206,7 @@ module KatakataIrb::TRex
201
206
  prev_opens = []
202
207
  min_depth = 0
203
208
  output = []
204
- last_opens = parse(tokens) do |t, _index, opens|
209
+ last_opens = parse(tokens) do |t, opens|
205
210
  depth = t == opens.last&.first ? opens.size - 1 : opens.size
206
211
  min_depth = depth if depth < min_depth
207
212
  if t.tok.include?("\n")
@@ -31,13 +31,13 @@ class KatakataIrb::TypeSimulator
31
31
  fallback = KatakataIrb::Types::NIL
32
32
  case BaseScope.type_by_name name
33
33
  when :cvar
34
- KatakataIrb::TypeSimulator.type_of(fallback:) { @self_object.class_variable_get name }
34
+ KatakataIrb::TypeSimulator.type_of(fallback: fallback) { @self_object.class_variable_get name }
35
35
  when :ivar
36
- KatakataIrb::TypeSimulator.type_of(fallback:) { @self_object.instance_variable_get name }
36
+ KatakataIrb::TypeSimulator.type_of(fallback: fallback) { @self_object.instance_variable_get name }
37
37
  when :lvar
38
- KatakataIrb::TypeSimulator.type_of(fallback:) { @binding.local_variable_get(name) }
38
+ KatakataIrb::TypeSimulator.type_of(fallback: fallback) { @binding.local_variable_get(name) }
39
39
  when :const
40
- KatakataIrb::TypeSimulator.type_of(fallback:) { @binding.eval name }
40
+ KatakataIrb::TypeSimulator.type_of(fallback: fallback) { @binding.eval name }
41
41
  end
42
42
  )
43
43
  end
@@ -85,7 +85,7 @@ class KatakataIrb::TypeSimulator
85
85
  class Scope
86
86
  attr_reader :parent, :jump_branches
87
87
 
88
- def self.from_binding(binding) = new BaseScope.new(binding, binding.eval('self'))
88
+ def self.from_binding(binding) = new(BaseScope.new(binding, binding.eval('self')))
89
89
 
90
90
  def initialize(parent, table = {}, trace_cvar: true, trace_ivar: true, trace_lvar: true, passthrough: false)
91
91
  @tables = [table]
@@ -243,8 +243,8 @@ class KatakataIrb::TypeSimulator
243
243
  refine Ripper::Lexer::Elem do
244
244
  def deconstruct_keys(_keys)
245
245
  {
246
- tok:,
247
- event:,
246
+ tok: tok,
247
+ event: event,
248
248
  label: state.allbits?(Ripper::EXPR_LABEL),
249
249
  beg: state.allbits?(Ripper::EXPR_BEG),
250
250
  dot: state.allbits?(Ripper::EXPR_DOT)
@@ -280,7 +280,7 @@ class KatakataIrb::TypeSimulator
280
280
  end
281
281
 
282
282
  def simulate_evaluate(sexp, scope, case_target: nil)
283
- result = simulate_evaluate_inner(sexp, scope, case_target:)
283
+ result = simulate_evaluate_inner(sexp, scope, case_target: case_target)
284
284
  @dig_targets.resolve result, scope if @dig_targets.target?(sexp)
285
285
  result
286
286
  end
@@ -635,6 +635,8 @@ class KatakataIrb::TypeSimulator
635
635
  KatakataIrb::Types::OBJECT
636
636
  in [:redo | :retry]
637
637
  scope.terminate
638
+ in [:zsuper]
639
+ KatakataIrb::Types::OBJECT
638
640
  in [:super, args]
639
641
  args, kwargs, _block = retrieve_method_args args
640
642
  args.each do |arg|
@@ -721,7 +723,7 @@ class KatakataIrb::TypeSimulator
721
723
  end
722
724
  else_branch = lambda do
723
725
  pattern.each { simulate_evaluate _1, scope }
724
- simulate_evaluate(else_statement, scope, case_target:)
726
+ simulate_evaluate(else_statement, scope, case_target: case_target)
725
727
  end
726
728
  if if_statements && else_statement
727
729
  KatakataIrb::Types::UnionType[*scope.run_branches(if_branch, else_branch)]
@@ -741,7 +743,7 @@ class KatakataIrb::TypeSimulator
741
743
  },
742
744
  -> {
743
745
  pattern_scope.merge_jumps
744
- else_statement ? simulate_evaluate(else_statement, scope, case_target:) : KatakataIrb::Types::NIL
746
+ else_statement ? simulate_evaluate(else_statement, scope, case_target: case_target) : KatakataIrb::Types::NIL
745
747
  }
746
748
  )
747
749
  KatakataIrb::Types::UnionType[*results]
@@ -1041,6 +1043,14 @@ class KatakataIrb::TypeSimulator
1041
1043
  types = type_breaks.map(&:first)
1042
1044
  breaks = type_breaks.map(&:last).compact
1043
1045
  types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
1046
+
1047
+ if method_name.to_sym == :new
1048
+ receiver.types.each do |type|
1049
+ if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
1050
+ types << KatakataIrb::Types::InstanceType.new(type.module_or_class)
1051
+ end
1052
+ end
1053
+ end
1044
1054
  KatakataIrb::Types::UnionType[*types, *breaks]
1045
1055
  end
1046
1056
 
@@ -90,7 +90,7 @@ module KatakataIrb::Types
90
90
  when Array
91
91
  values = object.size > sample_size ? object.sample(sample_size) : object
92
92
  if max_level > 0
93
- InstanceType.new Array, { Elem: UnionType[*values.map { type_from_object(_1, max_level:) }] }
93
+ InstanceType.new Array, { Elem: UnionType[*values.map { type_from_object(_1, max_level: max_level) }] }
94
94
  else
95
95
  InstanceType.new Array, { Elem: UnionType[*values.map(&:class).uniq.map { InstanceType.new _1 }] }
96
96
  end
@@ -98,8 +98,8 @@ module KatakataIrb::Types
98
98
  keys = object.size > sample_size ? object.keys.sample(sample_size) : object.keys
99
99
  values = object.size > sample_size ? object.values.sample(sample_size) : object.values
100
100
  if max_level > 0
101
- key_types = keys.map { type_from_object(_1, max_level:) }
102
- value_types = values.map { type_from_object(_1, max_level:) }
101
+ key_types = keys.map { type_from_object(_1, max_level: max_level) }
102
+ value_types = values.map { type_from_object(_1, max_level: max_level) }
103
103
  InstanceType.new Hash, { K: UnionType[*key_types], V: UnionType[*value_types] }
104
104
  else
105
105
  key_types = keys.map(&:class).uniq.map { InstanceType.new _1 }
@@ -120,7 +120,7 @@ module KatakataIrb::Types
120
120
  end
121
121
  def transform() = yield(self)
122
122
  def methods() = @module_or_class.methods
123
- def all_methods() = methods
123
+ def all_methods() = methods | Kernel.methods
124
124
  def constants() = @module_or_class.constants
125
125
  def types() = [self]
126
126
  end
@@ -297,19 +297,13 @@ module KatakataIrb::Types
297
297
  # unimplemented
298
298
  OBJECT
299
299
  when RBS::Types::ClassInstance
300
- classes = self_type.types.filter_map do |type|
301
- type.module_or_class if (type in SingletonType) && type.module_or_class.is_a?(Class)
302
- end
303
- if classes.empty?
304
- klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
305
- classes << klass if klass in Class
306
- end
300
+ klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
307
301
  if return_type.args
308
302
  args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
309
303
  names = rbs_builder.build_singleton(return_type.name).type_params
310
304
  params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
311
305
  end
312
- UnionType[*classes.map { InstanceType.new _1, params || {} }]
306
+ InstanceType.new klass, params || {}
313
307
  end
314
308
  end
315
309
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KatakataIrb
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/katakata_irb.rb CHANGED
@@ -1,11 +1,7 @@
1
- require 'io/console'
2
- module KatakataIrb
3
- def self.repl
4
- require 'katakata_irb/completor'
5
- KatakataIrb::Completor.setup
6
- IRB.start(__FILE__)
7
- end
1
+ require 'katakata_irb/version'
2
+ require 'katakata_irb/completor'
8
3
 
4
+ module KatakataIrb
9
5
  def self.log_output=(output)
10
6
  @log_output = output
11
7
  end
@@ -14,3 +10,5 @@ module KatakataIrb
14
10
  STDOUT.cooked { @log_output&.puts(...) }
15
11
  end
16
12
  end
13
+
14
+ KatakataIrb::Completor.setup
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katakata_irb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-08 00:00:00.000000000 Z
11
+ date: 2023-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: irb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rbs
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -27,8 +41,7 @@ dependencies:
27
41
  description: IRB with Typed Completion
28
42
  email:
29
43
  - tomoyapenguin@gmail.com
30
- executables:
31
- - kirb
44
+ executables: []
32
45
  extensions: []
33
46
  extra_rdoc_files: []
34
47
  files:
@@ -39,18 +52,10 @@ files:
39
52
  - Rakefile
40
53
  - bin/console
41
54
  - bin/setup
42
- - exe/kirb
43
55
  - katakata_irb.gemspec
44
56
  - lib/katakata_irb.rb
45
57
  - lib/katakata_irb/completor.rb
46
- - lib/katakata_irb/reline_patch.rb
47
- - lib/katakata_irb/reline_patches/escapeseq.patch
48
- - lib/katakata_irb/reline_patches/indent.patch
49
- - lib/katakata_irb/reline_patches/raw.patch
50
- - lib/katakata_irb/reline_patches/scrollbar.patch
51
- - lib/katakata_irb/reline_patches/wholelines.patch
52
- - lib/katakata_irb/ruby_lex_patch.rb
53
- - lib/katakata_irb/trex.rb
58
+ - lib/katakata_irb/nesting_parser.rb
54
59
  - lib/katakata_irb/type_simulator.rb
55
60
  - lib/katakata_irb/types.rb
56
61
  - lib/katakata_irb/version.rb
@@ -69,14 +74,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
74
  requirements:
70
75
  - - ">="
71
76
  - !ruby/object:Gem::Version
72
- version: 3.1.0
77
+ version: 3.0.0
73
78
  required_rubygems_version: !ruby/object:Gem::Requirement
74
79
  requirements:
75
80
  - - ">="
76
81
  - !ruby/object:Gem::Version
77
82
  version: '0'
78
83
  requirements: []
79
- rubygems_version: 3.4.3
84
+ rubygems_version: 3.4.5
80
85
  signing_key:
81
86
  specification_version: 4
82
87
  summary: IRB with Typed Completion
data/exe/kirb DELETED
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require_relative '../lib/katakata_irb'
3
- KatakataIrb.log_output = STDERR if ARGV.delete '--debug-output'
4
- unless ARGV.delete '--without-patch'
5
- require_relative '../lib/katakata_irb/reline_patch'
6
- KatakataIrb::RelinePatch.require_patched_reline
7
- require 'katakata_irb/ruby_lex_patch'
8
- KatakataIrb::RubyLexPatch.patch_to_ruby_lex
9
- end
10
- require 'katakata_irb'
11
- KatakataIrb.repl
@@ -1,43 +0,0 @@
1
- module KatakataIrb; end
2
- module KatakataIrb::RelinePatch
3
- module RelinePatchIseqLoader; end
4
- def self.require_patched_reline
5
- # Apply patches of unmerged pull-request to reline
6
- patches = %w[wholelines escapeseq indent raw scrollbar]
7
- patched = {}
8
- require 'reline/version.rb' # result of $LOAD_PATH.resolve_feature_path will change after this require
9
- patches.each do |patch_name|
10
- patch = File.read File.expand_path("reline_patches/#{patch_name}.patch", File.dirname(__FILE__))
11
- current_patched = {}
12
- patch.gsub(/^diff.+\nindex.+$/, '').split(/^--- a(.+)\n\+\+\+ b(.+)\n/).drop(1).each_slice(3) do |file, newfile, diff|
13
- raise if file != newfile
14
- _, path = $LOAD_PATH.resolve_feature_path file.sub(%r{^/lib/}, '')
15
- code = current_patched[path] || patched[path] || File.read(path)
16
- diff.split(/^@@.+\n/).drop(1).map(&:lines).each do |lines|
17
- target = lines.reject { _1[0] == '+' }.map { _1[1..] }.join
18
- replace = lines.reject { _1[0] == '-' }.map { _1[1..] }.join
19
- if code.include? target
20
- code = code.sub target, replace
21
- elsif !code.include?(replace)
22
- raise
23
- end
24
- end
25
- current_patched[path] = code
26
- end
27
- patched.update current_patched
28
- rescue
29
- KatakataIrb.log_puts "Failed to apply katakata_irb/reline_patches/#{patch_name}.patch to reline"
30
- end
31
-
32
- RelinePatchIseqLoader.define_method :load_iseq do |fname|
33
- if patched.key? fname
34
- RubyVM::InstructionSequence.compile patched[fname], fname
35
- else
36
- RubyVM::InstructionSequence.compile_file fname
37
- end
38
- end
39
- RubyVM::InstructionSequence.singleton_class.prepend RelinePatchIseqLoader
40
- require 'reline'
41
- RelinePatchIseqLoader.undef_method :load_iseq
42
- end
43
- end
@@ -1,45 +0,0 @@
1
- diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
2
- index 1c33a4b..bbf5e6c 100644
3
- --- a/lib/reline/line_editor.rb
4
- +++ b/lib/reline/line_editor.rb
5
- @@ -663,8 +663,10 @@ class Reline::LineEditor
6
- dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
7
- dialog_render_info = dialog.call(@last_key)
8
- if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
9
- + lines = whole_lines
10
- dialog.lines_backup = {
11
- - lines: modify_lines(whole_lines),
12
- + unmodified_lines: lines,
13
- + lines: modify_lines(lines),
14
- line_index: @line_index,
15
- first_line_started_from: @first_line_started_from,
16
- started_from: @started_from,
17
- @@ -766,8 +768,10 @@ class Reline::LineEditor
18
- Reline::IOGate.move_cursor_column(cursor_column)
19
- move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
20
- Reline::IOGate.show_cursor
21
- + lines = whole_lines
22
- dialog.lines_backup = {
23
- - lines: modify_lines(whole_lines),
24
- + unmodified_lines: lines,
25
- + lines: modify_lines(lines),
26
- line_index: @line_index,
27
- first_line_started_from: @first_line_started_from,
28
- started_from: @started_from,
29
- @@ -777,7 +781,7 @@ class Reline::LineEditor
30
- private def reset_dialog(dialog, old_dialog)
31
- return if dialog.lines_backup.nil? or old_dialog.contents.nil?
32
- - prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
33
- + prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:unmodified_lines])
34
- visual_lines = []
35
- visual_start = nil
36
- dialog.lines_backup[:lines].each_with_index { |l, i|
37
- @@ -888,7 +892,7 @@ class Reline::LineEditor
38
- private def clear_each_dialog(dialog)
39
- dialog.trap_key = nil
40
- return unless dialog.contents
41
- - prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
42
- + prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:unmodified_lines])
43
- visual_lines = []
44
- visual_lines_under_dialog = []
45
- visual_start = nil
@@ -1,25 +0,0 @@
1
- diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
2
- index bbf5e6c..c9e613e 100644
3
- --- a/lib/reline/line_editor.rb
4
- +++ b/lib/reline/line_editor.rb
5
- @@ -1707,17 +1707,18 @@ class Reline::LineEditor
6
- end
7
- new_lines = whole_lines
8
- new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
9
- - new_indent = @cursor_max if new_indent&.> @cursor_max
10
- if new_indent&.>= 0
11
- md = new_lines[@line_index].match(/\A */)
12
- prev_indent = md[0].count(' ')
13
- if @check_new_auto_indent
14
- - @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
15
- + line = @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
16
- @cursor = new_indent
17
- + @cursor_max = calculate_width(line)
18
- @byte_pointer = new_indent
19
- else
20
- @line = ' ' * new_indent + @line.lstrip
21
- @cursor += new_indent - prev_indent
22
- + @cursor_max = calculate_width(@line)
23
- @byte_pointer += new_indent - prev_indent
24
- end
25
- end
@@ -1,95 +0,0 @@
1
- diff --git a/lib/reline.rb b/lib/reline.rb
2
- index f22b573..8716a0c 100644
3
- --- a/lib/reline.rb
4
- +++ b/lib/reline.rb
5
- @@ -281,19 +281,21 @@ module Reline
6
- Reline::DEFAULT_DIALOG_CONTEXT = Array.new
7
-
8
- def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
9
- - unless confirm_multiline_termination
10
- - raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
11
- - end
12
- - inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
13
- + Reline::IOGate.with_raw_input do
14
- + unless confirm_multiline_termination
15
- + raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
16
- + end
17
- + inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
18
-
19
- - whole_buffer = line_editor.whole_buffer.dup
20
- - whole_buffer.taint if RUBY_VERSION < '2.7'
21
- - if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
22
- - Reline::HISTORY << whole_buffer
23
- - end
24
- + whole_buffer = line_editor.whole_buffer.dup
25
- + whole_buffer.taint if RUBY_VERSION < '2.7'
26
- + if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
27
- + Reline::HISTORY << whole_buffer
28
- + end
29
-
30
- - line_editor.reset_line if line_editor.whole_buffer.nil?
31
- - whole_buffer
32
- + line_editor.reset_line if line_editor.whole_buffer.nil?
33
- + whole_buffer
34
- + end
35
- end
36
-
37
- def readline(prompt = '', add_hist = false)
38
- diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
39
- index ab147a6..ccebe15 100644
40
- --- a/lib/reline/ansi.rb
41
- +++ b/lib/reline/ansi.rb
42
- @@ -142,6 +142,10 @@ class Reline::ANSI
43
- @@output = val
44
- end
45
-
46
- + def self.with_raw_input
47
- + @@input.raw { yield }
48
- + end
49
- +
50
- @@buf = []
51
- def self.inner_getc
52
- unless @@buf.empty?
53
- diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
54
- index 92c76cb..9929846 100644
55
- --- a/lib/reline/general_io.rb
56
- +++ b/lib/reline/general_io.rb
57
- @@ -31,6 +31,10 @@ class Reline::GeneralIO
58
- @@input = val
59
- end
60
-
61
- + def self.with_raw_input
62
- + yield
63
- + end
64
- +
65
- def self.getc
66
- unless @@buf.empty?
67
- return @@buf.shift
68
- diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
69
- index 6acf969..e3985a3 100644
70
- --- a/lib/reline/line_editor.rb
71
- +++ b/lib/reline/line_editor.rb
72
- @@ -452,7 +452,7 @@ class Reline::LineEditor
73
- new_lines = whole_lines
74
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
75
- modify_lines(new_lines).each_with_index do |line, index|
76
- - @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
77
- + @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\r\n"
78
- Reline::IOGate.erase_after_cursor
79
- end
80
- @output.flush
81
- diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
82
- index b952329..7ea2a00 100644
83
- --- a/lib/reline/windows.rb
84
- +++ b/lib/reline/windows.rb
85
- @@ -291,6 +291,10 @@ class Reline::Windows
86
- end
87
- end
88
-
89
- + def self.with_raw_input
90
- + yield
91
- + end
92
- +
93
- def self.getc
94
- check_input_event
95
- @@output_buf.shift
@@ -1,34 +0,0 @@
1
- diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
2
- index 8153aab..50a063a 100644
3
- --- a/lib/reline/line_editor.rb
4
- +++ b/lib/reline/line_editor.rb
5
- @@ -703,17 +703,17 @@ class Reline::LineEditor
6
- dialog.scroll_top = dialog.pointer
7
- end
8
- pointer = dialog.pointer - dialog.scroll_top
9
- + else
10
- + dialog.scroll_top = 0
11
- end
12
- dialog.contents = dialog.contents[dialog.scroll_top, height]
13
- end
14
- - if dialog.contents and dialog.scroll_top >= dialog.contents.size
15
- - dialog.scroll_top = dialog.contents.size - height
16
- - end
17
- if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
18
- bar_max_height = height * 2
19
- moving_distance = (dialog_render_info.contents.size - height) * 2
20
- position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
21
- bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
22
- + bar_height = 1 if bar_height.zero?
23
- dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
24
- else
25
- dialog.scrollbar_pos = nil
26
- @@ -755,7 +755,7 @@ class Reline::LineEditor
27
- str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
28
- str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
29
- @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}"
30
- - if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
31
- + if dialog.scrollbar_pos
32
- @output.write "\e[37m"
33
- if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
34
- @output.write @full_block
@@ -1,102 +0,0 @@
1
- diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
2
- index 8153aab..1c33a4b 100644
3
- --- a/lib/reline/line_editor.rb
4
- +++ b/lib/reline/line_editor.rb
5
- @@ -449,12 +449,8 @@ class Reline::LineEditor
6
- Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
7
- Reline::IOGate.move_cursor_column(0)
8
- @scroll_partial_screen = nil
9
- - prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
10
- - if @previous_line_index
11
- - new_lines = whole_lines(index: @previous_line_index, line: @line)
12
- - else
13
- - new_lines = whole_lines
14
- - end
15
- + new_lines = whole_lines
16
- + prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
17
- modify_lines(new_lines).each_with_index do |line, index|
18
- @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
19
- Reline::IOGate.erase_after_cursor
20
- @@ -490,11 +486,7 @@ class Reline::LineEditor
21
- if @is_multiline
22
- if finished?
23
- # Always rerender on finish because output_modifier_proc may return a different output.
24
- - if @previous_line_index
25
- - new_lines = whole_lines(index: @previous_line_index, line: @line)
26
- - else
27
- - new_lines = whole_lines
28
- - end
29
- + new_lines = whole_lines
30
- line = modify_lines(new_lines)[@line_index]
31
- clear_dialog
32
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
33
- @@ -1013,11 +1005,7 @@ class Reline::LineEditor
34
- end
35
-
36
- private def rerender_changed_current_line
37
- - if @previous_line_index
38
- - new_lines = whole_lines(index: @previous_line_index, line: @line)
39
- - else
40
- - new_lines = whole_lines
41
- - end
42
- + new_lines = whole_lines
43
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
44
- all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
45
- diff = all_height - @highest_in_all
46
- @@ -1698,7 +1686,7 @@ class Reline::LineEditor
47
- return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
48
- if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
49
- # Fix indent of a line when a newline is inserted to the next
50
- - new_lines = whole_lines(index: @previous_line_index, line: @line)
51
- + new_lines = whole_lines
52
- new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
53
- md = @line.match(/\A */)
54
- prev_indent = md[0].count(' ')
55
- @@ -1713,11 +1701,7 @@ class Reline::LineEditor
56
- @line = ' ' * new_indent + @line.lstrip
57
- end
58
- end
59
- - if @previous_line_index
60
- - new_lines = whole_lines(index: @previous_line_index, line: @line)
61
- - else
62
- - new_lines = whole_lines
63
- - end
64
- + new_lines = whole_lines
65
- new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
66
- new_indent = @cursor_max if new_indent&.> @cursor_max
67
- if new_indent&.>= 0
68
- @@ -1803,11 +1787,7 @@ class Reline::LineEditor
69
- target = before
70
- end
71
- if @is_multiline
72
- - if @previous_line_index
73
- - lines = whole_lines(index: @previous_line_index, line: @line)
74
- - else
75
- - lines = whole_lines
76
- - end
77
- + lines = whole_lines
78
- if @line_index > 0
79
- preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
80
- end
81
- @@ -1907,7 +1887,7 @@ class Reline::LineEditor
82
- @cursor_max = calculate_width(@line)
83
- end
84
-
85
- - def whole_lines(index: @line_index, line: @line)
86
- + def whole_lines(index: @previous_line_index || @line_index, line: @line)
87
- temp_lines = @buffer_of_lines.dup
88
- temp_lines[index] = line
89
- temp_lines
90
- @@ -1917,11 +1897,7 @@ class Reline::LineEditor
91
- if @buffer_of_lines.size == 1 and @line.nil?
92
- nil
93
- else
94
- - if @previous_line_index
95
- - whole_lines(index: @previous_line_index, line: @line).join("\n")
96
- - else
97
- - whole_lines.join("\n")
98
- - end
99
- + whole_lines.join("\n")
100
- end
101
- end
102
-
@@ -1,221 +0,0 @@
1
- require 'irb'
2
- require_relative 'trex'
3
-
4
- module KatakataIrb::RubyLexPatch
5
- def self.patch_to_ruby_lex
6
- (RubyLex.instance_methods(false) - [:set_prompt, :process_continue, :check_code_block]).each { RubyLex.remove_method _1 }
7
- RubyLex.prepend self
8
- end
9
-
10
- def self.complete_tokens(code, context: nil)
11
- incomplete_tokens = RubyLex.ripper_lex_without_warning(code, context: context)
12
- KatakataIrb::TRex.interpolate_ripper_ignored_tokens(code, incomplete_tokens)
13
- end
14
-
15
- def calc_nesting_depth(opens)
16
- indent_level = 0
17
- nesting_level = 0
18
- opens.each_with_index do |t, index|
19
- case t.event
20
- when :on_heredoc_beg
21
- if opens[index + 1]&.event != :on_heredoc_beg
22
- if t.tok.start_with?('<<~')
23
- indent_level += 1
24
- else
25
- indent_level = 0
26
- end
27
- end
28
- when :on_tstring_beg, :on_regexp_beg, :on_symbeg
29
- indent_level += 1 if t.tok[0] == '%'
30
- when :on_embdoc_beg
31
- indent_level = 0
32
- else
33
- nesting_level += 1
34
- indent_level += 1
35
- end
36
- end
37
- [indent_level, nesting_level]
38
- end
39
-
40
- def process_indent_level(tokens)
41
- opens = KatakataIrb::TRex.parse(tokens)
42
- indent, _nesting = calc_nesting_depth(opens)
43
- indent * 2
44
- end
45
-
46
- def check_corresponding_token_depth(tokens, line_index)
47
- line_results = KatakataIrb::TRex.parse_line(tokens)
48
- result = line_results[line_index]
49
- return unless result
50
- _tokens, prev, opens, min_depth = result
51
- depth, = calc_nesting_depth(opens.take(min_depth))
52
- prev_depth, = calc_nesting_depth(prev)
53
- depth * 2 if depth < prev_depth
54
- end
55
-
56
- def ltype_from_open_tokens(opens)
57
- return nil if opens.empty?
58
- case opens.last.tok
59
- when ?`, /^<<[-~]?`/, /^%x.$/
60
- ?`
61
- when ?', /^<<[-~]?'/, /^%q.$/
62
- ?'
63
- when ?", /^<</, /^%.$/, /^%Q.$/
64
- ?"
65
- when ":'", ':"', ':', /^%s.$/
66
- ':'
67
- when /^%[iwIW].$/
68
- ']'
69
- when '/', /^%r.$/
70
- '/'
71
- end
72
- end
73
-
74
- def check_termination_in_prev_line(code, context: nil)
75
- tokens = self.class.ripper_lex_without_warning(code, context: context)
76
- last_newline_index = tokens.rindex { |t| t.tok.include?("\n") }
77
- index = (0...last_newline_index).reverse_each.find { |i| tokens[i].tok.include?("\n") }
78
- return false unless index
79
-
80
- last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
81
- first_token = last_line_tokens.find do |t|
82
- ![:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
83
- end
84
-
85
- if first_token && first_token.state != Ripper::EXPR_DOT
86
- tokens_without_last_line = tokens[0..index]
87
- if check_termination(tokens_without_last_line.map(&:tok).join, context: context)
88
- return last_line_tokens.map(&:tok).join
89
- end
90
- end
91
- false
92
- end
93
-
94
- def check_termination(code, context: nil)
95
- tokens = KatakataIrb::RubyLexPatch.complete_tokens(code, context: context)
96
- opens = KatakataIrb::TRex.parse(tokens)
97
- opens.empty? && !process_continue(tokens) && !check_code_block(code, tokens)
98
- end
99
-
100
- def set_input(io, p = nil, context: nil, &block)
101
- @io = io
102
- if @io.respond_to?(:check_termination)
103
- @io.check_termination do |code|
104
- if Reline::IOGate.in_pasting?
105
- rest = check_termination_in_prev_line(code, context: context)
106
- if rest
107
- Reline.delete_text
108
- rest.bytes.reverse_each do |c|
109
- Reline.ungetc(c)
110
- end
111
- true
112
- else
113
- false
114
- end
115
- else
116
- # Accept any single-line input for symbol aliases or commands that transform args
117
- command = code.split(/\s/, 2).first
118
- if context.symbol_alias?(command) || context.transform_args?(command)
119
- next true
120
- end
121
-
122
- code.gsub!(/\s*\z/, '').concat("\n")
123
- check_termination(code, context: context)
124
- end
125
- end
126
- end
127
- if @io.respond_to?(:dynamic_prompt)
128
- @io.dynamic_prompt do |lines|
129
- lines << '' if lines.empty?
130
- code = lines.map{ |l| l + "\n" }.join
131
- tokens = KatakataIrb::RubyLexPatch.complete_tokens code, context: context
132
- line_results = KatakataIrb::TRex.parse_line(tokens)
133
- continue = false
134
- tokens_until_line = []
135
- line_results.map.with_index do |(line_tokens, _prev_opens, next_opens), line_num_offset|
136
- line_tokens.each do |token, _s|
137
- tokens_until_line << token if token != tokens_until_line.last
138
- end
139
- continue = process_continue(tokens_until_line)
140
- prompt next_opens, continue, line_num_offset
141
- end
142
- end
143
- end
144
-
145
- if p.respond_to?(:call)
146
- @input = p
147
- elsif block_given?
148
- @input = block
149
- else
150
- @input = Proc.new{@io.gets}
151
- end
152
- end
153
-
154
- def set_auto_indent(context)
155
- if @io.respond_to?(:auto_indent) and context.auto_indent_mode
156
- @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
157
- if is_newline
158
- tokens = KatakataIrb::RubyLexPatch.complete_tokens(lines[0..line_index].join("\n"), context: context)
159
- process_indent_level(tokens)
160
- else
161
- code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
162
- last_line = lines[line_index]&.byteslice(0, byte_pointer)
163
- code += last_line if last_line
164
- tokens = KatakataIrb::RubyLexPatch.complete_tokens(code, context: context)
165
- check_corresponding_token_depth(tokens, line_index)
166
- end
167
- end
168
- end
169
- end
170
-
171
- def prompt(opens, continue, line_num_offset)
172
- ltype = ltype_from_open_tokens(opens)
173
- _indent, nesting_level = calc_nesting_depth(opens)
174
- @prompt.call(ltype, nesting_level, opens.any? || continue, @line_no + line_num_offset)
175
- end
176
-
177
- # TODO: do not use this. change the api. example: @input.call(prompt)
178
- def store_prompt_to_irb(opens, continue, line_num_offset)
179
- prompt(opens, continue, line_num_offset)
180
- end
181
-
182
- def readmultiline(context)
183
- if @io.respond_to? :check_termination
184
- store_prompt_to_irb([], false, 0)
185
- @input.call
186
- else
187
- # nomultiline
188
- line = ''
189
- line_offset = 0
190
- store_prompt_to_irb([], false, 0)
191
- loop do
192
- l = @input.call
193
- unless l
194
- return if line.empty?
195
- next
196
- end
197
- line << l
198
- tokens = KatakataIrb::RubyLexPatch.complete_tokens(line, context: context)
199
- _line_tokens, _prev_opens, next_opens = KatakataIrb::TRex.parse_line(tokens).last
200
- return line if next_opens.empty?
201
- line_offset += 1
202
- store_prompt_to_irb(next_opens, true, line_offset)
203
- end
204
- end
205
- end
206
-
207
- def each_top_level_statement(context = nil)
208
- loop do
209
- begin
210
- line = readmultiline(context)
211
- break unless line
212
- if line != "\n"
213
- line.force_encoding(@io.encoding)
214
- yield line, @line_no
215
- end
216
- @line_no += line.count("\n")
217
- rescue RubyLex::TerminateLineInput
218
- end
219
- end
220
- end
221
- end