Skip to content

Commit 09163a2

Browse files
committed
add pager for pretty output
1 parent 083418e commit 09163a2

2 files changed

Lines changed: 63 additions & 5 deletions

File tree

cmd/output.go

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package cmd
22

33
import (
44
"fmt"
5+
"os"
6+
"os/exec"
57

8+
"github.com/charmbracelet/x/term"
69
"github.com/hardhacker/podwise-cli/internal/config"
710
"github.com/hardhacker/podwise-cli/internal/render"
811
"github.com/spf13/cobra"
@@ -21,18 +24,69 @@ func loadGlamourStyle() string {
2124
// printMarkdown writes text to cmd's output stream, rendering it through
2225
// glamour when the global --pretty flag is set.
2326
func printMarkdown(cmd *cobra.Command, text string) {
24-
if prettyOutput {
27+
// --pretty-no-pager takes priority over --pretty
28+
if prettyNoPager {
2529
text = render.Markdown(text, loadGlamourStyle())
30+
fmt.Fprint(cmd.OutOrStdout(), text)
31+
} else if prettyOutput {
32+
text = render.Markdown(text, loadGlamourStyle())
33+
printWithPager(cmd, text)
34+
} else {
35+
fmt.Fprint(cmd.OutOrStdout(), text)
2636
}
27-
fmt.Fprint(cmd.OutOrStdout(), text)
2837
}
2938

3039
// printMarkdownAnswer is like printMarkdown but uses render.MarkdownAnswer,
3140
// which normalizes AI-generated multi-paragraph list items before rendering
3241
// so glamour does not collapse them into a single line per item.
3342
func printMarkdownAnswer(cmd *cobra.Command, text string) {
34-
if prettyOutput {
43+
// --pretty-no-pager takes priority over --pretty
44+
if prettyNoPager {
45+
text = render.MarkdownAnswer(text, loadGlamourStyle())
46+
fmt.Fprint(cmd.OutOrStdout(), text)
47+
} else if prettyOutput {
3548
text = render.MarkdownAnswer(text, loadGlamourStyle())
49+
printWithPager(cmd, text)
50+
} else {
51+
fmt.Fprint(cmd.OutOrStdout(), text)
52+
}
53+
}
54+
55+
// printWithPager writes text to cmd's output stream, using a pager (less -R)
56+
// for interactive terminals. The pager allows scrolling and can be exited with 'q'.
57+
func printWithPager(cmd *cobra.Command, text string) {
58+
// Check if stdout is a TTY - only use pager in interactive mode
59+
if !isTTY() {
60+
fmt.Fprint(cmd.OutOrStdout(), text)
61+
return
62+
}
63+
64+
// Use less -RXF pager
65+
// -R: raw control characters (for ANSI colors)
66+
// -X: don't clear screen on exit
67+
// -F: quit if output fits in one screen
68+
cmdObj := exec.Command("less", "-RXF")
69+
cmdObj.Stdout = os.Stdout
70+
cmdObj.Stderr = os.Stderr
71+
72+
stdin, err := cmdObj.StdinPipe()
73+
if err != nil {
74+
fmt.Fprint(cmd.OutOrStdout(), text)
75+
return
76+
}
77+
78+
if err := cmdObj.Start(); err != nil {
79+
fmt.Fprint(cmd.OutOrStdout(), text)
80+
return
3681
}
37-
fmt.Fprint(cmd.OutOrStdout(), text)
82+
83+
stdin.Write([]byte(text))
84+
stdin.Close()
85+
86+
cmdObj.Wait()
87+
}
88+
89+
// isTTY returns true if stdout is a terminal.
90+
func isTTY() bool {
91+
return term.IsTerminal(1) // fd 1 = stdout
3892
}

cmd/root.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212
// prettyOutput is the global flag that enables glamour markdown rendering.
1313
var prettyOutput bool
1414

15+
// prettyNoPager is the global flag that enables pretty output without pager.
16+
var prettyNoPager bool
17+
1518
var rootCmd = &cobra.Command{
1619
Use: "podwise",
1720
Short: "podwise — AI podcast & YouTube insights from your terminal",
@@ -96,7 +99,8 @@ func isTerminal(f *os.File) bool {
9699
}
97100

98101
func init() {
99-
rootCmd.PersistentFlags().BoolVar(&prettyOutput, "pretty", false, "render markdown output with terminal styling (AI Agents/LLMs should not use this flag)")
102+
rootCmd.PersistentFlags().BoolVar(&prettyOutput, "pretty", false, "render markdown output with terminal styling and pager (AI Agents/LLMs should not use this flag)")
103+
rootCmd.PersistentFlags().BoolVar(&prettyNoPager, "pretty-no-pager", false, "render markdown output with terminal styling but without pager (AI Agents/LLMs should not use this flag)")
100104

101105
rootCmd.AddCommand(getCmd)
102106
rootCmd.AddCommand(processCmd)

0 commit comments

Comments
 (0)