gob/shell/console/atom/buffer.go

316 lines
6.0 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 atom
import (
"gitea.zaclys.com/bvaudour/gob/option"
)
// Buffer stocke lensemble des caractère saisis et la position du curseur.
type Buffer struct {
data []rune
cursor int
}
// Len retourne le nombre de caractères du buffer.
func (b *Buffer) Len() int {
return len(b.data)
}
// Insert ajoute les caractères donnés à la position du curseur.
func (b *Buffer) Insert(data ...rune) {
l1, l2, c := b.Len(), len(data), b.cursor
newData := make([]rune, l1+l2)
if c > 0 {
copy(newData[:c], b.data[:c])
}
copy(newData[c:c+l2], data)
if c < l1 {
copy(newData[c+l2:], b.data[c:])
}
b.data = newData
b.cursor += l2
}
// Replace remplace les caractères du buffer à partir de la position du curseur
// par les caractères donnés.
// Si le buffer nest pas assez grand, le buffer est agrandi.
func (b *Buffer) Replace(data ...rune) {
l1, l2, c := b.Len(), len(data), b.cursor
l := max(l1, c+l2)
newData := make([]rune, l)
if c > 0 {
copy(newData[:c], b.data[:c])
}
copy(newData[c:c+l2], data)
if c+l2 < l1 {
copy(newData[c+l2:], b.data[c+l2:])
}
b.data = newData
b.cursor += l2
}
// Transpose transpose le caractère sous le curseur avec le caractère précédent.
// Si la transposition na pu se faire, il retourne faux.
func (b *Buffer) Transpose() (ok bool) {
l := b.Len()
if ok = b.cursor > 0 && l >= 2; ok {
c := b.cursor
if c == l {
c--
}
b.data[c-1], b.data[c] = b.data[c], b.data[c-1]
}
return
}
// Move déplace le curseur avec lincrément donné.
// Si lincrément est négatif, le déplacement se fait vers la gauche.
// Sinon, il se fait vers la droite.
// Si la position du curseur sort du buffer, retourne faux.
func (b *Buffer) Move(inc int) (ok bool) {
c, l := b.cursor+inc, b.Len()
if ok = c >= 0 && c <= l; ok {
b.cursor = c
}
return
}
// Left déplace le curseur dun caractère vers la gauche.
func (b *Buffer) Left() (ok bool) {
return b.Move(-1)
}
// Right déplace le curseur dun caractère vers la droite.
func (b *Buffer) Right() (ok bool) {
return b.Move(1)
}
// Begin déplace le curseur au début du buffer.
func (b *Buffer) Begin() (ok bool) {
if ok = b.cursor > 0; ok {
b.cursor = 0
}
return
}
// End déplace le curseur à la fin du buffer.
func (b *Buffer) End() (ok bool) {
l := b.Len()
if ok = b.cursor < l; ok {
b.cursor = l
}
return
}
// PrevWord déplace le curseur au début du mot,
// ou au début du précédent mot si le curseur nest
// pas positionné sur un mot.
func (b *Buffer) PrevWord() (ok bool) {
l := b.Len()
if l == 0 || b.cursor == 0 {
return
}
i := b.cursor - 1
for i == l || IsSpace(b.data[i]) {
i--
}
for i > 0 && !IsSpace(b.data[i-1]) {
i--
}
return b.Move(i - b.cursor)
}
// NextWord déplace le curseur au début du prochain mot.
func (b *Buffer) NextWord() (ok bool) {
i, l := b.cursor, b.Len()
if i == l {
return
}
for i < l && !IsSpace(b.data[i]) {
i++
}
for i < l && IsSpace(b.data[i]) {
i++
}
return b.Move(i - b.cursor)
}
// Backn supprime n caractères à gauche du curseur.
// Si la suppression a bien été effectuée, il retourne
// la chaîne supprimée.
func (b *Buffer) Backn(n int) (shifted option.Option[string]) {
l, c := b.Len(), b.cursor
c2 := c - n
if n <= 0 || c2 < 0 {
return
}
shifted = option.Some(string(b.data[c2:c]))
newData := make([]rune, l-n)
copy(newData[:c2], b.data[:c2])
if c < l {
copy(newData[c2:], b.data[c:])
}
b.data = newData
b.cursor = c2
return
}
// Deln supprime n caractères à partir du curseur.
// Si la suppression a bien été effectuée, il retourne
// la chaîne supprimée.
func (b *Buffer) Deln(n int) (shifted option.Option[string]) {
l, c := b.Len(), b.cursor
c2 := c + n
if n <= 0 || c2 > l {
return
}
shifted = option.Some(string(b.data[c:c2]))
newData := make([]rune, l-n)
copy(newData[:c], b.data[:c])
if c2 < l {
copy(newData[c:], b.data[c2:])
}
b.data = newData
return
}
// Back supprime le caractère avant le curseur.
func (b *Buffer) Back() option.Option[string] {
return b.Backn(1)
}
// Del supprime le caractère sous le curseur.
func (b *Buffer) Del() option.Option[string] {
return b.Deln(1)
}
// BackWord supprime le mot avant le caractère.
func (b *Buffer) BackWord() (shifted option.Option[string]) {
l := b.Len()
if l == 0 || b.cursor == 0 {
return
}
i := b.cursor - 1
for i == l || IsSpace(b.data[i]) {
i--
}
for i > 0 && !IsSpace(b.data[i-1]) {
i--
}
return b.Backn(b.cursor - i)
}
// DelWord supprime le mot après le caractère.
func (b *Buffer) DelWord() (shifted option.Option[string]) {
i, l := b.cursor, b.Len()
if i == l {
return
}
for i < l || IsSpace(b.data[i]) {
i++
}
for i < l && !IsSpace(b.data[i]) {
i++
}
return b.Deln(i - b.cursor)
}
// RemoveBegin supprime les caractères avant le curseur.
func (b *Buffer) RemoveBegin() (shifted option.Option[string]) {
if b.cursor > 0 {
shifted = option.Some(string(b.data[:b.cursor]))
b.data = b.data[b.cursor:]
b.cursor = 0
}
return
}
// RemoveEnd supprime les caractères après le curseur, curseur compris.
func (b *Buffer) RemoveEnd() (shifted option.Option[string]) {
if b.cursor < b.Len() {
shifted = option.Some(string(b.data[b.cursor:]))
b.data = b.data[:b.cursor]
}
return
}
// Clear efface tout le buffer.
func (b *Buffer) Clear() (shifted option.Option[string]) {
if b.Len() > 0 {
shifted = option.Some(string(b.data))
b.data, b.cursor = b.data[:0], 0
}
return
}
// String retourne le contenu du buffer sous forme de chaîne de caractères.
func (b *Buffer) String() string {
return string(b.data)
}
// Cursor retourne la position du curseur.
func (b *Buffer) Cursor() int {
return b.cursor
}
// Clone effectue une copie du buffer.
func (b *Buffer) Clone() *Buffer {
l, c := len(b.data), cap(b.data)
cb := Buffer{
data: make([]rune, l, c),
cursor: b.cursor,
}
copy(cb.data, b.data)
return &cb
}
func (b *Buffer) SetCursor(cursor int) (ok bool) {
if ok = cursor > 0 && cursor <= b.Len() && cursor != b.cursor; ok {
b.cursor = cursor
}
return
}