diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-01-02 12:33:26 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-03-23 18:51:22 +0100 |
commit | 597e418cb02883418f2cebb41400e8e61413f651 (patch) | |
tree | 177ad9c540b2583b6dab138c9f0490d28989c7f7 /hugolib/page_content.go | |
parent | 44f5c1c14cb1f42cc5f01739c289e9cfc83602af (diff) |
Make Page an interface
The main motivation of this commit is to add a `page.Page` interface to replace the very file-oriented `hugolib.Page` struct.
This is all a preparation step for issue #5074, "pages from other data sources".
But this also fixes a set of annoying limitations, especially related to custom output formats, and shortcodes.
Most notable changes:
* The inner content of shortcodes using the `{{%` as the outer-most delimiter will now be sent to the content renderer, e.g. Blackfriday.
This means that any markdown will partake in the global ToC and footnote context etc.
* The Custom Output formats are now "fully virtualized". This removes many of the current limitations.
* The taxonomy list type now has a reference to the `Page` object.
This improves the taxonomy template `.Title` situation and make common template constructs much simpler.
See #5074
Fixes #5763
Fixes #5758
Fixes #5090
Fixes #5204
Fixes #4695
Fixes #5607
Fixes #5707
Fixes #5719
Fixes #3113
Fixes #5706
Fixes #5767
Fixes #5723
Fixes #5769
Fixes #5770
Fixes #5771
Fixes #5759
Fixes #5776
Fixes #5777
Fixes #5778
Diffstat (limited to 'hugolib/page_content.go')
-rw-r--r-- | hugolib/page_content.go | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/hugolib/page_content.go b/hugolib/page_content.go deleted file mode 100644 index 924400aea..000000000 --- a/hugolib/page_content.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2018 The Hugo Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package hugolib - -import ( - "bytes" - "io" - - "github.com/gohugoio/hugo/helpers" - - errors "github.com/pkg/errors" - - bp "github.com/gohugoio/hugo/bufferpool" - - "github.com/gohugoio/hugo/common/herrors" - "github.com/gohugoio/hugo/common/text" - "github.com/gohugoio/hugo/parser/metadecoders" - "github.com/gohugoio/hugo/parser/pageparser" -) - -var ( - internalSummaryDividerBase = "HUGOMORE42" - internalSummaryDividerBaseBytes = []byte(internalSummaryDividerBase) - internalSummaryDividerPre = []byte("\n\n" + internalSummaryDividerBase + "\n\n") -) - -// The content related items on a Page. -type pageContent struct { - renderable bool - - // workContent is a copy of rawContent that may be mutated during site build. - workContent []byte - - shortcodeState *shortcodeHandler - - source rawPageContent -} - -type rawPageContent struct { - hasSummaryDivider bool - - // The AST of the parsed page. Contains information about: - // shortcodes, front matter, summary indicators. - parsed pageparser.Result - - // Returns the position in bytes after any front matter. - posMainContent int -} - -// TODO(bep) lazy consolidate -func (p *Page) mapContent() error { - p.shortcodeState = newShortcodeHandler(p) - s := p.shortcodeState - p.renderable = true - p.source.posMainContent = -1 - - result := bp.GetBuffer() - defer bp.PutBuffer(result) - - iter := p.source.parsed.Iterator() - - fail := func(err error, i pageparser.Item) error { - return p.parseError(err, iter.Input(), i.Pos) - } - - // the parser is guaranteed to return items in proper order or fail, so … - // … it's safe to keep some "global" state - var currShortcode shortcode - var ordinal int - -Loop: - for { - it := iter.Next() - - switch { - case it.Type == pageparser.TypeIgnore: - case it.Type == pageparser.TypeHTMLStart: - // This is HTML without front matter. It can still have shortcodes. - p.renderable = false - result.Write(it.Val) - case it.IsFrontMatter(): - f := metadecoders.FormatFromFrontMatterType(it.Type) - m, err := metadecoders.Default.UnmarshalToMap(it.Val, f) - if err != nil { - if fe, ok := err.(herrors.FileError); ok { - return herrors.ToFileErrorWithOffset(fe, iter.LineNumber()-1) - } else { - return err - } - } - if err := p.updateMetaData(m); err != nil { - return err - } - - next := iter.Peek() - if !next.IsDone() { - p.source.posMainContent = next.Pos - } - - if !p.shouldBuild() { - // Nothing more to do. - return nil - } - - case it.Type == pageparser.TypeLeadSummaryDivider: - result.Write(internalSummaryDividerPre) - p.source.hasSummaryDivider = true - // Need to determine if the page is truncated. - f := func(item pageparser.Item) bool { - if item.IsNonWhitespace() { - p.truncated = true - - // Done - return false - } - return true - } - iter.PeekWalk(f) - - // Handle shortcode - case it.IsLeftShortcodeDelim(): - // let extractShortcode handle left delim (will do so recursively) - iter.Backup() - - currShortcode, err := s.extractShortcode(ordinal, iter, p) - - if currShortcode.name != "" { - s.nameSet[currShortcode.name] = true - } - - if err != nil { - return fail(errors.Wrap(err, "failed to extract shortcode"), it) - } - - if currShortcode.params == nil { - currShortcode.params = make([]string, 0) - } - - placeHolder := s.createShortcodePlaceholder() - result.WriteString(placeHolder) - ordinal++ - s.shortcodes.Add(placeHolder, currShortcode) - case it.Type == pageparser.TypeEmoji: - if emoji := helpers.Emoji(it.ValStr()); emoji != nil { - result.Write(emoji) - } else { - result.Write(it.Val) - } - case it.IsEOF(): - break Loop - case it.IsError(): - err := fail(errors.WithStack(errors.New(it.ValStr())), it) - currShortcode.err = err - return err - - default: - result.Write(it.Val) - } - } - - resultBytes := make([]byte, result.Len()) - copy(resultBytes, result.Bytes()) - p.workContent = resultBytes - - return nil -} - -func (p *Page) parse(reader io.Reader) error { - - parseResult, err := pageparser.Parse( - reader, - pageparser.Config{EnableEmoji: p.s.Cfg.GetBool("enableEmoji")}, - ) - if err != nil { - return err - } - - p.source = rawPageContent{ - parsed: parseResult, - } - - p.lang = p.File.Lang() - - if p.s != nil && p.s.owner != nil { - gi, enabled := p.s.owner.gitInfo.forPage(p) - if gi != nil { - p.GitInfo = gi - } else if enabled { - p.s.Log.INFO.Printf("Failed to find GitInfo for page %q", p.Path()) - } - } - - return nil -} - -func (p *Page) parseError(err error, input []byte, offset int) error { - if herrors.UnwrapFileError(err) != nil { - // Use the most specific location. - return err - } - pos := p.posFromInput(input, offset) - return herrors.NewFileError("md", -1, pos.LineNumber, pos.ColumnNumber, err) - -} - -func (p *Page) posFromInput(input []byte, offset int) text.Position { - lf := []byte("\n") - input = input[:offset] - lineNumber := bytes.Count(input, lf) + 1 - endOfLastLine := bytes.LastIndex(input, lf) - - return text.Position{ - Filename: p.pathOrTitle(), - LineNumber: lineNumber, - ColumnNumber: offset - endOfLastLine, - Offset: offset, - } -} - -func (p *Page) posFromPage(offset int) text.Position { - return p.posFromInput(p.source.parsed.Input(), offset) -} |