fencedCodeBlock returns the end index if data contains a fenced code block at the beginning, or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects. If doRender is true, a final newline is mandatory to recognize the fenced code block.
(data []byte, doRender bool)
| 667 | // or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects. |
| 668 | // If doRender is true, a final newline is mandatory to recognize the fenced code block. |
| 669 | func (p *Markdown) fencedCodeBlock(data []byte, doRender bool) int { |
| 670 | var info string |
| 671 | beg, marker := isFenceLine(data, &info, "") |
| 672 | if beg == 0 || beg >= len(data) { |
| 673 | return 0 |
| 674 | } |
| 675 | fenceLength := beg - 1 |
| 676 | |
| 677 | var work bytes.Buffer |
| 678 | work.Write([]byte(info)) |
| 679 | work.WriteByte('\n') |
| 680 | |
| 681 | for { |
| 682 | // safe to assume beg < len(data) |
| 683 | |
| 684 | // check for the end of the code block |
| 685 | fenceEnd, _ := isFenceLine(data[beg:], nil, marker) |
| 686 | if fenceEnd != 0 { |
| 687 | beg += fenceEnd |
| 688 | break |
| 689 | } |
| 690 | |
| 691 | // copy the current line |
| 692 | end := skipUntilChar(data, beg, '\n') + 1 |
| 693 | |
| 694 | // did we reach the end of the buffer without a closing marker? |
| 695 | if end >= len(data) { |
| 696 | return 0 |
| 697 | } |
| 698 | |
| 699 | // verbatim copy to the working buffer |
| 700 | if doRender { |
| 701 | work.Write(data[beg:end]) |
| 702 | } |
| 703 | beg = end |
| 704 | } |
| 705 | |
| 706 | if doRender { |
| 707 | block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer |
| 708 | block.IsFenced = true |
| 709 | block.FenceLength = fenceLength |
| 710 | finalizeCodeBlock(block) |
| 711 | } |
| 712 | |
| 713 | return beg |
| 714 | } |
| 715 | |
| 716 | func unescapeChar(str []byte) []byte { |
| 717 | if str[0] == '\\' { |
no test coverage detected