cani 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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