Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renderer: add support for codespan #14

Merged
merged 1 commit into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package markdown

import (
"bytes"
"fmt"
"strings"

Expand Down Expand Up @@ -59,10 +60,10 @@ func (r *Renderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
// inlines
reg.Register(ast.KindText, r.renderText)
reg.Register(ast.KindLink, r.renderLink)
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
/* TODO
reg.Register(ast.KindString, r.renderString)
reg.Register(ast.KindAutoLink, r.renderAutoLink)
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
reg.Register(ast.KindEmphasis, r.renderEmphasis)
reg.Register(ast.KindImage, r.renderImage)
reg.Register(ast.KindRawHTML, r.renderRawHTML)
Expand Down Expand Up @@ -248,7 +249,13 @@ func (r *Renderer) renderListItem(w util.BufWriter, source []byte, node ast.Node
func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.Text)
if entering {
r.writer.Write(w, n.Text(source))
text := n.Text(source)

if r.rc.inCodeSpan {
text = bytes.ReplaceAll(text, []byte("\n"), []byte(" "))
}

r.writer.Write(w, text)
if n.SoftLineBreak() {
r.writer.WriteString(w, "\n")
}
Expand All @@ -272,11 +279,29 @@ func (r *Renderer) renderLink(w util.BufWriter, source []byte, node ast.Node, en
return ast.WalkContinue, nil
}

func (r *Renderer) renderCodeSpan(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if bytes.Count(node.Text(source), []byte("`"))%2 != 0 {
r.writer.WriteString(w, "``")
} else {
r.writer.WriteString(w, "`")
}

if entering {
r.rc.inCodeSpan = true
} else {
r.rc.inCodeSpan = false
}

return ast.WalkContinue, nil
}

type renderContext struct {
// listIndent is the current indentation level for List
listIndent int
// listMarker is the marker character used for the current list
listMarker byte
// inCodeSpan is true if inside a code span
inCodeSpan bool
}

// renderWriter wraps util.BufWriter methods to implement error handling.
Expand Down
123 changes: 123 additions & 0 deletions renderer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,129 @@ func TestRenderedOutput(t *testing.T) {
"\tfoo\n\tbar\n\tbaz",
" foo\n bar\n baz\n",
},
// Code Span
{
"Simple code span",
[]Option{},
"`foo`",
"`foo`\n",
},
{
"Two-backtick code span",
[]Option{},
"``foo ` bar``",
"``foo ` bar``\n",
},
{
"Code span stripping leading and trailing spaces",
[]Option{},
"` `` `",
"````\n",
},
{
"Code span stripping one space",
[]Option{},
"` `` `",
"` `` `\n",
},
{
"Unstrippable left space only",
[]Option{},
"` a`",
"` a`\n",
},
{
"Unstrippable only spaces",
[]Option{},
"` `\n` `",
"` `\n` `\n",
},
{
"Multiple line-endings treated as spaces",
[]Option{},
"``\nfoo\nbar \nbaz\n``",
"`foo bar baz`\n",
},
{
"Line-ending treated as space",
[]Option{},
"``\nfoo \n``",
"`foo `\n",
},
{
"Interior spaces are not collapsed",
[]Option{},
"`foo bar \nbaz`",
"`foo bar baz`\n",
},
{
"Backlashes are treated literally",
[]Option{},
"`foo\\`bar`",
"`foo\\`bar`\n",
},
{
"Two backticks act as delimiters",
[]Option{},
"``foo`bar``",
"``foo`bar``\n",
},
{
"Two backtics inside single ones with spaces trimmed",
[]Option{},
"` foo `` bar `",
"`foo `` bar`\n",
},
{
"Codespan backticks have precedence over emphasis",
[]Option{},
"*foo`*`",
"*foo`*`\n",
},
{
"Codespan backticks have equal precedence with HTML",
[]Option{},
"`<a href=\"`\">`",
"`<a href=\"`\">`\n",
},
// TODO: support KindRawHTML
// {
// "HTML tag with backtick",
// []Option{},
// "<a href=\"`\">`",
// "<a href=\"`\">`",
// },
{
"Autolink split by a backtick",
[]Option{},
"`<http://foo.bar.`baz>`",
"`<http://foo.bar.`baz>`\n",
},
// TODO: support KindAutoLink
// {
// "Autolink with a backtick",
// []Option{},
// "<http://foo.bar.`baz>`",
// "<http://foo.bar.`baz>`\n",
// },
{
"Unbalanced 3-2 backticks remain intact",
[]Option{},
"```foo``",
"```foo``\n",
},
{
"Unbalanced 1-0 backticks remain intact",
[]Option{},
"`foo",
"`foo\n",
},
{
"Unbalanced double backticks",
[]Option{},
"`foo``bar``",
"`foo`bar`\n",
},
// Paragraph
{
"Simple paragraph",
Expand Down