2023-10-07 19:13:39 +00:00
|
|
|
|
package atom
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"gitea.zaclys.com/bvaudour/gob/option"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Buffer stocke l’ensemble 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 n’est 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 n’a 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 l’incrément donné.
|
|
|
|
|
// Si l’incré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 d’un caractère vers la gauche.
|
|
|
|
|
func (b *Buffer) Left() (ok bool) {
|
|
|
|
|
return b.Move(-1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Right déplace le curseur d’un 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 n’est
|
|
|
|
|
// 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
|
|
|
|
|
}
|
2024-03-02 13:26:17 +00:00
|
|
|
|
|
|
|
|
|
func (b *Buffer) SetCursor(cursor int) (ok bool) {
|
|
|
|
|
if ok = cursor > 0 && cursor <= b.Len() && cursor != b.cursor; ok {
|
|
|
|
|
b.cursor = cursor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|