[😁 Resolved]How to write a custom syntax plugin to parse ==highlight_content==
to <mark>highlight_content</mark>
?
#1674
Answered
by
yswang0927
yswang0927
asked this question in
Q&A
-
Hello, Can somebody help me? Thanks! ==================================
|
Beta Was this translation helpful? Give feedback.
Answered by
yswang0927
Feb 18, 2025
Replies: 2 comments 4 replies
-
1. Transform your syntaxFirst, you'll need a remark plugin to transform your syntax to target AST, like how https://github.com/remarkjs/remark-math works. ==highlight_content== to {
type: 'markdown_highlight_type',
value: 'highlight_content'
} 2. Add an implementation in schema// I use `pm_highlight_type` and `markdown_highlight_type` to show how it works
// but it's okay in realworld to use same value as type.
export const highlightSchema = $markSchema('pm_highlight_type', () => ({
inclusive: false,
code: true,
parseDOM: [
{
tag: `span[data-type="inline_highlight"]`,
},
],
toDOM: (mark) => ['span', { 'data-type': "inline_highlight" }],
parseMarkdown: {
// TODO
},
toMarkdown: {
// TODO
},
})) 3. Implement the markdown transformerparseMarkdown: {
match: (node) => node.type === 'markdown_highlight_type',
runner: (state, node, markType) => {
state
.openMark(markType)
next(node.children)
.closeMark(markType)
},
},
toMarkdown: {
match: (mark) => mark.type.name === 'pm_highlight_type',
runner: (state, mark, node) => {
// if you implemented the toMarkdownExtension in remark
// similar to: https://github.com/remarkjs/remark-math/blob/main/packages/remark-math/lib/index.js#L34
state.withMark(mark, 'markdown_highlight_type')
// if you didn't implement toMarkdownExtension
state.addText('==').addText(node.text || '').addText('==')
},
} |
Beta Was this translation helpful? Give feedback.
4 replies
-
Hi, @Saul-Mirone I wrote it, it works ok now 😁, thank you very much 🤝🤝 import { $inputRule, $node, $remark } from '@milkdown/kit/utils';
import { InputRule } from '@milkdown/kit/prose/inputrules';
/**
* custom-syntax-plugin: Parse `==content==` to `<mark>content</mark>`
*/
const remarkMark = $remark('remarkMark', () => () => (tree) => {
const visit = (node) => {
// only parse text node
if (node.type === 'text' && typeof node.value === 'string') {
const value = node.value;
const regex = /==([^=]+)==/g;
let match;
let lastIndex = 0;
const nodes = [];
while ((match = regex.exec(value)) !== null) {
// add before text node
if (match.index > lastIndex) {
nodes.push({
type: 'text',
value: value.slice(lastIndex, match.index)
});
}
// add mark node
nodes.push({
type: 'mark',
content: match[1]
});
//lastIndex = match.index + match[0].length;
lastIndex = regex.lastIndex;
}
// add other text node
if (lastIndex < value.length) {
nodes.push({
type: 'text',
value: value.slice(lastIndex)
});
}
return nodes.length > 0 ? nodes : [node];
}
// parse children nodes
if (Array.isArray(node.children)) {
node.children = node.children.flatMap(visit);
}
return [node];
};
tree.children = tree.children.flatMap(visit);
return tree;
});
const markNode = $node('mark', () => ({
group: 'inline',
inline: true,
atom: true,
marks: '',
content: '',
attrs: {
content: { default: '' },
},
parseDOM: [{
tag: 'mark',
getAttrs: (dom) => ({
'content': dom.textContent,
}),
}],
toDOM: (node) => ['mark', {}, node.attrs.content],
parseMarkdown: {
match: (node) => node.type === 'mark',
runner: (state, node, type) => {
state.addNode(type, { content: node.content });
},
},
toMarkdown: {
match: (node) => node.type.name === 'mark',
runner: (state, node) => {
state.addNode('text', undefined, undefined, {
value: `==${node.attrs.content}==`
});
},
}
}));
const markInputRule = $inputRule((ctx) => new InputRule(/==([^=]+)==/, (state, match, start, end) => {
const [okay, content = ''] = match;
const { tr } = state;
if (okay) {
tr.replaceWith(start, end, markNode.type(ctx).create({ 'content': content }));
}
return tr;
}));
export const highlightMarkPlugin = [remarkMark, markInputRule, markNode].flat(); |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
yswang0927
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, @Saul-Mirone
I wrote it, it works ok now 😁, thank you very much 🤝🤝