mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			177 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
package goterm
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
	_ "unicode/utf8"
 | 
						|
)
 | 
						|
 | 
						|
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)
 | 
						|
}
 | 
						|
 | 
						|
var ANSI_RE = regexp.MustCompile(`\\0\d+\[\d+(?:;\d+)?m`)
 | 
						|
 | 
						|
// String renders 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 = ""
 | 
						|
			}
 | 
						|
 | 
						|
			r := []rune(line)
 | 
						|
 | 
						|
			lastAnsii := ""
 | 
						|
			withoutAnsii := []rune{}
 | 
						|
			withOffset := []rune{}
 | 
						|
			i := 0
 | 
						|
 | 
						|
			for {
 | 
						|
				if i >= len(r) {
 | 
						|
					break
 | 
						|
				}
 | 
						|
 | 
						|
				if r[i] == 27 {
 | 
						|
					lastAnsii = ""
 | 
						|
					withOffset = append(withOffset, r[i])
 | 
						|
					lastAnsii += string(r[i])
 | 
						|
					i++
 | 
						|
					for {
 | 
						|
 | 
						|
						i++
 | 
						|
						if i > len(r) {
 | 
						|
							break
 | 
						|
						}
 | 
						|
 | 
						|
						withOffset = append(withOffset, r[i])
 | 
						|
						lastAnsii += string(r[i])
 | 
						|
 | 
						|
						if r[i] == 'm' {
 | 
						|
							i++
 | 
						|
							break
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if i >= len(r) {
 | 
						|
					break
 | 
						|
				}
 | 
						|
 | 
						|
				withoutAnsii = append(withoutAnsii, r[i])
 | 
						|
 | 
						|
				if len(withoutAnsii) <= contentWidth {
 | 
						|
					withOffset = append(withOffset, r[i])
 | 
						|
				}
 | 
						|
 | 
						|
				i++
 | 
						|
			}
 | 
						|
 | 
						|
			if len(withoutAnsii) > contentWidth {
 | 
						|
				// If line is too large limit it
 | 
						|
				line = string(withOffset)
 | 
						|
			} else {
 | 
						|
				// If line is too small enlarge it by adding spaces
 | 
						|
				line += strings.Repeat(" ", contentWidth-len(withoutAnsii))
 | 
						|
			}
 | 
						|
 | 
						|
			if lastAnsii != "" {
 | 
						|
				line += RESET
 | 
						|
			}
 | 
						|
 | 
						|
			line = prefix + line + suffix
 | 
						|
		}
 | 
						|
 | 
						|
		// Don't add newline for last element
 | 
						|
		if y != b.Height-1 {
 | 
						|
			line += "\n"
 | 
						|
		}
 | 
						|
 | 
						|
		out += line
 | 
						|
	}
 | 
						|
 | 
						|
	return out
 | 
						|
}
 |