diff options
| author | Paul Buetow <paul@buetow.org> | 2025-07-08 22:47:18 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-07-08 22:47:18 +0300 |
| commit | 5004ae7bf93e59e0e4992fa6c9640c427393f4a1 (patch) | |
| tree | fa079bed0f0ed0be29a875d545d7bfa49e30347d | |
| parent | 35b38d55f9260e49fc8a910a78fd1cfdf4b6bcb5 (diff) | |
feat: separate documentation from code in showcase statistics
- Add new Documentation field to RepoMetadata structure
- Update language detector to categorize Markdown, reStructuredText, LaTeX, etc. as documentation
- Display documentation statistics separately in both project entries and overall stats
- Calculate lines of code and documentation independently
- Show "Documentation: Markdown (100.0%)" style formatting
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
| -rw-r--r-- | internal/showcase/language_detector.go | 79 | ||||
| -rw-r--r-- | internal/showcase/metadata.go | 25 | ||||
| -rw-r--r-- | internal/showcase/showcase.go | 39 |
3 files changed, 116 insertions, 27 deletions
diff --git a/internal/showcase/language_detector.go b/internal/showcase/language_detector.go index ac7bc75..d049aac 100644 --- a/internal/showcase/language_detector.go +++ b/internal/showcase/language_detector.go @@ -10,8 +10,10 @@ import ( ) // detectLanguages detects programming languages used in the repository with line counts -func detectLanguages(repoPath string) ([]LanguageStats, error) { +// Returns both programming languages and documentation/text files separately +func detectLanguages(repoPath string) (languages []LanguageStats, documentation []LanguageStats, err error) { languageLines := make(map[string]int) + documentationLines := make(map[string]int) // Define common language extensions langExtensions := map[string]string{ @@ -70,9 +72,16 @@ func detectLanguages(repoPath string) ([]LanguageStats, error) { ".cfg": "Config", ".conf": "Config", ".sql": "SQL", + } + + // Define documentation/text extensions + docExtensions := map[string]string{ ".md": "Markdown", ".rst": "reStructuredText", ".tex": "LaTeX", + ".txt": "Text", + ".adoc": "AsciiDoc", + ".org": "Org", } // Special files that indicate specific languages @@ -102,7 +111,7 @@ func detectLanguages(repoPath string) ([]LanguageStats, error) { } // Count lines for each language - err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error { if err != nil { return nil // Skip errors } @@ -134,15 +143,20 @@ func detectLanguages(repoPath string) ([]LanguageStats, error) { basename := strings.ToLower(filepath.Base(path)) ext := strings.ToLower(filepath.Ext(path)) - // Determine the language + // Determine the language or documentation type var language string + var isDoc bool // Check special files first if lang, ok := specialFiles[basename]; ok { language = lang } else { - // Check by extension - if lang, ok := langExtensions[ext]; ok { + // Check documentation extensions + if docType, ok := docExtensions[ext]; ok { + language = docType + isDoc = true + } else if lang, ok := langExtensions[ext]; ok { + // Check programming language extensions language = lang } } @@ -151,7 +165,11 @@ func detectLanguages(repoPath string) ([]LanguageStats, error) { if language != "" { lines, err := countFileLines(path) if err == nil { - languageLines[language] += lines + if isDoc { + documentationLines[language] += lines + } else { + languageLines[language] += lines + } } } @@ -159,35 +177,58 @@ func detectLanguages(repoPath string) ([]LanguageStats, error) { }) if err != nil { - return nil, err + return nil, nil, err } - // Calculate total lines - totalLines := 0 + // Process programming languages + totalCodeLines := 0 for _, lines := range languageLines { - totalLines += lines + totalCodeLines += lines } - // Convert to LanguageStats with percentages - var stats []LanguageStats + var languageStats []LanguageStats for lang, lines := range languageLines { percentage := 0.0 - if totalLines > 0 { - percentage = float64(lines) * 100.0 / float64(totalLines) + if totalCodeLines > 0 { + percentage = float64(lines) * 100.0 / float64(totalCodeLines) } - stats = append(stats, LanguageStats{ + languageStats = append(languageStats, LanguageStats{ Name: lang, Lines: lines, Percentage: percentage, }) } - // Sort by percentage (descending) - sort.Slice(stats, func(i, j int) bool { - return stats[i].Percentage > stats[j].Percentage + // Sort languages by percentage (descending) + sort.Slice(languageStats, func(i, j int) bool { + return languageStats[i].Percentage > languageStats[j].Percentage + }) + + // Process documentation + totalDocLines := 0 + for _, lines := range documentationLines { + totalDocLines += lines + } + + var docStats []LanguageStats + for docType, lines := range documentationLines { + percentage := 0.0 + if totalDocLines > 0 { + percentage = float64(lines) * 100.0 / float64(totalDocLines) + } + docStats = append(docStats, LanguageStats{ + Name: docType, + Lines: lines, + Percentage: percentage, + }) + } + + // Sort documentation by percentage (descending) + sort.Slice(docStats, func(i, j int) bool { + return docStats[i].Percentage > docStats[j].Percentage }) - return stats, nil + return languageStats, docStats, nil } // countFileLines counts the number of lines in a file diff --git a/internal/showcase/metadata.go b/internal/showcase/metadata.go index 713af90..13caf9f 100644 --- a/internal/showcase/metadata.go +++ b/internal/showcase/metadata.go @@ -19,9 +19,11 @@ type LanguageStats struct { // RepoMetadata holds metadata about a repository type RepoMetadata struct { - Languages []LanguageStats // Languages with usage statistics + Languages []LanguageStats // Programming languages with usage statistics + Documentation []LanguageStats // Documentation/text files with usage statistics CommitCount int - LinesOfCode int + LinesOfCode int // Lines of code (excluding documentation) + LinesOfDocs int // Lines of documentation FirstCommitDate string LastCommitDate string License string @@ -32,12 +34,13 @@ type RepoMetadata struct { func extractRepoMetadata(repoPath string) (*RepoMetadata, error) { metadata := &RepoMetadata{} - // Get programming languages by analyzing file extensions - languages, err := detectLanguages(repoPath) + // Get programming languages and documentation by analyzing file extensions + languages, documentation, err := detectLanguages(repoPath) if err != nil { fmt.Printf("Warning: Failed to detect languages: %v\n", err) } metadata.Languages = languages + metadata.Documentation = documentation // Get commit count commitCount, err := getCommitCount(repoPath) @@ -46,12 +49,18 @@ func extractRepoMetadata(repoPath string) (*RepoMetadata, error) { } metadata.CommitCount = commitCount - // Get lines of code - loc, err := countLinesOfCode(repoPath) - if err != nil { - fmt.Printf("Warning: Failed to count lines of code: %v\n", err) + // Calculate lines of code and documentation from language stats + loc := 0 + for _, lang := range metadata.Languages { + loc += lang.Lines } metadata.LinesOfCode = loc + + locDocs := 0 + for _, doc := range metadata.Documentation { + locDocs += doc.Lines + } + metadata.LinesOfDocs = locDocs // Get first and last commit dates firstDate, err := getFirstCommitDate(repoPath) diff --git a/internal/showcase/showcase.go b/internal/showcase/showcase.go index e9ae55f..60b0fb2 100644 --- a/internal/showcase/showcase.go +++ b/internal/showcase/showcase.go @@ -297,17 +297,25 @@ func (g *Generator) formatGemtext(summaries []ProjectSummary) string { totalProjects := len(summaries) totalCommits := 0 totalLOC := 0 + totalDocs := 0 languageTotals := make(map[string]int) + docTotals := make(map[string]int) for _, summary := range summaries { if summary.Metadata != nil { totalCommits += summary.Metadata.CommitCount totalLOC += summary.Metadata.LinesOfCode + totalDocs += summary.Metadata.LinesOfDocs // Aggregate language statistics for _, lang := range summary.Metadata.Languages { languageTotals[lang.Name] += lang.Lines } + + // Aggregate documentation statistics + for _, doc := range summary.Metadata.Documentation { + docTotals[doc.Name] += doc.Lines + } } } @@ -330,14 +338,39 @@ func (g *Generator) formatGemtext(summaries []ProjectSummary) string { return languageStats[i].Percentage > languageStats[j].Percentage }) + // Calculate documentation percentages + var docStats []LanguageStats + for name, lines := range docTotals { + percentage := 0.0 + if totalDocs > 0 { + percentage = float64(lines) * 100.0 / float64(totalDocs) + } + docStats = append(docStats, LanguageStats{ + Name: name, + Lines: lines, + Percentage: percentage, + }) + } + + // Sort documentation by percentage + sort.Slice(docStats, func(i, j int) bool { + return docStats[i].Percentage > docStats[j].Percentage + }) + // Write total stats section builder.WriteString("## Overall Statistics\n\n") builder.WriteString(fmt.Sprintf("* Total Projects: %d\n", totalProjects)) builder.WriteString(fmt.Sprintf("* Total Commits: %s\n", formatNumber(totalCommits))) builder.WriteString(fmt.Sprintf("* Total Lines of Code: %s\n", formatNumber(totalLOC))) + if totalDocs > 0 { + builder.WriteString(fmt.Sprintf("* Total Lines of Documentation: %s\n", formatNumber(totalDocs))) + } if len(languageStats) > 0 { builder.WriteString(fmt.Sprintf("* Languages: %s\n", FormatLanguagesWithPercentages(languageStats))) } + if len(docStats) > 0 { + builder.WriteString(fmt.Sprintf("* Documentation: %s\n", FormatLanguagesWithPercentages(docStats))) + } builder.WriteString("\n") builder.WriteString(fmt.Sprintf("Generated on: %s\n\n", time.Now().Format("2006-01-02"))) @@ -358,8 +391,14 @@ func (g *Generator) formatGemtext(summaries []ProjectSummary) string { if len(summary.Metadata.Languages) > 0 { builder.WriteString(fmt.Sprintf("* Languages: %s\n", FormatLanguagesWithPercentages(summary.Metadata.Languages))) } + if len(summary.Metadata.Documentation) > 0 { + builder.WriteString(fmt.Sprintf("* Documentation: %s\n", FormatLanguagesWithPercentages(summary.Metadata.Documentation))) + } builder.WriteString(fmt.Sprintf("* Commits: %d\n", summary.Metadata.CommitCount)) builder.WriteString(fmt.Sprintf("* Lines of Code: %d\n", summary.Metadata.LinesOfCode)) + if summary.Metadata.LinesOfDocs > 0 { + builder.WriteString(fmt.Sprintf("* Lines of Documentation: %d\n", summary.Metadata.LinesOfDocs)) + } builder.WriteString(fmt.Sprintf("* Development Period: %s to %s\n", summary.Metadata.FirstCommitDate, summary.Metadata.LastCommitDate)) builder.WriteString(fmt.Sprintf("* Recent Activity: %.1f days (avg. age of last 42 commits)\n", summary.Metadata.AvgCommitAge)) builder.WriteString(fmt.Sprintf("* License: %s\n\n", summary.Metadata.License)) |
