package cli import ( "io" "os" "os/exec" "strings" "github.com/lukaszkasprzak/lectio/internal/config" ) // pagerRequested decides whether the reading-output tail should be paged, // given -P/--pager, --no-pager, and cfg.Pager. --no-pager always wins (an // explicit "never page" beats everything); otherwise -P forces paging on; // otherwise a non-empty cfg.Pager turns paging on by default. Pure and // side-effect free -- the actual TTY gate lives in isTerminalWriter. func pagerRequested(pagerFlag, noPager bool, cfg config.Config) bool { if noPager { return false } if pagerFlag { return true } return cfg.Pager != "" } // pagerCommand resolves the pager argv to run: cfg.Pager wins, then $PAGER, // then the "less -R" built-in default. The resolved command string is split // on whitespace via strings.Fields into an argv slice (so "less -R" or a // $PAGER value with flags works without a shell). func pagerCommand(cfg config.Config) []string { cmd := cfg.Pager if cmd == "" { cmd = os.Getenv("PAGER") } if cmd == "" { cmd = "less -R" } return strings.Fields(cmd) } // isTerminalWriter reports whether w is a real terminal -- only then is // paging worth doing. Reuses ttyWidth (termwidth_unix.go/termwidth_other.go) // via the *os.File it already knows how to probe; anything else (notably // the bytes.Buffer every test uses for stdout) is never a terminal, so // paging never triggers in tests, and `lectio | cat` (stdout redirected to // a pipe, not a *os.File terminal) writes directly too. func isTerminalWriter(w io.Writer) bool { if f, ok := w.(*os.File); ok { return ttyWidth(f) > 0 } return false } // startPager launches argv[0] as a pager subprocess wired to the real // terminal (stdout/stderr passed through), returning a WriteCloser the // caller renders reading output into. ok=false (with out, finish both nil) // on any setup failure -- an empty argv, a StdinPipe error, or the pager // binary not being found/startable -- so the caller can fall back to // writing directly to stdout without crashing. func startPager(argv []string, stdout, stderr io.Writer) (out io.WriteCloser, finish func(), ok bool) { if len(argv) == 0 { return nil, nil, false } cmd := exec.Command(argv[0], argv[1:]...) cmd.Stdout = stdout cmd.Stderr = stderr w, err := cmd.StdinPipe() if err != nil { return nil, nil, false } if err := cmd.Start(); err != nil { return nil, nil, false } finish = func() { w.Close() _ = cmd.Wait() } return w, finish, true }