From 86e8dd62f0b1c8adf14e9369b089d209317aaf2d Mon Sep 17 00:00:00 2001 From: Chase Adams Date: Mon, 20 Feb 2017 23:46:03 -0800 Subject: [PATCH] all: Add org-mode support Fixes #1483 See #936 --- docs/content/content/summaries.md | 6 +++--- docs/content/content/supported-formats.md | 2 +- helpers/content.go | 13 +++++++++++-- helpers/general.go | 2 ++ helpers/general_test.go | 1 + hugolib/handler_page.go | 10 ++++++++++ hugolib/page.go | 6 +++++- parser/frontmatter.go | 7 +++++++ parser/page.go | 16 +++++++++++++--- vendor/vendor.json | 6 ++++++ 10 files changed, 59 insertions(+), 10 deletions(-) diff --git a/docs/content/content/summaries.md b/docs/content/content/summaries.md index 0f2e6433b..1f65d431d 100644 --- a/docs/content/content/summaries.md +++ b/docs/content/content/summaries.md @@ -24,14 +24,14 @@ By default, Hugo automatically takes the first 70 words of your content as its s ## User-defined: manual summary split: -Alternatively, you may add the <!--more--> summary divider[^1] where you want to split the article. Content prior to the summary divider will be used as that content's summary, and stored into the `.Summary` variable with all HTML formatting intact. +Alternatively, you may add the <!--more--> summary divider[^1] (for org content, use # more) where you want to split the article. Content prior to the summary divider will be used as that content's summary, and stored into the `.Summary` variable with all HTML formatting intact. [^1]: The **summary divider** is also called "more tag", "excerpt separator", etc. in other literature. * Pros: Freedom, precision, and improved rendering. All formatting is preserved. -* Cons: Need to remember to type <!--more--> in your content file. :-) +* Cons: Need to remember to type <!--more--> (or # more for org content) in your content file. :-) -Be careful to enter <!--more--> exactly, i.e. all lowercase with no whitespace, otherwise it would be treated as regular comment and ignored. +Be careful to enter <!--more--> (or # more for org content) exactly, i.e. all lowercase with no whitespace, otherwise it would be treated as regular comment and ignored. If there is nothing but spaces and newlines after the summary divider then `.Truncated` will be false. diff --git a/docs/content/content/supported-formats.md b/docs/content/content/supported-formats.md index 68aa66acc..1b3033596 100644 --- a/docs/content/content/supported-formats.md +++ b/docs/content/content/supported-formats.md @@ -13,7 +13,7 @@ weight: 15 toc: true --- - Since 0.14, Hugo has defined a new concept called _external helpers_. It means that you can write your content using Asciidoc[tor], or reStructuredText. If you have files with associated extensions ([details](https://github.com/spf13/hugo/blob/77c60a3440806067109347d04eb5368b65ea0fe8/helpers/general.go#L65)), then Hugo will call external commands to generate the content. + Since 0.14, Hugo has defined a new concept called _external helpers_. It means that you can write your content using Asciidoc[tor], reStructuredText or Org-Mode. If you have files with associated extensions ([details](https://github.com/spf13/hugo/blob/77c60a3440806067109347d04eb5368b65ea0fe8/helpers/general.go#L65)), then Hugo will call external commands to generate the content (the exception being Org-Mode content, which is parsed natively). This means that you will have to install the associated tool on your machine to be able to use those formats. diff --git a/helpers/content.go b/helpers/content.go index 0eb687af6..7b529304d 100644 --- a/helpers/content.go +++ b/helpers/content.go @@ -24,12 +24,12 @@ import ( "unicode" "unicode/utf8" - "github.com/spf13/hugo/config" - + "github.com/chaseadamsio/goorgeous" "github.com/miekg/mmark" "github.com/mitchellh/mapstructure" "github.com/russross/blackfriday" bp "github.com/spf13/hugo/bufferpool" + "github.com/spf13/hugo/config" jww "github.com/spf13/jwalterweatherman" "strings" @@ -415,6 +415,8 @@ func (c ContentSpec) RenderBytes(ctx *RenderingContext) []byte { return c.mmarkRender(ctx) case "rst": return getRstContent(ctx) + case "org": + return orgRender(ctx, c) } } @@ -663,3 +665,10 @@ func getRstContent(ctx *RenderingContext) []byte { return result[bodyStart+7 : bodyEnd] } + +func orgRender(ctx *RenderingContext, c ContentSpec) []byte { + content := ctx.Content + cleanContent := bytes.Replace(content, []byte("# more"), []byte(""), 1) + return goorgeous.Org(cleanContent, + c.getHTMLRenderer(blackfriday.HTML_TOC, ctx)) +} diff --git a/helpers/general.go b/helpers/general.go index 91c25c04c..f9e67e72d 100644 --- a/helpers/general.go +++ b/helpers/general.go @@ -80,6 +80,8 @@ func GuessType(in string) string { return "rst" case "html", "htm": return "html" + case "org": + return "org" } return "unknown" diff --git a/helpers/general_test.go b/helpers/general_test.go index 8afdb59eb..3fa587e78 100644 --- a/helpers/general_test.go +++ b/helpers/general_test.go @@ -36,6 +36,7 @@ func TestGuessType(t *testing.T) { {"mmark", "mmark"}, {"html", "html"}, {"htm", "html"}, + {"org", "org"}, {"excel", "unknown"}, } { result := GuessType(this.in) diff --git a/hugolib/handler_page.go b/hugolib/handler_page.go index a47758f84..6439344b0 100644 --- a/hugolib/handler_page.go +++ b/hugolib/handler_page.go @@ -26,6 +26,7 @@ func init() { RegisterHandler(new(asciidocHandler)) RegisterHandler(new(rstHandler)) RegisterHandler(new(mmarkHandler)) + RegisterHandler(new(orgHandler)) } type basicPageHandler Handle @@ -110,6 +111,15 @@ func (h mmarkHandler) PageConvert(p *Page) HandledResult { return commonConvert(p) } +type orgHandler struct { + basicPageHandler +} + +func (h orgHandler) Extensions() []string { return []string{"org"} } +func (h orgHandler) PageConvert(p *Page) HandledResult { + return commonConvert(p) +} + func commonConvert(p *Page) HandledResult { if p.rendered { panic(fmt.Sprintf("Page %q already rendered, does not need conversion", p.BaseFileName())) diff --git a/hugolib/page.go b/hugolib/page.go index 23e11e5b4..07d073c9e 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -420,7 +420,11 @@ var ( // rendering engines. // TODO(bep) inline replace func (p *Page) replaceDivider(content []byte) []byte { - sections := bytes.Split(content, helpers.SummaryDivider) + summaryDivider := helpers.SummaryDivider + if p.Ext() == "org" { + summaryDivider = []byte("# more") + } + sections := bytes.Split(content, summaryDivider) // If the raw content has nothing but whitespace after the summary // marker then the page shouldn't be marked as truncated. This check diff --git a/parser/frontmatter.go b/parser/frontmatter.go index ed25c08e1..e57a593ab 100644 --- a/parser/frontmatter.go +++ b/parser/frontmatter.go @@ -19,6 +19,7 @@ import ( "errors" "strings" + "github.com/chaseadamsio/goorgeous" toml "github.com/pelletier/go-toml" "gopkg.in/yaml.v2" @@ -154,6 +155,8 @@ func DetectFrontMatter(mark rune) (f *frontmatterType) { return &frontmatterType{[]byte(TOMLDelim), []byte(TOMLDelim), HandleTOMLMetaData, false} case '{': return &frontmatterType{[]byte{'{'}, []byte{'}'}, HandleJSONMetaData, true} + case '#': + return &frontmatterType{[]byte("#+"), []byte("\n"), HandleOrgMetaData, false} default: return nil } @@ -189,3 +192,7 @@ func HandleJSONMetaData(datum []byte) (interface{}, error) { err := json.Unmarshal(datum, &f) return f, err } + +func HandleOrgMetaData(datum []byte) (interface{}, error) { + return goorgeous.OrgHeaders(datum) +} diff --git a/parser/page.go b/parser/page.go index 57b2d3045..3347380d7 100644 --- a/parser/page.go +++ b/parser/page.go @@ -21,6 +21,8 @@ import ( "regexp" "strings" "unicode" + + "github.com/chaseadamsio/goorgeous" ) const ( @@ -91,9 +93,11 @@ func (p *page) Metadata() (meta interface{}, err error) { if len(frontmatter) != 0 { fm := DetectFrontMatter(rune(frontmatter[0])) - meta, err = fm.Parse(frontmatter) - if err != nil { - return + if fm != nil { + meta, err = fm.Parse(frontmatter) + if err != nil { + return + } } } return @@ -129,6 +133,12 @@ func ReadFrom(r io.Reader) (p Page, err error) { return nil, err } newp.frontmatter = fm + } else if newp.render && goorgeous.IsKeyword(firstLine) { + fm, err := goorgeous.ExtractOrgHeaders(reader) + if err != nil { + return nil, err + } + newp.frontmatter = fm } content, err := extractContent(reader) diff --git a/vendor/vendor.json b/vendor/vendor.json index 95641d000..8749dee0d 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -32,6 +32,12 @@ "revision": "b896c45f5af983b1f416bdf3bb89c4f1f0926f69", "revisionTime": "2016-04-08T19:03:23Z" }, + { + "checksumSHA1": "RxIwAgjIuBpwde5BCZRLLK7VRG8=", + "path": "github.com/chaseadamsio/goorgeous", + "revision": "72a06e1b07db57f3931f5a9c00f3f04e636ad0a8", + "revisionTime": "2017-02-17T13:03:04Z" + }, { "checksumSHA1": "ntacCkWfMT63DaehXLG5FeXWyNM=", "path": "github.com/cpuguy83/go-md2man/md2man",