emdbed/emdbed.go

82 lines
1.8 KiB
Go

package emdbed
import (
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
)
var (
start = regexp.MustCompile(`(?m)^<!--\s*emdbed:\s*([^\s]+)\s*(~[\w]+)?\s*(?:(/[^/]+/|L\d+)\s*(/[^/]+/|L\d+)?)?\s*-->$`)
end = regexp.MustCompile(`(?m)^<!--\s*/emdbed\s*-->$`)
)
// ConvertFile is a helper for converting a file on disk
func ConvertFile(path string) (string, error) {
fi, err := os.Open(path)
if err != nil {
return "", err
}
defer fi.Close()
return Convert(filepath.Dir(path), fi)
}
// Convert converts an io.Reader with respect to a base directory
func Convert(dir string, file io.Reader) (string, error) {
data, err := io.ReadAll(file)
if err != nil {
return "", err
}
contents := string(data)
var out strings.Builder
starts := start.FindAllStringSubmatchIndex(contents, -1)
ends := end.FindAllStringIndex(contents, -1)
if len(starts) != len(ends) {
return "", fmt.Errorf("start selectors (%d) != end selectors (%d)", len(starts), len(ends))
}
var last int
for idx, start := range starts {
out.WriteString(contents[last:start[1]])
relPath := contents[start[2]:start[3]]
fileContents, err := os.ReadFile(filepath.Join(dir, relPath))
if err != nil {
return "", err
}
lang := strings.TrimPrefix(filepath.Ext(relPath), ".")
if start[4] != -1 {
lang = contents[start[4]+1 : start[5]]
}
var startSel string
if start[6] != -1 {
startSel = contents[start[6]:start[7]]
}
var endSel string
if start[8] != -1 {
endSel = contents[start[8]:start[9]]
}
e := emdbed{
name: relPath,
contents: string(fileContents),
language: lang,
start: startSel,
end: endSel,
}
sel, err := e.Selection()
if err != nil {
return "", err
}
out.WriteString(fmt.Sprintf("\n```%s\n%s\n```\n", e.language, sel))
last = ends[idx][0]
}
out.WriteString(contents[last:])
return out.String(), nil
}