
11 changed files with 529 additions and 495 deletions
@ -1,139 +1,4 @@ |
|||||
'use strict'; |
'use strict'; |
||||
|
|
||||
|
|
||||
var Renderer = require('./lib/renderer'); |
module.exports = require('./lib/parser'); |
||||
var LexerBlock = require('./lib/lexer_block'); |
|
||||
var LexerInline = require('./lib/lexer_inline'); |
|
||||
|
|
||||
|
|
||||
// Parser state class
|
|
||||
//
|
|
||||
function State(src, lexerBlock, lexerInline, renderer, options) { |
|
||||
var ch, s, start, pos, len, indent, indent_found; |
|
||||
|
|
||||
// TODO: Temporary solution. Check if more effective possible,
|
|
||||
// withous str change
|
|
||||
//
|
|
||||
// - replace tabs with spaces
|
|
||||
// - remove `\r` to simplify newlines check (???)
|
|
||||
|
|
||||
this.src = src |
|
||||
.replace(/\t/g, ' ') |
|
||||
.replace(/\r/g, '') |
|
||||
.replace(/\u00a0/g, ' ') |
|
||||
.replace(/\u2424/g, '\n'); |
|
||||
|
|
||||
// Shortcuts to simplify nested calls
|
|
||||
this.lexerBlock = lexerBlock; |
|
||||
this.lexerInline = lexerInline; |
|
||||
this.renderer = renderer; |
|
||||
|
|
||||
// TODO: (?) set directly for faster access.
|
|
||||
this.options = options; |
|
||||
|
|
||||
//
|
|
||||
// Internal state vartiables
|
|
||||
//
|
|
||||
|
|
||||
this.tokens = []; |
|
||||
|
|
||||
this.bMarks = []; // line begin offsets for fast jumps
|
|
||||
this.eMarks = []; // line end offsets for fast jumps
|
|
||||
this.tShift = []; // indent for each line
|
|
||||
|
|
||||
// Generate markers.
|
|
||||
s = this.src; |
|
||||
indent = 0; |
|
||||
indent_found = false; |
|
||||
|
|
||||
for(start = pos = indent = 0, len = s.length; pos < len; pos++) { |
|
||||
ch = s.charCodeAt(pos); |
|
||||
|
|
||||
// TODO: check other spaces and tabs too or keep existing regexp replace ??
|
|
||||
if (!indent_found && ch === 0x20/* space */) { |
|
||||
indent++; |
|
||||
} |
|
||||
if (!indent_found && ch !== 0x20/* space */) { |
|
||||
this.tShift.push(indent); |
|
||||
indent_found = true; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
if (ch === 0x0D || ch === 0x0A) { |
|
||||
this.bMarks.push(start); |
|
||||
this.eMarks.push(pos); |
|
||||
indent_found = false; |
|
||||
indent = 0; |
|
||||
start = pos + 1; |
|
||||
} |
|
||||
if (ch === 0x0D && pos < len && s.charCodeAt(pos) === 0x0A) { |
|
||||
pos++; |
|
||||
start++; |
|
||||
} |
|
||||
} |
|
||||
if (ch !== 0x0D || ch !== 0x0A) { |
|
||||
this.bMarks.push(start); |
|
||||
this.eMarks.push(len); |
|
||||
this.tShift.push(indent); |
|
||||
} |
|
||||
|
|
||||
// inline lexer variables
|
|
||||
this.pos = 0; // char index in src
|
|
||||
|
|
||||
// block lexer variables
|
|
||||
this.blkLevel = 0; |
|
||||
this.blkIndent = 0; |
|
||||
this.line = 0; // line index in src
|
|
||||
this.lineMax = this.bMarks.length; |
|
||||
|
|
||||
// renderer
|
|
||||
this.result = ''; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
// Main class
|
|
||||
//
|
|
||||
function Remarkable(options) { |
|
||||
this.options = {}; |
|
||||
this.state = null; |
|
||||
|
|
||||
this.lexerInline = new LexerInline(); |
|
||||
this.lexerBlock = new LexerBlock(); |
|
||||
this.renderer = new Renderer(); |
|
||||
|
|
||||
if (options) { this.set(options); } |
|
||||
} |
|
||||
|
|
||||
|
|
||||
Remarkable.prototype.set = function (options) { |
|
||||
Object.keys(options).forEach(function (key) { |
|
||||
this.options[key] = options[key]; |
|
||||
}, this); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
Remarkable.prototype.render = function (src) { |
|
||||
|
|
||||
if (!src) { return ''; } |
|
||||
|
|
||||
var state = new State( |
|
||||
src, |
|
||||
this.lexerBlock, |
|
||||
this.lexerInline, |
|
||||
this.renderer, |
|
||||
this.options |
|
||||
); |
|
||||
|
|
||||
// TODO: skip leading empty lines
|
|
||||
|
|
||||
state.lexerBlock.tokenize(state, state.line, state.lineMax); |
|
||||
|
|
||||
// TODO: ??? eat empty paragraphs from tail
|
|
||||
|
|
||||
//console.log(state.tokens)
|
|
||||
|
|
||||
return this.renderer.render(state); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
module.exports = Remarkable; |
|
||||
|
@ -0,0 +1,54 @@ |
|||||
|
// Common functions for lexers
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
function isWhiteSpace(ch) { |
||||
|
return ch === 0x20; |
||||
|
} |
||||
|
|
||||
|
// Check if line has zero length or contains spaces only
|
||||
|
function isEmpty(state, line) { |
||||
|
return state.bMarks[line] + state.tShift[line] >= state.eMarks[line]; |
||||
|
} |
||||
|
|
||||
|
// Scan lines from given one and return first not empty
|
||||
|
function skipEmptyLines(state, from) { |
||||
|
for (var max = state.lineMax; from < max; from++) { |
||||
|
if (state.bMarks[from] + state.tShift[from] < state.eMarks[from]) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return from; |
||||
|
} |
||||
|
|
||||
|
// Skip spaces from given position.
|
||||
|
function skipSpaces(state, pos) { |
||||
|
for (var max = state.src.length; pos < max; pos++) { |
||||
|
if (!isWhiteSpace(state.src.charCodeAt(pos))) { break; } |
||||
|
} |
||||
|
return pos; |
||||
|
} |
||||
|
|
||||
|
// Skip char codes from given position
|
||||
|
function skipChars(state, pos, code) { |
||||
|
for (var max = state.src.length; pos < max; pos++) { |
||||
|
if (state.src.charCodeAt(pos) !== code) { break; } |
||||
|
} |
||||
|
return pos; |
||||
|
} |
||||
|
|
||||
|
// Skip char codes reverse from given position
|
||||
|
/*function skipCharsBack(state, pos, code, min) { |
||||
|
for (; pos >= min; pos--) { |
||||
|
if (code !== state.src.charCodeAt(pos)) { break; } |
||||
|
} |
||||
|
return pos; |
||||
|
}*/ |
||||
|
|
||||
|
|
||||
|
exports.isWhiteSpace = isWhiteSpace; |
||||
|
exports.isEmpty = isEmpty; |
||||
|
exports.skipEmptyLines = skipEmptyLines; |
||||
|
exports.skipSpaces = skipSpaces; |
||||
|
exports.skipChars = skipChars; |
@ -0,0 +1,42 @@ |
|||||
|
// Code block (4 spaces padded)
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var isEmpty = require('../helpers').isEmpty; |
||||
|
|
||||
|
|
||||
|
module.exports = function code(state, startLine, endLine, silent) { |
||||
|
var nextLine, last; |
||||
|
|
||||
|
if (state.tShift[startLine] < 4) { return false; } |
||||
|
|
||||
|
last = nextLine = startLine + 1; |
||||
|
|
||||
|
while (nextLine < endLine) { |
||||
|
if (isEmpty(state, nextLine)) { |
||||
|
nextLine++; |
||||
|
if (state.options.pedantic) { |
||||
|
last = nextLine; |
||||
|
} |
||||
|
continue; |
||||
|
} |
||||
|
if (state.tShift[nextLine] >= 4) { |
||||
|
nextLine++; |
||||
|
last = nextLine; |
||||
|
continue; |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (silent) { return true; } |
||||
|
|
||||
|
state.tokens.push({ |
||||
|
type: 'code', |
||||
|
startLine: startLine, |
||||
|
endLine: last |
||||
|
}); |
||||
|
|
||||
|
state.line = nextLine; |
||||
|
return true; |
||||
|
}; |
@ -0,0 +1,79 @@ |
|||||
|
// fences (``` lang, ~~~ lang)
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var skipEmptyLines = require('../helpers').skipEmptyLines; |
||||
|
|
||||
|
|
||||
|
module.exports =function fences(state, startLine, endLine, silent) { |
||||
|
var marker, len, params, nextLine, |
||||
|
pos = state.bMarks[startLine] + state.tShift[startLine], |
||||
|
max = state.eMarks[startLine]; |
||||
|
|
||||
|
if (pos + 3 > max) { return false; } |
||||
|
|
||||
|
marker = state.src.charCodeAt(pos); |
||||
|
|
||||
|
if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// scan marker length
|
||||
|
len = 1; |
||||
|
while (state.src.charCodeAt(++pos) === marker) { |
||||
|
len++; |
||||
|
} |
||||
|
|
||||
|
if (len < 3) { return false; } |
||||
|
|
||||
|
params = state.src.slice(pos, max).trim(); |
||||
|
|
||||
|
if (!/\S/.test(params)) { return false; } |
||||
|
|
||||
|
// search end of block
|
||||
|
nextLine = startLine; |
||||
|
|
||||
|
do { |
||||
|
nextLine++; |
||||
|
|
||||
|
if (nextLine > endLine) { return false; } |
||||
|
|
||||
|
pos = state.bMarks[nextLine] + state.tShift[nextLine]; |
||||
|
max = state.eMarks[nextLine]; |
||||
|
|
||||
|
if (pos + 3 > max) { continue; } |
||||
|
|
||||
|
// check markers
|
||||
|
if (state.src.charCodeAt(pos) !== marker && |
||||
|
state.src.charCodeAt(pos + 1) !== marker && |
||||
|
state.src.charCodeAt(pos + 2) !== marker) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
pos += 3; |
||||
|
|
||||
|
// make sure tail has spaces only
|
||||
|
//pos = pos < max ? skipSpaces(state, pos) : pos;
|
||||
|
|
||||
|
// stmd allow any combonation of markers and spaces in tail
|
||||
|
|
||||
|
if (pos < max) { continue; } |
||||
|
|
||||
|
// found!
|
||||
|
break; |
||||
|
|
||||
|
} while (true); |
||||
|
|
||||
|
if (silent) { return true; } |
||||
|
|
||||
|
state.tokens.push({ |
||||
|
type: 'fence', |
||||
|
params: params.split(/\s+/g), |
||||
|
startLine: startLine + 1, |
||||
|
endLine: nextLine |
||||
|
}); |
||||
|
|
||||
|
state.line = skipEmptyLines(state, nextLine + 1); |
||||
|
return true; |
||||
|
}; |
@ -0,0 +1,72 @@ |
|||||
|
// heading (#, ##, ...)
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var isWhiteSpace = require('../helpers').isWhiteSpace; |
||||
|
var skipEmptyLines = require('../helpers').skipEmptyLines; |
||||
|
var skipSpaces = require('../helpers').skipSpaces; |
||||
|
|
||||
|
|
||||
|
module.exports = function heading(state, startLine, endLine, silent) { |
||||
|
var ch, level, |
||||
|
pos = state.bMarks[startLine], |
||||
|
max = state.eMarks[startLine], |
||||
|
start = pos; |
||||
|
|
||||
|
pos += state.tShift[startLine]; |
||||
|
|
||||
|
if (pos >= max) { return false; } |
||||
|
|
||||
|
ch = state.src.charCodeAt(pos); |
||||
|
|
||||
|
if (ch !== 0x23/* # */ || pos >= max) { return false; } |
||||
|
|
||||
|
// count heading level
|
||||
|
level = 1; |
||||
|
ch = state.src.charCodeAt(++pos); |
||||
|
while (ch === 0x23/* # */ && pos < max && level <= 6) { |
||||
|
level++; |
||||
|
ch = state.src.charCodeAt(++pos); |
||||
|
} |
||||
|
|
||||
|
if (level > 6 || (pos < max && !isWhiteSpace(ch))) { return false; } |
||||
|
|
||||
|
// skip spaces before heading text
|
||||
|
pos = pos < max ? skipSpaces(state, pos) : pos; |
||||
|
|
||||
|
// Now pos contains offset of first heared char
|
||||
|
// Let's cut tails like ' ### ' from the end of string
|
||||
|
|
||||
|
max--; |
||||
|
ch = state.src.charCodeAt(max); |
||||
|
|
||||
|
while (max > start && isWhiteSpace(ch)) { |
||||
|
ch = state.src.charCodeAt(--max); |
||||
|
} |
||||
|
if (ch === 0x23/* # */) { |
||||
|
while (max > start && ch === 0x23/* # */) { |
||||
|
ch = state.src.charCodeAt(--max); |
||||
|
} |
||||
|
if (isWhiteSpace(ch)) { |
||||
|
while (max > start && isWhiteSpace(ch)) { |
||||
|
ch = state.src.charCodeAt(--max); |
||||
|
} |
||||
|
} else if (ch === 0x5C/* \ */) { |
||||
|
max++; |
||||
|
} |
||||
|
} |
||||
|
max++; |
||||
|
|
||||
|
if (silent) { return true; } |
||||
|
|
||||
|
state.tokens.push({ type: 'heading_open', level: level }); |
||||
|
// only if header is not empty
|
||||
|
if (pos < max) { |
||||
|
state.lexerInline.tokenize(state, pos, max); |
||||
|
} |
||||
|
state.tokens.push({ type: 'heading_close', level: level }); |
||||
|
|
||||
|
state.line = skipEmptyLines(state, ++startLine); |
||||
|
return true; |
||||
|
}; |
@ -0,0 +1,48 @@ |
|||||
|
// Horizontal rule
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var isWhiteSpace = require('../helpers').isWhiteSpace; |
||||
|
var skipEmptyLines = require('../helpers').skipEmptyLines; |
||||
|
|
||||
|
|
||||
|
module.exports = function hr(state, startLine, endLine, silent) { |
||||
|
var marker, cnt, ch, |
||||
|
pos = state.bMarks[startLine], |
||||
|
max = state.eMarks[startLine]; |
||||
|
|
||||
|
// should not have > 3 leading spaces
|
||||
|
if (state.tShift[startLine] > 3) { return false; } |
||||
|
|
||||
|
pos += state.tShift[startLine]; |
||||
|
|
||||
|
if (pos > max) { return false; } |
||||
|
|
||||
|
marker = state.src.charCodeAt(pos++); |
||||
|
|
||||
|
// Check hr marker
|
||||
|
if (marker !== 0x2A/* * */ && |
||||
|
marker !== 0x2D/* - */ && |
||||
|
marker !== 0x5F/* _ */) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// markers can be mixed with spaces, but there should be at least 3 one
|
||||
|
|
||||
|
cnt = 1; |
||||
|
while (pos < max) { |
||||
|
ch = state.src.charCodeAt(pos++); |
||||
|
if (ch !== marker && !isWhiteSpace(ch)) { return false; } |
||||
|
if (ch === marker) { cnt++; } |
||||
|
} |
||||
|
|
||||
|
if (cnt < 3) { return false; } |
||||
|
|
||||
|
if (silent) { return true; } |
||||
|
|
||||
|
state.tokens.push({ type: 'hr' }); |
||||
|
|
||||
|
state.line = skipEmptyLines(state, ++startLine); |
||||
|
return true; |
||||
|
}; |
@ -0,0 +1,42 @@ |
|||||
|
// lheading (---, ===)
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var skipEmptyLines = require('../helpers').skipEmptyLines; |
||||
|
var skipSpaces = require('../helpers').skipSpaces; |
||||
|
var skipChars = require('../helpers').skipChars; |
||||
|
|
||||
|
|
||||
|
module.exports = function lheading(state, startLine, endLine, silent) { |
||||
|
var marker, pos, mem, max, |
||||
|
next = startLine + 1; |
||||
|
|
||||
|
if (next >= state.lineMax) { return false; } |
||||
|
|
||||
|
// Scan next line
|
||||
|
pos = state.bMarks[next] + state.tShift[next]; |
||||
|
max = state.eMarks[next]; |
||||
|
|
||||
|
if (pos + 3 > max) { return false; } |
||||
|
|
||||
|
marker = state.src.charCodeAt(pos); |
||||
|
|
||||
|
if (marker !== 0x2D/* - */ && marker !== 0x3D/* = */) { return false; } |
||||
|
|
||||
|
mem = pos; |
||||
|
pos = skipChars(state, pos, marker); |
||||
|
|
||||
|
if (pos - mem < 3) { return false; } |
||||
|
|
||||
|
pos = skipSpaces(state, pos); |
||||
|
|
||||
|
if (pos < max) { return false; } |
||||
|
|
||||
|
state.tokens.push({ type: 'heading_open', level: marker === 0x3D/* = */ ? 1 : 2 }); |
||||
|
state.lexerInline.tokenize(state, state.bMarks[startLine], state.eMarks[startLine]); |
||||
|
state.tokens.push({ type: 'heading_close', level: marker === 0x3D/* = */ ? 1 : 2 }); |
||||
|
|
||||
|
state.line = skipEmptyLines(state, ++next); |
||||
|
return true; |
||||
|
}; |
@ -0,0 +1,38 @@ |
|||||
|
// Paragraph
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var isEmpty = require('../helpers').isEmpty; |
||||
|
var skipEmptyLines = require('../helpers').skipEmptyLines; |
||||
|
|
||||
|
|
||||
|
module.exports = function paragraph(state, startLine, endLine) { |
||||
|
var nextLine = startLine + 1, |
||||
|
rules_named = state.lexerBlock.rules_named; |
||||
|
|
||||
|
// jump line-by-line until empty one or EOF
|
||||
|
while (nextLine < endLine && !isEmpty(state, nextLine)) { |
||||
|
// Some tags can terminate paragraph without empty line.
|
||||
|
// Try those tags in validation more (without tokens generation)
|
||||
|
if (rules_named.fences(state, nextLine, endLine, true)) { break; } |
||||
|
if (rules_named.hr(state, nextLine, endLine, true)) { break; } |
||||
|
if (rules_named.heading(state, nextLine, endLine, true)) { break; } |
||||
|
if (rules_named.lheading(state, nextLine, endLine, true)) { break; } |
||||
|
//if (rules_named.blockquote(state, nextLine, endLine, true)) { break; }
|
||||
|
//if (rules_named.tag(state, nextLine, endLine, true)) { break; }
|
||||
|
//if (rules_named.def(state, nextLine, endLine, true)) { break; }
|
||||
|
nextLine++; |
||||
|
} |
||||
|
|
||||
|
state.tokens.push({ type: 'paragraph_open' }); |
||||
|
state.lexerInline.tokenize( |
||||
|
state, |
||||
|
state.bMarks[startLine], |
||||
|
state.eMarks[nextLine - 1] |
||||
|
); |
||||
|
state.tokens.push({ type: 'paragraph_close' }); |
||||
|
|
||||
|
state.line = skipEmptyLines(state, nextLine); |
||||
|
return true; |
||||
|
}; |
@ -0,0 +1,58 @@ |
|||||
|
// Main perser class
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
var State = require('./state'); |
||||
|
var Renderer = require('./renderer'); |
||||
|
var LexerBlock = require('./lexer_block'); |
||||
|
var LexerInline = require('./lexer_inline'); |
||||
|
|
||||
|
|
||||
|
// Main class
|
||||
|
//
|
||||
|
function Parser(options) { |
||||
|
this.options = {}; |
||||
|
this.state = null; |
||||
|
|
||||
|
this.lexerInline = new LexerInline(); |
||||
|
this.lexerBlock = new LexerBlock(); |
||||
|
this.renderer = new Renderer(); |
||||
|
|
||||
|
if (options) { this.set(options); } |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Parser.prototype.set = function (options) { |
||||
|
Object.keys(options).forEach(function (key) { |
||||
|
this.options[key] = options[key]; |
||||
|
}, this); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
Parser.prototype.render = function (src) { |
||||
|
var state; |
||||
|
|
||||
|
if (!src) { return ''; } |
||||
|
|
||||
|
state = new State( |
||||
|
src, |
||||
|
this.lexerBlock, |
||||
|
this.lexerInline, |
||||
|
this.renderer, |
||||
|
this.options |
||||
|
); |
||||
|
|
||||
|
// TODO: skip leading empty lines
|
||||
|
|
||||
|
state.lexerBlock.tokenize(state, state.line, state.lineMax); |
||||
|
|
||||
|
// TODO: ??? eat empty paragraphs from tail
|
||||
|
|
||||
|
//console.log(state.tokens)
|
||||
|
|
||||
|
return this.renderer.render(state); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
module.exports = Parser; |
@ -0,0 +1,89 @@ |
|||||
|
// Parser state class
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
function State(src, lexerBlock, lexerInline, renderer, options) { |
||||
|
var ch, s, start, pos, len, indent, indent_found; |
||||
|
|
||||
|
// TODO: Temporary solution. Check if more effective possible,
|
||||
|
// withous str change
|
||||
|
//
|
||||
|
// - replace tabs with spaces
|
||||
|
// - remove `\r` to simplify newlines check (???)
|
||||
|
|
||||
|
this.src = src |
||||
|
.replace(/\t/g, ' ') |
||||
|
.replace(/\r/g, '') |
||||
|
.replace(/\u00a0/g, ' ') |
||||
|
.replace(/\u2424/g, '\n'); |
||||
|
|
||||
|
// Shortcuts to simplify nested calls
|
||||
|
this.lexerBlock = lexerBlock; |
||||
|
this.lexerInline = lexerInline; |
||||
|
this.renderer = renderer; |
||||
|
|
||||
|
// TODO: (?) set directly for faster access.
|
||||
|
this.options = options; |
||||
|
|
||||
|
//
|
||||
|
// Internal state vartiables
|
||||
|
//
|
||||
|
|
||||
|
this.tokens = []; |
||||
|
|
||||
|
this.bMarks = []; // line begin offsets for fast jumps
|
||||
|
this.eMarks = []; // line end offsets for fast jumps
|
||||
|
this.tShift = []; // indent for each line
|
||||
|
|
||||
|
// Generate markers.
|
||||
|
s = this.src; |
||||
|
indent = 0; |
||||
|
indent_found = false; |
||||
|
|
||||
|
for(start = pos = indent = 0, len = s.length; pos < len; pos++) { |
||||
|
ch = s.charCodeAt(pos); |
||||
|
|
||||
|
// TODO: check other spaces and tabs too or keep existing regexp replace ??
|
||||
|
if (!indent_found && ch === 0x20/* space */) { |
||||
|
indent++; |
||||
|
} |
||||
|
if (!indent_found && ch !== 0x20/* space */) { |
||||
|
this.tShift.push(indent); |
||||
|
indent_found = true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
if (ch === 0x0D || ch === 0x0A) { |
||||
|
this.bMarks.push(start); |
||||
|
this.eMarks.push(pos); |
||||
|
indent_found = false; |
||||
|
indent = 0; |
||||
|
start = pos + 1; |
||||
|
} |
||||
|
if (ch === 0x0D && pos < len && s.charCodeAt(pos) === 0x0A) { |
||||
|
pos++; |
||||
|
start++; |
||||
|
} |
||||
|
} |
||||
|
if (ch !== 0x0D || ch !== 0x0A) { |
||||
|
this.bMarks.push(start); |
||||
|
this.eMarks.push(len); |
||||
|
this.tShift.push(indent); |
||||
|
} |
||||
|
|
||||
|
// inline lexer variables
|
||||
|
this.pos = 0; // char index in src
|
||||
|
|
||||
|
// block lexer variables
|
||||
|
this.blkLevel = 0; |
||||
|
this.blkIndent = 0; |
||||
|
this.line = 0; // line index in src
|
||||
|
this.lineMax = this.bMarks.length; |
||||
|
|
||||
|
// renderer
|
||||
|
this.result = ''; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
module.exports = State; |
Loading…
Reference in new issue