parse fences and paragraphs

This commit is contained in:
dre 2021-07-04 00:18:57 +08:00
parent d5b609b6ea
commit c779d963a0
2 changed files with 76 additions and 11 deletions

View file

@ -1,6 +1,7 @@
## md2gmi
Convert Markdown to Gemini Gemini "gemtext" markup with Go.
Convert Markdown to Gemini Gemini "gemtext" markup with Go. Working with streams and pipes for UNIX
like behavior utilizing Go channels.
### Usage

View file

@ -10,10 +10,13 @@ type stateFn func(*fsm, []byte) stateFn
// state machine
type fsm struct {
state stateFn
out io.Writer
quit chan struct{}
data <-chan []byte
state stateFn
buffer []byte
out io.Writer
quit chan struct{}
data <-chan []byte
pending []byte
}
func NewParser(data <-chan []byte, writer io.Writer, quit chan struct{}) *fsm {
@ -25,18 +28,51 @@ func NewParser(data <-chan []byte, writer io.Writer, quit chan struct{}) *fsm {
}
func (m *fsm) Parse() {
var buffer []byte
for m.state = initial; m.state != nil; {
var line []byte
for m.state = normal; m.state != nil; {
select {
case <-m.quit:
m.flush()
m.state = nil
case buffer = <-m.data:
m.state = m.state(m, buffer)
case line = <-m.data:
m.state = m.state(m, line)
}
}
}
func initial(m *fsm, data []byte) stateFn {
func (m *fsm) flush() {
if len(m.pending) > 0 {
fmt.Fprintf(m.out, string(m.pending)+"\n")
m.pending = m.pending[:0]
}
}
func normal(m *fsm, data []byte) stateFn {
m.flush()
// blank line
if len(data) == 0 {
fmt.Fprintf(m.out, "\n")
return normal
}
// header
if data[0] == '#' {
fmt.Fprintf(m.out, string(data)+"\n")
return normal
}
if len(data) >= 3 && string(data[0:3]) == "```" {
fmt.Fprintf(m.out, string(data)+"\n")
return fence
}
if len(data) >= 4 && string(data[0:4]) == " " {
fmt.Fprintf(m.out, string("```")+"\n")
fmt.Fprintf(m.out, string(data)+"\n")
m.pending = []byte("```")
return tofence
}
if data[len(data)-1] != '.' {
m.buffer = append(m.buffer, data...)
return paragraph
}
// TODO
// find linebreaks
// find code fences
@ -44,5 +80,33 @@ func initial(m *fsm, data []byte) stateFn {
// collapse lists
fmt.Fprintf(m.out, string(data)+"\n")
return initial
return normal
}
func fence(m *fsm, data []byte) stateFn {
fmt.Fprintf(m.out, string(data)+"\n")
if len(data) >= 3 && string(data[0:3]) == "```" {
return normal
}
return fence
}
func tofence(m *fsm, data []byte) stateFn {
if len(data) >= 4 && string(data[0:4]) == " " {
fmt.Fprintf(m.out, string(data)+"\n")
return tofence
}
fmt.Fprintf(m.out, string(data)+"\n")
return normal
}
func paragraph(m *fsm, data []byte) stateFn {
if len(data) == 0 || data[len(data)-1] == '.' {
m.buffer = append(m.buffer, data...)
fmt.Fprintf(m.out, string(m.buffer)+"\n")
m.buffer = m.buffer[:0]
return normal
}
m.buffer = append(m.buffer, data...)
return paragraph
}