Files

139 lines
4.1 KiB
Go
Raw Permalink Normal View History

2026-09-19 22:31:37 +00:00
/*
* Copyright 2026 Safronov Grigorii
*
* Licensed under the CDDL, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* https://opensource.org/licenses/CDDL-1.0
*/
// Файл: internal/repl/pager.go
2026-10-05 21:29:14 +00:00
// Назначение: Простой пейджер для длинных выводов REPL.
// Если количество строк превышает threshold, вывод отправляется в
// внешний пейджер (по умолчанию `less -R`), иначе печатается напрямую.
//
// ДОБАВЛЕНО (2026-10):
// - Threshold() / SetThreshold() — геттер и сеттер порога включения
// пейджера. Используются REPL-командой `pager size <N>` /
// `pager threshold <N>`. Значения <= 0 игнорируются, чтобы случайно
// не сломать вывод.
2026-09-19 22:31:37 +00:00
package repl
import (
2026-10-05 21:29:14 +00:00
"bytes"
2026-09-19 22:31:37 +00:00
"fmt"
"os"
"os/exec"
2026-10-05 21:29:14 +00:00
"runtime"
2026-09-19 22:31:37 +00:00
"strings"
)
2026-10-05 21:29:14 +00:00
// Pager — простой пейджер.
//
// Все поля читаются/пишутся только из REPL-цикла (последовательный
// доступ), поэтому мьютекс здесь не нужен. Если пейджер начнёт
// использоваться из фоновых горутин — добавьте sync.RWMutex.
2026-09-19 22:31:37 +00:00
type Pager struct {
2026-10-05 21:29:14 +00:00
enabled bool
threshold int
external string
lines int
2026-09-19 22:31:37 +00:00
}
// NewPager создаёт пейджер.
func NewPager(enabled bool, threshold int) *Pager {
p := &Pager{
enabled: enabled,
threshold: threshold,
2026-10-05 21:29:14 +00:00
external: defaultPagerCommand(),
lines: 0,
2026-09-19 22:31:37 +00:00
}
return p
}
2026-10-05 21:29:14 +00:00
// Enabled возвращает статус пейджера.
func (p *Pager) Enabled() bool {
return p.enabled
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
// SetEnabled включает или отключает пейджер.
func (p *Pager) SetEnabled(enabled bool) {
p.enabled = enabled
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
// Threshold возвращает порог включения пейджера (в строках).
// Если вывод короче порога — пейджер не используется.
func (p *Pager) Threshold() int {
return p.threshold
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
// SetThreshold устанавливает порог включения пейджера.
// Значения <= 0 игнорируются, чтобы случайно не сломать вывод.
2026-09-19 22:31:37 +00:00
func (p *Pager) SetThreshold(n int) {
2026-10-05 21:29:14 +00:00
if n > 0 {
2026-09-19 22:31:37 +00:00
p.threshold = n
}
}
2026-10-05 21:29:14 +00:00
// Page отображает текст через пейджер, если он включён и текст достаточно
// длинный. Иначе печатает напрямую в stdout.
2026-09-19 22:31:37 +00:00
func (p *Pager) Page(text string) error {
2026-10-05 21:29:14 +00:00
if !p.enabled {
2026-09-19 22:31:37 +00:00
fmt.Print(text)
return nil
}
lineCount := strings.Count(text, "\n")
if lineCount < p.threshold {
fmt.Print(text)
return nil
}
2026-10-05 21:29:14 +00:00
if p.external == "" {
// Нет внешнего пейджера — печатаем напрямую.
fmt.Print(text)
return nil
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
return p.pipeToExternal(text)
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
// pipeToExternal отправляет текст во внешний пейджер.
func (p *Pager) pipeToExternal(text string) error {
parts := strings.Fields(p.external)
if len(parts) == 0 {
fmt.Print(text)
return nil
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
cmd := exec.Command(parts[0], parts[1:]...)
cmd.Stdin = bytes.NewBufferString(text)
2026-09-19 22:31:37 +00:00
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
2026-10-05 21:29:14 +00:00
if err := cmd.Run(); err != nil {
// Если внешний пейджер упал — печатаем напрямую.
fmt.Print(text)
2026-09-19 22:31:37 +00:00
return err
}
2026-10-05 21:29:14 +00:00
return nil
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
// defaultPagerCommand выбирает команду пейджера в зависимости от ОС.
func defaultPagerCommand() string {
switch runtime.GOOS {
case "windows":
return "more"
default:
// less -R: -R сохраняет ANSI-цвета, используется на Linux/BSD/illumos.
if _, err := exec.LookPath("less"); err == nil {
return "less -R"
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
if _, err := exec.LookPath("more"); err == nil {
return "more"
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
return ""
2026-09-19 22:31:37 +00:00
}
2026-10-05 21:29:14 +00:00
}