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 +4 -4
- data/Gemfile.lock +8 -2
- data/README.md +16 -26
- data/bin/console +2 -7
- data/katakata_irb.gemspec +2 -1
- data/lib/katakata_irb/completor.rb +45 -6
- data/lib/katakata_irb/{trex.rb → nesting_parser.rb} +13 -8
- data/lib/katakata_irb/type_simulator.rb +20 -10
- data/lib/katakata_irb/types.rb +6 -12
- data/lib/katakata_irb/version.rb +1 -1
- data/lib/katakata_irb.rb +5 -7
- metadata +20 -15
- data/exe/kirb +0 -11
- data/lib/katakata_irb/reline_patch.rb +0 -43
- data/lib/katakata_irb/reline_patches/escapeseq.patch +0 -45
- data/lib/katakata_irb/reline_patches/indent.patch +0 -25
- data/lib/katakata_irb/reline_patches/raw.patch +0 -95
- data/lib/katakata_irb/reline_patches/scrollbar.patch +0 -34
- data/lib/katakata_irb/reline_patches/wholelines.patch +0 -102
- data/lib/katakata_irb/ruby_lex_patch.rb +0 -221
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e13d1b43d98e8be7595125b4e1e27533d83da1ee4d87df0dfb613d8fb8adee4
|
4
|
+
data.tar.gz: ae508bc65cd1049100fe4811b1d2b27036b30131cab13821d52b637e91e2ed41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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
|
-
|
14
|
-
|
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
|
-
|
26
|
-
|
31
|
+
irb(main):001:0> require 'katakata_irb'
|
32
|
+
=> true
|
33
|
+
irb(main):002:0> a = 10
|
27
34
|
=> 10
|
28
|
-
irb(main):
|
29
|
-
irb(main):
|
30
|
-
irb(main):
|
31
|
-
irb(main):
|
32
|
-
irb(main):
|
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
|
-
|
9
|
-
|
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 '
|
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
|
-
|
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::
|
69
|
-
last_opens = KatakataIrb::
|
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
|
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.
|
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
|
-
|
40
|
-
|
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 << [
|
196
|
+
pending_heredocs.reverse_each { |t| opens << [t, nil] }
|
192
197
|
pending_heredocs = []
|
193
198
|
end
|
194
|
-
yield t,
|
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,
|
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
|
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
|
|
data/lib/katakata_irb/types.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
306
|
+
InstanceType.new klass, params || {}
|
313
307
|
end
|
314
308
|
end
|
315
309
|
|
data/lib/katakata_irb/version.rb
CHANGED
data/lib/katakata_irb.rb
CHANGED
@@ -1,11 +1,7 @@
|
|
1
|
-
require '
|
2
|
-
|
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.
|
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-
|
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/
|
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.
|
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.
|
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
|