parse fences and paragraphs
This commit is contained in:
parent
d5b609b6ea
commit
c779d963a0
2 changed files with 76 additions and 11 deletions
|
@ -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
|
||||
|
||||
|
|
84
parser.go
84
parser.go
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue