diff options
Diffstat (limited to 'vendor/github.com/gomarkdown/markdown/parser')
7 files changed, 147 insertions, 94 deletions
diff --git a/vendor/github.com/gomarkdown/markdown/parser/aside.go b/vendor/github.com/gomarkdown/markdown/parser/aside.go index 96e25fe0..9d02ed04 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/aside.go +++ b/vendor/github.com/gomarkdown/markdown/parser/aside.go @@ -25,13 +25,13 @@ func (p *Parser) asidePrefix(data []byte) int { // aside ends with at least one blank line // followed by something without a aside prefix func (p *Parser) terminateAside(data []byte, beg, end int) bool { - if p.isEmpty(data[beg:]) <= 0 { + if IsEmpty(data[beg:]) <= 0 { return false } if end >= len(data) { return true } - return p.asidePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 + return p.asidePrefix(data[end:]) == 0 && IsEmpty(data[end:]) == 0 } // parse a aside fragment @@ -66,8 +66,8 @@ func (p *Parser) aside(data []byte) int { beg = end } - block := p.addBlock(&ast.Aside{}) - p.block(raw.Bytes()) - p.finalize(block) + block := p.AddBlock(&ast.Aside{}) + p.Block(raw.Bytes()) + p.Finalize(block) return end } diff --git a/vendor/github.com/gomarkdown/markdown/parser/block.go b/vendor/github.com/gomarkdown/markdown/parser/block.go index 490871c7..028ae758 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/block.go +++ b/vendor/github.com/gomarkdown/markdown/parser/block.go @@ -103,10 +103,10 @@ func sanitizeHeadingID(text string) string { return string(anchorName) } -// Parse block-level data. +// Parse Block-level data. // Note: this function and many that it calls assume that // the input buffer ends with a newline. -func (p *Parser) block(data []byte) { +func (p *Parser) Block(data []byte) { // this is called recursively: enforce a maximum depth if p.nesting >= p.maxNesting { return @@ -142,7 +142,7 @@ func (p *Parser) block(data []byte) { } } p.includeStack.Push(path) - p.block(included) + p.Block(included) p.includeStack.Pop() data = data[consumed:] continue @@ -156,10 +156,10 @@ func (p *Parser) block(data []byte) { data = data[consumed:] if node != nil { - p.addBlock(node) + p.AddBlock(node) if blockdata != nil { - p.block(blockdata) - p.finalize(node) + p.Block(blockdata) + p.Finalize(node) } } continue @@ -213,7 +213,7 @@ func (p *Parser) block(data []byte) { } // blank lines. note: returns the # of bytes to skip - if i := p.isEmpty(data); i > 0 { + if i := IsEmpty(data); i > 0 { data = data[i:] continue } @@ -255,11 +255,11 @@ func (p *Parser) block(data []byte) { // ****** // or // ______ - if p.isHRule(data) { + if isHRule(data) { i := skipUntilChar(data, 0, '\n') hr := ast.HorizontalRule{} hr.Literal = bytes.Trim(data[:i], " \n") - p.addBlock(&hr) + p.AddBlock(&hr) data = data[i:] continue } @@ -377,7 +377,7 @@ func (p *Parser) block(data []byte) { p.nesting-- } -func (p *Parser) addBlock(n ast.Node) ast.Node { +func (p *Parser) AddBlock(n ast.Node) ast.Node { p.closeUnmatchedBlocks() if p.attr != nil { @@ -448,7 +448,7 @@ func (p *Parser) prefixHeading(data []byte) int { p.allHeadingsWithAutoID = append(p.allHeadingsWithAutoID, block) } block.Content = data[i:end] - p.addBlock(block) + p.AddBlock(block) } return skip } @@ -521,7 +521,7 @@ func (p *Parser) prefixSpecialHeading(data []byte) int { } block.Literal = data[i:end] block.Content = data[i:end] - p.addBlock(block) + p.AddBlock(block) } return skip } @@ -572,7 +572,7 @@ func (p *Parser) titleBlock(data []byte, doRender bool) int { IsTitleblock: true, } block.Content = data - p.addBlock(block) + p.AddBlock(block) return consumed } @@ -617,14 +617,14 @@ func (p *Parser) html(data []byte, doRender bool) int { } // see if it is the only thing on the line - if skip := p.isEmpty(data[j:]); skip > 0 { + if skip := IsEmpty(data[j:]); skip > 0 { // see if it is followed by a blank line/eof j += skip if j >= len(data) { found = true i = j } else { - if skip := p.isEmpty(data[j:]); skip > 0 { + if skip := IsEmpty(data[j:]); skip > 0 { j += skip found = true i = j @@ -667,7 +667,7 @@ func (p *Parser) html(data []byte, doRender bool) int { // trim newlines end := backChar(data, i, '\n') htmlBLock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} - p.addBlock(htmlBLock) + p.AddBlock(htmlBLock) finalizeHTMLBlock(htmlBLock) } @@ -683,13 +683,13 @@ func finalizeHTMLBlock(block *ast.HTMLBlock) { func (p *Parser) htmlComment(data []byte, doRender bool) int { i := p.inlineHTMLComment(data) // needs to end with a blank line - if j := p.isEmpty(data[i:]); j > 0 { + if j := IsEmpty(data[i:]); j > 0 { size := i + j if doRender { // trim trailing newlines end := backChar(data, size, '\n') htmlBLock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} - p.addBlock(htmlBLock) + p.AddBlock(htmlBLock) finalizeHTMLBlock(htmlBLock) } return size @@ -715,13 +715,13 @@ func (p *Parser) htmlHr(data []byte, doRender bool) int { } if i < len(data) && data[i] == '>' { i++ - if j := p.isEmpty(data[i:]); j > 0 { + if j := IsEmpty(data[i:]); j > 0 { size := i + j if doRender { // trim newlines end := backChar(data, size, '\n') htmlBlock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} - p.addBlock(htmlBlock) + p.AddBlock(htmlBlock) finalizeHTMLBlock(htmlBlock) } return size @@ -753,7 +753,7 @@ func (p *Parser) htmlFindEnd(tag string, data []byte) int { // check that the rest of the line is blank skip := 0 - if skip = p.isEmpty(data[i:]); skip == 0 { + if skip = IsEmpty(data[i:]); skip == 0 { return 0 } i += skip @@ -766,7 +766,7 @@ func (p *Parser) htmlFindEnd(tag string, data []byte) int { if p.extensions&LaxHTMLBlocks != 0 { return i } - if skip = p.isEmpty(data[i:]); skip == 0 { + if skip = IsEmpty(data[i:]); skip == 0 { // following line must be blank return 0 } @@ -774,7 +774,7 @@ func (p *Parser) htmlFindEnd(tag string, data []byte) int { return i + skip } -func (*Parser) isEmpty(data []byte) int { +func IsEmpty(data []byte) int { // it is okay to call isEmpty on an empty buffer if len(data) == 0 { return 0 @@ -790,7 +790,7 @@ func (*Parser) isEmpty(data []byte) int { return i } -func (*Parser) isHRule(data []byte) bool { +func isHRule(data []byte) bool { i := 0 // skip up to three spaces @@ -976,7 +976,7 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int { codeBlock.Content = work.Bytes() // TODO: get rid of temp buffer if p.extensions&Mmark == 0 { - p.addBlock(codeBlock) + p.AddBlock(codeBlock) finalizeCodeBlock(codeBlock) return beg } @@ -988,12 +988,12 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int { figure.HeadingID = id p.Inline(caption, captionContent) - p.addBlock(figure) + p.AddBlock(figure) codeBlock.AsLeaf().Attribute = figure.AsContainer().Attribute p.addChild(codeBlock) finalizeCodeBlock(codeBlock) p.addChild(caption) - p.finalize(figure) + p.Finalize(figure) beg += consumed @@ -1001,7 +1001,7 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int { } // Still here, normal block - p.addBlock(codeBlock) + p.AddBlock(codeBlock) finalizeCodeBlock(codeBlock) } @@ -1055,13 +1055,13 @@ func (p *Parser) quotePrefix(data []byte) int { // blockquote ends with at least one blank line // followed by something without a blockquote prefix func (p *Parser) terminateBlockquote(data []byte, beg, end int) bool { - if p.isEmpty(data[beg:]) <= 0 { + if IsEmpty(data[beg:]) <= 0 { return false } if end >= len(data) { return true } - return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 + return p.quotePrefix(data[end:]) == 0 && IsEmpty(data[end:]) == 0 } // parse a blockquote fragment @@ -1096,9 +1096,9 @@ func (p *Parser) quote(data []byte) int { } if p.extensions&Mmark == 0 { - block := p.addBlock(&ast.BlockQuote{}) - p.block(raw.Bytes()) - p.finalize(block) + block := p.AddBlock(&ast.BlockQuote{}) + p.Block(raw.Bytes()) + p.Finalize(block) return end } @@ -1108,24 +1108,24 @@ func (p *Parser) quote(data []byte) int { figure.HeadingID = id p.Inline(caption, captionContent) - p.addBlock(figure) // this discard any attributes + p.AddBlock(figure) // this discard any attributes block := &ast.BlockQuote{} block.AsContainer().Attribute = figure.AsContainer().Attribute p.addChild(block) - p.block(raw.Bytes()) - p.finalize(block) + p.Block(raw.Bytes()) + p.Finalize(block) p.addChild(caption) - p.finalize(figure) + p.Finalize(figure) end += consumed return end } - block := p.addBlock(&ast.BlockQuote{}) - p.block(raw.Bytes()) - p.finalize(block) + block := p.AddBlock(&ast.BlockQuote{}) + p.Block(raw.Bytes()) + p.Finalize(block) return end } @@ -1152,7 +1152,7 @@ func (p *Parser) code(data []byte) int { i = skipUntilChar(data, i, '\n') i = skipCharN(data, i, '\n', 1) - blankline := p.isEmpty(data[beg:i]) > 0 + blankline := IsEmpty(data[beg:i]) > 0 if pre := p.codePrefix(data[beg:i]); pre > 0 { beg += pre } else if !blankline { @@ -1185,7 +1185,7 @@ func (p *Parser) code(data []byte) int { } // TODO: get rid of temp buffer codeBlock.Content = work.Bytes() - p.addBlock(codeBlock) + p.AddBlock(codeBlock) finalizeCodeBlock(codeBlock) return i @@ -1237,10 +1237,29 @@ func (p *Parser) dliPrefix(data []byte) int { if data[0] != ':' || !(data[1] == ' ' || data[1] == '\t') { return 0 } + // TODO: this is a no-op (data[0] is ':' so not ' '). + // Maybe the intent was to eat spaces before ':' ? + // either way, no change in tests i := skipChar(data, 0, ' ') return i + 2 } +// TODO: maybe it was meant to be like below +// either way, no change in tests +/* +func (p *Parser) dliPrefix(data []byte) int { + i := skipChar(data, 0, ' ') + if i+len(data) < 2 { + return 0 + } + // need a ':' followed by a space or a tab + if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') { + return 0 + } + return i + 2 +} +*/ + // parse ordered or unordered list block func (p *Parser) list(data []byte, flags ast.ListType, start int, delim byte) int { i := 0 @@ -1251,7 +1270,7 @@ func (p *Parser) list(data []byte, flags ast.ListType, start int, delim byte) in Start: start, Delimiter: delim, } - block := p.addBlock(list) + block := p.AddBlock(list) for i < len(data) { skip := p.listItem(data[i:], &flags) @@ -1398,7 +1417,7 @@ gatherlines: // if it is an empty line, guess that it is part of this item // and move on to the next line - if p.isEmpty(data[line:i]) > 0 { + if IsEmpty(data[line:i]) > 0 { containsBlankLine = true line = i continue @@ -1432,7 +1451,7 @@ gatherlines: // evaluate how this line fits in switch { // is this a nested list item? - case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) || p.oliPrefix(chunk) > 0 || p.dliPrefix(chunk) > 0: + case (p.uliPrefix(chunk) > 0 && !isHRule(chunk)) || p.oliPrefix(chunk) > 0 || p.dliPrefix(chunk) > 0: // if indent is 4 or more spaces on unordered or ordered lists // we need to add leadingWhiteSpaces + 1 spaces in the beginning of the chunk @@ -1484,10 +1503,7 @@ gatherlines: case containsBlankLine && indent < 4: if *flags&ast.ListTypeDefinition != 0 && i < len(data)-1 { // is the next item still a part of this list? - next := i - for next < len(data) && data[next] != '\n' { - next++ - } + next := skipUntilChar(data, i, '\n') for next < len(data)-1 && data[next] == '\n' { next++ } @@ -1526,16 +1542,16 @@ gatherlines: BulletChar: bulletChar, Delimiter: delimiter, } - p.addBlock(listItem) + p.AddBlock(listItem) // render the contents of the list item if *flags&ast.ListItemContainsBlock != 0 && *flags&ast.ListTypeTerm == 0 { // intermediate render of block item, except for definition term if sublist > 0 { - p.block(rawBytes[:sublist]) - p.block(rawBytes[sublist:]) + p.Block(rawBytes[:sublist]) + p.Block(rawBytes[sublist:]) } else { - p.block(rawBytes) + p.Block(rawBytes) } } else { // intermediate render of inline item @@ -1547,7 +1563,7 @@ gatherlines: } p.addChild(para) if sublist > 0 { - p.block(rawBytes[sublist:]) + p.Block(rawBytes[sublist:]) } } return line @@ -1574,7 +1590,7 @@ func (p *Parser) renderParagraph(data []byte) { } para := &ast.Paragraph{} para.Content = data[beg:end] - p.addBlock(para) + p.AddBlock(para) } // blockMath handle block surround with $$ @@ -1596,7 +1612,7 @@ func (p *Parser) blockMath(data []byte) int { // render the display math mathBlock := &ast.MathBlock{} mathBlock.Literal = data[2:end] - p.addBlock(mathBlock) + p.AddBlock(mathBlock) return end + 2 } @@ -1626,7 +1642,7 @@ func (p *Parser) paragraph(data []byte) int { } // did we find a blank line marking the end of the paragraph? - if n := p.isEmpty(current); n > 0 { + if n := IsEmpty(current); n > 0 { // did this blank line followed by a definition list item? if p.extensions&DefinitionLists != 0 { if i < len(data)-1 && data[i+1] == ':' { @@ -1663,7 +1679,7 @@ func (p *Parser) paragraph(data []byte) int { } block.Content = data[prev:eol] - p.addBlock(block) + p.AddBlock(block) // find the end of the underline return skipUntilChar(data, i, '\n') @@ -1680,7 +1696,7 @@ func (p *Parser) paragraph(data []byte) int { } // if there's a prefixed heading or a horizontal rule after this, paragraph is over - if p.isPrefixHeading(current) || p.isPrefixSpecialHeading(current) || p.isHRule(current) { + if p.isPrefixHeading(current) || p.isPrefixSpecialHeading(current) || isHRule(current) { p.renderParagraph(data[:i]) return i } diff --git a/vendor/github.com/gomarkdown/markdown/parser/block_table.go b/vendor/github.com/gomarkdown/markdown/parser/block_table.go index 0bf4f4ad..fa8efdf2 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/block_table.go +++ b/vendor/github.com/gomarkdown/markdown/parser/block_table.go @@ -12,7 +12,7 @@ func isBackslashEscaped(data []byte, i int) bool { } func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool) { - p.addBlock(&ast.TableRow{}) + p.AddBlock(&ast.TableRow{}) col := 0 i := skipChar(data, 0, '|') @@ -61,7 +61,7 @@ func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool // an empty cell that we should ignore, it exists because of colspan colspans-- } else { - p.addBlock(block) + p.AddBlock(block) } if colspan > 0 { @@ -75,7 +75,7 @@ func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool IsHeader: header, Align: columns[col], } - p.addBlock(block) + p.AddBlock(block) } // silently ignore rows with too many cells @@ -109,7 +109,7 @@ func (p *Parser) tableFooter(data []byte) bool { return false } - p.addBlock(&ast.TableFooter{}) + p.AddBlock(&ast.TableFooter{}) return true } @@ -217,7 +217,7 @@ func (p *Parser) tableHeader(data []byte, doRender bool) (size int, columns []as } // end of column test is messy switch { - case dashes < 3: + case dashes < 1: // not a valid column return @@ -253,9 +253,9 @@ func (p *Parser) tableHeader(data []byte, doRender bool) (size int, columns []as if doRender { table = &ast.Table{} - p.addBlock(table) + p.AddBlock(table) if header != nil { - p.addBlock(&ast.TableHeader{}) + p.AddBlock(&ast.TableHeader{}) p.tableRow(header, columns, true) } } @@ -277,7 +277,7 @@ func (p *Parser) table(data []byte) int { return 0 } - p.addBlock(&ast.TableBody{}) + p.AddBlock(&ast.TableBody{}) for i < len(data) { pipes, rowStart := 0, i @@ -319,7 +319,7 @@ func (p *Parser) table(data []byte) int { ast.AppendChild(figure, caption) p.addChild(figure) - p.finalize(figure) + p.Finalize(figure) i += consumed } diff --git a/vendor/github.com/gomarkdown/markdown/parser/caption.go b/vendor/github.com/gomarkdown/markdown/parser/caption.go index fe31711a..08794504 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/caption.go +++ b/vendor/github.com/gomarkdown/markdown/parser/caption.go @@ -11,7 +11,7 @@ func (p *Parser) caption(data, caption []byte) ([]byte, string, int) { } j := len(caption) data = data[j:] - end := p.linesUntilEmpty(data) + end := LinesUntilEmpty(data) data = data[:end] @@ -23,8 +23,8 @@ func (p *Parser) caption(data, caption []byte) ([]byte, string, int) { return data, "", end + j } -// linesUntilEmpty scans lines up to the first empty line. -func (p *Parser) linesUntilEmpty(data []byte) int { +// LinesUntilEmpty scans lines up to the first empty line. +func LinesUntilEmpty(data []byte) int { line, i := 0, 0 for line < len(data) { @@ -35,7 +35,7 @@ func (p *Parser) linesUntilEmpty(data []byte) int { i++ } - if p.isEmpty(data[line:i]) == 0 { + if IsEmpty(data[line:i]) == 0 { line = i continue } diff --git a/vendor/github.com/gomarkdown/markdown/parser/figures.go b/vendor/github.com/gomarkdown/markdown/parser/figures.go index 6615449c..0566c16e 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/figures.go +++ b/vendor/github.com/gomarkdown/markdown/parser/figures.go @@ -98,10 +98,10 @@ func (p *Parser) figureBlock(data []byte, doRender bool) int { } figure := &ast.CaptionFigure{} - p.addBlock(figure) - p.block(raw.Bytes()) + p.AddBlock(figure) + p.Block(raw.Bytes()) - defer p.finalize(figure) + defer p.Finalize(figure) if captionContent, id, consumed := p.caption(data[beg:], []byte("Figure: ")); consumed > 0 { caption := &ast.Caption{} @@ -113,7 +113,5 @@ func (p *Parser) figureBlock(data []byte, doRender bool) int { beg += consumed } - - p.finalize(figure) return beg } diff --git a/vendor/github.com/gomarkdown/markdown/parser/matter.go b/vendor/github.com/gomarkdown/markdown/parser/matter.go index 92686357..df284237 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/matter.go +++ b/vendor/github.com/gomarkdown/markdown/parser/matter.go @@ -29,8 +29,8 @@ func (p *Parser) documentMatter(data []byte) int { return 0 } node := &ast.DocumentMatter{Matter: matter} - p.addBlock(node) - p.finalize(node) + p.AddBlock(node) + p.Finalize(node) return consumed } diff --git a/vendor/github.com/gomarkdown/markdown/parser/parser.go b/vendor/github.com/gomarkdown/markdown/parser/parser.go index 07444cd8..91123e1b 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/parser.go +++ b/vendor/github.com/gomarkdown/markdown/parser/parser.go @@ -42,7 +42,7 @@ const ( SuperSubscript // Super- and subscript support: 2^10^, H~2~O. EmptyLinesBreakList // 2 empty lines break out of list Includes // Support including other files. - Mmark // Support Mmark syntax, see https://mmark.nl/syntax + Mmark // Support Mmark syntax, see https://mmark.miek.nl/post/syntax/ CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | Autolink | Strikethrough | SpaceHeadings | HeadingIDs | @@ -206,13 +206,13 @@ func (p *Parser) isFootnote(ref *reference) bool { return ok } -func (p *Parser) finalize(block ast.Node) { +func (p *Parser) Finalize(block ast.Node) { p.tip = block.GetParent() } func (p *Parser) addChild(node ast.Node) ast.Node { for !canNodeContain(p.tip, node) { - p.finalize(p.tip) + p.Finalize(p.tip) } ast.AppendChild(p.tip, node) p.tip = node @@ -239,6 +239,18 @@ func canNodeContain(n ast.Node, v ast.Node) bool { _, ok := v.(*ast.TableCell) return ok } + // for nodes implemented outside of ast package, allow them + // to implement this logic via CanContain interface + if o, ok := n.(ast.CanContain); ok { + return o.CanContain(v) + } + // for container nodes outside of ast package default to true + // because false is a bad default + typ := fmt.Sprintf("%T", n) + customNode := !strings.HasPrefix(typ, "*ast.") + if customNode { + return n.AsLeaf() == nil + } return false } @@ -248,7 +260,7 @@ func (p *Parser) closeUnmatchedBlocks() { } for p.oldTip != p.lastMatchedContainer { parent := p.oldTip.GetParent() - p.finalize(p.oldTip) + p.Finalize(p.oldTip) p.oldTip = parent } p.allClosed = true @@ -273,10 +285,14 @@ type Reference struct { // You can then convert AST to html using html.Renderer, to some other format // using a custom renderer or transform the tree. func (p *Parser) Parse(input []byte) ast.Node { - p.block(input) + // the code only works with Unix CR newlines so to make life easy for + // callers normalize newlines + input = NormalizeNewlines(input) + + p.Block(input) // Walk the tree and finish up some of unfinished blocks for p.tip != nil { - p.finalize(p.tip) + p.Finalize(p.tip) } // Walk the tree again and process inline markdown in each block ast.WalkFunc(p.Doc, func(node ast.Node, entering bool) ast.WalkStatus { @@ -322,8 +338,8 @@ func (p *Parser) parseRefsToAST() { IsFootnotesList: true, ListFlags: ast.ListTypeOrdered, } - p.addBlock(&ast.Footnotes{}) - block := p.addBlock(list) + p.AddBlock(&ast.Footnotes{}) + block := p.AddBlock(list) flags := ast.ListItemBeginningOfList // Note: this loop is intentionally explicit, not range-form. This is // because the body of the loop will append nested footnotes to p.notes and @@ -338,7 +354,7 @@ func (p *Parser) parseRefsToAST() { listItem.RefLink = ref.link if ref.hasBlock { flags |= ast.ListItemContainsBlock - p.block(ref.title) + p.Block(ref.title) } else { p.Inline(block, ref.title) } @@ -660,7 +676,7 @@ gatherLines: // if it is an empty line, guess that it is part of this item // and move on to the next line - if p.isEmpty(data[blockEnd:i]) > 0 { + if IsEmpty(data[blockEnd:i]) > 0 { containsBlankLine = true blockEnd = i continue @@ -883,3 +899,26 @@ func isListItem(d ast.Node) bool { _, ok := d.(*ast.ListItem) return ok } + +func NormalizeNewlines(d []byte) []byte { + wi := 0 + n := len(d) + for i := 0; i < n; i++ { + c := d[i] + // 13 is CR + if c != 13 { + d[wi] = c + wi++ + continue + } + // replace CR (mac / win) with LF (unix) + d[wi] = 10 + wi++ + if i < n-1 && d[i+1] == 10 { + // this was CRLF, so skip the LF + i++ + } + + } + return d[:wi] +} |