mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
Document and clean SourceRelativeLinksEval code
This commit is contained in:
parent
819271cb78
commit
1648e327c0
6 changed files with 80 additions and 80 deletions
|
@ -289,6 +289,38 @@ Its behavior can be modified with the <code>latexDashes</code> flag listed below
|
||||||
<td class="purpose-description" colspan="2">Extensions in this option won't be loaded.<br>
|
<td class="purpose-description" colspan="2">Extensions in this option won't be loaded.<br>
|
||||||
<small><strong>Example:</strong> Add <code>"autoHeaderIds"</code> to disable <code>EXTENSION_AUTO_HEADER_IDS</code>.</small></td>
|
<small><strong>Example:</strong> Add <code>"autoHeaderIds"</code> to disable <code>EXTENSION_AUTO_HEADER_IDS</code>.</small></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code><strong>sourceRelativeLinksEval</strong></code></td>
|
||||||
|
<td><code>false</code></td>
|
||||||
|
<td><code>none</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="purpose-title">Purpose:</td>
|
||||||
|
<td class="purpose-description" colspan="2">Source file based relative linking (a la Github).<br>
|
||||||
|
Relative links to markdown and static files within a page will be evaluated relative to the
|
||||||
|
location of that page, and then converted to html links during rendering. For example,
|
||||||
|
`[example](../other/page.md)` in `content/total/overview.md` will be linked to
|
||||||
|
`content/other/overview.md`, and then rendered to `/other/overview/` in the HTML output.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code><strong>sourceRelativeLinksProjectFolder</strong></code></td>
|
||||||
|
<td><code>"/docs/content"</code></td>
|
||||||
|
<td><code>none</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="purpose-title">Purpose:</td>
|
||||||
|
<td class="purpose-description" colspan="2">Source file based relative linking Hugo Project sub-folder.<br>
|
||||||
|
When `sourceRelativeLinksEval` is enabled, source level paths may contain an absolute respository path to the
|
||||||
|
markdown or static file which needs to be removed before trying to match it with the intended link.
|
||||||
|
For example, if your documentation is in `/docs/content`, then
|
||||||
|
`[example](/docs/content/other/page.md)` in `/docs/content/total/overview.md` will be linked to
|
||||||
|
`/docs/content/other/overview.md`, and then rendered to `/other/overview/` in the HTML output.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -43,29 +43,31 @@ var SummaryDivider = []byte("<!--more-->")
|
||||||
|
|
||||||
// Blackfriday holds configuration values for Blackfriday rendering.
|
// Blackfriday holds configuration values for Blackfriday rendering.
|
||||||
type Blackfriday struct {
|
type Blackfriday struct {
|
||||||
Smartypants bool
|
Smartypants bool
|
||||||
AngledQuotes bool
|
AngledQuotes bool
|
||||||
Fractions bool
|
Fractions bool
|
||||||
HrefTargetBlank bool
|
HrefTargetBlank bool
|
||||||
SmartDashes bool
|
SmartDashes bool
|
||||||
LatexDashes bool
|
LatexDashes bool
|
||||||
PlainIDAnchors bool
|
PlainIDAnchors bool
|
||||||
SourceRelativeLinksEval bool
|
SourceRelativeLinksEval bool
|
||||||
Extensions []string
|
SourceRelativeLinksProjectFolder string
|
||||||
ExtensionsMask []string
|
Extensions []string
|
||||||
|
ExtensionsMask []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults.
|
// NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults.
|
||||||
func NewBlackfriday() *Blackfriday {
|
func NewBlackfriday() *Blackfriday {
|
||||||
combinedParam := map[string]interface{}{
|
combinedParam := map[string]interface{}{
|
||||||
"smartypants": true,
|
"smartypants": true,
|
||||||
"angledQuotes": false,
|
"angledQuotes": false,
|
||||||
"fractions": true,
|
"fractions": true,
|
||||||
"hrefTargetBlank": false,
|
"hrefTargetBlank": false,
|
||||||
"smartDashes": true,
|
"smartDashes": true,
|
||||||
"latexDashes": true,
|
"latexDashes": true,
|
||||||
"plainIDAnchors": false,
|
"plainIDAnchors": false,
|
||||||
"sourceRelativeLinks": false,
|
"sourceRelativeLinks": false,
|
||||||
|
"sourceRelativeLinksProjectFolder": "/docs/content",
|
||||||
}
|
}
|
||||||
|
|
||||||
siteParam := viper.GetStringMap("blackfriday")
|
siteParam := viper.GetStringMap("blackfriday")
|
||||||
|
|
|
@ -49,6 +49,7 @@ func (renderer *HugoHTMLRenderer) Link(out *bytes.Buffer, link []byte, title []b
|
||||||
// Use the blackfriday built in Link handler
|
// Use the blackfriday built in Link handler
|
||||||
renderer.Renderer.Link(out, link, title, content)
|
renderer.Renderer.Link(out, link, title, content)
|
||||||
} else {
|
} else {
|
||||||
|
// set by SourceRelativeLinksEval
|
||||||
newLink, err := renderer.LinkResolver(string(link))
|
newLink, err := renderer.LinkResolver(string(link))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newLink = string(link)
|
newLink = string(link)
|
||||||
|
@ -62,6 +63,7 @@ func (renderer *HugoHTMLRenderer) Image(out *bytes.Buffer, link []byte, title []
|
||||||
// Use the blackfriday built in Image handler
|
// Use the blackfriday built in Image handler
|
||||||
renderer.Renderer.Image(out, link, title, alt)
|
renderer.Renderer.Image(out, link, title, alt)
|
||||||
} else {
|
} else {
|
||||||
|
// set by SourceRelativeLinksEval
|
||||||
newLink, err := renderer.FileResolver(string(link))
|
newLink, err := renderer.FileResolver(string(link))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newLink = string(link)
|
newLink = string(link)
|
||||||
|
|
|
@ -257,10 +257,10 @@ func (p *Page) renderBytes(content []byte) []byte {
|
||||||
var fileFn helpers.FileResolverFunc
|
var fileFn helpers.FileResolverFunc
|
||||||
if p.getRenderingConfig().SourceRelativeLinksEval {
|
if p.getRenderingConfig().SourceRelativeLinksEval {
|
||||||
fn = func(ref string) (string, error) {
|
fn = func(ref string) (string, error) {
|
||||||
return p.Node.Site.GitHub(ref, p)
|
return p.Node.Site.SourceRelativeLink(ref, p)
|
||||||
}
|
}
|
||||||
fileFn = func(ref string) (string, error) {
|
fileFn = func(ref string) (string, error) {
|
||||||
return p.Node.Site.GitHubFileLink(ref, p)
|
return p.Node.Site.SourceRelativeLinkFile(ref, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return helpers.RenderBytes(
|
return helpers.RenderBytes(
|
||||||
|
@ -273,10 +273,10 @@ func (p *Page) renderContent(content []byte) []byte {
|
||||||
var fileFn helpers.FileResolverFunc
|
var fileFn helpers.FileResolverFunc
|
||||||
if p.getRenderingConfig().SourceRelativeLinksEval {
|
if p.getRenderingConfig().SourceRelativeLinksEval {
|
||||||
fn = func(ref string) (string, error) {
|
fn = func(ref string) (string, error) {
|
||||||
return p.Node.Site.GitHub(ref, p)
|
return p.Node.Site.SourceRelativeLink(ref, p)
|
||||||
}
|
}
|
||||||
fileFn = func(ref string) (string, error) {
|
fileFn = func(ref string) (string, error) {
|
||||||
return p.Node.Site.GitHubFileLink(ref, p)
|
return p.Node.Site.SourceRelativeLinkFile(ref, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return helpers.RenderBytesWithTOC(&helpers.RenderingContext{Content: content, PageFmt: p.guessMarkupType(),
|
return helpers.RenderBytesWithTOC(&helpers.RenderingContext{Content: content, PageFmt: p.guessMarkupType(),
|
||||||
|
|
|
@ -225,28 +225,18 @@ func (s *SiteInfo) RelRef(ref string, page *Page) (string, error) {
|
||||||
return s.refLink(ref, page, true)
|
return s.refLink(ref, page, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(sven): Document
|
// SourceRelativeLink attempts to convert any source page relative links (like [../another.md]) into absolute links
|
||||||
func (s *SiteInfo) GitHub(ref string, page *Page) (string, error) {
|
func (s *SiteInfo) SourceRelativeLink(ref string, currentPage *Page) (string, error) {
|
||||||
return s.githubLink(ref, page, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SiteInfo) githubLink(ref string, currentPage *Page, relative bool) (string, error) {
|
|
||||||
var refURL *url.URL
|
var refURL *url.URL
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// TODO can I make this a param to `hugo --use-github-links=/docs`?
|
refURL, err = url.Parse(strings.TrimPrefix(ref, currentPage.getRenderingConfig().SourceRelativeLinksProjectFolder))
|
||||||
// SVEN: add more tests - the prefix might be a real dir inside tho - add some pages that have it as a legitimate path
|
|
||||||
repositoryPathPrefix := "/docs"
|
|
||||||
|
|
||||||
refURL, err = url.Parse(strings.TrimPrefix(ref, repositoryPathPrefix))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if refURL.Scheme != "" {
|
if refURL.Scheme != "" {
|
||||||
// TODO: consider looking for http(s?)://github.com/user/project/prefix and replacing it - tho this may be intentional, so idk
|
// Not a relative source level path
|
||||||
//return "", fmt.Errorf("Not a plain filepath link (%s)", ref)
|
|
||||||
// Treat this as not an error, as the link is used as-is
|
|
||||||
return ref, nil
|
return ref, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,19 +281,13 @@ func (s *SiteInfo) githubLink(ref string, currentPage *Page, relative bool) (str
|
||||||
return "", fmt.Errorf("No page found for \"%s\" on page \"%s\".\n", ref, currentPage.Source.Path())
|
return "", fmt.Errorf("No page found for \"%s\" on page \"%s\".\n", ref, currentPage.Source.Path())
|
||||||
}
|
}
|
||||||
|
|
||||||
// SVEN: look at filepath.Rel() it might help, got the rel/non-rel url's (dangerous tho)
|
link, err = target.RelPermalink()
|
||||||
if relative {
|
|
||||||
link, err = target.RelPermalink()
|
|
||||||
} else {
|
|
||||||
link, err = target.Permalink()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SVEN: add tests for github style relative fragments
|
|
||||||
if refURL.Fragment != "" {
|
if refURL.Fragment != "" {
|
||||||
link = link + "#" + refURL.Fragment
|
link = link + "#" + refURL.Fragment
|
||||||
|
|
||||||
|
@ -317,29 +301,18 @@ func (s *SiteInfo) githubLink(ref string, currentPage *Page, relative bool) (str
|
||||||
return link, nil
|
return link, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(sven): Document
|
// SourceRelativeLinkFile attempts to convert any non-md source relative links (like [../another.gif]) into absolute links
|
||||||
func (s *SiteInfo) GitHubFileLink(ref string, page *Page) (string, error) {
|
func (s *SiteInfo) SourceRelativeLinkFile(ref string, currentPage *Page) (string, error) {
|
||||||
return s.githubFileLink(ref, page, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for non-pages in the site tree
|
|
||||||
func (s *SiteInfo) githubFileLink(ref string, currentPage *Page, relative bool) (string, error) {
|
|
||||||
var refURL *url.URL
|
var refURL *url.URL
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// TODO can I make this a param to `hugo --use-github-links=/docs`?
|
refURL, err = url.Parse(strings.TrimPrefix(ref, currentPage.getRenderingConfig().SourceRelativeLinksProjectFolder))
|
||||||
// SVEN: add more tests - the prefix might be a real dir inside tho - add some pages that have it as a legitimate path
|
|
||||||
repositoryPathPrefix := "/docs"
|
|
||||||
|
|
||||||
refURL, err = url.Parse(strings.TrimPrefix(ref, repositoryPathPrefix))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if refURL.Scheme != "" {
|
if refURL.Scheme != "" {
|
||||||
// TODO: consider looking for http(s?)://github.com/user/project/prefix and replacing it - tho this may be intentional, so idk
|
// Not a relative source level path
|
||||||
//return "", fmt.Errorf("Not a plain filepath link (%s)", ref)
|
|
||||||
// Treat this as not an error, as the link is used as-is
|
|
||||||
return ref, nil
|
return ref, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,13 +342,7 @@ func (s *SiteInfo) githubFileLink(ref string, currentPage *Page, relative bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
link = target.Path()
|
link = target.Path()
|
||||||
// SVEN: look at filepath.Rel() it might help, got the rel/non-rel url's (dangerous tho)
|
return "/" + filepath.ToSlash(link), nil
|
||||||
// SVEN: reconsider the fact I hardcoded the `relative` bool in both github resolvers
|
|
||||||
if relative {
|
|
||||||
return "./" + filepath.ToSlash(link), nil
|
|
||||||
} else {
|
|
||||||
return "/" + filepath.ToSlash(link), nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("failed to find a file to match \"%s\" on page \"%s\"", ref, currentPage.Source.Path())
|
return "", fmt.Errorf("failed to find a file to match \"%s\" on page \"%s\"", ref, currentPage.Source.Path())
|
||||||
|
|
|
@ -1023,8 +1023,6 @@ func TestWeightedTaxonomies(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func findPage(site *Site, f string) *Page {
|
func findPage(site *Site, f string) *Page {
|
||||||
// TODO: it seems that filepath.FromSlash results in page.Source.Path() returning windows backslash - which means refLinking's string compare is totally busted.
|
|
||||||
// TODO: Not used for non-fragment linking (SVEN thinks this is a bug)
|
|
||||||
currentPath := source.NewFile(filepath.FromSlash(f))
|
currentPath := source.NewFile(filepath.FromSlash(f))
|
||||||
//t.Logf("looking for currentPath: %s", currentPath.Path())
|
//t.Logf("looking for currentPath: %s", currentPath.Path())
|
||||||
|
|
||||||
|
@ -1062,6 +1060,15 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
||||||
{filepath.FromSlash("level2/level3/common.png"), []byte("")},
|
{filepath.FromSlash("level2/level3/common.png"), []byte("")},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viper.Set("baseurl", "http://auth/")
|
||||||
|
viper.Set("DefaultExtension", "html")
|
||||||
|
viper.Set("UglyURLs", false)
|
||||||
|
viper.Set("PluralizeListTitles", false)
|
||||||
|
viper.Set("CanonifyURLs", false)
|
||||||
|
viper.Set("blackfriday",
|
||||||
|
map[string]interface{}{
|
||||||
|
"sourceRelativeLinksProjectFolder": "/docs"})
|
||||||
|
|
||||||
site := &Site{
|
site := &Site{
|
||||||
Source: &source.InMemorySource{ByteSource: sources},
|
Source: &source.InMemorySource{ByteSource: sources},
|
||||||
}
|
}
|
||||||
|
@ -1072,12 +1079,6 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
||||||
t.Fatalf("Unable to create pages: %s", err)
|
t.Fatalf("Unable to create pages: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.Set("baseurl", "http://auth/bub")
|
|
||||||
viper.Set("DefaultExtension", "html")
|
|
||||||
viper.Set("UglyURLs", false)
|
|
||||||
viper.Set("PluralizeListTitles", false)
|
|
||||||
viper.Set("CanonifyURLs", false)
|
|
||||||
|
|
||||||
return site
|
return site
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1228,7 +1229,7 @@ func TestSourceRelativeLinksing(t *testing.T) {
|
||||||
t.Fatalf("failed to find current page in site")
|
t.Fatalf("failed to find current page in site")
|
||||||
}
|
}
|
||||||
for link, url := range results {
|
for link, url := range results {
|
||||||
if out, err := site.Info.githubLink(link, currentPage, true); err != nil || out != url {
|
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)
|
t.Errorf("Expected %s to resolve to (%s), got (%s) - error: %s", link, url, out, err)
|
||||||
} else {
|
} else {
|
||||||
//t.Logf("tested ok %s maps to %s", link, out)
|
//t.Logf("tested ok %s maps to %s", link, out)
|
||||||
|
@ -1241,7 +1242,7 @@ func TestSourceRelativeLinksing(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGitHubFileLinking(t *testing.T) {
|
func TestSourceRelativeLinkFileing(t *testing.T) {
|
||||||
viper.Reset()
|
viper.Reset()
|
||||||
defer viper.Reset()
|
defer viper.Reset()
|
||||||
site := setupLinkingMockSite(t)
|
site := setupLinkingMockSite(t)
|
||||||
|
@ -1278,15 +1279,11 @@ func TestGitHubFileLinking(t *testing.T) {
|
||||||
t.Fatalf("failed to find current page in site")
|
t.Fatalf("failed to find current page in site")
|
||||||
}
|
}
|
||||||
for link, url := range results {
|
for link, url := range results {
|
||||||
if out, err := site.Info.githubFileLink(link, currentPage, false); err != nil || out != url {
|
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)
|
t.Errorf("Expected %s to resolve to (%s), got (%s) - error: %s", link, url, out, err)
|
||||||
} else {
|
} else {
|
||||||
//t.Logf("tested ok %s maps to %s", link, out)
|
//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)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue