141 lines
3.5 KiB
Go
141 lines
3.5 KiB
Go
package main
|
|
|
|
import(
|
|
"fmt"
|
|
"os"
|
|
"io"
|
|
"strings"
|
|
"strconv"
|
|
p "github.com/mcecode/gemtext-parser"
|
|
)
|
|
|
|
type State struct {
|
|
out io.Writer
|
|
maxLineLength int
|
|
insertionMap []string
|
|
insertionIndex int
|
|
isInCodeBlock bool
|
|
wasPreviousLink bool
|
|
isWebOnly bool
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 3 {
|
|
fmt.Printf("Usage: %s input.gmi output_gophermap [max line length (default 70)] [preprocessor insertion map file]\n", os.Args[0])
|
|
return
|
|
}
|
|
|
|
var asl p.ASL
|
|
var err error
|
|
if os.Args[1] != "-" {
|
|
asl, err = p.ParseFile(os.Args[1])
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return
|
|
}
|
|
} else {
|
|
stdin, err := io.ReadAll(os.Stdin)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return
|
|
}
|
|
asl = p.Parse(string(stdin))
|
|
}
|
|
|
|
var outputWriter io.Writer
|
|
if os.Args[2] != "-" {
|
|
file, err := os.Create(os.Args[2])
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
outputWriter = file
|
|
} else {
|
|
outputWriter = os.Stdout
|
|
}
|
|
|
|
preprocessorMap := []string{}
|
|
if len(os.Args) >= 5 {
|
|
data, err := os.ReadFile(os.Args[4])
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
preprocessorMap = strings.Split(string(data), "<!--break-->")
|
|
}
|
|
|
|
s := State{outputWriter, 70, preprocessorMap, 0, false, false, false}
|
|
if len(os.Args) >= 4 {
|
|
maxLineLength, err := strconv.Atoi(os.Args[3])
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return
|
|
}
|
|
s.maxLineLength = maxLineLength
|
|
}
|
|
|
|
asl.Visit(s.handleElement)
|
|
}
|
|
|
|
var gopherTypeCharParams = GopherTypeCharParams{
|
|
GophermapFiles: []string{"gophermap"},
|
|
GophermapExtensions: []string{},
|
|
PromptFileExtensions: []string{},
|
|
}
|
|
|
|
func (s *State) handleElement(e p.Element) {
|
|
if strings.HasPrefix(e.Text(), "<!--web-only-->") {
|
|
s.isWebOnly = !s.isWebOnly
|
|
return
|
|
}
|
|
if s.isWebOnly { return }
|
|
if strings.HasPrefix(e.Text(), "<!--insert-gopher-->") {
|
|
s.out.Write([]byte(s.insertionMap[s.insertionIndex]))
|
|
s.insertionIndex += 1
|
|
return
|
|
}
|
|
|
|
switch (e.Type()) {
|
|
case p.ElementTypes.Text():
|
|
if e.Text() == "" { return }
|
|
if !s.isInCodeBlock { s.out.Write([]byte("\n")) }
|
|
s.out.Write([]byte(JoinGophermapLines("i", WrapLines(e.Text(), s.maxLineLength, " "), "\t/FAKE\tNULL\t0")))
|
|
s.wasPreviousLink = false
|
|
case p.ElementTypes.Link():
|
|
if !s.wasPreviousLink {
|
|
s.out.Write([]byte("\n"))
|
|
}
|
|
isUrl := strings.Contains(e.URL(), "://")
|
|
linkPrefix := ""
|
|
if isUrl {
|
|
linkPrefix = "URL:"
|
|
}
|
|
typeChar := gopherTypeCharParams.GopherTypeChar(e.URL(), strings.HasSuffix(e.URL(), "/"))
|
|
s.out.Write([]byte(typeChar + e.Text() + "\t" + linkPrefix + e.URL()))
|
|
s.wasPreviousLink = true
|
|
case p.ElementTypes.Heading():
|
|
s.out.Write([]byte("\n"))
|
|
if e.Level() == p.HeadingLevels.Heading() || e.Level() == p.HeadingLevels.SubHeading() {
|
|
s.out.Write([]byte("\n\n"))
|
|
}
|
|
if e.Level() == p.HeadingLevels.SubSubHeading() {
|
|
s.out.Write([]byte("\n"))
|
|
}
|
|
s.out.Write([]byte(JoinGophermapLines("i", WrapLines(e.Text(), s.maxLineLength, " "), "\t/FAKE\tNULL\t0")))
|
|
s.wasPreviousLink = false
|
|
case p.ElementTypes.List():
|
|
s.out.Write([]byte(JoinGophermapLines("i- ", WrapLines(e.Text(), s.maxLineLength - 2, " "), "\t/FAKE\tNULL\t0")))
|
|
s.wasPreviousLink = false
|
|
case p.ElementTypes.Quote():
|
|
s.out.Write([]byte(JoinGophermapLines("i> ", WrapLines(e.Text(), s.maxLineLength - 2, " "), "\t/FAKE\tNULL\t0")))
|
|
s.wasPreviousLink = false
|
|
case p.ElementTypes.PreformatToggle():
|
|
s.isInCodeBlock = !s.isInCodeBlock
|
|
s.wasPreviousLink = false
|
|
}
|
|
if e.Text() != "" {
|
|
s.out.Write([]byte("\n"))
|
|
}
|
|
}
|