summaryrefslogtreecommitdiff
path: root/vendor/github.com/buger/goterm
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
committerMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
commita031b83a09a8628435317a03f199cdc18b78262f (patch)
treebc017a96769ce6de33745b8b0b1304ccf38e9df0 /vendor/github.com/buger/goterm
parent2b74391cd5281f6fdf391ff8ad50fd1490f6bf89 (diff)
downloadpodman-a031b83a09a8628435317a03f199cdc18b78262f.tar.gz
podman-a031b83a09a8628435317a03f199cdc18b78262f.tar.bz2
podman-a031b83a09a8628435317a03f199cdc18b78262f.zip
Initial checkin from CRI-O repo
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'vendor/github.com/buger/goterm')
-rw-r--r--vendor/github.com/buger/goterm/README.md119
-rw-r--r--vendor/github.com/buger/goterm/box.go122
-rw-r--r--vendor/github.com/buger/goterm/plot.go328
-rw-r--r--vendor/github.com/buger/goterm/table.go34
-rw-r--r--vendor/github.com/buger/goterm/terminal.go258
-rw-r--r--vendor/github.com/buger/goterm/terminal_nosysioctl.go12
-rw-r--r--vendor/github.com/buger/goterm/terminal_sysioctl.go36
7 files changed, 909 insertions, 0 deletions
diff --git a/vendor/github.com/buger/goterm/README.md b/vendor/github.com/buger/goterm/README.md
new file mode 100644
index 000000000..536b7b885
--- /dev/null
+++ b/vendor/github.com/buger/goterm/README.md
@@ -0,0 +1,119 @@
+## Description
+
+This library provides basic building blocks for building advanced console UIs.
+
+Initially created for [Gor](http://github.com/buger/gor).
+
+Full API documentation: http://godoc.org/github.com/buger/goterm
+
+## Basic usage
+
+Full screen console app, printing current time:
+
+```go
+import (
+ tm "github.com/buger/goterm"
+ "time"
+)
+
+func main() {
+ tm.Clear() // Clear current screen
+
+ for {
+ // By moving cursor to top-left position we ensure that console output
+ // will be overwritten each time, instead of adding new.
+ tm.MoveCursor(1,1)
+
+ tm.Println("Current Time:", time.Now().Format(time.RFC1123))
+
+ tm.Flush() // Call it every time at the end of rendering
+
+ time.Sleep(time.Second)
+ }
+}
+```
+
+This can be seen in [examples/time_example.go](examples/time_example.go). To
+run it yourself, go into your `$GOPATH/src/github.com/buger/goterm` directory
+and run `go run ./examples/time_example.go`
+
+
+Print red bold message on white background:
+
+```go
+tm.Println(tm.Background(tm.Color(tm.Bold("Important header"), tm.RED), tm.WHITE))
+```
+
+
+Create box and move it to center of the screen:
+
+```go
+tm.Clear()
+
+// Create Box with 30% width of current screen, and height of 20 lines
+box := tm.NewBox(30|tm.PCT, 20, 0)
+
+// Add some content to the box
+// Note that you can add ANY content, even tables
+fmt.Fprint(box, "Some box content")
+
+// Move Box to approx center of the screen
+tm.Print(tm.MoveTo(box.String(), 40|tm.PCT, 40|tm.PCT))
+
+tm.Flush()
+```
+
+This can be found in [examples/box_example.go](examples/box_example.go).
+
+Draw table:
+
+```go
+// Based on http://golang.org/pkg/text/tabwriter
+totals := tm.NewTable(0, 10, 5, ' ', 0)
+fmt.Fprintf(totals, "Time\tStarted\tActive\tFinished\n")
+fmt.Fprintf(totals, "%s\t%d\t%d\t%d\n", "All", started, started-finished, finished)
+tm.Println(totals)
+tm.Flush()
+```
+
+This can be found in [examples/table_example.go](examples/table_example.go).
+
+## Line charts
+
+Chart example:
+
+![screen shot 2013-07-09 at 5 05 37 pm](https://f.cloud.github.com/assets/14009/767676/e3dd35aa-e887-11e2-9cd2-f6451eb26adc.png)
+
+
+```go
+ import (
+ tm "github.com/buger/goterm"
+ )
+
+ chart := tm.NewLineChart(100, 20)
+
+ data := new(tm.DataTable)
+ data.addColumn("Time")
+ data.addColumn("Sin(x)")
+ data.addColumn("Cos(x+1)")
+
+ for i := 0.1; i < 10; i += 0.1 {
+ data.addRow(i, math.Sin(i), math.Cos(i+1))
+ }
+
+ tm.Println(chart.Draw(data))
+```
+
+This can be found in [examples/chart_example.go](examples/chart_example.go).
+
+Drawing 2 separate graphs in different scales. Each graph have its own Y axe.
+
+```go
+chart.Flags = tm.DRAW_INDEPENDENT
+```
+
+Drawing graph with relative scale (Grapwh draw starting from min value instead of zero)
+
+```go
+chart.Flags = tm.DRAW_RELATIVE
+```
diff --git a/vendor/github.com/buger/goterm/box.go b/vendor/github.com/buger/goterm/box.go
new file mode 100644
index 000000000..7df929d7d
--- /dev/null
+++ b/vendor/github.com/buger/goterm/box.go
@@ -0,0 +1,122 @@
+package goterm
+
+import (
+ "bytes"
+ "strings"
+)
+
+const DEFAULT_BORDER = "- │ ┌ ┐ └ ┘"
+
+// Box allows you to create independent parts of screen, with its own buffer and borders.
+// Can be used for creating modal windows
+//
+// Generates boxes likes this:
+// ┌--------┐
+// │hello │
+// │world │
+// │ │
+// └--------┘
+//
+type Box struct {
+ Buf *bytes.Buffer
+
+ Width int
+ Height int
+
+ // To get even padding: PaddingX ~= PaddingY*4
+ PaddingX int
+ PaddingY int
+
+ // Should contain 6 border pieces separated by spaces
+ //
+ // Example border:
+ // "- │ ┌ ┐ └ ┘"
+ Border string
+
+ Flags int // Not used now
+}
+
+// Create new Box.
+// Width and height can be relative:
+//
+// // Create box with 50% with of current screen and 10 lines height
+// box := tm.NewBox(50|tm.PCT, 10, 0)
+//
+func NewBox(width, height int, flags int) *Box {
+ width, height = GetXY(width, height)
+
+ box := new(Box)
+ box.Buf = new(bytes.Buffer)
+ box.Width = width
+ box.Height = height
+ box.Border = DEFAULT_BORDER
+ box.PaddingX = 1
+ box.PaddingY = 0
+ box.Flags = flags
+
+ return box
+}
+
+func (b *Box) Write(p []byte) (int, error) {
+ return b.Buf.Write(p)
+}
+
+// Render Box
+func (b *Box) String() (out string) {
+ borders := strings.Split(b.Border, " ")
+ lines := strings.Split(b.Buf.String(), "\n")
+
+ // Border + padding
+ prefix := borders[1] + strings.Repeat(" ", b.PaddingX)
+ suffix := strings.Repeat(" ", b.PaddingX) + borders[1]
+
+ offset := b.PaddingY + 1 // 1 is border width
+
+ // Content width without borders and padding
+ contentWidth := b.Width - (b.PaddingX+1)*2
+
+ for y := 0; y < b.Height; y++ {
+ var line string
+
+ switch {
+ // Draw borders for first line
+ case y == 0:
+ line = borders[2] + strings.Repeat(borders[0], b.Width-2) + borders[3]
+
+ // Draw borders for last line
+ case y == (b.Height - 1):
+ line = borders[4] + strings.Repeat(borders[0], b.Width-2) + borders[5]
+
+ // Draw top and bottom padding
+ case y <= b.PaddingY || y >= (b.Height-b.PaddingY):
+ line = borders[1] + strings.Repeat(" ", b.Width-2) + borders[1]
+
+ // Render content
+ default:
+ if len(lines) > y-offset {
+ line = lines[y-offset]
+ } else {
+ line = ""
+ }
+
+ if len(line) > contentWidth-1 {
+ // If line is too large limit it
+ line = line[0:contentWidth]
+ } else {
+ // If line is too small enlarge it by adding spaces
+ line = line + strings.Repeat(" ", contentWidth-len(line))
+ }
+
+ line = prefix + line + suffix
+ }
+
+ // Don't add newline for last element
+ if y != b.Height-1 {
+ line = line + "\n"
+ }
+
+ out += line
+ }
+
+ return out
+}
diff --git a/vendor/github.com/buger/goterm/plot.go b/vendor/github.com/buger/goterm/plot.go
new file mode 100644
index 000000000..77b9fb097
--- /dev/null
+++ b/vendor/github.com/buger/goterm/plot.go
@@ -0,0 +1,328 @@
+package goterm
+
+import (
+ "fmt"
+ "math"
+ "strings"
+)
+
+const (
+ AXIS_LEFT = iota
+ AXIS_RIGHT
+)
+
+const (
+ DRAW_INDEPENDENT = 1 << iota
+ DRAW_RELATIVE
+)
+
+type DataTable struct {
+ columns []string
+
+ rows [][]float64
+}
+
+func (d *DataTable) AddColumn(name string) {
+ d.columns = append(d.columns, name)
+}
+
+func (d *DataTable) AddRow(elms ...float64) {
+ d.rows = append(d.rows, elms)
+}
+
+type Chart interface {
+ Draw(data DataTable, flags int) string
+}
+
+type LineChart struct {
+ Buf []string
+ chartBuf []string
+
+ data *DataTable
+
+ Width int
+ Height int
+
+ chartHeight int
+ chartWidth int
+
+ paddingX int
+
+ paddingY int
+
+ Flags int
+}
+
+func genBuf(size int) []string {
+ buf := make([]string, size)
+
+ for i := 0; i < size; i++ {
+ buf[i] = " "
+ }
+
+ return buf
+}
+
+// Format float
+func ff(num interface{}) string {
+ return fmt.Sprintf("%.1f", num)
+}
+
+func NewLineChart(width, height int) *LineChart {
+ chart := new(LineChart)
+ chart.Width = width
+ chart.Height = height
+ chart.Buf = genBuf(width * height)
+
+ // axis lines + axies text
+ chart.paddingY = 2
+
+ return chart
+}
+
+func (c *LineChart) DrawAxes(maxX, minX, maxY, minY float64, index int) {
+ side := AXIS_LEFT
+
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ if index%2 == 0 {
+ side = AXIS_RIGHT
+ }
+
+ c.DrawLine(c.paddingX-1, 1, c.Width-c.paddingX, 1, "-")
+ } else {
+ c.DrawLine(c.paddingX-1, 1, c.Width-1, 1, "-")
+ }
+
+ if side == AXIS_LEFT {
+ c.DrawLine(c.paddingX-1, 1, c.paddingX-1, c.Height-1, "│")
+ } else {
+ c.DrawLine(c.Width-c.paddingX, 1, c.Width-c.paddingX, c.Height-1, "│")
+ }
+
+ left := 0
+ if side == AXIS_RIGHT {
+ left = c.Width - c.paddingX + 1
+ }
+
+ if c.Flags&DRAW_RELATIVE != 0 {
+ c.writeText(ff(minY), left, 1)
+ } else {
+ if minY > 0 {
+ c.writeText("0", left, 1)
+ } else {
+ c.writeText(ff(minY), left, 1)
+ }
+ }
+
+ c.writeText(ff(maxY), left, c.Height-1)
+
+ c.writeText(ff(minX), c.paddingX, 0)
+
+ x_col := c.data.columns[0]
+ c.writeText(c.data.columns[0], c.Width/2-len(x_col)/2, 1)
+
+ if c.Flags&DRAW_INDEPENDENT != 0 || len(c.data.columns) < 3 {
+ col := c.data.columns[index]
+
+ for idx, char := range strings.Split(col, "") {
+ start_from := c.Height/2 + len(col)/2 - idx
+
+ if side == AXIS_LEFT {
+ c.writeText(char, c.paddingX-1, start_from)
+ } else {
+ c.writeText(char, c.Width-c.paddingX, start_from)
+ }
+ }
+ }
+
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ c.writeText(ff(maxX), c.Width-c.paddingX-len(ff(maxX)), 0)
+ } else {
+ c.writeText(ff(maxX), c.Width-len(ff(maxX)), 0)
+ }
+}
+
+func (c *LineChart) writeText(text string, x, y int) {
+ coord := y*c.Width + x
+
+ for idx, char := range strings.Split(text, "") {
+ c.Buf[coord+idx] = char
+ }
+}
+
+func (c *LineChart) Draw(data *DataTable) (out string) {
+ var scaleY, scaleX float64
+
+ c.data = data
+
+ if c.Flags&DRAW_INDEPENDENT != 0 && len(data.columns) > 3 {
+ fmt.Println("Error: Can't use DRAW_INDEPENDENT for more then 2 graphs")
+ return ""
+ }
+
+ charts := len(data.columns) - 1
+
+ prevPoint := [2]int{-1, -1}
+
+ maxX, minX, maxY, minY := getBoundaryValues(data, -1)
+
+ c.paddingX = int(math.Max(float64(len(ff(minY))), float64(len(ff(maxY))))) + 1
+
+ c.chartHeight = c.Height - c.paddingY
+
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ c.chartWidth = c.Width - 2*c.paddingX
+ } else {
+ c.chartWidth = c.Width - c.paddingX - 1
+ }
+
+ scaleX = float64(c.chartWidth) / (maxX - minX)
+
+ if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
+ scaleY = float64(c.chartHeight) / (maxY - minY)
+ } else {
+ scaleY = float64(c.chartHeight) / maxY
+ }
+
+ for i := 1; i < charts+1; i++ {
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ maxX, minX, maxY, minY = getBoundaryValues(data, i)
+
+ scaleX = float64(c.chartWidth-1) / (maxX - minX)
+ scaleY = float64(c.chartHeight) / maxY
+
+ if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
+ scaleY = float64(c.chartHeight) / (maxY - minY)
+ }
+ }
+
+ symbol := Color("•", i)
+
+ c_data := getChartData(data, i)
+
+ for _, point := range c_data {
+ x := int((point[0]-minX)*scaleX) + c.paddingX
+ y := int((point[1])*scaleY) + c.paddingY
+
+ if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
+ y = int((point[1]-minY)*scaleY) + c.paddingY
+ }
+
+ if prevPoint[0] == -1 {
+ prevPoint[0] = x
+ prevPoint[1] = y
+ }
+
+ if prevPoint[0] <= x {
+ c.DrawLine(prevPoint[0], prevPoint[1], x, y, symbol)
+ }
+
+ prevPoint[0] = x
+ prevPoint[1] = y
+ }
+
+ c.DrawAxes(maxX, minX, maxY, minY, i)
+ }
+
+ for row := c.Height - 1; row >= 0; row-- {
+ out += strings.Join(c.Buf[row*c.Width:(row+1)*c.Width], "") + "\n"
+ }
+
+ return
+}
+
+func (c *LineChart) DrawLine(x0, y0, x1, y1 int, symbol string) {
+ drawLine(x0, y0, x1, y1, func(x, y int) {
+ coord := y*c.Width + x
+
+ if coord > 0 && coord < len(c.Buf) {
+ c.Buf[coord] = symbol
+ }
+ })
+}
+
+func getBoundaryValues(data *DataTable, index int) (maxX, minX, maxY, minY float64) {
+ maxX = data.rows[0][0]
+ minX = data.rows[0][0]
+ maxY = data.rows[0][1]
+ minY = data.rows[0][1]
+
+ for _, r := range data.rows {
+ maxX = math.Max(maxX, r[0])
+ minX = math.Min(minX, r[0])
+
+ for idx, c := range r {
+ if idx > 0 {
+ if index == -1 || index == idx {
+ maxY = math.Max(maxY, c)
+ minY = math.Min(minY, c)
+ }
+ }
+ }
+ }
+
+ if maxY > 0 {
+ maxY = maxY * 1.1
+ } else {
+ maxY = maxY * 0.9
+ }
+
+ if minY > 0 {
+ minY = minY * 0.9
+ } else {
+ minY = minY * 1.1
+ }
+
+ return
+}
+
+// DataTable can contain data for multiple graphs, we need to extract only 1
+func getChartData(data *DataTable, index int) (out [][]float64) {
+ for _, r := range data.rows {
+ out = append(out, []float64{r[0], r[index]})
+ }
+
+ return
+}
+
+// Algorithm for drawing line between two points
+//
+// http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
+func drawLine(x0, y0, x1, y1 int, plot func(int, int)) {
+ dx := x1 - x0
+ if dx < 0 {
+ dx = -dx
+ }
+ dy := y1 - y0
+ if dy < 0 {
+ dy = -dy
+ }
+ var sx, sy int
+ if x0 < x1 {
+ sx = 1
+ } else {
+ sx = -1
+ }
+ if y0 < y1 {
+ sy = 1
+ } else {
+ sy = -1
+ }
+ err := dx - dy
+
+ for {
+ plot(x0, y0)
+ if x0 == x1 && y0 == y1 {
+ break
+ }
+ e2 := 2 * err
+ if e2 > -dy {
+ err -= dy
+ x0 += sx
+ }
+ if e2 < dx {
+ err += dx
+ y0 += sy
+ }
+ }
+}
diff --git a/vendor/github.com/buger/goterm/table.go b/vendor/github.com/buger/goterm/table.go
new file mode 100644
index 000000000..d8dae55ce
--- /dev/null
+++ b/vendor/github.com/buger/goterm/table.go
@@ -0,0 +1,34 @@
+package goterm
+
+import (
+ "bytes"
+ "text/tabwriter"
+)
+
+// Tabwriter with own buffer:
+//
+// totals := tm.NewTable(0, 10, 5, ' ', 0)
+// fmt.Fprintf(totals, "Time\tStarted\tActive\tFinished\n")
+// fmt.Fprintf(totals, "%s\t%d\t%d\t%d\n", "All", started, started-finished, finished)
+// tm.Println(totals)
+//
+// Based on http://golang.org/pkg/text/tabwriter
+type Table struct {
+ tabwriter.Writer
+
+ Buf *bytes.Buffer
+}
+
+// Same as here http://golang.org/pkg/text/tabwriter/#Writer.Init
+func NewTable(minwidth, tabwidth, padding int, padchar byte, flags uint) *Table {
+ tbl := new(Table)
+ tbl.Buf = new(bytes.Buffer)
+ tbl.Init(tbl.Buf, minwidth, tabwidth, padding, padchar, flags)
+
+ return tbl
+}
+
+func (t *Table) String() string {
+ t.Flush()
+ return t.Buf.String()
+}
diff --git a/vendor/github.com/buger/goterm/terminal.go b/vendor/github.com/buger/goterm/terminal.go
new file mode 100644
index 000000000..6b45c78bc
--- /dev/null
+++ b/vendor/github.com/buger/goterm/terminal.go
@@ -0,0 +1,258 @@
+// Provides basic bulding blocks for advanced console UI
+//
+// Coordinate system:
+//
+// 1/1---X---->
+// |
+// Y
+// |
+// v
+//
+// Documentation for ANSI codes: http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+//
+// Inspired by: http://www.darkcoding.net/software/pretty-command-line-console-output-on-unix-in-python-and-go-lang/
+package goterm
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+)
+
+// Reset all custom styles
+const RESET = "\033[0m"
+
+// Reset to default color
+const RESET_COLOR = "\033[32m"
+
+// Return curor to start of line and clean it
+const RESET_LINE = "\r\033[K"
+
+// List of possible colors
+const (
+ BLACK = iota
+ RED
+ GREEN
+ YELLOW
+ BLUE
+ MAGENTA
+ CYAN
+ WHITE
+)
+
+var Output *bufio.Writer = bufio.NewWriter(os.Stdout)
+
+func getColor(code int) string {
+ return fmt.Sprintf("\033[3%dm", code)
+}
+
+func getBgColor(code int) string {
+ return fmt.Sprintf("\033[4%dm", code)
+}
+
+// Set percent flag: num | PCT
+//
+// Check percent flag: num & PCT
+//
+// Reset percent flag: num & 0xFF
+const shift = uint(^uint(0)>>63) << 4
+const PCT = 0x8000 << shift
+
+type winsize struct {
+ Row uint16
+ Col uint16
+ Xpixel uint16
+ Ypixel uint16
+}
+
+// Global screen buffer
+// Its not recommented write to buffer dirrectly, use package Print,Printf,Println fucntions instead.
+var Screen *bytes.Buffer = new(bytes.Buffer)
+
+// Get relative or absolute coorditantes
+// To get relative, set PCT flag to number:
+//
+// // Get 10% of total width to `x` and 20 to y
+// x, y = tm.GetXY(10|tm.PCT, 20)
+//
+func GetXY(x int, y int) (int, int) {
+ if y == -1 {
+ y = CurrentHeight() + 1
+ }
+
+ if x&PCT != 0 {
+ x = int((x & 0xFF) * Width() / 100)
+ }
+
+ if y&PCT != 0 {
+ y = int((y & 0xFF) * Height() / 100)
+ }
+
+ return x, y
+}
+
+type sf func(int, string) string
+
+// Apply given transformation func for each line in string
+func applyTransform(str string, transform sf) (out string) {
+ out = ""
+
+ for idx, line := range strings.Split(str, "\n") {
+ out += transform(idx, line)
+ }
+
+ return
+}
+
+// Clear screen
+func Clear() {
+ Output.WriteString("\033[2J")
+}
+
+// Move cursor to given position
+func MoveCursor(x int, y int) {
+ fmt.Fprintf(Screen, "\033[%d;%dH", x, y)
+}
+
+// Move cursor up relative the current position
+func MoveCursorUp(bias int) {
+ fmt.Fprintf(Screen, "\033[%dA", bias)
+}
+
+// Move cursor down relative the current position
+func MoveCursorDown(bias int) {
+ fmt.Fprintf(Screen, "\033[%dB", bias)
+}
+
+// Move cursor forward relative the current position
+func MoveCursorForward(bias int) {
+ fmt.Fprintf(Screen, "\033[%dC", bias)
+}
+
+// Move cursor backward relative the current position
+func MoveCursorBackward(bias int) {
+ fmt.Fprintf(Screen, "\033[%dD", bias)
+}
+
+// Move string to possition
+func MoveTo(str string, x int, y int) (out string) {
+ x, y = GetXY(x, y)
+
+ return applyTransform(str, func(idx int, line string) string {
+ return fmt.Sprintf("\033[%d;%dH%s", y+idx, x, line)
+ })
+}
+
+// Return carrier to start of line
+func ResetLine(str string) (out string) {
+ return applyTransform(str, func(idx int, line string) string {
+ return fmt.Sprintf(RESET_LINE, line)
+ })
+}
+
+// Make bold
+func Bold(str string) string {
+ return applyTransform(str, func(idx int, line string) string {
+ return fmt.Sprintf("\033[1m%s\033[0m", line)
+ })
+}
+
+// Apply given color to string:
+//
+// tm.Color("RED STRING", tm.RED)
+//
+func Color(str string, color int) string {
+ return applyTransform(str, func(idx int, line string) string {
+ return fmt.Sprintf("%s%s%s", getColor(color), line, RESET)
+ })
+}
+
+func Highlight(str, substr string, color int) string {
+ hiSubstr := Color(substr, color)
+ return strings.Replace(str, substr, hiSubstr, -1)
+}
+
+func HighlightRegion(str string, from, to, color int) string {
+ return str[:from] + Color(str[from:to], color) + str[to:]
+}
+
+// Change background color of string:
+//
+// tm.Background("string", tm.RED)
+//
+func Background(str string, color int) string {
+ return applyTransform(str, func(idx int, line string) string {
+ return fmt.Sprintf("%s%s%s", getBgColor(color), line, RESET)
+ })
+}
+
+// Get console width
+func Width() int {
+ ws, err := getWinsize()
+
+ if err != nil {
+ return -1
+ }
+
+ return int(ws.Col)
+}
+
+// Get console height
+func Height() int {
+ ws, err := getWinsize()
+ if err != nil {
+ return -1
+ }
+ return int(ws.Row)
+}
+
+// Get current height. Line count in Screen buffer.
+func CurrentHeight() int {
+ return strings.Count(Screen.String(), "\n")
+}
+
+// Flush buffer and ensure that it will not overflow screen
+func Flush() {
+ for idx, str := range strings.Split(Screen.String(), "\n") {
+ if idx > Height() {
+ return
+ }
+
+ Output.WriteString(str + "\n")
+ }
+
+ Output.Flush()
+ Screen.Reset()
+}
+
+func Print(a ...interface{}) (n int, err error) {
+ return fmt.Fprint(Screen, a...)
+}
+
+func Println(a ...interface{}) (n int, err error) {
+ return fmt.Fprintln(Screen, a...)
+}
+
+func Printf(format string, a ...interface{}) (n int, err error) {
+ return fmt.Fprintf(Screen, format, a...)
+}
+
+func Context(data string, idx, max int) string {
+ var start, end int
+
+ if len(data[:idx]) < (max / 2) {
+ start = 0
+ } else {
+ start = idx - max/2
+ }
+
+ if len(data)-idx < (max / 2) {
+ end = len(data) - 1
+ } else {
+ end = idx + max/2
+ }
+
+ return data[start:end]
+}
diff --git a/vendor/github.com/buger/goterm/terminal_nosysioctl.go b/vendor/github.com/buger/goterm/terminal_nosysioctl.go
new file mode 100644
index 000000000..690615008
--- /dev/null
+++ b/vendor/github.com/buger/goterm/terminal_nosysioctl.go
@@ -0,0 +1,12 @@
+// +build windows plan9 solaris
+
+package goterm
+
+func getWinsize() (*winsize, error) {
+ ws := new(winsize)
+
+ ws.Col = 80
+ ws.Row = 24
+
+ return ws, nil
+}
diff --git a/vendor/github.com/buger/goterm/terminal_sysioctl.go b/vendor/github.com/buger/goterm/terminal_sysioctl.go
new file mode 100644
index 000000000..e98430fb9
--- /dev/null
+++ b/vendor/github.com/buger/goterm/terminal_sysioctl.go
@@ -0,0 +1,36 @@
+// +build !windows,!plan9,!solaris
+
+package goterm
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+func getWinsize() (*winsize, error) {
+ ws := new(winsize)
+
+ var _TIOCGWINSZ int64
+
+ switch runtime.GOOS {
+ case "linux":
+ _TIOCGWINSZ = 0x5413
+ case "darwin":
+ _TIOCGWINSZ = 1074295912
+ }
+
+ r1, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
+ uintptr(syscall.Stdin),
+ uintptr(_TIOCGWINSZ),
+ uintptr(unsafe.Pointer(ws)),
+ )
+
+ if int(r1) == -1 {
+ fmt.Println("Error:", os.NewSyscallError("GetWinsize", errno))
+ return nil, os.NewSyscallError("GetWinsize", errno)
+ }
+ return ws, nil
+}