diff --git a/org.eclipse.tm4e.markdown/.classpath b/org.eclipse.tm4e.markdown/.classpath new file mode 100644 index 000000000..b495f5276 --- /dev/null +++ b/org.eclipse.tm4e.markdown/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.eclipse.tm4e.markdown/.gitignore b/org.eclipse.tm4e.markdown/.gitignore new file mode 100644 index 000000000..934e0e06f --- /dev/null +++ b/org.eclipse.tm4e.markdown/.gitignore @@ -0,0 +1,2 @@ +/bin +/target diff --git a/org.eclipse.tm4e.markdown/.project b/org.eclipse.tm4e.markdown/.project new file mode 100644 index 000000000..9898c5b37 --- /dev/null +++ b/org.eclipse.tm4e.markdown/.project @@ -0,0 +1,34 @@ + + + org.eclipse.tm4e.markdown + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.pde.PluginNature + + diff --git a/org.eclipse.tm4e.markdown/META-INF/MANIFEST.MF b/org.eclipse.tm4e.markdown/META-INF/MANIFEST.MF new file mode 100644 index 000000000..096b54812 --- /dev/null +++ b/org.eclipse.tm4e.markdown/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Bundle-SymbolicName: org.eclipse.tm4e.markdown;singleton:=true +Bundle-Version: 1.0.0.qualifier +Require-Bundle: org.eclipse.core.runtime +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: org.eclipse.tm4e.markdown, + org.eclipse.tm4e.markdown.marked +Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.tm4e.markdown/build.properties b/org.eclipse.tm4e.markdown/build.properties new file mode 100644 index 000000000..72298f605 --- /dev/null +++ b/org.eclipse.tm4e.markdown/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java/,\ + src/main/resources/ +bin.includes = META-INF/,\ + .,\ + plugin.properties diff --git a/org.eclipse.tm4e.markdown/plugin.properties b/org.eclipse.tm4e.markdown/plugin.properties new file mode 100644 index 000000000..430dd2428 --- /dev/null +++ b/org.eclipse.tm4e.markdown/plugin.properties @@ -0,0 +1,12 @@ +############################################################################### +# Copyright (c) 2015-2016 Angelo Zerr and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Angelo Zerr - Initial API and implementation +############################################################################### +pluginName=TextMate support in Eclipse IDE - Markdown +providerName=Angelo ZERR \ No newline at end of file diff --git a/org.eclipse.tm4e.markdown/pom.xml b/org.eclipse.tm4e.markdown/pom.xml new file mode 100644 index 000000000..fed8a7807 --- /dev/null +++ b/org.eclipse.tm4e.markdown/pom.xml @@ -0,0 +1,10 @@ + + 4.0.0 + org.eclipse.tm4e.markdown + eclipse-plugin + + org.eclipse + org.eclipse.tm4e + 1.0.0-SNAPSHOT + + diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/TMMarkdownPlugin.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/TMMarkdownPlugin.java new file mode 100644 index 000000000..ba1d20c31 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/TMMarkdownPlugin.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package org.eclipse.tm4e.markdown; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * OSGi Activator for TextMate Markdown bundle. + * + */ +public class TMMarkdownPlugin implements BundleActivator { + + public static final String PLUGIN_ID = "org.eclipse.tm4e.markdown"; + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + @Override + public void start(BundleContext bundleContext) throws Exception { + TMMarkdownPlugin.context = bundleContext; + } + + @Override + public void stop(BundleContext bundleContext) throws Exception { + TMMarkdownPlugin.context = null; + } +} \ No newline at end of file diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/BlockRules.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/BlockRules.java new file mode 100644 index 000000000..394eaa7e9 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/BlockRules.java @@ -0,0 +1,103 @@ +package org.eclipse.tm4e.markdown.marked; + +import java.util.regex.Matcher; + +public class BlockRules { + + private static final String _tag = "(?!(?:" + "a|em|strong|small|s|cite|q|dfn|abbr|data|time|code" + + "|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo" + + "|span|br|wbr|ins|del|img)\\b)\\w+(?!:\\/|[^\\w\\s@]*@)\\b"; + + public static BlockRules normal = normal(); + public static BlockRules gfm = gfm(); + public static BlockRules tables = tables(); + + public final RegExp newline; + public final RegExp code; + public final RegExp fences; + public final RegExp hr; + public final RegExp heading; + public final RegExp nptable; + public final RegExp lheading; + public final RegExp blockquote; + public final RegExp list; + public final RegExp html; + public final RegExp def; + public final RegExp table; + public final RegExp paragraph; + public final RegExp text; + public final RegExp bullet; + public final RegExp item; + + public BlockRules(RegExp newline, RegExp code, RegExp fences, RegExp hr, RegExp heading, RegExp nptable, + RegExp lheading, RegExp blockquote, RegExp list, RegExp html, RegExp def, RegExp table, RegExp paragraph, + RegExp text, RegExp bullet, RegExp item) { + this.newline = newline; + this.code = code; + this.fences = fences; + this.hr = hr; + this.heading = heading; + this.nptable = nptable; + this.lheading = lheading; + this.blockquote = blockquote; + this.list = list; + this.html = html; + this.def = def; + this.table = table; + this.paragraph = paragraph; + this.text = text; + this.bullet = bullet; + this.item = item; + } + + private static BlockRules block() { + RegExp newline = new RegExp("^\\n+"); + RegExp code = new RegExp("^( {4}[^\\n]+\\n*)+/"); + RegExp fences = new RegExp(""); + RegExp hr = new RegExp("^( *[-*_]){3,} *(?:\\n+|$)"); + RegExp heading = new RegExp("^ *(#{1,6}) *([^\\n]+?) *#* *(?:\\n+|$)"); + RegExp nptable = new RegExp(""); + RegExp lheading = new RegExp("^([^\\n]+)\\n *(=|-){2,} *(?:\\n+|$)"); + RegExp blockquote = new RegExp("^( *>[^\\n]+(\\n(?!def)[^\\n]+)*\\n*)+"); + RegExp list = new RegExp("^( *)(bull) [\\s\\S]+?(?:hr|def|\\n{2,}(?! )(?!\\1bull )\\n*|\\s*$)"); + RegExp html = new RegExp("^ *(?:comment *(?:\\n|\\s*$)|closed *(?:\\n{2,}|\\s*$)|closing *(?:\\n{2,}|\\s*$))"); + RegExp def = new RegExp("^ *\\[([^\\]]+)\\]: *]+)>?(?: +[\"(]([^\\n]+)[\")])? *(?:\\n+|$)"); + RegExp table = RegExp.noop(); + RegExp paragraph = new RegExp("^((?:[^\\n]+\\n?(?!hr|heading|lheading|blockquote|tag|def))+)\\n*"); + RegExp text = new RegExp("^[^\\n]+"); + RegExp bullet = new RegExp("(?:[*+-]|\\d+\\.)"); + RegExp item = new RegExp("^( *)(bull) [^\\n]*(?:\\n(?!\\1bull )[^\\n]*)*"); + + item.replaceAll("bull", bullet); + list.replaceAll("bull", bullet).replace("hr", "\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))").replace("def", + "\\n+(?=" + def.source + ")"); + blockquote.replace("def", def); + paragraph.replace("hr", hr).replace("heading", heading).replace("lheading", lheading) + .replace("blockquote", blockquote).replace("tag", "<" + _tag).replace("def", def); + return new BlockRules(newline, code, fences, hr, heading, nptable, lheading, blockquote, list, html, def, table, + paragraph, text, bullet, item); + } + + private static BlockRules normal() { + return block(); + } + + private static BlockRules gfm() { + BlockRules gfm = normal(); + gfm.fences.source = "^ *(`{3,}|~{3,})[ \\.]*(\\S+)? *\\n([\\s\\S]*?)\\s*\\1 *(?:\\n+|$)"; + // gfm.paragraph.source = "^"; + gfm.heading.source = "^ *(#{1,6}) +([^\\n]+?) *#* *(?:\\n+|$)"; + String pattern = "(?!" + gfm.fences.source.replaceFirst("\\\\1", "\\\\2") + "|" + + gfm.list.source.replaceFirst("\\\\1", "\\\\3") + "|"; + //pattern = pattern.replaceAll("\\\"", "\\\\\""); + //pattern = pattern.replaceAll("[$]", "\\\\\\$"); + gfm.paragraph.replace("\\(\\?\\!", pattern); + return gfm; + } + + private static BlockRules tables() { + BlockRules tables = gfm(); + + return tables; + } +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/HTMLRenderer.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/HTMLRenderer.java new file mode 100644 index 000000000..481ced0d8 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/HTMLRenderer.java @@ -0,0 +1,155 @@ +package org.eclipse.tm4e.markdown.marked; + +import static org.eclipse.tm4e.markdown.marked.Helpers.escape; + +public class HTMLRenderer implements IRenderer { + + private final StringBuilder html; + + public HTMLRenderer() { + this.html = new StringBuilder(); + } + + @Override + public void code(String code, String lang, boolean escaped) { + if (lang == null) { + html.append("
");
+			html.append(escaped ? code : escape(code, true));
+			html.append("\n
"); + } else { + html.append("
");
+			html.append(escaped ? code : escape(code, true));
+			html.append("\n
"); + } + } + + @Override + public void blockquote(String quote) { + // TODO Auto-generated method stub + + } + + @Override + public void html(String html) { + // TODO Auto-generated method stub + + } + + @Override + public void heading(String text, int level, String raw) { + html.append(""); + html.append(text); + html.append("\n"); + } + + @Override + public void hr() { + html.append("
\n"); + } + + @Override + public void list(String body, boolean ordered) { + // TODO Auto-generated method stub + + } + + @Override + public void listitem(String text) { + // TODO Auto-generated method stub + + } + + @Override + public void startParagraph() { + html.append("

"); + } + + @Override + public void endParagraph() { + html.append("

\n"); + } + + @Override + public void table(String header, String body) { + // TODO Auto-generated method stub + + } + + @Override + public void tablerow(String content) { + // TODO Auto-generated method stub + + } + + @Override + public void tablecell(String content, String flags) { + // TODO Auto-generated method stub + + } + + @Override + public void startEm() { + html.append(""); + } + + @Override + public void endEm() { + html.append(""); + } + + @Override + public void startStrong() { + html.append(""); + } + + @Override + public void endStrong() { + html.append(""); + } + + @Override + public void codespan(String text) { + html.append(""); + html.append(text); + html.append(""); + } + + @Override + public void br() { + // TODO Auto-generated method stub + + } + + @Override + public void del(String text) { + // TODO Auto-generated method stub + + } + + @Override + public void link(String href, String title, String text) { + // TODO Auto-generated method stub + + } + + @Override + public void image(String href, String title, String text) { + // TODO Auto-generated method stub + + } + + @Override + public void text(String text) { + html.append(text); + } + + @Override + public String toString() { + return html.toString(); + } +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Helpers.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Helpers.java new file mode 100644 index 000000000..4646fb0a6 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Helpers.java @@ -0,0 +1,22 @@ +package org.eclipse.tm4e.markdown.marked; + +public class Helpers { + + public static String escape(String html) { + return escape(html, false); + } + + public static String escape(String html, boolean encode) { + return html + .replaceAll(!encode ? "&(?!#?\\w+;)" : "&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("\"", """) + .replaceAll("'", "'"); + } + + public static boolean isEmpty(String s) { + return s == null || s.length() < 1; + } + +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/IRenderer.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/IRenderer.java new file mode 100644 index 000000000..f08dc0403 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/IRenderer.java @@ -0,0 +1,51 @@ +package org.eclipse.tm4e.markdown.marked; + +public interface IRenderer { + + void code(String code, String lang, boolean escaped); + + void blockquote(String quote); + + void html(String html); + + void heading(String text, int level, String raw); + + void hr(); + + void list(String body, boolean ordered); + + void listitem(String text); + + void startParagraph(); + + void endParagraph(); + + void table(String header, String body); + + void tablerow(String content); + + void tablecell(String content, String flags); + + void startEm(); + + void endEm(); + + void startStrong(); + + void endStrong(); + + void codespan(String text); + + void br(); + + void del(String text); + + void link(String href, String title, String text); + + void image(String href, String title, String text); + + void text(String text); + + + +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/InlineLexer.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/InlineLexer.java new file mode 100644 index 000000000..1ad321237 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/InlineLexer.java @@ -0,0 +1,79 @@ +package org.eclipse.tm4e.markdown.marked; + +import static org.eclipse.tm4e.markdown.marked.Helpers.escape; +import static org.eclipse.tm4e.markdown.marked.Helpers.isEmpty; + +import java.util.regex.Matcher; +public class InlineLexer { + + private Options options; + private InlineRules rules; + private final IRenderer renderer; + + public InlineLexer(Object links, Options options, IRenderer renderer) { + this.options = options != null ? options : Options.DEFAULTS; + // this.links = links; + this.rules = InlineRules.normal; + this.renderer = renderer; + // this.renderer = this.options.renderer || new Renderer; + // this.renderer.options = this.options; + + // if (!this.links) { + // throw new + // Error('Tokens array requires a `links` property.'); + // } + + if (this.options.gfm) { + if (this.options.breaks) { + this.rules = InlineRules.breaks; + } else { + this.rules = InlineRules.gfm; + } + } else if (this.options.pedantic) { + this.rules = InlineRules.pedantic; + } + } + + public void output(String src) { + Matcher cap = null; + while (!isEmpty(src)) { + + // strong + if ((cap = this.rules.strong.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + this.renderer.startStrong(); + this.output(!isEmpty(cap.group(2)) ? cap.group(2) : cap.group(1)); + this.renderer.endStrong(); + continue; + } + + // em + if ((cap = this.rules.em.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + this.renderer.startEm(); + this.output(!isEmpty(cap.group(2)) ? cap.group(2) : cap.group(1)); + this.renderer.endEm(); + continue; + } + + // code + if ((cap = this.rules.code.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + this.renderer.codespan(escape(cap.group(2), true)); + continue; + } + + // text + if ((cap = this.rules.text.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + this.renderer.text(escape(this.smartypants(cap.group(0)))); + continue; + } + } + } + + private String smartypants(String text) { + return text; + } + +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/InlineRules.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/InlineRules.java new file mode 100644 index 000000000..e6054841c --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/InlineRules.java @@ -0,0 +1,94 @@ +package org.eclipse.tm4e.markdown.marked; + +public class InlineRules { + + private static final String INLINE_INSIDE = "(?:\\[[^\\]]*\\]|[^\\[\\]]|\\](?=[^\\[]*\\]))*"; + private static final String INLINE_HREF = "\\s*?(?:\\s+['\"]([\\s\\S]*?)['\"])?\\s*"; + + public static final InlineRules normal = normal(); + + public static final InlineRules pedantic = pedantic(); + + public static final InlineRules gfm = gfm(); + + public static final InlineRules breaks = breaks(); + + public final RegExp escape; + public final RegExp autolink; + public final RegExp url; + public final RegExp tag; + public final RegExp link; + public final RegExp reflink; + public final RegExp nolink; + public final RegExp strong; + public final RegExp em; + public final RegExp code; + public final RegExp br; + public final RegExp del; + public final RegExp text; + + public InlineRules(RegExp escape, RegExp autolink, RegExp url, RegExp tag, RegExp link, RegExp reflink, + RegExp nolink, RegExp strong, RegExp em, RegExp code, RegExp br, RegExp del, RegExp text) { + this.escape = escape; + this.autolink = autolink; + this.url = url; + this.tag = tag; + this.link = link; + this.reflink = reflink; + this.nolink = nolink; + this.strong = strong; + this.em = em; + this.code = code; + this.br = br; + this.del = del; + this.text = text; + } + + private static InlineRules inline() { + RegExp escape = new RegExp("^\\\\([\\\\`*{}\\[\\]()#+\\-.!_>])"); + RegExp autolink = new RegExp("^<([^ >]+(@|:\\/)[^ >]+)>"); + RegExp url = RegExp.noop(); + RegExp tag = new RegExp("^|^<\\/?\\w+(?:\"[^\"]*\"|'[^']*'|[^'\">])*?>"); + RegExp link = new RegExp("^!?\\[(inside)\\]\\(href\\)"); + RegExp reflink = new RegExp("^!?\\[(inside)\\]\\s*\\[([^\\]]*)\\]"); + RegExp nolink = new RegExp("^!?\\[((?:\\[[^\\]]*\\]|[^\\[\\]])*)\\]"); + RegExp strong = new RegExp("^__([\\s\\S]+?)__(?!_)|^\\*\\*([\\s\\S]+?)\\*\\*(?!\\*)"); + RegExp em = new RegExp("^\\b_((?:[^_]|__)+?)_\\b|^\\*((?:\\*\\*|[\\s\\S])+?)\\*(?!\\*)"); + RegExp code = new RegExp("^(`+)\\s*([\\s\\S]*?[^`])\\s*\\1(?!`)"); + RegExp br = new RegExp("^ {2,}\\n(?!\\s*$)"); + RegExp del = RegExp.noop(); + RegExp text = new RegExp("^[\\s\\S]+?(?=[\\\\ 1) { + this.tokens.add(new Token(TokenType.space)); + } + } + + // code + // if ((cap = this.rules.code.exec(src)) != null) { + // src = src.substring(cap.group(0).length()); + // cap = cap.group(0).matches("^ {4}", ""); + // String text = !this.options.pedantic + // ? cap.replace(/\n+$/, '') + // : cap; + // this.tokens.add(new Token(TokenType.type)); + // continue; + // } + + // fences (gfm) + if ((cap = this.rules.fences.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + String lang = cap.group(2); + String text = !isEmpty(cap.group(3)) ? cap.group(3) : ""; + this.tokens.add(new Token(TokenType.code, lang, text)); + continue; + } + + // heading + if ((cap = this.rules.heading.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + String text = cap.group(2); + int depth = cap.group(1).length(); + this.tokens.add(new Token(TokenType.heading, text, depth)); + continue; + } + + // table no leading pipe (gfm) + // TODO + + // lheading + if ((cap = this.rules.lheading.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + String text = cap.group(1); + int depth = cap.group(2).equals("=") ? 1 : 2; + this.tokens.add(new Token(TokenType.heading, text, depth)); + continue; + } + + // hr + if ((cap = this.rules.hr.exec(src)) != null) { + src = src.substring(cap.group(0).length()); + this.tokens.add(new Token(TokenType.hr)); + continue; + } + + // top-level paragraph + if (top && ((cap = this.rules.paragraph.exec(src)) != null)) { + src = src.substring(cap.group(0).length()); + String text = cap.group(1).charAt(cap.group(1).length() - 1) == '\n' ? cap.group(1) : cap.group(1); + this.tokens.add(new Token(TokenType.paragraph, text)); + continue; + } + } + return this.tokens; + } + +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Marked.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Marked.java new file mode 100644 index 000000000..76cc646fe --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Marked.java @@ -0,0 +1,13 @@ +package org.eclipse.tm4e.markdown.marked; + +public class Marked { + + public static IRenderer parse(String src) { + return process(src, null); + } + + public static IRenderer process(String src, Options opt) { + + return Parser.parse(Lexer.lex(src, opt), opt); + } +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Options.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Options.java new file mode 100644 index 000000000..229594d20 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Options.java @@ -0,0 +1,10 @@ +package org.eclipse.tm4e.markdown.marked; + +public class Options { + + public static final Options DEFAULTS = new Options(); + public boolean gfm = true; + public boolean breaks; + public boolean pedantic; + public boolean tables; +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Parser.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Parser.java new file mode 100644 index 000000000..201c71445 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Parser.java @@ -0,0 +1,70 @@ +package org.eclipse.tm4e.markdown.marked; + +public class Parser { + + private Tokens tokens; + private Token token; + private Options options; + private InlineLexer inline; + private IRenderer renderer; + + public Parser(Options options) { + this.tokens = new Tokens(); + this.token = null; + this.options = options != null ? options : Options.DEFAULTS; + this.renderer = new HTMLRenderer(); + } + + public static IRenderer parse(Tokens src, Options options) { + Parser parser = new Parser(options); + return parser.parse(src); + } + + private IRenderer parse(Tokens src) { + this.inline = new InlineLexer(src.links, this.options, this.renderer); + this.tokens = src.reverse(); + + // var out = ''; + while (this.next()) { + // out += this.tok(); + this.tok(); + } + + return renderer; + } + + /** + * Next Token + */ + private boolean next() { + return ((this.token = this.tokens.pop()) != null); + } + + /** + * Parse Current Token + */ + private void tok() { + switch (this.token.type) { + case space: + break; + case hr: + this.renderer.hr(); + break; + case heading: + // this.renderer.heading(this.inline.output(this.token.text), + // this.token.depth, this.token.text); + this.renderer.heading(this.token.text, this.token.depth, this.token.text); + break; + case code: + this.renderer.code(this.token.text, this.token.lang, this.token.escaped); + break; + case paragraph: + this.renderer.startParagraph(); + this.inline.output(this.token.text); + this.renderer.endParagraph(); + break; + } + + } + +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/RegExp.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/RegExp.java new file mode 100644 index 000000000..05e65b599 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/RegExp.java @@ -0,0 +1,57 @@ +package org.eclipse.tm4e.markdown.marked; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RegExp { + + protected String source; + private Pattern pattern; + + public RegExp(String source) { + this.source = source; + } + + public Matcher exec(String s) { + if (source == null) { + return null; + } + if (pattern == null) { + pattern = Pattern.compile(source); + } + Matcher matcher = pattern.matcher(s); + if (matcher.find()) { + return matcher; + } + return null; + } + + public RegExp replace(String name, RegExp val) { + return replace(name, val.source); + } + + public RegExp replace(String name, String val) { + if (name == null) + return new RegExp(this.source); + val = val.replaceAll("(^|[^\\[])\\^", "$1"); + this.source = this.source.replaceFirst(name, Matcher.quoteReplacement(val)); + return this; + } + + public RegExp replaceAll(String name, RegExp val) { + return replaceAll(name, val.source); + } + + public RegExp replaceAll(String name, String val) { + if (name == null) + return new RegExp(this.source); + val = val.replaceAll("(^|[^\\[])\\^", "$1"); + this.source = this.source.replaceAll(name, Matcher.quoteReplacement(val)); + return this; + } + + public static final RegExp noop() { + return new RegExp(null); + }; + +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Token.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Token.java new file mode 100644 index 000000000..26124c31b --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Token.java @@ -0,0 +1,34 @@ +package org.eclipse.tm4e.markdown.marked; + +public class Token { + + public final TokenType type; + public final String text; + public final int depth; + public final String lang; + public final boolean escaped; + + public Token(TokenType type) { + this(type, null); + } + + public Token(TokenType type, String text) { + this(type, text, -1); + } + + public Token(TokenType type, String text, int depth) { + this(type, text, depth, null, false); + } + + public Token(TokenType type, String lang, String text) { + this(type, text, -1, lang, false); + } + + private Token(TokenType type, String text, int depth, String lang, boolean escaped) { + this.type = type; + this.text = text; + this.depth = depth; + this.lang = lang; + this.escaped = escaped; + } +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/TokenType.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/TokenType.java new file mode 100644 index 000000000..35b54e728 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/TokenType.java @@ -0,0 +1,6 @@ +package org.eclipse.tm4e.markdown.marked; + +public enum TokenType { + + space, hr, heading, code, table, blockquote_start, blockquote_end, list_start, list_end, list_item_start, list_item_end, loose_item_start, html, paragraph, text; +} diff --git a/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Tokens.java b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Tokens.java new file mode 100644 index 000000000..658ff5980 --- /dev/null +++ b/org.eclipse.tm4e.markdown/src/main/java/org/eclipse/tm4e/markdown/marked/Tokens.java @@ -0,0 +1,22 @@ +package org.eclipse.tm4e.markdown.marked; + +import java.util.ArrayList; +import java.util.Collections; + +public class Tokens extends ArrayList { + + public Object links; + + public Tokens reverse() { + Collections.reverse(this); + return this; + } + + public Token pop() { + if (super.isEmpty()) { + return null; + } + return super.remove(super.size() - 1); + } + +} diff --git a/org.eclipse.tm4e.markdown/src/main/resources/.gitkeep b/org.eclipse.tm4e.markdown/src/main/resources/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/pom.xml b/pom.xml index 57f983ccb..0f4644d01 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ org.eclipse.tm4e.core org.eclipse.tm4e.core.tests org.eclipse.tm4e.ui + org.eclipse.tm4e.markdown org.eclipse.tm4e.samples tm-feature org.eclipse.tm4e.repository