diff --git a/project/build.scala b/project/build.scala index 6249a92..9a19a67 100644 --- a/project/build.scala +++ b/project/build.scala @@ -50,7 +50,8 @@ "org.json4s" %% "json4s-jackson" % "3.2.11", "jp.sf.amateras" %% "scalatra-forms" % "0.1.0", "commons-io" % "commons-io" % "2.4", - "org.pegdown" % "pegdown" % "1.5.0", +// "org.pegdown" % "pegdown" % "1.5.0", + "io.github.gitbucket" % "markedj" % "1.0.0", "org.apache.commons" % "commons-compress" % "1.9", "org.apache.commons" % "commons-email" % "1.3.3", "org.apache.httpcomponents" % "httpclient" % "4.3.6", diff --git a/src/main/scala/gitbucket/core/view/Markdown.scala b/src/main/scala/gitbucket/core/view/Markdown.scala index 3a80b8f..ebdf976 100644 --- a/src/main/scala/gitbucket/core/view/Markdown.scala +++ b/src/main/scala/gitbucket/core/view/Markdown.scala @@ -7,10 +7,11 @@ import gitbucket.core.controller.Context import gitbucket.core.service.{RepositoryService, RequestCache, WikiService} import gitbucket.core.util.StringUtil -import org.parboiled.common.StringUtils -import org.pegdown.LinkRenderer.Rendering -import org.pegdown._ -import org.pegdown.ast._ +import io.github.gitbucket.markedj._ +//import org.parboiled.common.StringUtils +//import org.pegdown.LinkRenderer.Rendering +//import org.pegdown._ +//import org.pegdown.ast._ import scala.collection.JavaConverters._ @@ -35,241 +36,241 @@ enableTaskList: Boolean = false, hasWritePermission: Boolean = false, pages: List[String] = Nil)(implicit context: Context): String = { - - // escape issue id - val s = if(enableRefsLink){ - markdown.replaceAll("(?<=(\\W|^))#(\\d+)(?=(\\W|$))", "issue:$2") - } else markdown - - // escape task list - val source = if(enableTaskList){ - GitBucketHtmlSerializer.escapeTaskList(s) - } else s - - val rootNode = new PegDownProcessor( - Extensions.AUTOLINKS | Extensions.WIKILINKS | Extensions.FENCED_CODE_BLOCKS | - Extensions.TABLES | Extensions.HARDWRAPS | Extensions.SUPPRESS_ALL_HTML | Extensions.STRIKETHROUGH - ).parseMarkdown(source.toCharArray) - - new GitBucketHtmlSerializer( - markdown, repository, enableWikiLink, enableRefsLink, enableAnchor, enableTaskList, - hasWritePermission, pages - ).toHtml(rootNode) + Marked.marked(markdown, new Options()) +// // escape issue id +// val s = if(enableRefsLink){ +// markdown.replaceAll("(?<=(\\W|^))#(\\d+)(?=(\\W|$))", "issue:$2") +// } else markdown +// +// // escape task list +// val source = if(enableTaskList){ +// GitBucketHtmlSerializer.escapeTaskList(s) +// } else s +// +// val rootNode = new PegDownProcessor( +// Extensions.AUTOLINKS | Extensions.WIKILINKS | Extensions.FENCED_CODE_BLOCKS | +// Extensions.TABLES | Extensions.HARDWRAPS | Extensions.SUPPRESS_ALL_HTML | Extensions.STRIKETHROUGH +// ).parseMarkdown(source.toCharArray) +// +// new GitBucketHtmlSerializer( +// markdown, repository, enableWikiLink, enableRefsLink, enableAnchor, enableTaskList, +// hasWritePermission, pages +// ).toHtml(rootNode) } } -class GitBucketLinkRender( - context: Context, - repository: RepositoryService.RepositoryInfo, - enableWikiLink: Boolean, - pages: List[String]) extends LinkRenderer with WikiService { - - override def render(node: WikiLinkNode): Rendering = { - if(enableWikiLink){ - try { - val text = node.getText - val (label, page) = if(text.contains('|')){ - val i = text.indexOf('|') - (text.substring(0, i), text.substring(i + 1)) - } else { - (text, text) - } - - val url = repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/wiki/" + StringUtil.urlEncode(page) - - if(pages.contains(page)){ - new Rendering(url, label) - } else { - new Rendering(url, label).withAttribute("class", "absent") - } - } catch { - case e: java.io.UnsupportedEncodingException => throw new IllegalStateException - } - } else { - super.render(node) - } - } -} - -class GitBucketVerbatimSerializer extends VerbatimSerializer { - def serialize(node: VerbatimNode, printer: Printer): Unit = { - printer.println.print("") - var text: String = node.getText - while (text.charAt(0) == '\n') { - printer.print("
") - text = text.substring(1) - } - printer.printEncoded(text) - printer.print("") - } -} - -class GitBucketHtmlSerializer( - markdown: String, - repository: RepositoryService.RepositoryInfo, - enableWikiLink: Boolean, - enableRefsLink: Boolean, - enableAnchor: Boolean, - enableTaskList: Boolean, - hasWritePermission: Boolean, - pages: List[String] - )(implicit val context: Context) extends ToHtmlSerializer( - new GitBucketLinkRender(context, repository, enableWikiLink, pages), - Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava - ) with LinkConverter with RequestCache { - - override protected def printImageTag(rendering: LinkRenderer.Rendering): Unit = { - printer.print("") - .print("\"").printEncoded(rendering.text).print("\"/") - } - - override protected def printLink(rendering: LinkRenderer.Rendering): Unit = { - printer.print('<').print('a') - printAttribute("href", fixUrl(rendering.href)) - for (attr <- rendering.attributes.asScala) { - printAttribute(attr.name, attr.value) - } - printer.print('>').print(rendering.text).print("") - } - - private def fixUrl(url: String, isImage: Boolean = false): String = { - if(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("/")){ - url - } else if(url.startsWith("#")){ - ("#" + GitBucketHtmlSerializer.generateAnchorName(url.substring(1))) - } else if(!enableWikiLink){ - if(context.currentPath.contains("/blob/")){ - url + (if(isImage) "?raw=true" else "") - } else if(context.currentPath.contains("/tree/")){ - val paths = context.currentPath.split("/") - val branch = if(paths.length > 3) paths.drop(4).mkString("/") else repository.repository.defaultBranch - repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url + (if(isImage) "?raw=true" else "") - } else { - val paths = context.currentPath.split("/") - val branch = if(paths.length > 3) paths.last else repository.repository.defaultBranch - repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url + (if(isImage) "?raw=true" else "") - } - } else { - repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/wiki/_blob/" + url - } - } - - private def printAttribute(name: String, value: String): Unit = { - printer.print(' ').print(name).print('=').print('"').print(value).print('"') - } - - private def printHeaderTag(node: HeaderNode): Unit = { - val tag = s"h${node.getLevel}" - val child = node.getChildren.asScala.headOption - val anchorName = child match { - case Some(x: AnchorLinkNode) => x.getName - case Some(x: TextNode) => x.getText - case _ => GitBucketHtmlSerializer.generateAnchorName(extractText(node)) // TODO - } - - printer.print(s"""<$tag class="markdown-head">""") - if(enableAnchor){ - printer.print(s"""""") - printer.print(s"""""") - } - child match { - case Some(x: AnchorLinkNode) => printer.print(x.getText) - case _ => visitChildren(node) - } - printer.print(s"") - } - - private def extractText(node: Node): String = { - val sb = new StringBuilder() - node.getChildren.asScala.map { - case x: TextNode => sb.append(x.getText) - case x: Node => sb.append(extractText(x)) - } - sb.toString() - } - - override def visit(node: HeaderNode): Unit = { - printHeaderTag(node) - } - - override def visit(node: TextNode): Unit = { - // convert commit id and username to link. - val t = if(enableRefsLink) convertRefsLinks(node.getText, repository, "issue:") else node.getText - - // convert task list to checkbox. - val text = if(enableTaskList) GitBucketHtmlSerializer.convertCheckBox(t, hasWritePermission) else t - - if (abbreviations.isEmpty) { - printer.print(text) - } else { - printWithAbbreviations(text) - } - } - - override def visit(node: VerbatimNode) { - val printer = new Printer() - val serializer = verbatimSerializers.get(VerbatimSerializer.DEFAULT) - serializer.serialize(node, printer) - val html = printer.getString - - // convert commit id and username to link. - val t = if(enableRefsLink) convertRefsLinks(html, repository, "issue:", escapeHtml = false) else html - - this.printer.print(t) - } - - override def visit(node: BulletListNode): Unit = { - if (printChildrenToString(node).contains("""class="task-list-item-checkbox" """)) { - printer.println().print("""") - } else { - printIndentedTag(node, "ul") - } - } - - override def visit(node: ListItemNode): Unit = { - if (printChildrenToString(node).contains("""class="task-list-item-checkbox" """)) { - printer.println() - printer.print("""
  • """) - visitChildren(node) - printer.print("
  • ") - } else { - printer.println() - printTag(node, "li") - } - } - - override def visit(node: ExpLinkNode) { - printLink(linkRenderer.render(node, printLinkChildrenToString(node))) - } - - def printLinkChildrenToString(node: SuperNode) = { - val priorPrinter = printer - printer = new Printer() - visitLinkChildren(node) - val result = printer.getString() - printer = priorPrinter - result - } - - def visitLinkChildren(node: SuperNode) { - import scala.collection.JavaConversions._ - node.getChildren.foreach(child => child match { - case node: ExpImageNode => visitLinkChild(node) - case node: SuperNode => visitLinkChildren(node) - case _ => child.accept(this) - }) - } - - def visitLinkChild(node: ExpImageNode) { - printer.print("\"").printEncoded(printChildrenToString(node)).print("\"/") - } -} +//class GitBucketLinkRender( +// context: Context, +// repository: RepositoryService.RepositoryInfo, +// enableWikiLink: Boolean, +// pages: List[String]) extends LinkRenderer with WikiService { +// +// override def render(node: WikiLinkNode): Rendering = { +// if(enableWikiLink){ +// try { +// val text = node.getText +// val (label, page) = if(text.contains('|')){ +// val i = text.indexOf('|') +// (text.substring(0, i), text.substring(i + 1)) +// } else { +// (text, text) +// } +// +// val url = repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/wiki/" + StringUtil.urlEncode(page) +// +// if(pages.contains(page)){ +// new Rendering(url, label) +// } else { +// new Rendering(url, label).withAttribute("class", "absent") +// } +// } catch { +// case e: java.io.UnsupportedEncodingException => throw new IllegalStateException +// } +// } else { +// super.render(node) +// } +// } +//} +// +//class GitBucketVerbatimSerializer extends VerbatimSerializer { +// def serialize(node: VerbatimNode, printer: Printer): Unit = { +// printer.println.print("") +// var text: String = node.getText +// while (text.charAt(0) == '\n') { +// printer.print("
    ") +// text = text.substring(1) +// } +// printer.printEncoded(text) +// printer.print("") +// } +//} +// +//class GitBucketHtmlSerializer( +// markdown: String, +// repository: RepositoryService.RepositoryInfo, +// enableWikiLink: Boolean, +// enableRefsLink: Boolean, +// enableAnchor: Boolean, +// enableTaskList: Boolean, +// hasWritePermission: Boolean, +// pages: List[String] +// )(implicit val context: Context) extends ToHtmlSerializer( +// new GitBucketLinkRender(context, repository, enableWikiLink, pages), +// Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava +// ) with LinkConverter with RequestCache { +// +// override protected def printImageTag(rendering: LinkRenderer.Rendering): Unit = { +// printer.print("") +// .print("\"").printEncoded(rendering.text).print("\"/") +// } +// +// override protected def printLink(rendering: LinkRenderer.Rendering): Unit = { +// printer.print('<').print('a') +// printAttribute("href", fixUrl(rendering.href)) +// for (attr <- rendering.attributes.asScala) { +// printAttribute(attr.name, attr.value) +// } +// printer.print('>').print(rendering.text).print("") +// } +// +// private def fixUrl(url: String, isImage: Boolean = false): String = { +// if(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("/")){ +// url +// } else if(url.startsWith("#")){ +// ("#" + GitBucketHtmlSerializer.generateAnchorName(url.substring(1))) +// } else if(!enableWikiLink){ +// if(context.currentPath.contains("/blob/")){ +// url + (if(isImage) "?raw=true" else "") +// } else if(context.currentPath.contains("/tree/")){ +// val paths = context.currentPath.split("/") +// val branch = if(paths.length > 3) paths.drop(4).mkString("/") else repository.repository.defaultBranch +// repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url + (if(isImage) "?raw=true" else "") +// } else { +// val paths = context.currentPath.split("/") +// val branch = if(paths.length > 3) paths.last else repository.repository.defaultBranch +// repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url + (if(isImage) "?raw=true" else "") +// } +// } else { +// repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/wiki/_blob/" + url +// } +// } +// +// private def printAttribute(name: String, value: String): Unit = { +// printer.print(' ').print(name).print('=').print('"').print(value).print('"') +// } +// +// private def printHeaderTag(node: HeaderNode): Unit = { +// val tag = s"h${node.getLevel}" +// val child = node.getChildren.asScala.headOption +// val anchorName = child match { +// case Some(x: AnchorLinkNode) => x.getName +// case Some(x: TextNode) => x.getText +// case _ => GitBucketHtmlSerializer.generateAnchorName(extractText(node)) // TODO +// } +// +// printer.print(s"""<$tag class="markdown-head">""") +// if(enableAnchor){ +// printer.print(s"""""") +// printer.print(s"""""") +// } +// child match { +// case Some(x: AnchorLinkNode) => printer.print(x.getText) +// case _ => visitChildren(node) +// } +// printer.print(s"") +// } +// +// private def extractText(node: Node): String = { +// val sb = new StringBuilder() +// node.getChildren.asScala.map { +// case x: TextNode => sb.append(x.getText) +// case x: Node => sb.append(extractText(x)) +// } +// sb.toString() +// } +// +// override def visit(node: HeaderNode): Unit = { +// printHeaderTag(node) +// } +// +// override def visit(node: TextNode): Unit = { +// // convert commit id and username to link. +// val t = if(enableRefsLink) convertRefsLinks(node.getText, repository, "issue:") else node.getText +// +// // convert task list to checkbox. +// val text = if(enableTaskList) GitBucketHtmlSerializer.convertCheckBox(t, hasWritePermission) else t +// +// if (abbreviations.isEmpty) { +// printer.print(text) +// } else { +// printWithAbbreviations(text) +// } +// } +// +// override def visit(node: VerbatimNode) { +// val printer = new Printer() +// val serializer = verbatimSerializers.get(VerbatimSerializer.DEFAULT) +// serializer.serialize(node, printer) +// val html = printer.getString +// +// // convert commit id and username to link. +// val t = if(enableRefsLink) convertRefsLinks(html, repository, "issue:", escapeHtml = false) else html +// +// this.printer.print(t) +// } +// +// override def visit(node: BulletListNode): Unit = { +// if (printChildrenToString(node).contains("""class="task-list-item-checkbox" """)) { +// printer.println().print("""") +// } else { +// printIndentedTag(node, "ul") +// } +// } +// +// override def visit(node: ListItemNode): Unit = { +// if (printChildrenToString(node).contains("""class="task-list-item-checkbox" """)) { +// printer.println() +// printer.print("""
  • """) +// visitChildren(node) +// printer.print("
  • ") +// } else { +// printer.println() +// printTag(node, "li") +// } +// } +// +// override def visit(node: ExpLinkNode) { +// printLink(linkRenderer.render(node, printLinkChildrenToString(node))) +// } +// +// def printLinkChildrenToString(node: SuperNode) = { +// val priorPrinter = printer +// printer = new Printer() +// visitLinkChildren(node) +// val result = printer.getString() +// printer = priorPrinter +// result +// } +// +// def visitLinkChildren(node: SuperNode) { +// import scala.collection.JavaConversions._ +// node.getChildren.foreach(child => child match { +// case node: ExpImageNode => visitLinkChild(node) +// case node: SuperNode => visitLinkChildren(node) +// case _ => child.accept(this) +// }) +// } +// +// def visitLinkChild(node: ExpImageNode) { +// printer.print("\"").printEncoded(printChildrenToString(node)).print("\"/") +// } +//} object GitBucketHtmlSerializer {