main 5041353

gen_docs.go RawHistoryFolder

1package cmd
2
3import (
4	"fmt"
5	"os"
6	"path/filepath"
7	"time"
8
9	"github.com/spf13/cobra"
10	"github.com/spf13/cobra/doc"
11
12	xdgadapter "github.com/bnema/dumber/internal/infrastructure/xdg"
13)
14
15const dirPerm = 0o755
16
17var (
18	genDocsOutputDir string
19	genDocsFormat    string
20)
21
22var genDocsCmd = &cobra.Command{
23	Use:   "gen-docs",
24	Short: "Generate documentation from CLI commands",
25	Long: `Generate documentation (man pages or markdown) from CLI command definitions.
26
27The documentation is auto-generated from the command structure, including:
28- Command names and aliases
29- Short and long descriptions
30- Flags and their descriptions
31- Usage examples
32
33Supported formats:
34  man       Unix manual pages (groff format)
35  markdown  Markdown files (for websites/wikis)
36
37By default, man pages are installed to ~/.local/share/man/man1/ so they
38are immediately available via 'man dumber'. You may need to run 'mandb'
39to update the man page index.
40
41Examples:
42  dumber gen-docs                           # Install man pages to ~/.local/share/man/man1/
43  dumber gen-docs --format markdown         # Generate markdown docs
44  dumber gen-docs --output ./man            # Generate to local directory`,
45	RunE: runGenDocs,
46}
47
48func init() {
49	rootCmd.AddCommand(genDocsCmd)
50	genDocsCmd.Flags().StringVarP(&genDocsOutputDir, "output", "o", "", "Output directory for generated docs")
51	genDocsCmd.Flags().StringVarP(&genDocsFormat, "format", "f", "man", "Output format: man, markdown")
52}
53
54func runGenDocs(_ *cobra.Command, _ []string) error {
55	// Resolve output directory
56	outputDir := genDocsOutputDir
57	if outputDir == "" {
58		switch genDocsFormat {
59		case "man":
60			xdg := xdgadapter.New(false, "")
61			manDir, err := xdg.ManDir()
62			if err != nil {
63				return fmt.Errorf("resolve man directory: %w", err)
64			}
65			outputDir = manDir
66		case "markdown":
67			outputDir = "./docs"
68		}
69	}
70
71	// Create output directory if it doesn't exist
72	if err := os.MkdirAll(outputDir, dirPerm); err != nil {
73		return fmt.Errorf("create output directory: %w", err)
74	}
75
76	switch genDocsFormat {
77	case "man":
78		return generateManPages(outputDir)
79	case "markdown":
80		return generateMarkdown(outputDir)
81	default:
82		return fmt.Errorf("unsupported format %q (use: man, markdown)", genDocsFormat)
83	}
84}
85
86func generateManPages(outputDir string) error {
87	header := &doc.GenManHeader{
88		Title:   "DUMBER",
89		Section: "1",
90		Source:  "dumber " + buildInfo.Version,
91		Manual:  "Dumber Manual",
92		Date:    func() *time.Time { t := time.Now(); return &t }(),
93	}
94
95	// Disable auto-generation timestamp in the footer for reproducible builds
96	rootCmd.DisableAutoGenTag = true
97
98	if err := doc.GenManTree(rootCmd, header, outputDir); err != nil {
99		return fmt.Errorf("generate man pages: %w", err)
100	}
101
102	fmt.Printf("Installed man pages to %s\n", outputDir)
103	fmt.Println("Run 'mandb' if 'man dumber' doesn't work immediately.")
104
105	// List generated files
106	entries, err := os.ReadDir(outputDir)
107	if err != nil {
108		return nil // Non-fatal
109	}
110	for _, e := range entries {
111		if filepath.Ext(e.Name()) == ".1" {
112			fmt.Printf("  - %s\n", e.Name())
113		}
114	}
115
116	return nil
117}
118
119func generateMarkdown(outputDir string) error {
120	// Disable auto-generation timestamp for reproducible builds
121	rootCmd.DisableAutoGenTag = true
122
123	if err := doc.GenMarkdownTree(rootCmd, outputDir); err != nil {
124		return fmt.Errorf("generate markdown docs: %w", err)
125	}
126
127	fmt.Printf("Generated markdown docs in %s\n", outputDir)
128
129	// List generated files
130	entries, err := os.ReadDir(outputDir)
131	if err != nil {
132		return nil // Non-fatal
133	}
134	for _, e := range entries {
135		if filepath.Ext(e.Name()) == ".md" {
136			fmt.Printf("  - %s\n", e.Name())
137		}
138	}
139
140	return nil
141}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close