ruby_jard 0.2.0 → 0.2.1

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +18 -0
  4. data/CNAME +1 -0
  5. data/README.md +206 -33
  6. data/_config.yml +1 -0
  7. data/docs/_config.yml +8 -0
  8. data/docs/demo.png +0 -0
  9. data/docs/index.md +238 -0
  10. data/docs/logo.jpg +0 -0
  11. data/docs/screen-backtrace.png +0 -0
  12. data/docs/screen-repl.png +0 -0
  13. data/docs/screen-source.png +0 -0
  14. data/docs/screen-threads.png +0 -0
  15. data/docs/screen-variables.png +0 -0
  16. data/images/bg_hr.png +0 -0
  17. data/images/blacktocat.png +0 -0
  18. data/images/body-bg.jpg +0 -0
  19. data/images/download-button.png +0 -0
  20. data/images/github-button.png +0 -0
  21. data/images/header-bg.jpg +0 -0
  22. data/images/highlight-bg.jpg +0 -0
  23. data/images/icon_download.png +0 -0
  24. data/images/sidebar-bg.jpg +0 -0
  25. data/images/sprite_download.png +0 -0
  26. data/javascripts/main.js +1 -0
  27. data/lib/ruby_jard.rb +3 -18
  28. data/lib/ruby_jard/box_drawer.rb +68 -22
  29. data/lib/ruby_jard/color_scheme.rb +28 -0
  30. data/lib/ruby_jard/color_schemes.rb +26 -0
  31. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +64 -0
  32. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +63 -0
  33. data/lib/ruby_jard/column.rb +12 -6
  34. data/lib/ruby_jard/commands/continue_command.rb +1 -0
  35. data/lib/ruby_jard/commands/list_command.rb +29 -0
  36. data/lib/ruby_jard/commands/next_command.rb +1 -0
  37. data/lib/ruby_jard/commands/step_command.rb +1 -0
  38. data/lib/ruby_jard/commands/step_out_command.rb +1 -0
  39. data/lib/ruby_jard/console.rb +102 -18
  40. data/lib/ruby_jard/control_flow.rb +9 -8
  41. data/lib/ruby_jard/decorators/color_decorator.rb +46 -57
  42. data/lib/ruby_jard/decorators/inspection_decorator.rb +76 -0
  43. data/lib/ruby_jard/decorators/loc_decorator.rb +83 -107
  44. data/lib/ruby_jard/decorators/source_decorator.rb +1 -1
  45. data/lib/ruby_jard/keys.rb +1 -0
  46. data/lib/ruby_jard/layout.rb +9 -99
  47. data/lib/ruby_jard/layout_calculator.rb +151 -0
  48. data/lib/ruby_jard/layouts/narrow_layout.rb +41 -0
  49. data/lib/ruby_jard/layouts/wide_layout.rb +17 -103
  50. data/lib/ruby_jard/repl_processor.rb +5 -1
  51. data/lib/ruby_jard/repl_proxy.rb +2 -1
  52. data/lib/ruby_jard/row.rb +5 -5
  53. data/lib/ruby_jard/row_renderer.rb +108 -0
  54. data/lib/ruby_jard/screen.rb +20 -115
  55. data/lib/ruby_jard/screen_drawer.rb +8 -75
  56. data/lib/ruby_jard/screen_manager.rb +78 -55
  57. data/lib/ruby_jard/screen_renderer.rb +138 -0
  58. data/lib/ruby_jard/screens/backtrace_screen.rb +67 -69
  59. data/lib/ruby_jard/screens/menu_screen.rb +43 -38
  60. data/lib/ruby_jard/screens/source_screen.rb +43 -27
  61. data/lib/ruby_jard/screens/threads_screen.rb +91 -39
  62. data/lib/ruby_jard/screens/variables_screen.rb +72 -56
  63. data/lib/ruby_jard/session.rb +16 -0
  64. data/lib/ruby_jard/span.rb +8 -6
  65. data/lib/ruby_jard/version.rb +1 -1
  66. data/ruby_jard.gemspec +4 -4
  67. data/stylesheets/github-light.css +130 -0
  68. data/stylesheets/normalize.css +424 -0
  69. data/stylesheets/print.css +228 -0
  70. data/stylesheets/stylesheet.css +245 -0
  71. metadata +52 -21
  72. data/lib/ruby_jard/templates/column_template.rb +0 -17
  73. data/lib/ruby_jard/templates/row_template.rb +0 -22
  74. data/lib/ruby_jard/templates/space_template.rb +0 -15
  75. data/lib/ruby_jard/templates/span_template.rb +0 -25
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ ##
5
+ # Adjust the layout between screens, render row's bitmap by calling RowRenderer,
6
+ # calculate screen window to ready for putting on the screen.
7
+ class ScreenRenderer
8
+ def initialize(screen:, color_scheme:)
9
+ @screen = screen
10
+ @color_scheme = color_scheme
11
+ end
12
+
13
+ def render
14
+ return unless @screen.need_to_render?
15
+
16
+ # Move this logic into a class called SreenRenderer
17
+ calculate_content_lengths
18
+ column_widths = calculate_column_widths
19
+ adjust_column_widths(column_widths)
20
+ render_rows
21
+ calculate_window
22
+ @screen.mark_rendered!
23
+
24
+ @screen
25
+ end
26
+
27
+ private
28
+
29
+ def calculate_content_lengths
30
+ @screen.rows.each do |row|
31
+ row.columns.each do |column|
32
+ column.content_length = column.spans.map(&:content_length).inject(&:+)
33
+ end
34
+ end
35
+ end
36
+
37
+ def calculate_column_widths
38
+ column_widths = {}
39
+ total_columns = count_columns
40
+
41
+ return column_widths if total_columns == 0
42
+
43
+ ideal_column_width = @screen.layout.width / total_columns
44
+ total_columns.times do |column_index|
45
+ column_widths[column_index] ||= 0
46
+ @screen.rows.each do |row|
47
+ column = row.columns[column_index]
48
+ if column.content_length > ideal_column_width - 1
49
+ column_widths[column_index] = nil
50
+ break
51
+ elsif column.content_length + 1 > column_widths[column_index]
52
+ column_widths[column_index] = column.content_length + 1
53
+ end
54
+ end
55
+ end
56
+ column_widths
57
+ end
58
+
59
+ def adjust_column_widths(column_widths)
60
+ dynamic_count = column_widths.values.select(&:nil?).length
61
+ fixed_width = column_widths.values.inject(0) do |sum, col|
62
+ col.nil? ? sum : sum + col
63
+ end
64
+
65
+ @screen.rows.each do |row|
66
+ total_width = 0
67
+ row.columns.each_with_index do |column, column_index|
68
+ column.width =
69
+ if column_index == row.columns.length - 1
70
+ @screen.layout.width - total_width
71
+ elsif column_widths[column_index].nil?
72
+ (@screen.layout.width - fixed_width) / dynamic_count
73
+ else
74
+ column_widths[column_index]
75
+ end
76
+ total_width += column.width
77
+ end
78
+ end
79
+ end
80
+
81
+ def render_rows
82
+ @screen.rows.each do |row|
83
+ RubyJard::RowRenderer.new(
84
+ row: row,
85
+ width: @screen.layout.width,
86
+ height: @screen.layout.height,
87
+ color_scheme: @color_scheme
88
+ ).render
89
+ end
90
+ end
91
+
92
+ def calculate_window
93
+ @screen.window = []
94
+
95
+ if @screen.cursor.nil?
96
+ find_seleted_window
97
+ else
98
+ find_cursor_window
99
+ end
100
+ end
101
+
102
+ def find_seleted_window
103
+ @screen.rows.each_with_index do |row, row_index|
104
+ row.content.each_with_index do |line, line_index|
105
+ if @screen.window.length < @screen.layout.height
106
+ @screen.window << line
107
+ elsif row_index < @screen.selected
108
+ @screen.window = [line]
109
+ elsif row_index == @screen.selected
110
+ if line_index != 0
111
+ @screen.window.shift
112
+ @screen.window << line
113
+ else
114
+ @screen.window = [line]
115
+ end
116
+ else
117
+ return
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ def find_cursor_window
124
+ cursor_line = -1
125
+ @screen.rows.each do |row|
126
+ row.content.each do |line|
127
+ cursor_line += 1
128
+ @screen.window << line if cursor_line >= @screen.cursor
129
+ return if @screen.window.length >= @screen.layout.height
130
+ end
131
+ end
132
+ end
133
+
134
+ def count_columns
135
+ @screen.rows.map { |row| row.columns.count }.max.to_i
136
+ end
137
+ end
138
+ end
@@ -6,48 +6,51 @@ module RubyJard
6
6
  # Backtrace screen implements the content to display current thread's backtrace to the user.
7
7
  class BacktraceScreen < RubyJard::Screen
8
8
  def title
9
- "Backtrace (#{frames_count})"
10
- end
11
-
12
- def data_size
13
- [@height, frames_count].min
14
- end
15
-
16
- def data_window
17
- return [] if data_size.zero?
18
-
19
- @data_window ||= backtrace[data_window_start..data_window_end]
20
- end
21
-
22
- def data_window_start
23
- return 0 if data_size.zero?
24
-
25
- current_frame / data_size * data_size
26
- end
27
-
28
- def data_window_end
29
- [frames_count, data_window_start + data_size - 1].min
9
+ ['Backtrace', "#{frames_count} frames"]
10
+ end
11
+
12
+ def build
13
+ @rows = @session.backtrace.map.with_index do |frame, frame_id|
14
+ RubyJard::Row.new(
15
+ line_limit: 2,
16
+ columns: [
17
+ RubyJard::Column.new(
18
+ spans: [
19
+ span_frame_id(frame_id)
20
+ ]
21
+ ),
22
+ RubyJard::Column.new(
23
+ spans: [
24
+ span_class_label(frame),
25
+ span_label_preposition,
26
+ span_method_label(frame),
27
+ span_path(frame)
28
+ ]
29
+ )
30
+ ]
31
+ )
32
+ end
33
+ @selected = current_frame
30
34
  end
31
35
 
32
- def span_mark(_frame, index)
33
- [
34
- current_frame?(index) ? '→' : ' ',
35
- [:bright_yellow, current_frame?(index) ? :bold : nil]
36
- ]
37
- end
36
+ private
38
37
 
39
- def span_frame_id(_frame, index)
40
- frame_id = index + data_window_start
41
- [
42
- frame_id.to_s,
43
- [
44
- current_frame?(index) ? :bright_yellow : :white,
45
- current_frame?(index) ? :bold : nil
46
- ]
47
- ]
38
+ def span_frame_id(frame_id)
39
+ frame_id_label = frame_id.to_s.rjust(frames_count.to_s.length)
40
+ if current_frame?(frame_id)
41
+ RubyJard::Span.new(
42
+ content: frame_id_label,
43
+ styles: :frame_id_highlighted
44
+ )
45
+ else
46
+ RubyJard::Span.new(
47
+ content: frame_id_label,
48
+ styles: :frame_id
49
+ )
50
+ end
48
51
  end
49
52
 
50
- def span_klass_label(frame, index)
53
+ def span_class_label(frame)
51
54
  object = frame[1]
52
55
  klass = frame[2]
53
56
  klass_label =
@@ -63,18 +66,23 @@ module RubyJard
63
66
  else
64
67
  klass.name
65
68
  end
66
- c_frame = frame_at(index).last.nil? ? '[c] ' : ''
67
- [
68
- "#{c_frame}#{klass_label}",
69
- [:green, current_frame?(index) ? :bold : nil]
70
- ]
69
+ c_frame = frame.last.nil? ? '[c] ' : ''
70
+ RubyJard::Span.new(
71
+ content: "#{c_frame}#{klass_label}",
72
+ margin_right: 1,
73
+ styles: :constant
74
+ )
71
75
  end
72
76
 
73
- def span_label_preposition(_frame, index)
74
- ['in', current_frame?(index) ? [:bright_white] : [:white]]
77
+ def span_label_preposition
78
+ RubyJard::Span.new(
79
+ content: 'in',
80
+ margin_right: 1,
81
+ styles: :frame_location
82
+ )
75
83
  end
76
84
 
77
- def span_method_label(frame, index)
85
+ def span_method_label(frame)
78
86
  location = frame[0]
79
87
  method_label =
80
88
  if location.label != location.base_label
@@ -82,33 +90,31 @@ module RubyJard
82
90
  else
83
91
  location.base_label
84
92
  end
85
- [method_label, [:green, current_frame?(index) ? :bold : nil]]
86
- end
87
-
88
- def span_path_preposition(frame, index)
89
- location = frame[0]
90
- decorated_path = decorate_path(location.absolute_path, location.lineno)
91
- preposition = decorated_path.gem? ? 'in' : 'at'
92
- [preposition, current_frame?(index) ? [:bright_white] : [:white]]
93
+ RubyJard::Span.new(
94
+ content: method_label,
95
+ margin_right: 1,
96
+ styles: :method
97
+ )
93
98
  end
94
99
 
95
- def span_path(frame, index)
100
+ def span_path(frame)
96
101
  location = frame[0]
97
102
  decorated_path = decorate_path(location.absolute_path, location.lineno)
98
103
 
99
104
  path_label =
100
105
  if decorated_path.gem?
101
- "#{decorated_path.gem} (#{decorated_path.gem_version})"
106
+ "in #{decorated_path.gem} (#{decorated_path.gem_version})"
102
107
  else
103
- "#{decorated_path.path}:#{decorated_path.lineno}"
108
+ "at #{decorated_path.path}:#{decorated_path.lineno}"
104
109
  end
105
- [path_label, current_frame?(index) ? [:bold, :bright_white] : [:white]]
110
+ RubyJard::Span.new(
111
+ content: path_label,
112
+ styles: :frame_location
113
+ )
106
114
  end
107
115
 
108
- private
109
-
110
- def current_frame?(index)
111
- index + data_window_start == current_frame
116
+ def current_frame?(frame_id)
117
+ frame_id == current_frame
112
118
  end
113
119
 
114
120
  def current_frame
@@ -119,18 +125,10 @@ module RubyJard
119
125
  end
120
126
  end
121
127
 
122
- def frame_at(index)
123
- backtrace[index + data_window_start]
124
- end
125
-
126
128
  def frames_count
127
129
  @session.backtrace.length
128
130
  end
129
131
 
130
- def backtrace
131
- @session.backtrace
132
- end
133
-
134
132
  def decorate_path(path, lineno)
135
133
  RubyJard::Decorators::PathDecorator.new(path, lineno)
136
134
  end
@@ -3,49 +3,54 @@
3
3
  module RubyJard
4
4
  module Screens
5
5
  class MenuScreen < RubyJard::Screen
6
- def draw(output)
7
- RubyJard::Console.move_to(output, @x, @y)
8
-
9
- margin = 0
10
- left_menu = generate_left_menu
11
- left_menu.each do |text, length|
12
- RubyJard::Console.move_to(output, @x + 1 + margin, @y)
13
- output.print text
14
- margin += length + 3
15
- end
16
-
17
- margin = 0
18
- right_menu = generate_right_menu
19
- right_menu.reverse.each do |text, length|
20
- RubyJard::Console.move_to(output, @x + @width - margin - length - 1, @y)
21
- output.print text
22
- margin += length + 3
23
- end
6
+ def build
7
+ span_title = RubyJard::Span.new(
8
+ content: ' REPL Console ',
9
+ styles: :title_highlighted
10
+ )
11
+ menu_spans = generate_menu_spans
12
+
13
+ alignment =
14
+ @layout.width -
15
+ span_title.content_length -
16
+ menu_spans.map(&:content_length).sum
17
+ span_align = RubyJard::Span.new(
18
+ content: ' ' * (alignment < 0 ? 0 : alignment),
19
+ styles: :background
20
+ )
21
+ @rows = [RubyJard::Row.new(
22
+ line_limit: 1,
23
+ ellipsis: false,
24
+ columns: [
25
+ RubyJard::Column.new(
26
+ spans: [
27
+ span_title,
28
+ span_align,
29
+ menu_spans
30
+ ].flatten
31
+ )
32
+ ]
33
+ )]
34
+ @selected = 0
24
35
  end
25
36
 
26
37
  private
27
38
 
28
- def generate_left_menu
29
- [
30
- # Fill in later
31
- ]
32
- end
33
-
34
- def generate_right_menu
39
+ def generate_menu_spans
35
40
  [
36
- decorate_text('Step (F7)', :white),
37
- decorate_text('Step Out (Shift+F7)', :white),
38
- decorate_text('Next (F8)', :white),
39
- decorate_text('Continue (F9)', :white)
40
- ]
41
- end
42
-
43
- def decorate_text(str, *styles)
44
- [color_decorator.decorate(str, *styles), str.length]
45
- end
46
-
47
- def color_decorator
48
- @color_decorator ||= RubyJard::Decorators::ColorDecorator.new
41
+ 'Up (F6)',
42
+ 'Down (Shift+F6)',
43
+ 'Step (F7)',
44
+ 'Step Out (Shift+F7)',
45
+ 'Next (F8)',
46
+ 'Continue (F9)'
47
+ ].map do |menu_item|
48
+ RubyJard::Span.new(
49
+ content: menu_item,
50
+ margin_left: 3,
51
+ styles: :control_buttons
52
+ )
53
+ end
49
54
  end
50
55
  end
51
56
  end
@@ -8,41 +8,57 @@ module RubyJard
8
8
 
9
9
  decorated_path = path_decorator(current_file, current_line)
10
10
  if decorated_path.gem?
11
- "Source (#{decorated_path.gem} - #{decorated_path.path}:#{decorated_path.lineno})"
11
+ ['Source', "#{decorated_path.gem} - #{decorated_path.path}:#{decorated_path.lineno}"]
12
12
  else
13
- "Source (#{decorated_path.path}:#{decorated_path.lineno})"
13
+ ['Source', "#{decorated_path.path}:#{decorated_path.lineno}"]
14
14
  end
15
15
  end
16
16
 
17
- def data_size
18
- @height
19
- end
20
-
21
- def data_window
22
- return [] if RubyJard.current_session.frame.nil?
23
-
24
- @data_window ||= source_decorator.codes
17
+ def build
18
+ return if RubyJard.current_session.frame.nil?
19
+
20
+ # TODO: screen now supports window.
21
+ codes = source_decorator.codes
22
+ @rows = codes.map.with_index do |loc, index|
23
+ RubyJard::Row.new(
24
+ line_limit: 3,
25
+ columns: [
26
+ RubyJard::Column.new(
27
+ spans: [
28
+ span_mark(index),
29
+ span_lineno(index)
30
+ ]
31
+ ),
32
+ RubyJard::Column.new(
33
+ word_wrap: RubyJard::Column::WORD_WRAP_BREAK_WORD,
34
+ spans: loc_spans(loc)
35
+ )
36
+ ]
37
+ )
38
+ end
39
+ @selected = 0
25
40
  end
26
41
 
27
- def span_mark(_loc, index)
42
+ def span_mark(index)
28
43
  lineno = source_lineno(index)
29
- [
30
- current_line == lineno ? '→' : ' ',
31
- [:bright_yellow, current_line == lineno ? :bold : nil]
32
- ]
44
+ RubyJard::Span.new(
45
+ margin_right: 1,
46
+ content: current_line == lineno ? '➠' : ' ',
47
+ styles: :source_line_mark
48
+ )
33
49
  end
34
50
 
35
- def span_lineno(_loc, index)
36
- lineno = source_lineno(index)
37
- [
38
- lineno.to_s,
39
- current_line == lineno ? [:bold, :bright_yellow] : [:dim, :white]
40
- ]
51
+ def span_lineno(index)
52
+ lineno = source_lineno(index).to_s.rjust(source_decorator.window_end.to_s.length)
53
+ RubyJard::Span.new(
54
+ content: lineno,
55
+ styles: current_line == lineno ? :source_line_mark : :source_lineno
56
+ )
41
57
  end
42
58
 
43
- def span_code(loc, index)
44
- lineno = source_lineno(index)
45
- [loc_decorator(loc).spans, current_line == lineno ? [:brighter] : [:dim]]
59
+ def loc_spans(loc)
60
+ spans, _tokens = loc_decorator.decorate(loc, current_file)
61
+ spans
46
62
  end
47
63
 
48
64
  private
@@ -68,11 +84,11 @@ module RubyJard
68
84
  end
69
85
 
70
86
  def source_decorator
71
- @source_decorator ||= RubyJard::Decorators::SourceDecorator.new(current_file, current_line, data_size)
87
+ @source_decorator ||= RubyJard::Decorators::SourceDecorator.new(current_file, current_line, @layout.height)
72
88
  end
73
89
 
74
- def loc_decorator(loc)
75
- RubyJard::Decorators::LocDecorator.new(current_file, loc)
90
+ def loc_decorator
91
+ @loc_decorator ||= RubyJard::Decorators::LocDecorator.new
76
92
  end
77
93
 
78
94
  def source_lineno(index)