ruby_jard 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/ruby.yml +85 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +70 -1
- data/CHANGELOG.md +31 -0
- data/Gemfile +6 -3
- data/README.md +122 -8
- data/bin/console +1 -2
- data/docs/color_schemes/256-light.png +0 -0
- data/docs/color_schemes/gruvbox.png +0 -0
- data/docs/color_schemes/one-half-dark.png +0 -0
- data/docs/color_schemes/one-half-light.png +0 -0
- data/lib/ruby_jard.rb +5 -5
- data/lib/ruby_jard/box_drawer.rb +4 -1
- data/lib/ruby_jard/color_schemes.rb +31 -15
- data/lib/ruby_jard/color_schemes/256_color_scheme.rb +37 -37
- data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +62 -0
- data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +36 -36
- data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +62 -0
- data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +61 -0
- data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +62 -0
- data/lib/ruby_jard/column.rb +3 -1
- data/lib/ruby_jard/commands/continue_command.rb +2 -3
- data/lib/ruby_jard/commands/down_command.rb +9 -5
- data/lib/ruby_jard/commands/exit_command.rb +27 -0
- data/lib/ruby_jard/commands/frame_command.rb +11 -10
- data/lib/ruby_jard/commands/jard/color_scheme_command.rb +52 -0
- data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
- data/lib/ruby_jard/commands/jard/output_command.rb +28 -0
- data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
- data/lib/ruby_jard/commands/jard_command.rb +50 -0
- data/lib/ruby_jard/commands/list_command.rb +5 -4
- data/lib/ruby_jard/commands/next_command.rb +10 -5
- data/lib/ruby_jard/commands/step_command.rb +10 -5
- data/lib/ruby_jard/commands/step_out_command.rb +10 -5
- data/lib/ruby_jard/commands/up_command.rb +10 -5
- data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
- data/lib/ruby_jard/config.rb +7 -3
- data/lib/ruby_jard/console.rb +10 -22
- data/lib/ruby_jard/control_flow.rb +3 -3
- data/lib/ruby_jard/decorators/color_decorator.rb +11 -5
- data/lib/ruby_jard/decorators/loc_decorator.rb +1 -1
- data/lib/ruby_jard/decorators/path_decorator.rb +20 -7
- data/lib/ruby_jard/decorators/source_decorator.rb +2 -0
- data/lib/ruby_jard/frame.rb +55 -0
- data/lib/ruby_jard/keys.rb +0 -3
- data/lib/ruby_jard/layout.rb +9 -2
- data/lib/ruby_jard/layout_calculator.rb +29 -12
- data/lib/ruby_jard/layout_picker.rb +34 -0
- data/lib/ruby_jard/layouts.rb +52 -0
- data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +28 -0
- data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
- data/lib/ruby_jard/layouts/tiny_layout.rb +25 -0
- data/lib/ruby_jard/layouts/wide_layout.rb +13 -15
- data/lib/ruby_jard/pager.rb +96 -0
- data/lib/ruby_jard/repl_processor.rb +61 -31
- data/lib/ruby_jard/repl_proxy.rb +193 -89
- data/lib/ruby_jard/row.rb +16 -1
- data/lib/ruby_jard/row_renderer.rb +51 -42
- data/lib/ruby_jard/screen.rb +2 -12
- data/lib/ruby_jard/screen_adjuster.rb +104 -0
- data/lib/ruby_jard/screen_drawer.rb +3 -0
- data/lib/ruby_jard/screen_manager.rb +32 -54
- data/lib/ruby_jard/screen_renderer.rb +30 -16
- data/lib/ruby_jard/screens.rb +31 -12
- data/lib/ruby_jard/screens/backtrace_screen.rb +23 -26
- data/lib/ruby_jard/screens/menu_screen.rb +53 -22
- data/lib/ruby_jard/screens/source_screen.rb +65 -37
- data/lib/ruby_jard/screens/threads_screen.rb +14 -14
- data/lib/ruby_jard/screens/variables_screen.rb +59 -34
- data/lib/ruby_jard/session.rb +19 -10
- data/lib/ruby_jard/span.rb +3 -0
- data/lib/ruby_jard/templates/layout_template.rb +1 -1
- data/lib/ruby_jard/templates/screen_template.rb +3 -4
- data/lib/ruby_jard/version.rb +1 -1
- data/ruby_jard.gemspec +1 -1
- metadata +38 -9
- data/lib/ruby_jard/commands/color_scheme_command.rb +0 -42
- data/lib/ruby_jard/layouts/narrow_layout.rb +0 -41
- data/lib/ruby_jard/screens/empty_screen.rb +0 -13
data/lib/ruby_jard/repl_proxy.rb
CHANGED
@@ -1,14 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'ruby_jard/
|
5
|
-
require 'ruby_jard/commands/down_command'
|
6
|
-
require 'ruby_jard/commands/next_command'
|
7
|
-
require 'ruby_jard/commands/step_command'
|
8
|
-
require 'ruby_jard/commands/step_out_command'
|
9
|
-
require 'ruby_jard/commands/frame_command'
|
10
|
-
require 'ruby_jard/commands/list_command'
|
11
|
-
require 'ruby_jard/commands/color_scheme_command'
|
3
|
+
require 'pty'
|
4
|
+
require 'ruby_jard/pager'
|
12
5
|
|
13
6
|
module RubyJard
|
14
7
|
##
|
@@ -44,7 +37,6 @@ module RubyJard
|
|
44
37
|
'stat', # Included in jard UI
|
45
38
|
'backtrace', # Re-implemented later
|
46
39
|
'break', # Re-implemented later
|
47
|
-
'exit', # Conflicted with continue
|
48
40
|
'exit-all', # Conflicted with continue
|
49
41
|
'exit-program', # We already have `exit` native command
|
50
42
|
'!pry', # No need to complicate things
|
@@ -54,119 +46,218 @@ module RubyJard
|
|
54
46
|
'disable-pry' # No need to complicate things
|
55
47
|
].freeze
|
56
48
|
|
57
|
-
COMMANDS = [
|
58
|
-
CMD_FLOW = :flow,
|
59
|
-
CMD_EVALUATE = :evaluate,
|
60
|
-
CMD_IDLE = :idle,
|
61
|
-
CMD_INTERRUPT = :interrupt
|
62
|
-
].freeze
|
63
|
-
|
64
|
-
# rubocop:disable Layout/HashAlignment
|
65
49
|
INTERNAL_KEY_BINDINGS = {
|
66
|
-
RubyJard::Keys::
|
67
|
-
RubyJard::Keys::CTRL_C => (KEY_BINDING_INTERRUPT = :interrupt)
|
50
|
+
RubyJard::Keys::CTRL_C => (KEY_BINDING_INTERRUPT = :interrupt)
|
68
51
|
}.freeze
|
69
|
-
# rubocop:enable Layout/HashAlignment
|
70
52
|
|
71
|
-
|
53
|
+
KEY_READ_TIMEOUT = 0.2 # 200ms
|
54
|
+
PTY_OUTPUT_TIMEOUT = 1.to_f / 60 # 60hz
|
55
|
+
|
56
|
+
##
|
57
|
+
# A tool to communicate between functional threads and main threads
|
58
|
+
class FlowInterrupt < StandardError
|
59
|
+
attr_reader :flow
|
60
|
+
|
61
|
+
def initialize(msg = '', flow = nil)
|
62
|
+
super(msg)
|
63
|
+
@flow = flow
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# A class to store the state with multi-thread guarding
|
69
|
+
# Ready => Processing/Exiting
|
70
|
+
# Processing => Ready again
|
71
|
+
# Exiting => Exited
|
72
|
+
# Exited => Ready
|
73
|
+
class ReplState
|
74
|
+
STATES = [
|
75
|
+
STATE_READY = 0,
|
76
|
+
STATE_EXITING = 1,
|
77
|
+
STATE_PROCESSING = 2,
|
78
|
+
STATE_EXITED = 3
|
79
|
+
].freeze
|
80
|
+
def initialize
|
81
|
+
@state = STATE_EXITED
|
82
|
+
@mutex = Mutex.new
|
83
|
+
end
|
84
|
+
|
85
|
+
def check(method_name)
|
86
|
+
@mutex.synchronize { yield if send(method_name) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def ready?
|
90
|
+
@state == STATE_READY
|
91
|
+
end
|
92
|
+
|
93
|
+
def ready!
|
94
|
+
if ready? || processing? || exited?
|
95
|
+
@mutex.synchronize { @state = STATE_READY }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def processing?
|
100
|
+
@state == STATE_PROCESSING
|
101
|
+
end
|
102
|
+
|
103
|
+
def processing!
|
104
|
+
return unless ready?
|
105
|
+
|
106
|
+
@mutex.synchronize { @state = STATE_PROCESSING }
|
107
|
+
end
|
108
|
+
|
109
|
+
def exiting?
|
110
|
+
@state == STATE_EXITING
|
111
|
+
end
|
112
|
+
|
113
|
+
def exiting!
|
114
|
+
@mutex.synchronize { @state = STATE_EXITING }
|
115
|
+
end
|
116
|
+
|
117
|
+
def exited?
|
118
|
+
@state == STATE_EXITED
|
119
|
+
end
|
120
|
+
|
121
|
+
def exited!
|
122
|
+
@mutex.synchronize { @state = STATE_EXITED }
|
123
|
+
end
|
124
|
+
end
|
72
125
|
|
73
126
|
def initialize(key_bindings: nil)
|
74
|
-
@
|
127
|
+
@state = ReplState.new
|
128
|
+
|
129
|
+
@pry_input_pipe_read, @pry_input_pipe_write = IO.pipe
|
130
|
+
@pry_output_pty_read, @pry_output_pty_write = PTY.open
|
75
131
|
@pry = pry_instance
|
76
|
-
|
132
|
+
|
77
133
|
@key_bindings = key_bindings || RubyJard::KeyBindings.new
|
78
134
|
INTERNAL_KEY_BINDINGS.each do |sequence, action|
|
79
135
|
@key_bindings.push(sequence, action)
|
80
136
|
end
|
81
|
-
end
|
82
137
|
|
83
|
-
|
84
|
-
|
138
|
+
@pry_pty_output_thread = Thread.new { pry_pty_output }
|
139
|
+
@pry_pty_output_thread.name = '<<Jard: Pty Output Thread>>'
|
85
140
|
end
|
86
141
|
|
87
142
|
def repl(current_binding)
|
88
|
-
|
89
|
-
@
|
143
|
+
@state.ready!
|
144
|
+
@openning_pager = false
|
145
|
+
|
146
|
+
RubyJard::Console.disable_echo!
|
147
|
+
RubyJard::Console.raw!
|
148
|
+
|
149
|
+
Readline.input = @pry_input_pipe_read
|
150
|
+
Readline.output = @pry_output_pty_write
|
90
151
|
@pry.binding_stack.clear
|
91
152
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
153
|
+
@main_thread = Thread.current
|
154
|
+
|
155
|
+
@pry_input_thread = Thread.new { pry_repl(current_binding) }
|
156
|
+
@pry_input_thread.abort_on_exception = true
|
157
|
+
@pry_input_thread.report_on_exception = false
|
158
|
+
@pry_input_thread.name = '<<Jard: Pry input thread >>'
|
98
159
|
|
99
|
-
|
100
|
-
|
160
|
+
@key_listen_thread = Thread.new { listen_key_press }
|
161
|
+
@key_listen_thread.abort_on_exception = true
|
162
|
+
@key_listen_thread.report_on_exception = false
|
163
|
+
@key_listen_thread.name = '<<Jard: Repl key listen >>'
|
164
|
+
|
165
|
+
[@pry_input_thread, @key_listen_thread].map(&:join)
|
166
|
+
rescue FlowInterrupt => e
|
167
|
+
@state.exiting!
|
168
|
+
sleep PTY_OUTPUT_TIMEOUT until @state.exited?
|
169
|
+
RubyJard::ControlFlow.dispatch(e.flow)
|
170
|
+
ensure
|
171
|
+
RubyJard::Console.enable_echo!
|
172
|
+
RubyJard::Console.cooked!
|
173
|
+
Readline.input = STDIN
|
174
|
+
Readline.output = STDOUT
|
175
|
+
@key_listen_thread&.exit if @key_listen_thread&.alive?
|
176
|
+
@pry_input_thread&.exit if @pry_input_thread&.alive?
|
177
|
+
@state.exited!
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
def read_key
|
183
|
+
RubyJard::Console.getch(STDIN, KEY_READ_TIMEOUT)
|
184
|
+
end
|
185
|
+
|
186
|
+
def pry_pty_output
|
187
|
+
loop do
|
188
|
+
if @state.exiting?
|
189
|
+
if @pry_output_pty_read.ready?
|
190
|
+
STDOUT.write @pry_output_pty_read.read_nonblock(2048), from_jard: true
|
191
|
+
else
|
192
|
+
@state.exited!
|
193
|
+
end
|
194
|
+
elsif @state.exited?
|
195
|
+
sleep PTY_OUTPUT_TIMEOUT
|
101
196
|
else
|
102
|
-
|
103
|
-
|
197
|
+
output = @pry_output_pty_read.read_nonblock(2048)
|
198
|
+
unless output.nil?
|
199
|
+
STDOUT.write output, from_jard: true
|
200
|
+
end
|
104
201
|
end
|
202
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
203
|
+
# Retry
|
204
|
+
sleep PTY_OUTPUT_TIMEOUT
|
105
205
|
end
|
106
|
-
pry_thread&.join
|
107
|
-
Readline.input = STDIN
|
108
206
|
end
|
109
207
|
|
110
208
|
def pry_repl(current_binding)
|
111
209
|
flow = RubyJard::ControlFlow.listen do
|
112
210
|
@pry.repl(current_binding)
|
113
211
|
end
|
114
|
-
@
|
115
|
-
|
116
|
-
|
117
|
-
raise
|
212
|
+
@state.check(:ready?) do
|
213
|
+
@main_thread.raise FlowInterrupt.new('Interrupt from repl thread', flow)
|
214
|
+
end
|
118
215
|
end
|
119
216
|
|
120
217
|
def listen_key_press
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
218
|
+
loop do
|
219
|
+
break if @state.exiting? || @state.exited?
|
220
|
+
|
221
|
+
if @state.processing? && @openning_pager
|
222
|
+
# Discard all keys unfortunately
|
223
|
+
sleep PTY_OUTPUT_TIMEOUT
|
224
|
+
else
|
225
|
+
key = @key_bindings.match { read_key }
|
226
|
+
if key.is_a?(RubyJard::KeyBinding)
|
227
|
+
continue = handle_key_binding(key)
|
228
|
+
break unless continue
|
229
|
+
elsif !key.empty?
|
230
|
+
@pry_input_pipe_write.write(key)
|
231
|
+
end
|
232
|
+
end
|
126
233
|
end
|
127
234
|
end
|
128
235
|
|
129
236
|
def handle_key_binding(key_binding)
|
130
237
|
case key_binding.action
|
131
|
-
when KEY_BINDING_ENDLINE
|
132
|
-
@pry_write_stream.write(key_binding.sequence)
|
133
|
-
@commands << [CMD_EVALUATE]
|
134
238
|
when KEY_BINDING_INTERRUPT
|
135
|
-
|
239
|
+
handle_interrupt_command
|
240
|
+
true
|
136
241
|
else
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def handle_command(pry_thread, cmd, value)
|
144
|
-
case cmd
|
145
|
-
when CMD_FLOW
|
146
|
-
pry_thread.exit if pry_thread.alive?
|
147
|
-
RubyJard::ControlFlow.dispatch(value)
|
148
|
-
when CMD_EVALUATE
|
149
|
-
loop do
|
150
|
-
cmd, value = @commands.deq
|
151
|
-
break if [CMD_IDLE, CMD_FLOW, CMD_INTERRUPT].include?(cmd)
|
242
|
+
flow = RubyJard::ControlFlow.new(:key_binding, action: key_binding.action)
|
243
|
+
@state.check(:ready?) do
|
244
|
+
@main_thread.raise FlowInterrupt.new('Interrupt from repl thread', flow)
|
152
245
|
end
|
153
|
-
|
154
|
-
when CMD_INTERRUPT
|
155
|
-
handle_interrupt_command(pry_thread)
|
156
|
-
when CMD_IDLE
|
157
|
-
# Ignore
|
246
|
+
false
|
158
247
|
end
|
159
248
|
end
|
160
249
|
|
161
|
-
def handle_interrupt_command
|
162
|
-
|
250
|
+
def handle_interrupt_command
|
251
|
+
@state.check(:ready?) do
|
252
|
+
@pry_input_thread&.raise Interrupt if @pry_input_thread&.alive?
|
253
|
+
end
|
163
254
|
loop do
|
164
255
|
begin
|
165
|
-
sleep
|
256
|
+
sleep PTY_OUTPUT_TIMEOUT
|
166
257
|
rescue Interrupt
|
167
258
|
# Interrupt spam. Ignore.
|
168
259
|
end
|
169
|
-
break unless
|
260
|
+
break unless @pry_input_thread&.pending_interrupt?
|
170
261
|
end
|
171
262
|
end
|
172
263
|
|
@@ -175,7 +266,8 @@ module RubyJard
|
|
175
266
|
prompt: pry_jard_prompt,
|
176
267
|
quiet: true,
|
177
268
|
commands: pry_command_set,
|
178
|
-
hooks: pry_hooks
|
269
|
+
hooks: pry_hooks,
|
270
|
+
output: @pry_output_pty_write
|
179
271
|
)
|
180
272
|
# I'll be burned in hell for this
|
181
273
|
# TODO: Contact pry author to add :after_handle_line hook
|
@@ -186,6 +278,10 @@ module RubyJard
|
|
186
278
|
end
|
187
279
|
alias_method :_original_handle_line, :handle_line
|
188
280
|
alias_method :handle_line, :_jard_handle_line
|
281
|
+
|
282
|
+
def pager
|
283
|
+
RubyJard::Pager.new(self)
|
284
|
+
end
|
189
285
|
end
|
190
286
|
pry_instance
|
191
287
|
end
|
@@ -215,18 +311,26 @@ module RubyJard
|
|
215
311
|
|
216
312
|
def pry_hooks
|
217
313
|
hooks = Pry::Hooks.default
|
218
|
-
hooks.add_hook(:after_read, :jard_proxy_acquire_lock) do |
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
[CMD_IDLE]
|
224
|
-
end
|
225
|
-
rescue SyntaxError
|
226
|
-
@commands << [CMD_IDLE]
|
314
|
+
hooks.add_hook(:after_read, :jard_proxy_acquire_lock) do |_read_string, _pry|
|
315
|
+
RubyJard::Console.cooked!
|
316
|
+
@state.processing!
|
317
|
+
# Sleep 2 ticks, wait for pry to print out all existing output in the queue
|
318
|
+
sleep PTY_OUTPUT_TIMEOUT * 2
|
227
319
|
end
|
228
320
|
hooks.add_hook(:after_handle_line, :jard_proxy_release_lock) do
|
229
|
-
|
321
|
+
RubyJard::Console.raw!
|
322
|
+
@state.ready!
|
323
|
+
end
|
324
|
+
hooks.add_hook(:before_pager, :jard_proxy_before_pager) do
|
325
|
+
@openning_pager = true
|
326
|
+
|
327
|
+
@state.processing!
|
328
|
+
RubyJard::Console.cooked!
|
329
|
+
end
|
330
|
+
hooks.add_hook(:after_pager, :jard_proxy_after_pager) do
|
331
|
+
@openning_pager = false
|
332
|
+
@state.ready!
|
333
|
+
RubyJard::Console.raw!
|
230
334
|
end
|
231
335
|
end
|
232
336
|
end
|
data/lib/ruby_jard/row.rb
CHANGED
@@ -1,16 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RubyJard
|
4
|
+
##
|
5
|
+
# This class is an object to store a row of data display on a screen
|
4
6
|
class Row
|
5
7
|
extend Forwardable
|
6
8
|
|
7
|
-
attr_accessor :columns, :line_limit, :content
|
9
|
+
attr_accessor :columns, :line_limit, :content, :rendered
|
8
10
|
|
9
11
|
def initialize(line_limit: 1, columns: [], ellipsis: true)
|
10
12
|
@content = []
|
11
13
|
@columns = columns
|
12
14
|
@ellipsis = ellipsis
|
13
15
|
@line_limit = line_limit
|
16
|
+
@rendered = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def rendered?
|
20
|
+
@rendered == true
|
21
|
+
end
|
22
|
+
|
23
|
+
def mark_rendered
|
24
|
+
@rendered = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset_rendered
|
28
|
+
@rendered = false
|
14
29
|
end
|
15
30
|
end
|
16
31
|
end
|
@@ -14,63 +14,72 @@ module RubyJard
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def render
|
17
|
+
@row.reset_rendered
|
18
|
+
|
17
19
|
@x = 0
|
18
20
|
@y = 0
|
21
|
+
@original_x = 0
|
22
|
+
@original_y = 0
|
19
23
|
@content_map = []
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
@y =
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
render_column(column, original_x, content_width)
|
25
|
+
@row.columns.each do |column|
|
26
|
+
@x = @original_x
|
27
|
+
@y = @original_y
|
28
|
+
|
29
|
+
@drawing_width = 0
|
30
|
+
@drawing_lines = 1
|
28
31
|
|
29
|
-
|
32
|
+
column.spans.each do |span|
|
33
|
+
render_span(column, span)
|
34
|
+
end
|
35
|
+
|
36
|
+
@original_x += column.width
|
30
37
|
end
|
31
38
|
|
32
39
|
generate_bitmap
|
40
|
+
|
41
|
+
@row.mark_rendered
|
33
42
|
end
|
34
43
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
lines += 1
|
47
|
-
@y += 1
|
48
|
-
@x = original_x
|
49
|
-
end
|
50
|
-
elsif column.word_wrap == RubyJard::Column::WORD_WRAP_BREAK_WORD
|
51
|
-
if content_width - width <= 0
|
52
|
-
width = 0
|
53
|
-
lines += 1
|
54
|
-
@y += 1
|
55
|
-
@x = original_x
|
56
|
-
end
|
57
|
-
elsif content_width - width <= 0
|
58
|
-
return
|
44
|
+
# rubocop:disable Metrics/MethodLength
|
45
|
+
def render_span(column, span)
|
46
|
+
line_content = span.content
|
47
|
+
|
48
|
+
until line_content.nil? || line_content.empty?
|
49
|
+
if column.word_wrap == RubyJard::Column::WORD_WRAP_NORMAL
|
50
|
+
if column.content_width - @drawing_width < line_content.length && @drawing_width != 0
|
51
|
+
@drawing_width = 0
|
52
|
+
@drawing_lines += 1
|
53
|
+
@y += 1
|
54
|
+
@x = @original_x
|
59
55
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
draw_content(drawing_content, span.styles)
|
67
|
-
return
|
68
|
-
else
|
69
|
-
draw_content(drawing_content, span.styles)
|
56
|
+
elsif column.word_wrap == RubyJard::Column::WORD_WRAP_BREAK_WORD
|
57
|
+
if column.content_width - @drawing_width <= 0
|
58
|
+
@drawing_width = 0
|
59
|
+
@drawing_lines += 1
|
60
|
+
@y += 1
|
61
|
+
@x = @original_x
|
70
62
|
end
|
63
|
+
elsif column.content_width - @drawing_width <= 0
|
64
|
+
return
|
65
|
+
end
|
66
|
+
drawing_content = line_content[0..column.content_width - @drawing_width - 1]
|
67
|
+
line_content = line_content[column.content_width - @drawing_width..-1]
|
68
|
+
@drawing_width += drawing_content.length
|
69
|
+
|
70
|
+
if !@row.line_limit.nil? &&
|
71
|
+
@drawing_lines >= @row.line_limit &&
|
72
|
+
!line_content.nil? &&
|
73
|
+
!line_content.empty?
|
74
|
+
drawing_content[drawing_content.length - ELLIPSIS.length..-1] = ELLIPSIS
|
75
|
+
draw_content(drawing_content, span.styles)
|
76
|
+
return
|
77
|
+
else
|
78
|
+
draw_content(drawing_content, span.styles)
|
71
79
|
end
|
72
80
|
end
|
73
81
|
end
|
82
|
+
# rubocop:enable Metrics/MethodLength
|
74
83
|
|
75
84
|
def draw_content(drawing_content, styles)
|
76
85
|
return if @y < 0 || @y >= @height
|