Upload files to "internal/cli"
This commit is contained in:
parent
fc429084ad
commit
a9f1df6a89
148
internal/cli/history.go
Normal file
148
internal/cli/history.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// /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)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user