refactor(ast_query): emit cursor footer from formatter, not string-replace

handleASTQuery rebuilt the formatter's '[remaining: N]' placeholder string and strings.ReplaceAll'd it with the cursor line, plus a fallback append — fragile coupling to the formatter's exact output. New FormatResultsWithCursor appends the prebuilt '[cursor: ..., remaining: N]' footer in place of the bare hint when results are truncated; the handler just passes it through. FormatResultsWithOptions is unchanged (delegates with empty cursor). Adds TestFormatResultsWithCursor.
This commit is contained in:
2026-06-20 00:33:32 +01:00
parent cc1661d295
commit 53bc06df7f
3 changed files with 55 additions and 15 deletions
+27
View File
@@ -128,6 +128,33 @@ func TestFormatResultsPaginationCursor(t *testing.T) {
}
}
// FormatResultsWithCursor must emit the supplied cursor footer verbatim in place
// of the bare "[remaining: N]" hint when results are truncated.
func TestFormatResultsWithCursor(t *testing.T) {
results := makeResults(5)
cursor := "[cursor: abc123, remaining: 3]"
out := FormatResultsWithCursor(results, 2, "compact", 0, false, cursor)
if !strings.Contains(out, cursor) {
t.Errorf("expected cursor footer %q, got:\n%s", cursor, out)
}
if strings.Contains(out, "[remaining: 3]\n") {
t.Errorf("bare remaining hint should be replaced by cursor footer, got:\n%s", out)
}
// Empty cursorLine falls back to the bare hint (parity with FormatResultsWithOptions).
fallback := FormatResultsWithCursor(results, 2, "compact", 0, false, "")
if !strings.Contains(fallback, "[remaining: 3]") {
t.Errorf("empty cursorLine should fall back to [remaining: 3], got:\n%s", fallback)
}
// No truncation → no footer at all.
none := FormatResultsWithCursor(makeResults(2), 0, "compact", 0, false, cursor)
if strings.Contains(none, cursor) || strings.Contains(none, "[remaining:") {
t.Errorf("no truncation should emit no footer, got:\n%s", none)
}
}
func TestFormatResultsEmpty(t *testing.T) {
out := FormatResultsWithOptions(nil, 0, "verbose", 0)
if out != "No matches found." {
+25 -5
View File
@@ -460,7 +460,24 @@ func FormatResults(results []MatchResult, maxResults int) string {
// format: "verbose" (default) | "compact" | "location"
// offset: skip this many results before rendering (used for cursor pagination).
// verbose: opt-in variadic — pass true to restore "Found N match(es):" preamble (v1 behaviour).
// When results are truncated it emits a bare "[remaining: N]" hint; callers that
// have a pagination cursor should use FormatResultsWithCursor to emit the full line.
func FormatResultsWithOptions(results []MatchResult, maxResults int, format string, offset int, verbose ...bool) string {
return formatResults(results, maxResults, format, offset, len(verbose) > 0 && verbose[0], "")
}
// FormatResultsWithCursor is like FormatResultsWithOptions but, when results are
// truncated, appends cursorLine verbatim instead of the bare "[remaining: N]"
// hint. This lets the caller pass a fully-formed "[cursor: ..., remaining: N]"
// footer without string-replacing a placeholder. If cursorLine is empty it
// behaves like FormatResultsWithOptions.
func FormatResultsWithCursor(results []MatchResult, maxResults int, format string, offset int, verbose bool, cursorLine string) string {
return formatResults(results, maxResults, format, offset, verbose, cursorLine)
}
// formatResults is the shared implementation. cursorLine, when non-empty, is
// emitted in place of the "[remaining: N]" hint on truncation.
func formatResults(results []MatchResult, maxResults int, format string, offset int, verbose bool, cursorLine string) string {
if len(results) == 0 {
return "No matches found."
}
@@ -484,8 +501,7 @@ func FormatResultsWithOptions(results []MatchResult, maxResults int, format stri
var sb strings.Builder
// Emit preamble only when verbose=true is explicitly passed (opt-in, default off).
wantVerbose := len(verbose) > 0 && verbose[0]
if wantVerbose {
if verbose {
fmt.Fprintf(&sb, "Found %d match(es):\n", renderCount)
}
@@ -547,9 +563,13 @@ func FormatResultsWithOptions(results []MatchResult, maxResults int, format stri
}
if remaining > 0 {
// Caller must embed the cursor token; we just append the remaining count hint.
// The actual [cursor: ...] line is written by the handler after calling MakeCursor.
fmt.Fprintf(&sb, "[remaining: %d]\n", remaining)
if cursorLine != "" {
// Caller supplied a fully-formed "[cursor: ..., remaining: N]" footer.
sb.WriteString(strings.TrimRight(cursorLine, "\n"))
sb.WriteByte('\n')
} else {
fmt.Fprintf(&sb, "[remaining: %d]\n", remaining)
}
}
return sb.String()