page__content.go (3449B)
1 // Copyright 2019 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package hugolib
15
16 import (
17 "fmt"
18
19 "github.com/gohugoio/hugo/output"
20 "github.com/gohugoio/hugo/parser/pageparser"
21 )
22
23 var (
24 internalSummaryDividerBase = "HUGOMORE42"
25 internalSummaryDividerBaseBytes = []byte(internalSummaryDividerBase)
26 internalSummaryDividerPre = []byte("\n\n" + internalSummaryDividerBase + "\n\n")
27 )
28
29 // The content related items on a Page.
30 type pageContent struct {
31 selfLayout string
32 truncated bool
33
34 cmap *pageContentMap
35
36 source rawPageContent
37 }
38
39 // returns the content to be processed by Goldmark or similar.
40 func (p pageContent) contentToRender(parsed pageparser.Result, pm *pageContentMap, renderedShortcodes map[string]string) []byte {
41 source := parsed.Input()
42
43 c := make([]byte, 0, len(source)+(len(source)/10))
44
45 for _, it := range pm.items {
46 switch v := it.(type) {
47 case pageparser.Item:
48 c = append(c, source[v.Pos:v.Pos+len(v.Val)]...)
49 case pageContentReplacement:
50 c = append(c, v.val...)
51 case *shortcode:
52 if !v.insertPlaceholder() {
53 // Insert the rendered shortcode.
54 renderedShortcode, found := renderedShortcodes[v.placeholder]
55 if !found {
56 // This should never happen.
57 panic(fmt.Sprintf("rendered shortcode %q not found", v.placeholder))
58 }
59
60 c = append(c, []byte(renderedShortcode)...)
61
62 } else {
63 // Insert the placeholder so we can insert the content after
64 // markdown processing.
65 c = append(c, []byte(v.placeholder)...)
66 }
67 default:
68 panic(fmt.Sprintf("unknown item type %T", it))
69 }
70 }
71
72 return c
73 }
74
75 func (p pageContent) selfLayoutForOutput(f output.Format) string {
76 if p.selfLayout == "" {
77 return ""
78 }
79 return p.selfLayout + f.Name
80 }
81
82 type rawPageContent struct {
83 hasSummaryDivider bool
84
85 // The AST of the parsed page. Contains information about:
86 // shortcodes, front matter, summary indicators.
87 parsed pageparser.Result
88
89 // Returns the position in bytes after any front matter.
90 posMainContent int
91
92 // These are set if we're able to determine this from the source.
93 posSummaryEnd int
94 posBodyStart int
95 }
96
97 type pageContentReplacement struct {
98 val []byte
99
100 source pageparser.Item
101 }
102
103 type pageContentMap struct {
104
105 // If not, we can skip any pre-rendering of shortcodes.
106 hasMarkdownShortcode bool
107
108 // Indicates whether we must do placeholder replacements.
109 hasNonMarkdownShortcode bool
110
111 // *shortcode, pageContentReplacement or pageparser.Item
112 items []any
113 }
114
115 func (p *pageContentMap) AddBytes(item pageparser.Item) {
116 p.items = append(p.items, item)
117 }
118
119 func (p *pageContentMap) AddReplacement(val []byte, source pageparser.Item) {
120 p.items = append(p.items, pageContentReplacement{val: val, source: source})
121 }
122
123 func (p *pageContentMap) AddShortcode(s *shortcode) {
124 p.items = append(p.items, s)
125 if s.insertPlaceholder() {
126 p.hasNonMarkdownShortcode = true
127 } else {
128 p.hasMarkdownShortcode = true
129 }
130 }