Browse Source

Add multichar replacements in smartquotes

fix #115
pull/124/head
Alex Kocharin 10 years ago
parent
commit
a7b2b3b4e8
  1. 5
      README.md
  2. 7
      lib/index.js
  3. 5
      lib/presets/commonmark.js
  4. 5
      lib/presets/default.js
  5. 5
      lib/presets/zero.js
  6. 2
      lib/rules_core/replacements.js
  7. 28
      lib/rules_core/smartquotes.js
  8. 33
      test/misc.js

5
README.md

@ -111,7 +111,10 @@ var md = require('markdown-it')({
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
// and smartquotes on. Could be either a String or an Array.
//
// For example, you can use '«»„“' for Russian, '„“‚‘' for German,
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
quotes: '“”‘’',
// Highlighter function. Should return escaped HTML,

7
lib/index.js

@ -152,9 +152,10 @@ function normalizeLinkText(url) {
* - __typographer__ - `false`. Set `true` to enable [some language-neutral
* replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.js) +
* quotes beautification (smartquotes).
* - __quotes__ - `“”‘’`, string. Double + single quotes replacement pairs, when
* typographer enabled and smartquotes on. Set doubles to '«»' for Russian,
* '„“' for German.
* - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement
* pairs, when typographer enabled and smartquotes on. For example, you can
* use `'«»„“'` for Russian, `'„“‚‘'` for German, and
* `['«\xA0', '\xA0»', '‹\xA0', '\xA0›']` for French (including nbsp).
* - __highlight__ - `null`. Highlighter function for fenced code blocks.
* Highlighter `function (str, lang)` should return escaped HTML. It can also
* return empty string if the source was not changed and should be escaped externaly.

5
lib/presets/commonmark.js

@ -15,7 +15,10 @@ module.exports = {
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
// and smartquotes on. Could be either a String or an Array.
//
// For example, you can use '«»„“' for Russian, '„“‚‘' for German,
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */,
// Highlighter function. Should return escaped HTML,

5
lib/presets/default.js

@ -15,7 +15,10 @@ module.exports = {
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
// and smartquotes on. Could be either a String or an Array.
//
// For example, you can use '«»„“' for Russian, '„“‚‘' for German,
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */,
// Highlighter function. Should return escaped HTML,

5
lib/presets/zero.js

@ -16,7 +16,10 @@ module.exports = {
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
// and smartquotes on. Could be either a String or an Array.
//
// For example, you can use '«»„“' for Russian, '„“‚‘' for German,
// and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp).
quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */,
// Highlighter function. Should return escaped HTML,

2
lib/rules_core/replacements.js

@ -1,7 +1,5 @@
// Simple typographyc replacements
//
// '' → ‘’
// "" → “”. Set '«»' for Russian, '„“' for German, empty to disable
// (c) (C) → ©
// (tm) (TM) → ™
// (r) (R) → ®

28
lib/rules_core/smartquotes.js

@ -19,7 +19,7 @@ function replaceAt(str, index, ch) {
function process_inlines(tokens, state) {
var i, token, text, t, pos, max, thisLevel, item, lastChar, nextChar,
isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace,
canOpen, canClose, j, isSingle, stack;
canOpen, canClose, j, isSingle, stack, openQuote, closeQuote;
stack = [];
@ -104,16 +104,28 @@ function process_inlines(tokens, state) {
if (stack[j].level < thisLevel) { break; }
if (item.single === isSingle && stack[j].level === thisLevel) {
item = stack[j];
if (isSingle) {
tokens[item.token].content = replaceAt(
tokens[item.token].content, item.pos, state.md.options.quotes[2]);
token.content = replaceAt(
token.content, t.index, state.md.options.quotes[3]);
openQuote = state.md.options.quotes[2];
closeQuote = state.md.options.quotes[3];
} else {
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]);
openQuote = state.md.options.quotes[0];
closeQuote = state.md.options.quotes[1];
}
// replace token.content *before* tokens[item.token].content,
// because, if they are pointing at the same token, replaceAt
// could mess up indices when quote length != 1
token.content = replaceAt(token.content, t.index, closeQuote);
tokens[item.token].content = replaceAt(
tokens[item.token].content, item.pos, openQuote);
pos += closeQuote.length - 1;
if (item.token === i) { pos += openQuote.length - 1; }
text = token.content;
max = text.length;
stack.length = j;
continue OUTER;
}

33
test/misc.js

@ -275,3 +275,36 @@ describe('maxNesting', function () {
});
});
describe('smartquotes', function () {
var md = markdownit({
typographer: true,
// all strings have different length to make sure
// we didn't accidentally count the wrong one
quotes: [ '[[[', ']]', '(((((', '))))' ]
});
it('Should support multi-character quotes', function () {
assert.strictEqual(
md.render('"foo" \'bar\''),
'<p>[[[foo]] (((((bar))))</p>\n'
);
});
it('Should support nested multi-character quotes', function () {
assert.strictEqual(
md.render('"foo \'bar\' baz"'),
'<p>[[[foo (((((bar)))) baz]]</p>\n'
);
});
it('Should support multi-character quotes in different tags', function () {
assert.strictEqual(
md.render('"a *b \'c *d* e\' f* g"'),
'<p>[[[a <em>b (((((c <em>d</em> e)))) f</em> g]]</p>\n'
);
});
});

Loading…
Cancel
Save