cani 0.2.2 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cd61890b987c88ef41a0dcf5e30ee5fb22dafd234e5855fadc3e3319753e0ba
4
- data.tar.gz: c40c2b1cd8ebe4e6bf6ec16ee5cce0863b903711d21b518ac8e45c562b166a99
3
+ metadata.gz: 1df7e81ecfee9fcb8dde134bf7d3c6db8ae21520c3185b28055bfdefbf2f2f94
4
+ data.tar.gz: c3c2eb816e5ea8fb0707db1a49c19f5fbdd8ac9122f4e8678713e5a9d184b3d9
5
5
  SHA512:
6
- metadata.gz: 4e16c24b8230c0d6515be703fa6ab9f1f0cf5a0672b4896e711c4ba230569c5c373cf27b4930559a4a57ff912010bdb131d2fffa675407304359ee32da4922a2
7
- data.tar.gz: c252dc1cdb93ed2a18e229b55bec0b4f92429922326ce764f4f34b32909af4ba867a9eb4cd8df77429e23a840350d06977f36667695438e1502a024d8346ea31
6
+ metadata.gz: e5ca259ccc81e38e8646feb058863231439831a1fbc1f6adc06d32240286cf19cb68bbccefd0d9b3275f9d05a7d495472c11a7570056fddafb03a51307c8d3a8
7
+ data.tar.gz: a77833ff65dd10cfe9f71ba665d5979acf7d95dcb45042b0083afd023e979bdaebc98846bcc0a8a54682b54ee0595de4a92b03e4643cc746a2bbac1d06f3115a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cani (0.2.0)
4
+ cani (0.2.2)
5
5
  colorize
6
6
  curses
7
7
  json
@@ -1,7 +1,7 @@
1
1
  module Cani
2
2
  class Api
3
3
  class Feature
4
- attr_reader :title, :status, :spec, :stats, :percent, :name
4
+ attr_reader :title, :status, :spec, :stats, :percent, :name, :browser_note_nums, :notes, :notes_by_num
5
5
 
6
6
  STATUSES = {
7
7
  'rec' => 'rc',
@@ -25,9 +25,14 @@ module Cani
25
25
  @status = STATUSES.fetch attributes['status'], attributes['status']
26
26
  @spec = attributes['spec']
27
27
  @percent = attributes['usage_perc_y']
28
- @stats = attributes['stats'].each_with_object({}) do |(k, v), h|
29
- h[k] = v.each_with_object({}) do |(vv, s), hh|
30
- vv.split('-').each { |ver| hh[ver] = s[0] }
28
+ @notes = attributes['notes'].split "\n"
29
+ @notes_by_num = attributes['notes_by_num']
30
+ @stats, @browser_note_nums = attributes['stats'].each_with_object([{}, {}]) do |(browser, info), (stts, notes)|
31
+ stts[browser], notes[browser] = info.each_with_object([{}, {}]) do |(version, stat), (st, nt)|
32
+ version.split('-').each do |v|
33
+ nt[v] = stat.scan(/#(\d+)/).flatten
34
+ st[v] = stat[' d '] ? 'd' : stat[0]
35
+ end
31
36
  end
32
37
  end
33
38
  end
@@ -7,31 +7,43 @@ module Cani
7
7
  COLOR_PAIRS = {
8
8
  # foreground colors
9
9
  69 => [70, -1], # green on default (legend supported, feature status, percentage counter)
10
- 213 => [214, -1], # orange on default (legend partial, percentage counter)
11
- 195 => [9, -1], # red on default (legend unsupported, percentage counter)
12
- 133 => [13, -1], # magenta on default (legend flag, current feature status)
10
+ 213 => [208, -1], # orange on default (legend partial, percentage counter)
11
+ 195 => [160, -1], # red on default (legend unsupported, percentage counter)
12
+ 133 => [134, -1], # magenta on default (legend flag, current feature status)
13
13
  12 => [75, -1], # blue on default (legend prefix)
14
14
  204 => [205, -1], # pink on default (legend polyfill)
15
- 99 => [8, -1], # gray on default (legend unknown)
15
+ 99 => [239, -1], # gray on default (legend unknown)
16
16
 
17
+ # note background + foreground colors
18
+ 71 => [22, 70], # dark green on green (supported feature)
19
+ 209 => [130, 208], # dark orange on orange (partial feature)
20
+ 197 => [88, 160], # dark red on red (unsupported feature)
21
+ 135 => [91, 134], # dark magenta on magenta (flag features)
22
+ 13 => [27, 75], # dark blue on blue (prefix feature)
23
+ 101 => [235, 239], # dark gray on gray (unknown features)
24
+ 206 => [127, 205], # dark pink on pink (polyfill features)
17
25
 
18
26
  # background colors
19
27
  70 => [7, 70], # white on green (supported feature)
20
- 208 => [7, 214], # white on orange (partial feature)
21
- 196 => [7, 9], # white on red (unsupported feature)
22
- 134 => [7, 13], # white on magenta (flag features)
28
+ 208 => [7, 208], # white on orange (partial feature)
29
+ 196 => [7, 160], # white on red (unsupported feature)
30
+ 134 => [7, 134], # white on magenta (flag features)
23
31
  11 => [7, 75], # white on blue (prefix feature)
24
- 100 => [7, 8], # white on gray (unknown features)
32
+ 100 => [7, 239], # white on gray (unknown features)
25
33
  205 => [7, 205], # white on pink (polyfill features)
26
34
 
27
35
  # misc / one-off
28
36
  254 => [238, 255], # black on light gray (browser names, legend title)
37
+ 239 => [232, 236]
29
38
  }.freeze
30
39
 
31
40
  COLORS = {
32
41
  # table headers
33
42
  header: {fg: Curses.color_pair(254), bg: Curses.color_pair(254)},
34
43
 
44
+ # current era border
45
+ era_border: {fg: Curses.color_pair(239), bg: Curses.color_pair(239)},
46
+
35
47
  # support types
36
48
  default: {fg: Curses.color_pair(69), bg: Curses.color_pair(70)},
37
49
  partial: {fg: Curses.color_pair(213), bg: Curses.color_pair(208)},
@@ -46,6 +58,16 @@ module Cani
46
58
  ot: {fg: Curses.color_pair(133), bg: Curses.color_pair(134)}
47
59
  }.freeze
48
60
 
61
+ NOTE_COLORS = {
62
+ default: {fg: Curses.color_pair(71), bg: Curses.color_pair(70)},
63
+ partial: {fg: Curses.color_pair(209), bg: Curses.color_pair(208)},
64
+ prefix: {fg: Curses.color_pair(13), bg: Curses.color_pair(11)},
65
+ polyfill: {fg: Curses.color_pair(206), bg: Curses.color_pair(205)},
66
+ flag: {fg: Curses.color_pair(135), bg: Curses.color_pair(134)},
67
+ unsupported: {fg: Curses.color_pair(197), bg: Curses.color_pair(196)},
68
+ unknown: {fg: Curses.color_pair(101), bg: Curses.color_pair(100)},
69
+ }
70
+
49
71
  PERCENT_COLORS = {
50
72
  70..101 => {fg: Curses.color_pair(69), bg: Curses.color_pair(70)},
51
73
  40..70 => {fg: Curses.color_pair(213), bg: Curses.color_pair(208)},
@@ -67,7 +89,6 @@ module Cani
67
89
  Curses.init_screen
68
90
  Curses.curs_set 0
69
91
  Curses.noecho
70
- Curses.cbreak
71
92
 
72
93
  if Curses.has_colors?
73
94
  Curses.use_default_colors
@@ -93,14 +114,10 @@ module Cani
93
114
  status_format = "[#{feature.status}]"
94
115
  percent_label = compact? ? '' : 'support: '
95
116
  legend_format = 'legend'.center table_width
117
+ notes_format = 'notes'.center table_width
96
118
 
97
- title_size = [table_width - percent_num.size - percent_label.size - status_format.size - 3, 1].max
98
- title_size += status_format.size if compact?
99
- title_chunks = feature.title.chars.each_slice(title_size).map { |chrs| chrs.compact.join }
100
-
101
- type_count = Feature::TYPES.keys.size
102
119
  offset_x = ((width - table_width) / 2.0).floor
103
- offset_y = ((height - ERAS - title_chunks.size - 10 - (type_count / [type_count, viewable].min.to_f).ceil) / 2.0).floor
120
+ offset_y = 1
104
121
  cy = 0
105
122
 
106
123
  # positioning and drawing of percentage
@@ -119,6 +136,10 @@ module Cani
119
136
  end
120
137
 
121
138
  # draw possibly multi-line feature title
139
+ title_size = [table_width - percent_num.size - percent_label.size - status_format.size - 3, 1].max
140
+ title_size += status_format.size if compact?
141
+ title_chunks = feature.title.chars.each_slice(title_size).map(&:join)
142
+
122
143
  title_chunks.each do |part|
123
144
  Curses.setpos offset_y + cy, offset_x
124
145
  Curses.addstr part
@@ -138,6 +159,8 @@ module Cani
138
159
  Curses.addstr status_format
139
160
  end
140
161
 
162
+ compact_height = height <= 40
163
+
141
164
  # meaty part, loop through browsers to create
142
165
  # the final feature table
143
166
  browsers[0...viewable].each.with_index do |browser, x|
@@ -156,39 +179,51 @@ module Cani
156
179
 
157
180
  # accordingly increment current browser y for the table header (browser names)
158
181
  # and an additional empty line below the table header
159
- by += 2
182
+ by += 3
160
183
 
161
184
  # draw era's for the current browser
162
185
  era_range.each.with_index do |cur_era, y|
163
- era = browser.eras[cur_era].to_s
164
- colr = color(feature.support_in(browser.name, era))
165
-
166
- # since the current era versions are displayed as 3-line rows
167
- # with an empty line before and after them, when we are at the current
168
- # era we increment era y by an additional 2 for the lines above,
169
- # whenever we are past the current era, increment by 2 for above plus 2
170
- # extra lines below the current era
171
- ey = by + y + (cur_era == era_idx ? 2 : (cur_era > era_idx ? 4 : 0))
186
+ era = browser.eras[cur_era].to_s
187
+ supp_type = feature.support_in(browser.name, era)
188
+ colr = color supp_type
189
+ is_current = cur_era == era_idx
190
+ past_curr = cur_era > era_idx
191
+ top_pad = 1
192
+ bot_pad = compact_height ? 0 : 1
193
+ ey = by + (y * (2 + top_pad + bot_pad)) + (bot_pad.zero? && past_curr ? 1 : 0)
194
+ note_nums = feature.browser_note_nums.fetch(browser.name, {})
195
+ .fetch(era, [])
196
+
197
+ if is_current
198
+ Curses.setpos ey - top_pad - 1, bx - 1
199
+ Curses.attron(color(:era_border)) { Curses.addstr ' ' * (col_width + 2) }
200
+
201
+ Curses.setpos ey + (is_current ? 1 : bot_pad) + 1, bx - 1
202
+ Curses.attron(color(:era_border)) { Curses.addstr ' ' * (col_width + 2) }
203
+ end
172
204
 
173
- # only show relevant browsers
205
+ # only show visible / relevant browsers
174
206
  if browser.usage[era].to_i >= 0.5 || (!era.empty? && cur_era >= era_idx)
175
- Curses.setpos ey, bx
176
- Curses.attron colr do
177
- Curses.addstr era.center(col_width)
178
- end
207
+ ((ey - top_pad)..(ey + (is_current ? 1 : bot_pad))).each do |ry|
208
+ txt = (bot_pad.zero? && !is_current) ? (ry >= ey + (is_current ? 1 : bot_pad) ? era.to_s : ' ')
209
+ : (ry == ey ? era.to_s : ' ')
210
+
211
+ Curses.setpos ry, bx
212
+ Curses.attron(colr) { Curses.addstr txt.center(col_width) }
213
+
214
+ if is_current
215
+ Curses.setpos ry, bx - 1
216
+ Curses.attron(color(:era_border)) { Curses.addstr ' ' }
179
217
 
180
- # previously, we only skipped some lines in order to create
181
- # enough space to create the 3-line current era
182
- # this snippet fills the line before and after the current era
183
- # with the same color that the era has for that browser / feature
184
- if cur_era == era_idx
185
- [-1, 1].each do |relative_y|
186
- Curses.setpos ey - relative_y, bx
187
- Curses.attron colr do
188
- Curses.addstr ' ' * col_width
189
- end
218
+ Curses.setpos ry, offset_x + table_width + 2
219
+ Curses.attron(color(:era_border)) { Curses.addstr ' ' }
190
220
  end
191
221
  end
222
+
223
+ if note_nums.any?
224
+ Curses.setpos ey - top_pad, bx
225
+ Curses.attron(note_color(supp_type)) { Curses.addstr ' ' + note_nums.join(' ') }
226
+ end
192
227
  end
193
228
  end
194
229
  end
@@ -197,12 +232,14 @@ module Cani
197
232
  # plus the 4 lines around the current era
198
233
  # plus the 1 line of browser names
199
234
  # plus the 2 blank lines above and below the eras
200
- cy += ERAS + 7
235
+ cy += (ERAS - 1) * (compact_height ? 3 : 4) + ERAS
201
236
 
202
- # print legend header
203
- Curses.setpos offset_y + cy, offset_x
204
- Curses.attron color(:header) do
205
- Curses.addstr legend_format
237
+ if height > cy + 3
238
+ # print legend header
239
+ Curses.setpos offset_y + cy, offset_x
240
+ Curses.attron color(:header) do
241
+ Curses.addstr legend_format
242
+ end
206
243
  end
207
244
 
208
245
  # increment current y by 2
@@ -212,16 +249,64 @@ module Cani
212
249
 
213
250
  # loop through all features to create a legend
214
251
  # showing which label belongs to which color
215
- Feature::TYPES.values.each_slice viewable do |group|
216
- group.compact.each.with_index do |type, lx|
217
- Curses.setpos offset_y + cy, offset_x + lx * col_width + lx
218
- Curses.attron color(type[:name], :fg) do
219
- Curses.addstr "#{type[:short]}(#{type[:symbol]})".center(col_width)
252
+ if height > cy + 1
253
+ Feature::TYPES.values.each_slice viewable do |group|
254
+ group.compact.each.with_index do |type, lx|
255
+ Curses.setpos offset_y + cy, offset_x + lx * col_width + lx
256
+ Curses.attron color(type[:name], :fg) do
257
+ Curses.addstr "#{type[:short]}(#{type[:symbol]})".center(col_width)
258
+ end
220
259
  end
260
+
261
+ # if there is more than one group, print the next
262
+ # group on a new line
263
+ cy += 1
264
+ end
265
+ end
266
+
267
+ # add extra empty line after legend
268
+ cy += 1
269
+
270
+ notes_chunked = feature.notes.map { |nt| nt.chars.each_slice(table_width).map(&:join).map(&:strip) }
271
+ num_chunked = feature.notes_by_num.each_with_object({}) { |(k, nt), h| h[k] = nt.chars.each_slice(table_width - 5).map(&:join).map(&:strip) }
272
+ notes_total = notes_chunked.map(&:size).sum + num_chunked.map(&:size).sum
273
+
274
+ if height > cy + 2 && (notes_chunked.any? || num_chunked.any?)
275
+ # print notes header
276
+ Curses.setpos offset_y + cy, offset_x
277
+ Curses.attron color(:header) do
278
+ Curses.addstr notes_format
279
+ end
280
+ end
281
+
282
+ # add two new lines, one for the notes header
283
+ # and one empty line below it
284
+ cy += 2
285
+
286
+ notes_chunked.each do |chunks|
287
+ break if cy + 1 + chunks.size > height
288
+ chunks.each do |part|
289
+ Curses.setpos offset_y + cy, offset_x
290
+ Curses.addstr part
291
+ cy += 1
292
+ end
293
+
294
+ cy += 1
295
+ end
296
+
297
+ num_chunked.each do |num, chunks|
298
+ break if cy + 1 + chunks.size > height
299
+ Curses.setpos offset_y + cy, offset_x
300
+ Curses.attron color(:header) do
301
+ Curses.addstr num.center(3)
302
+ end
303
+
304
+ chunks.each do |part|
305
+ Curses.setpos offset_y + cy, offset_x + 5
306
+ Curses.addstr part
307
+ cy += 1
221
308
  end
222
309
 
223
- # if there is more than one group, print the next
224
- # group on a new line
225
310
  cy += 1
226
311
  end
227
312
 
@@ -262,20 +347,24 @@ module Cani
262
347
  end
263
348
 
264
349
  @col_width = [colw, Feature::TYPES.map { |(_, h)| h[:short].size }.max + 3].max
265
- @table_width = tablew
350
+ @table_width = tablew - 2 # vertical padding at start and end of current era line
266
351
  end
267
352
 
268
353
  def compact?
269
354
  width < COMPACT
270
355
  end
271
356
 
272
- def color(key, type = :bg)
357
+ def color(key, type = :bg, source = COLORS)
273
358
  target = key.to_s.downcase.to_sym
274
359
  type = type.to_sym
275
360
 
276
- COLORS.find { |(k, _)| k == target }.to_a
361
+ source.find { |(k, _)| k == target }.to_a
277
362
  .fetch(1, {})
278
- .fetch(type, COLORS[:default][type])
363
+ .fetch(type, source[:default][type])
364
+ end
365
+
366
+ def note_color(status)
367
+ color status, :fg, NOTE_COLORS
279
368
  end
280
369
 
281
370
  def status_color(status)
data/lib/cani/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cani
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cani
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sidney Liebrand
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-19 00:00:00.000000000 Z
11
+ date: 2018-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize