Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 106 additions & 72 deletions components/prism-markup-templating.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,123 @@
Prism.languages['markup-templating'] = {};

Object.defineProperties(Prism.languages['markup-templating'], {
buildPlaceholders: {
// Tokenize all inline templating expressions matching placeholderPattern
// If the replaceFilter function is provided, it will be called with every match.
// If it returns false, the match will not be replaced.
value: function (env, language, placeholderPattern, replaceFilter) {
if (env.language !== language) {
return;
}
(function (Prism) {

env.tokenStack = [];
/**
* Returns the placeholder for the given language id and index.
*
* @param {string} language
* @param {string|number} index
* @returns {string}
*/
function getPlaceholder(language, index) {
return '___' + language.toUpperCase() + index + '___';
}

env.code = env.code.replace(placeholderPattern, function(match) {
if (typeof replaceFilter === 'function' && !replaceFilter(match)) {
return match;
Object.defineProperties(Prism.languages['markup-templating'] = {}, {
buildPlaceholders: {
/**
* Tokenize all inline templating expressions matching `placeholderPattern`.
*
* If `replaceFilter` is provided, only matches of `placeholderPattern` for which `replaceFilter` returns
* `true` will be replaced.
*
* @param {object} env The environment of the `before-tokenize` hook.
* @param {string} language The language id.
* @param {RegExp} placeholderPattern The matches of this pattern will be replaced by placeholders.
* @param {(match: string) => boolean} [replaceFilter]
*/
value: function (env, language, placeholderPattern, replaceFilter) {
if (env.language !== language) {
return;
}
var i = env.tokenStack.length;
// Check for existing strings
while (env.code.indexOf('___' + language.toUpperCase() + i + '___') !== -1)
++i;

// Create a sparse array
env.tokenStack[i] = match;
var tokenStack = env.tokenStack = [];

return '___' + language.toUpperCase() + i + '___';
});
env.code = env.code.replace(placeholderPattern, function (match) {
if (typeof replaceFilter === 'function' && !replaceFilter(match)) {
return match;
}
var i = tokenStack.length;
var placeholder;

// Switch the grammar to markup
env.grammar = Prism.languages.markup;
}
},
tokenizePlaceholders: {
// Replace placeholders with proper tokens after tokenizing
value: function (env, language) {
if (env.language !== language || !env.tokenStack) {
return;
}
// Check for existing strings
while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1)
++i;

// Switch the grammar back
env.grammar = Prism.languages[language];
// Create a sparse array
tokenStack[i] = match;

var j = 0;
var keys = Object.keys(env.tokenStack);
var walkTokens = function (tokens) {
if (j >= keys.length) {
return placeholder;
});

// Switch the grammar to markup
env.grammar = Prism.languages.markup;
}
},
tokenizePlaceholders: {
/**
* Replace placeholders with proper tokens after tokenizing.
*
* @param {object} env The environment of the `after-tokenize` hook.
* @param {string} language The language id.
*/
value: function (env, language) {
if (env.language !== language || !env.tokenStack) {
return;
}
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (typeof token === 'string' || (token.content && typeof token.content === 'string')) {
var k = keys[j];
var t = env.tokenStack[k];
var s = typeof token === 'string' ? token : token.content;

var index = s.indexOf('___' + language.toUpperCase() + k + '___');
if (index > -1) {
++j;
var before = s.substring(0, index);
var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar, language), 'language-' + language, t);
var after = s.substring(index + ('___' + language.toUpperCase() + k + '___').length);
var replacement;
if (before || after) {
replacement = [before, middle, after].filter(function (v) { return !!v; });
walkTokens(replacement);
} else {
replacement = middle;
}
if (typeof token === 'string') {
Array.prototype.splice.apply(tokens, [i, 1].concat(replacement));
} else {
token.content = replacement;
}

if (j >= keys.length) {
break;
// Switch the grammar back
env.grammar = Prism.languages[language];

var j = 0;
var keys = Object.keys(env.tokenStack);

function walkTokens(tokens) {
for (var i = 0; i < tokens.length; i++) {
// all placeholders are replaced already
if (j >= keys.length) {
break;
}

var token = tokens[i];
if (typeof token === 'string' || (token.content && typeof token.content === 'string')) {
var k = keys[j];
var t = env.tokenStack[k];
var s = typeof token === 'string' ? token : token.content;
var placeholder = getPlaceholder(language, k);

var index = s.indexOf(placeholder);
if (index > -1) {
++j;

var before = s.substring(0, index);
var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar), 'language-' + language, t);
var after = s.substring(index + placeholder.length);

var replacement = [];
if (before) {
replacement.push.apply(replacement, walkTokens([before]));
}
replacement.push(middle);
if (after) {
replacement.push.apply(replacement, walkTokens([after]));
}

if (typeof token === 'string') {
tokens.splice.apply(tokens, [i, 1].concat(replacement));
} else {
token.content = replacement;
}
}
} else if (token.content /* && typeof token.content !== 'string' */) {
walkTokens(token.content);
}
} else if (token.content && typeof token.content !== 'string') {
walkTokens(token.content);
}

return tokens;
}
};

walkTokens(env.tokens);
walkTokens(env.tokens);
}
}
}
});
});

}(Prism));
2 changes: 1 addition & 1 deletion components/prism-markup-templating.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.