katakata_irb 0.1.2 → 0.1.3
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 +1 -1
- data/lib/katakata_irb/reline_patch.rb +1 -1
- data/lib/katakata_irb/reline_patches/scrollbar.patch +7 -16
- data/lib/katakata_irb/ruby_lex_patch.rb +21 -16
- data/lib/katakata_irb/trex.rb +43 -26
- data/lib/katakata_irb/type_simulator.rb +5 -1
- data/lib/katakata_irb/types.rb +12 -9
- data/lib/katakata_irb/version.rb +1 -1
- metadata +3 -4
- data/lib/katakata_irb/reline_patches/fullwidth.patch +0 -200
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb7e44af7218463a13dd4e072748d5880924a3b5678f8c30200f3e5bfde391cd
|
4
|
+
data.tar.gz: c0a6c33286b4a8197ad594f16baa87892448ea487e2faa153cac4d8f48d4208f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c79ea66192ad0c3f671a8cbaa9cf2d497b6b662482615a6f497e9a86ad6f797cc4d7b8d228bd44afd4c0968736a1ea83630311d2056b3bd4ae4befc1d2c94609
|
7
|
+
data.tar.gz: d3cde5bdd7a966ecf6a06e82bdd9f276664e513999902e37e3abd1a0870452e4eb8265c43949ce8c7f110e6786980a79e4b07abaf0dd7880c37dee39a27865c3
|
data/Gemfile.lock
CHANGED
@@ -3,7 +3,7 @@ module KatakataIrb::RelinePatch
|
|
3
3
|
module RelinePatchIseqLoader; end
|
4
4
|
def self.require_patched_reline
|
5
5
|
# Apply patches of unmerged pull-request to reline
|
6
|
-
patches = %w[wholelines escapeseq indent
|
6
|
+
patches = %w[wholelines escapeseq indent raw scrollbar]
|
7
7
|
patched = {}
|
8
8
|
require 'reline/version.rb' # result of $LOAD_PATH.resolve_feature_path will change after this require
|
9
9
|
patches.each do |patch_name|
|
@@ -1,18 +1,8 @@
|
|
1
1
|
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
|
2
|
-
index
|
2
|
+
index 8153aab..50a063a 100644
|
3
3
|
--- a/lib/reline/line_editor.rb
|
4
4
|
+++ b/lib/reline/line_editor.rb
|
5
|
-
@@ -
|
6
|
-
end
|
7
|
-
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
|
8
|
-
height = dialog.contents.size if dialog.contents.size < height
|
9
|
-
+ if dialog.scroll_top >= dialog.contents.size - height
|
10
|
-
+ dialog.scroll_top = dialog.contents.size - height
|
11
|
-
+ end
|
12
|
-
if dialog.contents.size > height
|
13
|
-
if dialog.pointer
|
14
|
-
if dialog.pointer < 0
|
15
|
-
@@ -690,17 +693,20 @@ class Reline::LineEditor
|
5
|
+
@@ -703,17 +703,17 @@ class Reline::LineEditor
|
16
6
|
dialog.scroll_top = dialog.pointer
|
17
7
|
end
|
18
8
|
pointer = dialog.pointer - dialog.scroll_top
|
@@ -23,9 +13,7 @@ index e3985a3..8d785db 100644
|
|
23
13
|
end
|
24
14
|
- if dialog.contents and dialog.scroll_top >= dialog.contents.size
|
25
15
|
- dialog.scroll_top = dialog.contents.size - height
|
26
|
-
|
27
|
-
+ dialog.scroll_top = dialog_render_info.contents.size - height
|
28
|
-
end
|
16
|
+
- end
|
29
17
|
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
30
18
|
bar_max_height = height * 2
|
31
19
|
moving_distance = (dialog_render_info.contents.size - height) * 2
|
@@ -35,7 +23,10 @@ index e3985a3..8d785db 100644
|
|
35
23
|
dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
|
36
24
|
else
|
37
25
|
dialog.scrollbar_pos = nil
|
38
|
-
@@ -
|
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}"
|
39
30
|
- if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
|
40
31
|
+ if dialog.scrollbar_pos
|
41
32
|
@output.write "\e[37m"
|
@@ -84,16 +84,17 @@ module KatakataIrb::RubyLexPatch
|
|
84
84
|
|
85
85
|
if first_token && first_token.state != Ripper::EXPR_DOT
|
86
86
|
tokens_without_last_line = tokens[0..index]
|
87
|
-
if check_termination(tokens_without_last_line)
|
87
|
+
if check_termination(tokens_without_last_line.map(&:tok).join, context: context)
|
88
88
|
return last_line_tokens.map(&:tok).join
|
89
89
|
end
|
90
90
|
end
|
91
91
|
false
|
92
92
|
end
|
93
93
|
|
94
|
-
def check_termination(
|
94
|
+
def check_termination(code, context: nil)
|
95
|
+
tokens = KatakataIrb::RubyLexPatch.complete_tokens(code, context: context)
|
95
96
|
opens = KatakataIrb::TRex.parse(tokens)
|
96
|
-
opens.empty? && !process_continue(tokens)
|
97
|
+
opens.empty? && !process_continue(tokens) && !check_code_block(code, tokens)
|
97
98
|
end
|
98
99
|
|
99
100
|
def set_input(io, p = nil, context: nil, &block)
|
@@ -101,8 +102,7 @@ module KatakataIrb::RubyLexPatch
|
|
101
102
|
if @io.respond_to?(:check_termination)
|
102
103
|
@io.check_termination do |code|
|
103
104
|
if Reline::IOGate.in_pasting?
|
104
|
-
|
105
|
-
rest = lex.check_termination_in_prev_line(code, context: context)
|
105
|
+
rest = check_termination_in_prev_line(code, context: context)
|
106
106
|
if rest
|
107
107
|
Reline.delete_text
|
108
108
|
rest.bytes.reverse_each do |c|
|
@@ -113,8 +113,14 @@ module KatakataIrb::RubyLexPatch
|
|
113
113
|
false
|
114
114
|
end
|
115
115
|
else
|
116
|
-
|
117
|
-
|
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)
|
118
124
|
end
|
119
125
|
end
|
120
126
|
end
|
@@ -130,9 +136,7 @@ module KatakataIrb::RubyLexPatch
|
|
130
136
|
line_tokens.each do |token, _s|
|
131
137
|
tokens_until_line << token if token != tokens_until_line.last
|
132
138
|
end
|
133
|
-
|
134
|
-
continue = c
|
135
|
-
end
|
139
|
+
continue = process_continue(tokens_until_line)
|
136
140
|
prompt next_opens, continue, line_num_offset
|
137
141
|
end
|
138
142
|
end
|
@@ -152,7 +156,7 @@ module KatakataIrb::RubyLexPatch
|
|
152
156
|
@io.auto_indent do |lines, line_index, byte_pointer, is_newline|
|
153
157
|
if is_newline
|
154
158
|
tokens = KatakataIrb::RubyLexPatch.complete_tokens(lines[0..line_index].join("\n"), context: context)
|
155
|
-
process_indent_level
|
159
|
+
process_indent_level(tokens)
|
156
160
|
else
|
157
161
|
code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
|
158
162
|
last_line = lines[line_index]&.byteslice(0, byte_pointer)
|
@@ -170,19 +174,20 @@ module KatakataIrb::RubyLexPatch
|
|
170
174
|
@prompt.call(ltype, nesting_level, opens.any? || continue, @line_no + line_num_offset)
|
171
175
|
end
|
172
176
|
|
173
|
-
|
174
|
-
|
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)
|
175
180
|
end
|
176
181
|
|
177
182
|
def readmultiline(context)
|
178
183
|
if @io.respond_to? :check_termination
|
179
|
-
store_prompt_to_irb
|
184
|
+
store_prompt_to_irb([], false, 0)
|
180
185
|
@input.call
|
181
186
|
else
|
182
187
|
# nomultiline
|
183
188
|
line = ''
|
184
189
|
line_offset = 0
|
185
|
-
store_prompt_to_irb
|
190
|
+
store_prompt_to_irb([], false, 0)
|
186
191
|
loop do
|
187
192
|
l = @input.call
|
188
193
|
unless l
|
@@ -194,7 +199,7 @@ module KatakataIrb::RubyLexPatch
|
|
194
199
|
_line_tokens, _prev_opens, next_opens = KatakataIrb::TRex.parse_line(tokens).last
|
195
200
|
return line if next_opens.empty?
|
196
201
|
line_offset += 1
|
197
|
-
store_prompt_to_irb
|
202
|
+
store_prompt_to_irb(next_opens, true, line_offset)
|
198
203
|
end
|
199
204
|
end
|
200
205
|
end
|
data/lib/katakata_irb/trex.rb
CHANGED
@@ -37,75 +37,92 @@ module KatakataIrb::TRex
|
|
37
37
|
case state
|
38
38
|
when :in_unquoted_symbol
|
39
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?
|
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)
|
41
41
|
when :in_method_head
|
42
|
-
unless %i[on_sp on_ignored_nl].include?(t.event)
|
42
|
+
unless %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end].include?(t.event)
|
43
43
|
next_args = []
|
44
44
|
body = nil
|
45
|
-
if args.include?
|
45
|
+
if args.include?(:receiver)
|
46
46
|
case t.event
|
47
47
|
when :on_lparen, :on_ivar, :on_gvar, :on_cvar
|
48
|
+
# def (receiver). | def @ivar. | def $gvar. | def @@cvar.
|
48
49
|
next_args << :dot
|
49
50
|
when :on_kw
|
50
|
-
|
51
|
-
|
51
|
+
case t.tok
|
52
|
+
when 'self', 'true', 'false', 'nil'
|
53
|
+
# def self(arg) | def self.
|
54
|
+
next_args.push(:arg, :dot)
|
52
55
|
else
|
56
|
+
# def if(arg)
|
53
57
|
skip = true
|
54
58
|
next_args << :arg
|
55
59
|
end
|
56
|
-
when :on_op
|
60
|
+
when :on_op, :on_backtick
|
61
|
+
# def +(arg)
|
57
62
|
skip = true
|
58
63
|
next_args << :arg
|
59
64
|
when :on_ident, :on_const
|
60
|
-
|
65
|
+
# def a(arg) | def a.
|
66
|
+
next_args.push(:arg, :dot)
|
61
67
|
end
|
62
68
|
end
|
63
|
-
if args.include?
|
69
|
+
if args.include?(:dot)
|
70
|
+
# def receiver.name
|
64
71
|
next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
|
65
72
|
end
|
66
|
-
if args.include?
|
67
|
-
if %i[on_ident on_const on_op on_kw].include?
|
73
|
+
if args.include?(:name)
|
74
|
+
if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
|
75
|
+
# def name(arg) | def receiver.name(arg)
|
68
76
|
next_args << :arg
|
69
77
|
skip = true
|
70
78
|
end
|
71
79
|
end
|
72
|
-
if args.include?
|
80
|
+
if args.include?(:arg)
|
73
81
|
case t.event
|
74
|
-
when :on_op
|
75
|
-
body = :oneliner if t.tok == '='
|
76
82
|
when :on_nl, :on_semicolon
|
83
|
+
# def recever.f;
|
77
84
|
body = :normal
|
78
85
|
when :on_lparen
|
86
|
+
# def recever.f()
|
79
87
|
next_args << :eq
|
80
88
|
else
|
81
|
-
|
89
|
+
if t.event == :on_op && t.tok == '='
|
90
|
+
# def receiver.f =
|
91
|
+
body = :oneliner
|
92
|
+
else
|
93
|
+
# def recever.f arg
|
94
|
+
next_args << :arg_without_paren
|
95
|
+
end
|
82
96
|
end
|
83
97
|
end
|
84
|
-
if args.include?
|
98
|
+
if args.include?(:eq)
|
85
99
|
if t.event == :on_op && t.tok == '='
|
86
100
|
body = :oneliner
|
87
|
-
|
101
|
+
else
|
88
102
|
body = :normal
|
89
103
|
end
|
90
104
|
end
|
91
|
-
if args.include?
|
92
|
-
|
105
|
+
if args.include?(:arg_without_paren)
|
106
|
+
if %i[on_semicolon on_nl].include?(t.event)
|
107
|
+
# def f a;
|
108
|
+
body = :normal
|
109
|
+
else
|
110
|
+
# def f a, b
|
111
|
+
next_args << :arg_without_paren
|
112
|
+
end
|
93
113
|
end
|
94
114
|
if body == :oneliner
|
95
115
|
opens.pop
|
96
116
|
elsif body
|
97
|
-
opens
|
98
|
-
opens << [last_tok, nil]
|
117
|
+
opens[-1] = [last_tok, nil]
|
99
118
|
else
|
100
|
-
opens
|
101
|
-
opens << [last_tok, :in_method_head, next_args]
|
119
|
+
opens[-1] = [last_tok, :in_method_head, next_args]
|
102
120
|
end
|
103
121
|
end
|
104
122
|
when :in_for_while_until_condition
|
105
123
|
if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
|
106
124
|
skip = true if t.event == :on_kw && t.tok == 'do'
|
107
|
-
opens
|
108
|
-
opens << [last_tok, nil]
|
125
|
+
opens[-1] = [last_tok, nil]
|
109
126
|
end
|
110
127
|
end
|
111
128
|
|
@@ -184,10 +201,10 @@ module KatakataIrb::TRex
|
|
184
201
|
prev_opens = []
|
185
202
|
min_depth = 0
|
186
203
|
output = []
|
187
|
-
last_opens =
|
204
|
+
last_opens = parse(tokens) do |t, _index, opens|
|
188
205
|
depth = t == opens.last&.first ? opens.size - 1 : opens.size
|
189
206
|
min_depth = depth if depth < min_depth
|
190
|
-
if t.tok.include?
|
207
|
+
if t.tok.include?("\n")
|
191
208
|
t.tok.each_line do |line|
|
192
209
|
line_tokens << [t, line]
|
193
210
|
next if line[-1] != "\n"
|
@@ -293,7 +293,7 @@ class KatakataIrb::TypeSimulator
|
|
293
293
|
sexp in [:def, _method_name_exp, params, body_stmt]
|
294
294
|
sexp in [:defs, receiver_exp, _dot_exp, _method_name_exp, params, body_stmt]
|
295
295
|
if receiver_exp
|
296
|
-
receiver_exp in
|
296
|
+
receiver_exp in [:paren, receiver_exp]
|
297
297
|
self_type = simulate_evaluate receiver_exp, scope
|
298
298
|
else
|
299
299
|
current_self_types = scope.self_type.types
|
@@ -407,6 +407,9 @@ class KatakataIrb::TypeSimulator
|
|
407
407
|
KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values]
|
408
408
|
in [:hash, nil]
|
409
409
|
KatakataIrb::Types::InstanceType.new Hash
|
410
|
+
in [:paren, [Symbol,] | false => statement]
|
411
|
+
# workaround for `p ()` and `p (foo)`
|
412
|
+
simulate_evaluate statement, scope if statement
|
410
413
|
in [:paren | :ensure | :else, statements]
|
411
414
|
statements.map { simulate_evaluate _1, scope }.last
|
412
415
|
in [:const_path_ref, receiver, [:@const, name,]]
|
@@ -574,6 +577,7 @@ class KatakataIrb::TypeSimulator
|
|
574
577
|
simulate_evaluate target, scope
|
575
578
|
simulate_evaluate value, scope
|
576
579
|
in [:massign, targets, value]
|
580
|
+
targets in [:mlhs, *targets] # (a,b) = value
|
577
581
|
rhs = simulate_evaluate value, scope
|
578
582
|
evaluate_massign targets, rhs, scope
|
579
583
|
rhs
|
data/lib/katakata_irb/types.rb
CHANGED
@@ -85,23 +85,26 @@ module KatakataIrb::Types
|
|
85
85
|
|
86
86
|
def self.type_from_object(object, max_level: 4)
|
87
87
|
max_level -= 1
|
88
|
+
sample_size = 1000
|
88
89
|
case object
|
89
90
|
when Array
|
91
|
+
values = object.size > sample_size ? object.sample(sample_size) : object
|
90
92
|
if max_level > 0
|
91
|
-
|
92
|
-
InstanceType.new Array, { Elem: UnionType[*values] }
|
93
|
+
InstanceType.new Array, { Elem: UnionType[*values.map { type_from_object(_1, max_level:) }] }
|
93
94
|
else
|
94
|
-
InstanceType.new Array, { Elem: UnionType[*
|
95
|
+
InstanceType.new Array, { Elem: UnionType[*values.map(&:class).uniq.map { InstanceType.new _1 }] }
|
95
96
|
end
|
96
97
|
when Hash
|
98
|
+
keys = object.size > sample_size ? object.keys.sample(sample_size) : object.keys
|
99
|
+
values = object.size > sample_size ? object.values.sample(sample_size) : object.values
|
97
100
|
if max_level > 0
|
98
|
-
|
99
|
-
|
100
|
-
InstanceType.new Hash, { K: UnionType[*
|
101
|
+
key_types = keys.map { type_from_object(_1, max_level:) }
|
102
|
+
value_types = values.map { type_from_object(_1, max_level:) }
|
103
|
+
InstanceType.new Hash, { K: UnionType[*key_types], V: UnionType[*value_types] }
|
101
104
|
else
|
102
|
-
|
103
|
-
|
104
|
-
InstanceType.new Hash, { K: UnionType[*
|
105
|
+
key_types = keys.map(&:class).uniq.map { InstanceType.new _1 }
|
106
|
+
value_types = values.map(&:class).uniq.map { InstanceType.new _1 }
|
107
|
+
InstanceType.new Hash, { K: UnionType[*key_types], V: UnionType[*value_types] }
|
105
108
|
end
|
106
109
|
when Module
|
107
110
|
SingletonType.new object
|
data/lib/katakata_irb/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tompng
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|
@@ -45,7 +45,6 @@ files:
|
|
45
45
|
- lib/katakata_irb/completor.rb
|
46
46
|
- lib/katakata_irb/reline_patch.rb
|
47
47
|
- lib/katakata_irb/reline_patches/escapeseq.patch
|
48
|
-
- lib/katakata_irb/reline_patches/fullwidth.patch
|
49
48
|
- lib/katakata_irb/reline_patches/indent.patch
|
50
49
|
- lib/katakata_irb/reline_patches/raw.patch
|
51
50
|
- lib/katakata_irb/reline_patches/scrollbar.patch
|
@@ -77,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
76
|
- !ruby/object:Gem::Version
|
78
77
|
version: '0'
|
79
78
|
requirements: []
|
80
|
-
rubygems_version: 3.
|
79
|
+
rubygems_version: 3.4.3
|
81
80
|
signing_key:
|
82
81
|
specification_version: 4
|
83
82
|
summary: IRB with Typed Completion
|
@@ -1,200 +0,0 @@
|
|
1
|
-
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
|
2
|
-
index c9e613e..6acf969 100644
|
3
|
-
--- a/lib/reline/line_editor.rb
|
4
|
-
+++ b/lib/reline/line_editor.rb
|
5
|
-
@@ -748,3 +741,3 @@ class Reline::LineEditor
|
6
|
-
end
|
7
|
-
str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
|
8
|
-
- str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
|
9
|
-
+ str, = Reline::Unicode.take_range(item, 0, str_width, padding: true)
|
10
|
-
@@ -793,85 +786,42 @@ class Reline::LineEditor
|
11
|
-
end
|
12
|
-
visual_lines.concat(vl)
|
13
|
-
}
|
14
|
-
- old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
|
15
|
-
- y = @first_line_started_from + @started_from
|
16
|
-
- y_diff = y - old_y
|
17
|
-
- if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
|
18
|
-
- # rerender top
|
19
|
-
- move_cursor_down(old_dialog.vertical_offset - y_diff)
|
20
|
-
- start = visual_start + old_dialog.vertical_offset
|
21
|
-
- line_num = dialog.vertical_offset - old_dialog.vertical_offset
|
22
|
-
- line_num.times do |i|
|
23
|
-
- Reline::IOGate.move_cursor_column(old_dialog.column)
|
24
|
-
- if visual_lines[start + i].nil?
|
25
|
-
- s = ' ' * old_dialog.width
|
26
|
-
- else
|
27
|
-
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
28
|
-
- s = padding_space_with_escape_sequences(s, old_dialog.width)
|
29
|
-
- end
|
30
|
-
- @output.write "\e[0m#{s}\e[0m"
|
31
|
-
- move_cursor_down(1) if i < (line_num - 1)
|
32
|
-
- end
|
33
|
-
- move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
34
|
-
- end
|
35
|
-
- if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
|
36
|
-
- # rerender bottom
|
37
|
-
- move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
|
38
|
-
- start = visual_start + dialog.vertical_offset + dialog.contents.size
|
39
|
-
- line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
|
40
|
-
- line_num.times do |i|
|
41
|
-
- Reline::IOGate.move_cursor_column(old_dialog.column)
|
42
|
-
- if visual_lines[start + i].nil?
|
43
|
-
- s = ' ' * old_dialog.width
|
44
|
-
- else
|
45
|
-
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
46
|
-
- s = padding_space_with_escape_sequences(s, old_dialog.width)
|
47
|
-
+ old_dialog_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
|
48
|
-
+ dialog_y = @first_line_started_from + @started_from
|
49
|
-
+
|
50
|
-
+ x_range = dialog.column...dialog.column + dialog.width
|
51
|
-
+ old_x_range = old_dialog.column...old_dialog.column + old_dialog.width
|
52
|
-
+ y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
|
53
|
-
+ old_y_range = old_dialog_y + old_dialog.vertical_offset...old_dialog_y + old_dialog.vertical_offset + old_dialog.contents.size
|
54
|
-
+
|
55
|
-
+ cursor_y = dialog_y
|
56
|
-
+ old_y_range.each do |y|
|
57
|
-
+ rerender_ranges = []
|
58
|
-
+ if y_range.cover?(y) && x_range.any?(old_x_range)
|
59
|
-
+ if old_x_range.begin < x_range.begin
|
60
|
-
+ # rerender left
|
61
|
-
+ rerender_ranges << [old_x_range.begin...[old_x_range.end, x_range.begin].min, true, false]
|
62
|
-
end
|
63
|
-
- @output.write "\e[0m#{s}\e[0m"
|
64
|
-
- move_cursor_down(1) if i < (line_num - 1)
|
65
|
-
- end
|
66
|
-
- move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
|
67
|
-
- end
|
68
|
-
- if old_dialog.column < dialog.column
|
69
|
-
- # rerender left
|
70
|
-
- move_cursor_down(old_dialog.vertical_offset - y_diff)
|
71
|
-
- width = dialog.column - old_dialog.column
|
72
|
-
- start = visual_start + old_dialog.vertical_offset
|
73
|
-
- line_num = old_dialog.contents.size
|
74
|
-
- line_num.times do |i|
|
75
|
-
- Reline::IOGate.move_cursor_column(old_dialog.column)
|
76
|
-
- if visual_lines[start + i].nil?
|
77
|
-
- s = ' ' * width
|
78
|
-
- else
|
79
|
-
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
|
80
|
-
- s = padding_space_with_escape_sequences(s, dialog.width)
|
81
|
-
+ if x_range.end < old_x_range.end
|
82
|
-
+ # rerender right
|
83
|
-
+ rerender_ranges << [[x_range.end, old_x_range.begin].max...old_x_range.end, false, true]
|
84
|
-
end
|
85
|
-
+ else
|
86
|
-
+ rerender_ranges << [old_x_range, true, true]
|
87
|
-
+ end
|
88
|
-
+
|
89
|
-
+ rerender_ranges.each do |range, cover_begin, cover_end|
|
90
|
-
+ move_cursor_down(y - cursor_y)
|
91
|
-
+ cursor_y = y
|
92
|
-
+ col = range.begin
|
93
|
-
+ width = range.end - range.begin
|
94
|
-
+ line = visual_lines[y + visual_start - old_dialog_y] || ''
|
95
|
-
+ s, col = Reline::Unicode.take_range(line, col, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
96
|
-
+ Reline::IOGate.move_cursor_column(col)
|
97
|
-
@output.write "\e[0m#{s}\e[0m"
|
98
|
-
- move_cursor_down(1) if i < (line_num - 1)
|
99
|
-
- end
|
100
|
-
- move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
101
|
-
- end
|
102
|
-
- if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
|
103
|
-
- # rerender right
|
104
|
-
- move_cursor_down(old_dialog.vertical_offset + y_diff)
|
105
|
-
- width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
|
106
|
-
- start = visual_start + old_dialog.vertical_offset
|
107
|
-
- line_num = old_dialog.contents.size
|
108
|
-
- line_num.times do |i|
|
109
|
-
- Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
|
110
|
-
- if visual_lines[start + i].nil?
|
111
|
-
- s = ' ' * width
|
112
|
-
- else
|
113
|
-
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
|
114
|
-
- rerender_width = old_dialog.width - dialog.width
|
115
|
-
- s = padding_space_with_escape_sequences(s, rerender_width)
|
116
|
-
- end
|
117
|
-
- Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
|
118
|
-
- @output.write "\e[0m#{s}\e[0m"
|
119
|
-
- move_cursor_down(1) if i < (line_num - 1)
|
120
|
-
end
|
121
|
-
- move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
|
122
|
-
end
|
123
|
-
+ move_cursor_up(cursor_y - dialog_y)
|
124
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
125
|
-
end
|
126
|
-
|
127
|
-
@@ -912,9 +862,8 @@ class Reline::LineEditor
|
128
|
-
dialog_vertical_size = dialog.contents.size
|
129
|
-
dialog_vertical_size.times do |i|
|
130
|
-
if i < visual_lines_under_dialog.size
|
131
|
-
- Reline::IOGate.move_cursor_column(dialog.column)
|
132
|
-
- str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
|
133
|
-
- str = padding_space_with_escape_sequences(str, dialog.width)
|
134
|
-
+ str, start_pos = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width, cover_begin: true, cover_end: true, padding: true)
|
135
|
-
+ Reline::IOGate.move_cursor_column(start_pos)
|
136
|
-
@output.write "\e[0m#{str}\e[0m"
|
137
|
-
else
|
138
|
-
Reline::IOGate.move_cursor_column(dialog.column)
|
139
|
-
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
|
140
|
-
index 6000c9f..03074dd 100644
|
141
|
-
--- a/lib/reline/unicode.rb
|
142
|
-
+++ b/lib/reline/unicode.rb
|
143
|
-
@@ -194,17 +194,21 @@ class Reline::Unicode
|
144
|
-
end
|
145
|
-
|
146
|
-
# Take a chunk of a String cut by width with escape sequences.
|
147
|
-
- def self.take_range(str, start_col, max_width, encoding = str.encoding)
|
148
|
-
+ def self.take_range(str, start_col, width, encoding: str.encoding, cover_begin: false, cover_end: false, padding: false)
|
149
|
-
chunk = String.new(encoding: encoding)
|
150
|
-
total_width = 0
|
151
|
-
rest = str.encode(Encoding::UTF_8)
|
152
|
-
in_zero_width = false
|
153
|
-
+ chunk_start_col = nil
|
154
|
-
+ chunk_end_col = nil
|
155
|
-
rest.scan(WIDTH_SCANNER) do |gc|
|
156
|
-
case
|
157
|
-
when gc[NON_PRINTING_START_INDEX]
|
158
|
-
in_zero_width = true
|
159
|
-
+ chunk << NON_PRINTING_START
|
160
|
-
when gc[NON_PRINTING_END_INDEX]
|
161
|
-
in_zero_width = false
|
162
|
-
+ chunk << NON_PRINTING_END
|
163
|
-
when gc[CSI_REGEXP_INDEX]
|
164
|
-
chunk << gc[CSI_REGEXP_INDEX]
|
165
|
-
when gc[OSC_REGEXP_INDEX]
|
166
|
-
@@ -215,13 +219,31 @@ class Reline::Unicode
|
167
|
-
chunk << gc
|
168
|
-
else
|
169
|
-
mbchar_width = get_mbchar_width(gc)
|
170
|
-
+ prev_width = total_width
|
171
|
-
total_width += mbchar_width
|
172
|
-
- break if (start_col + max_width) < total_width
|
173
|
-
- chunk << gc if start_col < total_width
|
174
|
-
+ break if !cover_end && total_width > start_col + width
|
175
|
-
+ if cover_begin ? start_col < total_width : start_col <= prev_width
|
176
|
-
+ chunk << gc
|
177
|
-
+ chunk_start_col ||= prev_width
|
178
|
-
+ chunk_end_col = total_width
|
179
|
-
+ end
|
180
|
-
+ break if total_width >= start_col + width
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
- chunk
|
185
|
-
+ chunk_start_col ||= start_col
|
186
|
-
+ chunk_end_col ||= start_col
|
187
|
-
+ if padding
|
188
|
-
+ if start_col < chunk_start_col
|
189
|
-
+ chunk = ' ' * (chunk_start_col - start_col) + chunk
|
190
|
-
+ chunk_start_col = start_col
|
191
|
-
+ end
|
192
|
-
+ if chunk_end_col < start_col + width
|
193
|
-
+ chunk << ' ' * (start_col + width - chunk_end_col)
|
194
|
-
+ chunk_end_col = start_col + width
|
195
|
-
+ end
|
196
|
-
+ end
|
197
|
-
+ [chunk, chunk_start_col, chunk_end_col - chunk_start_col]
|
198
|
-
end
|
199
|
-
|
200
|
-
def self.get_next_mbchar_size(line, byte_pointer)
|