💾 Archived View for anachronauts.club › cgi-bin › repos › cgi › gmikit.git › tree › trunk › gmi.go captured on 2021-12-05 at 23:47:19. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

gmikit.git

git @ anachronauts.club

summary

tree

log

refs

gmikit.git/gmi.go | 3 KB

view raw

  1 package gmikit
  2 
  3 import (
  4 	"bufio"
  5 	"fmt"
  6 	"io"
  7 	"net/url"
  8 	"strings"
  9 )
 10 
 11 type Visitor interface {
 12 	Begin() error
 13 	End() error
 14 	Text(text string) error
 15 	Link(target *url.URL, friendlyName string) error
 16 	PreformattingToggle(altText string) error
 17 	PreformattedText(text string) error
 18 	Heading1(text string) error
 19 	Heading2(text string) error
 20 	Heading3(text string) error
 21 	UnorderedListItem(text string) error
 22 	Quote(text string) error
 23 }
 24 
 25 func ParseLines(r io.Reader, v Visitor) error {
 26 	const ws = " \t"
 27 	pre := false
 28 	scanner := bufio.NewScanner(r)
 29 	if err := v.Begin(); err != nil {
 30 		return err
 31 	}
 32 	for scanner.Scan() {
 33 		text := scanner.Text()
 34 		if strings.HasPrefix(text, "```") {
 35 			pre = !pre
 36 			if err := v.PreformattingToggle(text[3:]); err != nil {
 37 				return err
 38 			}
 39 		} else if pre {
 40 			if err := v.PreformattedText(text); err != nil {
 41 				return err
 42 			}
 43 		} else if strings.HasPrefix(text, "=>") {
 44 			text = text[2:]
 45 			text = strings.TrimLeft(text, ws)
 46 			split := strings.IndexAny(text, ws)
 47 			if split == -1 {
 48 				url, err := url.Parse(text)
 49 				if err != nil {
 50 					return err
 51 				}
 52 
 53 				if err = v.Link(url, ""); err != nil {
 54 					return err
 55 				}
 56 			} else {
 57 				url, err := url.Parse(text[:split])
 58 				if err != nil {
 59 					return err
 60 				}
 61 
 62 				name := strings.TrimLeft(text[split:], ws)
 63 				if err = v.Link(url, name); err != nil {
 64 					return err
 65 				}
 66 			}
 67 		} else if strings.HasPrefix(text, "*") {
 68 			text = strings.TrimLeft(text[1:], ws)
 69 			if err := v.UnorderedListItem(text); err != nil {
 70 				return err
 71 			}
 72 		} else if strings.HasPrefix(text, "###") {
 73 			text = strings.TrimLeft(text[3:], ws)
 74 			if err := v.Heading3(text); err != nil {
 75 				return err
 76 			}
 77 		} else if strings.HasPrefix(text, "##") {
 78 			text = strings.TrimLeft(text[2:], ws)
 79 			if err := v.Heading2(text); err != nil {
 80 				return err
 81 			}
 82 		} else if strings.HasPrefix(text, "#") {
 83 			text = strings.TrimLeft(text[1:], ws)
 84 			if err := v.Heading1(text); err != nil {
 85 				return err
 86 			}
 87 		} else if strings.HasPrefix(text, ">") {
 88 			text = strings.TrimLeft(text[1:], ws)
 89 			if err := v.Quote(text); err != nil {
 90 				return err
 91 			}
 92 		} else {
 93 			if err := v.Text(text); err != nil {
 94 				return err
 95 			}
 96 		}
 97 	}
 98 	if err := v.End(); err != nil {
 99 		return err
100 	}
101 
102 	return scanner.Err()
103 }
104 
105 type GmiWriter struct {
106 	w   io.Writer
107 	pre bool
108 }
109 
110 func NewGmiWriter(w io.Writer) *GmiWriter {
111 	return &GmiWriter{w: w, pre: false}
112 }
113 
114 func (g *GmiWriter) Begin() error { return nil }
115 func (g *GmiWriter) End() error   { return nil }
116 
117 func (g *GmiWriter) Text(text string) error {
118 	_, err := fmt.Fprintf(g.w, "%s\n", text)
119 	return err
120 }
121 
122 func (g *GmiWriter) Link(target *url.URL, friendlyName string) error {
123 	if friendlyName == "" {
124 		_, err := fmt.Fprintf(g.w, "=> %s\n", target)
125 		return err
126 	} else {
127 		_, err := fmt.Fprintf(g.w, "=> %s %s\n", target, friendlyName)
128 		return err
129 	}
130 }
131 
132 func (g *GmiWriter) PreformattingToggle(altText string) error {
133 	if g.pre {
134 		g.pre = false
135 		_, err := fmt.Fprintf(g.w, "```\n")
136 		return err
137 	} else {
138 		g.pre = true
139 		_, err := fmt.Fprintf(g.w, "```%s\n", altText)
140 		return err
141 	}
142 }
143 
144 func (g *GmiWriter) PreformattedText(text string) error {
145 	_, err := fmt.Fprintf(g.w, "%s\n", text)
146 	return err
147 }
148 
149 func (g *GmiWriter) Heading1(text string) error {
150 	_, err := fmt.Fprintf(g.w, "# %s\n", text)
151 	return err
152 }
153 
154 func (g *GmiWriter) Heading2(text string) error {
155 	_, err := fmt.Fprintf(g.w, "## %s\n", text)
156 	return err
157 }
158 
159 func (g *GmiWriter) Heading3(text string) error {
160 	_, err := fmt.Fprintf(g.w, "### %s\n", text)
161 	return err
162 }
163 
164 func (g *GmiWriter) UnorderedListItem(text string) error {
165 	_, err := fmt.Fprintf(g.w, "* %s\n", text)
166 	return err
167 }
168 
169 func (g *GmiWriter) Quote(text string) error {
170 	_, err := fmt.Fprintf(g.w, "> %s\n", text)
171 	return err
172 }
173 
174 func NormalizeGmi(r io.Reader, w io.Writer) error {
175 	return ParseLines(r, NewGmiWriter(w))
176 }