mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-29 10:02:12 -05:00
parent
481924b34d
commit
9891c0fb0e
6 changed files with 22 additions and 329 deletions
|
@ -71,8 +71,6 @@ type Blackfriday struct {
|
||||||
LatexDashes bool
|
LatexDashes bool
|
||||||
TaskLists bool
|
TaskLists bool
|
||||||
PlainIDAnchors bool
|
PlainIDAnchors bool
|
||||||
SourceRelativeLinksEval bool
|
|
||||||
SourceRelativeLinksProjectFolder string
|
|
||||||
Extensions []string
|
Extensions []string
|
||||||
ExtensionsMask []string
|
ExtensionsMask []string
|
||||||
}
|
}
|
||||||
|
@ -89,8 +87,6 @@ func (c ContentSpec) NewBlackfriday() *Blackfriday {
|
||||||
"latexDashes": true,
|
"latexDashes": true,
|
||||||
"plainIDAnchors": true,
|
"plainIDAnchors": true,
|
||||||
"taskLists": true,
|
"taskLists": true,
|
||||||
"sourceRelativeLinks": false,
|
|
||||||
"sourceRelativeLinksProjectFolder": "/docs/content",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ToLowerMap(defaultParam)
|
ToLowerMap(defaultParam)
|
||||||
|
@ -112,13 +108,6 @@ func (c ContentSpec) NewBlackfriday() *Blackfriday {
|
||||||
jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error())
|
jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if combinedConfig.SourceRelativeLinksEval {
|
|
||||||
// Remove in Hugo 0.21
|
|
||||||
Deprecated("blackfriday", "sourceRelativeLinksEval",
|
|
||||||
`There is no replacement for this feature, as no developer has stepped up to the plate and volunteered to maintain this feature`, false)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return combinedConfig
|
return combinedConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,8 +401,6 @@ type RenderingContext struct {
|
||||||
DocumentName string
|
DocumentName string
|
||||||
Config *Blackfriday
|
Config *Blackfriday
|
||||||
RenderTOC bool
|
RenderTOC bool
|
||||||
FileResolver FileResolverFunc
|
|
||||||
LinkResolver LinkResolverFunc
|
|
||||||
Cfg config.Provider
|
Cfg config.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/miekg/mmark"
|
"github.com/miekg/mmark"
|
||||||
"github.com/russross/blackfriday"
|
"github.com/russross/blackfriday"
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LinkResolverFunc func(ref string) (string, error)
|
type LinkResolverFunc func(ref string) (string, error)
|
||||||
|
@ -43,35 +42,6 @@ func (r *HugoHTMLRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HugoHTMLRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
|
||||||
if r.LinkResolver == nil || bytes.HasPrefix(link, []byte("HAHAHUGOSHORTCODE")) {
|
|
||||||
// Use the blackfriday built in Link handler
|
|
||||||
r.Renderer.Link(out, link, title, content)
|
|
||||||
} else {
|
|
||||||
// set by SourceRelativeLinksEval
|
|
||||||
newLink, err := r.LinkResolver(string(link))
|
|
||||||
if err != nil {
|
|
||||||
newLink = string(link)
|
|
||||||
jww.ERROR.Printf("LinkResolver: %s", err)
|
|
||||||
}
|
|
||||||
r.Renderer.Link(out, []byte(newLink), title, content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (r *HugoHTMLRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
|
||||||
if r.FileResolver == nil || bytes.HasPrefix(link, []byte("HAHAHUGOSHORTCODE")) {
|
|
||||||
// Use the blackfriday built in Image handler
|
|
||||||
r.Renderer.Image(out, link, title, alt)
|
|
||||||
} else {
|
|
||||||
// set by SourceRelativeLinksEval
|
|
||||||
newLink, err := r.FileResolver(string(link))
|
|
||||||
if err != nil {
|
|
||||||
newLink = string(link)
|
|
||||||
jww.ERROR.Printf("FileResolver: %s", err)
|
|
||||||
}
|
|
||||||
r.Renderer.Image(out, []byte(newLink), title, alt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListItem adds task list support to the Blackfriday renderer.
|
// ListItem adds task list support to the Blackfriday renderer.
|
||||||
func (r *HugoHTMLRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
func (r *HugoHTMLRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||||
if !r.Config.TaskLists {
|
if !r.Config.TaskLists {
|
||||||
|
|
|
@ -188,7 +188,6 @@ func TestGetHTMLRendererAllFlags(t *testing.T) {
|
||||||
ctx.Config.SmartDashes = true
|
ctx.Config.SmartDashes = true
|
||||||
ctx.Config.Smartypants = true
|
ctx.Config.Smartypants = true
|
||||||
ctx.Config.SmartypantsQuotesNBSP = true
|
ctx.Config.SmartypantsQuotesNBSP = true
|
||||||
ctx.Config.SourceRelativeLinksEval = true
|
|
||||||
renderer := c.getHTMLRenderer(defaultFlags, ctx)
|
renderer := c.getHTMLRenderer(defaultFlags, ctx)
|
||||||
actualFlags := renderer.GetFlags()
|
actualFlags := renderer.GetFlags()
|
||||||
var expectedFlags int
|
var expectedFlags int
|
||||||
|
|
|
@ -622,22 +622,11 @@ func (p *Page) setAutoSummary() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Page) renderContent(content []byte) []byte {
|
func (p *Page) renderContent(content []byte) []byte {
|
||||||
var fn helpers.LinkResolverFunc
|
|
||||||
var fileFn helpers.FileResolverFunc
|
|
||||||
if p.getRenderingConfig().SourceRelativeLinksEval {
|
|
||||||
fn = func(ref string) (string, error) {
|
|
||||||
return p.Site.SourceRelativeLink(ref, p)
|
|
||||||
}
|
|
||||||
fileFn = func(ref string) (string, error) {
|
|
||||||
return p.Site.SourceRelativeLinkFile(ref, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.s.ContentSpec.RenderBytes(&helpers.RenderingContext{
|
return p.s.ContentSpec.RenderBytes(&helpers.RenderingContext{
|
||||||
Content: content, RenderTOC: true, PageFmt: p.determineMarkupType(),
|
Content: content, RenderTOC: true, PageFmt: p.determineMarkupType(),
|
||||||
Cfg: p.Language(),
|
Cfg: p.Language(),
|
||||||
DocumentID: p.UniqueID(), DocumentName: p.Path(),
|
DocumentID: p.UniqueID(), DocumentName: p.Path(),
|
||||||
Config: p.getRenderingConfig(), LinkResolver: fn, FileResolver: fileFn})
|
Config: p.getRenderingConfig()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Page) getRenderingConfig() *helpers.Blackfriday {
|
func (p *Page) getRenderingConfig() *helpers.Blackfriday {
|
||||||
|
|
120
hugolib/site.go
120
hugolib/site.go
|
@ -493,126 +493,6 @@ func (s *SiteInfo) RelRef(ref string, page *Page, options ...string) (string, er
|
||||||
return s.refLink(ref, page, true, outputFormat)
|
return s.refLink(ref, page, true, outputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SourceRelativeLink attempts to convert any source page relative links (like [../another.md]) into absolute links
|
|
||||||
func (s *SiteInfo) SourceRelativeLink(ref string, currentPage *Page) (string, error) {
|
|
||||||
var refURL *url.URL
|
|
||||||
var err error
|
|
||||||
|
|
||||||
refURL, err = url.Parse(strings.TrimPrefix(ref, currentPage.getRenderingConfig().SourceRelativeLinksProjectFolder))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if refURL.Scheme != "" {
|
|
||||||
// Not a relative source level path
|
|
||||||
return ref, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var target *Page
|
|
||||||
var link string
|
|
||||||
|
|
||||||
if refURL.Path != "" {
|
|
||||||
refPath := filepath.Clean(filepath.FromSlash(refURL.Path))
|
|
||||||
|
|
||||||
if strings.IndexRune(refPath, os.PathSeparator) == 0 { // filepath.IsAbs fails to me.
|
|
||||||
refPath = refPath[1:]
|
|
||||||
} else {
|
|
||||||
if currentPage != nil {
|
|
||||||
refPath = filepath.Join(currentPage.Source.Dir(), refURL.Path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, page := range s.AllRegularPages {
|
|
||||||
if page.Source.Path() == refPath {
|
|
||||||
target = page
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// need to exhaust the test, then try with the others :/
|
|
||||||
// if the refPath doesn't end in a filename with extension `.md`, then try with `.md` , and then `/index.md`
|
|
||||||
mdPath := strings.TrimSuffix(refPath, string(os.PathSeparator)) + ".md"
|
|
||||||
for _, page := range s.AllRegularPages {
|
|
||||||
if page.Source.Path() == mdPath {
|
|
||||||
target = page
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
indexPath := filepath.Join(refPath, "index.md")
|
|
||||||
for _, page := range s.AllRegularPages {
|
|
||||||
if page.Source.Path() == indexPath {
|
|
||||||
target = page
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if target == nil {
|
|
||||||
return "", fmt.Errorf("No page found for \"%s\" on page \"%s\".\n", ref, currentPage.Source.Path())
|
|
||||||
}
|
|
||||||
|
|
||||||
link = target.RelPermalink()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if refURL.Fragment != "" {
|
|
||||||
link = link + "#" + refURL.Fragment
|
|
||||||
|
|
||||||
if refURL.Path != "" && target != nil && !target.getRenderingConfig().PlainIDAnchors {
|
|
||||||
link = link + ":" + target.UniqueID()
|
|
||||||
} else if currentPage != nil && !currentPage.getRenderingConfig().PlainIDAnchors {
|
|
||||||
link = link + ":" + currentPage.UniqueID()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return link, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SourceRelativeLinkFile attempts to convert any non-md source relative links (like [../another.gif]) into absolute links
|
|
||||||
func (s *SiteInfo) SourceRelativeLinkFile(ref string, currentPage *Page) (string, error) {
|
|
||||||
var refURL *url.URL
|
|
||||||
var err error
|
|
||||||
|
|
||||||
refURL, err = url.Parse(strings.TrimPrefix(ref, currentPage.getRenderingConfig().SourceRelativeLinksProjectFolder))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if refURL.Scheme != "" {
|
|
||||||
// Not a relative source level path
|
|
||||||
return ref, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var target *source.File
|
|
||||||
var link string
|
|
||||||
|
|
||||||
if refURL.Path != "" {
|
|
||||||
refPath := filepath.Clean(filepath.FromSlash(refURL.Path))
|
|
||||||
|
|
||||||
if strings.IndexRune(refPath, os.PathSeparator) == 0 { // filepath.IsAbs fails to me.
|
|
||||||
refPath = refPath[1:]
|
|
||||||
} else {
|
|
||||||
if currentPage != nil {
|
|
||||||
refPath = filepath.Join(currentPage.Source.Dir(), refURL.Path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range *s.Files {
|
|
||||||
if file.Path() == refPath {
|
|
||||||
target = file
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if target == nil {
|
|
||||||
return "", fmt.Errorf("No file found for \"%s\" on page \"%s\".\n", ref, currentPage.Source.Path())
|
|
||||||
}
|
|
||||||
|
|
||||||
link = target.Path()
|
|
||||||
return "/" + filepath.ToSlash(link), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", fmt.Errorf("failed to find a file to match \"%s\" on page \"%s\"", ref, currentPage.Source.Path())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SiteInfo) addToPaginationPageCount(cnt uint64) {
|
func (s *SiteInfo) addToPaginationPageCount(cnt uint64) {
|
||||||
atomic.AddUint64(&s.paginationPageCount, cnt)
|
atomic.AddUint64(&s.paginationPageCount, cnt)
|
||||||
}
|
}
|
||||||
|
|
|
@ -938,8 +938,7 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
||||||
cfg.Set("pluralizeListTitles", false)
|
cfg.Set("pluralizeListTitles", false)
|
||||||
cfg.Set("canonifyURLs", false)
|
cfg.Set("canonifyURLs", false)
|
||||||
cfg.Set("blackfriday",
|
cfg.Set("blackfriday",
|
||||||
map[string]interface{}{
|
map[string]interface{}{})
|
||||||
"sourceRelativeLinksProjectFolder": "/docs"})
|
|
||||||
writeSourcesToSource(t, "content", fs, sources...)
|
writeSourcesToSource(t, "content", fs, sources...)
|
||||||
return buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
|
return buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
|
||||||
|
|
||||||
|
@ -973,134 +972,3 @@ func TestRefLinking(t *testing.T) {
|
||||||
|
|
||||||
// TODO: and then the failure cases.
|
// TODO: and then the failure cases.
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSourceRelativeLinksing(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
site := setupLinkingMockSite(t)
|
|
||||||
|
|
||||||
type resultMap map[string]string
|
|
||||||
|
|
||||||
okresults := map[string]resultMap{
|
|
||||||
"index.md": map[string]string{
|
|
||||||
"/docs/rootfile.md": "/rootfile/",
|
|
||||||
"rootfile.md": "/rootfile/",
|
|
||||||
// See #3396 -- this may potentially be ambiguous (i.e. name conflict with home page).
|
|
||||||
// But the user have chosen so. This index.md patterns is more relevant in /sub-folders.
|
|
||||||
"index.md": "/",
|
|
||||||
"level2/2-root.md": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root.md": "/level2/2-root/",
|
|
||||||
"level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/2-root/": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root": "/level2/2-root/",
|
|
||||||
"/level2/2-root/": "/level2/2-root/",
|
|
||||||
"/level2/2-root": "/level2/2-root/",
|
|
||||||
}, "rootfile.md": map[string]string{
|
|
||||||
"/docs/rootfile.md": "/rootfile/",
|
|
||||||
"rootfile.md": "/rootfile/",
|
|
||||||
"level2/2-root.md": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root.md": "/level2/2-root/",
|
|
||||||
"level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
}, "level2/2-root.md": map[string]string{
|
|
||||||
"../rootfile.md": "/rootfile/",
|
|
||||||
"/docs/rootfile.md": "/rootfile/",
|
|
||||||
"2-root.md": "/level2/2-root/",
|
|
||||||
"../level2/2-root.md": "/level2/2-root/",
|
|
||||||
"./2-root.md": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root.md": "/level2/2-root/",
|
|
||||||
"level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"../level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
}, "level2/index.md": map[string]string{
|
|
||||||
"../rootfile.md": "/rootfile/",
|
|
||||||
"/docs/rootfile.md": "/rootfile/",
|
|
||||||
"2-root.md": "/level2/2-root/",
|
|
||||||
"../level2/2-root.md": "/level2/2-root/",
|
|
||||||
"./2-root.md": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root.md": "/level2/2-root/",
|
|
||||||
"level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"../level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
}, "level2/level3/3-root.md": map[string]string{
|
|
||||||
"../../rootfile.md": "/rootfile/",
|
|
||||||
"/docs/rootfile.md": "/rootfile/",
|
|
||||||
"../2-root.md": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root.md": "/level2/2-root/",
|
|
||||||
"3-root.md": "/level2/level3/3-root/",
|
|
||||||
"./3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
}, "level2/level3/index.md": map[string]string{
|
|
||||||
"../../rootfile.md": "/rootfile/",
|
|
||||||
"/docs/rootfile.md": "/rootfile/",
|
|
||||||
"../2-root.md": "/level2/2-root/",
|
|
||||||
"/docs/level2/2-root.md": "/level2/2-root/",
|
|
||||||
"3-root.md": "/level2/level3/3-root/",
|
|
||||||
"./3-root.md": "/level2/level3/3-root/",
|
|
||||||
"/docs/level2/level3/3-root.md": "/level2/level3/3-root/",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for currentFile, results := range okresults {
|
|
||||||
currentPage := findPage(site, currentFile)
|
|
||||||
if currentPage == nil {
|
|
||||||
t.Fatalf("failed to find current page in site")
|
|
||||||
}
|
|
||||||
for link, url := range results {
|
|
||||||
if out, err := site.Info.SourceRelativeLink(link, currentPage); err != nil || out != url {
|
|
||||||
t.Errorf("Expected %s to resolve to (%s), got (%s) - error: %s", link, url, out, err)
|
|
||||||
} else {
|
|
||||||
//t.Logf("tested ok %s maps to %s", link, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: and then the failure cases.
|
|
||||||
// "https://docker.com": "",
|
|
||||||
// site_test.go:1094: Expected https://docker.com to resolve to (), got () - error: Not a plain filepath link (https://docker.com)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSourceRelativeLinkFileing(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
site := setupLinkingMockSite(t)
|
|
||||||
|
|
||||||
type resultMap map[string]string
|
|
||||||
|
|
||||||
okresults := map[string]resultMap{
|
|
||||||
"index.md": map[string]string{
|
|
||||||
"/root-image.png": "/root-image.png",
|
|
||||||
"root-image.png": "/root-image.png",
|
|
||||||
}, "rootfile.md": map[string]string{
|
|
||||||
"/root-image.png": "/root-image.png",
|
|
||||||
}, "level2/2-root.md": map[string]string{
|
|
||||||
"/root-image.png": "/root-image.png",
|
|
||||||
"common.png": "/level2/common.png",
|
|
||||||
}, "level2/index.md": map[string]string{
|
|
||||||
"/root-image.png": "/root-image.png",
|
|
||||||
"common.png": "/level2/common.png",
|
|
||||||
"./common.png": "/level2/common.png",
|
|
||||||
}, "level2/level3/3-root.md": map[string]string{
|
|
||||||
"/root-image.png": "/root-image.png",
|
|
||||||
"common.png": "/level2/level3/common.png",
|
|
||||||
"../common.png": "/level2/common.png",
|
|
||||||
}, "level2/level3/index.md": map[string]string{
|
|
||||||
"/root-image.png": "/root-image.png",
|
|
||||||
"common.png": "/level2/level3/common.png",
|
|
||||||
"../common.png": "/level2/common.png",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for currentFile, results := range okresults {
|
|
||||||
currentPage := findPage(site, currentFile)
|
|
||||||
if currentPage == nil {
|
|
||||||
t.Fatalf("failed to find current page in site")
|
|
||||||
}
|
|
||||||
for link, url := range results {
|
|
||||||
if out, err := site.Info.SourceRelativeLinkFile(link, currentPage); err != nil || out != url {
|
|
||||||
t.Errorf("Expected %s to resolve to (%s), got (%s) - error: %s", link, url, out, err)
|
|
||||||
} else {
|
|
||||||
//t.Logf("tested ok %s maps to %s", link, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue