readability
This commit is contained in:
parent
c279e77ef8
commit
ba528e13fc
5 changed files with 61 additions and 18 deletions
14
main.go
14
main.go
|
@ -46,7 +46,7 @@ func reader(in string) (io.Reader, error) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
file, err := os.Open(in)
|
file, err := os.Open(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("reader: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return file, nil
|
return file, nil
|
||||||
|
@ -59,7 +59,7 @@ func writer(out string) (io.Writer, error) {
|
||||||
if out != "" {
|
if out != "" {
|
||||||
file, err := os.Create(out)
|
file, err := os.Create(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("writer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return file, nil
|
return file, nil
|
||||||
|
@ -76,14 +76,17 @@ func source(r io.Reader) pipe.Source {
|
||||||
return func() chan pipe.StreamItem {
|
return func() chan pipe.StreamItem {
|
||||||
data := make(chan pipe.StreamItem)
|
data := make(chan pipe.StreamItem)
|
||||||
s := bufio.NewScanner(r)
|
s := bufio.NewScanner(r)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
for s.Scan() {
|
for s.Scan() {
|
||||||
data <- pipe.NewItem(i, s.Bytes())
|
data <- pipe.NewItem(i, s.Bytes())
|
||||||
i += 1
|
i++
|
||||||
}
|
}
|
||||||
close(data)
|
close(data)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,11 +118,8 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
preproc := NewPreproc()
|
|
||||||
|
|
||||||
//sink.Input(preproc.Process(source.Output()))
|
|
||||||
s := pipe.New()
|
s := pipe.New()
|
||||||
s.Use(preproc.Process)
|
s.Use(newPreproc().Process)
|
||||||
s.Use(RemoveFrontMatter)
|
s.Use(RemoveFrontMatter)
|
||||||
s.Use(RemoveComments)
|
s.Use(RemoveComments)
|
||||||
s.Use(FormatHeadings)
|
s.Use(FormatHeadings)
|
||||||
|
|
|
@ -12,12 +12,16 @@ type StreamItem struct {
|
||||||
|
|
||||||
func NewItem(index int, payload []byte) StreamItem {
|
func NewItem(index int, payload []byte) StreamItem {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
w := StreamItem{index: index}
|
w := StreamItem{index: index}
|
||||||
|
|
||||||
if err := gob.NewEncoder(&buf).Encode(payload); err != nil {
|
if err := gob.NewEncoder(&buf).Encode(payload); err != nil {
|
||||||
// assert no broken pipes
|
// assert no broken pipes
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.payload = buf.Bytes()
|
w.payload = buf.Bytes()
|
||||||
|
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +31,9 @@ func (w *StreamItem) Index() int {
|
||||||
|
|
||||||
func (w *StreamItem) Payload() []byte {
|
func (w *StreamItem) Payload() []byte {
|
||||||
var dec []byte
|
var dec []byte
|
||||||
|
|
||||||
buf := bytes.NewReader(w.payload)
|
buf := bytes.NewReader(w.payload)
|
||||||
|
|
||||||
if err := gob.NewDecoder(buf).Decode(&dec); err != nil {
|
if err := gob.NewDecoder(buf).Decode(&dec); err != nil {
|
||||||
// assert no broken pipes
|
// assert no broken pipes
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -26,6 +26,7 @@ func chain(nodes []Pipeline, src Connector) Connector {
|
||||||
for i := 1; i < len(nodes); i++ {
|
for i := 1; i < len(nodes); i++ {
|
||||||
c = nodes[i](c)
|
c = nodes[i](c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
preproc.go
31
preproc.go
|
@ -7,10 +7,10 @@ import (
|
||||||
"github.com/n0x1m/md2gmi/pipe"
|
"github.com/n0x1m/md2gmi/pipe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// state function
|
// state function.
|
||||||
type stateFn func(*fsm, []byte) stateFn
|
type stateFn func(*fsm, []byte) stateFn
|
||||||
|
|
||||||
// state machine
|
// state machine.
|
||||||
type fsm struct {
|
type fsm struct {
|
||||||
state stateFn
|
state stateFn
|
||||||
|
|
||||||
|
@ -24,12 +24,13 @@ type fsm struct {
|
||||||
pending []byte
|
pending []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPreproc() *fsm {
|
func newPreproc() *fsm {
|
||||||
return &fsm{}
|
return &fsm{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fsm) Process(in chan pipe.StreamItem) chan pipe.StreamItem {
|
func (m *fsm) Process(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
m.out = make(chan pipe.StreamItem)
|
m.out = make(chan pipe.StreamItem)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for m.state = normal; m.state != nil; {
|
for m.state = normal; m.state != nil; {
|
||||||
b, ok := <-in
|
b, ok := <-in
|
||||||
|
@ -38,6 +39,7 @@ func (m *fsm) Process(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
m.sync()
|
m.sync()
|
||||||
close(m.out)
|
close(m.out)
|
||||||
m.state = nil
|
m.state = nil
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +47,7 @@ func (m *fsm) Process(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
m.sync()
|
m.sync()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return m.out
|
return m.out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +56,7 @@ func (m *fsm) sync() {
|
||||||
m.sendBuffer = append(m.sendBuffer, '\n')
|
m.sendBuffer = append(m.sendBuffer, '\n')
|
||||||
m.out <- pipe.NewItem(m.i, m.sendBuffer)
|
m.out <- pipe.NewItem(m.i, m.sendBuffer)
|
||||||
m.sendBuffer = m.sendBuffer[:0]
|
m.sendBuffer = m.sendBuffer[:0]
|
||||||
m.i += 1
|
m.i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +87,7 @@ func handleList(data []byte) ([]byte, bool) {
|
||||||
if len(sub) > 1 {
|
if len(sub) > 1 {
|
||||||
return bytes.Replace(data, sub[1], []byte("-"), 1), true
|
return bytes.Replace(data, sub[1], []byte("-"), 1), true
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, false
|
return data, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,27 +103,34 @@ func normal(m *fsm, data []byte) stateFn {
|
||||||
if data, isList := handleList(data); isList {
|
if data, isList := handleList(data); isList {
|
||||||
m.blockBuffer = append(data, '\n')
|
m.blockBuffer = append(data, '\n')
|
||||||
m.blockFlush()
|
m.blockFlush()
|
||||||
|
|
||||||
return normal
|
return normal
|
||||||
}
|
}
|
||||||
|
|
||||||
if isFence(data) {
|
if isFence(data) {
|
||||||
m.blockBuffer = append(data, '\n')
|
m.blockBuffer = append(data, '\n')
|
||||||
|
|
||||||
return fence
|
return fence
|
||||||
}
|
}
|
||||||
|
|
||||||
if needsFence(data) {
|
if needsFence(data) {
|
||||||
m.blockBuffer = append(m.blockBuffer, []byte("```\n")...)
|
m.blockBuffer = append(m.blockBuffer, []byte("```\n")...)
|
||||||
m.blockBuffer = append(m.blockBuffer, append(data[4:], '\n')...)
|
m.blockBuffer = append(m.blockBuffer, append(data[4:], '\n')...)
|
||||||
m.pending = []byte("```\n")
|
m.pending = []byte("```\n")
|
||||||
|
|
||||||
return toFence
|
return toFence
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTerminated(data) {
|
if isTerminated(data) {
|
||||||
m.blockBuffer = append(m.blockBuffer, data...)
|
m.blockBuffer = append(m.blockBuffer, data...)
|
||||||
m.blockBuffer = append(m.blockBuffer, ' ')
|
m.blockBuffer = append(m.blockBuffer, ' ')
|
||||||
|
|
||||||
return paragraph
|
return paragraph
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
// collapse lists
|
|
||||||
m.blockBuffer = append(m.blockBuffer, append(data, '\n')...)
|
m.blockBuffer = append(m.blockBuffer, append(data, '\n')...)
|
||||||
m.blockFlush()
|
m.blockFlush()
|
||||||
|
|
||||||
return normal
|
return normal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,18 +139,23 @@ func fence(m *fsm, data []byte) stateFn {
|
||||||
// second fence returns to normal
|
// second fence returns to normal
|
||||||
if isFence(data) {
|
if isFence(data) {
|
||||||
m.blockFlush()
|
m.blockFlush()
|
||||||
|
|
||||||
return normal
|
return normal
|
||||||
}
|
}
|
||||||
|
|
||||||
return fence
|
return fence
|
||||||
}
|
}
|
||||||
|
|
||||||
func toFence(m *fsm, data []byte) stateFn {
|
func toFence(m *fsm, data []byte) stateFn {
|
||||||
if needsFence(data) {
|
if needsFence(data) {
|
||||||
m.blockBuffer = append(m.blockBuffer, append(data[4:], '\n')...)
|
m.blockBuffer = append(m.blockBuffer, append(data[4:], '\n')...)
|
||||||
|
|
||||||
return toFence
|
return toFence
|
||||||
}
|
}
|
||||||
|
|
||||||
m.blockFlush()
|
m.blockFlush()
|
||||||
m.blockBuffer = append(m.blockBuffer, append(data, '\n')...)
|
m.blockBuffer = append(m.blockBuffer, append(data, '\n')...)
|
||||||
|
|
||||||
return normal
|
return normal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,9 +165,12 @@ func paragraph(m *fsm, data []byte) stateFn {
|
||||||
m.blockBuffer = bytes.TrimSpace(m.blockBuffer)
|
m.blockBuffer = bytes.TrimSpace(m.blockBuffer)
|
||||||
m.blockBuffer = append(m.blockBuffer, '\n')
|
m.blockBuffer = append(m.blockBuffer, '\n')
|
||||||
m.blockFlush()
|
m.blockFlush()
|
||||||
|
|
||||||
return normal
|
return normal
|
||||||
}
|
}
|
||||||
|
|
||||||
m.blockBuffer = append(m.blockBuffer, data...)
|
m.blockBuffer = append(m.blockBuffer, data...)
|
||||||
m.blockBuffer = append(m.blockBuffer, []byte(" ")...)
|
m.blockBuffer = append(m.blockBuffer, []byte(" ")...)
|
||||||
|
|
||||||
return paragraph
|
return paragraph
|
||||||
}
|
}
|
||||||
|
|
27
proc.go
27
proc.go
|
@ -10,28 +10,36 @@ import (
|
||||||
|
|
||||||
func FormatLinks(in chan pipe.StreamItem) chan pipe.StreamItem {
|
func FormatLinks(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
out := make(chan pipe.StreamItem)
|
out := make(chan pipe.StreamItem)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
fenceOn := false
|
fenceOn := false
|
||||||
|
|
||||||
for b := range in {
|
for b := range in {
|
||||||
data := b.Payload()
|
data := b.Payload()
|
||||||
if isFence(data) {
|
if isFence(data) {
|
||||||
fenceOn = !fenceOn
|
fenceOn = !fenceOn
|
||||||
}
|
}
|
||||||
|
|
||||||
if fenceOn {
|
if fenceOn {
|
||||||
out <- pipe.NewItem(b.Index(), b.Payload())
|
out <- pipe.NewItem(b.Index(), b.Payload())
|
||||||
} else {
|
|
||||||
out <- pipe.NewItem(b.Index(), formatLinks(b.Payload()))
|
continue
|
||||||
}
|
}
|
||||||
|
out <- pipe.NewItem(b.Index(), formatLinks(b.Payload()))
|
||||||
}
|
}
|
||||||
|
|
||||||
close(out)
|
close(out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatLinks(data []byte) []byte {
|
func formatLinks(data []byte) []byte {
|
||||||
// find link name and url
|
// find link name and url
|
||||||
var buffer []byte
|
var buffer []byte
|
||||||
|
|
||||||
re := regexp.MustCompile(`!?\[([^\]*]*)\]\(([^)]*)\)`)
|
re := regexp.MustCompile(`!?\[([^\]*]*)\]\(([^)]*)\)`)
|
||||||
|
|
||||||
for i, match := range re.FindAllSubmatch(data, -1) {
|
for i, match := range re.FindAllSubmatch(data, -1) {
|
||||||
replaceWithIndex := append(match[1], fmt.Sprintf("[%d]", i+1)...)
|
replaceWithIndex := append(match[1], fmt.Sprintf("[%d]", i+1)...)
|
||||||
data = bytes.Replace(data, match[0], replaceWithIndex, 1)
|
data = bytes.Replace(data, match[0], replaceWithIndex, 1)
|
||||||
|
@ -50,43 +58,51 @@ func formatLinks(data []byte) []byte {
|
||||||
|
|
||||||
func RemoveComments(in chan pipe.StreamItem) chan pipe.StreamItem {
|
func RemoveComments(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
out := make(chan pipe.StreamItem)
|
out := make(chan pipe.StreamItem)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
re := regexp.MustCompile(`<!--.*-->`)
|
re := regexp.MustCompile(`<!--.*-->`)
|
||||||
|
|
||||||
for b := range in {
|
for b := range in {
|
||||||
data := b.Payload()
|
data := b.Payload()
|
||||||
for _, match := range re.FindAllSubmatch(data, -1) {
|
for _, match := range re.FindAllSubmatch(data, -1) {
|
||||||
data = bytes.Replace(data, match[0], []byte(""), 1)
|
data = bytes.Replace(data, match[0], []byte(""), 1)
|
||||||
}
|
}
|
||||||
out <- pipe.NewItem(b.Index(), append(bytes.TrimSpace(data), '\n'))
|
out <- pipe.NewItem(b.Index(), append(bytes.TrimSpace(data), '\n'))
|
||||||
//out <- pipe.NewItem(b.Index(), data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(out)
|
close(out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveFrontMatter(in chan pipe.StreamItem) chan pipe.StreamItem {
|
func RemoveFrontMatter(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
out := make(chan pipe.StreamItem)
|
out := make(chan pipe.StreamItem)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
re := regexp.MustCompile(`---.*---`)
|
re := regexp.MustCompile(`---.*---`)
|
||||||
|
|
||||||
for b := range in {
|
for b := range in {
|
||||||
data := b.Payload()
|
data := b.Payload()
|
||||||
for _, match := range re.FindAllSubmatch(data, -1) {
|
for _, match := range re.FindAllSubmatch(data, -1) {
|
||||||
data = bytes.Replace(data, match[0], []byte(""), 1)
|
data = bytes.Replace(data, match[0], []byte(""), 1)
|
||||||
}
|
}
|
||||||
out <- pipe.NewItem(b.Index(), append(bytes.TrimSpace(data), '\n'))
|
out <- pipe.NewItem(b.Index(), append(bytes.TrimSpace(data), '\n'))
|
||||||
//out <- pipe.NewItem(b.Index(), data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(out)
|
close(out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatHeadings(in chan pipe.StreamItem) chan pipe.StreamItem {
|
func FormatHeadings(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
out := make(chan pipe.StreamItem)
|
out := make(chan pipe.StreamItem)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
re := regexp.MustCompile(`^[#]{4,}`)
|
re := regexp.MustCompile(`^[#]{4,}`)
|
||||||
re2 := regexp.MustCompile(`^(#+)[^# ]`)
|
re2 := regexp.MustCompile(`^(#+)[^# ]`)
|
||||||
|
|
||||||
for b := range in {
|
for b := range in {
|
||||||
// fix up more than 4 levels
|
// fix up more than 4 levels
|
||||||
data := re.ReplaceAll(b.Payload(), []byte("###"))
|
data := re.ReplaceAll(b.Payload(), []byte("###"))
|
||||||
|
@ -101,9 +117,10 @@ func FormatHeadings(in chan pipe.StreamItem) chan pipe.StreamItem {
|
||||||
}
|
}
|
||||||
// writeback
|
// writeback
|
||||||
out <- pipe.NewItem(b.Index(), data)
|
out <- pipe.NewItem(b.Index(), data)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(out)
|
close(out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue