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>
|
||||
<small><strong>Example:</strong> Add <code>"autoHeaderIds"</code> to disable <code>EXTENSION_AUTO_HEADER_IDS</code>.</small></td>
|
||||
</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>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -43,29 +43,31 @@ var SummaryDivider = []byte("<!--more-->")
|
|||
|
||||
// Blackfriday holds configuration values for Blackfriday rendering.
|
||||
type Blackfriday struct {
|
||||
Smartypants bool
|
||||
AngledQuotes bool
|
||||
Fractions bool
|
||||
HrefTargetBlank bool
|
||||
SmartDashes bool
|
||||
LatexDashes bool
|
||||
PlainIDAnchors bool
|
||||
SourceRelativeLinksEval bool
|
||||
Extensions []string
|
||||
ExtensionsMask []string
|
||||
Smartypants bool
|
||||
AngledQuotes bool
|
||||
Fractions bool
|
||||
HrefTargetBlank bool
|
||||
SmartDashes bool
|
||||
LatexDashes bool
|
||||
PlainIDAnchors bool
|
||||
SourceRelativeLinksEval bool
|
||||
SourceRelativeLinksProjectFolder string
|
||||
Extensions []string
|
||||
ExtensionsMask []string
|
||||
}
|
||||
|
||||
// NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults.
|
||||
func NewBlackfriday() *Blackfriday {
|
||||
combinedParam := map[string]interface{}{
|
||||
"smartypants": true,
|
||||
"angledQuotes": false,
|
||||
"fractions": true,
|
||||
"hrefTargetBlank": false,
|
||||
"smartDashes": true,
|
||||
"latexDashes": true,
|
||||
"plainIDAnchors": false,
|
||||
"sourceRelativeLinks": false,
|
||||
"smartypants": true,
|
||||
"angledQuotes": false,
|
||||
"fractions": true,
|
||||
"hrefTargetBlank": false,
|
||||
"smartDashes": true,
|
||||
"latexDashes": true,
|
||||
"plainIDAnchors": false,
|
||||
"sourceRelativeLinks": false,
|
||||
"sourceRelativeLinksProjectFolder": "/docs/content",
|
||||
}
|
||||
|
||||
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
|
||||
renderer.Renderer.Link(out, link, title, content)
|
||||
} else {
|
||||
// set by SourceRelativeLinksEval
|
||||
newLink, err := renderer.LinkResolver(string(link))
|
||||
if err != nil {
|
||||
newLink = string(link)
|
||||
|
@ -62,6 +63,7 @@ func (renderer *HugoHTMLRenderer) Image(out *bytes.Buffer, link []byte, title []
|
|||
// Use the blackfriday built in Image handler
|
||||
renderer.Renderer.Image(out, link, title, alt)
|
||||
} else {
|
||||
// set by SourceRelativeLinksEval
|
||||
newLink, err := renderer.FileResolver(string(link))
|
||||
if err != nil {
|
||||
newLink = string(link)
|
||||
|
|
|
@ -257,10 +257,10 @@ func (p *Page) renderBytes(content []byte) []byte {
|
|||
var fileFn helpers.FileResolverFunc
|
||||
if p.getRenderingConfig().SourceRelativeLinksEval {
|
||||
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) {
|
||||
return p.Node.Site.GitHubFileLink(ref, p)
|
||||
return p.Node.Site.SourceRelativeLinkFile(ref, p)
|
||||
}
|
||||
}
|
||||
return helpers.RenderBytes(
|
||||
|
@ -273,10 +273,10 @@ func (p *Page) renderContent(content []byte) []byte {
|
|||
var fileFn helpers.FileResolverFunc
|
||||
if p.getRenderingConfig().SourceRelativeLinksEval {
|
||||
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) {
|
||||
return p.Node.Site.GitHubFileLink(ref, p)
|
||||
return p.Node.Site.SourceRelativeLinkFile(ref, p)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// TODO(sven): Document
|
||||
func (s *SiteInfo) GitHub(ref string, page *Page) (string, error) {
|
||||
return s.githubLink(ref, page, true)
|
||||
}
|
||||
|
||||
func (s *SiteInfo) githubLink(ref string, currentPage *Page, relative bool) (string, error) {
|
||||
// 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
|
||||
|
||||
// TODO can I make this a param to `hugo --use-github-links=/docs`?
|
||||
// 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))
|
||||
refURL, err = url.Parse(strings.TrimPrefix(ref, currentPage.getRenderingConfig().SourceRelativeLinksProjectFolder))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if refURL.Scheme != "" {
|
||||
// TODO: consider looking for http(s?)://github.com/user/project/prefix and replacing it - tho this may be intentional, so idk
|
||||
//return "", fmt.Errorf("Not a plain filepath link (%s)", ref)
|
||||
// Treat this as not an error, as the link is used as-is
|
||||
// Not a relative source level path
|
||||
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())
|
||||
}
|
||||
|
||||
// SVEN: look at filepath.Rel() it might help, got the rel/non-rel url's (dangerous tho)
|
||||
if relative {
|
||||
link, err = target.RelPermalink()
|
||||
} else {
|
||||
link, err = target.Permalink()
|
||||
}
|
||||
link, err = target.RelPermalink()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// SVEN: add tests for github style relative fragments
|
||||
if refURL.Fragment != "" {
|
||||
link = link + "#" + refURL.Fragment
|
||||
|
||||
|
@ -317,29 +301,18 @@ func (s *SiteInfo) githubLink(ref string, currentPage *Page, relative bool) (str
|
|||
return link, nil
|
||||
}
|
||||
|
||||
// TODO(sven): Document
|
||||
func (s *SiteInfo) GitHubFileLink(ref string, page *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) {
|
||||
// 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
|
||||
|
||||
// TODO can I make this a param to `hugo --use-github-links=/docs`?
|
||||
// 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))
|
||||
refURL, err = url.Parse(strings.TrimPrefix(ref, currentPage.getRenderingConfig().SourceRelativeLinksProjectFolder))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if refURL.Scheme != "" {
|
||||
// TODO: consider looking for http(s?)://github.com/user/project/prefix and replacing it - tho this may be intentional, so idk
|
||||
//return "", fmt.Errorf("Not a plain filepath link (%s)", ref)
|
||||
// Treat this as not an error, as the link is used as-is
|
||||
// Not a relative source level path
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
|
@ -369,13 +342,7 @@ func (s *SiteInfo) githubFileLink(ref string, currentPage *Page, relative bool)
|
|||
}
|
||||
|
||||
link = target.Path()
|
||||
// SVEN: look at filepath.Rel() it might help, got the rel/non-rel url's (dangerous tho)
|
||||
// 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 "/" + filepath.ToSlash(link), nil
|
||||
}
|
||||
|
||||
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 {
|
||||
// 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))
|
||||
//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("")},
|
||||
}
|
||||
|
||||
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{
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
}
|
||||
|
@ -1072,12 +1079,6 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -1228,7 +1229,7 @@ func TestSourceRelativeLinksing(t *testing.T) {
|
|||
t.Fatalf("failed to find current page in site")
|
||||
}
|
||||
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)
|
||||
} else {
|
||||
//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()
|
||||
defer viper.Reset()
|
||||
site := setupLinkingMockSite(t)
|
||||
|
@ -1278,15 +1279,11 @@ func TestGitHubFileLinking(t *testing.T) {
|
|||
t.Fatalf("failed to find current page in site")
|
||||
}
|
||||
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)
|
||||
} 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)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue