katakata_irb 0.1.3 → 0.1.4

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: 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