diff --git a/README.md b/README.md index ce69417..06fa148 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/parser.go b/parser.go index cb4757a..bb2da29 100644 --- a/parser.go +++ b/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 }