diff --git a/README.md b/README.md
index bb8feff7ba..0007fa9f61 100644
--- a/README.md
+++ b/README.md
@@ -75,10 +75,11 @@ marked has a few different switches which change behavior.
- __smartLists__: Use smarter list behavior than the original markdown.
Disabled by default. May eventually be default with the old behavior
moved into `pedantic`.
-- __langPrefix__: Set the prefix for code block classes. Defaults to `lang-`.
## Usage
+A simple overview of the usage:
+
``` js
// Set default options
marked.setOptions({
@@ -87,18 +88,53 @@ marked.setOptions({
breaks: false,
pedantic: false,
sanitize: true,
- smartLists: true,
- langPrefix: 'language-',
- highlight: function(code, lang) {
- if (lang === 'js') {
- return highlighter.javascript(code);
- }
- return code;
- }
+ smartLists: true
});
console.log(marked('i am using __markdown__.'));
```
+### High level
+
+You can customize the result with a customized renderer.
+
+``` js
+var renderer = new marked.Renderer()
+
+renderer.header = function(text, level) {
+ return '
' + text + '
'
+}
+
+var parse = function(src, options) {
+ options = options || {};
+ return marked.parser(marked.lexer(src, options), options, renderer);
+}
+
+console.log(parse('# h1'))
+```
+
+The renderer API:
+
+```
+blockcode: function(code, lang)
+blockquote: function(text)
+blockhtml: function(html)
+
+header: function(text, level)
+paragraph: function(text)
+
+hrule: function()
+
+list: function(contents, isOrdered)
+listitem: function(text)
+
+table: function(header, body)
+tablerow: function(content)
+tablecell: function(text, flags)
+// flags: {header: false, align: 'center'}
+```
+
+### Pro level
+
You also have direct access to the lexer and parser if you so desire.
``` js
diff --git a/lib/marked.js b/lib/marked.js
index e71e19dbd4..ec3c90169a 100644
--- a/lib/marked.js
+++ b/lib/marked.js
@@ -742,13 +742,77 @@ InlineLexer.prototype.mangle = function(text) {
return out;
};
+/**
+ * Renderer
+ */
+
+function Renderer(options) {
+ this.options = options || {};
+}
+Renderer.prototype.blockcode = function(code, lang) {
+ if (!lang) {
+ return '' + escape(code, true) + '\n
';
+ }
+ return ''
+ + escape(code)
+ + '\n
\n';
+};
+Renderer.prototype.blockquote = function(quote) {
+ return '\n' + quote + '
\n';
+};
+Renderer.prototype.blockhtml = function(html) {
+ return html;
+};
+Renderer.prototype.header = function(text, level) {
+ return '' + text + '\n';
+};
+Renderer.prototype.hrule = function() {
+ return '
\n';
+};
+Renderer.prototype.list = function(body, ordered) {
+ var type = ordered ? 'ol' : 'ul';
+ return '<' + type + '>\n' + body + '' + type + '>\n';
+};
+Renderer.prototype.listitem = function(text) {
+ return '' + text + '\n';
+};
+Renderer.prototype.paragraph = function(text) {
+ return '' + text + '
\n';
+};
+Renderer.prototype.table = function(header, body) {
+ return '\n'
+ + '\n'
+ + header
+ + '\n'
+ + '\n'
+ + body
+ + '\n'
+ + '
\n';
+};
+Renderer.prototype.tablerow = function(content) {
+ return '\n' + content + '
\n';
+};
+Renderer.prototype.tablecell = function(content, flags) {
+ var type = flags.header ? 'th' : 'td';
+ var tag = flags.align
+ ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
+ return tag + content + '' + type + '>\n';
+};
+
/**
* Parsing & Compiling
*/
-function Parser(options) {
+function Parser(options, renderer) {
this.tokens = [];
this.token = null;
+ if (options instanceof Renderer) {
+ options = null;
+ renderer = options;
+ }
+ this.renderer = renderer || new Renderer();
this.options = options || marked.defaults;
}
@@ -756,8 +820,8 @@ function Parser(options) {
* Static Parse Method
*/
-Parser.parse = function(src, options) {
- var parser = new Parser(options);
+Parser.parse = function(src, options, renderer) {
+ var parser = new Parser(options, renderer);
return parser.parse(src);
};
@@ -812,82 +876,60 @@ Parser.prototype.parseText = function() {
*/
Parser.prototype.tok = function() {
+ var renderer = this.renderer;
+
switch (this.token.type) {
case 'space': {
return '';
}
case 'hr': {
- return '
\n';
+ return renderer.hrule();
}
case 'heading': {
- return ''
- + this.inline.output(this.token.text)
- + '\n';
+ return renderer.header(
+ this.inline.output(this.token.text),
+ this.token.depth
+ );
}
case 'code': {
- if (this.options.highlight) {
- var code = this.options.highlight(this.token.text, this.token.lang);
- if (code != null && code !== this.token.text) {
- this.token.escaped = true;
- this.token.text = code;
- }
- }
-
- if (!this.token.escaped) {
- this.token.text = escape(this.token.text, true);
- }
-
- return ''
- + this.token.text
- + '
\n';
+ return renderer.blockcode(this.token.text, this.token.lang);
}
case 'table': {
- var body = ''
- , heading
+ var header = ''
+ , body = ''
, i
, row
, cell
+ , flags
, j;
// header
- body += '\n\n';
+ cell = '';
for (i = 0; i < this.token.header.length; i++) {
- heading = this.inline.output(this.token.header[i]);
- body += this.token.align[i]
- ? '' + heading + ' | \n'
- : '' + heading + ' | \n';
+ // render cell
+ flags = {header: true, align: this.token.align[i]};
+ cell += renderer.tablecell(
+ this.inline.output(this.token.header[i]),
+ {header: true, align: this.token.align[i]}
+ );
+ // render row
}
- body += '
\n\n';
+ header += renderer.tablerow(cell);
- // body
- body += '\n'
for (i = 0; i < this.token.cells.length; i++) {
row = this.token.cells[i];
- body += '\n';
+
+ cell = '';
for (j = 0; j < row.length; j++) {
- cell = this.inline.output(row[j]);
- body += this.token.align[j]
- ? '' + cell + ' | \n'
- : '' + cell + ' | \n';
+ cell += renderer.tablecell(
+ this.inline.output(row[j]),
+ {header: false, align: this.token.align[j]}
+ );
}
- body += '
\n';
- }
- body += '\n';
- return '\n';
+ body += renderer.tablerow(cell);
+ }
+ return renderer.table(header, body);
}
case 'blockquote_start': {
var body = '';
@@ -896,25 +938,16 @@ Parser.prototype.tok = function() {
body += this.tok();
}
- return '\n'
- + body
- + '
\n';
+ return renderer.blockquote(body);
}
case 'list_start': {
- var type = this.token.ordered ? 'ol' : 'ul'
- , body = '';
+ var body = '', ordered = this.token.ordered;
while (this.next().type !== 'list_end') {
body += this.tok();
}
- return '<'
- + type
- + '>\n'
- + body
- + ''
- + type
- + '>\n';
+ return renderer.list(body, ordered);
}
case 'list_item_start': {
var body = '';
@@ -925,9 +958,7 @@ Parser.prototype.tok = function() {
: this.tok();
}
- return ''
- + body
- + '\n';
+ return renderer.listitem(body);
}
case 'loose_item_start': {
var body = '';
@@ -936,19 +967,16 @@ Parser.prototype.tok = function() {
body += this.tok();
}
- return ''
- + body
- + '\n';
+ return renderer.listitem(body);
}
case 'html': {
- return !this.token.pre && !this.options.pedantic
+ var html = !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
+ return renderer.blockhtml(html);
}
case 'paragraph': {
- return ''
- + this.inline.output(this.token.text)
- + '
\n';
+ return renderer.paragraph(this.inline.output(this.token.text));
}
case 'text': {
return ''
@@ -1003,6 +1031,7 @@ function merge(obj) {
return obj;
}
+
/**
* Marked
*/
@@ -1039,9 +1068,7 @@ marked.defaults = {
pedantic: false,
sanitize: false,
smartLists: false,
- silent: false,
- highlight: null,
- langPrefix: 'lang-'
+ silent: false
};
/**
@@ -1051,6 +1078,8 @@ marked.defaults = {
marked.Parser = Parser;
marked.parser = Parser.parse;
+marked.Renderer = Renderer;
+
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
diff --git a/package.json b/package.json
index 5a71165d4f..a94f03ab7a 100644
--- a/package.json
+++ b/package.json
@@ -2,11 +2,10 @@
"name": "marked",
"description": "A markdown parser built for speed",
"author": "Christopher Jeffrey",
- "version": "0.2.8",
+ "version": "0.3.0a1",
"main": "./lib/marked.js",
"bin": "./bin/marked",
"man": "./man/marked.1",
- "preferGlobal": true,
"repository": "git://github.com/chjj/marked.git",
"homepage": "https://github.com/chjj/marked",
"bugs": { "url": "http://github.com/chjj/marked/issues" },