Created
October 4, 2025 13:47
-
-
Save padurean/92ab414e33faf8eed91b204ac605946d to your computer and use it in GitHub Desktop.
Go pagination for CLI app output - detect if terminal and if it is use the available pager (e.g. less) #GoLang #CLI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"io" | |
"os" | |
"os/exec" | |
"syscall" | |
"golang.org/x/term" | |
) | |
// usePager attempts to pipe output to $PAGER if available and stdout is a TTY | |
// Returns a writer and a cleanup function | |
func usePager() (io.Writer, func() error) { | |
// Don't use pager if output is redirected/piped | |
if !term.IsTerminal(int(syscall.Stdout)) { | |
return os.Stdout, func() error { return nil } | |
} | |
pager := os.Getenv("PAGER") | |
if pager == "" { | |
// Fallback to common pagers | |
pager = "less" | |
if _, err := exec.LookPath(pager); err != nil { | |
pager = "more" | |
if _, err := exec.LookPath(pager); err != nil { | |
// No pager available, use stdout | |
return os.Stdout, func() error { return nil } | |
} | |
} | |
} | |
cmd := exec.Command(pager) | |
cmd.Stdout = os.Stdout | |
cmd.Stderr = os.Stderr | |
// Set better defaults for less if it's being used | |
if pager == "less" || (pager != "more" && os.Getenv("LESS") == "") { | |
// -F: exit if content fits on one screen | |
// -R: allow ANSI color codes | |
// -X: don't clear screen on exit | |
// -K: exit on Ctrl-C | |
cmd.Env = append(os.Environ(), "LESS=-FRX") | |
} | |
stdin, err := cmd.StdinPipe() | |
if err != nil { | |
return os.Stdout, func() error { return nil } | |
} | |
if err := cmd.Start(); err != nil { | |
return os.Stdout, func() error { return nil } | |
} | |
cleanup := func() error { | |
stdin.Close() | |
return cmd.Wait() | |
} | |
return stdin, cleanup | |
} | |
func main() { | |
w, cleanupPager := usePager() | |
defer cleanupPager() | |
// Write your output to w instead of os.Stdout | |
// ANSI colors will work properly with the -R flag | |
for i := 1; i <= 100; i++ { | |
if i%10 == 0 { | |
fmt.Fprintf(w, "\033[1;32mLine %d: Highlighted output\033[0m\n", i) | |
} else { | |
fmt.Fprintf(w, "Line %d: Some output here\n", i) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment