From a7317acec01cde855a9f9f3d2da3dcc49d89aa86 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Oct 2013 23:44:11 -0400 Subject: Support for intra-Markdown linking using [[WikiLinks]] syntax (issue-324) All WikiLinks must be specified relative to the root of the repository. The displayed link text is stripped to just the document name. Spaces in the document name are replaced with '-' characters; this is consistent with wiki syntax and Github. Change-Id: Id3fb1b5441352d9bacc4993a5b85882db113693b --- src/main/java/com/gitblit/utils/MarkdownUtils.java | 14 ++++- .../com/gitblit/wicket/GitBlitWebApp.properties | 3 +- .../java/com/gitblit/wicket/pages/DocsPage.html | 25 ++++++-- .../java/com/gitblit/wicket/pages/DocsPage.java | 67 ++++++++++++++++++---- .../com/gitblit/wicket/pages/MarkdownPage.java | 32 +++++++++-- .../com/gitblit/wicket/pages/RepositoryPage.java | 31 ++++++++++ .../java/com/gitblit/wicket/pages/SummaryPage.java | 4 +- 7 files changed, 153 insertions(+), 23 deletions(-) (limited to 'src/main/java/com/gitblit') diff --git a/src/main/java/com/gitblit/utils/MarkdownUtils.java b/src/main/java/com/gitblit/utils/MarkdownUtils.java index f9c07fbc..1595f654 100644 --- a/src/main/java/com/gitblit/utils/MarkdownUtils.java +++ b/src/main/java/com/gitblit/utils/MarkdownUtils.java @@ -22,6 +22,7 @@ import java.io.Reader; import java.io.StringWriter; import org.apache.commons.io.IOUtils; +import org.pegdown.LinkRenderer; import org.pegdown.PegDownProcessor; /** @@ -55,8 +56,19 @@ public class MarkdownUtils { * @throws java.text.ParseException */ public static String transformMarkdown(String markdown) { + return transformMarkdown(markdown, null); + } + + /** + * Returns the html version of the markdown source text. + * + * @param markdown + * @return html version of markdown text + * @throws java.text.ParseException + */ + public static String transformMarkdown(String markdown, LinkRenderer linkRenderer) { PegDownProcessor pd = new PegDownProcessor(ALL); - String html = pd.markdownToHtml(markdown); + String html = pd.markdownToHtml(markdown, linkRenderer == null ? new LinkRenderer() : linkRenderer); return html; } diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 4b19f9b2..526093ab 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -503,4 +503,5 @@ gb.todaysActivityNone = today / none gb.noActivityToday = there has been no activity today gb.anonymousUser= anonymous gb.commitMessageRenderer = commit message renderer -gb.diffStat = {0} insertions & {1} deletions \ No newline at end of file +gb.diffStat = {0} insertions & {1} deletions +gb.home = home \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/DocsPage.html b/src/main/java/com/gitblit/wicket/pages/DocsPage.html index ad93000c..7f1e64e0 100644 --- a/src/main/java/com/gitblit/wicket/pages/DocsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/DocsPage.html @@ -6,10 +6,26 @@ - - + +
+ + + +
+
+
+
+
+ +
[header]
- +
+
+ + @@ -22,7 +38,8 @@ -
+ +
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/DocsPage.java b/src/main/java/com/gitblit/wicket/pages/DocsPage.java index eea9595c..58471ef9 100644 --- a/src/main/java/com/gitblit/wicket/pages/DocsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/DocsPage.java @@ -15,21 +15,27 @@ */ package com.gitblit.wicket.pages; +import java.util.Arrays; import java.util.List; +import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.models.PathModel; import com.gitblit.utils.ByteFormat; import com.gitblit.utils.JGitUtils; +import com.gitblit.utils.MarkdownUtils; +import com.gitblit.utils.StringUtils; import com.gitblit.wicket.CacheControl; import com.gitblit.wicket.CacheControl.LastModified; import com.gitblit.wicket.WicketUtils; @@ -42,14 +48,51 @@ public class DocsPage extends RepositoryPage { super(params); Repository r = getRepository(); + RevCommit head = JGitUtils.getCommit(r, null); List extensions = GitBlit.getStrings(Keys.web.markdownExtensions); List paths = JGitUtils.getDocuments(r, extensions); - final ByteFormat byteFormat = new ByteFormat(); + String doc = null; + String markdown = null; + String html = null; + + List roots = Arrays.asList("home"); - add(new Label("header", getString("gb.docs"))); + // try to find a custom index/root page + for (PathModel path : paths) { + String name = path.name.toLowerCase(); + if (name.indexOf('.') > -1) { + name = name.substring(0, name.lastIndexOf('.')); + } + if (roots.contains(name)) { + doc = path.name; + break; + } + } - // documents list + if (!StringUtils.isEmpty(doc)) { + // load the document + String [] encodings = GitBlit.getEncodings(); + markdown = JGitUtils.getStringContent(r, head.getTree(), doc, encodings); + html = MarkdownUtils.transformMarkdown(markdown, getLinkRenderer()); + } + + Fragment fragment = null; + if (StringUtils.isEmpty(html)) { + // no custom index/root, use the standard document list + fragment = new Fragment("docs", "noIndexFragment", this); + fragment.add(new Label("header", getString("gb.docs"))); + } else { + // custom index/root, use tabbed ui of index/root and document list + fragment = new Fragment("docs", "indexFragment", this); + Component content = new Label("index", html).setEscapeModelStrings(false); + fragment.add(content); + } + + // document list + final String id = getBestCommitId(head); + final ByteFormat byteFormat = new ByteFormat(); + Fragment docs = new Fragment("documents", "documentsFragment", this); ListDataProvider pathsDp = new ListDataProvider(paths); DataView pathsView = new DataView("document", pathsDp) { private static final long serialVersionUID = 1L; @@ -60,23 +103,25 @@ public class DocsPage extends RepositoryPage { PathModel entry = item.getModelObject(); item.add(WicketUtils.newImage("docIcon", "file_world_16x16.png")); item.add(new Label("docSize", byteFormat.format(entry.size))); - item.add(new LinkPanel("docName", "list", entry.name, BlobPage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path))); + item.add(new LinkPanel("docName", "list", entry.name, MarkdownPage.class, WicketUtils + .newPathParameter(repositoryName, id, entry.path))); // links - item.add(new BookmarkablePageLink("view", BlobPage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path))); + item.add(new BookmarkablePageLink("view", MarkdownPage.class, WicketUtils + .newPathParameter(repositoryName, id, entry.path))); item.add(new BookmarkablePageLink("raw", RawPage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path))); + .newPathParameter(repositoryName, id, entry.path))); item.add(new BookmarkablePageLink("blame", BlamePage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path))); + .newPathParameter(repositoryName, id, entry.path))); item.add(new BookmarkablePageLink("history", HistoryPage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path))); + .newPathParameter(repositoryName, id, entry.path))); WicketUtils.setAlternatingBackground(item, counter); counter++; } }; - add(pathsView); + docs.add(pathsView); + fragment.add(docs); + add(fragment); } @Override diff --git a/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java b/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java index 188a5b4b..e0c85cf5 100644 --- a/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java @@ -16,6 +16,7 @@ package com.gitblit.wicket.pages; import java.text.MessageFormat; +import java.util.List; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; @@ -25,6 +26,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import com.gitblit.GitBlit; +import com.gitblit.Keys; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils; @@ -38,11 +40,32 @@ public class MarkdownPage extends RepositoryPage { public MarkdownPage(PageParameters params) { super(params); - final String markdownPath = WicketUtils.getPath(params); + final String path = WicketUtils.getPath(params).replace("%2f", "/").replace("%2F", "/"); Repository r = getRepository(); RevCommit commit = JGitUtils.getCommit(r, objectId); String [] encodings = GitBlit.getEncodings(); + List extensions = GitBlit.getStrings(Keys.web.markdownExtensions); + + // Read raw markdown content and transform it to html + String markdownPath = path; + String markdownText = JGitUtils.getStringContent(r, commit.getTree(), path, encodings); + if (StringUtils.isEmpty(markdownText)) { + String name = path; + if (path.indexOf('.') > -1) { + name = path.substring(0, path.lastIndexOf('.')); + } + + for (String ext : extensions) { + String checkName = name + "." + ext; + markdownText = JGitUtils.getStringContent(r, commit.getTree(), checkName, encodings); + if (!StringUtils.isEmpty(markdownText)) { + // found it + markdownPath = path; + break; + } + } + } // markdown page links add(new BookmarkablePageLink("blameLink", BlamePage.class, @@ -54,13 +77,14 @@ public class MarkdownPage extends RepositoryPage { add(new BookmarkablePageLink("headLink", MarkdownPage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, markdownPath))); - // Read raw markdown content and transform it to html - String markdownText = JGitUtils.getStringContent(r, commit.getTree(), markdownPath, encodings); String htmlText; try { - htmlText = MarkdownUtils.transformMarkdown(markdownText); + htmlText = MarkdownUtils.transformMarkdown(markdownText, getLinkRenderer()); } catch (Exception e) { logger.error("failed to transform markdown", e); + if (markdownText == null) { + markdownText = String.format("Markdown document %1$s not found in %2$s", markdownPath, repositoryName); + } markdownText = MessageFormat.format("
{0}: {1}
{2}", getString("gb.error"), getString("gb.markdownFailure"), markdownText); htmlText = StringUtils.breakLinesForHtml(markdownText); } diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java index 2df0a0e0..3b1d296b 100644 --- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java @@ -16,6 +16,8 @@ package com.gitblit.wicket.pages; import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -43,6 +45,8 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import org.pegdown.LinkRenderer; +import org.pegdown.ast.WikiLinkNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -644,6 +648,33 @@ public abstract class RepositoryPage extends RootPage { return isOwner; } + /** + * Returns a Pegdown/Markdown link renderer which renders WikiLinks. + * + * @return a link renderer + */ + protected LinkRenderer getLinkRenderer() { + RevCommit head = JGitUtils.getCommit(r, "HEAD"); + final String id = getBestCommitId(head); + LinkRenderer renderer = new LinkRenderer() { + @Override + public Rendering render(WikiLinkNode node) { + try { + String path = URLEncoder.encode(node.getText().replace(' ', '-'), "UTF-8"); + String name = node.getText(); + if (name.indexOf('/') > -1) { + name = name.substring(name.lastIndexOf('/') + 1); + } + String url = urlFor(MarkdownPage.class, WicketUtils.newPathParameter(repositoryName, id, path)).toString(); + return new Rendering(url, name); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(); + } + } + }; + return renderer; + } + private class SearchForm extends SessionlessForm implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java index 0a138371..827e0799 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java @@ -167,7 +167,7 @@ public class SummaryPage extends RepositoryPage { String [] encodings = GitBlit.getEncodings(); markdownText = JGitUtils.getStringContent(r, head.getTree(), readme, encodings); if (isMarkdown) { - htmlText = MarkdownUtils.transformMarkdown(markdownText); + htmlText = MarkdownUtils.transformMarkdown(markdownText, getLinkRenderer()); } else { htmlText = MarkdownUtils.transformPlainText(markdownText); } @@ -181,7 +181,7 @@ public class SummaryPage extends RepositoryPage { if (StringUtils.isEmpty(htmlText)) { add(new Label("readme").setVisible(false)); } else { - Fragment fragment = new Fragment("readme", isMarkdown ? "markdownPanel" : "plaintextPanel"); + Fragment fragment = new Fragment("readme", isMarkdown ? "markdownPanel" : "plaintextPanel", this); fragment.add(new Label("readmeFile", readme)); // Add the html to the page Component content = new Label("readmeContent", htmlText).setEscapeModelStrings(false); -- cgit v1.2.3