From aa5c0f810aecd154e7773920f432a710c67179f9 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 06:26:19 +0000 Subject: [PATCH] feat(help): add explicit search subcommand Co-Authored-By: Virgil --- cmd/core/help/cmd.go | 26 +++++++++++++++- cmd/core/help/cmd_test.go | 65 ++++++++++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/cmd/core/help/cmd.go b/cmd/core/help/cmd.go index 0ddda7d..f87472e 100644 --- a/cmd/core/help/cmd.go +++ b/cmd/core/help/cmd.go @@ -24,7 +24,7 @@ func AddHelpCommands(root *cli.Command) { catalog := gohelp.DefaultCatalog() if searchQuery != "" { - return renderSearchResults(catalog.Search(searchQuery), searchQuery) + return searchHelpTopics(catalog, searchQuery) } if len(args) == 0 { @@ -47,6 +47,25 @@ func AddHelpCommands(root *cli.Command) { }, } + searchCmd := &cli.Command{ + Use: "search [query]", + Short: "Search help topics", + Args: cobra.ArbitraryArgs, + } + var searchCmdQuery string + searchCmd.Flags().StringVarP(&searchCmdQuery, "query", "q", "", "Search query") + searchCmd.RunE = func(cmd *cli.Command, args []string) error { + catalog := gohelp.DefaultCatalog() + query := strings.TrimSpace(searchCmdQuery) + if query == "" { + query = strings.TrimSpace(strings.Join(args, " ")) + } + if query == "" { + return cli.Err("help search query is required") + } + return searchHelpTopics(catalog, query) + } + var serveAddr string serveCmd := &cli.Command{ Use: "serve", @@ -59,10 +78,15 @@ func AddHelpCommands(root *cli.Command) { serveCmd.Flags().StringVar(&serveAddr, "addr", ":8080", "HTTP listen address") helpCmd.AddCommand(serveCmd) + helpCmd.AddCommand(searchCmd) helpCmd.Flags().StringVarP(&searchQuery, "search", "s", "", "Search help topics") root.AddCommand(helpCmd) } +func searchHelpTopics(catalog *gohelp.Catalog, query string) error { + return renderSearchResults(catalog.Search(query), query) +} + func renderSearchResults(results []*gohelp.SearchResult, query string) error { if len(results) == 0 { return cli.Err("no help topics matched %q", query) diff --git a/cmd/core/help/cmd_test.go b/cmd/core/help/cmd_test.go index 6cabe44..655e80c 100644 --- a/cmd/core/help/cmd_test.go +++ b/cmd/core/help/cmd_test.go @@ -45,6 +45,23 @@ func newHelpCommand(t *testing.T) *cli.Command { return cmd } +func searchableHelpQuery(t *testing.T) string { + t.Helper() + + catalog := gohelp.DefaultCatalog() + for _, candidate := range []string{"configuration", "docs", "search", "topic", "help"} { + if _, err := catalog.Get(candidate); err == nil { + continue + } + if len(catalog.Search(candidate)) > 0 { + return candidate + } + } + + t.Skip("no suitable query found with suggestions") + return "" +} + func TestAddHelpCommands_Good(t *testing.T) { cmd := newHelpCommand(t) @@ -83,6 +100,26 @@ func TestAddHelpCommands_Good_Serve(t *testing.T) { assert.Equal(t, "127.0.0.1:9090", gotAddr) } +func TestAddHelpCommands_Good_Search(t *testing.T) { + root := &cli.Command{Use: "core"} + AddHelpCommands(root) + + cmd, _, err := root.Find([]string{"help", "search"}) + require.NoError(t, err) + require.NotNil(t, cmd) + + query := searchableHelpQuery(t) + require.NoError(t, cmd.Flags().Set("query", query)) + + out := captureOutput(t, func() { + err := cmd.RunE(cmd, nil) + require.NoError(t, err) + }) + + assert.Contains(t, out, "SEARCH RESULTS") + assert.Contains(t, out, query) +} + func TestRenderSearchResults_Good(t *testing.T) { out := captureOutput(t, func() { err := renderSearchResults([]*gohelp.SearchResult{ @@ -129,6 +166,19 @@ func TestAddHelpCommands_Bad(t *testing.T) { assert.Contains(t, err.Error(), "no help topics matched") }) + t.Run("missing search query", func(t *testing.T) { + root := &cli.Command{Use: "core"} + AddHelpCommands(root) + + cmd, _, err := root.Find([]string{"help", "search"}) + require.NoError(t, err) + require.NotNil(t, cmd) + + err = cmd.RunE(cmd, nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "help search query is required") + }) + t.Run("missing topic", func(t *testing.T) { cmd := newHelpCommand(t) err := cmd.RunE(cmd, []string{"definitely-not-a-real-topic"}) @@ -137,20 +187,7 @@ func TestAddHelpCommands_Bad(t *testing.T) { }) t.Run("missing topic shows suggestions when available", func(t *testing.T) { - catalog := gohelp.DefaultCatalog() - query := "" - for _, candidate := range []string{"configuration", "docs", "search", "topic", "help"} { - if _, err := catalog.Get(candidate); err == nil { - continue - } - if len(catalog.Search(candidate)) > 0 { - query = candidate - break - } - } - if query == "" { - t.Skip("no suitable query found with suggestions") - } + query := searchableHelpQuery(t) cmd := newHelpCommand(t) out := captureOutput(t, func() { -- 2.45.3