mirror of
https://github.com/Maks1mS/bubbles.git
synced 2024-12-25 15:04:39 +03:00
99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
package viewport
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type renderer struct {
|
|
Out io.Writer
|
|
Y int
|
|
Height int
|
|
TerminalWidth int
|
|
TerminalHeight int
|
|
}
|
|
|
|
// sync paints the whole area.
|
|
func (r *renderer) sync(content string) {
|
|
r.clear()
|
|
moveTo(r.Out, r.Y, 0)
|
|
r.write(content)
|
|
}
|
|
|
|
// clear clears the viewport region.
|
|
func (r *renderer) clear() {
|
|
b := new(bytes.Buffer)
|
|
moveTo(b, r.Y, 0)
|
|
for i := 0; i < r.Height; i++ {
|
|
clearLine(b)
|
|
cursorDown(b, 1)
|
|
}
|
|
r.Out.Write(b.Bytes())
|
|
}
|
|
|
|
// write writes to the set writer.
|
|
func (r *renderer) write(s string) {
|
|
if len(s) == 0 {
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for _, r := range []rune(s) {
|
|
if r == '\n' {
|
|
buf.WriteString("\r\n")
|
|
continue
|
|
}
|
|
buf.WriteRune(r)
|
|
}
|
|
|
|
r.Out.Write(buf.Bytes())
|
|
}
|
|
|
|
// Effectively scroll up. That is, insert a line at the top, scrolling
|
|
// everything else down. This is roughly how ncurses does it.
|
|
func (r *renderer) insertTop(line string) {
|
|
changeScrollingRegion(r.Out, r.Y, r.Y+r.Height)
|
|
moveTo(r.Out, r.Y, 0)
|
|
insertLine(r.Out, 1)
|
|
io.WriteString(r.Out, line)
|
|
changeScrollingRegion(r.Out, r.TerminalWidth, r.TerminalHeight)
|
|
}
|
|
|
|
// Effectively scroll down. That is, insert a line at the bottom, scrolling
|
|
// everything else up. This is roughly how ncurses does it.
|
|
func (r *renderer) insertBottom(line string) {
|
|
changeScrollingRegion(r.Out, r.Y, r.Y+r.Height)
|
|
moveTo(r.Out, r.Y+r.Height, 0)
|
|
io.WriteString(r.Out, "\n"+line)
|
|
changeScrollingRegion(r.Out, r.TerminalWidth, r.TerminalHeight)
|
|
}
|
|
|
|
// Screen command
|
|
|
|
const csi = "\x1b["
|
|
|
|
func changeScrollingRegion(w io.Writer, top, bottom int) {
|
|
fmt.Fprintf(w, csi+"%d;%dr", top, bottom)
|
|
}
|
|
|
|
func moveTo(w io.Writer, row, col int) {
|
|
fmt.Fprintf(w, csi+"%d;%dH", row, col)
|
|
}
|
|
|
|
func cursorDown(w io.Writer, numLines int) {
|
|
fmt.Fprintf(w, csi+"%dB", numLines)
|
|
}
|
|
|
|
func cursorDownString(numLines int) string {
|
|
return fmt.Sprintf(csi+"%dB", numLines)
|
|
}
|
|
|
|
func clearLine(w io.Writer) {
|
|
fmt.Fprint(w, csi+"2K")
|
|
}
|
|
|
|
func insertLine(w io.Writer, numLines int) {
|
|
fmt.Fprintf(w, csi+"%dL", numLines)
|
|
}
|