diff --git a/go.mod b/go.mod index e1bbd9ac89d73..02f0c46f22e1c 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( github.com/blevesearch/go-porterstemmer v0.0.0-20141230013033-23a2c8e5cf1f // indirect github.com/blevesearch/segment v0.0.0-20160105220820-db70c57796cc // indirect github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 // indirect - github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f github.com/couchbase/vellum v0.0.0-20190111184608-e91b68ff3efe // indirect github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect @@ -73,6 +72,7 @@ require ( github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 + github.com/niklasfasching/go-org v0.1.7 github.com/oliamb/cutter v0.2.2 github.com/philhofer/fwd v1.0.0 // indirect github.com/pkg/errors v0.8.1 @@ -80,12 +80,13 @@ require ( github.com/prometheus/client_golang v1.1.0 github.com/prometheus/procfs v0.0.4 // indirect github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect - github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff + github.com/russross/blackfriday v2.0.0+incompatible // indirect + github.com/russross/blackfriday/v2 v2.0.1 github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/satori/go.uuid v1.2.0 github.com/sergi/go-diff v1.0.0 github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect - github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect github.com/stretchr/testify v1.4.0 @@ -100,7 +101,7 @@ require ( github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad - golang.org/x/net v0.0.0-20190909003024-a7b16738d86b + golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b golang.org/x/text v0.3.2 diff --git a/go.sum b/go.sum index 2eeaa79810c0f..7445469d7ed94 100644 --- a/go.sum +++ b/go.sum @@ -86,8 +86,6 @@ github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26/go.mod h1:paBWMc github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f h1:REH9VH5ubNR0skLaOxK7TRJeRbE2dDfvaouQo8FsRcA= -github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f/go.mod h1:6QaC0vFoKWYDth94dHFNgRT2YkT5FHdQp/Yx15aAAi0= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs= @@ -425,6 +423,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niklasfasching/go-org v0.1.6 h1:F521WcqRNl8OJumlgAnekZgERaTA2HpfOYYfVEKOeI8= +github.com/niklasfasching/go-org v0.1.6/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU= +github.com/niklasfasching/go-org v0.1.7 h1:t3V+3XnS/7BhKv/7SlMUa8FvAiq577/a1T3D7mLIRXE= +github.com/niklasfasching/go-org v0.1.7/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU= @@ -487,8 +489,10 @@ github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qq github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff h1:g9ZlAHmkc/h5So+OjNCkZWh+FjuKEOOOoyRkqlGA8+c= -github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk= +github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -499,6 +503,8 @@ github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnP github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1:3wIrJvFb3Pf6B/2mDBnN1G5IfUVev4X5apadQlWOczE= github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= @@ -650,6 +656,8 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc= golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= +golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 91ef320b40927..07747e97e1174 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -323,6 +323,6 @@ func TestRender_ShortLinks(t *testing.T) { `
`) test( "", - ``, - ``) + ``, + ``) } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index d9fc768891f11..ff78d7ea3a8e4 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -7,13 +7,14 @@ package markdown import ( "bytes" + "io" "strings" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/russross/blackfriday" + "github.com/russross/blackfriday/v2" ) // Renderer is a extended version of underlying render object. @@ -25,134 +26,138 @@ type Renderer struct { var byteMailto = []byte("mailto:") -// Link defines how formal links should be processed to produce corresponding HTML elements. -func (r *Renderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { - // special case: this is not a link, a hash link or a mailto:, so it's a - // relative URL - if len(link) > 0 && !markup.IsLink(link) && - link[0] != '#' && !bytes.HasPrefix(link, byteMailto) { - lnk := string(link) - if r.IsWiki { - lnk = util.URLJoin("wiki", lnk) - } - mLink := util.URLJoin(r.URLPrefix, lnk) - link = []byte(mLink) - } - - if len(content) > 10 && string(content[0:9]) == "': []byte(">"), + '"': []byte("""), } -// List renders markdown bullet or digit lists to HTML -func (r *Renderer) List(out *bytes.Buffer, text func() bool, flags int) { - marker := out.Len() - if out.Len() > 0 { - out.WriteByte('\n') - } - - if flags&blackfriday.LIST_TYPE_DEFINITION != 0 { - out.WriteString("")) { - prefix = "
" - } - switch { - case bytes.HasPrefix(text, []byte(prefix+"[ ] ")): - text = append([]byte(``), text[3+len(prefix):]...) - if prefix != "" { - text = bytes.Replace(text, []byte(prefix), []byte{}, 1) +// RenderNode is a default renderer of a single node of a syntax tree. For +// block nodes it will be called twice: first time with entering=true, second +// time with entering=false, so that it could know when it's working on an open +// tag and when on close. It writes the result to w. +// +// The return value is a way to tell the calling walker to adjust its walk +// pattern: e.g. it can terminate the traversal by returning Terminate. Or it +// can ask the walker to skip a subtree of this node by returning SkipChildren. +// The typical behavior is to return GoToNext, which asks for the usual +// traversal to the next node. +func (r *Renderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + switch node.Type { + case blackfriday.Image: + prefix := r.URLPrefix + if r.IsWiki { + prefix = util.URLJoin(prefix, "wiki", "raw") } - case bytes.HasPrefix(text, []byte(prefix+"[x] ")): - text = append([]byte(``), text[3+len(prefix):]...) - if prefix != "" { - text = bytes.Replace(text, []byte(prefix), []byte{}, 1) + prefix = strings.Replace(prefix, "/src/", "/media/", 1) + link := node.LinkData.Destination + if len(link) > 0 && !markup.IsLink(link) { + lnk := string(link) + lnk = util.URLJoin(prefix, lnk) + lnk = strings.Replace(lnk, " ", "+", -1) + link = []byte(lnk) + } + node.LinkData.Destination = link + // Render link around image only if parent is not link already + if node.Parent != nil && node.Parent.Type != blackfriday.Link { + if entering { + _, _ = w.Write([]byte(``)) + return r.Renderer.RenderNode(w, node, entering) + } + s := r.Renderer.RenderNode(w, node, entering) + _, _ = w.Write([]byte(``)) + return s + } + return r.Renderer.RenderNode(w, node, entering) + case blackfriday.Link: + // special case: this is not a link, a hash link or a mailto:, so it's a + // relative URL + link := node.LinkData.Destination + if len(link) > 0 && !markup.IsLink(link) && + link[0] != '#' && !bytes.HasPrefix(link, byteMailto) && + node.LinkData.Footnote == nil { + lnk := string(link) + if r.IsWiki { + lnk = util.URLJoin("wiki", lnk) + } + link = []byte(util.URLJoin(r.URLPrefix, lnk)) + } + node.LinkData.Destination = link + return r.Renderer.RenderNode(w, node, entering) + case blackfriday.Text: + isListItem := false + for n := node.Parent; n != nil; n = n.Parent { + if n.Type == blackfriday.Item { + isListItem = true + break + } + } + if isListItem { + text := node.Literal + switch { + case bytes.HasPrefix(text, []byte("[ ] ")): + _, _ = w.Write([]byte(``)) + text = text[3:] + case bytes.HasPrefix(text, []byte("[x] ")): + _, _ = w.Write([]byte(``)) + text = text[3:] + } + node.Literal = text } } - r.Renderer.ListItem(out, text, flags) -} - -// Image defines how images should be processed to produce corresponding HTML elements. -func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { - prefix := r.URLPrefix - if r.IsWiki { - prefix = util.URLJoin(prefix, "wiki", "raw") - } - prefix = strings.Replace(prefix, "/src/", "/media/", 1) - if len(link) > 0 && !markup.IsLink(link) { - lnk := string(link) - lnk = util.URLJoin(prefix, lnk) - lnk = strings.Replace(lnk, " ", "+", -1) - link = []byte(lnk) - } - - // Put a link around it pointing to itself by default - out.WriteString(``) - r.Renderer.Image(out, link, title, alt) - out.WriteString("") + return r.Renderer.RenderNode(w, node, entering) } const ( blackfridayExtensions = 0 | - blackfriday.EXTENSION_NO_INTRA_EMPHASIS | - blackfriday.EXTENSION_TABLES | - blackfriday.EXTENSION_FENCED_CODE | - blackfriday.EXTENSION_STRIKETHROUGH | - blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK | - blackfriday.EXTENSION_DEFINITION_LISTS | - blackfriday.EXTENSION_FOOTNOTES | - blackfriday.EXTENSION_HEADER_IDS | - blackfriday.EXTENSION_AUTO_HEADER_IDS + blackfriday.NoIntraEmphasis | + blackfriday.Tables | + blackfriday.FencedCode | + blackfriday.Strikethrough | + blackfriday.NoEmptyLineBeforeBlock | + blackfriday.DefinitionLists | + blackfriday.Footnotes | + blackfriday.HeadingIDs | + blackfriday.AutoHeadingIDs blackfridayHTMLFlags = 0 | - blackfriday.HTML_SKIP_STYLE | - blackfriday.HTML_OMIT_CONTENTS | - blackfriday.HTML_USE_SMARTYPANTS + blackfriday.Smartypants ) // RenderRaw renders Markdown to HTML without handling special links. func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte { renderer := &Renderer{ - Renderer: blackfriday.HtmlRenderer(blackfridayHTMLFlags, "", ""), + Renderer: blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ + Flags: blackfridayHTMLFlags, + }), URLPrefix: urlPrefix, IsWiki: wikiMarkdown, } exts := blackfridayExtensions if setting.Markdown.EnableHardLineBreak { - exts |= blackfriday.EXTENSION_HARD_LINE_BREAK + exts |= blackfriday.HardLineBreak } - body = blackfriday.Markdown(body, renderer, exts) + body = blackfriday.Run(body, blackfriday.WithRenderer(renderer), blackfriday.WithExtensions(exts)) return markup.SanitizeBytes(body) } diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 669b49367ee0a..b29f870ce5268 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -166,13 +166,13 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
Here is a simple footnote,1 and here is a longer one.2
+Here is one with multiple paragraphs and code.
@@ -180,9 +180,9 @@ func testAnswers(baseURLContent, baseURLImages string) []string {{ my code }
Add as many paragraphs as you like.
-Add as many paragraphs as you like.
\nWikiPage\n
") } func TestRender_Images(t *testing.T) { @@ -45,10 +45,8 @@ func TestRender_Images(t *testing.T) { } url := "../../.images/src/02/train.jpg" - title := "Train" result := util.URLJoin(AppSubURL, url) - test( - "[[file:"+url+"]["+title+"]]", - ``) + test("[[file:"+url+"]]", + "\n\n
") } diff --git a/vendor/github.com/chaseadamsio/goorgeous/.gitignore b/vendor/github.com/chaseadamsio/goorgeous/.gitignore deleted file mode 100644 index 496ee2ca6a2f0..0000000000000 --- a/vendor/github.com/chaseadamsio/goorgeous/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.DS_Store \ No newline at end of file diff --git a/vendor/github.com/chaseadamsio/goorgeous/.travis.yml b/vendor/github.com/chaseadamsio/goorgeous/.travis.yml deleted file mode 100644 index 31dca02817e7c..0000000000000 --- a/vendor/github.com/chaseadamsio/goorgeous/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go - -go: - - 1.7 - -before_install: - - go get golang.org/x/tools/cmd/cover - - go get github.com/mattn/goveralls - -script: - - go test -v -covermode=count -coverprofile=coverage.out - - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci diff --git a/vendor/github.com/chaseadamsio/goorgeous/README.org b/vendor/github.com/chaseadamsio/goorgeous/README.org deleted file mode 100644 index 37e0f2ec730db..0000000000000 --- a/vendor/github.com/chaseadamsio/goorgeous/README.org +++ /dev/null @@ -1,66 +0,0 @@ -#+TITLE: chaseadamsio/goorgeous - -[[https://travis-ci.org/chaseadamsio/goorgeous.svg?branch=master]] -[[https://coveralls.io/repos/github/chaseadamsio/goorgeous/badge.svg?branch=master]] - -/goorgeous is a Go Org to HTML Parser./ - -[[file:gopher_small.gif]] - -*Pronounced: Go? Org? Yes!* - -#+BEGIN_QUOTE -"Org mode is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system." - -- [[orgmode.org]] -#+END_QUOTE - -The purpose of this package is to come as close as possible as parsing an =*.org= document into HTML, the same way one might publish [[http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html][with org-publish-html from Emacs]]. - -* Installation - -#+BEGIN_SRC sh - go get -u github.com/chaseadamsio/goorgeous -#+END_SRC - -* Usage - -** Org Headers - -To retrieve the headers from a =[]byte=, call =OrgHeaders= and it will return a =map[string]interface{}=: - -#+BEGIN_SRC go - input := "#+title: goorgeous\n* Some Headline\n" - out := goorgeous.OrgHeaders(input) -#+END_SRC - -#+BEGIN_SRC go - map[string]interface{}{ - "title": "goorgeous" - } -#+END_SRC - -** Org Content - -After importing =github.com/chaseadamsio/goorgeous=, you can call =Org= with a =[]byte= and it will return an =html= version of the content as a =[]byte= - -#+BEGIN_SRC go - input := "#+TITLE: goorgeous\n* Some Headline\n" - out := goorgeous.Org(input) -#+END_SRC - -=out= will be: - -#+BEGIN_SRC html -\n")) - p.inline(&tmpBuf, data) - tmpBuf.WriteByte('\n') - tmpBuf.Write([]byte("
\n")) - tmpBlock.Write(tmpBuf.Bytes()) - - } else { - tmpBlock.WriteByte('\n') - tmpBlock.Write(data) - } - - } else { - marker = string(matches[2]) - syntax = string(matches[3]) - } - case isFootnoteDef(data): - matches := reFootnoteDef.FindSubmatch(data) - for i := range p.notes { - if p.notes[i].id == string(matches[1]) { - p.notes[i].def = string(matches[2]) - } - } - case isTable(data): - if inTable != true { - inTable = true - } - tmpBlock.Write(data) - tmpBlock.WriteByte('\n') - case IsKeyword(data): - continue - case isComment(data): - p.generateComment(&output, data) - case isHeadline(data): - p.generateHeadline(&output, data) - case isDefinitionList(data): - if inList != true { - listType = "dl" - inList = true - } - var work bytes.Buffer - flags := blackfriday.LIST_TYPE_DEFINITION - matches := reDefinitionList.FindSubmatch(data) - flags |= blackfriday.LIST_TYPE_TERM - p.inline(&work, matches[1]) - p.r.ListItem(&tmpBlock, work.Bytes(), flags) - work.Reset() - flags &= ^blackfriday.LIST_TYPE_TERM - p.inline(&work, matches[2]) - p.r.ListItem(&tmpBlock, work.Bytes(), flags) - case isUnorderedList(data): - if inList != true { - listType = "ul" - inList = true - } - matches := reUnorderedList.FindSubmatch(data) - var work bytes.Buffer - p.inline(&work, matches[2]) - p.r.ListItem(&tmpBlock, work.Bytes(), 0) - case isOrderedList(data): - if inList != true { - listType = "ol" - inList = true - } - matches := reOrderedList.FindSubmatch(data) - var work bytes.Buffer - tmpBlock.WriteString("\n") - inFixedWidthArea = true - } - matches := reExampleLine.FindSubmatch(data) - tmpBlock.Write(matches[1]) - tmpBlock.WriteString("\n") - break - default: - if inParagraph == false { - inParagraph = true - if inFixedWidthArea == true { - if tmpBlock.Len() > 0 { - tmpBlock.WriteString("") - output.Write(tmpBlock.Bytes()) - } - inFixedWidthArea = false - tmpBlock.Reset() - } - } - tmpBlock.Write(data) - tmpBlock.WriteByte('\n') - } - } - - if len(tmpBlock.Bytes()) > 0 { - if inParagraph == true { - p.generateParagraph(&output, tmpBlock.Bytes()[:len(tmpBlock.Bytes())-1]) - } else if inFixedWidthArea == true { - tmpBlock.WriteString("\n") - output.Write(tmpBlock.Bytes()) - } - } - - // Writing footnote def. list - if len(p.notes) > 0 { - flags := blackfriday.LIST_ITEM_BEGINNING_OF_LIST - p.r.Footnotes(&output, func() bool { - for i := range p.notes { - p.r.FootnoteItem(&output, []byte(p.notes[i].id), []byte(p.notes[i].def), flags) - } - return true - }) - } - - return output.Bytes() -} - -// Org Syntax has been broken up into 4 distinct sections based on -// the org-syntax draft (http://orgmode.org/worg/dev/org-syntax.html): -// - Headlines -// - Greater Elements -// - Elements -// - Objects - -// Headlines -func isHeadline(data []byte) bool { - if !charMatches(data[0], '*') { - return false - } - level := 0 - for level < 6 && charMatches(data[level], '*') { - level++ - } - return charMatches(data[level], ' ') -} - -func (p *parser) generateHeadline(out *bytes.Buffer, data []byte) { - level := 1 - status := "" - priority := "" - - for level < 6 && data[level] == '*' { - level++ - } - - start := skipChar(data, level, ' ') - - data = data[start:] - i := 0 - - // Check if has a status so it can be rendered as a separate span that can be hidden or - // modified with CSS classes - if hasStatus(data[i:4]) { - status = string(data[i:4]) - i += 5 // one extra character for the next whitespace - } - - // Check if the next byte is a priority marker - if data[i] == '[' && hasPriority(data[i+1]) { - priority = string(data[i+1]) - i += 4 // for "[c]" + ' ' - } - - tags, tagsFound := findTags(data, i) - - headlineID := sanitized_anchor_name.Create(string(data[i:])) - - generate := func() bool { - dataEnd := len(data) - if tagsFound > 0 { - dataEnd = tagsFound - } - - headline := bytes.TrimRight(data[i:dataEnd], " \t") - - if status != "" { - out.WriteString("" + status + "") - out.WriteByte(' ') - } - - if priority != "" { - out.WriteString("[" + priority + "]") - out.WriteByte(' ') - } - - p.inline(out, headline) - - if tagsFound > 0 { - for _, tag := range tags { - out.WriteByte(' ') - out.WriteString(" ") - out.WriteByte(' ') - } - } - return true - } - - p.r.Header(out, generate, level, headlineID) -} - -func hasStatus(data []byte) bool { - return bytes.Contains(data, []byte("TODO")) || bytes.Contains(data, []byte("DONE")) -} - -func hasPriority(char byte) bool { - return (charMatches(char, 'A') || charMatches(char, 'B') || charMatches(char, 'C')) -} - -func findTags(data []byte, start int) ([]string, int) { - tags := []string{} - tagOpener := 0 - tagMarker := tagOpener - for tIdx := start; tIdx < len(data); tIdx++ { - if tagMarker > 0 && data[tIdx] == ':' { - tags = append(tags, string(data[tagMarker+1:tIdx])) - tagMarker = tIdx - } - if data[tIdx] == ':' && tagOpener == 0 && data[tIdx-1] == ' ' { - tagMarker = tIdx - tagOpener = tIdx - } - } - return tags, tagOpener -} - -// Greater Elements -// ~~ Definition Lists -var reDefinitionList = regexp.MustCompile(`^\s*-\s+(.+?)\s+::\s+(.*)`) - -func isDefinitionList(data []byte) bool { - return reDefinitionList.Match(data) -} - -// ~~ Example lines -var reExampleLine = regexp.MustCompile(`^\s*:\s(\s*.*)|^\s*:$`) - -func isExampleLine(data []byte) bool { - return reExampleLine.Match(data) -} - -// ~~ Ordered Lists -var reOrderedList = regexp.MustCompile(`^(\s*)\d+\.\s+\[?@?(\d*)\]?(.+)`) - -func isOrderedList(data []byte) bool { - return reOrderedList.Match(data) -} - -// ~~ Unordered Lists -var reUnorderedList = regexp.MustCompile(`^(\s*)[-\+]\s+(.+)`) - -func isUnorderedList(data []byte) bool { - return reUnorderedList.Match(data) -} - -// ~~ Tables -var reTableHeaders = regexp.MustCompile(`^[|+-]*$`) - -func isTable(data []byte) bool { - return charMatches(data[0], '|') -} - -func (p *parser) generateTable(output *bytes.Buffer, data []byte) { - var table bytes.Buffer - rows := bytes.Split(bytes.Trim(data, "\n"), []byte("\n")) - hasTableHeaders := len(rows) > 1 - if len(rows) > 1 { - hasTableHeaders = reTableHeaders.Match(rows[1]) - } - tbodySet := false - - for idx, row := range rows { - var rowBuff bytes.Buffer - if hasTableHeaders && idx == 0 { - table.WriteString("") - for _, cell := range bytes.Split(row[1:len(row)-1], []byte("|")) { - p.r.TableHeaderCell(&rowBuff, bytes.Trim(cell, " \t"), 0) - } - p.r.TableRow(&table, rowBuff.Bytes()) - table.WriteString("\n") - } else if hasTableHeaders && idx == 1 { - continue - } else { - if !tbodySet { - table.WriteString("") - tbodySet = true - } - if !reTableHeaders.Match(row) { - for _, cell := range bytes.Split(row[1:len(row)-1], []byte("|")) { - var cellBuff bytes.Buffer - p.inline(&cellBuff, bytes.Trim(cell, " \t")) - p.r.TableCell(&rowBuff, cellBuff.Bytes(), 0) - } - p.r.TableRow(&table, rowBuff.Bytes()) - } - if tbodySet && idx == len(rows)-1 { - table.WriteString("\n") - tbodySet = false - } - } - } - - output.WriteString("\n
", "
"},
+ "=": []string{``, "
"},
+ "_": []string{``, ""},
+ "_{}": []string{"", ""},
+ "^{}": []string{"", ""},
+}
+
+var listTags = map[string][]string{
+ "unordered": []string{"\n%s\n
\n` + "\n" + content + "\n\n") + case name == "EXPORT" && len(b.Parameters) >= 1 && strings.ToLower(b.Parameters[0]) == "html": + w.WriteString(content + "\n") + case name == "QUOTE": + w.WriteString("
\n" + content + "\n") + case name == "CENTER": + w.WriteString(`
[%s]
`, s.Content))
+}
+
+func (w *HTMLWriter) WriteLineBreak(l LineBreak) {
+ w.WriteString(strings.Repeat("\n", l.Count))
+}
+
+func (w *HTMLWriter) WriteExplicitLineBreak(l ExplicitLineBreak) {
+ w.WriteString("") + if _, ok := p.Children[0].(LineBreak); !ok { + w.WriteString("\n") + } + WriteNodes(w, p.Children...) + w.WriteString("\n
\n") +} + +func (w *HTMLWriter) WriteExample(e Example) { + w.WriteString(`` + "\n") + if len(e.Children) != 0 { + for _, n := range e.Children { + WriteNodes(w, n) + w.WriteString("\n") + } + } + w.WriteString("\n") +} + +func (w *HTMLWriter) WriteHorizontalRule(h HorizontalRule) { + w.WriteString("