aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/awesome-gocui/gocui/view.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/awesome-gocui/gocui/view.go')
-rw-r--r--vendor/github.com/awesome-gocui/gocui/view.go800
1 files changed, 0 insertions, 800 deletions
diff --git a/vendor/github.com/awesome-gocui/gocui/view.go b/vendor/github.com/awesome-gocui/gocui/view.go
deleted file mode 100644
index 81f90603..00000000
--- a/vendor/github.com/awesome-gocui/gocui/view.go
+++ /dev/null
@@ -1,800 +0,0 @@
-// Copyright 2014 The gocui Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gocui
-
-import (
- "bytes"
- "io"
- "strings"
- "sync"
- "unicode/utf8"
-
- "github.com/go-errors/errors"
-
- "github.com/awesome-gocui/termbox-go"
- "github.com/mattn/go-runewidth"
-)
-
-// Constants for overlapping edges
-const (
- TOP = 1 // view is overlapping at top edge
- BOTTOM = 2 // view is overlapping at bottom edge
- LEFT = 4 // view is overlapping at left edge
- RIGHT = 8 // view is overlapping at right edge
-)
-
-var (
- // ErrInvalidPoint is returned when client passed invalid coordinates of a cell.
- // Most likely client has passed negative coordinates of a cell.
- ErrInvalidPoint = errors.New("invalid point")
-)
-
-// A View is a window. It maintains its own internal buffer and cursor
-// position.
-type View struct {
- name string
- x0, y0, x1, y1 int // left top right bottom
- ox, oy int // view offsets
- cx, cy int // cursor position
- rx, ry int // Read() offsets
- wx, wy int // Write() offsets
- lines [][]cell // All the data
-
- // readBuffer is used for storing unread bytes
- readBuffer []byte
-
- // tained is true if the viewLines must be updated
- tainted bool
-
- // internal representation of the view's buffer
- viewLines []viewLine
-
- // writeMutex protects locks the write process
- writeMutex sync.Mutex
-
- // ei is used to decode ESC sequences on Write
- ei *escapeInterpreter
-
- // Visible specifies whether the view is visible.
- Visible bool
-
- // BgColor and FgColor allow to configure the background and foreground
- // colors of the View.
- BgColor, FgColor Attribute
-
- // SelBgColor and SelFgColor are used to configure the background and
- // foreground colors of the selected line, when it is highlighted.
- SelBgColor, SelFgColor Attribute
-
- // If Editable is true, keystrokes will be added to the view's internal
- // buffer at the cursor position.
- Editable bool
-
- // Editor allows to define the editor that manages the editing mode,
- // including keybindings or cursor behaviour. DefaultEditor is used by
- // default.
- Editor Editor
-
- // Overwrite enables or disables the overwrite mode of the view.
- Overwrite bool
-
- // If Highlight is true, Sel{Bg,Fg}Colors will be used
- // for the line under the cursor position.
- Highlight bool
-
- // If Frame is true, a border will be drawn around the view.
- Frame bool
-
- // If Wrap is true, the content that is written to this View is
- // automatically wrapped when it is longer than its width. If true the
- // view's x-origin will be ignored.
- Wrap bool
-
- // If Autoscroll is true, the View will automatically scroll down when the
- // text overflows. If true the view's y-origin will be ignored.
- Autoscroll bool
-
- // If Frame is true, Title allows to configure a title for the view.
- Title string
-
- // If Frame is true, Subtitle allows to configure a subtitle for the view.
- Subtitle string
-
- // If Mask is true, the View will display the mask instead of the real
- // content
- Mask rune
-
- // Overlaps describes which edges are overlapping with another view's edges
- Overlaps byte
-
- // If HasLoader is true, the message will be appended with a spinning loader animation
- HasLoader bool
-}
-
-type viewLine struct {
- linesX, linesY int // coordinates relative to v.lines
- line []cell
-}
-
-type cell struct {
- chr rune
- bgColor, fgColor Attribute
-}
-
-type lineType []cell
-
-// String returns a string from a given cell slice.
-func (l lineType) String() string {
- str := ""
- for _, c := range l {
- str += string(c.chr)
- }
- return str
-}
-
-// newView returns a new View object.
-func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
- v := &View{
- name: name,
- x0: x0,
- y0: y0,
- x1: x1,
- y1: y1,
- Visible: true,
- Frame: true,
- Editor: DefaultEditor,
- tainted: true,
- ei: newEscapeInterpreter(mode),
- }
- return v
-}
-
-// Dimensions returns the dimensions of the View
-func (v *View) Dimensions() (int, int, int, int) {
- return v.x0, v.y0, v.x1, v.y1
-}
-
-// Size returns the number of visible columns and rows in the View.
-func (v *View) Size() (x, y int) {
- return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
-}
-
-// Name returns the name of the view.
-func (v *View) Name() string {
- return v.name
-}
-
-// setRune sets a rune at the given point relative to the view. It applies the
-// specified colors, taking into account if the cell must be highlighted. Also,
-// it checks if the position is valid.
-func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
- maxX, maxY := v.Size()
- if x < 0 || x >= maxX || y < 0 || y >= maxY {
- return ErrInvalidPoint
- }
- var (
- ry, rcy int
- err error
- )
- if v.Highlight {
- _, ry, err = v.realPosition(x, y)
- if err != nil {
- return err
- }
- _, rcy, err = v.realPosition(v.cx, v.cy)
- if err != nil {
- return err
- }
- }
-
- if v.Mask != 0 {
- fgColor = v.FgColor
- bgColor = v.BgColor
- ch = v.Mask
- } else if v.Highlight && ry == rcy {
- fgColor = fgColor | AttrBold
- }
-
- // Don't display NUL characters
- if ch == 0 {
- ch = ' '
- }
-
- termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
- termbox.Attribute(fgColor), termbox.Attribute(bgColor))
-
- return nil
-}
-
-// SetCursor sets the cursor position of the view at the given point,
-// relative to the view. It checks if the position is valid.
-func (v *View) SetCursor(x, y int) error {
- maxX, maxY := v.Size()
- if x < 0 || x >= maxX || y < 0 || y >= maxY {
- return ErrInvalidPoint
- }
- v.cx = x
- v.cy = y
- return nil
-}
-
-// Cursor returns the cursor position of the view.
-func (v *View) Cursor() (x, y int) {
- return v.cx, v.cy
-}
-
-// SetOrigin sets the origin position of the view's internal buffer,
-// so the buffer starts to be printed from this point, which means that
-// it is linked with the origin point of view. It can be used to
-// implement Horizontal and Vertical scrolling with just incrementing
-// or decrementing ox and oy.
-func (v *View) SetOrigin(x, y int) error {
- if x < 0 || y < 0 {
- return ErrInvalidPoint
- }
- v.ox = x
- v.oy = y
- return nil
-}
-
-// Origin returns the origin position of the view.
-func (v *View) Origin() (x, y int) {
- return v.ox, v.oy
-}
-
-// SetWritePos sets the write position of the view's internal buffer.
-// So the next Write call would write directly to the specified position.
-func (v *View) SetWritePos(x, y int) error {
- if x < 0 || y < 0 {
- return ErrInvalidPoint
- }
- v.wx = x
- v.wy = y
- return nil
-}
-
-// WritePos returns the current write position of the view's internal buffer.
-func (v *View) WritePos() (x, y int) {
- return v.wx, v.wy
-}
-
-// SetReadPos sets the read position of the view's internal buffer.
-// So the next Read call would read from the specified position.
-func (v *View) SetReadPos(x, y int) error {
- if x < 0 || y < 0 {
- return ErrInvalidPoint
- }
- v.readBuffer = nil
- v.rx = x
- v.ry = y
- return nil
-}
-
-// ReadPos returns the current read position of the view's internal buffer.
-func (v *View) ReadPos() (x, y int) {
- return v.rx, v.ry
-}
-
-// makeWriteable creates empty cells if required to make position (x, y) writeable.
-func (v *View) makeWriteable(x, y int) {
- // TODO: make this more efficient
-
- // line `y` must be index-able (that's why `<=`)
- for len(v.lines) <= y {
- if cap(v.lines) > len(v.lines) {
- newLen := cap(v.lines)
- if newLen > y {
- newLen = y + 1
- }
- v.lines = v.lines[:newLen]
- } else {
- v.lines = append(v.lines, nil)
- }
- }
- // cell `x` must not be index-able (that's why `<`)
- // append should be used by `lines[y]` user if he wants to write beyond `x`
- for len(v.lines[y]) < x {
- if cap(v.lines[y]) > len(v.lines[y]) {
- newLen := cap(v.lines[y])
- if newLen > x {
- newLen = x
- }
- v.lines[y] = v.lines[y][:newLen]
- } else {
- v.lines[y] = append(v.lines[y], cell{})
- }
- }
-}
-
-// writeCells copies []cell to specified location (x, y)
-// !!! caller MUST ensure that specified location (x, y) is writeable by calling makeWriteable
-func (v *View) writeCells(x, y int, cells []cell) {
- var newLen int
- // use maximum len available
- line := v.lines[y][:cap(v.lines[y])]
- maxCopy := len(line) - x
- if maxCopy < len(cells) {
- copy(line[x:], cells[:maxCopy])
- line = append(line, cells[maxCopy:]...)
- newLen = len(line)
- } else { // maxCopy >= len(cells)
- copy(line[x:], cells)
- newLen = x + len(cells)
- if newLen < len(v.lines[y]) {
- newLen = len(v.lines[y])
- }
- }
- v.lines[y] = line[:newLen]
-}
-
-// Write appends a byte slice into the view's internal buffer. Because
-// View implements the io.Writer interface, it can be passed as parameter
-// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
-// be called to clear the view's buffer.
-func (v *View) Write(p []byte) (n int, err error) {
- v.tainted = true
- v.writeMutex.Lock()
- v.makeWriteable(v.wx, v.wy)
- v.writeRunes(bytes.Runes(p))
- v.writeMutex.Unlock()
-
- return len(p), nil
-}
-
-func (v *View) WriteRunes(p []rune) {
- v.tainted = true
-
- // Fill with empty cells, if writing outside current view buffer
- v.makeWriteable(v.wx, v.wy)
- v.writeRunes(p)
-}
-
-func (v *View) WriteString(s string) {
- v.WriteRunes([]rune(s))
-}
-
-// writeRunes copies slice of runes into internal lines buffer.
-// caller must make sure that writing position is accessable.
-func (v *View) writeRunes(p []rune) {
- for _, r := range p {
- switch r {
- case '\n':
- v.wy++
- if v.wy >= len(v.lines) {
- v.lines = append(v.lines, nil)
- }
-
- fallthrough
- // not valid in every OS, but making runtime OS checks in cycle is bad.
- case '\r':
- v.wx = 0
- default:
- cells := v.parseInput(r)
- if cells == nil {
- continue
- }
- v.writeCells(v.wx, v.wy, cells)
- v.wx += len(cells)
- }
- }
-}
-
-// parseInput parses char by char the input written to the View. It returns nil
-// while processing ESC sequences. Otherwise, it returns a cell slice that
-// contains the processed data.
-func (v *View) parseInput(ch rune) []cell {
- cells := []cell{}
-
- isEscape, err := v.ei.parseOne(ch)
- if err != nil {
- for _, r := range v.ei.runes() {
- c := cell{
- fgColor: v.FgColor,
- bgColor: v.BgColor,
- chr: r,
- }
- cells = append(cells, c)
- }
- v.ei.reset()
- } else {
- if isEscape {
- return nil
- }
- repeatCount := 1
- if ch == '\t' {
- ch = ' '
- repeatCount = 4
- }
- for i := 0; i < repeatCount; i++ {
- c := cell{
- fgColor: v.ei.curFgColor,
- bgColor: v.ei.curBgColor,
- chr: ch,
- }
- cells = append(cells, c)
- }
- }
-
- return cells
-}
-
-// Read reads data into p from the current reading position set by SetReadPos.
-// It returns the number of bytes read into p.
-// At EOF, err will be io.EOF.
-func (v *View) Read(p []byte) (n int, err error) {
- buffer := make([]byte, utf8.UTFMax)
- offset := 0
- if v.readBuffer != nil {
- copy(p, v.readBuffer)
- if len(v.readBuffer) >= len(p) {
- if len(v.readBuffer) > len(p) {
- v.readBuffer = v.readBuffer[len(p):]
- }
- return len(p), nil
- }
- v.readBuffer = nil
- }
- for v.ry < len(v.lines) {
- for v.rx < len(v.lines[v.ry]) {
- count := utf8.EncodeRune(buffer, v.lines[v.ry][v.rx].chr)
- copy(p[offset:], buffer[:count])
- v.rx++
- newOffset := offset + count
- if newOffset >= len(p) {
- if newOffset > len(p) {
- v.readBuffer = buffer[newOffset-len(p):]
- }
- return len(p), nil
- }
- offset += count
- }
- v.rx = 0
- v.ry++
- }
- return offset, io.EOF
-}
-
-// Rewind sets read and write pos to (0, 0).
-func (v *View) Rewind() {
- if err := v.SetReadPos(0, 0); err != nil {
- // SetReadPos returns error only if x and y are negative
- // we are passing 0, 0, thus no error should occur.
- panic(err)
- }
- if err := v.SetWritePos(0, 0); err != nil {
- // SetWritePos returns error only if x and y are negative
- // we are passing 0, 0, thus no error should occur.
- panic(err)
- }
-}
-
-// IsTainted tells us if the view is tainted
-func (v *View) IsTainted() bool {
- return v.tainted
-}
-
-// draw re-draws the view's contents.
-func (v *View) draw() error {
- if !v.Visible {
- return nil
- }
-
- maxX, maxY := v.Size()
-
- if v.Wrap {
- if maxX == 0 {
- return errors.New("X size of the view cannot be 0")
- }
- v.ox = 0
- }
- if v.tainted {
- v.viewLines = nil
- lines := v.lines
- if v.HasLoader {
- lines = v.loaderLines()
- }
- for i, line := range lines {
- wrap := 0
- if v.Wrap {
- wrap = maxX
- }
-
- ls := lineWrap(line, wrap)
- for j := range ls {
- vline := viewLine{linesX: j, linesY: i, line: ls[j]}
- v.viewLines = append(v.viewLines, vline)
- }
- }
- if !v.HasLoader {
- v.tainted = false
- }
- }
-
- if v.Autoscroll && len(v.viewLines) > maxY {
- v.oy = len(v.viewLines) - maxY
- }
- y := 0
- for i, vline := range v.viewLines {
- if i < v.oy {
- continue
- }
- if y >= maxY {
- break
- }
- x := 0
- for j, c := range vline.line {
- if j < v.ox {
- continue
- }
- if x >= maxX {
- break
- }
-
- fgColor := c.fgColor
- if fgColor == ColorDefault {
- fgColor = v.FgColor
- }
- bgColor := c.bgColor
- if bgColor == ColorDefault {
- bgColor = v.BgColor
- }
-
- if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
- return err
- }
-
- if c.chr != 0 {
- // If it is a rune, add rune width
- x += runewidth.RuneWidth(c.chr)
- } else {
- // If it is NULL rune, add 1 to be able to use SetWritePos
- // (runewidth.RuneWidth of space is 1)
- x++
- }
- }
- y++
- }
- return nil
-}
-
-// realPosition returns the position in the internal buffer corresponding to the
-// point (x, y) of the view.
-func (v *View) realPosition(vx, vy int) (x, y int, err error) {
- vx = v.ox + vx
- vy = v.oy + vy
-
- if vx < 0 || vy < 0 {
- return 0, 0, ErrInvalidPoint
- }
-
- if len(v.viewLines) == 0 {
- return vx, vy, nil
- }
-
- if vy < len(v.viewLines) {
- vline := v.viewLines[vy]
- x = vline.linesX + vx
- y = vline.linesY
- } else {
- vline := v.viewLines[len(v.viewLines)-1]
- x = vx
- y = vline.linesY + vy - len(v.viewLines) + 1
- }
-
- return x, y, nil
-}
-
-// Clear empties the view's internal buffer.
-// And resets reading and writing offsets.
-func (v *View) Clear() {
- v.writeMutex.Lock()
- v.Rewind()
- v.tainted = true
- v.ei.reset()
- v.lines = nil
- v.viewLines = nil
- v.clearRunes()
- v.writeMutex.Unlock()
-}
-
-// clearRunes erases all the cells in the view.
-func (v *View) clearRunes() {
- maxX, maxY := v.Size()
- for x := 0; x < maxX; x++ {
- for y := 0; y < maxY; y++ {
- termbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',
- termbox.Attribute(v.FgColor), termbox.Attribute(v.BgColor))
- }
- }
-}
-
-// BufferLines returns the lines in the view's internal
-// buffer.
-func (v *View) BufferLines() []string {
- lines := make([]string, len(v.lines))
- for i, l := range v.lines {
- str := lineType(l).String()
- str = strings.Replace(str, "\x00", " ", -1)
- lines[i] = str
- }
- return lines
-}
-
-// Buffer returns a string with the contents of the view's internal
-// buffer.
-func (v *View) Buffer() string {
- return linesToString(v.lines)
-}
-
-// ViewBufferLines returns the lines in the view's internal
-// buffer that is shown to the user.
-func (v *View) ViewBufferLines() []string {
- lines := make([]string, len(v.viewLines))
- for i, l := range v.viewLines {
- str := lineType(l.line).String()
- str = strings.Replace(str, "\x00", " ", -1)
- lines[i] = str
- }
- return lines
-}
-
-// LinesHeight is the count of view lines (i.e. lines excluding wrapping)
-func (v *View) LinesHeight() int {
- return len(v.lines)
-}
-
-// ViewLinesHeight is the count of view lines (i.e. lines including wrapping)
-func (v *View) ViewLinesHeight() int {
- return len(v.viewLines)
-}
-
-// ViewBuffer returns a string with the contents of the view's buffer that is
-// shown to the user.
-func (v *View) ViewBuffer() string {
- lines := make([][]cell, len(v.viewLines))
- for i := range v.viewLines {
- lines[i] = v.viewLines[i].line
- }
-
- return linesToString(lines)
-}
-
-// Line returns a string with the line of the view's internal buffer
-// at the position corresponding to the point (x, y).
-func (v *View) Line(y int) (string, error) {
- _, y, err := v.realPosition(0, y)
- if err != nil {
- return "", err
- }
-
- if y < 0 || y >= len(v.lines) {
- return "", ErrInvalidPoint
- }
-
- return lineType(v.lines[y]).String(), nil
-}
-
-// Word returns a string with the word of the view's internal buffer
-// at the position corresponding to the point (x, y).
-func (v *View) Word(x, y int) (string, error) {
- x, y, err := v.realPosition(x, y)
- if err != nil {
- return "", err
- }
-
- if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
- return "", ErrInvalidPoint
- }
-
- str := lineType(v.lines[y]).String()
-
- nl := strings.LastIndexFunc(str[:x], indexFunc)
- if nl == -1 {
- nl = 0
- } else {
- nl = nl + 1
- }
- nr := strings.IndexFunc(str[x:], indexFunc)
- if nr == -1 {
- nr = len(str)
- } else {
- nr = nr + x
- }
- return string(str[nl:nr]), nil
-}
-
-// indexFunc allows to split lines by words taking into account spaces
-// and 0.
-func indexFunc(r rune) bool {
- return r == ' ' || r == 0
-}
-
-// SetLine changes the contents of an existing line.
-func (v *View) SetLine(y int, text string) error {
- if y < 0 || y >= len(v.lines) {
- err := ErrInvalidPoint
- return err
- }
-
- v.tainted = true
- line := make([]cell, 0)
- for _, r := range text {
- c := v.parseInput(r)
- line = append(line, c...)
- }
- v.lines[y] = line
- return nil
-}
-
-// SetHighlight toggles highlighting of separate lines, for custom lists
-// or multiple selection in views.
-func (v *View) SetHighlight(y int, on bool) error {
- if y < 0 || y >= len(v.lines) {
- err := ErrInvalidPoint
- return err
- }
-
- line := v.lines[y]
- cells := make([]cell, 0)
- for _, c := range line {
- if on {
- c.bgColor = v.SelBgColor
- c.fgColor = v.SelFgColor
- } else {
- c.bgColor = v.BgColor
- c.fgColor = v.FgColor
- }
- cells = append(cells, c)
- }
- v.tainted = true
- v.lines[y] = cells
- return nil
-}
-
-func lineWidth(line []cell) (n int) {
- for i := range line {
- n += runewidth.RuneWidth(line[i].chr)
- }
-
- return
-}
-
-func lineWrap(line []cell, columns int) [][]cell {
- if columns == 0 {
- return [][]cell{line}
- }
-
- var n int
- var offset int
- lines := make([][]cell, 0, 1)
- for i := range line {
- rw := runewidth.RuneWidth(line[i].chr)
- n += rw
- if n > columns {
- n = rw
- lines = append(lines, line[offset:i])
- offset = i
- }
- }
-
- lines = append(lines, line[offset:])
- return lines
-}
-
-func linesToString(lines [][]cell) string {
- str := make([]string, len(lines))
- for i := range lines {
- rns := make([]rune, 0, len(lines[i]))
- line := lineType(lines[i]).String()
- for _, c := range line {
- if c != '\x00' {
- rns = append(rns, c)
- }
- }
- str[i] = string(rns)
- }
-
- return strings.Join(str, "\n")
-}