ruby_jard 0.2.2 → 0.2.3

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.github/workflows/ruby.yml +85 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +70 -1
  7. data/CHANGELOG.md +31 -0
  8. data/Gemfile +6 -3
  9. data/README.md +122 -8
  10. data/bin/console +1 -2
  11. data/docs/color_schemes/256-light.png +0 -0
  12. data/docs/color_schemes/gruvbox.png +0 -0
  13. data/docs/color_schemes/one-half-dark.png +0 -0
  14. data/docs/color_schemes/one-half-light.png +0 -0
  15. data/lib/ruby_jard.rb +5 -5
  16. data/lib/ruby_jard/box_drawer.rb +4 -1
  17. data/lib/ruby_jard/color_schemes.rb +31 -15
  18. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +37 -37
  19. data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +62 -0
  20. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +36 -36
  21. data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +62 -0
  22. data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +61 -0
  23. data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +62 -0
  24. data/lib/ruby_jard/column.rb +3 -1
  25. data/lib/ruby_jard/commands/continue_command.rb +2 -3
  26. data/lib/ruby_jard/commands/down_command.rb +9 -5
  27. data/lib/ruby_jard/commands/exit_command.rb +27 -0
  28. data/lib/ruby_jard/commands/frame_command.rb +11 -10
  29. data/lib/ruby_jard/commands/jard/color_scheme_command.rb +52 -0
  30. data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
  31. data/lib/ruby_jard/commands/jard/output_command.rb +28 -0
  32. data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
  33. data/lib/ruby_jard/commands/jard_command.rb +50 -0
  34. data/lib/ruby_jard/commands/list_command.rb +5 -4
  35. data/lib/ruby_jard/commands/next_command.rb +10 -5
  36. data/lib/ruby_jard/commands/step_command.rb +10 -5
  37. data/lib/ruby_jard/commands/step_out_command.rb +10 -5
  38. data/lib/ruby_jard/commands/up_command.rb +10 -5
  39. data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
  40. data/lib/ruby_jard/config.rb +7 -3
  41. data/lib/ruby_jard/console.rb +10 -22
  42. data/lib/ruby_jard/control_flow.rb +3 -3
  43. data/lib/ruby_jard/decorators/color_decorator.rb +11 -5
  44. data/lib/ruby_jard/decorators/loc_decorator.rb +1 -1
  45. data/lib/ruby_jard/decorators/path_decorator.rb +20 -7
  46. data/lib/ruby_jard/decorators/source_decorator.rb +2 -0
  47. data/lib/ruby_jard/frame.rb +55 -0
  48. data/lib/ruby_jard/keys.rb +0 -3
  49. data/lib/ruby_jard/layout.rb +9 -2
  50. data/lib/ruby_jard/layout_calculator.rb +29 -12
  51. data/lib/ruby_jard/layout_picker.rb +34 -0
  52. data/lib/ruby_jard/layouts.rb +52 -0
  53. data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +28 -0
  54. data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
  55. data/lib/ruby_jard/layouts/tiny_layout.rb +25 -0
  56. data/lib/ruby_jard/layouts/wide_layout.rb +13 -15
  57. data/lib/ruby_jard/pager.rb +96 -0
  58. data/lib/ruby_jard/repl_processor.rb +61 -31
  59. data/lib/ruby_jard/repl_proxy.rb +193 -89
  60. data/lib/ruby_jard/row.rb +16 -1
  61. data/lib/ruby_jard/row_renderer.rb +51 -42
  62. data/lib/ruby_jard/screen.rb +2 -12
  63. data/lib/ruby_jard/screen_adjuster.rb +104 -0
  64. data/lib/ruby_jard/screen_drawer.rb +3 -0
  65. data/lib/ruby_jard/screen_manager.rb +32 -54
  66. data/lib/ruby_jard/screen_renderer.rb +30 -16
  67. data/lib/ruby_jard/screens.rb +31 -12
  68. data/lib/ruby_jard/screens/backtrace_screen.rb +23 -26
  69. data/lib/ruby_jard/screens/menu_screen.rb +53 -22
  70. data/lib/ruby_jard/screens/source_screen.rb +65 -37
  71. data/lib/ruby_jard/screens/threads_screen.rb +14 -14
  72. data/lib/ruby_jard/screens/variables_screen.rb +59 -34
  73. data/lib/ruby_jard/session.rb +19 -10
  74. data/lib/ruby_jard/span.rb +3 -0
  75. data/lib/ruby_jard/templates/layout_template.rb +1 -1
  76. data/lib/ruby_jard/templates/screen_template.rb +3 -4
  77. data/lib/ruby_jard/version.rb +1 -1
  78. data/ruby_jard.gemspec +1 -1
  79. metadata +38 -9
  80. data/lib/ruby_jard/commands/color_scheme_command.rb +0 -42
  81. data/lib/ruby_jard/layouts/narrow_layout.rb +0 -41
  82. data/lib/ruby_jard/screens/empty_screen.rb +0 -13
@@ -4,22 +4,27 @@ module RubyJard
4
4
  module Commands
5
5
  # Command used to Step into the execution of the current line.
6
6
  class StepCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ValidationHelpers
8
+
7
9
  group 'RubyJard'
8
10
  description 'Step into the execution of the current line'
9
11
 
10
12
  match 'step'
11
13
 
12
14
  banner <<-BANNER
13
- Usage: step
14
-
15
- Step into the execution of the current line
16
-
15
+ Usage: step [times]
17
16
  Examples:
18
17
  step
18
+ step 1
19
+ step 7
20
+
21
+ Step into the execution of the current line.
19
22
  BANNER
20
23
 
21
24
  def process
22
- RubyJard::ControlFlow.dispatch(:step)
25
+ times = validate_positive_integer!(args.first || 1)
26
+
27
+ RubyJard::ControlFlow.dispatch(:step, times: times.to_i)
23
28
  end
24
29
  end
25
30
  end
@@ -4,22 +4,27 @@ module RubyJard
4
4
  module Commands
5
5
  # Command used to Step into the execution of the current line.
6
6
  class StepOutCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ValidationHelpers
8
+
7
9
  group 'RubyJard'
8
10
  description 'Step out of current frame and move to the execution of the upper frame'
9
11
 
10
12
  match 'step-out'
11
13
 
12
14
  banner <<-BANNER
13
- Usage: step-out
14
-
15
- Step out of current frame and move to the execution of the upper frame
16
-
15
+ Usage: step-out [times]
17
16
  Examples:
18
17
  step-out
18
+ step-out 1
19
+ step-out 7
20
+
21
+ Step out of current frame and move to the execution of the upper frame.
19
22
  BANNER
20
23
 
21
24
  def process
22
- RubyJard::ControlFlow.dispatch(:step_out)
25
+ times = validate_positive_integer!(args.first || 1)
26
+
27
+ RubyJard::ControlFlow.dispatch(:step_out, times: times.to_i)
23
28
  end
24
29
  end
25
30
  end
@@ -4,22 +4,27 @@ module RubyJard
4
4
  module Commands
5
5
  # Command used to explore stacktrace.
6
6
  class UpCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ValidationHelpers
8
+
7
9
  group 'RubyJard'
8
10
  description 'Explore the frames above the current stopped line in the backtrace'
9
11
 
10
12
  match 'up'
11
13
 
12
14
  banner <<-BANNER
13
- Usage: up
14
-
15
- Explore the frames above the current stopped line in the backtrace.
16
-
15
+ Usage: up [-h] [times]
17
16
  Examples:
18
17
  up
18
+ up 1
19
+ up 7
20
+
21
+ Explore the frames above the current stopped line in the backtrace. All the C frames will be skipped.
19
22
  BANNER
20
23
 
21
24
  def process
22
- RubyJard::ControlFlow.dispatch(:up)
25
+ times = validate_positive_integer!(args.first || 1)
26
+
27
+ RubyJard::ControlFlow.dispatch(:up, times: times.to_i)
23
28
  end
24
29
  end
25
30
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ ##
6
+ # Helpers to help validate commands
7
+ module ValidationHelpers
8
+ def validate_positive_integer!(input)
9
+ input = input.to_s.strip
10
+ unless input =~ /^[+\-\d]+$/
11
+ raise ::Pry::CommandError, '`argument is not an integer'
12
+ end
13
+
14
+ input = input.to_i
15
+ raise ::Pry::CommandError, 'argument must be positive' if input <= 0
16
+
17
+ input
18
+ end
19
+
20
+ def validate_non_negative_integer!(input)
21
+ input = input.to_s.strip
22
+ unless input =~ /^[+\-\d]+$/
23
+ raise ::Pry::CommandError, 'argument is not an integer'
24
+ end
25
+
26
+ input = input.to_i
27
+ raise ::Pry::CommandError, 'argument must be positive' if input < 0
28
+
29
+ input.to_i
30
+ end
31
+
32
+ def validate_present!(input)
33
+ input = input.to_s.strip
34
+ if input.empty?
35
+ raise ::Pry::CommandError, 'argument must be present'
36
+ end
37
+
38
+ input
39
+ end
40
+
41
+ def validate_range!(input, from, to)
42
+ if input < from || input > to
43
+ raise ::Pry::CommandError, "argument must be from #{from} to #{to}"
44
+ end
45
+
46
+ input
47
+ end
48
+ end
49
+ end
50
+ end
@@ -31,16 +31,20 @@ module RubyJard
31
31
  end
32
32
  end
33
33
 
34
- attr_reader :color_scheme
35
- attr_writer :color_scheme
34
+ attr_accessor :color_scheme, :alias_to_debugger, :layout, :enabled_screens
36
35
 
37
36
  CONFIG_FILE_NAME = '.jardrc'
38
37
  DEFAULTS = [
39
- DEFAULT_COLOR_SCHEME = '256'
38
+ DEFAULT_COLOR_SCHEME = '256',
39
+ DEFAULT_ALIAS_TO_DEBUGGER = false,
40
+ DEFAULT_LAYOUT = nil # Pick layout automatically
40
41
  ].freeze
41
42
 
42
43
  def initialize
43
44
  @color_scheme = DEFAULT_COLOR_SCHEME
45
+ @alias_to_debugger = DEFAULT_ALIAS_TO_DEBUGGER
46
+ @layout = DEFAULT_LAYOUT
47
+ @enabled_screens = RubyJard::Screens.names
44
48
  end
45
49
 
46
50
  def config
@@ -69,28 +69,16 @@ module RubyJard
69
69
  end
70
70
 
71
71
  def getch(input, timeout)
72
- return input.getch(min: 0, time: timeout) if input.respond_to?(:getch)
73
-
74
- raw!
75
- disable_echo!
76
- key =
77
- begin
78
- input.read_nonblock(255)
79
- rescue IO::WaitReadable
80
- io = IO.select([input], nil, nil, timeout)
81
- if io.nil?
82
- nil
83
- else
84
- retry
85
- end
86
- rescue IO::WaitWritable
87
- nil
88
- end
89
-
90
- key
91
- ensure
92
- cooked!
93
- enable_echo!
72
+ input.read_nonblock(255)
73
+ rescue IO::WaitReadable
74
+ io = IO.select([input], nil, nil, timeout)
75
+ if io.nil?
76
+ nil
77
+ else
78
+ retry
79
+ end
80
+ rescue IO::WaitWritable
81
+ nil
94
82
  end
95
83
 
96
84
  def raw!(output = STDOUT)
@@ -7,7 +7,8 @@ module RubyJard
7
7
  class ControlFlow
8
8
  THROW_KEYWORD = :jard_control_flow
9
9
  ALLOW_LIST = {
10
- continue: [:times], # lib/ruby_jard/commands/continue_command.rb
10
+ continue: [], # lib/ruby_jard/commands/continue_command.rb
11
+ exit: [], # lib/ruby_jard/commands/exit_command.rb
11
12
  frame: [:frame], # lib/ruby_jard/commands/frame_command.rb
12
13
  up: [:times], # lib/ruby_jard/commands/up_command.rb
13
14
  down: [:times], # lib/ruby_jard/commands/down_command.rb
@@ -15,8 +16,7 @@ module RubyJard
15
16
  step: [:times], # lib/ruby_jard/commands/step_command.rb
16
17
  step_out: [:times], # lib/ruby_jard/commands/step_out_command.rb
17
18
  key_binding: [:action], # lib/ruby_jard/commands/step_command.rb
18
- list: [], # lib/ruby_jard/commands/list_command.rb
19
- color_scheme: [:color_scheme] # lib/ruby_jard/commands/colorscheme_command.rb
19
+ list: [] # lib/ruby_jard/commands/list_command.rb
20
20
  }.freeze
21
21
 
22
22
  attr_reader :command, :arguments
@@ -4,6 +4,12 @@ module RubyJard
4
4
  module Decorators
5
5
  ##
6
6
  # Manipulate and decorate color for texts.
7
+ # This class translate colors to corresponding escape sequences.
8
+ # Support 24-bit color (#51617d format) or 256 colors (https://jonasjacek.github.io/colors/)
9
+ # Example:
10
+ # - #fafafa => \e[38;2;250;250;250m
11
+ # - #aaa => \e[38;2;170;170;170m
12
+ # - 77 => \e[38;2;170;170;170m
7
13
  class ColorDecorator
8
14
  HEX_PATTERN_6 = /^#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})$/i.freeze
9
15
  HEX_PATTERN_3 = /^#([A-Fa-f0-9]{1})([A-Fa-f0-9]{1})([A-Fa-f0-9]{1})$/i.freeze
@@ -35,22 +41,20 @@ module RubyJard
35
41
  "#{foreground}#{background}#{translate_styles(styles)}#{content}#{CSI_RESET}"
36
42
  end
37
43
 
38
- private
39
-
40
44
  def translate_color(color, foreground)
41
- if matches = HEX_PATTERN_6.match(color.to_s)
45
+ if (matches = HEX_PATTERN_6.match(color.to_s))
42
46
  red = matches[1].to_i(16)
43
47
  green = matches[2].to_i(16)
44
48
  blue = matches[3].to_i(16)
45
49
  sequence = foreground ? CSI_FOREGROUND_24BIT : CSI_BACKGROUND_24BIT
46
50
  format sequence, red, green, blue
47
- elsif matches = HEX_PATTERN_3.match(color.to_s)
51
+ elsif (matches = HEX_PATTERN_3.match(color.to_s))
48
52
  red = (matches[1] * 2).to_i(16)
49
53
  green = (matches[2] * 2).to_i(16)
50
54
  blue = (matches[3] * 2).to_i(16)
51
55
  sequence = foreground ? CSI_FOREGROUND_24BIT : CSI_BACKGROUND_24BIT
52
56
  format sequence, red, green, blue
53
- elsif matches = XTERM_NUMBER_PATTERN.match(color.to_s)
57
+ elsif (matches = XTERM_NUMBER_PATTERN.match(color.to_s))
54
58
  color = matches[1]
55
59
  sequence = foreground ? CSI_FOREGROUND_256 : CSI_BACKGROUND_256
56
60
  format sequence, color
@@ -59,6 +63,8 @@ module RubyJard
59
63
  end
60
64
  end
61
65
 
66
+ private
67
+
62
68
  def translate_styles(styles = [])
63
69
  styles.map { |key| STYLES_CSI_MAP[key] }.compact.join
64
70
  end
@@ -156,7 +156,7 @@ module RubyJard
156
156
  @opened << kind
157
157
  open_token(kind)
158
158
  end
159
- alias begin_line begin_group
159
+ alias_method :begin_line, :begin_group
160
160
 
161
161
  def end_group(_kind)
162
162
  return unless @opened.pop
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pathname'
4
+
3
5
  module RubyJard
4
6
  module Decorators
5
7
  ##
@@ -8,7 +10,7 @@ module RubyJard
8
10
  # location of the file.
9
11
  # If it's from the current working dir, strip the working dir.
10
12
  class PathDecorator
11
- GEM_PATTERN = /(.*)\-(\d+\.\d+[\.\d]*[\.\d]*[\-\.\w]*)/i.freeze
13
+ GEM_PATTERN = /(.*)-(\d+\.\d+[.\d]*[.\d]*[-.\w]*)/i.freeze
12
14
  PATH_TYPES = [
13
15
  TYPE_UNKNOWN = :unknown,
14
16
  TYPE_PWD = :pwd,
@@ -28,14 +30,16 @@ module RubyJard
28
30
  end
29
31
 
30
32
  def decorate
31
- if path.start_with?(Dir.pwd)
32
- @type = TYPE_PWD
33
+ try_parse_gem_path
34
+ return if gem?
35
+
36
+ @type = TYPE_PWD
37
+ if @path.start_with?(Dir.pwd)
33
38
  @path = @path[Dir.pwd.length..-1]
39
+ @path = @path[1..-1] if @path.start_with?('/')
34
40
  else
35
- decorate_gem_path
41
+ try_relative_path
36
42
  end
37
-
38
- @path = @path[1..-1] if @path.start_with?('/')
39
43
  end
40
44
 
41
45
  def gem?
@@ -44,7 +48,7 @@ module RubyJard
44
48
 
45
49
  private
46
50
 
47
- def decorate_gem_path
51
+ def try_parse_gem_path
48
52
  gem_paths.each do |gem_path|
49
53
  next unless path.start_with?(gem_path)
50
54
 
@@ -65,6 +69,15 @@ module RubyJard
65
69
  end
66
70
  end
67
71
 
72
+ def try_relative_path
73
+ relative_path = Pathname.new(@path).relative_path_from(Pathname.pwd).to_s
74
+ if relative_path.length < @path.length
75
+ @path = relative_path
76
+ end
77
+ rescue ArgumentError
78
+ # Fail to get relative path, ignore
79
+ end
80
+
68
81
  def gem_paths
69
82
  paths = []
70
83
 
@@ -12,6 +12,8 @@ module RubyJard
12
12
  @file = file
13
13
  @lineno = lineno
14
14
  @window = window
15
+ @window_start = 0
16
+ @window_end = 0
15
17
  @codes = []
16
18
 
17
19
  decorate
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ ##
5
+ # This class is a wrapper for Byebug::Frame. This class prevents direct
6
+ # access to Byebug's internal data structure, provides some more helpers
7
+ # and make Jard easier to test.
8
+ class Frame
9
+ attr_reader :pos
10
+
11
+ def initialize(context, pos)
12
+ @context = context
13
+ @pos = pos
14
+ end
15
+
16
+ def frame_file
17
+ @context.frame_file(@pos)
18
+ end
19
+
20
+ def frame_line
21
+ @context.frame_line(@pos)
22
+ end
23
+
24
+ def frame_location
25
+ frame_backtrace = @context.backtrace[@pos]
26
+ return nil if frame_backtrace.nil?
27
+
28
+ frame_backtrace.first
29
+ end
30
+
31
+ def frame_self
32
+ @context.frame_self(@pos)
33
+ end
34
+
35
+ def frame_class
36
+ @context.frame_class(@pos)
37
+ end
38
+
39
+ def frame_binding
40
+ @context.frame_binding(@pos)
41
+ end
42
+
43
+ def frame_method
44
+ @context.frame_method(@pos)
45
+ end
46
+
47
+ def c_frame?
48
+ frame_binding.nil?
49
+ end
50
+
51
+ def thread
52
+ @context.thread
53
+ end
54
+ end
55
+ end
@@ -34,8 +34,6 @@ module RubyJard
34
34
  SHIFT_F10 = "\e[21;2~"
35
35
  SHIFT_F11 = "\e[23;2~"
36
36
  SHIFT_F12 = "\e[24;2~"
37
-
38
- # rubocop:disable Layout/HashAlignment
39
37
  DEFAULT_KEY_BINDINGS = {
40
38
  F5 => (ACTION_LIST = :list),
41
39
  F6 => (ACTION_UP = :up),
@@ -45,6 +43,5 @@ module RubyJard
45
43
  F8 => (ACTION_NEXT = :next),
46
44
  F9 => (ACTION_CONTINUE = :continue)
47
45
  }.freeze
48
- # rubocop:enable Layout/HashAlignment
49
46
  end
50
47
  end
@@ -4,9 +4,15 @@ module RubyJard
4
4
  ##
5
5
  # Data object to store calculated layout
6
6
  class Layout
7
- attr_accessor :template, :box_width, :box_height, :box_x, :box_y, :width, :height, :x, :y
7
+ attr_accessor :template, :parent_template,
8
+ :box_width, :box_height, :box_x, :box_y,
9
+ :width, :height, :x, :y
8
10
 
9
- def initialize(template:, width: 0, height: 0, x: 0, y: 0, box_width:, box_height:, box_x:, box_y:)
11
+ def initialize(
12
+ template: nil, parent_template: nil,
13
+ width: 0, height: 0, x: 0, y: 0,
14
+ box_width: 0, box_height: 0, box_x: 0, box_y: 0
15
+ )
10
16
  @template = template
11
17
  @box_width = box_width
12
18
  @box_height = box_height
@@ -16,6 +22,7 @@ module RubyJard
16
22
  @height = height
17
23
  @x = x
18
24
  @y = y
25
+ @parent_template = parent_template
19
26
  end
20
27
  end
21
28
  end