pax_global_header 0000666 0000000 0000000 00000000064 14125072333 0014512 g ustar 00root root 0000000 0000000 52 comment=8b71cc96ebdcf1786021219160dacfda2b51cdbe
ansiterm-1.0.0/ 0000775 0000000 0000000 00000000000 14125072333 0013332 5 ustar 00root root 0000000 0000000 ansiterm-1.0.0/LICENSE 0000664 0000000 0000000 00000021501 14125072333 0014336 0 ustar 00root root 0000000 0000000 All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
ansiterm-1.0.0/Makefile 0000664 0000000 0000000 00000000551 14125072333 0014773 0 ustar 00root root 0000000 0000000 # Copyright 2016 Canonical Ltd.
# Licensed under the LGPLv3, see LICENCE file for details.
default: check
check:
go test
docs:
godoc2md github.com/juju/ansiterm > README.md
sed -i 's|\[godoc-link-here\]|[](https://godoc.org/github.com/juju/ansiterm)|' README.md
.PHONY: default check docs
ansiterm-1.0.0/README.md 0000664 0000000 0000000 00000013133 14125072333 0014612 0 ustar 00root root 0000000 0000000
# ansiterm
import "github.com/juju/ansiterm"
Package ansiterm provides a Writer that writes out the ANSI escape
codes for color and styles.
## type Color
``` go
type Color int
```
Color represents one of the standard 16 ANSI colors.
``` go
const (
Default Color
Black
Red
Green
Yellow
Blue
Magenta
Cyan
Gray
DarkGray
BrightRed
BrightGreen
BrightYellow
BrightBlue
BrightMagenta
BrightCyan
White
)
```
### func (Color) String
``` go
func (c Color) String() string
```
String returns the name of the color.
## type Context
``` go
type Context struct {
Foreground Color
Background Color
Styles []Style
}
```
Context provides a way to specify both foreground and background colors
along with other styles and write text to a Writer with those colors and
styles.
### func Background
``` go
func Background(color Color) *Context
```
Background is a convenience function that creates a Context with the
specified color as the background color.
### func Foreground
``` go
func Foreground(color Color) *Context
```
Foreground is a convenience function that creates a Context with the
specified color as the foreground color.
### func Styles
``` go
func Styles(styles ...Style) *Context
```
Styles is a convenience function that creates a Context with the
specified styles set.
### func (\*Context) Fprint
``` go
func (c *Context) Fprint(w sgrWriter, args ...interface{})
```
Fprint will set the sgr values of the writer to the specified foreground,
background and styles, then formats using the default formats for its
operands and writes to w. Spaces are added between operands when neither is
a string. It returns the number of bytes written and any write error
encountered.
### func (\*Context) Fprintf
``` go
func (c *Context) Fprintf(w sgrWriter, format string, args ...interface{})
```
Fprintf will set the sgr values of the writer to the specified
foreground, background and styles, then write the formatted string,
then reset the writer.
### func (\*Context) SetBackground
``` go
func (c *Context) SetBackground(color Color) *Context
```
SetBackground sets the background to the specified color.
### func (\*Context) SetForeground
``` go
func (c *Context) SetForeground(color Color) *Context
```
SetForeground sets the foreground to the specified color.
### func (\*Context) SetStyle
``` go
func (c *Context) SetStyle(styles ...Style) *Context
```
SetStyle replaces the styles with the new values.
## type Style
``` go
type Style int
```
``` go
const (
Bold Style
Faint
Italic
Underline
Blink
Reverse
Strikethrough
Conceal
)
```
### func (Style) String
``` go
func (s Style) String() string
```
## type TabWriter
``` go
type TabWriter struct {
Writer
// contains filtered or unexported fields
}
```
TabWriter is a filter that inserts padding around tab-delimited
columns in its input to align them in the output.
It also setting of colors and styles over and above the standard
tabwriter package.
### func NewTabWriter
``` go
func NewTabWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter
```
NewTabWriter returns a writer that is able to set colors and styels.
The ansi escape codes are stripped for width calculations.
### func (\*TabWriter) Flush
``` go
func (t *TabWriter) Flush() error
```
Flush should be called after the last call to Write to ensure
that any data buffered in the Writer is written to output. Any
incomplete escape sequence at the end is considered
complete for formatting purposes.
### func (\*TabWriter) Init
``` go
func (t *TabWriter) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter
```
A Writer must be initialized with a call to Init. The first parameter (output)
specifies the filter output. The remaining parameters control the formatting:
minwidth minimal cell width including any padding
tabwidth width of tab characters (equivalent number of spaces)
padding padding added to a cell before computing its width
padchar ASCII char used for padding
if padchar == '\t', the Writer will assume that the
width of a '\t' in the formatted output is tabwidth,
and cells are left-aligned independent of align_left
(for correct-looking results, tabwidth must correspond
to the tab width in the viewer displaying the result)
flags formatting control
## type Writer
``` go
type Writer struct {
io.Writer
// contains filtered or unexported fields
}
```
Writer allows colors and styles to be specified. If the io.Writer
is not a terminal capable of color, all attempts to set colors or
styles are no-ops.
### func NewWriter
``` go
func NewWriter(w io.Writer) *Writer
```
NewWriter returns a Writer that allows the caller to specify colors and
styles. If the io.Writer is not a terminal capable of color, all attempts
to set colors or styles are no-ops.
### func (\*Writer) ClearStyle
``` go
func (w *Writer) ClearStyle(s Style)
```
ClearStyle clears the text style.
### func (\*Writer) Reset
``` go
func (w *Writer) Reset()
```
Reset returns the default foreground and background colors with no styles.
### func (\*Writer) SetBackground
``` go
func (w *Writer) SetBackground(c Color)
```
SetBackground sets the background color.
### func (\*Writer) SetForeground
``` go
func (w *Writer) SetForeground(c Color)
```
SetForeground sets the foreground color.
### func (\*Writer) SetStyle
``` go
func (w *Writer) SetStyle(s Style)
```
SetStyle sets the text style.
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) ansiterm-1.0.0/attribute.go 0000664 0000000 0000000 00000002040 14125072333 0015660 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"fmt"
"sort"
"strings"
)
type attribute int
const (
unknownAttribute attribute = -1
reset attribute = 0
)
// sgr returns the escape sequence for the Select Graphic Rendition
// for the attribute.
func (a attribute) sgr() string {
if a < 0 {
return ""
}
return fmt.Sprintf("\x1b[%dm", a)
}
type attributes []attribute
func (a attributes) Len() int { return len(a) }
func (a attributes) Less(i, j int) bool { return a[i] < a[j] }
func (a attributes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// sgr returns the combined escape sequence for the Select Graphic Rendition
// for the sequence of attributes.
func (a attributes) sgr() string {
switch len(a) {
case 0:
return ""
case 1:
return a[0].sgr()
default:
sort.Sort(a)
var values []string
for _, attr := range a {
values = append(values, fmt.Sprint(attr))
}
return fmt.Sprintf("\x1b[%sm", strings.Join(values, ";"))
}
}
ansiterm-1.0.0/attribute_test.go 0000664 0000000 0000000 00000001455 14125072333 0016730 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import gc "gopkg.in/check.v1"
type attributeSuite struct{}
var _ = gc.Suite(&attributeSuite{})
func (*attributeSuite) TestSGR(c *gc.C) {
c.Check(unknownAttribute.sgr(), gc.Equals, "")
c.Check(reset.sgr(), gc.Equals, "\x1b[0m")
var yellow attribute = 33
c.Check(yellow.sgr(), gc.Equals, "\x1b[33m")
}
func (*attributeSuite) TestAttributes(c *gc.C) {
var a attributes
c.Check(a.sgr(), gc.Equals, "")
a = append(a, Yellow.foreground())
c.Check(a.sgr(), gc.Equals, "\x1b[33m")
a = append(a, Blue.background())
c.Check(a.sgr(), gc.Equals, "\x1b[33;44m")
// Add bold to the end to show sorting of the attributes.
a = append(a, Bold.enable())
c.Check(a.sgr(), gc.Equals, "\x1b[1;33;44m")
}
ansiterm-1.0.0/color.go 0000664 0000000 0000000 00000003341 14125072333 0015000 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
const (
_ Color = iota
Default
Black
Red
Green
Yellow
Blue
Magenta
Cyan
Gray
DarkGray
BrightRed
BrightGreen
BrightYellow
BrightBlue
BrightMagenta
BrightCyan
White
)
// Color represents one of the standard 16 ANSI colors.
type Color int
// String returns the name of the color.
func (c Color) String() string {
switch c {
case Default:
return "default"
case Black:
return "black"
case Red:
return "red"
case Green:
return "green"
case Yellow:
return "yellow"
case Blue:
return "blue"
case Magenta:
return "magenta"
case Cyan:
return "cyan"
case Gray:
return "gray"
case DarkGray:
return "darkgray"
case BrightRed:
return "brightred"
case BrightGreen:
return "brightgreen"
case BrightYellow:
return "brightyellow"
case BrightBlue:
return "brightblue"
case BrightMagenta:
return "brightmagenta"
case BrightCyan:
return "brightcyan"
case White:
return "white"
default:
return ""
}
}
func (c Color) foreground() attribute {
switch c {
case Default:
return 39
case Black:
return 30
case Red:
return 31
case Green:
return 32
case Yellow:
return 33
case Blue:
return 34
case Magenta:
return 35
case Cyan:
return 36
case Gray:
return 37
case DarkGray:
return 90
case BrightRed:
return 91
case BrightGreen:
return 92
case BrightYellow:
return 93
case BrightBlue:
return 94
case BrightMagenta:
return 95
case BrightCyan:
return 96
case White:
return 97
default:
return unknownAttribute
}
}
func (c Color) background() attribute {
value := c.foreground()
if value != unknownAttribute {
return value + 10
}
return value
}
ansiterm-1.0.0/color_test.go 0000664 0000000 0000000 00000001115 14125072333 0016034 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import gc "gopkg.in/check.v1"
type colorSuite struct{}
var _ = gc.Suite(&colorSuite{})
func (*colorSuite) TestString(c *gc.C) {
c.Check(Default.String(), gc.Equals, "default")
c.Check(Yellow.String(), gc.Equals, "yellow")
c.Check(BrightMagenta.String(), gc.Equals, "brightmagenta")
var blank Color
c.Check(blank.String(), gc.Equals, "")
var huge Color = 1234
c.Check(huge.String(), gc.Equals, "")
var negative Color = -1
c.Check(negative.String(), gc.Equals, "")
}
ansiterm-1.0.0/context.go 0000664 0000000 0000000 00000005124 14125072333 0015347 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"fmt"
"io"
)
// Context provides a way to specify both foreground and background colors
// along with other styles and write text to a Writer with those colors and
// styles.
type Context struct {
Foreground Color
Background Color
Styles []Style
}
// Foreground is a convenience function that creates a Context with the
// specified color as the foreground color.
func Foreground(color Color) *Context {
return &Context{Foreground: color}
}
// Background is a convenience function that creates a Context with the
// specified color as the background color.
func Background(color Color) *Context {
return &Context{Background: color}
}
// Styles is a convenience function that creates a Context with the
// specified styles set.
func Styles(styles ...Style) *Context {
return &Context{Styles: styles}
}
// SetForeground sets the foreground to the specified color.
func (c *Context) SetForeground(color Color) *Context {
c.Foreground = color
return c
}
// SetBackground sets the background to the specified color.
func (c *Context) SetBackground(color Color) *Context {
c.Background = color
return c
}
// SetStyle replaces the styles with the new values.
func (c *Context) SetStyle(styles ...Style) *Context {
c.Styles = styles
return c
}
type sgrWriter interface {
io.Writer
writeSGR(value sgr)
}
// Fprintf will set the sgr values of the writer to the specified
// foreground, background and styles, then write the formatted string,
// then reset the writer.
func (c *Context) Fprintf(w sgrWriter, format string, args ...interface{}) {
w.writeSGR(c)
fmt.Fprintf(w, format, args...)
w.writeSGR(reset)
}
// Fprint will set the sgr values of the writer to the specified foreground,
// background and styles, then formats using the default formats for its
// operands and writes to w. Spaces are added between operands when neither is
// a string. It returns the number of bytes written and any write error
// encountered.
func (c *Context) Fprint(w sgrWriter, args ...interface{}) {
w.writeSGR(c)
fmt.Fprint(w, args...)
w.writeSGR(reset)
}
func (c *Context) sgr() string {
var values attributes
if foreground := c.Foreground.foreground(); foreground != unknownAttribute {
values = append(values, foreground)
}
if background := c.Background.background(); background != unknownAttribute {
values = append(values, background)
}
for _, style := range c.Styles {
if value := style.enable(); value != unknownAttribute {
values = append(values, value)
}
}
return values.sgr()
}
ansiterm-1.0.0/context_test.go 0000664 0000000 0000000 00000004465 14125072333 0016415 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"bytes"
gc "gopkg.in/check.v1"
)
type contextSuite struct{}
var _ = gc.Suite(&contextSuite{})
func (*contextSuite) newWriter() (*bytes.Buffer, *Writer) {
buff := &bytes.Buffer{}
writer := NewWriter(buff)
writer.noColor = false
return buff, writer
}
func (*contextSuite) TestBlank(c *gc.C) {
var context Context
c.Assert(context.sgr(), gc.Equals, "")
}
func (*contextSuite) TestAllUnknown(c *gc.C) {
context := Context{
Foreground: 123,
Background: 432,
Styles: []Style{456, 99},
}
c.Assert(context.sgr(), gc.Equals, "")
}
func (*contextSuite) TestForeground(c *gc.C) {
context := Foreground(Yellow)
c.Assert(context.sgr(), gc.Equals, "\x1b[33m")
}
func (*contextSuite) TestBackground(c *gc.C) {
context := Background(Blue)
c.Assert(context.sgr(), gc.Equals, "\x1b[44m")
}
func (*contextSuite) TestStyles(c *gc.C) {
context := Styles(Bold, Italic)
c.Assert(context.sgr(), gc.Equals, "\x1b[1;3m")
}
func (*contextSuite) TestValid(c *gc.C) {
context := Context{
Foreground: Yellow,
Background: Blue,
Styles: []Style{Bold, Italic},
}
c.Assert(context.sgr(), gc.Equals, "\x1b[1;3;33;44m")
}
func (*contextSuite) TestSetForeground(c *gc.C) {
var context Context
context.SetForeground(Yellow)
c.Assert(context.sgr(), gc.Equals, "\x1b[33m")
}
func (*contextSuite) TestSetBackground(c *gc.C) {
var context Context
context.SetBackground(Blue)
c.Assert(context.sgr(), gc.Equals, "\x1b[44m")
}
func (*contextSuite) TestSetStyles(c *gc.C) {
var context Context
context.SetStyle(Bold, Italic)
c.Assert(context.sgr(), gc.Equals, "\x1b[1;3m")
}
func (s *contextSuite) TestFprintfNoColor(c *gc.C) {
buff, writer := s.newWriter()
writer.noColor = true
context := Context{
Foreground: Yellow,
Background: Blue,
Styles: []Style{Bold, Italic},
}
context.Fprintf(writer, "hello %s, %d", "world", 42)
c.Assert(buff.String(), gc.Equals, "hello world, 42")
}
func (s *contextSuite) TestFprintfColor(c *gc.C) {
buff, writer := s.newWriter()
context := Context{
Foreground: Yellow,
Background: Blue,
Styles: []Style{Bold, Italic},
}
context.Fprintf(writer, "hello %s, %d", "world", 42)
c.Assert(buff.String(), gc.Equals, "\x1b[1;3;33;44mhello world, 42\x1b[0m")
}
ansiterm-1.0.0/doc.go 0000664 0000000 0000000 00000000324 14125072333 0014425 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
// Package ansiterm provides a Writer that writes out the ANSI escape
// codes for color and styles.
package ansiterm
ansiterm-1.0.0/go.mod 0000664 0000000 0000000 00000000335 14125072333 0014441 0 ustar 00root root 0000000 0000000 module github.com/juju/ansiterm
go 1.14
require (
github.com/lunixbochs/vtclean v1.0.0
github.com/mattn/go-colorable v0.1.10
github.com/mattn/go-isatty v0.0.14
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
)
ansiterm-1.0.0/go.sum 0000664 0000000 0000000 00000003153 14125072333 0014467 0 ustar 00root root 0000000 0000000 github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mattn/go-colorable v0.1.10 h1:KWqbp83oZ6YOEgIbNW3BM1Jbe2tz4jgmWA9FOuAF8bw=
github.com/mattn/go-colorable v0.1.10/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
ansiterm-1.0.0/package_test.go 0000664 0000000 0000000 00000000314 14125072333 0016311 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"testing"
gc "gopkg.in/check.v1"
)
func Test(t *testing.T) {
gc.TestingT(t)
}
ansiterm-1.0.0/style.go 0000664 0000000 0000000 00000001747 14125072333 0015032 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
const (
_ Style = iota
Bold
Faint
Italic
Underline
Blink
Reverse
Strikethrough
Conceal
)
type Style int
func (s Style) String() string {
switch s {
case Bold:
return "bold"
case Faint:
return "faint"
case Italic:
return "italic"
case Underline:
return "underline"
case Blink:
return "blink"
case Reverse:
return "reverse"
case Strikethrough:
return "strikethrough"
case Conceal:
return "conceal"
default:
return ""
}
}
func (s Style) enable() attribute {
switch s {
case Bold:
return 1
case Faint:
return 2
case Italic:
return 3
case Underline:
return 4
case Blink:
return 5
case Reverse:
return 7
case Conceal:
return 8
case Strikethrough:
return 9
default:
return unknownAttribute
}
}
func (s Style) disable() attribute {
value := s.enable()
if value != unknownAttribute {
return value + 20
}
return value
}
ansiterm-1.0.0/style_test.go 0000664 0000000 0000000 00000001030 14125072333 0016052 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import gc "gopkg.in/check.v1"
type styleSuite struct{}
var _ = gc.Suite(&styleSuite{})
func (*styleSuite) TestString(c *gc.C) {
c.Check(Bold.String(), gc.Equals, "bold")
c.Check(Strikethrough.String(), gc.Equals, "strikethrough")
var blank Style
c.Check(blank.String(), gc.Equals, "")
var huge Style = 1234
c.Check(huge.String(), gc.Equals, "")
var negative Style = -1
c.Check(negative.String(), gc.Equals, "")
}
ansiterm-1.0.0/tabwriter.go 0000664 0000000 0000000 00000004325 14125072333 0015670 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"io"
"github.com/juju/ansiterm/tabwriter"
)
// NewTabWriter returns a writer that is able to set colors and styles.
// The ansi escape codes are stripped for width calculations.
func NewTabWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter {
return new(TabWriter).Init(output, minwidth, tabwidth, padding, padchar, flags)
}
// TabWriter is a filter that inserts padding around tab-delimited
// columns in its input to align them in the output.
//
// It also setting of colors and styles over and above the standard
// tabwriter package.
type TabWriter struct {
Writer
tw tabwriter.Writer
}
// Flush should be called after the last call to Write to ensure
// that any data buffered in the Writer is written to output. Any
// incomplete escape sequence at the end is considered
// complete for formatting purposes.
//
func (t *TabWriter) Flush() error {
return t.tw.Flush()
}
// SetColumnAlignRight will mark a particular column as align right.
// This is reset on the next flush.
func (t *TabWriter) SetColumnAlignRight(column int) {
t.tw.SetColumnAlignRight(column)
}
// A Writer must be initialized with a call to Init. The first parameter (output)
// specifies the filter output. The remaining parameters control the formatting:
//
// minwidth minimal cell width including any padding
// tabwidth width of tab characters (equivalent number of spaces)
// padding padding added to a cell before computing its width
// padchar ASCII char used for padding
// if padchar == '\t', the Writer will assume that the
// width of a '\t' in the formatted output is tabwidth,
// and cells are left-aligned independent of align_left
// (for correct-looking results, tabwidth must correspond
// to the tab width in the viewer displaying the result)
// flags formatting control
//
func (t *TabWriter) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter {
writer, colorCapable := colorEnabledWriter(output)
t.Writer = Writer{
Writer: t.tw.Init(writer, minwidth, tabwidth, padding, padchar, flags),
noColor: !colorCapable,
}
return t
}
ansiterm-1.0.0/tabwriter/ 0000775 0000000 0000000 00000000000 14125072333 0015335 5 ustar 00root root 0000000 0000000 ansiterm-1.0.0/tabwriter/LICENSE 0000664 0000000 0000000 00000002707 14125072333 0016350 0 ustar 00root root 0000000 0000000 Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ansiterm-1.0.0/tabwriter/tabwriter.go 0000664 0000000 0000000 00000042155 14125072333 0017676 0 ustar 00root root 0000000 0000000 // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file is mostly a copy of the go standard library text/tabwriter. With
// the additional stripping of ansi control characters for width calculations.
// Package tabwriter implements a write filter (tabwriter.Writer) that
// translates tabbed columns in input into properly aligned text.
//
// The package is using the Elastic Tabstops algorithm described at
// http://nickgravgaard.com/elastictabstops/index.html.
//
package tabwriter
import (
"bytes"
"io"
"unicode/utf8"
"github.com/lunixbochs/vtclean"
)
// ----------------------------------------------------------------------------
// Filter implementation
// A cell represents a segment of text terminated by tabs or line breaks.
// The text itself is stored in a separate buffer; cell only describes the
// segment's size in bytes, its width in runes, and whether it's an htab
// ('\t') terminated cell.
//
type cell struct {
size int // cell size in bytes
width int // cell width in runes
htab bool // true if the cell is terminated by an htab ('\t')
}
// A Writer is a filter that inserts padding around tab-delimited
// columns in its input to align them in the output.
//
// The Writer treats incoming bytes as UTF-8 encoded text consisting
// of cells terminated by (horizontal or vertical) tabs or line
// breaks (newline or formfeed characters). Cells in adjacent lines
// constitute a column. The Writer inserts padding as needed to
// make all cells in a column have the same width, effectively
// aligning the columns. It assumes that all characters have the
// same width except for tabs for which a tabwidth must be specified.
// Note that cells are tab-terminated, not tab-separated: trailing
// non-tab text at the end of a line does not form a column cell.
//
// The Writer assumes that all Unicode code points have the same width;
// this may not be true in some fonts.
//
// If DiscardEmptyColumns is set, empty columns that are terminated
// entirely by vertical (or "soft") tabs are discarded. Columns
// terminated by horizontal (or "hard") tabs are not affected by
// this flag.
//
// If a Writer is configured to filter HTML, HTML tags and entities
// are passed through. The widths of tags and entities are
// assumed to be zero (tags) and one (entities) for formatting purposes.
//
// A segment of text may be escaped by bracketing it with Escape
// characters. The tabwriter passes escaped text segments through
// unchanged. In particular, it does not interpret any tabs or line
// breaks within the segment. If the StripEscape flag is set, the
// Escape characters are stripped from the output; otherwise they
// are passed through as well. For the purpose of formatting, the
// width of the escaped text is always computed excluding the Escape
// characters.
//
// The formfeed character ('\f') acts like a newline but it also
// terminates all columns in the current line (effectively calling
// Flush). Cells in the next line start new columns. Unless found
// inside an HTML tag or inside an escaped text segment, formfeed
// characters appear as newlines in the output.
//
// The Writer must buffer input internally, because proper spacing
// of one line may depend on the cells in future lines. Clients must
// call Flush when done calling Write.
//
type Writer struct {
// configuration
output io.Writer
minwidth int
tabwidth int
padding int
padbytes [8]byte
flags uint
// current state
buf bytes.Buffer // collected text excluding tabs or line breaks
pos int // buffer position up to which cell.width of incomplete cell has been computed
cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
lines [][]cell // list of lines; each line is a list of cells
widths []int // list of column widths in runes - re-used during formatting
alignment map[int]uint // column alignment
}
func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
// Reset the current state.
func (b *Writer) reset() {
b.buf.Reset()
b.pos = 0
b.cell = cell{}
b.endChar = 0
b.lines = b.lines[0:0]
b.widths = b.widths[0:0]
b.alignment = make(map[int]uint)
b.addLine()
}
// Internal representation (current state):
//
// - all text written is appended to buf; tabs and line breaks are stripped away
// - at any given time there is a (possibly empty) incomplete cell at the end
// (the cell starts after a tab or line break)
// - cell.size is the number of bytes belonging to the cell so far
// - cell.width is text width in runes of that cell from the start of the cell to
// position pos; html tags and entities are excluded from this width if html
// filtering is enabled
// - the sizes and widths of processed text are kept in the lines list
// which contains a list of cells for each line
// - the widths list is a temporary list with current widths used during
// formatting; it is kept in Writer because it's re-used
//
// |<---------- size ---------->|
// | |
// |<- width ->|<- ignored ->| |
// | | | |
// [---processed---tab------------......]
// ^ ^ ^
// | | |
// buf start of incomplete cell pos
// Formatting can be controlled with these flags.
const (
// Ignore html tags and treat entities (starting with '&'
// and ending in ';') as single characters (width = 1).
FilterHTML uint = 1 << iota
// Strip Escape characters bracketing escaped text segments
// instead of passing them through unchanged with the text.
StripEscape
// Force right-alignment of cell content.
// Default is left-alignment.
AlignRight
// Handle empty columns as if they were not present in
// the input in the first place.
DiscardEmptyColumns
// Always use tabs for indentation columns (i.e., padding of
// leading empty cells on the left) independent of padchar.
TabIndent
// Print a vertical bar ('|') between columns (after formatting).
// Discarded columns appear as zero-width columns ("||").
Debug
)
// A Writer must be initialized with a call to Init. The first parameter (output)
// specifies the filter output. The remaining parameters control the formatting:
//
// minwidth minimal cell width including any padding
// tabwidth width of tab characters (equivalent number of spaces)
// padding padding added to a cell before computing its width
// padchar ASCII char used for padding
// if padchar == '\t', the Writer will assume that the
// width of a '\t' in the formatted output is tabwidth,
// and cells are left-aligned independent of align_left
// (for correct-looking results, tabwidth must correspond
// to the tab width in the viewer displaying the result)
// flags formatting control
//
func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
if minwidth < 0 || tabwidth < 0 || padding < 0 {
panic("negative minwidth, tabwidth, or padding")
}
b.output = output
b.minwidth = minwidth
b.tabwidth = tabwidth
b.padding = padding
for i := range b.padbytes {
b.padbytes[i] = padchar
}
if padchar == '\t' {
// tab padding enforces left-alignment
flags &^= AlignRight
}
b.flags = flags
b.reset()
return b
}
// debugging support (keep code around)
func (b *Writer) dump() {
pos := 0
for i, line := range b.lines {
print("(", i, ") ")
for _, c := range line {
print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
pos += c.size
}
print("\n")
}
print("\n")
}
// local error wrapper so we can distinguish errors we want to return
// as errors from genuine panics (which we don't want to return as errors)
type osError struct {
err error
}
func (b *Writer) write0(buf []byte) {
n, err := b.output.Write(buf)
if n != len(buf) && err == nil {
err = io.ErrShortWrite
}
if err != nil {
panic(osError{err})
}
}
func (b *Writer) writeN(src []byte, n int) {
for n > len(src) {
b.write0(src)
n -= len(src)
}
b.write0(src[0:n])
}
var (
newline = []byte{'\n'}
tabs = []byte("\t\t\t\t\t\t\t\t")
)
func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
if b.padbytes[0] == '\t' || useTabs {
// padding is done with tabs
if b.tabwidth == 0 {
return // tabs have no width - can't do any padding
}
// make cellw the smallest multiple of b.tabwidth
cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
n := cellw - textw // amount of padding
if n < 0 {
panic("internal error")
}
b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
return
}
// padding is done with non-tab characters
b.writeN(b.padbytes[0:], cellw-textw)
}
var vbar = []byte{'|'}
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
pos = pos0
for i := line0; i < line1; i++ {
line := b.lines[i]
// if TabIndent is set, use tabs to pad leading empty cells
useTabs := b.flags&TabIndent != 0
for j, c := range line {
if j > 0 && b.flags&Debug != 0 {
// indicate column break
b.write0(vbar)
}
if c.size == 0 {
// empty cell
if j < len(b.widths) {
b.writePadding(c.width, b.widths[j], useTabs)
}
} else {
// non-empty cell
useTabs = false
alignColumnRight := b.alignment[j] == AlignRight
if (b.flags&AlignRight == 0) && !alignColumnRight { // align left
b.write0(b.buf.Bytes()[pos : pos+c.size])
pos += c.size
if j < len(b.widths) {
b.writePadding(c.width, b.widths[j], false)
}
} else if alignColumnRight && j < len(b.widths) {
// just this column
internalSize := b.widths[j] - b.padding
if j < len(b.widths) {
b.writePadding(c.width, internalSize, false)
}
b.write0(b.buf.Bytes()[pos : pos+c.size])
if b.padding > 0 {
b.writePadding(0, b.padding, false)
}
pos += c.size
} else { // align right
if j < len(b.widths) {
b.writePadding(c.width, b.widths[j], false)
}
b.write0(b.buf.Bytes()[pos : pos+c.size])
pos += c.size
}
}
}
if i+1 == len(b.lines) {
// last buffered line - we don't have a newline, so just write
// any outstanding buffered data
b.write0(b.buf.Bytes()[pos : pos+b.cell.size])
pos += b.cell.size
} else {
// not the last line - write newline
b.write0(newline)
}
}
return
}
// Format the text between line0 and line1 (excluding line1); pos
// is the buffer position corresponding to the beginning of line0.
// Returns the buffer position corresponding to the beginning of
// line1 and an error, if any.
//
func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
pos = pos0
column := len(b.widths)
for this := line0; this < line1; this++ {
line := b.lines[this]
if column < len(line)-1 {
// cell exists in this column => this line
// has more cells than the previous line
// (the last cell per line is ignored because cells are
// tab-terminated; the last cell per line describes the
// text before the newline/formfeed and does not belong
// to a column)
// print unprinted lines until beginning of block
pos = b.writeLines(pos, line0, this)
line0 = this
// column block begin
width := b.minwidth // minimal column width
discardable := true // true if all cells in this column are empty and "soft"
for ; this < line1; this++ {
line = b.lines[this]
if column < len(line)-1 {
// cell exists in this column
c := line[column]
// update width
if w := c.width + b.padding; w > width {
width = w
}
// update discardable
if c.width > 0 || c.htab {
discardable = false
}
} else {
break
}
}
// column block end
// discard empty columns if necessary
if discardable && b.flags&DiscardEmptyColumns != 0 {
width = 0
}
// format and print all columns to the right of this column
// (we know the widths of this column and all columns to the left)
b.widths = append(b.widths, width) // push width
pos = b.format(pos, line0, this)
b.widths = b.widths[0 : len(b.widths)-1] // pop width
line0 = this
}
}
// print unprinted lines until end
return b.writeLines(pos, line0, line1)
}
// Append text to current cell.
func (b *Writer) append(text []byte) {
b.buf.Write(text)
b.cell.size += len(text)
}
// Update the cell width.
func (b *Writer) updateWidth() {
// ---- Changes here -----
newChars := b.buf.Bytes()[b.pos:b.buf.Len()]
cleaned := vtclean.Clean(string(newChars), false) // false to strip colors
b.cell.width += utf8.RuneCount([]byte(cleaned))
// --- end of changes ----
b.pos = b.buf.Len()
}
// To escape a text segment, bracket it with Escape characters.
// For instance, the tab in this string "Ignore this tab: \xff\t\xff"
// does not terminate a cell and constitutes a single character of
// width one for formatting purposes.
//
// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
//
const Escape = '\xff'
// Start escaped mode.
func (b *Writer) startEscape(ch byte) {
switch ch {
case Escape:
b.endChar = Escape
case '<':
b.endChar = '>'
case '&':
b.endChar = ';'
}
}
// Terminate escaped mode. If the escaped text was an HTML tag, its width
// is assumed to be zero for formatting purposes; if it was an HTML entity,
// its width is assumed to be one. In all other cases, the width is the
// unicode width of the text.
//
func (b *Writer) endEscape() {
switch b.endChar {
case Escape:
b.updateWidth()
if b.flags&StripEscape == 0 {
b.cell.width -= 2 // don't count the Escape chars
}
case '>': // tag of zero width
case ';':
b.cell.width++ // entity, count as one rune
}
b.pos = b.buf.Len()
b.endChar = 0
}
// Terminate the current cell by adding it to the list of cells of the
// current line. Returns the number of cells in that line.
//
func (b *Writer) terminateCell(htab bool) int {
b.cell.htab = htab
line := &b.lines[len(b.lines)-1]
*line = append(*line, b.cell)
b.cell = cell{}
return len(*line)
}
func handlePanic(err *error, op string) {
if e := recover(); e != nil {
if nerr, ok := e.(osError); ok {
*err = nerr.err
return
}
panic("tabwriter: panic during " + op)
}
}
// Flush should be called after the last call to Write to ensure
// that any data buffered in the Writer is written to output. Any
// incomplete escape sequence at the end is considered
// complete for formatting purposes.
//
func (b *Writer) Flush() (err error) {
defer b.reset() // even in the presence of errors
defer handlePanic(&err, "Flush")
// add current cell if not empty
if b.cell.size > 0 {
if b.endChar != 0 {
// inside escape - terminate it even if incomplete
b.endEscape()
}
b.terminateCell(false)
}
// format contents of buffer
b.format(0, 0, len(b.lines))
return
}
var hbar = []byte("---\n")
// SetColumnAlignRight will mark a particular column as align right.
// This is reset on the next flush.
func (b *Writer) SetColumnAlignRight(column int) {
b.alignment[column] = AlignRight
}
// Write writes buf to the writer b.
// The only errors returned are ones encountered
// while writing to the underlying output stream.
//
func (b *Writer) Write(buf []byte) (n int, err error) {
defer handlePanic(&err, "Write")
// split text into cells
n = 0
for i, ch := range buf {
if b.endChar == 0 {
// outside escape
switch ch {
case '\t', '\v', '\n', '\f':
// end of cell
b.append(buf[n:i])
b.updateWidth()
n = i + 1 // ch consumed
ncells := b.terminateCell(ch == '\t')
if ch == '\n' || ch == '\f' {
// terminate line
b.addLine()
if ch == '\f' || ncells == 1 {
// A '\f' always forces a flush. Otherwise, if the previous
// line has only one cell which does not have an impact on
// the formatting of the following lines (the last cell per
// line is ignored by format()), thus we can flush the
// Writer contents.
if err = b.Flush(); err != nil {
return
}
if ch == '\f' && b.flags&Debug != 0 {
// indicate section break
b.write0(hbar)
}
}
}
case Escape:
// start of escaped sequence
b.append(buf[n:i])
b.updateWidth()
n = i
if b.flags&StripEscape != 0 {
n++ // strip Escape
}
b.startEscape(Escape)
case '<', '&':
// possibly an html tag/entity
if b.flags&FilterHTML != 0 {
// begin of tag/entity
b.append(buf[n:i])
b.updateWidth()
n = i
b.startEscape(ch)
}
}
} else {
// inside escape
if ch == b.endChar {
// end of tag/entity
j := i + 1
if ch == Escape && b.flags&StripEscape != 0 {
j = i // strip Escape
}
b.append(buf[n:j])
n = i + 1 // ch consumed
b.endEscape()
}
}
}
// append leftover text
b.append(buf[n:])
n = len(buf)
return
}
// NewWriter allocates and initializes a new tabwriter.Writer.
// The parameters are the same as for the Init function.
//
func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
}
ansiterm-1.0.0/tabwriter/tabwriter_test.go 0000664 0000000 0000000 00000000675 14125072333 0020736 0 ustar 00root root 0000000 0000000 package tabwriter
import (
"bytes"
"testing"
gc "gopkg.in/check.v1"
)
func Test(t *testing.T) {
gc.TestingT(t)
}
type tabwriterSuite struct{}
var _ = gc.Suite(&tabwriterSuite{})
func (s *tabwriterSuite) TestRightAlignOverflow(c *gc.C) {
var buf bytes.Buffer
tw := NewWriter(&buf, 0, 1, 2, ' ', 0)
tw.SetColumnAlignRight(2)
tw.Write([]byte("not\tenough\ttabs"))
tw.Flush()
c.Assert(buf.String(), gc.Equals, "not enough tabs")
}
ansiterm-1.0.0/terminal.go 0000664 0000000 0000000 00000002235 14125072333 0015476 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"io"
"os"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
)
// colorEnabledWriter returns a writer that can handle the ansi color codes
// and true if the writer passed in is a terminal capable of color. If the
// TERM environment variable is set to "dumb", the terminal is not considered
// color capable.
func colorEnabledWriter(w io.Writer) (io.Writer, bool) {
f, ok := w.(*os.File)
if !ok {
return w, false
}
// NO_COLOR is a relatively new standard for preventing color enabled
// writers rather than using the TERM env.
//
// "...should check for the presence of a NO_COLOR environment variable
// that, when present (regardless of its value), prevents the addition of
// ANSI color."
// See: https://no-color.org/
if _, ok := os.LookupEnv("NO_COLOR"); ok {
return w, false
}
// Check the TERM environment variable specifically
// to check for "dumb" terminals.
if os.Getenv("TERM") == "dumb" {
return w, false
}
if !isatty.IsTerminal(f.Fd()) {
return w, false
}
return colorable.NewColorable(f), true
}
ansiterm-1.0.0/terminal_test.go 0000664 0000000 0000000 00000001465 14125072333 0016541 0 ustar 00root root 0000000 0000000 // Copyright 2021 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"io/ioutil"
"os"
gc "gopkg.in/check.v1"
)
type colorWriterSuite struct{}
var _ = gc.Suite(&colorWriterSuite{})
func (s *colorWriterSuite) TestNoColor(c *gc.C) {
file, err := ioutil.TempFile("", "")
c.Assert(err, gc.IsNil)
os.Setenv("NO_COLOR", "")
defer os.Unsetenv("NO_COLOR")
writer, ok := colorEnabledWriter(file)
c.Assert(ok, gc.Equals, false)
c.Assert(writer, gc.Equals, file)
}
func (s *colorWriterSuite) TestNoColorEvenIfFalse(c *gc.C) {
file, err := ioutil.TempFile("", "")
c.Assert(err, gc.IsNil)
os.Setenv("NO_COLOR", "false")
defer os.Unsetenv("NO_COLOR")
writer, ok := colorEnabledWriter(file)
c.Assert(ok, gc.Equals, false)
c.Assert(writer, gc.Equals, file)
}
ansiterm-1.0.0/writer.go 0000664 0000000 0000000 00000003362 14125072333 0015201 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"fmt"
"io"
)
// Writer allows colors and styles to be specified. If the io.Writer
// is not a terminal capable of color, all attempts to set colors or
// styles are no-ops.
type Writer struct {
io.Writer
noColor bool
}
// NewWriter returns a Writer that allows the caller to specify colors and
// styles. If the io.Writer is not a terminal capable of color, all attempts
// to set colors or styles are no-ops.
func NewWriter(w io.Writer) *Writer {
writer, colorCapable := colorEnabledWriter(w)
return &Writer{
Writer: writer,
noColor: !colorCapable,
}
}
// SetColorCapable forces the writer to either write the ANSI escape color
// if capable is true, or to not write them if capable is false.
func (w *Writer) SetColorCapable(capable bool) {
w.noColor = !capable
}
// SetForeground sets the foreground color.
func (w *Writer) SetForeground(c Color) {
w.writeSGR(c.foreground())
}
// SetBackground sets the background color.
func (w *Writer) SetBackground(c Color) {
w.writeSGR(c.background())
}
// SetStyle sets the text style.
func (w *Writer) SetStyle(s Style) {
w.writeSGR(s.enable())
}
// ClearStyle clears the text style.
func (w *Writer) ClearStyle(s Style) {
w.writeSGR(s.disable())
}
// Reset returns the default foreground and background colors with no styles.
func (w *Writer) Reset() {
w.writeSGR(reset)
}
type sgr interface {
// sgr returns the combined escape sequence for the Select Graphic Rendition.
sgr() string
}
// writeSGR takes the appropriate integer SGR parameters
// and writes out the ANIS escape code.
func (w *Writer) writeSGR(value sgr) {
if w.noColor {
return
}
fmt.Fprint(w, value.sgr())
}
ansiterm-1.0.0/writer_test.go 0000664 0000000 0000000 00000003314 14125072333 0016235 0 ustar 00root root 0000000 0000000 // Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"bytes"
gc "gopkg.in/check.v1"
)
type writerSuite struct{}
var _ = gc.Suite(&writerSuite{})
func (*writerSuite) TestNoColor(c *gc.C) {
buff := &bytes.Buffer{}
writer := NewWriter(buff)
c.Check(writer.noColor, gc.Equals, true)
writer.SetForeground(Yellow)
writer.SetBackground(Blue)
writer.SetStyle(Bold)
writer.ClearStyle(Bold)
writer.Reset()
c.Check(buff.String(), gc.Equals, "")
}
func (*writerSuite) TestSetColorCapable(c *gc.C) {
buff := &bytes.Buffer{}
writer := NewWriter(buff)
c.Check(writer.noColor, gc.Equals, true)
writer.SetColorCapable(true)
c.Check(writer.noColor, gc.Equals, false)
writer.SetColorCapable(false)
c.Check(writer.noColor, gc.Equals, true)
}
func (*writerSuite) newWriter() (*bytes.Buffer, *Writer) {
buff := &bytes.Buffer{}
writer := NewWriter(buff)
writer.noColor = false
return buff, writer
}
func (s *writerSuite) TestSetForeground(c *gc.C) {
buff, writer := s.newWriter()
writer.SetForeground(Yellow)
c.Check(buff.String(), gc.Equals, "\x1b[33m")
}
func (s *writerSuite) TestSetBackground(c *gc.C) {
buff, writer := s.newWriter()
writer.SetBackground(Blue)
c.Check(buff.String(), gc.Equals, "\x1b[44m")
}
func (s *writerSuite) TestSetStyle(c *gc.C) {
buff, writer := s.newWriter()
writer.SetStyle(Bold)
c.Check(buff.String(), gc.Equals, "\x1b[1m")
}
func (s *writerSuite) TestClearStyle(c *gc.C) {
buff, writer := s.newWriter()
writer.ClearStyle(Bold)
c.Check(buff.String(), gc.Equals, "\x1b[21m")
}
func (s *writerSuite) TestReset(c *gc.C) {
buff, writer := s.newWriter()
writer.Reset()
c.Check(buff.String(), gc.Equals, "\x1b[0m")
}