all: Add org-mode support

Fixes #1483 
See #936
This commit is contained in:
Chase Adams 2017-02-20 23:46:03 -08:00 committed by Bjørn Erik Pedersen
parent a3af4fe46e
commit 86e8dd62f0
10 changed files with 59 additions and 10 deletions

View file

@ -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 <code>&#60;&#33;&#45;&#45;more&#45;&#45;&#62;</code> 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 <code>&#60;&#33;&#45;&#45;more&#45;&#45;&#62;</code> summary divider[^1] (for org content, use <code># more</code>) 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 <code>&#60;&#33;&#45;&#45;more&#45;&#45;&#62;</code> in your content file. :-)
* Cons: Need to remember to type <code>&#60;&#33;&#45;&#45;more&#45;&#45;&#62;</code> (or <code># more</code> for org content) in your content file. :-)
Be careful to enter <code>&#60;&#33;&#45;&#45;more&#45;&#45;&#62;</code> exactly, i.e. all lowercase with no whitespace, otherwise it would be treated as regular comment and ignored.
Be careful to enter <code>&#60;&#33;&#45;&#45;more&#45;&#45;&#62;</code> (or <code># more</code> 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.

View file

@ -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.

View file

@ -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))
}

View file

@ -80,6 +80,8 @@ func GuessType(in string) string {
return "rst"
case "html", "htm":
return "html"
case "org":
return "org"
}
return "unknown"

View file

@ -36,6 +36,7 @@ func TestGuessType(t *testing.T) {
{"mmark", "mmark"},
{"html", "html"},
{"htm", "html"},
{"org", "org"},
{"excel", "unknown"},
} {
result := GuessType(this.in)

View file

@ -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()))

View file

@ -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

View file

@ -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)
}

View file

@ -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)

6
vendor/vendor.json vendored
View file

@ -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",