Skip to content

Commit 1ad1ba4

Browse files
authored
feat(core, Сolor): added support for custom escape characters (#746)
1 parent 6df182e commit 1ad1ba4

File tree

9 files changed

+58
-17
lines changed

9 files changed

+58
-17
lines changed

demo/defaults/md-plugins.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import video from '@diplodoc/transform/lib/plugins/video';
2020
import type {PluginWithParams} from 'markdown-it/lib';
2121

2222
import {emojiDefs} from 'src/bundle/emoji';
23-
import type {RenderPreviewParams} from 'src/index';
23+
import {type RenderPreviewParams, colorClassName} from 'src/index';
2424
import color from 'src/markdown-it/color';
2525
import {bare as emoji} from 'src/markdown-it/emoji';
2626
import ins from 'src/markdown-it/ins';
@@ -72,7 +72,7 @@ export function getPlugins({
7272
const extendedPlugins = defaultPlugins.concat(
7373
(md) => md.use(emoji, {defs: emojiDefs}),
7474
checkbox,
75-
color,
75+
(md) => md.use(color, {escape: true, defaultClassName: colorClassName}),
7676
ins,
7777
latex({bundle: false, validate: false, runtime: LATEX_RUNTIME}),
7878
mark,

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@
183183
"@codemirror/search": "^6.5.8",
184184
"@codemirror/state": "^6.5.1",
185185
"@codemirror/view": "^6.36.2",
186+
"@diplodoc/color-extension": "0.1.1",
186187
"@diplodoc/utils": "^2.1.0",
187188
"@gravity-ui/i18n": "^1.7.0",
188189
"@gravity-ui/icons": "^2.12.0",
@@ -194,7 +195,6 @@
194195
"is-number": "^7.0.0",
195196
"lodash": "^4.17.21",
196197
"markdown-it-attrs": "^4.2.0",
197-
"markdown-it-color": "^2.1.1",
198198
"markdown-it-emoji": "2.0.2",
199199
"markdown-it-ins": "^3.0.1",
200200
"markdown-it-mark": "^3.0.1",

src/core/ExtensionsManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export class ExtensionsManager {
129129
this.#spec.marks().forEach(this.processMark);
130130
}
131131

132-
private processNode = (name: string, {spec, fromMd, toMd: toMd, view}: ExtensionNodeSpec) => {
132+
private processNode = (name: string, {spec, fromMd, toMd, view}: ExtensionNodeSpec) => {
133133
this.#schemaRegistry.addNode(name, spec);
134134

135135
this.#parserRegistry.addToken(fromMd.tokenName || name, fromMd.tokenSpec);

src/core/markdown/MarkdownSerializer.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export class MarkdownSerializerState {
126126
noAutoBlank: boolean;
127127
isAutolink: boolean | undefined;
128128
escapeWhitespace: boolean;
129+
escapeCharacters?: string[];
129130

130131
private readonly nodes: NodeMap;
131132
private readonly marks: MarkMap;
@@ -328,8 +329,9 @@ export class MarkdownSerializerState {
328329
while (keep < Math.min(active.length, len) && marks[keep].eq(active[keep])) ++keep;
329330

330331
// Close the marks that need to be closed
331-
while (keep < active.length)
332+
while (keep < active.length) {
332333
this.text(this.markString(active.pop()!, false, parent, index), false)
334+
}
333335

334336
// Output any previously expelled trailing whitespace outside the marks
335337
if (leading) this.text(leading)
@@ -378,7 +380,12 @@ export class MarkdownSerializerState {
378380
// have special meaning only at the start of the line.
379381
esc(str: string, startOfLine = false) {
380382
// eslint-disable-next-line no-useless-escape
381-
const escRegexp = this.options?.commonEscape || /[`\^+*\\\|~\[\]\{\}<>\$_]/g;
383+
const defaultEsc = /[`\^+*\\\|~\[\]\{\}<>\$_]/g;
384+
const extraChars = this.escapeCharacters?.length ? this.escapeCharacters.map(c => '\\' + c).join('') : '';
385+
const escRegexp = this.options?.commonEscape ||
386+
// Compose the escape regexp from default, options, and extra characters
387+
new RegExp(defaultEsc.source + (extraChars ? `|[${extraChars}]` : ''), 'g');
388+
382389
const startOfLineEscRegexp = this.options?.startOfLineEscape || /^[:#\-*+>]/;
383390

384391
str = str.replace(escRegexp, '\\$&');

src/extensions/yfm/Color/Color.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ describe('Color extension', () => {
3535
it('should parse code inside text', () =>
3636
same('he{c2}(llo wor)ld!', doc(p('he', c2('llo wor'), 'ld!'))));
3737

38+
it('should parse nested color marks with escaped parentheses', () =>
39+
same(
40+
'{green}(some\\(){blue}(2,3){green}(\\))',
41+
doc(
42+
p(
43+
color({[colorMarkName]: 'green'}, 'some('),
44+
color({[colorMarkName]: 'blue'}, '2,3'),
45+
color({[colorMarkName]: 'green'}, ')'),
46+
),
47+
),
48+
));
49+
3850
it('should parse span with md-colorify--* classname', () => {
3951
parseDOM(
4052
schema,
@@ -74,4 +86,18 @@ describe('Color extension', () => {
7486
doc(p('text with style color')),
7587
);
7688
});
89+
90+
it('should parse nested color spans for escaped parentheses', () => {
91+
parseDOM(
92+
schema,
93+
'<span class="yfm-colorify yfm-colorify--green">some(<span class="yfm-colorify yfm-colorify--blue">2,3</span><span class="yfm-colorify yfm-colorify--green">)</span></span>',
94+
doc(
95+
p(
96+
color({[colorMarkName]: 'green'}, 'some('),
97+
color({[colorMarkName]: 'blue'}, '2,3'),
98+
color({[colorMarkName]: 'green'}, ')'),
99+
),
100+
),
101+
);
102+
});
77103
});

src/extensions/yfm/Color/ColorSpecs/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import mdPlugin from 'src/markdown-it/color';
1+
import type MarkdownIt from 'markdown-it';
2+
3+
import color from 'src/markdown-it/color';
24

35
import type {ExtensionAuto} from '../../../../core';
46
import {markTypeFactory} from '../../../../utils/schema';
@@ -20,6 +22,8 @@ export type ColorSpecsOptions = {
2022

2123
export const ColorSpecs: ExtensionAuto<ColorSpecsOptions> = (builder, opts) => {
2224
const {validateClassNameColorName, parseStyleColorValue} = opts;
25+
const mdPlugin = (md: MarkdownIt) =>
26+
md.use(color, {escape: true, defaultClassName: colorClassName});
2327

2428
builder
2529
.configureMd((md) => md.use(mdPlugin, {defaultClassName: colorClassName, inline: false}))
@@ -87,10 +91,14 @@ export const ColorSpecs: ExtensionAuto<ColorSpecsOptions> = (builder, opts) => {
8791
},
8892
},
8993
toMd: {
90-
open: (_state, mark) => {
94+
open: (state, mark) => {
95+
state.escapeCharacters = ['(', ')'];
9196
return `{${mark.attrs[colorMarkName]}}(`;
9297
},
93-
close: ')',
98+
close: (state) => {
99+
state.escapeCharacters = undefined;
100+
return `)`;
101+
},
94102
mixable: true,
95103
expelEnclosingWhitespace: true,
96104
},

src/markdown-it/color.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import {colorPlugin} from 'markdown-it-color';
1+
import {colorPlugin} from '@diplodoc/color-extension';
22

33
export default colorPlugin;

src/markdown-it/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### Re-exports Markdown-it plugins:
44

5-
- [markdown-it-color](https://github.com/nkjmsss/markdown-it-color)
5+
- [@diplodoc/color-extension](https://github.com/diplodoc-platform/color-extension)
66
- [markdown-it-ins](https://github.com/markdown-it/markdown-it-ins)
77
- [markdown-it-mark](https://github.com/markdown-it/markdown-it-mark)
88
- [markdown-it-sub](https://github.com/markdown-it/markdown-it-sub)

0 commit comments

Comments
 (0)