From 7819c0ad5c68636dd09610cf43a111846529a1cb Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Sat, 7 May 2022 22:27:17 +0100 Subject: [PATCH] renderer: add support for codespan --- renderer.go | 29 ++++++++++- renderer_test.go | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/renderer.go b/renderer.go index 9eeae6c..01e7aba 100644 --- a/renderer.go +++ b/renderer.go @@ -2,6 +2,7 @@ package markdown import ( + "bytes" "fmt" "strings" @@ -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) @@ -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") } @@ -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. diff --git a/renderer_test.go b/renderer_test.go index 1a3cd44..7963094 100644 --- a/renderer_test.go +++ b/renderer_test.go @@ -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{}, + "``", + "``\n", + }, + // TODO: support KindRawHTML + // { + // "HTML tag with backtick", + // []Option{}, + // "`", + // "`", + // }, + { + "Autolink split by a backtick", + []Option{}, + "``", + "``\n", + }, + // TODO: support KindAutoLink + // { + // "Autolink with a backtick", + // []Option{}, + // "`", + // "`\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",