futriis/internal/cli/history.go

149 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.

// /futriis/internal/cli/history.go
// Пакет cli реализует управление историей команд для интерактивного режима.
// History хранит ограниченное количество последних команд с кольцевым буфером, предотвращает добавление последовательных дубликатов.
// Предоставляет навигацию по истории с помощью стрелок вверх/вниз для быстрого повторного выполнения команд.
// Интегрируется с Prompt для обеспечения полноценного интерфейса командной строки.
package cli
import (
"os"
"strings"
"golang.org/x/term"
)
// History управляет историей команд
type History struct {
commands []string
position int
maxSize int
}
// NewHistory создаёт новую историю команд
func NewHistory(maxSize int) *History {
return &History{
commands: make([]string, 0, maxSize),
position: -1, // Изначально позиция -1 (не в истории)
maxSize: maxSize,
}
}
// Add добавляет команду в историю
func (h *History) Add(cmd string) {
if cmd == "" {
return
}
// Не добавляем дубликаты подряд
if len(h.commands) > 0 && h.commands[len(h.commands)-1] == cmd {
return
}
// Если достигнут максимум, удаляем самую старую команду
if len(h.commands) >= h.maxSize {
h.commands = h.commands[1:]
}
h.commands = append(h.commands, cmd)
h.position = len(h.commands) // Устанавливаем позицию в конец
}
// GetPrevious возвращает предыдущую команду из истории
func (h *History) GetPrevious() string {
if len(h.commands) == 0 {
return ""
}
// Если мы в начале или не в истории, начинаем с последней команды
if h.position == -1 || h.position > len(h.commands)-1 {
h.position = len(h.commands) - 1
return h.commands[h.position]
}
// Если есть предыдущая команда
if h.position > 0 {
h.position--
return h.commands[h.position]
}
// Мы уже на самой первой команде
return h.commands[0]
}
// GetNext возвращает следующую команду из истории
func (h *History) GetNext() string {
if len(h.commands) == 0 {
return ""
}
// Если мы не в истории, возвращаем пустую строку
if h.position == -1 {
return ""
}
// Если есть следующая команда
if h.position < len(h.commands)-1 {
h.position++
return h.commands[h.position]
}
// Достигли конца истории, сбрасываем позицию
h.position = -1
return ""
}
// Search выполняет поиск команд по подстроке
func (h *History) Search(query string) []string {
if query == "" {
// Возвращаем все команды в обратном порядке (новые сначала)
result := make([]string, len(h.commands))
for i := 0; i < len(h.commands); i++ {
result[i] = h.commands[len(h.commands)-1-i]
}
return result
}
// Ищем команды, содержащие запрос (регистронезависимо)
queryLower := strings.ToLower(query)
result := make([]string, 0)
// Идем с конца, чтобы новые команды были в начале результатов
for i := len(h.commands) - 1; i >= 0; i-- {
if strings.Contains(strings.ToLower(h.commands[i]), queryLower) {
result = append(result, h.commands[i])
}
}
return result
}
// Reset сбрасывает позицию в истории
func (h *History) Reset() {
h.position = -1
}
// GetAll возвращает все команды истории
func (h *History) GetAll() []string {
result := make([]string, len(h.commands))
copy(result, h.commands)
return result
}
// Size возвращает размер истории
func (h *History) Size() int {
return len(h.commands)
}
// SetupRawMode устанавливает терминал в raw-режим для обработки клавиш
func SetupRawMode() (*term.State, error) {
fd := int(os.Stdin.Fd())
return term.MakeRaw(fd)
}
// RestoreMode восстанавливает режим терминала
func RestoreMode(oldState *term.State) error {
fd := int(os.Stdin.Fd())
return term.Restore(fd, oldState)
}