Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions cmd/chat_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func runPrint(text string) error {
for ev := range ch {
switch ev.Type {
case "content":
if outputFormat == "text" {
if outputFormat == "text" && !printMarkdown {
fmt.Print(ev.Content)
} else if outputFormat == "stream-json" {
writePrintEvent(sessionID, "content", ev.Content, "")
Expand Down Expand Up @@ -134,9 +134,7 @@ func runPrint(text string) error {
case "done":
switch outputFormat {
case "text":
if !strings.HasSuffix(printed.String(), "\n") {
fmt.Println()
}
printTextResponse(printed.String())
printTextUsageFooter(lastUsage, started)
case "json":
writePrintResult(printed.String(), sessionID, sess, false, nil)
Expand All @@ -151,9 +149,7 @@ func runPrint(text string) error {
}
switch outputFormat {
case "text":
if !strings.HasSuffix(printed.String(), "\n") {
fmt.Println()
}
printTextResponse(printed.String())
printTextUsageFooter(lastUsage, started)
case "json":
writePrintResult(printed.String(), sessionID, sess, false, nil)
Expand Down Expand Up @@ -202,6 +198,30 @@ func printTextUsageFooter(usage *engine.StreamUsage, started time.Time) {
_, _ = fmt.Fprintf(os.Stderr, "%s\n", auditTint("tokens: "+strings.Join(parts, " · "), textMuted))
}

// printTextResponse emits the final text-mode response, rendering markdown to
// styled ANSI when --markdown is set and color is enabled. Raw markdown is
// preserved for piped/NO_COLOR output so scripts stay machine-parseable.
func printTextResponse(s string) {
s = renderPrintResponse(s, printMarkdown, ShouldColor())
fmt.Print(s)
if !strings.HasSuffix(s, "\n") {
fmt.Println()
}
}

// renderPrintResponse applies markdown rendering when both markdown and color
// are requested; otherwise it returns the raw response unchanged.
func renderPrintResponse(s string, markdown, color bool) string {
if !markdown || !color || s == "" {
return s
}
w, _ := TermSize()
if w <= 0 {
w = 80
}
return renderMarkdown(s, w)
}

func writePrintResult(result, sessionID string, sess *engine.Session, isError bool, errors []string) {
event := map[string]interface{}{
"type": "result",
Expand Down
31 changes: 31 additions & 0 deletions cmd/print_markdown_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cmd

import (
"strings"
"testing"
)

func TestRenderPrintResponse(t *testing.T) {
const md = "## Hello **world**\n\n- one\n- two\n"

// markdown off -> raw, regardless of color
if got := renderPrintResponse(md, false, true); got != md {
t.Errorf("markdown=false: got %q, want raw %q", got, md)
}
// color off -> raw, regardless of markdown
if got := renderPrintResponse(md, true, false); got != md {
t.Errorf("color=false: got %q, want raw %q", got, md)
}
// empty stays empty
if got := renderPrintResponse("", true, true); got != "" {
t.Errorf("empty: got %q, want empty", got)
}
// markdown + color -> styled ANSI, raw markers stripped
got := renderPrintResponse(md, true, true)
if !strings.Contains(got, "\x1b[") {
t.Errorf("markdown+color: no ANSI in %q", got)
}
if strings.Contains(got, "**world**") {
t.Errorf("markdown+color: raw ** still present in %q", got)
}
}
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
printMode bool
versionFlag bool
outputFormat string
printMarkdown bool
outputFields string
inputFormat string
noSessionPersistence bool
Expand Down Expand Up @@ -222,6 +223,7 @@ func init() {
rootCmd.Flags().BoolVarP(&printMode, "print", "p", false, "print response and exit")
rootCmd.Flags().StringVar(&promptFlag, "prompt", "", "send a single prompt and exit (legacy alias for --print)")
rootCmd.Flags().StringVar(&outputFormat, "output-format", "text", `output format for --print: "text", "json", or "stream-json"`)
rootCmd.Flags().BoolVar(&printMarkdown, "markdown", false, `render --print text output as styled markdown (needs color; ignored for json/stream-json)`)
rootCmd.Flags().StringVar(&outputFields, "output-fields", "", `comma-separated field whitelist for --output-format json (e.g. "result,session_id")`)
rootCmd.Flags().StringVar(&inputFormat, "input-format", "text", `input format for --print: "text" or "stream-json"`)
rootCmd.Flags().BoolVar(&noSessionPersistence, "no-session-persistence", false, "disable session persistence in print mode")
Expand Down
1 change: 1 addition & 0 deletions testdata/golden/help_root.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ Flags:
-h, --help help for graycode
--input-format string input format for --print: "text" or "stream-json" (default "text")
--map-tokens int token budget for the --repo-map overview (default 1024)
--markdown render --print text output as styled markdown (needs color; ignored for json/stream-json)
--max-budget-usd float maximum estimated API spend in USD
--max-turns int maximum number of agentic turns in non-interactive mode
--mcp stringArray MCP server command
Expand Down
Loading