Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 30 additions & 2 deletions docs/interpreter/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,42 @@ limitations under the License.

## Overview
[Markdown](http://daringfireball.net/projects/markdown/) is a plain text formatting syntax designed so that it can be converted to HTML.
Apache Zeppelin uses markdown4j. For more examples and extension support, please checkout [here](https://code.google.com/p/markdown4j/).
Apache Zeppelin uses [markdown4j](https://github.com/jdcasey/markdown4j) and [pegdown](https://github.com/sirthias/pegdown) as markdown parsers.

In Zeppelin notebook, you can use ` %md ` in the beginning of a paragraph to invoke the Markdown interpreter and generate static html from Markdown plain text.

In Zeppelin, Markdown interpreter is enabled by default.
In Zeppelin, Markdown interpreter is enabled by default and uses the [markdown4j](https://github.com/jdcasey/markdown4j) parser.

<img src="../assets/themes/zeppelin/img/docs-img/markdown-interpreter-setting.png" width="60%" />

## Configuration
<table class="table-configuration">
<tr>
<th>Name</th>
<th>Default Value</th>
<th>Description</th>
</tr>
<tr>
<td>markdown.parser.type</td>
<td>markdown4j</td>
<td>Markdown Parser Type. <br/> Available values: markdown4j, pegdown.</td>
</tr>
</table>

## Example

The following example demonstrates the basic usage of Markdown in a Zeppelin notebook.

<img src="../assets/themes/zeppelin/img/docs-img/markdown-example.png" width="70%" />

### Markdown4j Parser

`markdown4j` parser provides [YUML](http://yuml.me/) and [Websequence](https://www.websequencediagrams.com/) extensions

<img src="../assets/themes/zeppelin/img/docs-img/markdown-example-markdown4j-parser.png" width="70%" />

### Pegdown Parser

`pegdown` parser provides github flavored markdown.

<img src="../assets/themes/zeppelin/img/docs-img/markdown-example-pegdown-parser.png" width="70%" />
10 changes: 8 additions & 2 deletions markdown/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,21 @@
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<dependency>
<groupId>org.commonjava.googlecode.markdown4j</groupId>
<artifactId>markdown4j</artifactId>
<version>2.2-cj-1.0</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<groupId>org.pegdown</groupId>
<artifactId>pegdown</artifactId>
<version>1.6.0</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.zeppelin.markdown;

import org.markdown4j.Markdown4jProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/** Markdown Parser using markdown4j processor . */
public class Markdown4jParser implements MarkdownParser {
private Markdown4jProcessor processor;

public Markdown4jParser() {
processor = new Markdown4jProcessor();
}

@Override
public String render(String markdownText) {
String html = "";

try {
html = processor.process(markdownText);
} catch (IOException e) {
// convert checked exception to non-checked exception
throw new RuntimeException(e);
}

return html;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,78 @@

import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterPropertyBuilder;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.apache.zeppelin.interpreter.InterpreterUtils;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.scheduler.Scheduler;
import org.apache.zeppelin.scheduler.SchedulerFactory;
import org.markdown4j.Markdown4jProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Markdown interpreter for Zeppelin.
*/
public class Markdown extends Interpreter {
private Markdown4jProcessor md;
static final Logger LOGGER = LoggerFactory.getLogger(Markdown.class);
/** MarkdownInterpreter interpreter for Zeppelin. */
public class MarkdownInterpreter extends Interpreter {
private static final Logger LOGGER = LoggerFactory.getLogger(MarkdownInterpreter.class);

private MarkdownParser parser;

/** Markdown Parser Type. */
public enum MarkdownParserType {
PEGDOWN {
@Override
public String toString() {
return PARSER_TYPE_PEGDOWN;
}
},

MARKDOWN4j {
@Override
public String toString() {
return PARSER_TYPE_MARKDOWN4J;
}
}
}

public static final String MARKDOWN_PARSER_TYPE = "markdown.parser.type";
public static final String PARSER_TYPE_PEGDOWN = "pegdown";
public static final String PARSER_TYPE_MARKDOWN4J = "markdown4j";

public Markdown(Properties property) {
public MarkdownInterpreter(Properties property) {
super(property);
}

public static MarkdownParser createMarkdownParser(String parserType) {
LOGGER.debug("Creating " + parserType + " markdown interpreter");

if (MarkdownParserType.PEGDOWN.toString().equals(parserType)) {
return new PegdownParser();
} else {
/** default parser. */
return new Markdown4jParser();
}
}

@Override
public void open() {
md = new Markdown4jProcessor();
String parserType = getProperty(MARKDOWN_PARSER_TYPE);
parser = createMarkdownParser(parserType);
}

@Override
public void close() {}

@Override
public InterpreterResult interpret(String st, InterpreterContext interpreterContext) {
public InterpreterResult interpret(String markdownText, InterpreterContext interpreterContext) {
String html;

try {
html = md.process(st);
} catch (IOException | java.lang.RuntimeException e) {
LOGGER.error("Exception in Markdown while interpret ", e);
html = parser.render(markdownText);
} catch (RuntimeException e) {
LOGGER.error("Exception in MarkdownInterpreter while interpret ", e);
return new InterpreterResult(Code.ERROR, InterpreterUtils.getMostRelevantMessage(e));
}

return new InterpreterResult(Code.SUCCESS, "%html " + html);
}

Expand All @@ -79,8 +113,8 @@ public int getProgress(InterpreterContext context) {

@Override
public Scheduler getScheduler() {
return SchedulerFactory.singleton().createOrGetParallelScheduler(
Markdown.class.getName() + this.hashCode(), 5);
return SchedulerFactory.singleton()
.createOrGetParallelScheduler(MarkdownInterpreter.class.getName() + this.hashCode(), 5);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.zeppelin.markdown;

/** Abstract Markdown Parser. */
public interface MarkdownParser {
String render(String markdownText);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.zeppelin.markdown;

import org.pegdown.Extensions;
import org.pegdown.PegDownProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Markdown Parser using pegdown processor. */
public class PegdownParser implements MarkdownParser {
private PegDownProcessor processor;

public PegdownParser() {
int pegdownOptions = Extensions.ALL_WITH_OPTIONALS - Extensions.ANCHORLINKS;
int parsingTimeoutAsMillis = 5000;
processor = new PegDownProcessor(pegdownOptions, parsingTimeoutAsMillis);
}

@Override
public String render(String markdownText) {
String html = "";
String parsed = processor.markdownToHtml(markdownText);

if (null == parsed) {
throw new RuntimeException("Cannot parse markdown text to HTML using pegdown");
}

html = wrapWithMarkdownClassDiv(parsed);
return html;
}

/** wrap with markdown class div to styling DOM using css. */
public static String wrapWithMarkdownClassDiv(String html) {
return new StringBuilder()
.append("<div class=\"markdown-body\">\n")
.append(html)
.append("\n</div>")
.toString();
}
}
11 changes: 9 additions & 2 deletions markdown/src/main/resources/interpreter-setting.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
{
"group": "md",
"name": "md",
"className": "org.apache.zeppelin.markdown.Markdown",
"properties": null
"className": "org.apache.zeppelin.markdown.MarkdownInterpreter",
"properties": {
"markdown.parser.type": {
"envName": "MARKDOWN_PARSER_TYPE",
"propertyName": "markdown.parser.type",
"defaultValue": "markdown4j",
"description": "Markdown Parser Type. Available values: markdown4j, pegdown. Default = markdown4j"
}
}
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,35 @@

package org.apache.zeppelin.markdown;

import static org.junit.Assert.assertEquals;

import java.util.Properties;

import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.markdown.Markdown;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class MarkdownTest {
import java.util.Properties;

import static org.junit.Assert.assertEquals;

public class Markdown4jParserTest {

@Before
public void setUp() throws Exception {
}
MarkdownInterpreter md;

@After
public void tearDown() throws Exception {
}
@Before
public void setUp() throws Exception {
Properties props = new Properties();
props.put(MarkdownInterpreter.MARKDOWN_PARSER_TYPE, MarkdownInterpreter.PARSER_TYPE_MARKDOWN4J);
md = new MarkdownInterpreter(props);
md.open();
}

@Test
public void test() {
Markdown md = new Markdown(new Properties());
md.open();
InterpreterResult result = md.interpret("This is ~~deleted~~ text", null);
assertEquals("<p>This is <s>deleted</s> text</p>\n", result.message());
}
@After
public void tearDown() throws Exception {
md.close();
}

@Test
public void testStrikethrough() {
InterpreterResult result = md.interpret("This is ~~deleted~~ text", null);
assertEquals("<p>This is <s>deleted</s> text</p>\n", result.message());
}
}
Loading