custom tag command
This commit is contained in:
parent
d4dbec8a84
commit
87f599a01e
|
|
@ -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</%s>", innerContent)`, targetTag, targetClass, targetTag)
|
||||
} else {
|
||||
replacementLogic = fmt.Sprintf(`return fmt.Sprintf("<%s>%%s</%s>", innerContent)`, targetTag, targetTag)
|
||||
}
|
||||
|
||||
codeBlock := fmt.Sprintf(`
|
||||
// %s %s
|
||||
%sRegex := regexp.MustCompile("(?s)<%s>.*?</%s>")
|
||||
if %sRegex.MatchString(htmlContent) {
|
||||
htmlContent = %sRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
|
||||
innerContent := strings.TrimPrefix(match, "<%s>")
|
||||
innerContent = strings.TrimSuffix(innerContent, "</%s>")
|
||||
%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, ""
|
||||
}
|
||||
|
|
@ -1 +1,7 @@
|
|||
# I'm quite fond of lyrics. Particicularly, I like interpol lyrics.
|
||||
|
||||
I'm testing custom tags:
|
||||
|
||||
{[]}(\(x+x\)).
|
||||
|
||||
{[]}x+1
|
||||
|
|
|
|||
8
main.go
8
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
|
||||
|
|
|
|||
13
parse.go
13
parse.go
|
|
@ -61,6 +61,7 @@ func GetContentPath(file ContentFile) (string, error) {
|
|||
&frontmatter.Extender{},
|
||||
templates.SidebarTag, // ||| -> <sidebar>
|
||||
templates.TopBanner,
|
||||
templates.Mathtext,
|
||||
),
|
||||
goldmark.WithRendererOptions(
|
||||
html.WithUnsafe(),
|
||||
|
|
@ -143,8 +144,20 @@ func GetContentPath(file ContentFile) (string, error) {
|
|||
return fmt.Sprintf(`<div class="topbanner">%s</div>`, bannerHTML)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Mathtext mathtext
|
||||
mathtextRegex := regexp.MustCompile("(?s)<mathtext>.*?</mathtext>")
|
||||
if mathtextRegex.MatchString(htmlContent) {
|
||||
htmlContent = mathtextRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
|
||||
innerContent := strings.TrimPrefix(match, "<mathtext>")
|
||||
innerContent = strings.TrimSuffix(innerContent, "</mathtext>")
|
||||
return fmt.Sprintf("<li class=\"mathtext\">%s</li>", innerContent)
|
||||
})
|
||||
}
|
||||
// Build Full Page
|
||||
dataToWrite = templates.BuildFullPage([]byte(htmlContent), meta)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@ import customtag "github.com/tendstofortytwo/goldmark-customtag"
|
|||
// ||| -> <sidebar></sidebar>
|
||||
var SidebarTag = customtag.New("|||", "sidebar")
|
||||
var TopBanner = customtag.New("_-_-", "topbanner")
|
||||
var Mathtext = customtag.New("{[]}", "mathtext")
|
||||
|
|
|
|||
Loading…
Reference in New Issue