196 lines
4.6 KiB
Go
196 lines
4.6 KiB
Go
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) && r != '\n' {
|
||
return option.Some(ErrInvalidUnicode)
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// VisibleWith indique le nombre de colonnes nécessaires
|
||
// pour afficher d’une 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 jusqu’au 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 l’historique de l’affichage.
|
||
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--
|
||
}
|
||
}
|