Document and clean SourceRelativeLinksEval code

This commit is contained in:
Sven Dowideit 2016-03-15 16:00:36 +10:00 committed by Bjørn Erik Pedersen
parent 819271cb78
commit 1648e327c0
6 changed files with 80 additions and 80 deletions

View file

@ -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>&nbsp;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>

View file

@ -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")

View file

@ -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)

View file

@ -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(),

View file

@ -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())

View file

@ -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)
}