Browse Source

Splitted replacements & smartquotes to smaller functions

pull/82/head
Vitaly Puzrin 10 years ago
parent
commit
9ae876b0fe
  1. 68
      lib/rules_core/replacements.js
  2. 213
      lib/rules_core/smartquotes.js

68
lib/rules_core/replacements.js

@ -36,8 +36,43 @@ function replaceScopedAbbr(str) {
} }
function replace_scoped(inlineTokens) {
var i, token;
for (i = inlineTokens.length - 1; i >= 0; i--) {
token = inlineTokens[i];
if (token.type === 'text') {
token.content = replaceScopedAbbr(token.content);
}
}
}
function replace_rare(inlineTokens) {
var i, token;
for (i = inlineTokens.length - 1; i >= 0; i--) {
token = inlineTokens[i];
if (token.type === 'text') {
if (RARE_RE.test(token.content)) {
token.content = token.content
.replace(/\+-/g, '±')
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..')
.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')
// em-dash
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2')
// en-dash
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2')
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2');
}
}
}
}
module.exports = function replace(state) { module.exports = function replace(state) {
var i, token, text, inlineTokens, blkIdx; var blkIdx;
if (!state.md.options.typographer) { return; } if (!state.md.options.typographer) { return; }
@ -45,30 +80,13 @@ module.exports = function replace(state) {
if (state.tokens[blkIdx].type !== 'inline') { continue; } if (state.tokens[blkIdx].type !== 'inline') { continue; }
inlineTokens = state.tokens[blkIdx].children; if (SCOPED_ABBR_RE.test(state.tokens[blkIdx].content)) {
replace_scoped(state.tokens[blkIdx].children);
for (i = inlineTokens.length - 1; i >= 0; i--) { }
token = inlineTokens[i];
if (token.type === 'text') { if (RARE_RE.test(state.tokens[blkIdx].content)) {
text = token.content; replace_rare(state.tokens[blkIdx].children);
text = replaceScopedAbbr(text);
if (RARE_RE.test(text)) {
text = text.replace(/\+-/g, '±')
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..')
.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')
// em-dash
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2')
// en-dash
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2')
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2');
}
token.content = text;
}
} }
} }
}; };

213
lib/rules_core/smartquotes.js

@ -16,136 +16,139 @@ function replaceAt(str, index, ch) {
return str.substr(0, index) + ch + str.substr(index + 1); return str.substr(0, index) + ch + str.substr(index + 1);
} }
function process_inlines(tokens, state) {
module.exports = function smartquotes(state) {
/*eslint max-depth:0*/
var i, token, text, t, pos, max, thisLevel, item, lastChar, nextChar, var i, token, text, t, pos, max, thisLevel, item, lastChar, nextChar,
isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace, isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace,
canOpen, canClose, j, isSingle, blkIdx, tokens, stack; canOpen, canClose, j, isSingle, stack;
if (!state.md.options.typographer) { return; }
stack = []; stack = [];
for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { for (i = 0; i < tokens.length; i++) {
token = tokens[i];
if (state.tokens[blkIdx].type !== 'inline' ||
!QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {
continue;
}
tokens = state.tokens[blkIdx].children;
stack.length = 0;
for (i = 0; i < tokens.length; i++) {
token = tokens[i];
if (token.type !== 'text' || QUOTE_TEST_RE.test(token.text)) { continue; } if (token.type !== 'text' || QUOTE_TEST_RE.test(token.text)) { continue; }
thisLevel = tokens[i].level; thisLevel = tokens[i].level;
for (j = stack.length - 1; j >= 0; j--) { for (j = stack.length - 1; j >= 0; j--) {
if (stack[j].level <= thisLevel) { break; } if (stack[j].level <= thisLevel) { break; }
} }
stack.length = j + 1; stack.length = j + 1;
text = token.content; text = token.content;
pos = 0; pos = 0;
max = text.length; max = text.length;
/*eslint no-labels:0,block-scoped-var:0*/ /*eslint no-labels:0,block-scoped-var:0*/
OUTER: OUTER:
while (pos < max) { while (pos < max) {
QUOTE_RE.lastIndex = pos; QUOTE_RE.lastIndex = pos;
t = QUOTE_RE.exec(text); t = QUOTE_RE.exec(text);
if (!t) { break; } if (!t) { break; }
canOpen = canClose = true; canOpen = canClose = true;
pos = t.index + 1; pos = t.index + 1;
isSingle = (t[0] === "'"); isSingle = (t[0] === "'");
lastChar = t.index - 1 >= 0 ? text.charCodeAt(t.index - 1) : -1; lastChar = t.index - 1 >= 0 ? text.charCodeAt(t.index - 1) : -1;
nextChar = pos < max ? text.charCodeAt(pos) : -1; nextChar = pos < max ? text.charCodeAt(pos) : -1;
isLastPunctChar = lastChar >= 0 && isLastPunctChar = lastChar >= 0 &&
(isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar))); (isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)));
isNextPunctChar = nextChar >= 0 && isNextPunctChar = nextChar >= 0 &&
(isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar))); (isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)));
// begin/end of the line counts as a whitespace too // begin/end of the line counts as a whitespace too
isLastWhiteSpace = lastChar < 0 || isWhiteSpace(lastChar); isLastWhiteSpace = lastChar < 0 || isWhiteSpace(lastChar);
isNextWhiteSpace = nextChar < 0 || isWhiteSpace(nextChar); isNextWhiteSpace = nextChar < 0 || isWhiteSpace(nextChar);
if (isNextWhiteSpace) { if (isNextWhiteSpace) {
canOpen = false;
} else if (isNextPunctChar) {
if (!(isLastWhiteSpace || isLastPunctChar)) {
canOpen = false; canOpen = false;
} else if (isNextPunctChar) {
if (!(isLastWhiteSpace || isLastPunctChar)) {
canOpen = false;
}
} }
}
if (isLastWhiteSpace) { if (isLastWhiteSpace) {
canClose = false;
} else if (isLastPunctChar) {
if (!(isNextWhiteSpace || isNextPunctChar)) {
canClose = false; canClose = false;
} else if (isLastPunctChar) {
if (!(isNextWhiteSpace || isNextPunctChar)) {
canClose = false;
}
} }
}
if (nextChar === 0x22 /* " */ && t[0] === '"') { if (nextChar === 0x22 /* " */ && t[0] === '"') {
if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) { if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {
// special case: 1"" - count first quote as an inch // special case: 1"" - count first quote as an inch
canClose = canOpen = false; canClose = canOpen = false;
}
} }
}
if (canOpen && canClose) { if (canOpen && canClose) {
// treat this as the middle of the word // treat this as the middle of the word
canOpen = canClose = false; canOpen = canClose = false;
} }
if (!canOpen && !canClose) { if (!canOpen && !canClose) {
// middle of word // middle of word
if (isSingle) { if (isSingle) {
token.content = replaceAt(token.content, t.index, APOSTROPHE); token.content = replaceAt(token.content, t.index, APOSTROPHE);
}
continue;
} }
continue;
}
if (canClose) { if (canClose) {
// this could be a closing quote, rewind the stack to get a match // this could be a closing quote, rewind the stack to get a match
for (j = stack.length - 1; j >= 0; j--) { for (j = stack.length - 1; j >= 0; j--) {
item = stack[j];
if (stack[j].level < thisLevel) { break; }
if (item.single === isSingle && stack[j].level === thisLevel) {
item = stack[j]; item = stack[j];
if (stack[j].level < thisLevel) { break; } if (isSingle) {
if (item.single === isSingle && stack[j].level === thisLevel) { tokens[item.token].content = replaceAt(
item = stack[j]; tokens[item.token].content, item.pos, state.md.options.quotes[2]);
if (isSingle) { token.content = replaceAt(
tokens[item.token].content = replaceAt( token.content, t.index, state.md.options.quotes[3]);
tokens[item.token].content, item.pos, state.md.options.quotes[2]); } else {
token.content = replaceAt( tokens[item.token].content = replaceAt(
token.content, t.index, state.md.options.quotes[3]); tokens[item.token].content, item.pos, state.md.options.quotes[0]);
} else { token.content = replaceAt(token.content, t.index, state.md.options.quotes[1]);
tokens[item.token].content = replaceAt(
tokens[item.token].content, item.pos, state.md.options.quotes[0]);
token.content = replaceAt(token.content, t.index, state.md.options.quotes[1]);
}
stack.length = j;
continue OUTER;
} }
stack.length = j;
continue OUTER;
} }
} }
}
if (canOpen) { if (canOpen) {
stack.push({ stack.push({
token: i, token: i,
pos: t.index, pos: t.index,
single: isSingle, single: isSingle,
level: thisLevel level: thisLevel
}); });
} else if (canClose && isSingle) { } else if (canClose && isSingle) {
token.content = replaceAt(token.content, t.index, APOSTROPHE); token.content = replaceAt(token.content, t.index, APOSTROPHE);
}
} }
} }
} }
}
module.exports = function smartquotes(state) {
/*eslint max-depth:0*/
var blkIdx;
if (!state.md.options.typographer) { return; }
for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
if (state.tokens[blkIdx].type !== 'inline' ||
!QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {
continue;
}
process_inlines(state.tokens[blkIdx].children, state);
}
}; };

Loading…
Cancel
Save