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
@@ -4,63 +4,105 @@ module RubyJard
4
4
  module Screens
5
5
  class ThreadsScreen < RubyJard::Screen
6
6
  def title
7
- "Threads (#{RubyJard.current_session.contexts.length})"
7
+ ['Threads', "#{RubyJard.current_session.contexts.length} threads"]
8
8
  end
9
9
 
10
- def data_size
11
- [@height, RubyJard.current_session.contexts.length].min
10
+ def build
11
+ contexts = RubyJard.current_session.contexts.filter { |c| c.thread.alive? }
12
+ contexts = sort_contexts(contexts)
13
+ @rows = contexts.map do |context|
14
+ RubyJard::Row.new(
15
+ line_limit: 2,
16
+ columns: [
17
+ RubyJard::Column.new(
18
+ spans: [
19
+ span_mark(context),
20
+ span_thread_id(context)
21
+ ]
22
+ ),
23
+ RubyJard::Column.new(
24
+ spans: [
25
+ span_thread_status(context)
26
+ ]
27
+ ),
28
+ RubyJard::Column.new(
29
+ spans: [
30
+ span_thread_name(context),
31
+ span_thread_location(context)
32
+ ]
33
+ )
34
+ ]
35
+ )
36
+ end
37
+ @selected = contexts.index { |c| current_thread?(c) }
12
38
  end
13
39
 
14
- def data_window
15
- return @data_window if defined?(@data_window)
40
+ private
16
41
 
17
- contexts = RubyJard.current_session.contexts.filter { |c| c.thread.alive? }
18
- @data_window ||= sort_contexts(contexts).first(data_size)
42
+ def span_mark(context)
43
+ RubyJard::Span.new(
44
+ margin_right: 1,
45
+ content: '•',
46
+ styles: thread_status_style(context.thread)
47
+ )
19
48
  end
20
49
 
21
- def span_mark(context, _index)
22
- [
23
- current_thread?(context) ? '→' : ' ',
24
- [:bright_yellow, current_thread?(context) ? :bold : nil]
25
- ]
50
+ def span_thread_id(context)
51
+ RubyJard::Span.new(
52
+ content: "Thread #{context.thread.object_id}",
53
+ styles: :thread_id
54
+ )
26
55
  end
27
56
 
28
- def span_thread_id(context, _index)
29
- [
30
- context.thread.object_id.to_s,
31
- [:green, current_thread?(context) ? :bold : nil]
32
- ]
57
+ def span_thread_status(context)
58
+ RubyJard::Span.new(
59
+ content: "(#{context.thread.status})",
60
+ styles: thread_status_style(context.thread)
61
+ )
33
62
  end
34
63
 
35
- def span_thread_status(context, _index)
36
- status_color =
37
- if context.suspended?
38
- :red
39
- elsif context.ignored?
40
- :white
41
- elsif context.thread.status == 'run'
42
- :green
64
+ def span_thread_name(context)
65
+ RubyJard::Span.new(
66
+ margin_right: 1,
67
+ content: context.thread.name.nil? ? 'untitled' : context.thread.name,
68
+ styles: :thread_name
69
+ )
70
+ end
71
+
72
+ def span_thread_location(context)
73
+ return unknown_thread_location if
74
+ context.thread.backtrace_locations.nil? ||
75
+ RubyJard.current_session.backtrace[0].nil?
76
+
77
+ last_backtrace =
78
+ if current_thread?(context)
79
+ RubyJard.current_session.backtrace[0].first
43
80
  else
44
- :white
81
+ context.thread.backtrace_locations[1]
45
82
  end
46
- [
47
- "(#{context.thread.status})",
48
- [status_color, current_thread?(context) ? :bold : nil]
49
- ]
50
- end
51
83
 
52
- def span_thread_name(context, _index)
53
- if context.thread.name.nil?
54
- last_backtrace = context.thread.backtrace_locations[1]
55
- location = decorate_path(last_backtrace.path, last_backtrace.lineno)
56
- ["#{location.path}:#{location.lineno}", current_thread?(context) ? [:bright_white, :bold] : :white]
84
+ return unknown_thread_location if last_backtrace.nil?
85
+
86
+ decorated_path = decorate_path(last_backtrace.path, last_backtrace.lineno)
87
+ if decorated_path.gem?
88
+ RubyJard::Span.new(
89
+ content: "in #{decorated_path.gem} (#{decorated_path.gem_version})",
90
+ styles: :thread_location
91
+ )
57
92
  else
58
- name = context.thread.name.to_s
59
- [name, current_thread?(context) ? [:bright_white, :bold] : :white]
93
+ RubyJard::Span.new(
94
+ content: "at #{decorated_path.path}:#{decorated_path.lineno}",
95
+ styles: :thread_location
96
+ )
60
97
  end
61
98
  end
62
99
 
63
- private
100
+ def unknown_thread_location
101
+ RubyJard::Span.new(
102
+ content: 'at ???',
103
+ styles: :thread_location
104
+ )
105
+ end
64
106
 
65
107
  def sort_contexts(contexts)
66
108
  # Sort: current context first
@@ -95,6 +137,16 @@ module RubyJard
95
137
  def decorate_path(path, lineno)
96
138
  RubyJard::Decorators::PathDecorator.new(path, lineno)
97
139
  end
140
+
141
+ def thread_status_style(thread)
142
+ if thread.status == 'run'
143
+ :thread_status_run
144
+ elsif thread.status == 'sleep'
145
+ :thread_status_sleep
146
+ else
147
+ :thread_status_other
148
+ end
149
+ end
98
150
  end
99
151
  end
100
152
  end
@@ -24,9 +24,9 @@ module RubyJard
24
24
  DEFAULT_TYPE_SYMBOL = :var
25
25
 
26
26
  KINDS = [
27
- KIND_LOC = :loc,
28
- KIND_INS = :ins,
29
- KIND_CON = :con
27
+ KIND_LOC = :local_variable,
28
+ KIND_INS = :instance_variable,
29
+ KIND_CON = :constant
30
30
  ].freeze
31
31
 
32
32
  KIND_PRIORITIES = {
@@ -35,12 +35,6 @@ module RubyJard
35
35
  KIND_CON => 3
36
36
  }.freeze
37
37
 
38
- KIND_COLORS = {
39
- KIND_LOC => :bright_blue,
40
- KIND_INS => :bright_blue,
41
- KIND_CON => :green
42
- }.freeze
43
-
44
38
  INLINE_TOKEN_KIND_MAPS = {
45
39
  KIND_LOC => :ident,
46
40
  KIND_INS => :instance_variable,
@@ -52,65 +46,82 @@ module RubyJard
52
46
  'Variables'
53
47
  end
54
48
 
55
- def data_size
56
- @height
57
- end
58
-
59
- def data_window
60
- return [] if current_frame.nil?
61
- return @data_window if defined?(@data_window)
62
-
49
+ def build
63
50
  variables = fetch_local_variables + fetch_instance_variables + fetch_constants
64
- # Each row is an array of [kind, name, value]
65
- @data_window = sort_variables(variables).first(data_size)
51
+ variables = sort_variables(variables)
52
+ @rows = variables.map do |variable|
53
+ RubyJard::Row.new(
54
+ line_limit: 3,
55
+ columns: [
56
+ RubyJard::Column.new(
57
+ spans: [
58
+ span_inline(variable)
59
+ ]
60
+ ),
61
+ RubyJard::Column.new(
62
+ spans: [
63
+ span_name(variable),
64
+ span_size(variable),
65
+ RubyJard::Span.new(margin_right: 1, content: '=', styles: :variable_assignment),
66
+ span_inspection(variable)
67
+ ]
68
+ )
69
+ ]
70
+ )
71
+ end
72
+ @selected = 0
66
73
  end
67
74
 
68
- def span_inline(data_row, _index)
69
- if inline?(data_row[0], data_row[1])
70
- ['•', [:bright_yellow, :bold]]
75
+ def span_inline(variable)
76
+ if inline?(variable[0], variable[1])
77
+ RubyJard::Span.new(
78
+ content: '•',
79
+ styles: :variable_mark_inline
80
+ )
71
81
  else
72
- [' ']
82
+ RubyJard::Span.new(
83
+ content: ' ',
84
+ styles: :variable_mark
85
+ )
73
86
  end
74
87
  end
75
88
 
76
- def span_type(data_row, _index)
77
- type_name = TYPE_SYMBOLS[data_row[2].class] || DEFAULT_TYPE_SYMBOL
78
- [type_name.to_s, :white]
79
- end
80
-
81
- def span_name(data_row, _index)
82
- [
83
- data_row[1].to_s,
84
- [
85
- KIND_COLORS[data_row[0]] || :bright_white,
86
- inline?(data_row[0], data_row[1]) ? :bold : nil
87
- ]
88
- ]
89
- end
90
-
91
- def span_indicator(_data_row, _index)
92
- ['=', [:bright_white]]
89
+ def span_name(variable)
90
+ RubyJard::Span.new(
91
+ margin_right: 1,
92
+ content: variable[1].to_s,
93
+ styles: variable[0].to_sym
94
+ )
93
95
  end
94
96
 
95
- def span_size(data_row, _index)
96
- value = data_row[2]
97
- if value.is_a?(Array) && !value.empty?
98
- ["(size:#{value.length})", :white]
99
- elsif value.is_a?(String) && value.length > 20
100
- ["(size:#{value.length})", :white]
101
- elsif value.is_a?(Hash) && !value.empty?
102
- ["(size:#{value.length})", :white]
103
- end
97
+ def span_size(variable)
98
+ value = variable[2]
99
+ size_label =
100
+ if value.is_a?(Array) && !value.empty?
101
+ "(len:#{value.length})"
102
+ elsif value.is_a?(String) && value.length > 20
103
+ "(len:#{value.length})"
104
+ elsif value.is_a?(Hash) && !value.empty?
105
+ "(size:#{value.length})"
106
+ end
107
+ RubyJard::Span.new(
108
+ margin_right: 1,
109
+ content: size_label,
110
+ styles: :variable_size
111
+ )
104
112
  end
105
113
 
106
- def span_inspection(data_row, _index)
114
+ def span_inspection(variable)
107
115
  # Hard limit: screen area
108
- inspection = data_row[2].inspect[0..@height * @width]
116
+ inspection = variable[2].inspect[0..@layout.height * @layout.width]
109
117
  # TODO: This is just a workable. Should write a decorator to inspect objects accurately
110
118
  ["\n", "\r", "\r\n"].each do |esc|
111
119
  inspection.gsub!(esc, esc.inspect)
112
120
  end
113
- [inspection, :dim, :white]
121
+ RubyJard::Span.new(
122
+ content: inspection,
123
+ styles: :variable_inspection
124
+ )
114
125
  end
115
126
 
116
127
  private
@@ -169,6 +180,8 @@ module RubyJard
169
180
 
170
181
  constants = constant_source.constants.select { |v| v.to_s.upcase == v.to_s }
171
182
  constants.map do |variable|
183
+ next if %w[NIL TRUE FALSE].include?(variable.to_s)
184
+
172
185
  [KIND_CON, variable, constant_source.const_get(variable)]
173
186
  rescue NameError
174
187
  nil
@@ -209,13 +222,13 @@ module RubyJard
209
222
  current_file = RubyJard.current_session.frame.file
210
223
  current_line = RubyJard.current_session.frame.line
211
224
  source_decorator = RubyJard::Decorators::SourceDecorator.new(current_file, current_line, 1)
212
- loc_decorator = RubyJard::Decorators::LocDecorator.new(
213
- current_file,
214
- source_decorator.codes[current_line - source_decorator.window_start]
225
+ _spans, tokens = loc_decorator.decorate(
226
+ source_decorator.codes[current_line - source_decorator.window_start],
227
+ current_file
215
228
  )
216
229
 
217
230
  @inline_tokens = {}
218
- loc_decorator.tokens.each_slice(2) do |token, kind|
231
+ tokens.each_slice(2) do |token, kind|
219
232
  next unless INLINE_TOKEN_KINDS.include?(kind)
220
233
 
221
234
  @inline_tokens[kind] ||= []
@@ -224,6 +237,9 @@ module RubyJard
224
237
 
225
238
  @inline_tokens
226
239
  end
240
+ def loc_decorator
241
+ @loc_decorator ||= RubyJard::Decorators::LocDecorator.new
242
+ end
227
243
  end
228
244
  end
229
245
  end
@@ -27,6 +27,22 @@ module RubyJard
27
27
  def start
28
28
  return if started?
29
29
 
30
+ ##
31
+ # Globally configure Byebug. Byebug doesn't allow configuration by instance.
32
+ # So, I have no choice.
33
+ # TODO: Byebug autoloaded configuration may override those values.
34
+ Byebug::Setting[:autolist] = false
35
+ Byebug::Setting[:autoirb] = false
36
+ Byebug::Setting[:autopry] = false
37
+ Byebug::Context.processor = RubyJard::ReplProcessor
38
+ # Exclude all files in Ruby Jard source code from the stacktrace.
39
+ Byebug::Context.ignored_files = Byebug::Context.all_files + Dir.glob(
40
+ File.join(
41
+ File.expand_path(__dir__, '../lib'),
42
+ '**',
43
+ '*.rb'
44
+ )
45
+ )
30
46
  @started = true
31
47
  end
32
48
 
@@ -4,14 +4,16 @@ module RubyJard
4
4
  class Span
5
5
  extend Forwardable
6
6
 
7
- attr_accessor :span_template, :content, :content_length, :styles
7
+ attr_accessor :content, :content_length, :styles
8
8
 
9
- def_delegators :@span_template, :margin_left, :margin_right, :word_wrap, :ellipsis
9
+ def initialize(content: '', content_length: nil, margin_left: 0, margin_right: 0, styles: [])
10
+ if !content.nil? && !content.empty?
11
+ content = ' ' * margin_left + content if margin_left > 0
12
+ content += ' ' * margin_right if margin_right > 0
13
+ end
10
14
 
11
- def initialize(span_template:, content: '', content_length: 0, styles: [])
12
- @span_template = span_template
13
- @content = content
14
- @content_length = content_length
15
+ @content = content.to_s
16
+ @content_length = content_length || @content.length
15
17
  @styles = styles
16
18
  end
17
19
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Semantic versionn
4
4
  module RubyJard
5
- VERSION = '0.2.0'
5
+ VERSION = '0.2.1'
6
6
  end
@@ -27,10 +27,10 @@ Gem::Specification.new do |spec|
27
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
28
  end
29
29
  spec.bindir = 'bin'
30
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
30
+ spec.executables = []
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_runtime_dependency 'byebug', '>= 11.1.0'
34
- spec.add_runtime_dependency 'pastel', '>= 0.7.4'
35
- spec.add_runtime_dependency 'pry', '>= 0.13.0'
33
+ spec.add_runtime_dependency 'byebug', '~> 11.1.0'
34
+ spec.add_runtime_dependency 'pry', '~> 0.13.0'
35
+ spec.add_runtime_dependency 'tty-screen', '~> 0.8.1'
36
36
  end
@@ -0,0 +1,130 @@
1
+ /*!
2
+ * GitHub Light v0.4.1
3
+ * Copyright (c) 2012 - 2017 GitHub, Inc.
4
+ * Licensed under MIT (https://github.com/primer/github-syntax-theme-generator/blob/master/LICENSE)
5
+ */
6
+
7
+ .pl-c /* comment, punctuation.definition.comment, string.comment */ {
8
+ color: #6a737d;
9
+ }
10
+
11
+ .pl-c1 /* constant, entity.name.constant, variable.other.constant, variable.language, support, meta.property-name, support.constant, support.variable, meta.module-reference, markup.raw, meta.diff.header, meta.output */,
12
+ .pl-s .pl-v /* string variable */ {
13
+ color: #005cc5;
14
+ }
15
+
16
+ .pl-e /* entity */,
17
+ .pl-en /* entity.name */ {
18
+ color: #6f42c1;
19
+ }
20
+
21
+ .pl-smi /* variable.parameter.function, storage.modifier.package, storage.modifier.import, storage.type.java, variable.other */,
22
+ .pl-s .pl-s1 /* string source */ {
23
+ color: #24292e;
24
+ }
25
+
26
+ .pl-ent /* entity.name.tag, markup.quote */ {
27
+ color: #22863a;
28
+ }
29
+
30
+ .pl-k /* keyword, storage, storage.type */ {
31
+ color: #d73a49;
32
+ }
33
+
34
+ .pl-s /* string */,
35
+ .pl-pds /* punctuation.definition.string, source.regexp, string.regexp.character-class */,
36
+ .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
37
+ .pl-sr /* string.regexp */,
38
+ .pl-sr .pl-cce /* string.regexp constant.character.escape */,
39
+ .pl-sr .pl-sre /* string.regexp source.ruby.embedded */,
40
+ .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */ {
41
+ color: #032f62;
42
+ }
43
+
44
+ .pl-v /* variable */,
45
+ .pl-smw /* sublimelinter.mark.warning */ {
46
+ color: #e36209;
47
+ }
48
+
49
+ .pl-bu /* invalid.broken, invalid.deprecated, invalid.unimplemented, message.error, brackethighlighter.unmatched, sublimelinter.mark.error */ {
50
+ color: #b31d28;
51
+ }
52
+
53
+ .pl-ii /* invalid.illegal */ {
54
+ color: #fafbfc;
55
+ background-color: #b31d28;
56
+ }
57
+
58
+ .pl-c2 /* carriage-return */ {
59
+ color: #fafbfc;
60
+ background-color: #d73a49;
61
+ }
62
+
63
+ .pl-c2::before /* carriage-return */ {
64
+ content: "^M";
65
+ }
66
+
67
+ .pl-sr .pl-cce /* string.regexp constant.character.escape */ {
68
+ font-weight: bold;
69
+ color: #22863a;
70
+ }
71
+
72
+ .pl-ml /* markup.list */ {
73
+ color: #735c0f;
74
+ }
75
+
76
+ .pl-mh /* markup.heading */,
77
+ .pl-mh .pl-en /* markup.heading entity.name */,
78
+ .pl-ms /* meta.separator */ {
79
+ font-weight: bold;
80
+ color: #005cc5;
81
+ }
82
+
83
+ .pl-mi /* markup.italic */ {
84
+ font-style: italic;
85
+ color: #24292e;
86
+ }
87
+
88
+ .pl-mb /* markup.bold */ {
89
+ font-weight: bold;
90
+ color: #24292e;
91
+ }
92
+
93
+ .pl-md /* markup.deleted, meta.diff.header.from-file, punctuation.definition.deleted */ {
94
+ color: #b31d28;
95
+ background-color: #ffeef0;
96
+ }
97
+
98
+ .pl-mi1 /* markup.inserted, meta.diff.header.to-file, punctuation.definition.inserted */ {
99
+ color: #22863a;
100
+ background-color: #f0fff4;
101
+ }
102
+
103
+ .pl-mc /* markup.changed, punctuation.definition.changed */ {
104
+ color: #e36209;
105
+ background-color: #ffebda;
106
+ }
107
+
108
+ .pl-mi2 /* markup.ignored, markup.untracked */ {
109
+ color: #f6f8fa;
110
+ background-color: #005cc5;
111
+ }
112
+
113
+ .pl-mdr /* meta.diff.range */ {
114
+ font-weight: bold;
115
+ color: #6f42c1;
116
+ }
117
+
118
+ .pl-ba /* brackethighlighter.tag, brackethighlighter.curly, brackethighlighter.round, brackethighlighter.square, brackethighlighter.angle, brackethighlighter.quote */ {
119
+ color: #586069;
120
+ }
121
+
122
+ .pl-sg /* sublimelinter.gutter-mark */ {
123
+ color: #959da5;
124
+ }
125
+
126
+ .pl-corl /* constant.other.reference.link, string.other.link */ {
127
+ text-decoration: underline;
128
+ color: #032f62;
129
+ }
130
+