diff --git a/cmd_addtag.go b/cmd_addtag.go new file mode 100644 index 0000000..14c48ad --- /dev/null +++ b/cmd_addtag.go @@ -0,0 +1,148 @@ +package main + +import ( + "fmt" + "os" + "strings" + "unicode" +) + +// AddTag generates code for a new custom tag +func AddTag(delimiter, tagName, targetElement string) { + fmt.Printf("Adding tag: %s -> %s (delimiter: %s)\n", tagName, targetElement, delimiter) + + if err := updateTagsFile(delimiter, tagName); err != nil { + fmt.Printf("Error updating templates/tags.go: %v\n", err) + os.Exit(1) + } + + if err := updateParseFile(tagName, targetElement); err != nil { + fmt.Printf("Error updating parse.go: %v\n", err) + os.Exit(1) + } + + fmt.Println("Successfully added tag!") +} + +func updateTagsFile(delimiter, tagName string) error { + path := "templates/tags.go" + content, err := os.ReadFile(path) + if err != nil { + return err + } + + pascalTagName := toPascalCase(tagName) + newLine := fmt.Sprintf("var %s = customtag.New(\"%s\", \"%s\")\n", pascalTagName, delimiter, tagName) + + // check if already exists + if strings.Contains(string(content), newLine) { + fmt.Println("Tag definition already exists in templates/tags.go") + return nil + } + + // Append to file + f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + + if _, err := f.WriteString(newLine); err != nil { + return err + } + + return nil +} + +func updateParseFile(tagName, targetElement string) error { + path := "parse.go" + contentBytes, err := os.ReadFile(path) + if err != nil { + return err + } + content := string(contentBytes) + + pascalTagName := toPascalCase(tagName) + + // 1. Add to Goldmark Extensions + // Find `templates.SidebarTag,` or `templates.TopBanner,` and add after it + // We'll look for `goldmark.WithExtensions(` and find the closing `),` + + extLine := fmt.Sprintf("\t\t\t\ttemplates.%s,", pascalTagName) + if !strings.Contains(content, extLine) { + // Simple insertion strategy: find `templates.TopBanner,` + anchor := "templates.TopBanner," + if idx := strings.Index(content, anchor); idx != -1 { + insertAt := idx + len(anchor) + content = content[:insertAt] + "\n" + extLine + content[insertAt:] + } else { + return fmt.Errorf("could not find anchor 'templates.TopBanner,' in parse.go to insert extension registration") + } + } else { + fmt.Println("Extension registration already exists in parse.go") + } + + // 2. Add Post-Processing Logic + // We'll look for `// Build Full Page` and insert before it, or after the TopBanner block. + // A good anchor is `// _-_- TopBanner` block's end. + + // Let's construct the code block to insert + targetTag, targetClass := parseTargetElement(targetElement) + + // Prepare the replacement logic + var replacementLogic string + if targetClass != "" { + replacementLogic = fmt.Sprintf(`return fmt.Sprintf("<%s class=\"%s\">%%s", innerContent)`, targetTag, targetClass, targetTag) + } else { + replacementLogic = fmt.Sprintf(`return fmt.Sprintf("<%s>%%s", innerContent)`, targetTag, targetTag) + } + + codeBlock := fmt.Sprintf(` + // %s %s + %sRegex := regexp.MustCompile("(?s)<%s>.*?") + if %sRegex.MatchString(htmlContent) { + htmlContent = %sRegex.ReplaceAllStringFunc(htmlContent, func(match string) string { + innerContent := strings.TrimPrefix(match, "<%s>") + innerContent = strings.TrimSuffix(innerContent, "") + %s + }) + } +`, pascalTagName, tagName, tagName, tagName, tagName, tagName, tagName, tagName, tagName, replacementLogic) + + if !strings.Contains(content, fmt.Sprintf("%sRegex :=", tagName)) { + // Anchor: find end of TopBanner block + // We know TopBanner block ends with a closing brace for the `if topbannerRegex.MatchString` block + // But strictly speaking, we are inside `if file.RoutePath == "/" { ... }`. + // Let's look for `// Build Full Page` and insert BEFORE it. + + + anchor := "// Build Full Page" + if idx := strings.Index(content, anchor); idx != -1 { + // Insert BEFORE "// Build Full Page", which matches the global scope (after the if block) + content = content[:idx] + codeBlock + content[idx:] + } else { + return fmt.Errorf("could not find anchor '// Build Full Page' in parse.go") + } + } else { + fmt.Println("Regex logic already exists in parse.go") + } + + return os.WriteFile(path, []byte(content), 0644) +} + +func toPascalCase(s string) string { + if s == "" { + return "" + } + runes := []rune(s) + runes[0] = unicode.ToUpper(runes[0]) + return string(runes) +} + +func parseTargetElement(t string) (string, string) { + parts := strings.Split(t, ".") + if len(parts) == 2 { + return parts[0], parts[1] + } + return t, "" +} diff --git a/content/entries/entry1.md b/content/entries/entry1.md index 930f533..297cee4 100644 --- a/content/entries/entry1.md +++ b/content/entries/entry1.md @@ -1 +1,7 @@ -# I'm quite fond of lyrics. Particicularly, I like interpol lyrics. \ No newline at end of file +# I'm quite fond of lyrics. Particicularly, I like interpol lyrics. + +I'm testing custom tags: + +{[]}(\(x+x\)). + +{[]}x+1 diff --git a/main.go b/main.go index ba56832..259c9b8 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,14 @@ func main() { ClearCache() StartServer() return + case "addTag": + if len(os.Args) < 5 { + fmt.Println("Usage: blog addTag {delimiter} {tagName} {targetElement}") + fmt.Println("Example: blog addTag {[]} mathtext li.mathtext") + return + } + AddTag(os.Args[2], os.Args[3], os.Args[4]) + return default: fmt.Printf("Unknown command: %s\nUsage: blog [service|test]\n", os.Args[1]) return diff --git a/parse.go b/parse.go index 0ca004a..d9694f3 100644 --- a/parse.go +++ b/parse.go @@ -61,6 +61,7 @@ func GetContentPath(file ContentFile) (string, error) { &frontmatter.Extender{}, templates.SidebarTag, // ||| -> templates.TopBanner, + templates.Mathtext, ), goldmark.WithRendererOptions( html.WithUnsafe(), @@ -143,9 +144,21 @@ func GetContentPath(file ContentFile) (string, error) { return fmt.Sprintf(`
%s
`, bannerHTML) }) } - } + - // Build Full Page +} + + + // Mathtext mathtext + mathtextRegex := regexp.MustCompile("(?s).*?") + if mathtextRegex.MatchString(htmlContent) { + htmlContent = mathtextRegex.ReplaceAllStringFunc(htmlContent, func(match string) string { + innerContent := strings.TrimPrefix(match, "") + innerContent = strings.TrimSuffix(innerContent, "") + return fmt.Sprintf("
  • %s
  • ", innerContent) + }) + } +// Build Full Page dataToWrite = templates.BuildFullPage([]byte(htmlContent), meta) } diff --git a/templates/tags.go b/templates/tags.go index 6abd385..cd10b3b 100644 --- a/templates/tags.go +++ b/templates/tags.go @@ -6,3 +6,4 @@ import customtag "github.com/tendstofortytwo/goldmark-customtag" // ||| -> var SidebarTag = customtag.New("|||", "sidebar") var TopBanner = customtag.New("_-_-", "topbanner") +var Mathtext = customtag.New("{[]}", "mathtext")