ruby_jard 0.1.0 → 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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/workflows/documentation.yml +65 -0
  6. data/.github/workflows/rspec.yml +96 -0
  7. data/.gitignore +1 -0
  8. data/.rubocop.yml +90 -2
  9. data/CHANGELOG.md +112 -0
  10. data/Gemfile +14 -4
  11. data/README.md +95 -3
  12. data/benchmark/path_filter_bench.rb +58 -0
  13. data/bin/console +1 -2
  14. data/lib/ruby_jard.rb +68 -32
  15. data/lib/ruby_jard/box_drawer.rb +175 -0
  16. data/lib/ruby_jard/color_scheme.rb +28 -0
  17. data/lib/ruby_jard/color_schemes.rb +54 -0
  18. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +50 -0
  19. data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +50 -0
  20. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +49 -0
  21. data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +48 -0
  22. data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +47 -0
  23. data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +49 -0
  24. data/lib/ruby_jard/column.rb +26 -0
  25. data/lib/ruby_jard/commands/color_helpers.rb +32 -0
  26. data/lib/ruby_jard/commands/continue_command.rb +4 -9
  27. data/lib/ruby_jard/commands/down_command.rb +9 -8
  28. data/lib/ruby_jard/commands/exit_command.rb +27 -0
  29. data/lib/ruby_jard/commands/frame_command.rb +13 -11
  30. data/lib/ruby_jard/commands/jard/color_scheme_command.rb +74 -0
  31. data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
  32. data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
  33. data/lib/ruby_jard/commands/jard/output_command.rb +36 -0
  34. data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
  35. data/lib/ruby_jard/commands/jard_command.rb +52 -0
  36. data/lib/ruby_jard/commands/list_command.rb +31 -0
  37. data/lib/ruby_jard/commands/next_command.rb +11 -8
  38. data/lib/ruby_jard/commands/step_command.rb +11 -8
  39. data/lib/ruby_jard/commands/step_out_command.rb +34 -0
  40. data/lib/ruby_jard/commands/up_command.rb +10 -8
  41. data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
  42. data/lib/ruby_jard/config.rb +61 -0
  43. data/lib/ruby_jard/console.rb +158 -0
  44. data/lib/ruby_jard/control_flow.rb +73 -0
  45. data/lib/ruby_jard/decorators/array_decorator.rb +79 -0
  46. data/lib/ruby_jard/decorators/attributes_decorator.rb +172 -0
  47. data/lib/ruby_jard/decorators/color_decorator.rb +80 -0
  48. data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
  49. data/lib/ruby_jard/decorators/inspection_decorator.rb +109 -0
  50. data/lib/ruby_jard/decorators/loc_decorator.rb +108 -119
  51. data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
  52. data/lib/ruby_jard/decorators/path_decorator.rb +56 -60
  53. data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
  54. data/lib/ruby_jard/decorators/source_decorator.rb +3 -1
  55. data/lib/ruby_jard/decorators/string_decorator.rb +41 -0
  56. data/lib/ruby_jard/decorators/struct_decorator.rb +79 -0
  57. data/lib/ruby_jard/frame.rb +68 -0
  58. data/lib/ruby_jard/key_binding.rb +14 -0
  59. data/lib/ruby_jard/key_bindings.rb +96 -0
  60. data/lib/ruby_jard/keys.rb +48 -0
  61. data/lib/ruby_jard/layout.rb +17 -88
  62. data/lib/ruby_jard/layout_calculator.rb +168 -0
  63. data/lib/ruby_jard/layout_picker.rb +34 -0
  64. data/lib/ruby_jard/layouts.rb +52 -0
  65. data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +32 -0
  66. data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
  67. data/lib/ruby_jard/layouts/tiny_layout.rb +29 -0
  68. data/lib/ruby_jard/layouts/wide_layout.rb +50 -0
  69. data/lib/ruby_jard/pager.rb +112 -0
  70. data/lib/ruby_jard/path_classifier.rb +133 -0
  71. data/lib/ruby_jard/path_filter.rb +125 -0
  72. data/lib/ruby_jard/reflection.rb +97 -0
  73. data/lib/ruby_jard/repl_processor.rb +151 -89
  74. data/lib/ruby_jard/repl_proxy.rb +337 -0
  75. data/lib/ruby_jard/row.rb +31 -0
  76. data/lib/ruby_jard/row_renderer.rb +119 -0
  77. data/lib/ruby_jard/screen.rb +14 -41
  78. data/lib/ruby_jard/screen_adjuster.rb +104 -0
  79. data/lib/ruby_jard/screen_drawer.rb +25 -0
  80. data/lib/ruby_jard/screen_manager.rb +167 -82
  81. data/lib/ruby_jard/screen_renderer.rb +152 -0
  82. data/lib/ruby_jard/screens.rb +31 -12
  83. data/lib/ruby_jard/screens/backtrace_screen.rb +118 -116
  84. data/lib/ruby_jard/screens/menu_screen.rb +73 -45
  85. data/lib/ruby_jard/screens/source_screen.rb +86 -106
  86. data/lib/ruby_jard/screens/threads_screen.rb +103 -78
  87. data/lib/ruby_jard/screens/variables_screen.rb +224 -142
  88. data/lib/ruby_jard/session.rb +151 -16
  89. data/lib/ruby_jard/span.rb +23 -0
  90. data/lib/ruby_jard/templates/layout_template.rb +35 -0
  91. data/lib/ruby_jard/templates/screen_template.rb +34 -0
  92. data/lib/ruby_jard/thread_info.rb +69 -0
  93. data/lib/ruby_jard/version.rb +1 -1
  94. data/ruby_jard.gemspec +7 -8
  95. metadata +84 -50
  96. data/.travis.yml +0 -6
  97. data/lib/ruby_jard/commands/finish_command.rb +0 -31
  98. data/lib/ruby_jard/decorators/text_decorator.rb +0 -61
  99. data/lib/ruby_jard/layout_template.rb +0 -101
  100. data/lib/ruby_jard/screens/breakpoints_screen.rb +0 -23
  101. data/lib/ruby_jard/screens/empty_screen.rb +0 -13
  102. data/lib/ruby_jard/screens/expressions_sreen.rb +0 -22
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby_jard/decorators/array_decorator'
4
+ require 'ruby_jard/decorators/string_decorator'
5
+ require 'ruby_jard/decorators/hash_decorator'
6
+ require 'ruby_jard/decorators/struct_decorator'
7
+ require 'ruby_jard/decorators/object_decorator'
8
+ require 'ruby_jard/decorators/attributes_decorator'
9
+ require 'ruby_jard/decorators/rails_decorator'
10
+
11
+ module RubyJard
12
+ module Decorators
13
+ ##
14
+ # Generate beauty inspection of a particular variable.
15
+ # The inspection doesn't aim to become a better version of PP. Instead,
16
+ # it's scope is to generate an overview of a variable within a limited
17
+ # space. So, it only keeps useful information, and tries to reach the
18
+ # very shallow layers of a nested data structure.
19
+ # This class is inspired by Ruby's PP:
20
+ # https://github.com/ruby/ruby/blob/master/lib/pp.rb
21
+ class InspectionDecorator
22
+ PRIMITIVE_TYPES = {
23
+ # Intertal classes for those values may differ between Ruby versions
24
+ # For example: Bignum is renamed to Integer
25
+ # So, it's safer to use discrete value's class as the key for this mapping.
26
+ true.class.name => :literal,
27
+ false.class.name => :literal,
28
+ 1.class.name => :literal,
29
+ 1.1.class.name => :literal,
30
+ 1.to_r.class.name => :literal, # Rational: (1/1)
31
+ 1.to_c.class.name => :literal, # Complex: (1+0i)
32
+ :sym.class.name => :literal,
33
+ //.class.name => :literal, # TODO: create a new class to handle range
34
+ (0..0).class.name => :literal,
35
+ nil.class.name => :text_dim,
36
+ Class.class.name => :text_primary, # Sorry, I lied, Class will never change
37
+ Proc.name => :text_primary # TODO: create a new class to handle proc.
38
+ }.freeze
39
+
40
+ def initialize
41
+ @klass_decorators = [
42
+ @array_decorator = ArrayDecorator.new(self),
43
+ @string_decorator = StringDecorator.new(self),
44
+ @hash_decorator = HashDecorator.new(self),
45
+ @struct_decorator = StructDecorator.new(self),
46
+ @rails_decorator = RailsDecorator.new(self)
47
+ ]
48
+ @object_decorator = ObjectDecorator.new(self)
49
+ end
50
+
51
+ def decorate_singleline(variable, line_limit:, depth: 0)
52
+ if primitive?(variable)
53
+ return decorate_primitive(variable, line_limit)
54
+ end
55
+
56
+ @klass_decorators.each do |klass_decorator|
57
+ next unless klass_decorator.match?(variable)
58
+
59
+ spans = klass_decorator.decorate_singleline(variable, line_limit: line_limit, depth: depth)
60
+ return spans unless spans.nil?
61
+ end
62
+ @object_decorator.decorate_singleline(variable, line_limit: line_limit, depth: depth)
63
+ end
64
+
65
+ def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
66
+ if primitive?(variable)
67
+ return decorate_primitive(variable, first_line_limit)
68
+ end
69
+
70
+ @klass_decorators.each do |klass_decorator|
71
+ next unless klass_decorator.match?(variable)
72
+
73
+ spans = klass_decorator.decorate_multiline(
74
+ variable,
75
+ first_line_limit: first_line_limit,
76
+ lines: lines,
77
+ line_limit: line_limit,
78
+ depth: depth
79
+ )
80
+ return spans unless spans.nil?
81
+ end
82
+ @object_decorator.decorate_multiline(
83
+ variable,
84
+ first_line_limit: first_line_limit,
85
+ lines: lines,
86
+ line_limit: line_limit,
87
+ depth: depth
88
+ )
89
+ end
90
+
91
+ private
92
+
93
+ def primitive?(variable)
94
+ !PRIMITIVE_TYPES[RubyJard::Reflection.call_class(variable).name].nil?
95
+ end
96
+
97
+ def decorate_primitive(variable, line_limit)
98
+ inspection = variable.inspect
99
+ inspection = inspection[0..line_limit - 2] + '…' if inspection.length >= line_limit
100
+ [
101
+ RubyJard::Span.new(
102
+ content: inspection,
103
+ styles: PRIMITIVE_TYPES[RubyJard::Reflection.call_class(variable).name]
104
+ )
105
+ ]
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,135 +1,126 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'coderay'
4
+
3
5
  module RubyJard
4
6
  module Decorators
5
7
  ##
6
8
  # Decorate a line of code fetched from the source file.
7
9
  # The line is tokenized, and feed into JardEncoder to append color (with
8
- # Pastel).
10
+ # Span).
9
11
  class LocDecorator
10
- attr_reader :loc, :tokens
11
-
12
- def initialize(color_decorator, loc, highlighted)
13
- @loc = loc
14
- @highlighted = highlighted
15
- @encoder = JardLocEncoder.new(
16
- color_decorator: color_decorator,
17
- highlighted: highlighted
18
- )
12
+ def initialize
13
+ @encoder = JardLocEncoder.new
14
+ end
19
15
 
20
- decorate
16
+ def decorate(loc, file = nil)
17
+ tokens = CodeRay.scan(loc, extension(file))
18
+ spans = @encoder.encode_tokens(tokens)
19
+ [spans, tokens]
21
20
  end
22
21
 
23
- def decorate
24
- @tokens = CodeRay.scan(@loc, :ruby)
25
- @loc = @encoder.encode_tokens(tokens)
22
+ private
23
+
24
+ def extension(file)
25
+ # TODO: A map constant is better
26
+ if file =~ /.*\.erb$/
27
+ :erb
28
+ elsif file =~ /.*\.haml$/
29
+ :haml
30
+ else
31
+ :ruby
32
+ end
26
33
  end
27
34
 
28
35
  # A shameless copy from https://github.com/rubychan/coderay/blob/master/lib/coderay/encoders/terminal.rb
29
36
  class JardLocEncoder < CodeRay::Encoders::Encoder
30
- TOKEN_COLORS = {
31
- debug: [:white, :on_blue],
32
- annotation: [:blue],
33
- attribute_name: [:blue],
34
- attribute_value: [:blue],
37
+ DEFAULT_STYLE = :normal_token
38
+ TOKEN_STYLES = {
39
+ annotation: :keyword,
40
+ attribute_name: :keyword,
41
+ attribute_value: :keyword,
35
42
  binary: {
36
- self: [:blue],
37
- char: [:blue],
38
- delimiter: [:blue]
43
+ self: :keyword,
44
+ char: :keyword,
45
+ delimiter: :keyword
39
46
  },
40
47
  char: {
41
- self: [:blue],
42
- delimiter: [:blue]
48
+ self: :keyword,
49
+ delimiter: :keyword
43
50
  },
44
- class: [:underline, :green],
45
- class_variable: [:green],
46
- color: [:green],
51
+ class: :constant,
52
+ class_variable: :constant,
53
+ color: :constant,
47
54
  comment: {
48
- self: [:white],
49
- char: [:white],
50
- delimiter: [:white]
55
+ self: :comment,
56
+ char: :comment,
57
+ delimiter: :comment
51
58
  },
52
- constant: [:underline, :green],
53
- decorator: [:blue],
54
- definition: [:blue],
55
- directive: [:blue],
56
- docstring: [:blue],
57
- doctype: [:blue],
58
- done: [:blue],
59
- entity: [:blue],
60
- error: [:white, :on_red],
61
- exception: [:blue],
62
- float: [:blue],
63
- function: [:green],
64
- method: [:green],
65
- global_variable: [:green],
66
- hex: [:blue],
67
- id: [:blue],
68
- include: [:blue],
69
- integer: [:blue],
70
- imaginary: [:blue],
71
- important: [:blue],
59
+ constant: :constant,
60
+ decorator: :keyword,
61
+ definition: :keyword,
62
+ directive: :keyword,
63
+ docstring: :keyword,
64
+ doctype: :keyword,
65
+ done: :keyword,
66
+ entity: :keyword,
67
+ error: :constant,
68
+ exception: :keyword,
69
+ float: :literal,
70
+ function: :constant,
71
+ method: :method,
72
+ global_variable: :constant,
73
+ hex: :keyword,
74
+ id: :keyword,
75
+ include: :keyword,
76
+ integer: :literal,
77
+ imaginary: :keyword,
78
+ important: :keyword,
72
79
  key: {
73
- self: [:blue],
74
- char: [:blue],
75
- delimiter: [:blue]
80
+ self: :literal,
81
+ char: :literal,
82
+ delimiter: :literal
76
83
  },
77
- label: [:blue],
78
- local_variable: [:blue],
79
- namespace: [:blue],
80
- octal: [:blue],
81
- predefined: [:blue],
82
- predefined_constant: [:blue],
83
- predefined_type: [:green],
84
- preprocessor: [:blue],
85
- pseudo_class: [:blue],
84
+ label: :literal,
85
+ local_variable: :keyword,
86
+ namespace: :keyword,
87
+ octal: :keyword,
88
+ predefined: :keyword,
89
+ predefined_constant: :keyword,
90
+ predefined_type: :constant,
91
+ preprocessor: :keyword,
92
+ pseudo_class: :keyword,
86
93
  regexp: {
87
- self: [:blue],
88
- delimiter: [:blue],
89
- modifier: [:blue],
90
- char: [:blue]
94
+ self: :keyword,
95
+ delimiter: :keyword,
96
+ modifier: :keyword,
97
+ char: :keyword
91
98
  },
92
- reserved: [:blue],
93
- keyword: [:blue],
99
+ reserved: :keyword,
100
+ keyword: :keyword,
94
101
  shell: {
95
- self: [:blue],
96
- char: [:blue],
97
- delimiter: [:blue],
98
- escape: [:blue]
102
+ self: :keyword,
103
+ char: :keyword,
104
+ delimiter: :keyword,
105
+ escape: :keyword
99
106
  },
100
107
  string: {
101
- self: [:blue],
102
- modifier: [:blue],
103
- char: [:blue],
104
- delimiter: [:blue],
105
- escape: [:blue]
108
+ self: :string,
109
+ modifier: :string,
110
+ char: :string,
111
+ delimiter: :string,
112
+ escape: :string,
113
+ content: :string
106
114
  },
107
115
  symbol: {
108
- self: [:blue],
109
- delimiter: [:blue]
110
- },
111
- tag: [:green],
112
- type: [:blue],
113
- value: [:blue],
114
- variable: [:blue],
115
- insert: {
116
- self: [:on_green],
117
- insert: [:green, :on_green],
118
- eyecatcher: [:italic]
116
+ self: :literal,
117
+ delimiter: :literal
119
118
  },
120
- delete: {
121
- self: [:on_red],
122
- delete: [:blue, :on_red],
123
- eyecatcher: [:italic]
124
- },
125
- change: {
126
- self: [:on_blue],
127
- change: [:white, :on_blue]
128
- },
129
- head: {
130
- self: [:on_red],
131
- filename: [:white, :on_red]
132
- }
119
+ tag: :constant,
120
+ type: :keyword,
121
+ value: :keyword,
122
+ variable: :keyword,
123
+ instance_variable: :instance_variable
133
124
  }.freeze
134
125
 
135
126
  protected
@@ -137,9 +128,8 @@ module RubyJard
137
128
  def setup(options)
138
129
  super
139
130
  @opened = []
140
- @color_scopes = [TOKEN_COLORS]
141
- @color_decorator = options[:color_decorator]
142
- @highlighted = options[:highlighted]
131
+ @color_scopes = [TOKEN_STYLES]
132
+ @out = []
143
133
  end
144
134
 
145
135
  public
@@ -147,19 +137,26 @@ module RubyJard
147
137
  def text_token(text, kind)
148
138
  color = @color_scopes.last[kind]
149
139
  text.gsub!("\n", '')
150
- if color
151
- color = color[:self] if color.is_a? Hash
152
- @out << @color_decorator.decorate(text, *compose_color(color))
153
- else
154
- @out << @color_decorator.decorate(text, *compose_color([]))
155
- end
140
+ style =
141
+ if !color
142
+ DEFAULT_STYLE
143
+ elsif color.is_a? Hash
144
+ color[:self]
145
+ else
146
+ color
147
+ end
148
+ @out << Span.new(
149
+ content: text,
150
+ content_length: text.length,
151
+ styles: style.to_sym
152
+ )
156
153
  end
157
154
 
158
155
  def begin_group(kind)
159
156
  @opened << kind
160
157
  open_token(kind)
161
158
  end
162
- alias begin_line begin_group
159
+ alias_method :begin_line, :begin_group
163
160
 
164
161
  def end_group(_kind)
165
162
  return unless @opened.pop
@@ -186,14 +183,6 @@ module RubyJard
186
183
  @color_scopes.last
187
184
  end
188
185
  end
189
-
190
- def compose_color(color)
191
- if @highlighted
192
- [:clear] + color
193
- else
194
- [:dim] + color
195
- end
196
- end
197
186
  end
198
187
  end
199
188
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Decorators
5
+ ##
6
+ # Default decorator for non-primitive data structure. It is aimed to replace default `inspect`.
7
+ # If a variable re-implement `#inspect`, it hornors this decision, but still try to
8
+ # parse the result.
9
+ # Otherwise, it use `Kernel#to_s`, and try to push instance variables into the result.
10
+ class ObjectDecorator
11
+ DEFAULT_INSPECTION_PATTERN = /#<(.*:0x[0-9a-z]+)(.*)>/i.freeze
12
+
13
+ def initialize(generic_decorator)
14
+ @generic_decorator = generic_decorator
15
+ @attributes_decorator = RubyJard::Decorators::AttributesDecorator.new(generic_decorator)
16
+ end
17
+
18
+ def decorate_singleline(variable, line_limit:, depth: 0)
19
+ if native_inspect?(variable)
20
+ decorate_native_inspection(variable, line_limit: line_limit, depth: depth)
21
+ else
22
+ decorate_custom_inspection(variable, line_limit: line_limit)
23
+ end
24
+ end
25
+
26
+ def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
27
+ singleline = decorate_singleline(variable, line_limit: first_line_limit)
28
+ return [singleline] if singleline.map(&:content_length).sum < line_limit
29
+
30
+ spans = [decorate_native_inspection(variable, line_limit: first_line_limit, with_children: false)]
31
+
32
+ item_count = 0
33
+ instance_variables = RubyJard::Reflection.call_instance_variables(variable)
34
+ instance_variables.each do |key|
35
+ spans << @attributes_decorator.pair(
36
+ key, RubyJard::Reflection.call_instance_variable_get(variable, key),
37
+ line_limit: line_limit, process_key: false, depth: depth + 1
38
+ )
39
+
40
+ item_count += 1
41
+ break if item_count >= lines - 2
42
+ end
43
+
44
+ if instance_variables.length > item_count
45
+ spans << [
46
+ RubyJard::Span.new(
47
+ content: "▸ #{instance_variables.length - item_count} more...",
48
+ margin_left: 2, styles: :text_dim
49
+ )
50
+ ]
51
+ end
52
+
53
+ spans
54
+ end
55
+
56
+ private
57
+
58
+ def native_inspect?(variable)
59
+ return true unless RubyJard::Reflection.call_respond_to?(variable, :inspect)
60
+
61
+ RubyJard::Reflection.bind_call(::Kernel, :method, variable, :inspect).owner == ::Kernel
62
+ end
63
+
64
+ def call_inspect(variable)
65
+ variable.inspect
66
+ rescue StandardError
67
+ RubyJard::Reflection.call_to_s(variable)
68
+ end
69
+
70
+ def decorate_native_inspection(variable, line_limit:, depth: 0, with_children: true)
71
+ raw_inspection = RubyJard::Reflection.call_to_s(variable)
72
+ match = raw_inspection.match(DEFAULT_INSPECTION_PATTERN)
73
+
74
+ if match
75
+ instance_variables = RubyJard::Reflection.call_instance_variables(variable)
76
+ spans = [
77
+ RubyJard::Span.new(content: '#<', styles: :text_primary),
78
+ RubyJard::Span.new(content: match[1], styles: :text_primary)
79
+ ]
80
+ if with_children && !instance_variables.empty?
81
+ spans << RubyJard::Span.new(content: ' ', styles: :text_primary)
82
+ spans += @attributes_decorator.inline_pairs(
83
+ instance_variables.each_with_index, total: instance_variables.length,
84
+ line_limit: line_limit - spans.map(&:content_length).sum - 1,
85
+ depth: depth + 1, process_key: false,
86
+ value_proc: ->(key) { RubyJard::Reflection.call_instance_variable_get(variable, key) }
87
+ )
88
+ end
89
+ spans << RubyJard::Span.new(content: '>', styles: :text_primary)
90
+ spans
91
+ elsif raw_inspection.length <= line_limit
92
+ [RubyJard::Span.new(content: raw_inspection[0..line_limit], styles: :text_primary)]
93
+ else
94
+ [RubyJard::Span.new(content: raw_inspection[0..line_limit - 3] + '…>', styles: :text_primary)]
95
+ end
96
+ end
97
+
98
+ def decorate_custom_inspection(variable, line_limit:)
99
+ raw_inspection = call_inspect(variable)
100
+ match = raw_inspection.match(DEFAULT_INSPECTION_PATTERN)
101
+ if match
102
+ detail =
103
+ if match[2].length < line_limit - match[1].length - 3
104
+ match[2]
105
+ else
106
+ match[2][0..line_limit - match[1].length - 4] + '…'
107
+ end
108
+ [
109
+ RubyJard::Span.new(content: '#<', styles: :text_primary),
110
+ RubyJard::Span.new(content: match[1], styles: :text_primary),
111
+ RubyJard::Span.new(content: detail, styles: :text_dim),
112
+ RubyJard::Span.new(content: '>', styles: :text_primary)
113
+ ]
114
+ elsif raw_inspection.length <= line_limit
115
+ [RubyJard::Span.new(content: raw_inspection[0..line_limit], styles: :text_primary)]
116
+ else
117
+ [RubyJard::Span.new(content: raw_inspection[0..line_limit - 3] + '…>', styles: :text_primary)]
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end