Skip to content

Commit

Permalink
JSX: Add support for plain text inside tags (#1357)
Browse files Browse the repository at this point in the history
* JSX: Add support for plain text inside tags

* JSX: Use a "plain-text" token to identify plain text

* TSX: Add support for plain text

* Fix test after merge
  • Loading branch information
Golmote authored Mar 20, 2018
1 parent 212dd4e commit 2b8321d
Show file tree
Hide file tree
Showing 11 changed files with 242 additions and 15 deletions.
10 changes: 8 additions & 2 deletions components/prism-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,14 @@ var _ = _self.Prism = {
},

highlight: function (text, grammar, language) {
var tokens = _.tokenize(text, grammar);
return Token.stringify(_.util.encode(tokens), language);
var env = {
text: text,
grammar: grammar,
language: language
};
env.tokens = _.tokenize(text, grammar);
_.hooks.run('after-tokenize', env);
return Token.stringify(_.util.encode(env.tokens), language);
},

matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target) {
Expand Down
2 changes: 1 addition & 1 deletion components/prism-core.min.js

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

86 changes: 86 additions & 0 deletions components/prism-jsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,90 @@ Prism.languages.insertBefore('inside', 'attr-value',{
}
}, Prism.languages.jsx.tag);

// The following will handle plain text inside tags
var stringifyToken = function (token) {
if (typeof token === 'string') {
return token;
}
if (typeof token.content === 'string') {
return token.content;
}
return token.content.map(stringifyToken).join('');
};

var walkTokens = function (tokens) {
var openedTags = [];
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var notTagNorBrace = false;

if (typeof token !== 'string') {
if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
// We found a tag, now find its kind

if (token.content[0].content[0].content === '</') {
// Closing tag
if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
// Pop matching opening tag
openedTags.pop();
}
} else {
if (token.content[token.content.length - 1].content === '/>') {
// Autoclosed tag, ignore
} else {
// Opening tag
openedTags.push({
tagName: stringifyToken(token.content[0].content[1]),
openedBraces: 0
});
}
}
} else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {

// Here we might have entered a JSX context inside a tag
openedTags[openedTags.length - 1].openedBraces++;

} else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {

// Here we might have left a JSX context inside a tag
openedTags[openedTags.length - 1].openedBraces--;

} else {
notTagNorBrace = true
}
}
if (notTagNorBrace || typeof token === 'string') {
if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
// Here we are inside a tag, and not inside a JSX context.
// That's plain text: drop any tokens matched.
var plainText = stringifyToken(token);

// And merge text with adjacent text
if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
plainText += stringifyToken(tokens[i + 1]);
tokens.splice(i + 1, 1);
}
if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
plainText = stringifyToken(tokens[i - 1]) + plainText;
tokens.splice(i - 1, 1);
i--;
}

tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
}
}

if (token.content && typeof token.content !== 'string') {
walkTokens(token.content);
}
}
};

Prism.hooks.add('after-tokenize', function (env) {
if (env.language !== 'jsx' && env.language !== 'tsx') {
return;
}
walkTokens(env.tokens);
});

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

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

10 changes: 8 additions & 2 deletions prism.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,14 @@ var _ = _self.Prism = {
},

highlight: function (text, grammar, language) {
var tokens = _.tokenize(text, grammar);
return Token.stringify(_.util.encode(tokens), language);
var env = {
text: text,
grammar: grammar,
language: language
};
env.tokens = _.tokenize(text, grammar);
_.hooks.run('after-tokenize', env);
return Token.stringify(_.util.encode(env.tokens), language);
},

matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target) {
Expand Down
Loading

0 comments on commit 2b8321d

Please sign in to comment.