terminal-layout 0.3.1 → 0.4.0
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/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
|