terminal-layout 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/ansi_string.rb +9 -8
- data/lib/terminal_layout/version.rb +1 -1
- data/lib/terminal_layout.rb +78 -21
- data/spec/ansi_string_spec.rb +5 -0
- data/spec/spec_helper.rb +0 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: effa639a6efd09195fc644fe6d4b325191ca7905
|
4
|
+
data.tar.gz: 187b259dcc98d8584948c4856772d440c6895564
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2538c3ca865a7d81c0bc562d1a6c6c71da80fc345785ad3f3c138bb1622c0917369b36081244b48e309a7dc1fd63d4399e876341fe0b7834150a5d59c92d982
|
7
|
+
data.tar.gz: 5e57352329d7cf5cecd6b09d98d6d6d65fb8931b32dc0fdc7db510a8428842ec07a6fd58a45b77aee3a803aeaa8ce775a39eda2635a3d9e19b17411752aac86f
|
data/Gemfile.lock
CHANGED
data/lib/ansi_string.rb
CHANGED
@@ -42,19 +42,20 @@ class ANSIString
|
|
42
42
|
|
43
43
|
range_begin = range.begin
|
44
44
|
range_end = range.end
|
45
|
-
|
46
|
-
|
45
|
+
|
46
|
+
if range.exclude_end?
|
47
|
+
if range_begin == 0 && range_end == 0
|
48
|
+
return ""
|
49
|
+
else
|
50
|
+
range_end -= 1
|
51
|
+
end
|
47
52
|
end
|
48
53
|
|
49
54
|
range_begin = @without_ansi.length - range.begin.abs if range.begin < 0
|
50
55
|
range_end = @without_ansi.length - range.end.abs if range.end < 0
|
51
56
|
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
str = build_string_with_ansi_for(range_begin..range_end)
|
56
|
-
ANSIString.new str if str
|
57
|
-
end
|
57
|
+
str = build_string_with_ansi_for(range_begin..range_end)
|
58
|
+
ANSIString.new str if str
|
58
59
|
end
|
59
60
|
|
60
61
|
def []=(range, replacement_str)
|
data/lib/terminal_layout.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'ansi_string'
|
2
2
|
require 'ostruct'
|
3
|
+
require 'treefell'
|
3
4
|
|
4
5
|
module TerminalLayout
|
5
6
|
Dimension = Struct.new(:width, :height)
|
@@ -80,7 +81,7 @@ module TerminalLayout
|
|
80
81
|
|
81
82
|
define_method("#{method}=") do |value|
|
82
83
|
style[method.to_sym] = value
|
83
|
-
@box.computed[method] = value
|
84
|
+
@box.computed[method.to_sym] = value
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
@@ -109,7 +110,7 @@ module TerminalLayout
|
|
109
110
|
end
|
110
111
|
|
111
112
|
def to_s
|
112
|
-
"<#{self.class.name} position=(#{x},#{y}) dimensions=#{width}x#{height} content=#{content}/>"
|
113
|
+
"<#{self.class.name} position=(#{x},#{y}) dimensions=#{width}x#{height} content=#{content} name=#{@box.name}/>"
|
113
114
|
end
|
114
115
|
|
115
116
|
def render
|
@@ -136,6 +137,7 @@ module TerminalLayout
|
|
136
137
|
end
|
137
138
|
|
138
139
|
def layout
|
140
|
+
Treefell['render'].puts "layout #{self.inspect}"
|
139
141
|
self.children = []
|
140
142
|
@current_x = 0
|
141
143
|
@current_y = 0
|
@@ -151,6 +153,7 @@ module TerminalLayout
|
|
151
153
|
end
|
152
154
|
|
153
155
|
children2crawl.each do |cbox|
|
156
|
+
Treefell['render'].puts "layout crawling children #{cbox.inspect}"
|
154
157
|
if cbox.display == :float
|
155
158
|
next if cbox.width.to_i == 0
|
156
159
|
|
@@ -175,10 +178,12 @@ module TerminalLayout
|
|
175
178
|
available_width = ending_x_for_current_y - @current_x
|
176
179
|
end
|
177
180
|
|
178
|
-
render_object = render_object_for(cbox, content:nil, style: {
|
181
|
+
render_object = render_object_for(cbox, content:nil, style: {
|
182
|
+
x: @current_x,
|
183
|
+
y: @current_y,
|
184
|
+
width: (cbox.width || available_width)
|
185
|
+
})
|
179
186
|
render_object.layout
|
180
|
-
render_object.x = @current_x
|
181
|
-
render_object.y = @current_y
|
182
187
|
|
183
188
|
if cbox.height
|
184
189
|
render_object.height = cbox.height
|
@@ -200,7 +205,18 @@ module TerminalLayout
|
|
200
205
|
loop do
|
201
206
|
partial_content = cbox.content[content_i...(content_i + available_width)]
|
202
207
|
chars_needed = partial_content.length
|
203
|
-
|
208
|
+
Treefell['render'].puts "laying out inline #{cbox.name} @current_x=#{@current_x} @current_y=#{@current_y} x=#{x} y=#{y}"
|
209
|
+
self.children << render_object_for(
|
210
|
+
cbox,
|
211
|
+
content:partial_content,
|
212
|
+
style: {
|
213
|
+
display: :inline,
|
214
|
+
x: @current_x,
|
215
|
+
y: @current_y,
|
216
|
+
width:chars_needed,
|
217
|
+
height:1
|
218
|
+
}
|
219
|
+
)
|
204
220
|
|
205
221
|
content_i += chars_needed
|
206
222
|
|
@@ -230,6 +246,12 @@ module TerminalLayout
|
|
230
246
|
end
|
231
247
|
end
|
232
248
|
|
249
|
+
self.children.each do |child|
|
250
|
+
child.box.computed[:x] += x
|
251
|
+
child.box.computed[:y] += y
|
252
|
+
end
|
253
|
+
Treefell['render'].puts "laid out box=#{box.name} render-object=#{self.children}"
|
254
|
+
|
233
255
|
self.children
|
234
256
|
end
|
235
257
|
|
@@ -316,7 +338,7 @@ module TerminalLayout
|
|
316
338
|
class Box
|
317
339
|
include EventEmitter
|
318
340
|
|
319
|
-
attr_accessor :style, :children, :content, :computed
|
341
|
+
attr_accessor :style, :children, :content, :computed, :name
|
320
342
|
|
321
343
|
def initialize(style:{}, children:[], content:"")
|
322
344
|
@style = style
|
@@ -350,6 +372,17 @@ module TerminalLayout
|
|
350
372
|
emit :child_changed, old_children, new_children
|
351
373
|
end
|
352
374
|
|
375
|
+
def find_child_of_type(type, &block)
|
376
|
+
children.each do |child|
|
377
|
+
matches = child.is_a?(type)
|
378
|
+
matches &= block.call(child) if matches && block
|
379
|
+
return child if matches
|
380
|
+
child_matches = child.find_child_of_type(type, &block)
|
381
|
+
return child_matches if child_matches
|
382
|
+
end
|
383
|
+
nil
|
384
|
+
end
|
385
|
+
|
353
386
|
def position
|
354
387
|
Position.new(x, y)
|
355
388
|
end
|
@@ -375,7 +408,7 @@ module TerminalLayout
|
|
375
408
|
end
|
376
409
|
|
377
410
|
def to_s
|
378
|
-
"
|
411
|
+
"<#{self.class}##{object_id} position=(#{x},#{y}) dimensions=#{width}x#{height} display=#{display.inspect} content=#{content} name=#{@name}/>"
|
379
412
|
end
|
380
413
|
|
381
414
|
def update_computed(style)
|
@@ -399,7 +432,7 @@ module TerminalLayout
|
|
399
432
|
def subscribe_to_events_on_children
|
400
433
|
@children.each do |child|
|
401
434
|
child.on(:content_changed) do |*args|
|
402
|
-
emit :
|
435
|
+
emit :content_changed
|
403
436
|
end
|
404
437
|
child.on(:child_changed) do |*args|
|
405
438
|
emit :child_changed
|
@@ -407,11 +440,13 @@ module TerminalLayout
|
|
407
440
|
child.on(:position_changed) do |*args|
|
408
441
|
emit :position_changed
|
409
442
|
end
|
443
|
+
child.on(:focused_changed) do |*args|
|
444
|
+
emit :focused_changed, *args
|
445
|
+
end
|
410
446
|
end
|
411
447
|
end
|
412
448
|
end
|
413
449
|
|
414
|
-
|
415
450
|
class InputBox < Box
|
416
451
|
# cursor_position is the actual coordinates on the screen of where then
|
417
452
|
# cursor is rendered
|
@@ -421,11 +456,26 @@ module TerminalLayout
|
|
421
456
|
# displayed on a single line
|
422
457
|
attr_accessor :position
|
423
458
|
|
459
|
+
def focus!
|
460
|
+
return if @focused
|
461
|
+
@focused = true
|
462
|
+
emit :focus_changed, !@focused, @focused
|
463
|
+
end
|
464
|
+
|
465
|
+
def remove_focus!
|
466
|
+
return unless @focused
|
467
|
+
@focused = false
|
468
|
+
emit :focus_changed, !@focused, @focused
|
469
|
+
end
|
470
|
+
|
471
|
+
def focused? ; !!@focused ; end
|
472
|
+
|
424
473
|
def initialize(*args)
|
425
474
|
super
|
426
475
|
@computed = { x: 0, y: 0 }
|
427
476
|
@cursor_position = OpenStruct.new(x: 0, y: 0)
|
428
477
|
@position = 0
|
478
|
+
@focused = false
|
429
479
|
end
|
430
480
|
|
431
481
|
def cursor_off
|
@@ -457,6 +507,7 @@ module TerminalLayout
|
|
457
507
|
# spans multiple lines. We do not want to update the x/y position(s)
|
458
508
|
# in this instance. We want to keep the original starting x/y.
|
459
509
|
if style[:y] && style[:y] > 0
|
510
|
+
Treefell['render'].puts "update_computed received a y > 0. Removing Y from update."
|
460
511
|
style = style.dup.delete_if { |k,_| [:x, :y].include?(k) }
|
461
512
|
end
|
462
513
|
@computed.merge!(style)
|
@@ -480,6 +531,8 @@ module TerminalLayout
|
|
480
531
|
end
|
481
532
|
|
482
533
|
def render_cursor(input_box)
|
534
|
+
Treefell['render'].puts "render cursor at box=#{input_box.inspect} computed=#{input_box.computed.inspect}"
|
535
|
+
|
483
536
|
move_up_n_rows @y
|
484
537
|
move_to_beginning_of_row
|
485
538
|
|
@@ -526,6 +579,8 @@ module TerminalLayout
|
|
526
579
|
@x = cursor_x
|
527
580
|
@y = cursor_y
|
528
581
|
|
582
|
+
Treefell['render'].puts "rendering cursor at x=#{@x} y=#{@y}"
|
583
|
+
|
529
584
|
if input_box.style[:cursor] == 'none'
|
530
585
|
@output.print @term_info.control_string "civis"
|
531
586
|
else
|
@@ -537,6 +592,14 @@ module TerminalLayout
|
|
537
592
|
dumb_render(object, reset: reset)
|
538
593
|
end
|
539
594
|
|
595
|
+
def find_top_of_tree(object)
|
596
|
+
loop do
|
597
|
+
break unless object.parent
|
598
|
+
object = object.parent
|
599
|
+
end
|
600
|
+
object
|
601
|
+
end
|
602
|
+
|
540
603
|
def dumb_render(object, reset: false)
|
541
604
|
if reset
|
542
605
|
@y = 0
|
@@ -546,10 +609,7 @@ module TerminalLayout
|
|
546
609
|
move_up_n_rows @y
|
547
610
|
move_to_beginning_of_row
|
548
611
|
|
549
|
-
|
550
|
-
break unless object.parent
|
551
|
-
object = object.parent
|
552
|
-
end
|
612
|
+
object = find_top_of_tree(object)
|
553
613
|
|
554
614
|
object_width = object.width
|
555
615
|
|
@@ -571,6 +631,7 @@ module TerminalLayout
|
|
571
631
|
line2print = "#{new_line}\e[0m"
|
572
632
|
term_info.control "el"
|
573
633
|
move_to_beginning_of_row
|
634
|
+
term_info.control "el"
|
574
635
|
Treefell['render'].puts "printing line=#{line2print.inspect}"
|
575
636
|
@output.puts line2print
|
576
637
|
else
|
@@ -584,18 +645,14 @@ module TerminalLayout
|
|
584
645
|
lines_drawn = (printable_content.length / object_width.to_f).ceil
|
585
646
|
@y = lines_drawn
|
586
647
|
|
587
|
-
input_box =
|
648
|
+
input_box = object.box.find_child_of_type(InputBox) do |box|
|
649
|
+
box.focused?
|
650
|
+
end
|
588
651
|
render_cursor(input_box)
|
589
652
|
|
590
653
|
@previously_printed_lines = printable_lines
|
591
654
|
end
|
592
655
|
|
593
|
-
def find_input_box(dom_node)
|
594
|
-
dom_node.children.detect do |child|
|
595
|
-
child.is_a?(InputBox) || find_input_box(child)
|
596
|
-
end
|
597
|
-
end
|
598
|
-
|
599
656
|
def clear_to_beginning_of_line ; term_info.control "el1" ; end
|
600
657
|
def clear_screen ; term_info.control "clear" ; end
|
601
658
|
def clear_screen_down ; term_info.control "ed" ; end
|
data/spec/ansi_string_spec.rb
CHANGED
@@ -261,6 +261,11 @@ describe 'ANSIString' do
|
|
261
261
|
expect(ansi_string[12..14]).to eq "ABC"
|
262
262
|
end
|
263
263
|
|
264
|
+
it "returns dos thine" do
|
265
|
+
ansi_string = ANSIString.new("ABC")
|
266
|
+
expect(ansi_string[0...1]).to eq "A"
|
267
|
+
end
|
268
|
+
|
264
269
|
it "returns up to the end" do
|
265
270
|
expect(ansi_string[-2..-1]).to eq yellow("ow")
|
266
271
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,7 +2,6 @@ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
|
2
2
|
|
3
3
|
require 'pry'
|
4
4
|
require 'terminal_layout'
|
5
|
-
require 'ansi_string'
|
6
5
|
|
7
6
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
8
7
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminal-layout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Dennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-terminfo
|