ruby_jard 0.1.0 → 0.2.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/.rubocop.yml +10 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +1 -1
- data/README.md +65 -2
- data/docs/guide-ui.png +0 -0
- data/lib/ruby_jard.rb +49 -12
- data/lib/ruby_jard/box_drawer.rb +126 -0
- data/lib/ruby_jard/column.rb +18 -0
- data/lib/ruby_jard/commands/continue_command.rb +1 -6
- data/lib/ruby_jard/commands/down_command.rb +1 -4
- data/lib/ruby_jard/commands/frame_command.rb +12 -11
- data/lib/ruby_jard/commands/next_command.rb +1 -4
- data/lib/ruby_jard/commands/step_command.rb +1 -4
- data/lib/ruby_jard/commands/step_out_command.rb +28 -0
- data/lib/ruby_jard/commands/up_command.rb +1 -4
- data/lib/ruby_jard/console.rb +86 -0
- data/lib/ruby_jard/control_flow.rb +71 -0
- data/lib/ruby_jard/decorators/color_decorator.rb +78 -0
- data/lib/ruby_jard/decorators/loc_decorator.rb +41 -28
- data/lib/ruby_jard/decorators/source_decorator.rb +1 -1
- data/lib/ruby_jard/key_binding.rb +14 -0
- data/lib/ruby_jard/key_bindings.rb +96 -0
- data/lib/ruby_jard/keys.rb +49 -0
- data/lib/ruby_jard/layout.rb +67 -55
- data/lib/ruby_jard/layouts/wide_layout.rb +138 -0
- data/lib/ruby_jard/repl_processor.rb +80 -90
- data/lib/ruby_jard/repl_proxy.rb +232 -0
- data/lib/ruby_jard/row.rb +16 -0
- data/lib/ruby_jard/screen.rb +114 -36
- data/lib/ruby_jard/screen_drawer.rb +89 -0
- data/lib/ruby_jard/screen_manager.rb +157 -56
- data/lib/ruby_jard/screens/backtrace_screen.rb +88 -97
- data/lib/ruby_jard/screens/menu_screen.rb +23 -31
- data/lib/ruby_jard/screens/source_screen.rb +42 -90
- data/lib/ruby_jard/screens/threads_screen.rb +50 -64
- data/lib/ruby_jard/screens/variables_screen.rb +96 -99
- data/lib/ruby_jard/session.rb +13 -7
- data/lib/ruby_jard/span.rb +18 -0
- data/lib/ruby_jard/templates/column_template.rb +17 -0
- data/lib/ruby_jard/templates/layout_template.rb +35 -0
- data/lib/ruby_jard/templates/row_template.rb +22 -0
- data/lib/ruby_jard/templates/screen_template.rb +35 -0
- data/lib/ruby_jard/templates/space_template.rb +15 -0
- data/lib/ruby_jard/templates/span_template.rb +25 -0
- data/lib/ruby_jard/version.rb +1 -1
- data/ruby_jard.gemspec +1 -4
- metadata +29 -41
- data/lib/ruby_jard/commands/finish_command.rb +0 -31
- data/lib/ruby_jard/decorators/text_decorator.rb +0 -61
- data/lib/ruby_jard/layout_template.rb +0 -101
- data/lib/ruby_jard/screens/breakpoints_screen.rb +0 -23
- data/lib/ruby_jard/screens/expressions_sreen.rb +0 -22
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyJard
|
4
|
+
class Row
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_accessor :row_template, :columns
|
8
|
+
|
9
|
+
def_delegators :@row_template, :line_limit
|
10
|
+
|
11
|
+
def initialize(row_template:, columns: [])
|
12
|
+
@row_template = row_template
|
13
|
+
@columns = columns
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/ruby_jard/screen.rb
CHANGED
@@ -6,56 +6,134 @@ module RubyJard
|
|
6
6
|
# generated based on input layout specifiation, screen data, and top-left
|
7
7
|
# corner cordination.
|
8
8
|
class Screen
|
9
|
-
|
9
|
+
attr_accessor :output, :rows, :width, :height, :x, :y
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@
|
11
|
+
def initialize(screen_template:, session: nil, width:, height:, x:, y:)
|
12
|
+
@session = session || RubyJard.current_session
|
13
|
+
@screen_template = screen_template
|
14
|
+
@width = width
|
15
|
+
@height = height
|
16
|
+
@x = x
|
17
|
+
@y = y
|
18
18
|
end
|
19
19
|
|
20
|
-
def draw(
|
21
|
-
|
20
|
+
def draw(output)
|
21
|
+
calculate
|
22
|
+
drawer = RubyJard::ScreenDrawer.new(
|
23
|
+
output: output,
|
24
|
+
screen: self,
|
25
|
+
x: @x,
|
26
|
+
y: @y
|
27
|
+
)
|
28
|
+
drawer.draw
|
22
29
|
end
|
23
30
|
|
24
|
-
def
|
25
|
-
|
26
|
-
RubyJard::Decorators::TextDecorator.new(@color_decorator)
|
31
|
+
def data_size
|
32
|
+
raise NotImplementedError, "#{self.class} must implement #data_size method"
|
27
33
|
end
|
28
34
|
|
29
|
-
def
|
30
|
-
|
31
|
-
RubyJard::Decorators::PathDecorator.new(path, lineno)
|
35
|
+
def data_window
|
36
|
+
raise NotImplementedError, "#{self.class} must implement #data_window method"
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
39
|
+
def calculate
|
40
|
+
@rows = []
|
41
|
+
row_template = @screen_template.row_template
|
42
|
+
@rows = data_window.map.with_index do |data_row, index|
|
43
|
+
create_row(row_template, data_row, index)
|
44
|
+
end
|
45
|
+
column_widths = calculate_column_widths(row_template, @rows)
|
46
|
+
fill_column_widths(@rows, column_widths)
|
37
47
|
end
|
38
48
|
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
private
|
50
|
+
|
51
|
+
def calculate_column_widths(row_template, rows)
|
52
|
+
column_widths = {}
|
53
|
+
ideal_column_width = @width / row_template.columns.length
|
54
|
+
row_template.columns.each_with_index do |_column_template, column_index|
|
55
|
+
column_widths[column_index] ||= 0
|
56
|
+
rows.each do |row|
|
57
|
+
column = row.columns[column_index]
|
58
|
+
if column.content_length > ideal_column_width
|
59
|
+
column_widths[column_index] = nil
|
60
|
+
break
|
61
|
+
elsif column.content_length > column_widths[column_index]
|
62
|
+
column_widths[column_index] = column.content_length
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
column_widths
|
42
67
|
end
|
43
68
|
|
44
|
-
|
69
|
+
def fill_column_widths(rows, column_widths)
|
70
|
+
fixed_count = column_widths.length
|
71
|
+
fixed_width = column_widths.values.inject(0) do |sum, col|
|
72
|
+
col.nil? ? sum : sum + col
|
73
|
+
end
|
74
|
+
|
75
|
+
rows.each do |row|
|
76
|
+
total_width = 0
|
77
|
+
row.columns.each_with_index do |column, column_index|
|
78
|
+
column.width =
|
79
|
+
if column_index == row.columns.length - 1
|
80
|
+
@width - total_width
|
81
|
+
elsif column_widths[column_index].nil?
|
82
|
+
(@width - fixed_width) / fixed_count
|
83
|
+
else
|
84
|
+
column_widths[column_index]
|
85
|
+
end
|
86
|
+
total_width += column.width
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_row(row_template, data_row, index)
|
92
|
+
row = Row.new(row_template: row_template)
|
93
|
+
row.columns = row_template.columns.map do |column_template|
|
94
|
+
create_column(column_template, data_row, index)
|
95
|
+
end
|
96
|
+
row
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_column(column_template, data_row, index)
|
100
|
+
column = Column.new(column_template: column_template)
|
101
|
+
column.spans = column_template.spans.map do |span_template|
|
102
|
+
create_span(span_template, data_row, index)
|
103
|
+
end.flatten
|
104
|
+
column.content_length =
|
105
|
+
column.spans.map(&:content_length).inject(&:+) +
|
106
|
+
column.margin_left +
|
107
|
+
column.margin_right
|
108
|
+
column
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_span(span_template, data_row, index)
|
112
|
+
span = Span.new(span_template: span_template)
|
113
|
+
span_content_method = "span_#{span_template.name}".to_sym
|
114
|
+
|
115
|
+
if respond_to?(span_content_method)
|
116
|
+
content, styles = send(span_content_method, data_row, index)
|
117
|
+
if content.nil?
|
118
|
+
span.content = ''
|
119
|
+
span.content_length = 0
|
120
|
+
elsif content.is_a?(Array)
|
121
|
+
content.each do |sub_span|
|
122
|
+
sub_span.styles += Array(styles).flatten.compact
|
123
|
+
end
|
124
|
+
return content
|
125
|
+
else
|
126
|
+
content = ' ' * span_template.margin_left + content if span_template.margin_left
|
127
|
+
content += ' ' * span_template.margin_right if span_template.margin_right
|
128
|
+
span.content = content
|
129
|
+
span.styles = Array(styles).flatten.compact
|
130
|
+
span.content_length = span.content.length
|
131
|
+
end
|
132
|
+
else
|
133
|
+
raise NotImplementedError, "#{self.class} must implement #{span_content_method} method"
|
134
|
+
end
|
45
135
|
|
46
|
-
|
47
|
-
{
|
48
|
-
style: {
|
49
|
-
fg: :white
|
50
|
-
},
|
51
|
-
border: {
|
52
|
-
bottom_left: false,
|
53
|
-
bottom_right: false,
|
54
|
-
bottom: false,
|
55
|
-
left: :line,
|
56
|
-
right: false
|
57
|
-
}
|
58
|
-
}
|
136
|
+
span
|
59
137
|
end
|
60
138
|
end
|
61
139
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyJard
|
4
|
+
##
|
5
|
+
# Draw a screen and its rows into the output interface.
|
6
|
+
class ScreenDrawer
|
7
|
+
attr_reader :output
|
8
|
+
|
9
|
+
ELLIPSIS = ' »'
|
10
|
+
|
11
|
+
def initialize(output:, screen:, x:, y:)
|
12
|
+
@output = output
|
13
|
+
@color_decorator = RubyJard::Decorators::ColorDecorator.new
|
14
|
+
@x = x
|
15
|
+
@y = y
|
16
|
+
@original_x = x
|
17
|
+
@original_y = y
|
18
|
+
@screen = screen
|
19
|
+
end
|
20
|
+
|
21
|
+
def draw
|
22
|
+
@original_x = @x
|
23
|
+
@screen.rows.each do |row|
|
24
|
+
draw_columns(row, row.columns)
|
25
|
+
@y += 1
|
26
|
+
@x = @original_x
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def draw_columns(row, columns)
|
33
|
+
columns.each do |column|
|
34
|
+
width = 0
|
35
|
+
lines = 1
|
36
|
+
column_content_width = column.width - column.margin_left - column.margin_right
|
37
|
+
@x += column.margin_left
|
38
|
+
RubyJard::Console.move_to(@output, @x, @y)
|
39
|
+
|
40
|
+
column.spans.each do |span|
|
41
|
+
line_content = span.content
|
42
|
+
|
43
|
+
until line_content.nil? || line_content.empty?
|
44
|
+
if column_content_width - width <= 0
|
45
|
+
width = 0
|
46
|
+
lines += 1
|
47
|
+
@y += 1
|
48
|
+
RubyJard::Console.move_to(@output, @x, @y)
|
49
|
+
end
|
50
|
+
drawing_content = line_content[0..column_content_width - width - 1]
|
51
|
+
line_content = line_content[column_content_width - width..-1]
|
52
|
+
width += drawing_content.length
|
53
|
+
|
54
|
+
if !row.line_limit.nil? && lines >= row.line_limit && !line_content.nil? && !line_content.empty?
|
55
|
+
drawing_content[drawing_content.length - ELLIPSIS.length..-1] = ELLIPSIS
|
56
|
+
protected_print @color_decorator.decorate(drawing_content, *span.styles)
|
57
|
+
break
|
58
|
+
else
|
59
|
+
protected_print @color_decorator.decorate(drawing_content, *span.styles)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@x += column_content_width + column.margin_right
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def protected_print(content)
|
68
|
+
# TODO: currently, only row overflow is detected. Definitely should handle column overflow
|
69
|
+
return if @y < @original_y || @y > @original_y + @screen.height - 1
|
70
|
+
|
71
|
+
@output.print content
|
72
|
+
end
|
73
|
+
|
74
|
+
def default_frame_styles
|
75
|
+
{
|
76
|
+
style: {
|
77
|
+
fg: :white
|
78
|
+
},
|
79
|
+
border: {
|
80
|
+
bottom_left: false,
|
81
|
+
bottom_right: false,
|
82
|
+
bottom: false,
|
83
|
+
left: :line,
|
84
|
+
right: false
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -1,108 +1,209 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'ruby_jard/
|
3
|
+
require 'ruby_jard/console'
|
4
|
+
|
5
|
+
require 'ruby_jard/decorators/color_decorator'
|
4
6
|
require 'ruby_jard/decorators/path_decorator'
|
5
7
|
require 'ruby_jard/decorators/loc_decorator'
|
6
8
|
require 'ruby_jard/decorators/source_decorator'
|
9
|
+
|
7
10
|
require 'ruby_jard/screen'
|
11
|
+
require 'ruby_jard/box_drawer'
|
12
|
+
require 'ruby_jard/screen_drawer'
|
8
13
|
require 'ruby_jard/screens'
|
9
|
-
require 'ruby_jard/screens/breakpoints_screen'
|
10
|
-
require 'ruby_jard/screens/expressions_sreen'
|
11
14
|
require 'ruby_jard/screens/source_screen'
|
12
15
|
require 'ruby_jard/screens/backtrace_screen'
|
13
16
|
require 'ruby_jard/screens/threads_screen'
|
14
17
|
require 'ruby_jard/screens/variables_screen'
|
15
18
|
require 'ruby_jard/screens/menu_screen'
|
16
|
-
|
19
|
+
|
20
|
+
require 'ruby_jard/templates/layout_template'
|
21
|
+
require 'ruby_jard/templates/screen_template'
|
22
|
+
require 'ruby_jard/templates/row_template'
|
23
|
+
require 'ruby_jard/templates/column_template'
|
24
|
+
require 'ruby_jard/templates/span_template'
|
25
|
+
require 'ruby_jard/templates/space_template'
|
26
|
+
|
27
|
+
require 'ruby_jard/layouts/wide_layout'
|
17
28
|
require 'ruby_jard/layout'
|
29
|
+
require 'ruby_jard/row'
|
30
|
+
require 'ruby_jard/column'
|
31
|
+
require 'ruby_jard/span'
|
18
32
|
|
19
33
|
module RubyJard
|
20
34
|
##
|
21
35
|
# This class acts as a coordinator, in which it combines the data and screen
|
22
36
|
# layout template, triggers each screen to draw on the terminal.
|
23
37
|
class ScreenManager
|
24
|
-
|
38
|
+
class << self
|
39
|
+
extend Forwardable
|
40
|
+
|
41
|
+
def_delegators :instance, :update, :draw_error, :started?, :updating?
|
25
42
|
|
26
|
-
|
43
|
+
def instance
|
44
|
+
@instance ||= new
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :output, :output_storage
|
49
|
+
|
50
|
+
def initialize(output: STDOUT)
|
27
51
|
@output = output
|
28
|
-
@session = session
|
29
52
|
@screens = {}
|
53
|
+
@started = false
|
54
|
+
@updating = false
|
55
|
+
@output_storage = StringIO.new
|
30
56
|
end
|
31
57
|
|
32
58
|
def start
|
33
|
-
|
59
|
+
return if started?
|
60
|
+
|
61
|
+
RubyJard::Console.start_alternative_terminal(@output)
|
62
|
+
RubyJard::Console.hard_clear_screen(@output)
|
63
|
+
|
64
|
+
def $stdout.write(string)
|
65
|
+
if !RubyJard::ScreenManager.updating? && RubyJard::ScreenManager.started?
|
66
|
+
RubyJard::ScreenManager.instance.output_storage.write(string)
|
67
|
+
end
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
at_exit { stop }
|
72
|
+
@started = true
|
73
|
+
end
|
74
|
+
|
75
|
+
def started?
|
76
|
+
@started == true
|
77
|
+
end
|
78
|
+
|
79
|
+
def updating?
|
80
|
+
@updating == true
|
81
|
+
end
|
82
|
+
|
83
|
+
def stop
|
84
|
+
return unless started?
|
85
|
+
|
86
|
+
@started = false
|
87
|
+
|
88
|
+
RubyJard::Console.stop_alternative_terminal(@output)
|
89
|
+
RubyJard::Console.cooked!(@output)
|
90
|
+
RubyJard::Console.echo!(@output)
|
91
|
+
RubyJard::Console.show_cursor(@output)
|
92
|
+
|
93
|
+
unless @output_storage.string.empty?
|
94
|
+
@output.puts ''
|
95
|
+
@output.write @output_storage.string
|
96
|
+
@output.puts ''
|
97
|
+
end
|
98
|
+
@output_storage.close
|
34
99
|
end
|
35
100
|
|
36
|
-
def
|
101
|
+
def update
|
102
|
+
start unless started?
|
103
|
+
@updating = true
|
104
|
+
|
105
|
+
RubyJard::Console.hide_cursor(@output)
|
106
|
+
clear_screen
|
107
|
+
width, height = RubyJard::Console.screen_size(@output)
|
108
|
+
screen_layouts = calculate_layouts(width, height)
|
109
|
+
draw_screens(screen_layouts)
|
110
|
+
jump_to_prompt(screen_layouts)
|
111
|
+
draw_debug(width, height)
|
112
|
+
rescue StandardError => e
|
37
113
|
clear_screen
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
114
|
+
draw_error(e, height)
|
115
|
+
ensure
|
116
|
+
# You don't want to mess up previous user TTY no matter happens
|
117
|
+
RubyJard::Console.cooked!(@output)
|
118
|
+
RubyJard::Console.echo!(@output)
|
119
|
+
RubyJard::Console.show_cursor(@output)
|
120
|
+
@updating = false
|
121
|
+
end
|
122
|
+
|
123
|
+
def draw_error(exception, height = 0)
|
124
|
+
@output.puts '--- Error ---'
|
125
|
+
@output.puts "Internal error from Jard. I'm sorry to mess up your debugging experience."
|
126
|
+
@output.puts 'It would be great if you can submit an issue in https://github.com/nguyenquangminh0711/ruby_jard/issues'
|
127
|
+
@output.puts ''
|
128
|
+
@output.puts exception
|
129
|
+
if height == 0
|
130
|
+
@output.puts exception.backtrace
|
131
|
+
else
|
132
|
+
@output.puts exception.backtrace.first(height - 5)
|
48
133
|
end
|
134
|
+
@output.puts '-------------'
|
49
135
|
end
|
50
136
|
|
137
|
+
|
51
138
|
private
|
52
139
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
140
|
+
def calculate_layouts(width, height)
|
141
|
+
layout = pick_layout(width, height)
|
142
|
+
RubyJard::Layout.calculate(
|
143
|
+
layout: layout,
|
144
|
+
width: width, height: height,
|
145
|
+
x: 0, y: 0
|
146
|
+
)
|
56
147
|
end
|
57
148
|
|
58
|
-
def
|
59
|
-
|
149
|
+
def draw_box(screens)
|
150
|
+
RubyJard::BoxDrawer.new(
|
151
|
+
output: @output,
|
152
|
+
screens: screens
|
153
|
+
).draw
|
154
|
+
end
|
60
155
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
screen = fetch_screen(layout.screen)
|
156
|
+
def draw_screens(screen_layouts)
|
157
|
+
screens = screen_layouts.map do |screen_template, width, height, x, y|
|
158
|
+
screen = fetch_screen(screen_template.screen)
|
65
159
|
screen&.new(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
160
|
+
screen_template: screen_template,
|
161
|
+
width: width, height: height,
|
162
|
+
x: x, y: y
|
163
|
+
)
|
164
|
+
end
|
165
|
+
draw_box(screens)
|
166
|
+
adjust_screen_contents(screens)
|
167
|
+
screens.each do |screen|
|
168
|
+
screen.draw(@output)
|
72
169
|
end
|
73
170
|
end
|
74
171
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
max_height = child.height if max_height < child.height
|
86
|
-
# Overflow. Break to next line
|
87
|
-
if drawing_width >= layout.width
|
88
|
-
children_row += max_height
|
89
|
-
children_col = col
|
90
|
-
drawing_width = 0
|
91
|
-
max_height = 0
|
92
|
-
else
|
93
|
-
children_col += child.width
|
172
|
+
def jump_to_prompt(screen_layouts)
|
173
|
+
prompt_y = screen_layouts.map { |_template, _width, screen_height, _x, y| y + screen_height }.max
|
174
|
+
RubyJard::Console.move_to(@output, 0, prompt_y)
|
175
|
+
end
|
176
|
+
|
177
|
+
def draw_debug(_width, height)
|
178
|
+
unless RubyJard.debug_info.empty?
|
179
|
+
@output.puts '--- Debug ---'
|
180
|
+
RubyJard.debug_info.first(height - 2).each do |line|
|
181
|
+
@output.puts line
|
94
182
|
end
|
183
|
+
@output.puts '-------------'
|
95
184
|
end
|
185
|
+
RubyJard.clear_debug
|
186
|
+
end
|
96
187
|
|
97
|
-
|
188
|
+
def adjust_screen_contents(screens)
|
189
|
+
# After drawing the box, screen sizes should be updated to reflect content-only area
|
190
|
+
screens.each do |screen|
|
191
|
+
screen.width -= 2
|
192
|
+
screen.height -= 2
|
193
|
+
screen.x += 1
|
194
|
+
screen.y += 1
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def clear_screen
|
199
|
+
RubyJard::Console.clear_screen(@output)
|
98
200
|
end
|
99
|
-
# rubocop:enable Metrics/AbcSize
|
100
201
|
|
101
202
|
def fetch_screen(name)
|
102
203
|
RubyJard::Screens[name]
|
103
204
|
end
|
104
205
|
|
105
|
-
def
|
206
|
+
def pick_layout(width, height)
|
106
207
|
RubyJard::DEFAULT_LAYOUT_TEMPLATES.each do |template|
|
107
208
|
matched = true
|
108
209
|
matched &&= (
|