Document and clean SourceRelativeLinksEval code
authorSven Dowideit <SvenDowideit@home.org.au>
Tue, 15 Mar 2016 06:00:36 +0000 (16:00 +1000)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Thu, 7 Apr 2016 18:10:38 +0000 (20:10 +0200)
docs/content/overview/configuration.md
helpers/content.go
helpers/content_renderer.go
hugolib/page.go
hugolib/site.go
hugolib/site_test.go

index e351c651a736277e9573b973bb35c00e87bde058..9d721d4a0df06ba3e665edb2a2973bdc7b2fecf5 100644 (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>
 
index c1353ae292a10e93ad6c012e82979576f70119ef..f603490552ecb1f1ce11692179db7f849a0b1f25 100644 (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")
index aedf0e1d0d8f37ec092e22abe2b8b16693aee8f7..18df9ebef0380c7a73ef3be1a1c3eabc2e25fdb4 100644 (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)
index 3d1b48738ba85906ff778789f41a5a88434d10c9..2342e368fc517cf5035dcdaafb3c8d33b665366d 100644 (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(),
index ea9297b3dad02914c1347559f5780cf1296be40c..0f488f7cb54bb77e5f65c4139f0adfff0c66e918 100644 (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())
index ae30216244aa80ac4e4f8fa1a6cf2d0063f733d3..dd52b6d26b0ea2ca0bec1cfad415fe50c45cf26f 100644 (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)
-
 }