~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/mattn/go-colorable/colorable_windows.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package colorable
2
 
 
3
 
import (
4
 
        "bytes"
5
 
        "fmt"
6
 
        "io"
7
 
        "os"
8
 
        "strconv"
9
 
        "strings"
10
 
        "syscall"
11
 
        "unsafe"
12
 
 
13
 
        "github.com/mattn/go-isatty"
14
 
)
15
 
 
16
 
const (
17
 
        foregroundBlue      = 0x1
18
 
        foregroundGreen     = 0x2
19
 
        foregroundRed       = 0x4
20
 
        foregroundIntensity = 0x8
21
 
        foregroundMask      = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
22
 
        backgroundBlue      = 0x10
23
 
        backgroundGreen     = 0x20
24
 
        backgroundRed       = 0x40
25
 
        backgroundIntensity = 0x80
26
 
        backgroundMask      = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
27
 
)
28
 
 
29
 
type wchar uint16
30
 
type short int16
31
 
type dword uint32
32
 
type word uint16
33
 
 
34
 
type coord struct {
35
 
        x short
36
 
        y short
37
 
}
38
 
 
39
 
type smallRect struct {
40
 
        left   short
41
 
        top    short
42
 
        right  short
43
 
        bottom short
44
 
}
45
 
 
46
 
type consoleScreenBufferInfo struct {
47
 
        size              coord
48
 
        cursorPosition    coord
49
 
        attributes        word
50
 
        window            smallRect
51
 
        maximumWindowSize coord
52
 
}
53
 
 
54
 
var (
55
 
        kernel32                       = syscall.NewLazyDLL("kernel32.dll")
56
 
        procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
57
 
        procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
58
 
)
59
 
 
60
 
type Writer struct {
61
 
        out     io.Writer
62
 
        handle  syscall.Handle
63
 
        lastbuf bytes.Buffer
64
 
        oldattr word
65
 
}
66
 
 
67
 
func NewColorableStdout() io.Writer {
68
 
        var csbi consoleScreenBufferInfo
69
 
        out := os.Stdout
70
 
        if !isatty.IsTerminal(out.Fd()) {
71
 
                return out
72
 
        }
73
 
        handle := syscall.Handle(out.Fd())
74
 
        procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
75
 
        return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
76
 
}
77
 
 
78
 
func NewColorableStderr() io.Writer {
79
 
        var csbi consoleScreenBufferInfo
80
 
        out := os.Stderr
81
 
        if !isatty.IsTerminal(out.Fd()) {
82
 
                return out
83
 
        }
84
 
        handle := syscall.Handle(out.Fd())
85
 
        procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
86
 
        return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
87
 
}
88
 
 
89
 
var color256 = map[int]int{
90
 
        0:   0x000000,
91
 
        1:   0x800000,
92
 
        2:   0x008000,
93
 
        3:   0x808000,
94
 
        4:   0x000080,
95
 
        5:   0x800080,
96
 
        6:   0x008080,
97
 
        7:   0xc0c0c0,
98
 
        8:   0x808080,
99
 
        9:   0xff0000,
100
 
        10:  0x00ff00,
101
 
        11:  0xffff00,
102
 
        12:  0x0000ff,
103
 
        13:  0xff00ff,
104
 
        14:  0x00ffff,
105
 
        15:  0xffffff,
106
 
        16:  0x000000,
107
 
        17:  0x00005f,
108
 
        18:  0x000087,
109
 
        19:  0x0000af,
110
 
        20:  0x0000d7,
111
 
        21:  0x0000ff,
112
 
        22:  0x005f00,
113
 
        23:  0x005f5f,
114
 
        24:  0x005f87,
115
 
        25:  0x005faf,
116
 
        26:  0x005fd7,
117
 
        27:  0x005fff,
118
 
        28:  0x008700,
119
 
        29:  0x00875f,
120
 
        30:  0x008787,
121
 
        31:  0x0087af,
122
 
        32:  0x0087d7,
123
 
        33:  0x0087ff,
124
 
        34:  0x00af00,
125
 
        35:  0x00af5f,
126
 
        36:  0x00af87,
127
 
        37:  0x00afaf,
128
 
        38:  0x00afd7,
129
 
        39:  0x00afff,
130
 
        40:  0x00d700,
131
 
        41:  0x00d75f,
132
 
        42:  0x00d787,
133
 
        43:  0x00d7af,
134
 
        44:  0x00d7d7,
135
 
        45:  0x00d7ff,
136
 
        46:  0x00ff00,
137
 
        47:  0x00ff5f,
138
 
        48:  0x00ff87,
139
 
        49:  0x00ffaf,
140
 
        50:  0x00ffd7,
141
 
        51:  0x00ffff,
142
 
        52:  0x5f0000,
143
 
        53:  0x5f005f,
144
 
        54:  0x5f0087,
145
 
        55:  0x5f00af,
146
 
        56:  0x5f00d7,
147
 
        57:  0x5f00ff,
148
 
        58:  0x5f5f00,
149
 
        59:  0x5f5f5f,
150
 
        60:  0x5f5f87,
151
 
        61:  0x5f5faf,
152
 
        62:  0x5f5fd7,
153
 
        63:  0x5f5fff,
154
 
        64:  0x5f8700,
155
 
        65:  0x5f875f,
156
 
        66:  0x5f8787,
157
 
        67:  0x5f87af,
158
 
        68:  0x5f87d7,
159
 
        69:  0x5f87ff,
160
 
        70:  0x5faf00,
161
 
        71:  0x5faf5f,
162
 
        72:  0x5faf87,
163
 
        73:  0x5fafaf,
164
 
        74:  0x5fafd7,
165
 
        75:  0x5fafff,
166
 
        76:  0x5fd700,
167
 
        77:  0x5fd75f,
168
 
        78:  0x5fd787,
169
 
        79:  0x5fd7af,
170
 
        80:  0x5fd7d7,
171
 
        81:  0x5fd7ff,
172
 
        82:  0x5fff00,
173
 
        83:  0x5fff5f,
174
 
        84:  0x5fff87,
175
 
        85:  0x5fffaf,
176
 
        86:  0x5fffd7,
177
 
        87:  0x5fffff,
178
 
        88:  0x870000,
179
 
        89:  0x87005f,
180
 
        90:  0x870087,
181
 
        91:  0x8700af,
182
 
        92:  0x8700d7,
183
 
        93:  0x8700ff,
184
 
        94:  0x875f00,
185
 
        95:  0x875f5f,
186
 
        96:  0x875f87,
187
 
        97:  0x875faf,
188
 
        98:  0x875fd7,
189
 
        99:  0x875fff,
190
 
        100: 0x878700,
191
 
        101: 0x87875f,
192
 
        102: 0x878787,
193
 
        103: 0x8787af,
194
 
        104: 0x8787d7,
195
 
        105: 0x8787ff,
196
 
        106: 0x87af00,
197
 
        107: 0x87af5f,
198
 
        108: 0x87af87,
199
 
        109: 0x87afaf,
200
 
        110: 0x87afd7,
201
 
        111: 0x87afff,
202
 
        112: 0x87d700,
203
 
        113: 0x87d75f,
204
 
        114: 0x87d787,
205
 
        115: 0x87d7af,
206
 
        116: 0x87d7d7,
207
 
        117: 0x87d7ff,
208
 
        118: 0x87ff00,
209
 
        119: 0x87ff5f,
210
 
        120: 0x87ff87,
211
 
        121: 0x87ffaf,
212
 
        122: 0x87ffd7,
213
 
        123: 0x87ffff,
214
 
        124: 0xaf0000,
215
 
        125: 0xaf005f,
216
 
        126: 0xaf0087,
217
 
        127: 0xaf00af,
218
 
        128: 0xaf00d7,
219
 
        129: 0xaf00ff,
220
 
        130: 0xaf5f00,
221
 
        131: 0xaf5f5f,
222
 
        132: 0xaf5f87,
223
 
        133: 0xaf5faf,
224
 
        134: 0xaf5fd7,
225
 
        135: 0xaf5fff,
226
 
        136: 0xaf8700,
227
 
        137: 0xaf875f,
228
 
        138: 0xaf8787,
229
 
        139: 0xaf87af,
230
 
        140: 0xaf87d7,
231
 
        141: 0xaf87ff,
232
 
        142: 0xafaf00,
233
 
        143: 0xafaf5f,
234
 
        144: 0xafaf87,
235
 
        145: 0xafafaf,
236
 
        146: 0xafafd7,
237
 
        147: 0xafafff,
238
 
        148: 0xafd700,
239
 
        149: 0xafd75f,
240
 
        150: 0xafd787,
241
 
        151: 0xafd7af,
242
 
        152: 0xafd7d7,
243
 
        153: 0xafd7ff,
244
 
        154: 0xafff00,
245
 
        155: 0xafff5f,
246
 
        156: 0xafff87,
247
 
        157: 0xafffaf,
248
 
        158: 0xafffd7,
249
 
        159: 0xafffff,
250
 
        160: 0xd70000,
251
 
        161: 0xd7005f,
252
 
        162: 0xd70087,
253
 
        163: 0xd700af,
254
 
        164: 0xd700d7,
255
 
        165: 0xd700ff,
256
 
        166: 0xd75f00,
257
 
        167: 0xd75f5f,
258
 
        168: 0xd75f87,
259
 
        169: 0xd75faf,
260
 
        170: 0xd75fd7,
261
 
        171: 0xd75fff,
262
 
        172: 0xd78700,
263
 
        173: 0xd7875f,
264
 
        174: 0xd78787,
265
 
        175: 0xd787af,
266
 
        176: 0xd787d7,
267
 
        177: 0xd787ff,
268
 
        178: 0xd7af00,
269
 
        179: 0xd7af5f,
270
 
        180: 0xd7af87,
271
 
        181: 0xd7afaf,
272
 
        182: 0xd7afd7,
273
 
        183: 0xd7afff,
274
 
        184: 0xd7d700,
275
 
        185: 0xd7d75f,
276
 
        186: 0xd7d787,
277
 
        187: 0xd7d7af,
278
 
        188: 0xd7d7d7,
279
 
        189: 0xd7d7ff,
280
 
        190: 0xd7ff00,
281
 
        191: 0xd7ff5f,
282
 
        192: 0xd7ff87,
283
 
        193: 0xd7ffaf,
284
 
        194: 0xd7ffd7,
285
 
        195: 0xd7ffff,
286
 
        196: 0xff0000,
287
 
        197: 0xff005f,
288
 
        198: 0xff0087,
289
 
        199: 0xff00af,
290
 
        200: 0xff00d7,
291
 
        201: 0xff00ff,
292
 
        202: 0xff5f00,
293
 
        203: 0xff5f5f,
294
 
        204: 0xff5f87,
295
 
        205: 0xff5faf,
296
 
        206: 0xff5fd7,
297
 
        207: 0xff5fff,
298
 
        208: 0xff8700,
299
 
        209: 0xff875f,
300
 
        210: 0xff8787,
301
 
        211: 0xff87af,
302
 
        212: 0xff87d7,
303
 
        213: 0xff87ff,
304
 
        214: 0xffaf00,
305
 
        215: 0xffaf5f,
306
 
        216: 0xffaf87,
307
 
        217: 0xffafaf,
308
 
        218: 0xffafd7,
309
 
        219: 0xffafff,
310
 
        220: 0xffd700,
311
 
        221: 0xffd75f,
312
 
        222: 0xffd787,
313
 
        223: 0xffd7af,
314
 
        224: 0xffd7d7,
315
 
        225: 0xffd7ff,
316
 
        226: 0xffff00,
317
 
        227: 0xffff5f,
318
 
        228: 0xffff87,
319
 
        229: 0xffffaf,
320
 
        230: 0xffffd7,
321
 
        231: 0xffffff,
322
 
        232: 0x080808,
323
 
        233: 0x121212,
324
 
        234: 0x1c1c1c,
325
 
        235: 0x262626,
326
 
        236: 0x303030,
327
 
        237: 0x3a3a3a,
328
 
        238: 0x444444,
329
 
        239: 0x4e4e4e,
330
 
        240: 0x585858,
331
 
        241: 0x626262,
332
 
        242: 0x6c6c6c,
333
 
        243: 0x767676,
334
 
        244: 0x808080,
335
 
        245: 0x8a8a8a,
336
 
        246: 0x949494,
337
 
        247: 0x9e9e9e,
338
 
        248: 0xa8a8a8,
339
 
        249: 0xb2b2b2,
340
 
        250: 0xbcbcbc,
341
 
        251: 0xc6c6c6,
342
 
        252: 0xd0d0d0,
343
 
        253: 0xdadada,
344
 
        254: 0xe4e4e4,
345
 
        255: 0xeeeeee,
346
 
}
347
 
 
348
 
func (w *Writer) Write(data []byte) (n int, err error) {
349
 
        var csbi consoleScreenBufferInfo
350
 
        procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
351
 
 
352
 
        er := bytes.NewBuffer(data)
353
 
loop:
354
 
        for {
355
 
                r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
356
 
                if r1 == 0 {
357
 
                        break loop
358
 
                }
359
 
 
360
 
                c1, _, err := er.ReadRune()
361
 
                if err != nil {
362
 
                        break loop
363
 
                }
364
 
                if c1 != 0x1b {
365
 
                        fmt.Fprint(w.out, string(c1))
366
 
                        continue
367
 
                }
368
 
                c2, _, err := er.ReadRune()
369
 
                if err != nil {
370
 
                        w.lastbuf.WriteRune(c1)
371
 
                        break loop
372
 
                }
373
 
                if c2 != 0x5b {
374
 
                        w.lastbuf.WriteRune(c1)
375
 
                        w.lastbuf.WriteRune(c2)
376
 
                        continue
377
 
                }
378
 
 
379
 
                var buf bytes.Buffer
380
 
                var m rune
381
 
                for {
382
 
                        c, _, err := er.ReadRune()
383
 
                        if err != nil {
384
 
                                w.lastbuf.WriteRune(c1)
385
 
                                w.lastbuf.WriteRune(c2)
386
 
                                w.lastbuf.Write(buf.Bytes())
387
 
                                break loop
388
 
                        }
389
 
                        if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
390
 
                                m = c
391
 
                                break
392
 
                        }
393
 
                        buf.Write([]byte(string(c)))
394
 
                }
395
 
 
396
 
                switch m {
397
 
                case 'm':
398
 
                        attr := csbi.attributes
399
 
                        cs := buf.String()
400
 
                        if cs == "" {
401
 
                                procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
402
 
                                continue
403
 
                        }
404
 
                        token := strings.Split(cs, ";")
405
 
                        for i, ns := range token {
406
 
                                if n, err = strconv.Atoi(ns); err == nil {
407
 
                                        switch {
408
 
                                        case n == 0 || n == 100:
409
 
                                                attr = w.oldattr
410
 
                                        case 1 <= n && n <= 5:
411
 
                                                attr |= foregroundIntensity
412
 
                                        case n == 7:
413
 
                                                attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
414
 
                                        case 22 == n || n == 25 || n == 25:
415
 
                                                attr |= foregroundIntensity
416
 
                                        case n == 27:
417
 
                                                attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
418
 
                                        case 30 <= n && n <= 37:
419
 
                                                attr = (attr & backgroundMask)
420
 
                                                if (n-30)&1 != 0 {
421
 
                                                        attr |= foregroundRed
422
 
                                                }
423
 
                                                if (n-30)&2 != 0 {
424
 
                                                        attr |= foregroundGreen
425
 
                                                }
426
 
                                                if (n-30)&4 != 0 {
427
 
                                                        attr |= foregroundBlue
428
 
                                                }
429
 
                                        case n == 38: // set foreground color.
430
 
                                                if i < len(token)-2 && token[i+1] == "5" {
431
 
                                                        if n256, err := strconv.Atoi(token[i+2]); err == nil {
432
 
                                                                if n256foreAttr == nil {
433
 
                                                                        n256setup()
434
 
                                                                }
435
 
                                                                attr &= backgroundMask
436
 
                                                                attr |= n256foreAttr[n256]
437
 
                                                                i += 2
438
 
                                                        }
439
 
                                                } else {
440
 
                                                        attr = attr & (w.oldattr & backgroundMask)
441
 
                                                }
442
 
                                        case n == 39: // reset foreground color.
443
 
                                                attr &= backgroundMask
444
 
                                                attr |= w.oldattr & foregroundMask
445
 
                                        case 40 <= n && n <= 47:
446
 
                                                attr = (attr & foregroundMask)
447
 
                                                if (n-40)&1 != 0 {
448
 
                                                        attr |= backgroundRed
449
 
                                                }
450
 
                                                if (n-40)&2 != 0 {
451
 
                                                        attr |= backgroundGreen
452
 
                                                }
453
 
                                                if (n-40)&4 != 0 {
454
 
                                                        attr |= backgroundBlue
455
 
                                                }
456
 
                                        case n == 48: // set background color.
457
 
                                                if i < len(token)-2 && token[i+1] == "5" {
458
 
                                                        if n256, err := strconv.Atoi(token[i+2]); err == nil {
459
 
                                                                if n256backAttr == nil {
460
 
                                                                        n256setup()
461
 
                                                                }
462
 
                                                                attr &= foregroundMask
463
 
                                                                attr |= n256backAttr[n256]
464
 
                                                                i += 2
465
 
                                                        }
466
 
                                                } else {
467
 
                                                        attr = attr & (w.oldattr & foregroundMask)
468
 
                                                }
469
 
                                        case n == 49: // reset foreground color.
470
 
                                                attr &= foregroundMask
471
 
                                                attr |= w.oldattr & backgroundMask
472
 
                                        }
473
 
                                        procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
474
 
                                }
475
 
                        }
476
 
                }
477
 
        }
478
 
        return len(data) - w.lastbuf.Len(), nil
479
 
}
480
 
 
481
 
type consoleColor struct {
482
 
        red       bool
483
 
        green     bool
484
 
        blue      bool
485
 
        intensity bool
486
 
}
487
 
 
488
 
func minmax3(a, b, c int) (min, max int) {
489
 
        if a < b {
490
 
                if b < c {
491
 
                        return a, c
492
 
                } else if a < c {
493
 
                        return a, b
494
 
                } else {
495
 
                        return c, b
496
 
                }
497
 
        } else {
498
 
                if a < c {
499
 
                        return b, c
500
 
                } else if b < c {
501
 
                        return b, a
502
 
                } else {
503
 
                        return c, a
504
 
                }
505
 
        }
506
 
}
507
 
 
508
 
func toConsoleColor(rgb int) (c consoleColor) {
509
 
        r, g, b := (rgb&0xFF0000)>>16, (rgb&0x00FF00)>>8, rgb&0x0000FF
510
 
        min, max := minmax3(r, g, b)
511
 
        a := (min + max) / 2
512
 
        if r < 128 && g < 128 && b < 128 {
513
 
                if r >= a {
514
 
                        c.red = true
515
 
                }
516
 
                if g >= a {
517
 
                        c.green = true
518
 
                }
519
 
                if b >= a {
520
 
                        c.blue = true
521
 
                }
522
 
                // non-intensed white is lighter than intensed black, so swap those.
523
 
                if c.red && c.green && c.blue {
524
 
                        c.red, c.green, c.blue = false, false, false
525
 
                        c.intensity = true
526
 
                }
527
 
        } else {
528
 
                if min < 128 {
529
 
                        min = 128
530
 
                        a = (min + max) / 2
531
 
                }
532
 
                if r >= a {
533
 
                        c.red = true
534
 
                }
535
 
                if g >= a {
536
 
                        c.green = true
537
 
                }
538
 
                if b >= a {
539
 
                        c.blue = true
540
 
                }
541
 
                c.intensity = true
542
 
                // intensed black is darker than non-intensed white, so swap those.
543
 
                if !c.red && !c.green && !c.blue {
544
 
                        c.red, c.green, c.blue = true, true, true
545
 
                        c.intensity = false
546
 
                }
547
 
        }
548
 
        return c
549
 
}
550
 
 
551
 
func (c consoleColor) foregroundAttr() (attr word) {
552
 
        if c.red {
553
 
                attr |= foregroundRed
554
 
        }
555
 
        if c.green {
556
 
                attr |= foregroundGreen
557
 
        }
558
 
        if c.blue {
559
 
                attr |= foregroundBlue
560
 
        }
561
 
        if c.intensity {
562
 
                attr |= foregroundIntensity
563
 
        }
564
 
        return
565
 
}
566
 
 
567
 
func (c consoleColor) backgroundAttr() (attr word) {
568
 
        if c.red {
569
 
                attr |= backgroundRed
570
 
        }
571
 
        if c.green {
572
 
                attr |= backgroundGreen
573
 
        }
574
 
        if c.blue {
575
 
                attr |= backgroundBlue
576
 
        }
577
 
        if c.intensity {
578
 
                attr |= backgroundIntensity
579
 
        }
580
 
        return
581
 
}
582
 
 
583
 
var n256foreAttr []word
584
 
var n256backAttr []word
585
 
 
586
 
func n256setup() {
587
 
        n256foreAttr = make([]word, 256)
588
 
        n256backAttr = make([]word, 256)
589
 
        for i, rgb := range color256 {
590
 
                c := toConsoleColor(rgb)
591
 
                n256foreAttr[i] = c.foregroundAttr()
592
 
                n256backAttr[i] = c.backgroundAttr()
593
 
        }
594
 
}