summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-08 23:30:47 +0300
committerPaul Buetow <paul@buetow.org>2025-07-08 23:30:47 +0300
commitdf623bfdcecad9fd4c0f5229ce9af5e8416a9558 (patch)
tree31392b853685d7ead9540ecc2cf6cbca48cac421
parent22c5df936434d172f46e9a24cd4582d3658636eb (diff)
feat: add syntax highlighting labels and strip comments from code snippets
- Add language labels to code blocks for syntax highlighting (e.g., ```go, ```sh) - Map languages to source-highlight compatible identifiers - Strip comments from code snippets to show more actual code - Comments no longer count towards the ~10 line target - Support for multi-line and single-line comment removal - Remove inline comments where appropriate 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
-rw-r--r--internal/showcase/code_extractor.go80
-rw-r--r--internal/showcase/showcase.go59
2 files changed, 134 insertions, 5 deletions
diff --git a/internal/showcase/code_extractor.go b/internal/showcase/code_extractor.go
index e8ba0d3..b51761c 100644
--- a/internal/showcase/code_extractor.go
+++ b/internal/showcase/code_extractor.go
@@ -165,13 +165,14 @@ func extractSnippetFromFile(filePath string, minLines, maxLines int) (string, er
// Try to find the smallest complete function
bestFunction := findSmallestCompleteFunction(lines)
if bestFunction != "" {
- return bestFunction, nil
+ return stripComments(bestFunction), nil
}
// If no complete function found, try to find a complete function/method
functionStart, functionEnd := findCompleteFunctionOrMethod(lines, minLines, maxLines*2) // Allow larger functions
if functionStart >= 0 && functionEnd >= 0 {
- return strings.Join(lines[functionStart:functionEnd+1], "\n"), nil
+ snippet := strings.Join(lines[functionStart:functionEnd+1], "\n")
+ return stripComments(snippet), nil
}
// Fallback to finding an interesting start with at least minLines
@@ -181,7 +182,8 @@ func extractSnippetFromFile(filePath string, minLines, maxLines int) (string, er
if endLine > totalLines {
endLine = totalLines
}
- return strings.Join(lines[interestingStart:endLine], "\n"), nil
+ snippet := strings.Join(lines[interestingStart:endLine], "\n")
+ return stripComments(snippet), nil
}
// Last resort: return first minLines (skip imports if possible)
@@ -201,7 +203,8 @@ func extractSnippetFromFile(filePath string, minLines, maxLines int) (string, er
endLine = totalLines
}
- return strings.Join(lines[skipLines:endLine], "\n"), nil
+ snippet := strings.Join(lines[skipLines:endLine], "\n")
+ return stripComments(snippet), nil
}
// findSmallestCompleteFunction finds the smallest complete function in the file
@@ -392,4 +395,73 @@ func findInterestingStart(lines []string, snippetSize int) int {
// No interesting start found
return -1
+}
+
+// stripComments removes comment lines from code snippets to make them more concise
+func stripComments(code string) string {
+ lines := strings.Split(code, "\n")
+ var result []string
+ inMultilineComment := false
+
+ for _, line := range lines {
+ trimmed := strings.TrimSpace(line)
+
+ // Handle multi-line comments for C-style languages
+ if strings.Contains(line, "/*") {
+ inMultilineComment = true
+ // If comment ends on same line, process the rest
+ if strings.Contains(line, "*/") {
+ inMultilineComment = false
+ // Skip this line entirely if it's just a comment
+ if strings.TrimSpace(strings.Split(line, "/*")[0]) == "" {
+ continue
+ }
+ } else {
+ continue
+ }
+ }
+
+ if inMultilineComment {
+ if strings.Contains(line, "*/") {
+ inMultilineComment = false
+ }
+ continue
+ }
+
+ // Skip single-line comments
+ if trimmed == "" {
+ // Keep empty lines for readability
+ result = append(result, line)
+ } else if strings.HasPrefix(trimmed, "//") ||
+ strings.HasPrefix(trimmed, "#") && !strings.HasPrefix(trimmed, "#include") && !strings.HasPrefix(trimmed, "#define") ||
+ strings.HasPrefix(trimmed, "<!--") ||
+ strings.HasPrefix(trimmed, "*") && len(trimmed) > 1 && trimmed[1] == ' ' {
+ // Skip comment lines
+ continue
+ } else if strings.HasPrefix(trimmed, "\"\"\"") || strings.HasPrefix(trimmed, "'''") {
+ // Skip Python docstrings (simplified - doesn't handle all cases)
+ continue
+ } else {
+ // Keep the line but remove inline comments for some languages
+ // This is a simple approach - doesn't handle all edge cases
+ if idx := strings.Index(line, " //"); idx > 0 {
+ // Check if it's not inside a string (very basic check)
+ beforeComment := line[:idx]
+ if strings.Count(beforeComment, "\"")%2 == 0 && strings.Count(beforeComment, "'")%2 == 0 {
+ line = strings.TrimRight(line[:idx], " \t")
+ }
+ }
+ result = append(result, line)
+ }
+ }
+
+ // Remove leading and trailing empty lines
+ for len(result) > 0 && strings.TrimSpace(result[0]) == "" {
+ result = result[1:]
+ }
+ for len(result) > 0 && strings.TrimSpace(result[len(result)-1]) == "" {
+ result = result[:len(result)-1]
+ }
+
+ return strings.Join(result, "\n")
} \ No newline at end of file
diff --git a/internal/showcase/showcase.go b/internal/showcase/showcase.go
index bb71b0e..884f81a 100644
--- a/internal/showcase/showcase.go
+++ b/internal/showcase/showcase.go
@@ -492,7 +492,9 @@ func (g *Generator) formatGemtext(summaries []ProjectSummary) string {
// Add code snippet at the end for all projects
if summary.CodeSnippet != "" {
- builder.WriteString(fmt.Sprintf("\n%s:\n\n```\n%s\n```\n", summary.CodeLanguage, summary.CodeSnippet))
+ // Extract the language name for syntax highlighting
+ languageName := extractLanguageForHighlighting(summary.CodeLanguage)
+ builder.WriteString(fmt.Sprintf("\n%s:\n\n```%s\n%s\n```\n", summary.CodeLanguage, languageName, summary.CodeSnippet))
}
}
@@ -714,4 +716,59 @@ func detectAIUsage(repoPath string) bool {
}
return false
+}
+
+// extractLanguageForHighlighting extracts the language name from the CodeLanguage string
+// for syntax highlighting in code blocks
+func extractLanguageForHighlighting(codeLanguage string) string {
+ // codeLanguage format: "Language from `path/to/file`"
+ // Extract just the language name
+ parts := strings.Split(codeLanguage, " ")
+ if len(parts) > 0 {
+ lang := strings.ToLower(parts[0])
+
+ // Map language names to syntax highlighting identifiers
+ // Based on source-highlight --lang-list output
+ languageMap := map[string]string{
+ "go": "go",
+ "python": "python",
+ "javascript": "javascript",
+ "typescript": "javascript", // Use javascript for TypeScript
+ "java": "java",
+ "c": "c",
+ "c++": "cpp",
+ "c/c++": "cpp",
+ "c#": "csharp",
+ "ruby": "ruby",
+ "rust": "rust",
+ "shell": "sh", // source-highlight uses sh.lang
+ "bash": "bash",
+ "perl": "perl",
+ "php": "php",
+ "swift": "swift",
+ "kotlin": "java", // Use java highlighting for Kotlin
+ "haskell": "haskell",
+ "lua": "lua",
+ "html": "html",
+ "css": "css",
+ "sql": "sql",
+ "make": "makefile",
+ "docker": "dockerfile",
+ "yaml": "yaml",
+ "json": "json",
+ "xml": "xml",
+ "toml": "toml",
+ "hcl": "hcl",
+ "vim": "vim",
+ }
+
+ if mapped, ok := languageMap[lang]; ok {
+ return mapped
+ }
+
+ // Return the original language name if no mapping exists
+ return lang
+ }
+
+ return ""
} \ No newline at end of file