From e435d903692ecb38e49ab7ca3f6f27aa86f24aea Mon Sep 17 00:00:00 2001 From: Widthdom Date: Sun, 24 May 2026 23:20:04 +0900 Subject: [PATCH] Fix exact help wrapping (#1426) --- changelog.d/unreleased/1426.fixed.md | 16 ++++++++++ src/CodeIndex/Cli/ConsoleUi.cs | 15 ++++++++-- tests/CodeIndex.Tests/ConsoleUiTests.cs | 40 +++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 changelog.d/unreleased/1426.fixed.md diff --git a/changelog.d/unreleased/1426.fixed.md b/changelog.d/unreleased/1426.fixed.md new file mode 100644 index 0000000000..bd0e22229d --- /dev/null +++ b/changelog.d/unreleased/1426.fixed.md @@ -0,0 +1,16 @@ +--- +category: fixed +issues: + - 1426 +affected: + - src/CodeIndex/Cli/ConsoleUi.cs + - tests/CodeIndex.Tests/ConsoleUiTests.cs +--- + +## English + +- **Wrapped exact-match help text to fit 80-column terminals (#1426)** — `--exact`, `--exact-substring`, and `--exact-name` usage text now avoids unpredictable mid-word wrapping in narrow terminals and CI logs. + +## 日本語 + +- **exact-match 系ヘルプを 80 カラム端末に収まるよう折り返しました (#1426)** — `--exact`、`--exact-substring`、`--exact-name` の usage 表示が、狭い端末や CI ログで単語途中に折り返されにくくなりました。 diff --git a/src/CodeIndex/Cli/ConsoleUi.cs b/src/CodeIndex/Cli/ConsoleUi.cs index 2bf4cce6d8..abe918434a 100644 --- a/src/CodeIndex/Cli/ConsoleUi.cs +++ b/src/CodeIndex/Cli/ConsoleUi.cs @@ -705,9 +705,18 @@ public static void PrintUsage(bool showBanner = true) Console.WriteLine(" --focus-column excerpt: column to keep centered when clamping (must be within the focused line)"); Console.WriteLine(" --focus-length excerpt: width of the focused span (default: 1, requires --focus-column)"); Console.WriteLine($" --fts Use raw FTS5 query syntax for search (search query max {QueryLimits.MaxQueryLength} chars; raw FTS parser max {DbReader.MaxRawFtsQueryLength} chars, {DbReader.MaxRawFtsBooleanOperators} boolean ops, {DbReader.MaxRawFtsNearOperators} NEAR ops; trailing * is a prefix shorthand in literal-safe mode)"); - Console.WriteLine(" --exact Backward-compatible shorthand. Prefer --exact-substring for search, keep --exact for find, and prefer --exact-name for symbols/definition/references/callers/callees/inspect. Pass at most one of --exact, --exact-substring, --exact-name; combining two or more is rejected."); - Console.WriteLine(" --exact-substring Search only: case-sensitive exact substring (no FTS5)"); - Console.WriteLine(" --exact-name symbols/definition/references/callers/callees/inspect: NFKC + Unicode CaseFold exact name match (legacy/stale-fold DBs fall back to ASCII NOCASE; use `cdidx backfill-fold` or check `status --json` fold_ready)"); + Console.WriteLine(" --exact Backward-compatible shorthand."); + Console.WriteLine(" Prefer --exact-substring for search,"); + Console.WriteLine(" --exact for find,"); + Console.WriteLine(" and --exact-name for symbol/graph lookups."); + Console.WriteLine(" Combining exact-match flags is rejected."); + Console.WriteLine(" --exact-substring Search only: case-sensitive exact substring"); + Console.WriteLine(" (no FTS5)"); + Console.WriteLine(" --exact-name Exact name match for symbols, definition,"); + Console.WriteLine(" references, callers, callees, and inspect."); + Console.WriteLine(" Uses NFKC + Unicode CaseFold when ready."); + Console.WriteLine(" Legacy/stale-fold DBs fall back to ASCII NOCASE;"); + Console.WriteLine(" run `cdidx backfill-fold` or check fold_ready."); Console.WriteLine(" --kind definition/symbols/hotspots/unused: symbol kind; references: reference kind (call/instantiate/subscribe/attribute/annotation); callers/callees: call-graph kinds only (call/instantiate/subscribe — metadata kinds rejected, use references instead); validate: issue kind"); Console.WriteLine(" --visibility Filter symbols/definitions/unused/hotspots by visibility: public, protected, internal, private"); Console.WriteLine(" --exclude-visibility Exclude symbols/definitions/unused/hotspots by visibility"); diff --git a/tests/CodeIndex.Tests/ConsoleUiTests.cs b/tests/CodeIndex.Tests/ConsoleUiTests.cs index 3a5f32e101..f589fbbca6 100644 --- a/tests/CodeIndex.Tests/ConsoleUiTests.cs +++ b/tests/CodeIndex.Tests/ConsoleUiTests.cs @@ -76,8 +76,18 @@ public void PrintUsage_WithoutBanner_HidesAsciiArtAndEasterEggFlags() Assert.Contains("--max-line-width search/references/find/excerpt/inspect only: clamp very long single-line snippet/context/excerpt payloads (`0` disables clamping; default: 512)", output); Assert.Contains("cdidx find --path ", output); Assert.Contains("--fts Use raw FTS5 query syntax for search (search query max 1000 chars; raw FTS parser max 2000 chars, 64 boolean ops, 16 NEAR ops", output); - Assert.Contains("--exact-substring Search only: case-sensitive exact substring (no FTS5)", output); - Assert.Contains("--exact-name symbols/definition/references/callers/callees/inspect: NFKC + Unicode CaseFold exact name match", output); + Assert.Contains("--exact Backward-compatible shorthand.", output); + Assert.Contains(" Prefer --exact-substring for search,", output); + Assert.Contains(" --exact for find,", output); + Assert.Contains(" and --exact-name for symbol/graph lookups.", output); + Assert.Contains(" Combining exact-match flags is rejected.", output); + Assert.Contains("--exact-substring Search only: case-sensitive exact substring", output); + Assert.Contains(" (no FTS5)", output); + Assert.Contains("--exact-name Exact name match for symbols, definition,", output); + Assert.Contains(" references, callers, callees, and inspect.", output); + Assert.Contains(" Uses NFKC + Unicode CaseFold when ready.", output); + Assert.Contains(" Legacy/stale-fold DBs fall back to ASCII NOCASE;", output); + Assert.Contains(" run `cdidx backfill-fold` or check fold_ready.", output); Assert.Contains("--kind definition/symbols/hotspots/unused: symbol kind; references: reference kind (call/instantiate/subscribe/attribute/annotation); callers/callees: call-graph kinds only (call/instantiate/subscribe — metadata kinds rejected, use references instead); validate: issue kind", output); Assert.Contains("--count Count only; search/definition/references/callers/callees/symbols/files/find/unused ignore --limit, impact/hotspots still use visible page counts", output); Assert.Contains("--commits [id ...] Update only files changed in the specified git commits (preferred after commits)", output); @@ -108,7 +118,8 @@ public void PrintUsage_WithoutBanner_HidesAsciiArtAndEasterEggFlags() Assert.Contains("backfill-fold", output); Assert.Contains("optimize Optimize FTS5 segments in an existing index DB", output); Assert.Contains("find Find literal substring matches inside known indexed files", output); - Assert.Contains("Prefer --exact-substring for search, keep --exact for find", output); + Assert.Contains("Prefer --exact-substring for search", output); + Assert.Contains("--exact for find", output); Assert.Contains("impact Show transitive callers; type queries may return heuristic file-level dependency hints", output); Assert.Contains("hotspots Find high-impact symbols; duplicate-name families may fall back conservatively", output); Assert.Contains("cdidx find guard --path src/Auth.cs --after 2", output); @@ -123,6 +134,29 @@ public void PrintUsage_WithoutBanner_HidesAsciiArtAndEasterEggFlags() Assert.DoesNotContain("--random-spinner", output); } + [Fact] + public void PrintUsage_ExactMatchOptionLines_FitWithinEightyColumns() + { + var output = CaptureUsageOutput(showBanner: false); + var lines = output.Split(Environment.NewLine); + var exactStart = Array.FindIndex(lines, line => line.StartsWith(" --exact ", StringComparison.Ordinal)); + var exactSubstringStart = Array.FindIndex(lines, line => line.StartsWith(" --exact-substring", StringComparison.Ordinal)); + var exactNameStart = Array.FindIndex(lines, line => line.StartsWith(" --exact-name", StringComparison.Ordinal)); + var kindStart = Array.FindIndex(lines, line => line.StartsWith(" --kind ", StringComparison.Ordinal)); + + Assert.True(exactStart >= 0); + Assert.True(exactSubstringStart > exactStart); + Assert.True(exactNameStart > exactSubstringStart); + Assert.True(kindStart > exactNameStart); + + var exactMatchLines = lines[exactStart..kindStart] + .Where(line => line.Length > 0) + .ToArray(); + + Assert.NotEmpty(exactMatchLines); + Assert.All(exactMatchLines, line => Assert.True(line.Length <= 80, $"Line exceeds 80 columns ({line.Length}): {line}")); + } + [Fact] public void PrintUsage_ShowsCommitUpdateWorkflowClearly() {