Skip to content

Commit 2b8321d

Browse files
authored
JSX: Add support for plain text inside tags (#1357)
* 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
1 parent 212dd4e commit 2b8321d

11 files changed

+242
-15
lines changed

components/prism-core.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,14 @@ var _ = _self.Prism = {
272272
},
273273

274274
highlight: function (text, grammar, language) {
275-
var tokens = _.tokenize(text, grammar);
276-
return Token.stringify(_.util.encode(tokens), language);
275+
var env = {
276+
text: text,
277+
grammar: grammar,
278+
language: language
279+
};
280+
env.tokens = _.tokenize(text, grammar);
281+
_.hooks.run('after-tokenize', env);
282+
return Token.stringify(_.util.encode(env.tokens), language);
277283
},
278284

279285
matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target) {

components/prism-core.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/prism-jsx.js

+86
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,90 @@ Prism.languages.insertBefore('inside', 'attr-value',{
3232
}
3333
}, Prism.languages.jsx.tag);
3434

35+
// The following will handle plain text inside tags
36+
var stringifyToken = function (token) {
37+
if (typeof token === 'string') {
38+
return token;
39+
}
40+
if (typeof token.content === 'string') {
41+
return token.content;
42+
}
43+
return token.content.map(stringifyToken).join('');
44+
};
45+
46+
var walkTokens = function (tokens) {
47+
var openedTags = [];
48+
for (var i = 0; i < tokens.length; i++) {
49+
var token = tokens[i];
50+
var notTagNorBrace = false;
51+
52+
if (typeof token !== 'string') {
53+
if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
54+
// We found a tag, now find its kind
55+
56+
if (token.content[0].content[0].content === '</') {
57+
// Closing tag
58+
if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
59+
// Pop matching opening tag
60+
openedTags.pop();
61+
}
62+
} else {
63+
if (token.content[token.content.length - 1].content === '/>') {
64+
// Autoclosed tag, ignore
65+
} else {
66+
// Opening tag
67+
openedTags.push({
68+
tagName: stringifyToken(token.content[0].content[1]),
69+
openedBraces: 0
70+
});
71+
}
72+
}
73+
} else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
74+
75+
// Here we might have entered a JSX context inside a tag
76+
openedTags[openedTags.length - 1].openedBraces++;
77+
78+
} else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
79+
80+
// Here we might have left a JSX context inside a tag
81+
openedTags[openedTags.length - 1].openedBraces--;
82+
83+
} else {
84+
notTagNorBrace = true
85+
}
86+
}
87+
if (notTagNorBrace || typeof token === 'string') {
88+
if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
89+
// Here we are inside a tag, and not inside a JSX context.
90+
// That's plain text: drop any tokens matched.
91+
var plainText = stringifyToken(token);
92+
93+
// And merge text with adjacent text
94+
if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
95+
plainText += stringifyToken(tokens[i + 1]);
96+
tokens.splice(i + 1, 1);
97+
}
98+
if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
99+
plainText = stringifyToken(tokens[i - 1]) + plainText;
100+
tokens.splice(i - 1, 1);
101+
i--;
102+
}
103+
104+
tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
105+
}
106+
}
107+
108+
if (token.content && typeof token.content !== 'string') {
109+
walkTokens(token.content);
110+
}
111+
}
112+
};
113+
114+
Prism.hooks.add('after-tokenize', function (env) {
115+
if (env.language !== 'jsx' && env.language !== 'tsx') {
116+
return;
117+
}
118+
walkTokens(env.tokens);
119+
});
120+
35121
}(Prism));

components/prism-jsx.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

prism.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,14 @@ var _ = _self.Prism = {
277277
},
278278

279279
highlight: function (text, grammar, language) {
280-
var tokens = _.tokenize(text, grammar);
281-
return Token.stringify(_.util.encode(tokens), language);
280+
var env = {
281+
text: text,
282+
grammar: grammar,
283+
language: language
284+
};
285+
env.tokens = _.tokenize(text, grammar);
286+
_.hooks.run('after-tokenize', env);
287+
return Token.stringify(_.util.encode(env.tokens), language);
282288
},
283289

284290
matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target) {

0 commit comments

Comments
 (0)