aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/rsc.io/markdown/para.go
blob: 30e60a98ec4d0cd34b01c6bd9e66b4c0779e5794 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package markdown

import (
	"bytes"
	"strings"
)

type Empty struct {
	Position
}

func (b *Empty) PrintHTML(buf *bytes.Buffer) {}

func (b *Empty) printMarkdown(*bytes.Buffer, mdState) {}

type Paragraph struct {
	Position
	Text *Text
}

func (b *Paragraph) PrintHTML(buf *bytes.Buffer) {
	buf.WriteString("<p>")
	b.Text.PrintHTML(buf)
	buf.WriteString("</p>\n")
}

func (b *Paragraph) printMarkdown(buf *bytes.Buffer, s mdState) {
	// // Ignore prefix when in a list.
	// if s.bullet == 0 {
	// 	buf.WriteString(s.prefix)
	// }
	b.Text.printMarkdown(buf, s)
}

type paraBuilder struct {
	text  []string
	table *tableBuilder
}

func (b *paraBuilder) extend(p *parseState, s line) (line, bool) {
	return s, false
}

func (b *paraBuilder) build(p buildState) Block {
	if b.table != nil {
		return b.table.build(p)
	}

	s := strings.Join(b.text, "\n")
	for s != "" {
		end, ok := parseLinkRefDef(p, s)
		if !ok {
			break
		}
		s = s[skipSpace(s, end):]
	}

	if s == "" {
		return &Empty{p.pos()}
	}

	// Recompute EndLine because a line of b.text
	// might have been taken away to start a table.
	pos := p.pos()
	pos.EndLine = pos.StartLine + len(b.text) - 1
	return &Paragraph{
		pos,
		p.newText(pos, s),
	}
}

func newPara(p *parseState, s line) (line, bool) {
	// Process paragraph continuation text or start new paragraph.
	b := p.para()
	indented := p.lineDepth == len(p.stack)-2 // fully indented, not playing "pargraph continuation text" games
	text := s.trimSpaceString()

	if b != nil && b.table != nil {
		if indented && text != "" && text != "|" {
			// Continue table.
			b.table.addRow(text)
			return line{}, true
		}
		// Blank or unindented line ends table.
		// (So does a new block structure, but the caller has checked that already.)
		// So does a line with just a pipe:
		// https://github.com/github/cmark-gfm/pull/127 and
		// https://github.com/github/cmark-gfm/pull/128
		// fixed a buffer overread by rejecting | by itself as a table line.
		// That seems to violate the spec, but we will play along.
		b = nil
	}

	// If we are looking for tables and this is a table start, start a table.
	if p.Table && b != nil && indented && len(b.text) > 0 && isTableStart(b.text[len(b.text)-1], text) {
		hdr := b.text[len(b.text)-1]
		b.text = b.text[:len(b.text)-1]
		tb := new(paraBuilder)
		p.addBlock(tb)
		tb.table = new(tableBuilder)
		tb.table.start(hdr, text)
		return line{}, true
	}

	if b != nil {
		for i := p.lineDepth; i < len(p.stack); i++ {
			p.stack[i].pos.EndLine = p.lineno
		}
	} else {
		// Note: Ends anything without a matching prefix.
		b = new(paraBuilder)
		p.addBlock(b)
	}
	b.text = append(b.text, text)
	return line{}, true
}