term_color 0.0.2 → 0.0.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.
- checksums.yaml +4 -4
- data/README.md +126 -35
- data/lib/term_color/rule.rb +168 -36
- data/lib/term_color/rule_set.rb +137 -51
- data/lib/term_color.rb +5 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ca92238dae771cacd8dd2165975e084ac10aac980cdb3ce36f52da3d76742e4
|
4
|
+
data.tar.gz: 2e800af8a7aefbc39895d29ac25a8dcc67501b9a48a7827d76fbc017ae6ae9fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bc3d2a0e78014e06c21d0be5ed18a5ca081c712ee456080b4eddca3c216b75e5986d2b909807d6e286edbcb3236626183a5f4a9af61465659b3ca6fb2cc376f
|
7
|
+
data.tar.gz: dd06e1eba2e21496090f4681b7c4c79dcd80a5211dba25129cf106a181ce0df26cd68c1298c12afac53a20ec05546abac2025d8fc4be9f3751a0ec2e56f92cbf
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Rule-based text coloring/styling library for terminal text
|
4
4
|
|
5
|
+
[](https://badge.fury.io/rb/term_color)
|
6
|
+
|
5
7
|
## Overview
|
6
8
|
|
7
9
|
### Justifying Features
|
@@ -16,11 +18,40 @@ Rule-based text coloring/styling library for terminal text
|
|
16
18
|
|
17
19
|
## Concepts/Syntax
|
18
20
|
|
19
|
-
Rules are grouped into `RuleSets`, which are represented by instances of {TermColor::RuleSet}.
|
21
|
+
Rules are grouped into `RuleSets`, which are represented by instances of {TermColor::RuleSet}. Rules are applied to text using tag strings indicating start and end of rule application. There is also a tag that can be used outside of rule application to fully reset all styling options to system default.
|
22
|
+
|
23
|
+
### Tags
|
24
|
+
|
25
|
+
_The 'tag' strings used to specify start and end of ranges of text to apply a rule to can be customized in the `RuleSet` constructor. These details assume the defaults are used._
|
26
|
+
|
27
|
+
- Open: `{%<rule name>`
|
28
|
+
- Ex: `{%rule1`
|
29
|
+
- Close: `%}`
|
30
|
+
- Reset: `%@`
|
31
|
+
- Only usable outside of tags. Resets all styling to default even if a previously used rule is configured to keep styling applied after close
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
# Rules named :a and :b
|
35
|
+
"Unstyled {%a Styled with a %} Normal {%bStyled with b%} normal %@ fully reset"
|
36
|
+
```
|
37
|
+
|
38
|
+
Rules can be nested. When an inner rule tag is closed, the styling of the any outer/unclosed tags will be re-applied from outer most to inner most.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
"{%aRule A{%bRule A+B{%cRule A+B+C%}A+B%}A%} Normal"
|
42
|
+
```
|
43
|
+
|
44
|
+
### Rule Sets
|
20
45
|
|
21
|
-
|
46
|
+
Rule Sets contain named styling rules, any override options you chose to use (`after` behavior, open/close/reset symbols). Instances of `RuleSet` also provide methods for processing and displaying text with style tag markup via methods like `print` and `printf`
|
22
47
|
|
23
|
-
|
48
|
+
Gemeral Usage:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
rs = TermColor.create_rule_set(<rules hash>, <named options>)
|
52
|
+
```
|
53
|
+
|
54
|
+
Constructor:
|
24
55
|
|
25
56
|
```ruby
|
26
57
|
rules = {
|
@@ -33,6 +64,13 @@ rule_set = TermColor.create_rule_set(rules)
|
|
33
64
|
rule_set = TermColor::RuleSet.new(rules)
|
34
65
|
```
|
35
66
|
|
67
|
+
#### Constructor Options
|
68
|
+
|
69
|
+
- `after` - Override default 'after' rule (controlling what gets reset after a style tag is closed). Default is `:auto`, which automatically determines what styling to removed based on the rule being closed
|
70
|
+
- `:reset` - Causes all colors and styling to be reset on close
|
71
|
+
- `:keep` - Causes nothing to get reset
|
72
|
+
- Custom Hash - Allows you to specify your own after rule as a hash containing properties valid for `after` sections (`[:fg,:bg,:reset,:enable,:disable]`)
|
73
|
+
|
36
74
|
#### Applying to Text
|
37
75
|
|
38
76
|
Once you've got a `RuleSet` instance, calling its `apply` or `print`/`printf` methods with a string parameter will give back a copy of that string with styles applied
|
@@ -43,63 +81,116 @@ __Methods__
|
|
43
81
|
- `print` - {TermColor::RuleSet#print}
|
44
82
|
- `printf` - {TermColor::RuleSet#printf}
|
45
83
|
|
46
|
-
|
84
|
+
### Rule Definitions
|
47
85
|
|
48
|
-
|
49
|
-
- E.g.: `"%titleTitle Text%%"`
|
50
|
-
- `%%` indicates the end of rule application, after which any `after` rules will get applied
|
51
|
-
- Including `%%` when no rule is active will apply the `default` rule's `:after` options, which can either be overridden in your rule set, or make use of the built-in version which simply resets all colors and text styling to system default
|
52
|
-
- Rule application can be nested (`"%titleTitle of %otherBook%%%%"`)
|
86
|
+
A Rule definition is a hash consisting of two parts, `inside` and `after`. `inside` dictates styling that gets applied to text between the open and close tags for the rule, `after` allows you to override what happens when that tag closes (overrides default `after` rule as specified in constructor).
|
53
87
|
|
54
|
-
|
88
|
+
The `after` part, when used, must always be a hash in the rule definition assigned to the key `:after`. Everything else will be automatically grouped into a `inside` key/value if not explicitly specified.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
r = { inside: { fg: :red }, after: { keep: :fg }}
|
92
|
+
r = { fg: :red, bg: :blue }
|
93
|
+
r = { after: { reset: :all} }
|
94
|
+
```
|
95
|
+
|
96
|
+
### Rule Options/Actions
|
55
97
|
|
56
|
-
|
98
|
+
#### Colors
|
57
99
|
|
58
|
-
|
100
|
+
##### Attributes
|
101
|
+
|
102
|
+
- `fg` - Change foreground color
|
103
|
+
- `bg` - Change background color
|
104
|
+
|
105
|
+
##### Values
|
106
|
+
|
107
|
+
###### Standard Named Colors
|
108
|
+
|
109
|
+
Color values can be color-name symbols as defined in {TermColor::Rule::Colors} (`:black, :red, :yellow, :blue, :magenta, :cyan, :white`)
|
110
|
+
|
111
|
+
###### XTerm 256 Color Values
|
112
|
+
|
113
|
+
To use XTerm 256 Color Mode values, include the color code integer inside a single item array. (E.g. for code `208`, use `[208]`)
|
114
|
+
|
115
|
+
###### XTerm 16m Color Values
|
116
|
+
|
117
|
+
To use XTerm 16m Color Mode RGB colors, include the red, green and blue color values in an ordered array (E.g. for 80 red, 80 green, 255 blue, use `[80,80,255]`)
|
118
|
+
|
119
|
+
#### Styles
|
120
|
+
|
121
|
+
##### Actions
|
122
|
+
|
123
|
+
- `enable` - Style(s) to enable (Can be single item or array)
|
124
|
+
- `disable` - Style(s) to disable (Can be single item or array)
|
125
|
+
|
126
|
+
##### Values
|
127
|
+
|
128
|
+
(See symbols in {TermColor::Rule::Styles})
|
129
|
+
|
130
|
+
- `:bold`/`:intense`
|
131
|
+
- `:dim`/`:dark`
|
132
|
+
- `:italic`
|
133
|
+
- `:underline`
|
134
|
+
- `:inverse`
|
135
|
+
- `:hidden`
|
136
|
+
- `:strikethrough`
|
137
|
+
|
138
|
+
#### Reset / Keep
|
139
|
+
|
140
|
+
_(Only valid in `after` section)_
|
141
|
+
|
142
|
+
Quick way of resetting one or more style rules. `reset`/`keep` can be given a single symbol or an array of symbols.
|
143
|
+
|
144
|
+
`keep` will be ignored if included in default after rule
|
59
145
|
|
60
146
|
```ruby
|
61
|
-
|
62
|
-
|
63
|
-
# Same as above but with groups. after will be generated
|
64
|
-
rule = { inside: { fg: :red } }
|
65
|
-
# No groups, skip after generation by setting it to
|
66
|
-
# empty hash of options
|
67
|
-
rule = { fg: :red, after: {} }
|
68
|
-
# Both groups, same as others but with explicitly set after options,
|
69
|
-
# no auto-generation
|
70
|
-
rule = { inside: { fg: :red }, after: { reset: :fg } }
|
147
|
+
{ reset: [options] }
|
148
|
+
{ keep: [options] }
|
71
149
|
```
|
72
150
|
|
73
|
-
|
151
|
+
#### Options
|
74
152
|
|
75
|
-
|
153
|
+
- `:fg` / `:bg` - Reset foreground / background color
|
154
|
+
- `:style` - Reset all styling
|
155
|
+
- `:all` - Reset all colors and styling
|
76
156
|
|
77
157
|
[If example images are missing, view readme on github](https://github.com/vdtdev/term_color/blob/master/README.md)
|
78
158
|
|
79
|
-
|
159
|
+
## Examples
|
160
|
+
|
161
|
+
_If images don't show up, try viewing on [Github](https://github.com/vdtdev/term_color/blob/master/README.md)_
|
162
|
+
|
163
|
+
### Basic w/ Nesting (`:auto` after mode)
|
80
164
|
|
81
165
|
```ruby
|
82
166
|
rule_set = TermColor.create_rule_set({
|
83
|
-
|
84
|
-
|
167
|
+
yellow: { fg: :yellow },
|
168
|
+
ul: { enable: :ul },
|
169
|
+
err: { fg: :white, bg: :red, enable: [:italic] }
|
85
170
|
})
|
86
171
|
|
87
|
-
rule_set.
|
172
|
+
rule_set.print "Test Score: {%yellow65%}\n"
|
173
|
+
rule_set.print "{%ul{%err{%yellowNOTE:%}" +
|
174
|
+
"Your score is below a passing grade%}X%}\n"
|
88
175
|
```
|
89
176
|
|
90
177
|

|
91
178
|

|
92
179
|
|
93
|
-
###
|
180
|
+
### With `:keep` after mode
|
94
181
|
|
95
182
|
```ruby
|
96
183
|
rule_set = TermColor.create_rule_set({
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
})
|
101
|
-
|
102
|
-
rule_set.print "
|
184
|
+
g: { fg: :green },
|
185
|
+
i: { enable: :inverse },
|
186
|
+
f: { fg: :yellow, after: { reset: :fg }}
|
187
|
+
}, after: :keep)
|
188
|
+
|
189
|
+
rule_set.print "{%gTitle%}\n"
|
190
|
+
rule_set.print "{%i>%}"
|
191
|
+
(1..5).each {|i| print "#{i}\n" }
|
192
|
+
rule_set.print "{%fThis style reverts after closing%}\n"
|
193
|
+
rule_set.print "Before Reset%@After Reset\n"
|
103
194
|
```
|
104
195
|
|
105
196
|

|
data/lib/term_color/rule.rb
CHANGED
@@ -12,9 +12,9 @@ module TermColor
|
|
12
12
|
# # Insize: (`a:`) Foreground yellow, bg red, dark style on
|
13
13
|
# # After: Resets all color and style options to default,
|
14
14
|
# # including those set by other rules
|
15
|
-
# rule = {
|
15
|
+
# rule = {
|
16
16
|
# a: {
|
17
|
-
# fg: :yellow, bg: :red, enable: :dark
|
17
|
+
# fg: :yellow, bg: :red, enable: :dark
|
18
18
|
# },
|
19
19
|
# z: {
|
20
20
|
# reset: :all
|
@@ -45,23 +45,23 @@ module TermColor
|
|
45
45
|
##
|
46
46
|
# Numerical modifiers used with Color Values
|
47
47
|
# to target foreground or background.
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# - For {Colors Named Standard Colors}, value is added to given
|
50
50
|
# color's numerical value
|
51
51
|
# - For XTerm 256/16m color codes, value is added to mode base
|
52
|
-
#
|
52
|
+
#
|
53
53
|
# @example Named Standard Color Background
|
54
54
|
# { bg: :red } #=> 40 + 1 = 41
|
55
55
|
# @example XTerm 256 Foreground
|
56
56
|
# { fg: [208] } #=> 8 + 30 = 38
|
57
|
-
ColorTargets = {
|
57
|
+
ColorTargets = {
|
58
58
|
fg: 30, # Foreground target
|
59
59
|
bg: 40 # Background target
|
60
60
|
}.freeze
|
61
61
|
|
62
62
|
##
|
63
63
|
# Style option constants
|
64
|
-
# (Values that can be included in style `enable` and `disable`
|
64
|
+
# (Values that can be included in style `enable` and `disable`
|
65
65
|
# rule option attributes)
|
66
66
|
Styles = {
|
67
67
|
bold: 1,
|
@@ -75,6 +75,7 @@ module TermColor
|
|
75
75
|
italic: 3,
|
76
76
|
underline: 4,
|
77
77
|
inverse: 7,
|
78
|
+
hidden: 8,
|
78
79
|
strikethrough: 9
|
79
80
|
}.freeze
|
80
81
|
|
@@ -85,12 +86,12 @@ module TermColor
|
|
85
86
|
# was used)
|
86
87
|
# @example Disable italic
|
87
88
|
# (:disable) + (:italic) #=> 20 + 3 = 23
|
88
|
-
StyleActions = {
|
89
|
+
StyleActions = {
|
89
90
|
# Enable style(s) action
|
90
91
|
enable: 0,
|
91
92
|
# Disable style(s) action
|
92
|
-
disable: 20
|
93
|
-
}
|
93
|
+
disable: 20
|
94
|
+
}.freeze
|
94
95
|
|
95
96
|
##
|
96
97
|
# Reset option constants
|
@@ -101,9 +102,17 @@ module TermColor
|
|
101
102
|
# Reset foreground color only
|
102
103
|
fg: 39,
|
103
104
|
# Reset background color only
|
104
|
-
bg: 49
|
105
|
+
bg: 49,
|
106
|
+
# Reset style
|
107
|
+
style: StyleActions[:disable]
|
105
108
|
}.freeze
|
106
109
|
|
110
|
+
##
|
111
|
+
# Operations associated with reset
|
112
|
+
ResetOps = [ :reset, :keep ].freeze
|
113
|
+
|
114
|
+
ResetsExtra = [ :style ].freeze
|
115
|
+
|
107
116
|
##
|
108
117
|
# Descriptive aliases for part names
|
109
118
|
Parts = {
|
@@ -111,7 +120,7 @@ module TermColor
|
|
111
120
|
inside: :inside,
|
112
121
|
# Style appled when rule close is given
|
113
122
|
after: :after
|
114
|
-
}
|
123
|
+
}.freeze
|
115
124
|
|
116
125
|
##
|
117
126
|
# Valid rule operations mapped to accepted const values
|
@@ -126,13 +135,38 @@ module TermColor
|
|
126
135
|
# Disable style(s) action
|
127
136
|
disable: Styles.keys,
|
128
137
|
# Reset action
|
129
|
-
reset:
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
138
|
+
reset: Resets.keys,
|
139
|
+
# Keep action (opposite of reset)
|
140
|
+
keep: Resets.keys
|
141
|
+
}.freeze
|
142
|
+
|
143
|
+
##
|
144
|
+
# Normalize rules for ops; either `:keep` to
|
145
|
+
# not change original value, or `:array` to
|
146
|
+
# wrap single value inside array
|
147
|
+
OpNormalize = {
|
148
|
+
fg: :keep,
|
149
|
+
bg: :keep,
|
150
|
+
enable: :array,
|
151
|
+
disable: :array,
|
152
|
+
reset: :array,
|
153
|
+
keep: :array
|
154
|
+
}.freeze
|
155
|
+
|
156
|
+
##
|
157
|
+
# Allowed ops by part
|
158
|
+
PartOps = {
|
159
|
+
inside: [:fg, :bg, :enable, :disable],
|
160
|
+
after: [:fg, :bg, :enable, :disable, :reset, :keep]
|
161
|
+
}.freeze
|
162
|
+
|
163
|
+
##
|
164
|
+
# Operations allowed within 'after'
|
165
|
+
AfterOps = (Ops.filter{|k,v| PartOps[:after].include?(k)}).freeze
|
166
|
+
|
167
|
+
##
|
168
|
+
# Operations allowed within 'inside'
|
169
|
+
InsideOps = (Ops.filter {|k,v| PartOps[:inside].include?(k)}).freeze
|
136
170
|
|
137
171
|
##
|
138
172
|
# Value added to ColorTarget when using XTerm colors
|
@@ -167,10 +201,13 @@ module TermColor
|
|
167
201
|
##
|
168
202
|
# Compile rule into frozen instance of `Compiled` struct
|
169
203
|
# @param [Hash] rule Rule hash
|
204
|
+
# @param [RuleSet] rs Rule set
|
205
|
+
# @param [Boolean] is_reset Set to true to indicate rule is for reset
|
206
|
+
# operation, and should ignore default after resolution
|
170
207
|
# @return [Compiled] Frozen instance of `Compiled` struct
|
171
208
|
# containing compiled rule
|
172
|
-
def compile(rule)
|
173
|
-
evaluated = evaluate(rule)
|
209
|
+
def compile(rule, rs, is_reset=false)
|
210
|
+
evaluated = evaluate(rule,rs,is_reset)
|
174
211
|
return Compiled.new(
|
175
212
|
rule,
|
176
213
|
evaluated,
|
@@ -201,16 +238,16 @@ module TermColor
|
|
201
238
|
end
|
202
239
|
end
|
203
240
|
codes = codes.flatten.compact.uniq
|
204
|
-
end
|
241
|
+
end
|
205
242
|
|
206
243
|
def resolve_color(color, target = :fg)
|
207
244
|
if color.is_a?(Array)
|
208
245
|
color = color[0..2]
|
209
246
|
return xterm_color(color, target)
|
210
247
|
end
|
211
|
-
|
248
|
+
|
212
249
|
if !color.is_a?(Integer)
|
213
|
-
|
250
|
+
|
214
251
|
if color.is_a?(Hash) && ColorsAdvanced.keys.include?(color.keys[0])
|
215
252
|
return self.method(ColorsAdvanced[color.keys[0]]).call(color.values[0])
|
216
253
|
end
|
@@ -223,7 +260,10 @@ module TermColor
|
|
223
260
|
if !style.is_a?(Integer)
|
224
261
|
style = Styles[style.to_sym].to_i
|
225
262
|
end
|
226
|
-
(style + StyleActions[state.to_sym].to_i)
|
263
|
+
s_code = (style + StyleActions[state.to_sym].to_i)
|
264
|
+
# adjust so bold and dim both get 22
|
265
|
+
s_code = [s_code, StyleActions[:disable] + 2].max if state == :disable
|
266
|
+
return s_code
|
227
267
|
end
|
228
268
|
|
229
269
|
def resolve_reset(target)
|
@@ -257,15 +297,16 @@ module TermColor
|
|
257
297
|
# Evaluate rule, returning new hash containing list of numerical
|
258
298
|
# codes to use for inside (`:inside`) and after (`:after`)
|
259
299
|
# @param [Hash] rule Rule hash to evaluate
|
300
|
+
# @param [RuleSet] rs Rule set
|
260
301
|
# @return [Hash] evaluated version of rule, containing code numbers
|
261
|
-
def evaluate(rule)
|
302
|
+
def evaluate(rule, rs, is_reset)
|
262
303
|
# error if not hash
|
263
304
|
return nil if !rule.is_a?(Hash)
|
264
305
|
|
265
306
|
inside_part_key = Parts[:inside]
|
266
307
|
after_part_key = Parts[:after]
|
267
308
|
rule_keys = rule.keys.map{|k|k.to_sym}
|
268
|
-
|
309
|
+
|
269
310
|
# Find 'inside' rule options
|
270
311
|
if rule_keys.include?(inside_part_key)
|
271
312
|
# 'inside' key explicitly defined, so pull from that
|
@@ -279,15 +320,15 @@ module TermColor
|
|
279
320
|
# Find 'after' rule options, using nil if not present
|
280
321
|
# This means that if it is defined but as an empty hash,
|
281
322
|
# no 'after' rule options will be auto-generated
|
282
|
-
after_part = rule.fetch(after_part_key,
|
283
|
-
|
284
|
-
#
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
after_part =
|
289
|
-
|
290
|
-
after_part
|
323
|
+
after_part = rule.fetch(after_part_key, {})
|
324
|
+
|
325
|
+
# Resolve after, either from template mixed with any
|
326
|
+
# overrides or an automatically generated version mixed with
|
327
|
+
# overrides
|
328
|
+
if rs.default_after == :auto
|
329
|
+
after_part = build_auto_after(inside_part, after_part)
|
330
|
+
else
|
331
|
+
after_part = override_after(inside_part, after_part, rs.default_after)
|
291
332
|
end
|
292
333
|
|
293
334
|
parts = {}
|
@@ -296,9 +337,100 @@ module TermColor
|
|
296
337
|
parts[after_part_key] = evaluate_ops(after_part)
|
297
338
|
|
298
339
|
return parts.merge({evaluated: true})
|
340
|
+
end
|
341
|
+
|
342
|
+
def normalize_part(hash,part,clean=false)
|
343
|
+
h = hash.dup
|
344
|
+
PartOps[part].each do |o|
|
345
|
+
if OpNormalize[o] == :array
|
346
|
+
h[o] = [h.fetch(o,[])].flatten
|
347
|
+
else
|
348
|
+
h[o] = h.fetch(o,nil)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
if clean
|
353
|
+
h = h.filter {|k,v| (v.is_a?(Array))? v.length > 0 : !v.nil? }
|
354
|
+
end
|
355
|
+
|
356
|
+
return h
|
357
|
+
end
|
358
|
+
|
359
|
+
def override_after(inside, override, after)
|
360
|
+
c_ovr = normalize_part(override, :after)
|
361
|
+
c_aft = normalize_part(after, :after)
|
362
|
+
c_inside = normalize_part(inside, :inside)
|
363
|
+
|
364
|
+
# change reset :all to specific resets
|
365
|
+
if c_aft[:reset].include?(:all)
|
366
|
+
c_aft[:reset] = Resets.keys - [:all]
|
367
|
+
end
|
368
|
+
# change keep :all to specific resets
|
369
|
+
if c_ovr[:keep].include?(:all)
|
370
|
+
c_ovr[:keep] = Resets.keys - [:all]
|
371
|
+
end
|
372
|
+
|
373
|
+
c_aft[:reset] = (c_aft[:reset] + c_ovr[:reset]).uniq
|
374
|
+
# remove keeps from resets
|
375
|
+
c_aft[:reset] -= c_ovr[:keep]
|
376
|
+
|
377
|
+
# clear disable if keep :style
|
378
|
+
if c_ovr[:keep].include?(:style) ||
|
379
|
+
c_aft[:disable] = []
|
380
|
+
end
|
381
|
+
|
382
|
+
# if override disables styles, remove blanket style reset
|
383
|
+
if c_ovr[:disable].length >= 1
|
384
|
+
c_aft[:reset] -= [:style]
|
385
|
+
end
|
386
|
+
|
387
|
+
# replace reset :style with style specific targets
|
388
|
+
if c_inside[:enable].length > 0 && c_aft[:reset].include?(:style)
|
389
|
+
c_aft[:reset] -= [:style]
|
390
|
+
c_aft[:disable] += c_inside[:enable]
|
391
|
+
c_aft[:enable] -= c_inside[:enable]
|
392
|
+
end
|
299
393
|
|
394
|
+
# If we've reached this point with reset :style, change it into
|
395
|
+
# disables
|
396
|
+
if c_aft[:reset].include?(:style)
|
397
|
+
c_aft[:reset] -= [:style]
|
398
|
+
c_aft[:disable] += Styles.keys
|
399
|
+
end
|
400
|
+
|
401
|
+
# prevent enables from conflicting with disables
|
402
|
+
en = (c_aft[:enable] + c_ovr[:enable] - c_ovr[:disable]).uniq
|
403
|
+
di = (c_aft[:disable] + c_ovr[:disable] - c_ovr[:enable]).uniq
|
404
|
+
|
405
|
+
en -= di
|
406
|
+
di -= en
|
407
|
+
|
408
|
+
result = { enable: en, disable: di, reset: c_aft[:reset] }
|
409
|
+
ColorTargets.keys.each do |k|
|
410
|
+
val = (c_ovr[k] || c_aft[k])
|
411
|
+
result[k] = val unless val.nil?
|
412
|
+
end
|
413
|
+
|
414
|
+
return normalize_part(result, :after, true)
|
300
415
|
end
|
301
416
|
|
417
|
+
def build_auto_after(inside, after={})
|
418
|
+
c_inside = normalize_part(inside, :inside)
|
419
|
+
n_after = normalize_part({}, :after)
|
420
|
+
|
421
|
+
if c_inside[:enable].length > 0
|
422
|
+
n_after[:reset] += [:style]
|
423
|
+
end
|
424
|
+
|
425
|
+
ColorTargets.keys.each do |k|
|
426
|
+
if !c_inside[k].nil?
|
427
|
+
n_after[:reset] += [k]
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
override_after(inside, after, n_after)
|
432
|
+
end
|
433
|
+
|
302
434
|
##
|
303
435
|
# Return ANSI color codes from evaluated rule
|
304
436
|
# @param [Hash] rule Full rule
|
@@ -313,4 +445,4 @@ module TermColor
|
|
313
445
|
}
|
314
446
|
end
|
315
447
|
end
|
316
|
-
end
|
448
|
+
end
|
data/lib/term_color/rule_set.rb
CHANGED
@@ -5,24 +5,60 @@ module TermColor
|
|
5
5
|
# @license MIT
|
6
6
|
class RuleSet
|
7
7
|
|
8
|
+
DBG = false
|
9
|
+
|
8
10
|
##
|
9
|
-
#
|
10
|
-
|
11
|
+
# Default rule symbols
|
12
|
+
DEFAULT_SYMBOLS = {
|
13
|
+
open: '{%',
|
14
|
+
close: '%}',
|
15
|
+
reset: '%@'
|
16
|
+
}.freeze
|
17
|
+
|
11
18
|
##
|
12
|
-
#
|
13
|
-
|
19
|
+
# Default reset rule
|
20
|
+
DEFAULT_RESET_RULE = {after: {reset: :all} }.freeze
|
14
21
|
|
15
|
-
|
22
|
+
##
|
23
|
+
# After preset options
|
24
|
+
AFTER_PRESETS = {
|
25
|
+
# Full reset
|
26
|
+
reset: {reset: :all},
|
27
|
+
# Automatically determine what to toggle off
|
28
|
+
auto: :auto,
|
29
|
+
# No reset
|
30
|
+
keep: {keep: :all}
|
31
|
+
}
|
16
32
|
|
17
|
-
|
33
|
+
##
|
34
|
+
# Struct for rule and reset symbols
|
35
|
+
SymbolOptions = Struct.new(:open,:close,:reset)
|
36
|
+
|
37
|
+
##
|
38
|
+
# Default after preset choice
|
39
|
+
DEFAULT_AFTER = :auto
|
40
|
+
|
41
|
+
attr_reader :rules, :regexs, :default_after, :symbols
|
18
42
|
|
19
43
|
##
|
20
44
|
# Construct new rule set
|
21
45
|
# @param [Hash] rules Hash of rule names mapping to rule hashes,
|
22
|
-
# which can define before rules (`
|
23
|
-
# - If neither are given, content is treated as though it was inside a `
|
24
|
-
# - If `
|
25
|
-
# auto guess `
|
46
|
+
# which can define before rules (`inside:`), after rules (`after:`) or both.
|
47
|
+
# - If neither are given, content is treated as though it was inside a `inside:` key.
|
48
|
+
# - If `inside:` only is given, {TermColor::Rule#evaluate Rule evaluate method} attempts to
|
49
|
+
# auto guess `after:`, resetting any used color or style rules from `inside:`
|
50
|
+
# @param [Hash] opts Optional arguments
|
51
|
+
# @option opts [Hash|Symbol] :after Override default `:after` rule behavior when rule has no `after:`
|
52
|
+
# Options:
|
53
|
+
# - `:reset` - Reset all color and styles
|
54
|
+
# - `:auto` (default) - Try to automatically determine what to reset based on applied colors/styles
|
55
|
+
# - `:keep` - Keel all rule styles intact
|
56
|
+
# - (`Hash`) - Custom rule (formatted as Rule `after` prop, e.g. `{ reset: :fg, keep: :style }`)
|
57
|
+
# @option opts [Hash] :symbols Override styling symbols
|
58
|
+
# Options:
|
59
|
+
# - `:open` - Rule open symbol (used as symbolRulename) (default `{%`)
|
60
|
+
# - `:close` - Rule close symbol (default `%}`)
|
61
|
+
# - `:reset` - Symbol that can be used between rule blocks to fully reset everything (default `%@`)
|
26
62
|
# @see TermColor::Rule
|
27
63
|
# @example
|
28
64
|
# rules = RuleSet.new({
|
@@ -33,10 +69,10 @@ module TermColor
|
|
33
69
|
# quote: { enable: :italic },
|
34
70
|
# # A weird rule that will make fg red inside rule,
|
35
71
|
# # and change fg to blue after rule block ends
|
36
|
-
# weird: {
|
72
|
+
# weird: { inside: { fg: :red }, after: { fg: :blue }}
|
37
73
|
# })
|
38
74
|
#
|
39
|
-
# print rules.colorize("%nameJohn
|
75
|
+
# print rules.colorize("{%nameJohn%}: '{%quoteRoses are {%weirdRed%} (blue)%}.\n")
|
40
76
|
# # Result will be:
|
41
77
|
# # fg green+underline "John"
|
42
78
|
# # regular ": "
|
@@ -44,9 +80,23 @@ module TermColor
|
|
44
80
|
# # fg red (still italic) "Red"
|
45
81
|
# # (fg blue)(still italic) "(blue)"
|
46
82
|
# # (regular) "."
|
47
|
-
def initialize(rules)
|
83
|
+
def initialize(rules={}, **opts)
|
84
|
+
if rules.nil?
|
85
|
+
rules = opts
|
86
|
+
opts = {}
|
87
|
+
end
|
48
88
|
@base_rules = rules
|
49
|
-
@base_rules[:
|
89
|
+
@base_rules[:reset] = @base_rules.fetch(:reset, DEFAULT_RESET_RULE)
|
90
|
+
# binding.pry
|
91
|
+
after = opts.fetch(:after, nil)
|
92
|
+
after = DEFAULT_AFTER if after.nil? || (after.is_a?(Symbol) && !AFTER_PRESETS.has_key?(after))
|
93
|
+
@default_after = (after.is_a?(Hash))? after : AFTER_PRESETS[after]
|
94
|
+
sym_opts = opts.fetch(:symbols,{})
|
95
|
+
@symbols = SymbolOptions.new(
|
96
|
+
sym_opts.fetch(:open, DEFAULT_SYMBOLS[:open]),
|
97
|
+
sym_opts.fetch(:close, DEFAULT_SYMBOLS[:close]),
|
98
|
+
sym_opts.fetch(:reset, DEFAULT_SYMBOLS[:reset])
|
99
|
+
)
|
50
100
|
evaluate_rules
|
51
101
|
build_regexs
|
52
102
|
end
|
@@ -57,33 +107,54 @@ module TermColor
|
|
57
107
|
# @return [String] Text with ANSI style codes injected
|
58
108
|
def apply(text)
|
59
109
|
raw = process_text(text)
|
60
|
-
|
110
|
+
rule_stack = []
|
61
111
|
str = ''
|
112
|
+
rule_names = @rules.keys
|
62
113
|
raw.each do |r|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
last_rule = r
|
82
|
-
str.concat(@rules[r].codes(Rule::Parts[:inside]))
|
114
|
+
if r.is_a?(Symbol)
|
115
|
+
# Part is a rule
|
116
|
+
dprint "\tRule Symbol #{r}\n"
|
117
|
+
if r == :close && rule_stack.length >= 1
|
118
|
+
# Rule close with 1+ opened rules
|
119
|
+
opened = rule_stack.pop
|
120
|
+
opened_after = @rules[opened].codes(Rule::Parts[:after])
|
121
|
+
dprint "\t\tClose, opened rule '#{opened}'\n"
|
122
|
+
dprint "\t\t\tClosing rule '#{opened}' with After\n"
|
123
|
+
dprint 4,"After: #{opened_after.inspect}\n"
|
124
|
+
str.concat(opened_after)
|
125
|
+
unless rule_stack.length == 0
|
126
|
+
rule_stack.each do |outer|
|
127
|
+
outer_inside = @rules[outer].codes(Rule::Parts[:inside])
|
128
|
+
# Closed rule was nested in another open rule
|
129
|
+
dprint 3, "Outer rule '#{outer}' still open. Restoring Inside\n"
|
130
|
+
dprint 4, "Inside: #{outer_inside.inspect}\n}"
|
131
|
+
str.concat(outer_inside)
|
83
132
|
end
|
84
|
-
|
85
|
-
|
133
|
+
end
|
134
|
+
# binding.pry
|
135
|
+
# outer = rule_stack[-1]
|
136
|
+
# outer_inside = @rules[outer].codes(Rule::Parts[:inside])
|
137
|
+
# # Closed rule was nested in another open rule
|
138
|
+
# dprint 3, "Outer rule '#{outer}' still open. Restoring Inside\n"
|
139
|
+
# dprint 4, "Inside: #{outer_inside.inspect}\n}"
|
140
|
+
# str.concat(outer_inside)
|
141
|
+
# # binding.pry
|
142
|
+
# end
|
143
|
+
elsif r == :reset && rule_stack.length == 0
|
144
|
+
# no opened outer rules, reset symbol given
|
145
|
+
dprint "\t\tReset, no opened rule\n"
|
146
|
+
str.concat(@rules[r].codes(Rule::Parts[:after]))
|
147
|
+
elsif rule_names.include?(r)
|
148
|
+
# New rule to apply
|
149
|
+
dprint "\t\tApplying new rule '#{r}'\n"
|
150
|
+
dprint 3, "Previous active rule `#{rule_stack[-1]}`\n"
|
151
|
+
rule_stack.push r
|
152
|
+
str.concat(@rules[r].codes(Rule::Parts[:inside]))
|
86
153
|
end
|
154
|
+
else
|
155
|
+
# Part is text
|
156
|
+
str.concat(r)
|
157
|
+
end
|
87
158
|
end
|
88
159
|
str
|
89
160
|
end
|
@@ -104,7 +175,7 @@ module TermColor
|
|
104
175
|
# Wraps STDOUT printf method, passing output of `apply` to `print`
|
105
176
|
# Doesn't actually use `printf`, instead passes result of
|
106
177
|
# `format_string % args` to `print`.
|
107
|
-
# @param [String] format_string printf format string,
|
178
|
+
# @param [String] format_string printf format string,
|
108
179
|
# including TermColor style tags
|
109
180
|
# @param [Array] args printf values to use with format string
|
110
181
|
# @param [Hash] opts Optional params
|
@@ -115,23 +186,35 @@ module TermColor
|
|
115
186
|
|
116
187
|
# Sanitize rule symbols
|
117
188
|
sanitized = format_string.dup
|
118
|
-
@rules.keys.each { |k| sanitized.gsub!("#{
|
119
|
-
sanitized.gsub!(
|
120
|
-
|
189
|
+
@rules.keys.each { |k| sanitized.gsub!("#{@symbols.rule}#{k.to_s}","#{255.chr}#{k.to_s}") }
|
190
|
+
sanitized.gsub!(@symbols.reset, 255.chr*2)
|
191
|
+
|
121
192
|
t = sanitized % args
|
122
193
|
# Reinstate rule symbols
|
123
|
-
@rules.keys.each { |k| t.gsub!("#{255.chr}#{k.to_s}","#{
|
124
|
-
t.gsub!(255.chr*2
|
125
|
-
|
194
|
+
@rules.keys.each { |k| t.gsub!("#{255.chr}#{k.to_s}","#{@symbols.rule}#{k.to_s}") }
|
195
|
+
t.gsub!(255.chr*2,@symbols.reset)
|
196
|
+
|
126
197
|
stdout.print apply(t)
|
127
198
|
end
|
128
|
-
|
199
|
+
|
129
200
|
private
|
130
201
|
|
202
|
+
def dprint(*v)
|
203
|
+
if DBG
|
204
|
+
if v.length == 2
|
205
|
+
tc,t=v
|
206
|
+
tabs = "\t" * tc
|
207
|
+
print "#{tabs}#{t}"
|
208
|
+
else
|
209
|
+
print v[0]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
131
214
|
def evaluate_rules
|
132
215
|
@rules = {}
|
133
216
|
@base_rules.each_pair do |k,v|
|
134
|
-
@rules[k] = Rule.compile(v)
|
217
|
+
@rules[k] = Rule.compile(v, self)
|
135
218
|
end
|
136
219
|
end
|
137
220
|
|
@@ -140,11 +223,14 @@ module TermColor
|
|
140
223
|
src = @rules
|
141
224
|
src.each_pair do |k,v|
|
142
225
|
@regexs[k] = Regexp.compile(
|
143
|
-
"(?<#{k.to_s}>(#{
|
226
|
+
"(?<#{k.to_s}>(#{@symbols.open}#{k.to_s}))"
|
144
227
|
)
|
145
228
|
end
|
146
|
-
@regexs[:
|
147
|
-
"(?<default>(#{
|
229
|
+
@regexs[:close] = Regexp.compile(
|
230
|
+
"(?<default>(#{@symbols.close}))"
|
231
|
+
)
|
232
|
+
@regexs[:reset] = Regexp.compile(
|
233
|
+
"(?<default>(#{@symbols.reset}))"
|
148
234
|
)
|
149
235
|
end
|
150
236
|
|
@@ -203,7 +289,7 @@ module TermColor
|
|
203
289
|
if !is_last
|
204
290
|
end_pos = locations[i+1][:begin] - 1
|
205
291
|
end
|
206
|
-
|
292
|
+
|
207
293
|
working << l[:symbol]
|
208
294
|
working << text[l[:continue_pos]..end_pos]
|
209
295
|
end
|
@@ -211,4 +297,4 @@ module TermColor
|
|
211
297
|
end
|
212
298
|
|
213
299
|
end
|
214
|
-
end
|
300
|
+
end
|
data/lib/term_color.rb
CHANGED
@@ -9,8 +9,10 @@ module TermColor
|
|
9
9
|
##
|
10
10
|
# Alias for constructing a new RuleSet
|
11
11
|
# @see TermColor::RuleSet
|
12
|
-
def create_rule_set(rules=
|
13
|
-
|
12
|
+
def create_rule_set(rules=nil,**opts)
|
13
|
+
TermColor::RuleSet.new(rules,opts)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
|
17
|
+
|
18
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: term_color
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wade H.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -46,7 +46,7 @@ licenses:
|
|
46
46
|
- MIT
|
47
47
|
metadata:
|
48
48
|
source_code_uri: https://github.com/vdtdev/term_color
|
49
|
-
documentation_uri: https://rubydoc.info/gems/term_color/0.0.
|
49
|
+
documentation_uri: https://rubydoc.info/gems/term_color/0.0.3
|
50
50
|
post_install_message:
|
51
51
|
rdoc_options: []
|
52
52
|
require_paths:
|