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