Browse Source

Implemented nested blocks lexing, now block quotes works as expected

pull/14/head
Vitaly Puzrin 11 years ago
parent
commit
8cf045d940
  1. 2
      .jshintrc
  2. 15
      lib/helpers.js
  3. 16
      lib/lexer_block/blockquote.js
  4. 6
      lib/lexer_block/code.js
  5. 4
      lib/lexer_block/fences.js
  6. 3
      lib/lexer_inline.js
  7. 1
      lib/parser.js
  8. 15
      lib/renderer.js
  9. 23
      lib/state.js

2
.jshintrc

@ -22,7 +22,7 @@
"unused" : false, // This option warns when you define and never use your variables. "unused" : false, // This option warns when you define and never use your variables.
"strict" : true, // Require `use strict` pragma in every file. "strict" : true, // Require `use strict` pragma in every file.
"trailing" : true, // Prohibit trailing whitespaces. "trailing" : true, // Prohibit trailing whitespaces.
"maxparams" : 5, // Enforce max number of formal parameters allowed per function "maxparams" : 6, // Enforce max number of formal parameters allowed per function
"maxdepth" : 5, // Enforce max depth of nested blocks "maxdepth" : 5, // Enforce max depth of nested blocks
"maxstatements" : false, // Enforce max amount of statements per function "maxstatements" : false, // Enforce max amount of statements per function
"maxcomplexity" : false, // Enforce cyclomatic complexity level "maxcomplexity" : false, // Enforce cyclomatic complexity level

15
lib/helpers.js

@ -46,9 +46,22 @@ function skipChars(state, pos, code) {
return pos; return pos;
}*/ }*/
// cut lines range from source.
function getLines(state, begin, end, keepLastLF) {
var last;
if (keepLastLF) {
last = end < state.lineMax ? state.bMarks[end] : state.src.length;
} else {
last = end < state.lineMax ? state.eMarks[end - 1] : state.src.length;
}
return state.src.slice(state.bMarks[begin], last);
}
exports.isWhiteSpace = isWhiteSpace; exports.isWhiteSpace = isWhiteSpace;
exports.isEmpty = isEmpty; exports.isEmpty = isEmpty;
exports.skipEmptyLines = skipEmptyLines; exports.skipEmptyLines = skipEmptyLines;
exports.skipSpaces = skipSpaces; exports.skipSpaces = skipSpaces;
exports.skipChars = skipChars; exports.skipChars = skipChars;
exports.getLines = getLines;

16
lib/lexer_block/blockquote.js

@ -3,12 +3,13 @@
'use strict'; 'use strict';
var skipEmptyLines = require('../helpers').skipEmptyLines; var skipEmptyLines = require('../helpers').skipEmptyLines;
var skipSpaces = require('../helpers').skipSpaces; var skipSpaces = require('../helpers').skipSpaces;
var getLines = require('../helpers').getLines;
module.exports = function blockquote(state, startLine, endLine, silent) { module.exports = function blockquote(state, startLine, endLine, silent) {
var marker, nextLine, oldBMarks, lastLineEmpty, var marker, nextLine, oldBMarks, lastLineEmpty, subState,
rules_named = state.lexerBlock.rules_named, rules_named = state.lexerBlock.rules_named,
pos = state.bMarks[startLine] + state.tShift[startLine], pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine]; max = state.eMarks[startLine];
@ -75,11 +76,10 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
} }
state.tokens.push({ type: 'blockquote_open' }); state.tokens.push({ type: 'blockquote_open' });
state.lexerInline.tokenize(
state, subState = state.clone(getLines(state, startLine, nextLine, true).replace(/^ {0,3}> ?/mg, ''));
state.bMarks[startLine], state.lexerBlock.tokenize(subState, 0, subState.lineMax);
state.eMarks[nextLine - 1]
);
state.tokens.push({ type: 'blockquote_close' }); state.tokens.push({ type: 'blockquote_close' });
state.line = skipEmptyLines(state, nextLine); state.line = skipEmptyLines(state, nextLine);

6
lib/lexer_block/code.js

@ -3,7 +3,8 @@
'use strict'; 'use strict';
var isEmpty = require('../helpers').isEmpty; var isEmpty = require('../helpers').isEmpty;
var getLines = require('../helpers').getLines;
module.exports = function code(state, startLine, endLine, silent) { module.exports = function code(state, startLine, endLine, silent) {
@ -33,8 +34,7 @@ module.exports = function code(state, startLine, endLine, silent) {
state.tokens.push({ state.tokens.push({
type: 'code', type: 'code',
startLine: startLine, content: getLines(state, startLine, last, true).replace(/^ {4}/gm, '')
endLine: last
}); });
state.line = nextLine; state.line = nextLine;

4
lib/lexer_block/fences.js

@ -6,6 +6,7 @@
var skipEmptyLines = require('../helpers').skipEmptyLines; var skipEmptyLines = require('../helpers').skipEmptyLines;
var skipSpaces = require('../helpers').skipSpaces; var skipSpaces = require('../helpers').skipSpaces;
var skipChars = require('../helpers').skipChars; var skipChars = require('../helpers').skipChars;
var getLines = require('../helpers').getLines;
module.exports =function fences(state, startLine, endLine, silent) { module.exports =function fences(state, startLine, endLine, silent) {
@ -70,8 +71,7 @@ module.exports =function fences(state, startLine, endLine, silent) {
state.tokens.push({ state.tokens.push({
type: 'fence', type: 'fence',
params: params ? params.split(/\s+/g) : [], params: params ? params.split(/\s+/g) : [],
startLine: startLine + 1, content: getLines(state, startLine + 1, nextLine, true)
endLine: nextLine
}); });
state.line = skipEmptyLines(state, nextLine + 1); state.line = skipEmptyLines(state, nextLine + 1);

3
lib/lexer_inline.js

@ -13,8 +13,7 @@ var rules = [];
rules.push(function text(state, begin, end) { rules.push(function text(state, begin, end) {
state.tokens.push({ state.tokens.push({
type: 'text', type: 'text',
begin: begin, content: state.src.slice(begin, end)
end: end
}); });
state.pos = end; state.pos = end;

1
lib/parser.js

@ -40,6 +40,7 @@ Parser.prototype.render = function (src) {
this.lexerBlock, this.lexerBlock,
this.lexerInline, this.lexerInline,
this.renderer, this.renderer,
[],
this.options this.options
); );

15
lib/renderer.js

@ -14,12 +14,6 @@ function unescapeMd(str) {
return str.replace(MD_UNESCAPE_RE, '$1'); return str.replace(MD_UNESCAPE_RE, '$1');
} }
function joinLines(state, begin, end) {
return state.src.slice(
state.bMarks[begin],
end < state.lineMax ? state.bMarks[end] : state.src.length
);
}
var rules = {}; var rules = {};
@ -41,14 +35,11 @@ rules.bullet_list_close = function (state, token) {
rules.code = function (state, token) { rules.code = function (state, token) {
var content = joinLines(state, token.startLine, token.endLine).replace(/^ {4}/gm, ''); state.result += '<pre><code>' + escapeHtml(token.content) + '</code></pre>\n';
state.result += '<pre><code>' + escapeHtml(content) + '</code></pre>\n';
}; };
rules.fence = function (state, token) { rules.fence = function (state, token) {
var content = joinLines(state, token.startLine, token.endLine);
var langMark = ''; var langMark = '';
var langPrefix = state.options.codeLangPrefix || ''; var langPrefix = state.options.codeLangPrefix || '';
@ -56,7 +47,7 @@ rules.fence = function (state, token) {
langMark = ' class="' + langPrefix + escapeHtml(token.params[0]) + '"'; langMark = ' class="' + langPrefix + escapeHtml(token.params[0]) + '"';
} }
state.result += '<pre><code' + langMark + '>' + escapeHtml(content) + '</code></pre>\n'; state.result += '<pre><code' + langMark + '>' + escapeHtml(token.content) + '</code></pre>\n';
}; };
@ -90,7 +81,7 @@ rules.paragraph_close = function (state, token) {
rules.text = function (state, token) { rules.text = function (state, token) {
state.result += escapeHtml(unescapeMd(state.src.slice(token.begin, token.end))); state.result += escapeHtml(unescapeMd(token.content));
}; };

23
lib/state.js

@ -3,11 +3,14 @@
'use strict'; 'use strict';
function State(src, lexerBlock, lexerInline, renderer, options) { function State(src, lexerBlock, lexerInline, renderer, tokens, options) {
var ch, s, start, pos, len, indent, indent_found; var ch, s, start, pos, len, indent, indent_found;
// TODO: Temporary solution. Check if more effective possible, // TODO: check if we can move string replaces to parser, to avoid
// withous str change // unnesessary call on shadow clone creation. Or check if we can do
// cloning more effectively. Profile first.
// Prepare string to parse:
// //
// - replace tabs with spaces // - replace tabs with spaces
// - remove `\r` to simplify newlines check (???) // - remove `\r` to simplify newlines check (???)
@ -30,7 +33,7 @@ function State(src, lexerBlock, lexerInline, renderer, options) {
// Internal state vartiables // Internal state vartiables
// //
this.tokens = []; this.tokens = tokens;
this.bMarks = []; // line begin offsets for fast jumps this.bMarks = []; // line begin offsets for fast jumps
this.eMarks = []; // line end offsets for fast jumps this.eMarks = []; // line end offsets for fast jumps
@ -86,4 +89,16 @@ function State(src, lexerBlock, lexerInline, renderer, options) {
} }
// Create shadow clone of curent state with new input data
State.prototype.clone = function clone(src) {
return new State(
src,
this.lexerBlock,
this.lexerInline,
this.renderer,
this.tokens,
this.options
);
};
module.exports = State; module.exports = State;
Loading…
Cancel
Save