summaryrefslogtreecommitdiff
path: root/internal/showcase
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-08 22:47:18 +0300
committerPaul Buetow <paul@buetow.org>2025-07-08 22:47:18 +0300
commit5004ae7bf93e59e0e4992fa6c9640c427393f4a1 (patch)
treefa079bed0f0ed0be29a875d545d7bfa49e30347d /internal/showcase
parent35b38d55f9260e49fc8a910a78fd1cfdf4b6bcb5 (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>
Diffstat (limited to 'internal/showcase')
-rw-r--r--internal/showcase/language_detector.go79
-rw-r--r--internal/showcase/metadata.go25
-rw-r--r--internal/showcase/showcase.go39
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))