ruby_jard 0.2.3 → 0.3.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/documentation.yml +65 -0
  4. data/.github/workflows/{ruby.yml → rspec.yml} +22 -11
  5. data/.rubocop.yml +6 -0
  6. data/CHANGELOG.md +15 -3
  7. data/Gemfile +9 -2
  8. data/README.md +52 -332
  9. data/benchmark/path_filter_bench.rb +58 -0
  10. data/lib/ruby_jard.rb +15 -5
  11. data/lib/ruby_jard/color_schemes.rb +9 -1
  12. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +21 -35
  13. data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +23 -35
  14. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +20 -34
  15. data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +20 -34
  16. data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +20 -34
  17. data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +21 -34
  18. data/lib/ruby_jard/commands/color_helpers.rb +32 -0
  19. data/lib/ruby_jard/commands/frame_command.rb +2 -2
  20. data/lib/ruby_jard/commands/jard/color_scheme_command.rb +25 -3
  21. data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
  22. data/lib/ruby_jard/commands/jard/output_command.rb +13 -5
  23. data/lib/ruby_jard/commands/jard_command.rb +3 -1
  24. data/lib/ruby_jard/config.rb +9 -2
  25. data/lib/ruby_jard/decorators/array_decorator.rb +79 -0
  26. data/lib/ruby_jard/decorators/attributes_decorator.rb +172 -0
  27. data/lib/ruby_jard/decorators/color_decorator.rb +12 -5
  28. data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
  29. data/lib/ruby_jard/decorators/inspection_decorator.rb +91 -58
  30. data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
  31. data/lib/ruby_jard/decorators/path_decorator.rb +55 -72
  32. data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
  33. data/lib/ruby_jard/decorators/string_decorator.rb +41 -0
  34. data/lib/ruby_jard/decorators/struct_decorator.rb +79 -0
  35. data/lib/ruby_jard/frame.rb +23 -10
  36. data/lib/ruby_jard/keys.rb +1 -0
  37. data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +4 -0
  38. data/lib/ruby_jard/layouts/tiny_layout.rb +4 -0
  39. data/lib/ruby_jard/pager.rb +21 -5
  40. data/lib/ruby_jard/path_classifier.rb +133 -0
  41. data/lib/ruby_jard/path_filter.rb +125 -0
  42. data/lib/ruby_jard/reflection.rb +97 -0
  43. data/lib/ruby_jard/repl_processor.rb +71 -38
  44. data/lib/ruby_jard/row_renderer.rb +5 -3
  45. data/lib/ruby_jard/screen.rb +2 -2
  46. data/lib/ruby_jard/screen_manager.rb +13 -36
  47. data/lib/ruby_jard/screen_renderer.rb +1 -1
  48. data/lib/ruby_jard/screens/backtrace_screen.rb +55 -39
  49. data/lib/ruby_jard/screens/menu_screen.rb +30 -30
  50. data/lib/ruby_jard/screens/source_screen.rb +46 -62
  51. data/lib/ruby_jard/screens/threads_screen.rb +59 -72
  52. data/lib/ruby_jard/screens/variables_screen.rb +168 -124
  53. data/lib/ruby_jard/session.rb +120 -16
  54. data/lib/ruby_jard/thread_info.rb +69 -0
  55. data/lib/ruby_jard/version.rb +1 -1
  56. data/ruby_jard.gemspec +3 -1
  57. metadata +20 -39
  58. data/.travis.yml +0 -6
  59. data/CNAME +0 -1
  60. data/_config.yml +0 -1
  61. data/docs/_config.yml +0 -8
  62. data/docs/color_schemes/256-light.png +0 -0
  63. data/docs/color_schemes/256.png +0 -0
  64. data/docs/color_schemes/deep-space.png +0 -0
  65. data/docs/color_schemes/gruvbox.png +0 -0
  66. data/docs/color_schemes/one-half-dark.png +0 -0
  67. data/docs/color_schemes/one-half-light.png +0 -0
  68. data/docs/demo.png +0 -0
  69. data/docs/guide-ui.png +0 -0
  70. data/docs/index.md +0 -238
  71. data/docs/logo.jpg +0 -0
  72. data/docs/screen-backtrace.png +0 -0
  73. data/docs/screen-repl.png +0 -0
  74. data/docs/screen-source.png +0 -0
  75. data/docs/screen-threads.png +0 -0
  76. data/docs/screen-variables.png +0 -0
  77. data/images/bg_hr.png +0 -0
  78. data/images/blacktocat.png +0 -0
  79. data/images/body-bg.jpg +0 -0
  80. data/images/download-button.png +0 -0
  81. data/images/github-button.png +0 -0
  82. data/images/header-bg.jpg +0 -0
  83. data/images/highlight-bg.jpg +0 -0
  84. data/images/icon_download.png +0 -0
  85. data/images/sidebar-bg.jpg +0 -0
  86. data/images/sprite_download.png +0 -0
  87. data/javascripts/main.js +0 -1
  88. data/stylesheets/github-light.css +0 -130
  89. data/stylesheets/normalize.css +0 -424
  90. data/stylesheets/print.css +0 -228
  91. data/stylesheets/stylesheet.css +0 -245
@@ -20,40 +20,27 @@ module RubyJard
20
20
 
21
21
  BACKGROUND = WHITE
22
22
  STYLES = {
23
- background: [GRAY5, BACKGROUND],
24
- border: [GRAY3, BACKGROUND],
25
- title: [WHITE, GREEN],
26
- title_highlighted: [WHITE, YELLOW],
27
- title_secondary: [GRAY5, GRAY2],
28
- title_background: [GRAY3, BACKGROUND],
29
- menu_mode: [YELLOW, BACKGROUND],
30
- menu_tips: [GRAY4, BACKGROUND],
31
- thread_id: [GREEN, BACKGROUND],
32
- thread_name: [GRAY5, BACKGROUND],
33
- thread_status_run: [GREEN, BACKGROUND],
34
- thread_status_sleep: [GRAY4, BACKGROUND],
35
- thread_status_other: [GRAY4, BACKGROUND],
36
- thread_location: [GRAY5, BACKGROUND],
37
- frame_id: [GRAY4, BACKGROUND],
38
- frame_id_highlighted: [YELLOW, BACKGROUND],
39
- frame_location: [GRAY5, BACKGROUND],
40
- variable_mark: [GRAY4, BACKGROUND],
41
- variable_mark_inline: [YELLOW, BACKGROUND],
42
- variable_size: [GRAY5, BACKGROUND],
43
- variable_inspection: [GRAY5, BACKGROUND],
44
- variable_assignment: [GRAY5, BACKGROUND],
45
- source_line_mark: [YELLOW, BACKGROUND],
46
- source_lineno: [GRAY4, BACKGROUND],
47
- keyword: [PURPLE, BACKGROUND],
48
- method: [BLUE, BACKGROUND],
49
- comment: [GRAY4, BACKGROUND],
50
- literal: [YELLOW, BACKGROUND],
51
- string: [GREEN, BACKGROUND],
52
- local_variable: [RED, BACKGROUND],
53
- instance_variable: [RED, BACKGROUND],
54
- constant: [YELLOW, BACKGROUND],
55
- normal_token: [GRAY5, BACKGROUND],
56
- object: [YELLOW, BACKGROUND]
23
+ background: [GRAY5, BACKGROUND],
24
+ border: [GRAY3, BACKGROUND],
25
+ title: [WHITE, GREEN],
26
+ title_highlighted: [WHITE, YELLOW],
27
+ title_secondary: [GRAY5, GRAY2],
28
+ title_background: [GRAY3, BACKGROUND],
29
+ text_primary: [GRAY5, BACKGROUND],
30
+ text_dim: [GRAY4, BACKGROUND],
31
+ text_highlighted: [BLUE, BACKGROUND],
32
+ text_special: [RED, BACKGROUND],
33
+ text_selected: [GREEN, BACKGROUND],
34
+ keyword: [PURPLE, BACKGROUND],
35
+ method: [BLUE, BACKGROUND],
36
+ comment: [GRAY4, BACKGROUND],
37
+ literal: [YELLOW, BACKGROUND],
38
+ string: [GREEN, BACKGROUND],
39
+ local_variable: [RED, BACKGROUND],
40
+ instance_variable: [RED, BACKGROUND],
41
+ constant: [YELLOW, BACKGROUND],
42
+ normal_token: [GRAY5, BACKGROUND],
43
+ object: [YELLOW, BACKGROUND]
57
44
  }.freeze
58
45
  end
59
46
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ ##
6
+ # Helper to dedocrate command output
7
+ module ColorHelpers
8
+ def special(content)
9
+ color_decorator.decorate(:text_special, content)
10
+ end
11
+
12
+ def secondary(content)
13
+ color_decorator.decorate(:text_primary, content)
14
+ end
15
+
16
+ def highlight(content)
17
+ color_decorator.decorate(:text_highlighted, content)
18
+ end
19
+
20
+ def pick_color_scheme
21
+ (
22
+ RubyJard::ColorSchemes[RubyJard.config.color_scheme] ||
23
+ RubyJard::ColorSchemes[RubyJard::Config::DEFAULT_COLOR_SCHEME]
24
+ ).new
25
+ end
26
+
27
+ def color_decorator
28
+ @color_decorator ||= RubyJard::Decorators::ColorDecorator.new(pick_color_scheme)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -22,13 +22,13 @@ module RubyJard
22
22
 
23
23
  def initialize(context = {})
24
24
  super(context)
25
- @session = context[:session] || RubyJard.current_session
25
+ @current_backtrace = (context[:session] || RubyJard::Session).current_backtrace
26
26
  end
27
27
 
28
28
  def process
29
29
  frame = validate_present!(args.first)
30
30
  frame = validate_non_negative_integer!(frame)
31
- frame = validate_range!(frame, 0, @session.current_backtrace.length - 1)
31
+ frame = validate_range!(frame, 0, @current_backtrace.map(&:virtual_pos).compact.max)
32
32
  RubyJard::ControlFlow.dispatch(:frame, frame: frame)
33
33
  end
34
34
  end
@@ -4,6 +4,8 @@ module RubyJard
4
4
  module Commands
5
5
  # Command used to explore stacktrace.
6
6
  class ColorSchemeCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ColorHelpers
8
+
7
9
  group 'RubyJard'
8
10
  description 'Control the color scheme used in Jard'
9
11
 
@@ -29,24 +31,44 @@ module RubyJard
29
31
  if @color_schemes.names.empty?
30
32
  pry_instance.output.puts 'No loaded color schemes'
31
33
  else
32
- pry_instance.output.puts @color_schemes.names.join("\n")
34
+ print_color_schemes
33
35
  end
34
36
  else
35
37
  color_scheme = args.first.to_s.strip
36
38
  if color_scheme.empty?
37
39
  raise Pry::CommandError,
38
- 'You must provide a color scheme name. Please use `color-scheme -l` to list all color schemes.'
40
+ 'You must provide a color scheme name. '\
41
+ "Please use `#{highlight('jard color-scheme -l')}` to list all color schemes."
39
42
  end
40
43
 
41
44
  if @color_schemes[color_scheme].nil?
42
45
  raise Pry::CommandError,
43
- "Color scheme `#{color_scheme}` not found. Please use `color-scheme -l` to list all color schemes."
46
+ "Color scheme `#{secondary(color_scheme)}` not found. "\
47
+ "Please use `#{highlight('jard color-scheme -l')}` to list all color schemes."
44
48
  end
45
49
 
46
50
  @config.color_scheme = color_scheme
47
51
  RubyJard::ControlFlow.dispatch(:list)
48
52
  end
49
53
  end
54
+
55
+ private
56
+
57
+ def print_color_schemes
58
+ pry_instance.output.puts
59
+ pry_instance.output.puts highlight("#{@color_schemes.names.length} available color schemes")
60
+ pry_instance.output.puts
61
+ padding = @color_schemes.names.map(&:length).max
62
+ @color_schemes.names.each do |name|
63
+ scheme = @color_schemes[name]
64
+ decorator = RubyJard::Decorators::ColorDecorator.new(scheme.new)
65
+ pallete = scheme.const_get(:STYLES).keys.map do |style|
66
+ decorator.decorate(style, '⬤ ')
67
+ end.join(' ')
68
+ pry_instance.output.puts "#{name.ljust(padding)} #{pallete}"
69
+ pry_instance.output.puts
70
+ end
71
+ end
50
72
  end
51
73
  end
52
74
  end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ ##
6
+ # Control filter, included and excluded
7
+ class FilterCommand < Pry::ClassCommand
8
+ include RubyJard::Commands::ColorHelpers
9
+
10
+ group 'RubyJard'
11
+ description 'Filter to keep only relevant location when you debugging'
12
+
13
+ match 'filter'
14
+
15
+ banner <<-BANNER
16
+ Usage:
17
+ jard filter
18
+ jard filter [everything, gems, application, source_tree]
19
+ jard filter [include, exclude] pattern
20
+ jard filter clear
21
+
22
+ Ruby Jard has a strong filtering system. This system consists of a filter mode, included list, and excluded list. Filter mode is how Ruby Jard reacts to control flow commands. See https://rubyjard.org/docs/guides/filter for more information.
23
+
24
+ Examples:
25
+
26
+ jard filter # Show filter status
27
+
28
+ jard filter application # Switch to application mode
29
+ jard filter gems # Switch to gems mode
30
+ jard filter everything # Switch to everything mode
31
+ jard filter source_tree # Switch to source tree mode
32
+
33
+ jard filter include sidekiq # Include sidekiq pattern
34
+ jard filter include aws-*
35
+ jard filter include aws-* active* action* # Multiple patterns separated by <space>
36
+ jard filter include lib/**/*.erb
37
+ jard filter include ~/home/lib/**/*.rb
38
+
39
+ jard filter exclude sidekiq # exclude sidekiq pattern
40
+ jard filter exclude aws-*
41
+ jard filter exclude aws-* active* action* # Multiple patterns separated by <space>
42
+ jard filter exclude lib/**/*.erb
43
+ jard filter exclude ~/home/lib/**/*.rb
44
+
45
+ jard filter clear # Clear filter
46
+ BANNER
47
+
48
+ def initialize(*args)
49
+ super(*args)
50
+ @filters = RubyJard::PathFilter::FILTERS
51
+ @config = context[:config] || RubyJard.config
52
+ end
53
+
54
+ def process
55
+ if args.empty?
56
+ print_current_filter
57
+ return
58
+ end
59
+
60
+ sub_command = args.shift.to_sym
61
+
62
+ case sub_command
63
+ when *@filters
64
+ @config.filter = sub_command
65
+ RubyJard::ControlFlow.dispatch(:list)
66
+ when :include
67
+ handle_included
68
+ when :exclude
69
+ handle_excluded
70
+ when :clear
71
+ handle_clear
72
+ else
73
+ raise Pry::CommandError,
74
+ "Invalid filter '#{secondary(sub_command)}'."\
75
+ "Please type `#{highlight('jard filter --help')}` for more information"
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def print_current_filter
82
+ pry_instance.output.puts
83
+ pry_instance.output.puts highlight('Filter mode')
84
+ pry_instance.output.puts " #{@config.filter}"
85
+ pry_instance.output.puts highlight("Included (#{@config.filter_included.length})")
86
+ @config.filter_included.each do |included|
87
+ pry_instance.output.puts " +#{included}"
88
+ end
89
+
90
+ pry_instance.output.puts highlight("Excluded (#{@config.filter_excluded.length})")
91
+ @config.filter_excluded.each do |excluded|
92
+ pry_instance.output.puts " -#{excluded}"
93
+ end
94
+ pry_instance.output.puts
95
+ pry_instance.output.puts "Please type `#{highlight('jard filter --help')}` for more information"
96
+ pry_instance.output.puts
97
+ end
98
+
99
+ def handle_included
100
+ if args.empty?
101
+ raise Pry::CommandError,
102
+ 'Wrong number of arguments! '\
103
+ "Please type `#{highlight('jard filter --help')}` for more information"
104
+ end
105
+ filters = args.map(&:strip)
106
+ @config.filter_included.append(*filters)
107
+ @config.filter_included.uniq!
108
+ filters.each do |filter|
109
+ @config.filter_excluded.delete(filter) if @config.filter_excluded.include?(filter)
110
+ end
111
+ RubyJard::ControlFlow.dispatch(:list)
112
+ end
113
+
114
+ def handle_excluded
115
+ if args.empty?
116
+ raise Pry::CommandError,
117
+ 'Wrong number of arguments!'\
118
+ "Please type `#{highlight('jard filter --help')}` for more information"
119
+ end
120
+ filters = args.map(&:strip)
121
+ @config.filter_excluded.append(*filters)
122
+ @config.filter_excluded.uniq!
123
+ filters.each do |filter|
124
+ @config.filter_included.delete(filter) if @config.filter_included.include?(filter)
125
+ end
126
+ RubyJard::ControlFlow.dispatch(:list)
127
+ end
128
+
129
+ def handle_clear
130
+ @config.filter_excluded.clear
131
+ @config.filter_included.clear
132
+ RubyJard::ControlFlow.dispatch(:list)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -13,14 +13,22 @@ module RubyJard
13
13
  Usage: output
14
14
  BANNER
15
15
 
16
- def self.output_storage
17
- RubyJard::ScreenManager.instance.output_storage
16
+ def initialize(*args)
17
+ super(*args)
18
+ @session = (context[:session] || RubyJard::Session)
18
19
  end
19
20
 
20
21
  def process
21
- pry_instance.pager.open(force_open: true, pager_start_at_the_end: true) do |pager|
22
- self.class.output_storage.rewind
23
- pager.write self.class.output_storage.read_nonblock(2048) until self.class.output_storage.eof?
22
+ pry_instance.pager.open(
23
+ force_open: true,
24
+ pager_start_at_the_end: true,
25
+ prompt: 'Program output'
26
+ ) do |pager|
27
+ @session.output_buffer.each do |string|
28
+ string.each do |s|
29
+ pager.write(s)
30
+ end
31
+ end
24
32
  end
25
33
  end
26
34
  end
@@ -4,6 +4,7 @@ require 'ruby_jard/commands/jard/show_command'
4
4
  require 'ruby_jard/commands/jard/hide_command'
5
5
  require 'ruby_jard/commands/jard/color_scheme_command'
6
6
  require 'ruby_jard/commands/jard/output_command'
7
+ require 'ruby_jard/commands/jard/filter_command'
7
8
 
8
9
  module RubyJard
9
10
  module Commands
@@ -22,7 +23,8 @@ module RubyJard
22
23
  'show' => RubyJard::Commands::ShowCommand,
23
24
  'hide' => RubyJard::Commands::HideCommand,
24
25
  'color-scheme' => RubyJard::Commands::ColorSchemeCommand,
25
- 'output' => RubyJard::Commands::OutputCommand
26
+ 'output' => RubyJard::Commands::OutputCommand,
27
+ 'filter' => RubyJard::Commands::FilterCommand
26
28
  }.freeze
27
29
 
28
30
  def subcommands(cmd)
@@ -31,13 +31,17 @@ module RubyJard
31
31
  end
32
32
  end
33
33
 
34
- attr_accessor :color_scheme, :alias_to_debugger, :layout, :enabled_screens
34
+ attr_accessor :color_scheme, :alias_to_debugger, :layout, :enabled_screens,
35
+ :filter, :filter_included, :filter_excluded
35
36
 
36
37
  CONFIG_FILE_NAME = '.jardrc'
37
38
  DEFAULTS = [
38
39
  DEFAULT_COLOR_SCHEME = '256',
39
40
  DEFAULT_ALIAS_TO_DEBUGGER = false,
40
- DEFAULT_LAYOUT = nil # Pick layout automatically
41
+ DEFAULT_LAYOUT = nil, # Pick layout automatically
42
+ DEFAULT_FILTER = RubyJard::PathFilter::FILTER_APPLICATION,
43
+ DEFAULT_FILTER_INCLUDED = [].freeze,
44
+ DEFAULT_FILTER_EXCLUDED = [].freeze
41
45
  ].freeze
42
46
 
43
47
  def initialize
@@ -45,6 +49,9 @@ module RubyJard
45
49
  @alias_to_debugger = DEFAULT_ALIAS_TO_DEBUGGER
46
50
  @layout = DEFAULT_LAYOUT
47
51
  @enabled_screens = RubyJard::Screens.names
52
+ @filter = DEFAULT_FILTER
53
+ @filter_included = DEFAULT_FILTER_INCLUDED.dup
54
+ @filter_excluded = DEFAULT_FILTER_EXCLUDED.dup
48
55
  end
49
56
 
50
57
  def config
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Decorators
5
+ ##
6
+ # Decorate Array data structure, supports singleline and multiline form.
7
+ class ArrayDecorator
8
+ def initialize(generic_decorator)
9
+ @generic_decorator = generic_decorator
10
+ @attributes_decorator = RubyJard::Decorators::AttributesDecorator.new(generic_decorator)
11
+ end
12
+
13
+ def match?(variable)
14
+ RubyJard::Reflection.call_is_a?(variable, Array)
15
+ end
16
+
17
+ def decorate_singleline(variable, line_limit:, depth: 0)
18
+ spans = []
19
+ spans << RubyJard::Span.new(content: '[', styles: :text_primary)
20
+ spans += @attributes_decorator.inline_values(
21
+ variable.each_with_index, total: variable.length, line_limit: line_limit - 2, depth: depth + 1
22
+ )
23
+ spans << RubyJard::Span.new(content: ']', styles: :text_primary)
24
+
25
+ spans
26
+ end
27
+
28
+ def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
29
+ if variable.length > lines * 2
30
+ return do_decorate_multiline(variable, lines: lines, line_limit: line_limit, depth: depth)
31
+ end
32
+
33
+ singleline = decorate_singleline(variable, line_limit: first_line_limit, depth: depth)
34
+ if (singleline.map(&:content_length).sum < line_limit && same_type?(variable, lines)) || variable.length <= 1
35
+ [singleline]
36
+ else
37
+ do_decorate_multiline(variable, lines: lines, line_limit: line_limit, depth: depth)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def same_type?(variable, sample)
44
+ variable.first(sample).map { |item| RubyJard::Reflection.call_class(item) }.uniq.length <= 1
45
+ end
46
+
47
+ def do_decorate_multiline(variable, lines:, line_limit:, depth: 0)
48
+ spans = [[RubyJard::Span.new(content: '[', styles: :text_primary)]]
49
+
50
+ item_count = 0
51
+ variable.each_with_index do |value, index|
52
+ spans << @attributes_decorator.value(value, line_limit: line_limit, depth: depth + 1)
53
+
54
+ item_count += 1
55
+ break if index >= lines - 2
56
+ end
57
+
58
+ spans << last_line(variable.length, item_count)
59
+ end
60
+
61
+ def last_line(total, item_count)
62
+ if total > item_count
63
+ [
64
+ RubyJard::Span.new(
65
+ content: "▸ #{total - item_count} more...",
66
+ margin_left: 2, styles: :text_dim
67
+ ),
68
+ RubyJard::Span.new(
69
+ content: ']',
70
+ styles: :text_primary
71
+ )
72
+ ]
73
+ else
74
+ [RubyJard::Span.new(content: ']', styles: :text_primary)]
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end