diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 76e16e6ef..673f9525a 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -422,7 +422,7 @@ writer. Completed records are committed to the shared output writer in input order; an ordinary item failure remains isolated, while caller cancellation stops scheduling and propagates. -Editor integrations can request standard location shapes directly. `definition`, `references`, `search`, `find`, and `validate` accept `--format `; `lsp` emits LSP `Location` arrays, `qf` emits Vim quickfix lines, and `sarif` emits SARIF 2.1.0. `goto ` returns the single unambiguous definition as one LSP `Location`, while `goto --all ` returns all matching locations. +Editor integrations can request standard location shapes directly. `definition`, `references`, `search`, `find`, and `validate` accept `--format `; `lsp` emits LSP `Location` arrays, `qf` emits Vim quickfix lines, and `sarif` emits SARIF 2.1.0. `goto ` returns the single unambiguous definition as one LSP `Location`, while `goto --all ` returns all matching locations without applying the default or environment-provided query limit. An explicit `--limit` or `--top` still bounds the returned location array. The `cdidx lsp` server advertises full text document synchronization and keeps open document text in a bounded in-memory cache only. Position-based providers @@ -3568,7 +3568,7 @@ JSON-envelope capture を現在の worker の routed stdout に保ち、他 work 置き換えない。完了 record は入力順で共有 output writer へ commit する。通常の item failure は 他 item から隔離し、caller cancellation は scheduling を停止して伝播する。 -editor integration は標準的な location 形状を直接要求できる。`definition`、`references`、`search`、`find`、`validate` は `--format ` を受け付け、`lsp` は LSP `Location` 配列、`qf` は Vim quickfix 行、`sarif` は SARIF 2.1.0 を出力する。`goto ` は曖昧でない単一定義を 1 つの LSP `Location` として返し、`goto --all ` は一致する全 location を返す。 +editor integration は標準的な location 形状を直接要求できる。`definition`、`references`、`search`、`find`、`validate` は `--format ` を受け付け、`lsp` は LSP `Location` 配列、`qf` は Vim quickfix 行、`sarif` は SARIF 2.1.0 を出力する。`goto ` は曖昧でない単一定義を 1 つの LSP `Location` として返し、`goto --all ` は既定または環境変数由来の query limit を適用せず、一致する全 location を返す。明示的な `--limit` または `--top` を指定した場合は location 配列をその件数に制限する。 `cdidx lsp` server は full text document synchronization を advertise し、open document text は 上限付きの in-memory cache にだけ保持する。position-based provider は未保存 editor buffer から diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md index 484e516a6..21208f357 100644 --- a/TESTING_GUIDE.md +++ b/TESTING_GUIDE.md @@ -183,6 +183,7 @@ Use `docs/test-doc-maintenance-plan.md` before moving oversized suites or adding `ProgramRunnerTests.cs` enumerates `CliCommandCatalog.CommandSubcommands` and requires every valid nested verb to resolve to verb-specific usage with an example. It also pins destructive index confirmation and aggregate dependency-filter help, plus the read-only GitHub duplicate-preflight boundary for suggestion exports. Installer cancellation coverage must wait until the PID file contains a complete positive integer before cancelling, using a bounded dedicated waiter instead of a fixed-delay timer so parallel load cannot expose a redirection-created empty file. Global-tool-log home-shorthand coverage resolves the normalized first candidate through the test-only no-write-probe seam, so sandbox permissions cannot turn an expansion assertion into a writability-fallback assertion. Grouped-search limit coverage must seed more matches and files than the returned page, then assert query-wide matched/group/file totals separately from grouped, emitted, and omitted row counts so a bounded page cannot report itself as complete. + `goto --all` coverage shares one 63-definition fixture across the default bare LSP array and the plain `--json` argument path; it must assert complete deterministic output without a limit and retain a separate explicit-limit assertion in the same setup. Cursor-pagination coverage for `outline` and `unused` must replay the emitted opaque token successfully, then prove that changed filters/order and a changed index-generation stamp fail with restart-required diagnostics. Discovery-pagination coverage must page compact search/symbol/file output and the opt-in search-array/languages envelopes, assert authoritative total/omitted/stable-at metadata, reject query or generation cursor mismatches, and prove that a partial `find --all` scan resumes after the last scanned line. Quiet-flag coverage in `ProgramCliTests.cs` reuses one seeded symbols database across text, NDJSON, and JSON-array modes and compares stdout with and without a trailing quiet alias, proving that quiet mode changes only informational stderr. @@ -1078,6 +1079,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests" `ProgramRunnerTests.cs` は `CliCommandCatalog.CommandSubcommands` を列挙し、すべての有効な nested verb が例を含む verb 固有 usage に解決されることを必須とします。さらに destructive な index confirmation、aggregate dependency filter help、suggestion export の read-only GitHub duplicate-preflight 境界を固定します。installer cancellation coverage は固定時間タイマーではなく上限付きの専用 waiter を使い、PID ファイルが完全な正の整数を含むまで待ってから cancel してください。これにより並列負荷下でも redirection によって作成された空ファイルを読みません。 global tool log の home shorthand coverage は、test 専用の write probe なし seam から正規化済みの先頭 candidate を解決します。これにより sandbox permission の影響で、展開の assertion が writability fallback の assertion に変わることを防ぎます。 grouped search の limit coverage では、返却 page より多い match と file を seed し、query 全体の match/group/file 総数と grouped、emitted、omitted row 数を別々に検証して、上限付き page が完了済みと報告できないようにしてください。 + `goto --all` の coverage は、既定の bare LSP array と plain `--json` 引数経路で 1 つの 63 定義 fixture を共有し、limit 未指定時の完全かつ決定的な出力と、同じ setup 内での明示 limit の維持を検証してください。 `outline` と `unused` の cursor pagination coverage では、出力された opaque token の再利用成功に加え、filter/order の変更と index-generation stamp の変更が restart-required 診断で失敗することを検証してください。 discovery pagination の coverage では compact search / symbol / file と opt-in の search array / languages envelope をページングし、authoritative な total / omitted / stable-at metadata、query / generation 不一致 cursor の拒否、partial な `find --all` scan が最後に scan した line の次から再開することを検証してください。 `ProgramCliTests.cs` の quiet flag coverage は1つの seeded symbols database を text、NDJSON、JSON array の各 mode で再利用し、末尾に quiet alias を付けた場合と付けない場合の stdout を比較して、quiet mode が informational stderr だけを変えることを固定します。 diff --git a/changelog.d/unreleased/4837.fixed.md b/changelog.d/unreleased/4837.fixed.md new file mode 100644 index 000000000..74b0ec77b --- /dev/null +++ b/changelog.d/unreleased/4837.fixed.md @@ -0,0 +1,18 @@ +--- +category: fixed +issues: + - 4837 +affected: + - src/CodeIndex/Cli/QueryCommandRunner.Definition.cs + - tests/CodeIndex.Tests/QueryCommandRunnerSymbolTests.cs + - DEVELOPER_GUIDE.md + - TESTING_GUIDE.md +--- + +## English + +- **`goto --all` now returns every matching definition by default (#4837)** — the command no longer inherits the default or environment-provided 20-row query limit when `--all` is present, while an explicit `--limit` or `--top` still bounds the LSP location array. + +## 日本語 + +- **`goto --all` が既定で一致する全定義を返すようになりました (#4837)** — `--all` 指定時は既定または環境変数由来の20件の query limit を引き継がず、明示的な `--limit` または `--top` を指定した場合は引き続き LSP location 配列をその件数に制限します。 diff --git a/src/CodeIndex/Cli/QueryCommandRunner.Definition.cs b/src/CodeIndex/Cli/QueryCommandRunner.Definition.cs index e0b390cc6..b16d9101a 100644 --- a/src/CodeIndex/Cli/QueryCommandRunner.Definition.cs +++ b/src/CodeIndex/Cli/QueryCommandRunner.Definition.cs @@ -331,7 +331,9 @@ public static int RunGoto(string[] cmdArgs, JsonSerializerOptions jsonOptions) return WithDb(options, jsonOptions, reader => { - var limit = all ? options.Limit : Math.Max(options.Limit, 2); + var limit = all + ? options.LimitExplicit ? options.Limit : int.MaxValue + : Math.Max(options.Limit, 2); var results = reader.GetDefinitions(options.Query, limit, options.Kind, options.Lang, includeBody: false, options.PathPatterns, options.ExcludePaths, options.ExcludeTests, options.Since, exact, visibilityFilters: options.VisibilityFilters, excludeVisibilityFilters: options.ExcludeVisibilityFilters); if (results.Count == 0) { diff --git a/tests/CodeIndex.Tests/QueryCommandRunnerSymbolTests.cs b/tests/CodeIndex.Tests/QueryCommandRunnerSymbolTests.cs index 0fd3edc07..4c644163e 100644 --- a/tests/CodeIndex.Tests/QueryCommandRunnerSymbolTests.cs +++ b/tests/CodeIndex.Tests/QueryCommandRunnerSymbolTests.cs @@ -250,6 +250,58 @@ public partial class McpServer } } + [Fact] + public void RunGoto_AllIgnoresDefaultLimitAndHonorsExplicitLimit_Issue4837() + { + const int definitionCount = 63; + var projectRoot = TestProjectHelper.CreateTempProject("cdidx_goto_all_issue4837"); + try + { + var dbPath = TestProjectHelper.CreateProjectDb(projectRoot); + for (var index = 0; index < definitionCount; index++) + { + TestProjectHelper.InsertIndexedFile( + dbPath, + $"src/SharedDefinition{index:D2}.cs", + "csharp", + "namespace Demo;\n\npublic class SharedDefinition { }\n"); + } + + foreach (var outputArgs in new[] + { + Array.Empty(), + new[] { "--json" }, + }) + { + var (exitCode, stdout, stderr) = CaptureConsole(() => QueryCommandRunner.RunGoto( + ["SharedDefinition", "--db", dbPath, "--kind", "class", "--lang", "csharp", "--exact-name", "--all", .. outputArgs], + _jsonOptions)); + + Assert.True(exitCode == CommandExitCodes.Success, $"stdout: {stdout}\nstderr: {stderr}"); + Assert.Equal(string.Empty, stderr); + using var document = ParseJsonOutput(stdout); + var locations = document.RootElement.EnumerateArray().ToList(); + + Assert.Equal(definitionCount, locations.Count); + Assert.EndsWith("/src/SharedDefinition00.cs", locations[0].GetProperty("uri").GetString()); + Assert.EndsWith("/src/SharedDefinition62.cs", locations[^1].GetProperty("uri").GetString()); + } + + var (limitedExitCode, limitedStdout, limitedStderr) = CaptureConsole(() => QueryCommandRunner.RunGoto( + ["SharedDefinition", "--db", dbPath, "--kind", "class", "--lang", "csharp", "--exact-name", "--all", "--limit", "7"], + _jsonOptions)); + + Assert.True(limitedExitCode == CommandExitCodes.Success, $"stdout: {limitedStdout}\nstderr: {limitedStderr}"); + Assert.Equal(string.Empty, limitedStderr); + using var limitedDocument = ParseJsonOutput(limitedStdout); + Assert.Equal(7, limitedDocument.RootElement.GetArrayLength()); + } + finally + { + TestProjectHelper.DeleteDirectory(projectRoot); + } + } + [Fact] public void RunSymbols_CountJsonMaxJsonBytesRejectsBareVerbatimZero_Issue4165() {