From c05da657ec71c46d0e5bc32b074ddcd9d8b76353 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Tue, 12 Nov 2013 17:56:46 -0500
Subject: [PATCH] Add markup support for confluence, mediawiki, textile, trac, and twiki

---
 .classpath                                            |    6 +
 releases.moxie                                        |    2 
 src/main/distrib/data/gitblit.properties              |   35 ++++++++
 src/main/java/com/gitblit/wicket/pages/DocsPage.html  |    4 
 build.moxie                                           |    7 +
 gitblit.iml                                           |   66 ++++++++++++++++
 src/main/java/com/gitblit/wicket/MarkupProcessor.java |  100 ++++++++++++++++++++++++
 7 files changed, 217 insertions(+), 3 deletions(-)

diff --git a/.classpath b/.classpath
index 08039d6..998233b 100644
--- a/.classpath
+++ b/.classpath
@@ -27,6 +27,12 @@
 	<classpathentry kind="lib" path="ext/asm-tree-4.1.jar" sourcepath="ext/src/asm-tree-4.1.jar" />
 	<classpathentry kind="lib" path="ext/asm-analysis-4.1.jar" sourcepath="ext/src/asm-analysis-4.1.jar" />
 	<classpathentry kind="lib" path="ext/asm-util-4.1.jar" sourcepath="ext/src/asm-util-4.1.jar" />
+	<classpathentry kind="lib" path="ext/wikitext-core-1.4.jar" sourcepath="ext/src/wikitext-core-1.4.jar" />
+	<classpathentry kind="lib" path="ext/twiki-core-1.4.jar" sourcepath="ext/src/twiki-core-1.4.jar" />
+	<classpathentry kind="lib" path="ext/textile-core-1.4.jar" sourcepath="ext/src/textile-core-1.4.jar" />
+	<classpathentry kind="lib" path="ext/tracwiki-core-1.4.jar" sourcepath="ext/src/tracwiki-core-1.4.jar" />
+	<classpathentry kind="lib" path="ext/mediawiki-core-1.4.jar" sourcepath="ext/src/mediawiki-core-1.4.jar" />
+	<classpathentry kind="lib" path="ext/confluence-core-1.4.jar" sourcepath="ext/src/confluence-core-1.4.jar" />
 	<classpathentry kind="lib" path="ext/org.eclipse.jgit-3.1.0.201310021548-r.jar" sourcepath="ext/src/org.eclipse.jgit-3.1.0.201310021548-r.jar" />
 	<classpathentry kind="lib" path="ext/jsch-0.1.46.jar" sourcepath="ext/src/jsch-0.1.46.jar" />
 	<classpathentry kind="lib" path="ext/JavaEWAH-0.5.6.jar" sourcepath="ext/src/JavaEWAH-0.5.6.jar" />
diff --git a/build.moxie b/build.moxie
index 44f6d05..4783748 100644
--- a/build.moxie
+++ b/build.moxie
@@ -105,6 +105,7 @@
   groovy.version : 1.8.8
   bouncycastle.version : 1.47
   selenium.version : 2.28.0
+  wikitext.version : 1.4
   }
 
 # Dependencies
@@ -136,6 +137,12 @@
 - compile 'org.apache.lucene:lucene-highlighter:${lucene.version}' :war :fedclient
 - compile 'org.apache.lucene:lucene-memory:${lucene.version}' :war :fedclient
 - compile 'org.pegdown:pegdown:1.4.1' :war
+- compile 'org.fusesource.wikitext:wikitext-core:${wikitext.version}' :war
+- compile 'org.fusesource.wikitext:twiki-core:${wikitext.version}' :war
+- compile 'org.fusesource.wikitext:textile-core:${wikitext.version}' :war
+- compile 'org.fusesource.wikitext:tracwiki-core:${wikitext.version}' :war
+- compile 'org.fusesource.wikitext:mediawiki-core:${wikitext.version}' :war
+- compile 'org.fusesource.wikitext:confluence-core:${wikitext.version}' :war
 - compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager :authority
 - compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :fedclient :manager :authority
 - compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war :authority
diff --git a/gitblit.iml b/gitblit.iml
index c31d1e9..af35a7a 100644
--- a/gitblit.iml
+++ b/gitblit.iml
@@ -273,6 +273,72 @@
       </library>
     </orderEntry>
     <orderEntry type="module-library">
+      <library name="wikitext-core-1.4.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/wikitext-core-1.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/wikitext-core-1.4.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="twiki-core-1.4.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/twiki-core-1.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/twiki-core-1.4.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="textile-core-1.4.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/textile-core-1.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/textile-core-1.4.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="tracwiki-core-1.4.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/tracwiki-core-1.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/tracwiki-core-1.4.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="mediawiki-core-1.4.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/mediawiki-core-1.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/mediawiki-core-1.4.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="confluence-core-1.4.jar">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/ext/confluence-core-1.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/ext/src/confluence-core-1.4.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
       <library name="org.eclipse.jgit-3.1.0.201310021548-r.jar">
         <CLASSES>
           <root url="jar://$MODULE_DIR$/ext/org.eclipse.jgit-3.1.0.201310021548-r.jar!/" />
diff --git a/releases.moxie b/releases.moxie
index 3a0bee6..658b82a 100644
--- a/releases.moxie
+++ b/releases.moxie
@@ -34,6 +34,7 @@
 	- Set Link: <url>; rel="canonical" http header for SEO (issue-304)
 	- Added raw links to the commit, commitdiff, and compare pages (issue-319)
 	- Support intradocument linking in Markdown content using [[WikiLinks]] syntax (issue-324)
+	- Support rendering confluence, mediawiki, textile, tracwiki, and twiki markup documents
 	- Added setting to globally disable anonymous pushes in the receive pack
 	- Added a normalized diffstat display to the commit, commitdiff, and compare pages
 	- Added GO setting to automatically redirect all http requests to the secure https connector
@@ -41,6 +42,7 @@
 	- updated to Jetty 7.6.13
 	- updated to JGit 3.1.0
 	- replaced MarkdownPapers with pegdown 1.4.1
+	- added Eclipse WikiText libraries for processing confluence, mediawiki, textile, tracwiki, and twiki
     settings:
     - { name: 'git.createRepositoriesShared', defaultValue: 'false' }
     - { name: 'git.allowAnonymousPushes', defaultValue: 'false' }
diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties
index 722c501..a791c1f 100644
--- a/src/main/distrib/data/gitblit.properties
+++ b/src/main/distrib/data/gitblit.properties
@@ -1016,6 +1016,41 @@
 # SINCE 0.5.0
 web.markdownExtensions = md mkd markdown MD MKD
 
+# Registered extensions for mediawiki transformation
+#
+# SPACE-DELIMITED
+# CASE-SENSITIVE
+# SINCE 1.4.0
+web.mediawikiExtensions = mw mediawiki
+
+# Registered extensions for twiki transformation
+#
+# SPACE-DELIMITED
+# CASE-SENSITIVE
+# SINCE 1.4.0
+web.twikiExtensions = twiki
+
+# Registered extensions for textile transformation
+#
+# SPACE-DELIMITED
+# CASE-SENSITIVE
+# SINCE 1.4.0
+web.textileExtensions = textile
+
+# Registered extensions for confluence transformation
+#
+# SPACE-DELIMITED
+# CASE-SENSITIVE
+# SINCE 1.4.0
+web.confluenceExtensions = confluence
+
+# Registered extensions for tracwiki transformation
+#
+# SPACE-DELIMITED
+# CASE-SENSITIVE
+# SINCE 1.4.0
+web.tracwikiExtensions = tracwiki
+
 # Image extensions
 #
 # SPACE-DELIMITED
diff --git a/src/main/java/com/gitblit/wicket/MarkupProcessor.java b/src/main/java/com/gitblit/wicket/MarkupProcessor.java
index 4b4bee6..4324f80 100644
--- a/src/main/java/com/gitblit/wicket/MarkupProcessor.java
+++ b/src/main/java/com/gitblit/wicket/MarkupProcessor.java
@@ -16,6 +16,7 @@
 package com.gitblit.wicket;
 
 import java.io.Serializable;
+import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.text.MessageFormat;
@@ -26,6 +27,15 @@
 import org.apache.wicket.RequestCycle;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.mylyn.wikitext.confluence.core.ConfluenceLanguage;
+import org.eclipse.mylyn.wikitext.core.parser.Attributes;
+import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
+import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
+import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
+import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
+import org.eclipse.mylyn.wikitext.textile.core.TextileLanguage;
+import org.eclipse.mylyn.wikitext.tracwiki.core.TracWikiLanguage;
+import org.eclipse.mylyn.wikitext.twiki.core.TWikiLanguage;
 import org.pegdown.LinkRenderer;
 import org.pegdown.ast.WikiLinkNode;
 import org.slf4j.Logger;
@@ -38,6 +48,7 @@
 import com.gitblit.utils.MarkdownUtils;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.wicket.pages.DocPage;
+import com.gitblit.wicket.pages.RawPage;
 
 /**
  * Processes markup content and generates html with repository-relative page and
@@ -49,7 +60,7 @@
 public class MarkupProcessor {
 
 	public enum MarkupSyntax {
-		PLAIN, MARKDOWN
+		PLAIN, MARKDOWN, TWIKI, TRACWIKI, TEXTILE, MEDIAWIKI, CONFLUENCE
 	}
 
 	private Logger logger = LoggerFactory.getLogger(getClass());
@@ -62,7 +73,12 @@
 
 	public List<String> getMarkupExtensions() {
 		List<String> list = new ArrayList<String>();
+		list.addAll(settings.getStrings(Keys.web.confluenceExtensions));
 		list.addAll(settings.getStrings(Keys.web.markdownExtensions));
+		list.addAll(settings.getStrings(Keys.web.mediawikiExtensions));
+		list.addAll(settings.getStrings(Keys.web.textileExtensions));
+		list.addAll(settings.getStrings(Keys.web.tracwikiExtensions));
+		list.addAll(settings.getStrings(Keys.web.twikiExtensions));
 		return list;
 	}
 
@@ -72,8 +88,18 @@
 			return MarkupSyntax.PLAIN;
 		}
 
-		if (settings.getStrings(Keys.web.markdownExtensions).contains(ext)) {
+		if (settings.getStrings(Keys.web.confluenceExtensions).contains(ext)) {
+			return MarkupSyntax.CONFLUENCE;
+		} else if (settings.getStrings(Keys.web.markdownExtensions).contains(ext)) {
 			return MarkupSyntax.MARKDOWN;
+		} else if (settings.getStrings(Keys.web.mediawikiExtensions).contains(ext)) {
+			return MarkupSyntax.MEDIAWIKI;
+		} else if (settings.getStrings(Keys.web.textileExtensions).contains(ext)) {
+			return MarkupSyntax.TEXTILE;
+		} else if (settings.getStrings(Keys.web.tracwikiExtensions).contains(ext)) {
+			return MarkupSyntax.TRACWIKI;
+		} else if (settings.getStrings(Keys.web.twikiExtensions).contains(ext)) {
+			return MarkupSyntax.TWIKI;
 		}
 
 		return MarkupSyntax.PLAIN;
@@ -115,8 +141,23 @@
 		if (markupText != null) {
 			try {
 				switch (syntax){
+				case CONFLUENCE:
+					parse(doc, repositoryName, commitId, new ConfluenceLanguage());
+					break;
 				case MARKDOWN:
 					parse(doc, repositoryName, commitId);
+					break;
+				case MEDIAWIKI:
+					parse(doc, repositoryName, commitId, new MediaWikiLanguage());
+					break;
+				case TEXTILE:
+					parse(doc, repositoryName, commitId, new TextileLanguage());
+					break;
+				case TRACWIKI:
+					parse(doc, repositoryName, commitId, new TracWikiLanguage());
+					break;
+				case TWIKI:
+					parse(doc, repositoryName, commitId, new TWikiLanguage());
 					break;
 				default:
 					doc.html = MarkdownUtils.transformPlainText(markupText);
@@ -140,6 +181,61 @@
 	}
 
 	/**
+	 * Parses the markup using the specified markup language
+	 *
+	 * @param doc
+	 * @param repositoryName
+	 * @param commitId
+	 * @param lang
+	 */
+	private void parse(final MarkupDocument doc, final String repositoryName, final String commitId, MarkupLanguage lang) {
+		StringWriter writer = new StringWriter();
+		HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer) {
+
+			@Override
+			public void image(Attributes attributes, String imagePath) {
+				String url;
+				if (imagePath.indexOf("://") == -1) {
+					// relative image
+					String path = doc.getRelativePath(imagePath);
+					url = getWicketUrl(RawPage.class, repositoryName, commitId, path);
+				} else {
+					// absolute image
+					url = imagePath;
+				}
+				super.image(attributes, url);
+			}
+
+			@Override
+			public void link(Attributes attributes, String hrefOrHashName, String text) {
+				String url;
+				if (hrefOrHashName.charAt(0) != '#') {
+					if (hrefOrHashName.indexOf("://") == -1) {
+						// relative link
+						String path = doc.getRelativePath(hrefOrHashName);
+						url = getWicketUrl(DocPage.class, repositoryName, commitId, path);
+					} else {
+						// absolute link
+						url = hrefOrHashName;
+					}
+				} else {
+					// page-relative hash link
+					url = hrefOrHashName;
+				}
+				super.link(attributes, url, text);
+			}
+		};
+
+		// avoid the <html> and <body> tags
+		builder.setEmitAsDocument(false);
+
+		MarkupParser parser = new MarkupParser(lang);
+		parser.setBuilder(builder);
+		parser.parse(doc.markup);
+		doc.html = writer.toString();
+	}
+
+	/**
 	 * Parses the document as Markdown using Pegdown.
 	 *
 	 * @param doc
diff --git a/src/main/java/com/gitblit/wicket/pages/DocsPage.html b/src/main/java/com/gitblit/wicket/pages/DocsPage.html
index 7f1e64e..ab4d0b9 100644
--- a/src/main/java/com/gitblit/wicket/pages/DocsPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/DocsPage.html
@@ -15,7 +15,9 @@
 		<li><a data-toggle="tab" href="#pages"><wicket:message key="gb.pages">[pages]</wicket:message></a></li>
 	</ul>
 	<div class="tab-content">
-		<div id="home" wicket:id="index" class="tab-pane active"></div>
+		<div id="home" class="tab-pane active">
+			<div class="markdown" wicket:id="index"></div>
+		</div>
 		<div id="pages" wicket:id="documents" class="tab-pane"></div>
 	</div>
 </wicket:fragment>

--
Gitblit v1.9.1