Browse Source

Implemented nested blocks lexing, now block quotes works as expected

pull/14/head
Vitaly Puzrin 10 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.
"strict" : true, // Require `use strict` pragma in every file.
"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
"maxstatements" : false, // Enforce max amount of statements per function
"maxcomplexity" : false, // Enforce cyclomatic complexity level

15
lib/helpers.js

@ -46,9 +46,22 @@ function skipChars(state, pos, code) {
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.isEmpty = isEmpty;
exports.skipEmptyLines = skipEmptyLines;
exports.skipSpaces = skipSpaces;
exports.skipChars = skipChars;
exports.skipChars = skipChars;
exports.getLines = getLines;

16
lib/lexer_block/blockquote.js

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

6
lib/lexer_block/code.js

@ -3,7 +3,8 @@
'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) {
@ -33,8 +34,7 @@ module.exports = function code(state, startLine, endLine, silent) {
state.tokens.push({
type: 'code',
startLine: startLine,
endLine: last
content: getLines(state, startLine, last, true).replace(/^ {4}/gm, '')
});
state.line = nextLine;

4
lib/lexer_block/fences.js

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

3
lib/lexer_inline.js

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

1
lib/parser.js

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

15
lib/renderer.js

@ -14,12 +14,6 @@ function unescapeMd(str) {
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 = {};
@ -41,14 +35,11 @@ rules.bullet_list_close = function (state, token) {
rules.code = function (state, token) {
var content = joinLines(state, token.startLine, token.endLine).replace(/^ {4}/gm, '');
state.result += '<pre><code>' + escapeHtml(content) + '</code></pre>\n';
state.result += '<pre><code>' + escapeHtml(token.content) + '</code></pre>\n';
};
rules.fence = function (state, token) {
var content = joinLines(state, token.startLine, token.endLine);
var langMark = '';
var langPrefix = state.options.codeLangPrefix || '';
@ -56,7 +47,7 @@ rules.fence = function (state, token) {
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) {
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';
function State(src, lexerBlock, lexerInline, renderer, options) {
function State(src, lexerBlock, lexerInline, renderer, tokens, options) {
var ch, s, start, pos, len, indent, indent_found;
// TODO: Temporary solution. Check if more effective possible,
// withous str change
// TODO: check if we can move string replaces to parser, to avoid
// 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
// - remove `\r` to simplify newlines check (???)
@ -30,7 +33,7 @@ function State(src, lexerBlock, lexerInline, renderer, options) {
// Internal state vartiables
//
this.tokens = [];
this.tokens = tokens;
this.bMarks = []; // line begin 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;
Loading…
Cancel
Save