gob/shell/console/atom/output.go

196 lines
4.6 KiB
Go
Raw Normal View History

2023-10-07 19:13:39 +00:00
package atom
import (
"errors"
"fmt"
"strings"
"unicode"
"unicode/utf8"
"gitea.zaclys.com/bvaudour/gob/option"
)
var (
ErrInvalidUnicode = errors.New("Not unicode")
)
// NextUnescape enlève le caractère déchapement en début de chaîne.
func NextUnescape(str string) (result option.Option[string]) {
if !strings.HasPrefix(str, "\033[") {
result = option.Some(str)
} else if i := strings.Index(str, "m"); i >= 0 {
result = option.Some(str[i+1:])
}
return
}
// IsPrintable retourne vrai si le caractère donné est imprimable.
func IsPrintable(r Char) bool {
return r == '\n' || unicode.IsPrint(r)
}
// IsSpace retourne vrai si le caractère donné est un caractère blanc.
func IsSpace(r Char) bool {
return unicode.IsSpace(r)
}
// CheckUnicode vérifie si la chaîne de caractère
// ne contient que des caractères imprimables.
func CheckUnicode(str string) (err option.Option[error]) {
runes := []rune(str)
for i, r := range runes {
if r == Esc {
if i == len(runes)-1 || runes[i+1] != '[' {
return option.Some(ErrInvalidUnicode)
}
} else if unicode.Is(unicode.C, r) {
return option.Some(ErrInvalidUnicode)
}
}
return
}
// VisibleWith indique le nombre de colonnes nécessaires
// pour afficher dune chaîne passée à echo.
func VisibleWidth(str string) int {
w := 0
for len(str) > 0 {
cleaned := NextUnescape(str)
if s, ok := cleaned.Get(); ok {
str = s
} else {
break
}
r, i := utf8.DecodeRuneInString(str)
if IsPrintable(r) {
w++
}
str = str[i:]
}
return w
}
// CursorOffset calcule la position relative du curseur
// par rapport au début de la chaîne, ainsi que le
// le n° de la dernière ligne (en commençant de 0).
func CursorOffset(str string, p, w int) (px, py, l int) {
if len(str) == 0 {
return
}
var (
n, c int
)
for len(str) > 0 {
cleaned := NextUnescape(str)
if s, ok := cleaned.Get(); ok {
str = s
} else {
break
}
r, i := utf8.DecodeRuneInString(str)
str = str[i:]
if IsPrintable(r) {
if p == n {
px, py = c, l
}
n++
if r == '\n' {
c, l = 0, l+1
} else {
c++
if c == w {
c, l = 0, l+1
}
}
}
}
if p >= n {
px, py = c, l
}
return
}
// ClearBeginOfLine efface le début de la ligne, curseur compris
func ClearBeginOfLine() { fmt.Print("\033[1K") }
// ClearEndOfLine efface la fin de la ligne, curseur compris.
func ClearEndOfLine() { fmt.Print("\033[0K") }
// ClearLine efface toute la ligne.
func ClearLine() { fmt.Print("\033[2K") }
// ClearBeginOfScreen efface lécran jusquau curseur, curseur compris.
func ClearBeginOfScreen() { fmt.Print("\033[1J") }
// ClearBeginOfScreen efface lécran à partir du curseur, curseur compris.
func ClearEndOfScreen() { fmt.Print("\033[0J") }
// ClearAllScreen efface tout lécran.
func ClearAllScreen() { fmt.Print("\033[2J") }
// ClearAllScreenAndHistory efface tout lécran, ainsi que lhistorique de laffichage.
func ClearAllScreenAndHistory() { fmt.Print("\033[3J") }
// MoveUp déplace le curseur de c lignes vers le haut.
func MoveUp(c int) { fmt.Printf("\033[%dA", c) }
// MoveDown déplace le curseur de c lignes vers le bas.
func MoveDown(c int) { fmt.Printf("\033[%dB", c) }
// MoveLeft déplace le curseur de c colonnes vers la gauche.
func MoveLeft(c int) { fmt.Printf("\033[%dD", c) }
// MoveRight déplace le curseur de c colonnes vers la droite.
func MoveRight(c int) { fmt.Printf("\033[%dC", c) }
// MoveLineUp se déplace de c lignes vers le haut et revient en début de ligne.
func MoveLineUp(c int) { fmt.Printf("\033[%dF", c) }
// MoveLineDown se déplace de c lignes vers le bas et revient en début de ligne.
func MoveLineDown(c int) { fmt.Printf("\033[%dE", c) }
// MoveToColumn se déplace à la colonne c. La colonne commence à 1.
func MoveToColumn(c int) { fmt.Printf("\033[%dG", c) }
// MoveToScreen se déplace à la ligne l et la colonne c de lécran.
// l et c commencent à 1.
func MoveToScreen(l, c int) { fmt.Print("\033[%d;%dH", l, c) }
// MoveTopLeft se déplace au tout début de lécran
func MoveTopLeft() { MoveToScreen(1, 1) }
// SaveCursorPosition enregistre la position du curseur
// pour pouvoir y revenir plus tard.
func SaveCursorPosition() { fmt.Print("\033[s") }
// RestoreCursorPosition revient à la position précédemment enregistrée.
func RestoreCursorPosition() { fmt.Print("\033[u") }
// Beep émet un beep.
func Beep() { fmt.Print("\a") }
// CarriageReturn revient en début de ligne.
func CarriageReturn() { fmt.Print("\r") }
// NewLines rajoute c lignes.
func NewLines(c int) {
for c > 0 {
fmt.Print("\n")
c--
}
}