gob/shell/console/console.go

176 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package console
import (
"fmt"
"io"
"os"
"regexp"
"strings"
. "gitea.zaclys.com/bvaudour/gob/option"
)
// Cycler est une interface permettant de cycler dans les entrées dune liste.
type Cycler interface {
Len() int // Retourne la longueur de la liste
Cursor() int // Retourne lindex de lentrée pointée
Index(int) Option[string] // Retourne lentrée à lindex donné
SetCursor(int) bool // Déplace lentrée pointée à lindex demandé et retourne vrai si cet index existe
Append(string) // Ajoute une entrée dans la liste
Clear() // Efface la liste
Next() bool // Pointe vers lentrée suivante
Prev() bool // Pointe vers lentrée précédente
}
// History est une interface pour gérer lhistorique des commandes saisies.
type History interface {
Cycler
Read(io.Reader) Result[int]
Write(io.Writer) Result[int]
}
// Prompter est une interface pour représenter un prompt.
type Prompter interface {
Prompt(string) Result[string] // Affiche le prompt et retourne la saisie
}
// Console est un prompt avec gestion de lhistorique.
type Console interface {
Prompter
LoadHistory(io.Reader) Result[int]
SaveHistory(io.Writer) Result[int]
ClearHistory()
AppendHistory(string)
}
// Error représente une erreur terminal
type Error interface {
Error() string
Code() int
}
// Exit quitte le programme en affichant une erreur.
// Si aucun descripteur nest fourni, le message derreur
// est écrit sur la sortie erreur standard.
func Exit(code int, msg string, w ...io.Writer) {
var out io.Writer
if len(w) > 0 {
out = w[0]
} else {
out = os.Stderr
}
fmt.Fprintln(out, msg)
os.Exit(code)
}
// ExitfOn agit comme Exit mais mais formate le message.
func ExitfOn(code int, tmpl string, w io.Writer, args ...any) {
msg := fmt.Sprintf(tmpl, args...)
Exit(code, msg, w)
}
// Exitf agit comme ExitfOn sur la sortie erreur standard.
func Exitf(code int, tmpl string, args ...any) {
ExitfOn(code, tmpl, os.Stderr, args...)
}
// ExitWithError quitte le programme en utilisant
// lerreur fournie.
func ExitWithError(err Error, w ...io.Writer) {
Exit(err.Code(), err.Error(), w...)
}
// HistoryList retourne le contenu de lhistorique.
func HistoryList(h History) (out []string) {
l := h.Len()
out = make([]string, l)
for i := 0; i < l; i++ {
if line, ok := h.Index(i).Get(); ok {
out[i] = line
}
}
return
}
func hfilter(h History, motive string, cb func(string, string) bool, insensitive ...bool) (out []string) {
l := h.Len()
if l == 0 {
return
}
ins := false
if len(insensitive) > 0 {
ins = insensitive[0]
}
var cmp func(string) bool
if ins {
motive = strings.ToLower(motive)
cmp = func(e string) bool {
return cb(strings.ToLower(e), motive)
}
} else {
cmp = func(e string) bool { return cb(e, motive) }
}
for i := 0; i < l; i++ {
if e, ok := h.Index(i).Get(); ok && cmp(e) {
out = append(out, e)
}
}
return
}
// HistoryFilterMotive retourne les entrées de lhistorique contenant le motif donné.
// Il est possible de faire une recherche insensible à la casse.
func HistoryFilterMotive(h History, motive string, insensitive ...bool) (out []string) {
return hfilter(h, motive, strings.Contains, insensitive...)
}
// HistoryFilterPrefix retourne les entrées de lhistorique commençant le préfixe donné.
// Il est possible de faire une recherche insensible à la casse.
func HistoryFilterPrefix(h History, prefix string, insensitive ...bool) (out []string) {
return hfilter(h, prefix, strings.HasPrefix, insensitive...)
}
// HistoryFilterSuffix retourne les entrées de lhistorique terminant par le suffixe donné.
// Il est possible de faire une recherche insensible à la casse.
func HistoryFilterSuffix(h History, suffix string, insensitive ...bool) (out []string) {
return hfilter(h, suffix, strings.HasSuffix, insensitive...)
}
// HistoryFilter retourne les entrées de lhistorique vérifiant la regexp donnée.
func HistoryFilter(h History, r *regexp.Regexp) (out []string) {
l := h.Len()
if l == 0 {
return
}
for i := 0; i < l; i++ {
if e, ok := h.Index(i).Get(); ok && r.MatchString(e) {
out = append(out, e)
}
}
return
}
// IsFocused retourne vrai si le cycler pointe sur un élément existant.
func IsFocused(c Cycler) bool {
l, n := c.Len(), c.Cursor()
return n >= 0 && n < l
}
// FocusedElement retourne lélément pointé par le cycler.
func FocusedElement(c Cycler) Option[string] {
return c.Index(c.Cursor())
}
// Unfocus enlève le pointage de lhistorique.
func Unfocus(h History) {
h.SetCursor(h.Len())
}