From 31aa00856647433c3d4d2f2eb5840d2322e9ffa0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Nov 2020 23:41:21 +0900 Subject: Improve MFM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MFMの構文を調整 + 新しいアニメーション追加 Resolve #6816 --- src/mfm/language.ts | 61 +++++++++++++++++++++------------------------------- src/mfm/to-html.ts | 44 +------------------------------------ src/mfm/to-string.ts | 37 +++++-------------------------- 3 files changed, 31 insertions(+), 111 deletions(-) (limited to 'src/mfm') diff --git a/src/mfm/language.ts b/src/mfm/language.ts index 61d6422558..8e15ca43b9 100644 --- a/src/mfm/language.ts +++ b/src/mfm/language.ts @@ -23,7 +23,6 @@ export const mfmLanguage = P.createLanguage({ root: r => P.alt(r.block, r.inline).atLeast(1), plain: r => P.alt(r.emoji, r.text).atLeast(1), block: r => P.alt( - r.title, r.quote, r.search, r.blockCode, @@ -37,14 +36,6 @@ export const mfmLanguage = P.createLanguage({ return P.makeFailure(i, 'not newline'); } }), - title: r => r.startOfLine.then(P((input, i) => { - const text = input.substr(i); - const match = text.match(/^([【\[]([^【\[】\]\n]+?)[】\]])(\n|$)/); - if (!match) return P.makeFailure(i, 'not a title'); - const q = match[2].trim(); - const contents = r.inline.atLeast(1).tryParse(q); - return P.makeSuccess(i + match[0].length, createTree('title', contents, {})); - })), quote: r => r.startOfLine.then(P((input, i) => { const text = input.substr(i); if (!text.match(/^>[\s\S]+?/)) return P.makeFailure(i, 'not a quote'); @@ -67,17 +58,10 @@ export const mfmLanguage = P.createLanguage({ return P.makeSuccess(i + match[0].length, createLeaf('blockCode', { code: match[2], lang: match[1] ? match[1].trim() : null })); })), inline: r => P.alt( - r.big, r.bold, r.small, r.italic, r.strike, - r.motion, - r.spin, - r.jump, - r.flip, - r.twitch, - r.shake, r.inlineCode, r.mathInline, r.mention, @@ -85,9 +69,9 @@ export const mfmLanguage = P.createLanguage({ r.url, r.link, r.emoji, + r.fn, r.text ), - big: r => P.regexp(/^\*\*\*([\s\S]+?)\*\*\*/, 1).map(x => createTree('big', r.inline.atLeast(1).tryParse(x), {})), bold: r => { const asterisk = P.regexp(/\*\*([\s\S]+?)\*\*/, 1); const underscore = P.regexp(/__([a-zA-Z0-9\s]+?)__/, 1); @@ -107,25 +91,6 @@ export const mfmLanguage = P.createLanguage({ return P.alt(xml, underscore).map(x => createTree('italic', r.inline.atLeast(1).tryParse(x), {})); }, strike: r => P.regexp(/~~([^\n~]+?)~~/, 1).map(x => createTree('strike', r.inline.atLeast(1).tryParse(x), {})), - motion: r => { - const paren = P.regexp(/\(\(\(([\s\S]+?)\)\)\)/, 1); - const xml = P.regexp(/(.+?)<\/motion>/, 1); - return P.alt(paren, xml).map(x => createTree('motion', r.inline.atLeast(1).tryParse(x), {})); - }, - spin: r => { - return P((input, i) => { - const text = input.substr(i); - const match = text.match(/^(.+?)<\/spin>/i); - if (!match) return P.makeFailure(i, 'not a spin'); - return P.makeSuccess(i + match[0].length, { - content: match[2], attr: match[1] ? match[1].trim() : null - }); - }).map(x => createTree('spin', r.inline.atLeast(1).tryParse(x.content), { attr: x.attr })); - }, - jump: r => P.regexp(/(.+?)<\/jump>/, 1).map(x => createTree('jump', r.inline.atLeast(1).tryParse(x), {})), - flip: r => P.regexp(/(.+?)<\/flip>/, 1).map(x => createTree('flip', r.inline.atLeast(1).tryParse(x), {})), - twitch: r => P.regexp(/(.+?)<\/twitch>/, 1).map(x => createTree('twitch', r.inline.atLeast(1).tryParse(x), {})), - shake: r => P.regexp(/(.+?)<\/shake>/, 1).map(x => createTree('shake', r.inline.atLeast(1).tryParse(x), {})), center: r => r.startOfLine.then(P.regexp(/
([\s\S]+?)<\/center>/, 1).map(x => createTree('center', r.inline.atLeast(1).tryParse(x), {}))), inlineCode: () => P.regexp(/`([^´\n]+?)`/, 1).map(x => createLeaf('inlineCode', { code: x })), mathBlock: r => r.startOfLine.then(P.regexp(/\\\[([\s\S]+?)\\\]/, 1).map(x => createLeaf('mathBlock', { formula: x.trim() }))), @@ -192,5 +157,29 @@ export const mfmLanguage = P.createLanguage({ const code = P.regexp(emojiRegex).map(x => createLeaf('emoji', { emoji: x })); return P.alt(name, code); }, + fn: r => { + return P.seqObj( + P.string('['), ['fn', P.regexp(/[^\s\n\[\]]+/)] as any, P.string(' '), P.optWhitespace, ['text', P.regexp(/[^\n\[\]]+/)] as any, P.string(']'), + ).map((x: any) => { + let name = x.fn; + const args = {}; + const separator = x.fn.indexOf('.'); + if (separator > -1) { + name = x.fn.substr(0, separator); + for (const arg of x.fn.substr(separator + 1).split(',')) { + const kv = arg.split('='); + if (kv.length === 1) { + args[kv[0]] = true; + } else { + args[kv[0]] = kv[1]; + } + } + } + return createTree('fn', r.inline.atLeast(1).tryParse(x.text), { + name, + args + }); + }); + }, text: () => P.any.map(x => createLeaf('text', { text: x })) }); diff --git a/src/mfm/to-html.ts b/src/mfm/to-html.ts index 36680e374e..ab3f7c3d16 100644 --- a/src/mfm/to-html.ts +++ b/src/mfm/to-html.ts @@ -25,12 +25,6 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione return el; }, - big(token) { - const el = doc.createElement('strong'); - appendChildren(token.children, el); - return el; - }, - small(token) { const el = doc.createElement('small'); appendChildren(token.children, el); @@ -49,42 +43,12 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione return el; }, - motion(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - spin(token) { + fn(token) { const el = doc.createElement('i'); appendChildren(token.children, el); return el; }, - jump(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - twitch(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - shake(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - flip(token) { - const el = doc.createElement('span'); - appendChildren(token.children, el); - return el; - }, - blockCode(token) { const pre = doc.createElement('pre'); const inner = doc.createElement('code'); @@ -157,12 +121,6 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione return el; }, - title(token) { - const el = doc.createElement('h1'); - appendChildren(token.children, el); - return el; - }, - text(token) { const el = doc.createElement('span'); const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x) as Node); diff --git a/src/mfm/to-string.ts b/src/mfm/to-string.ts index 6b8dcf2c39..b70b99cbda 100644 --- a/src/mfm/to-string.ts +++ b/src/mfm/to-string.ts @@ -18,10 +18,6 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin return `**${appendChildren(token.children, opts)}**`; }, - big(token, opts) { - return `***${appendChildren(token.children, opts)}***`; - }, - small(token, opts) { return `${appendChildren(token.children, opts)}`; }, @@ -34,30 +30,11 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin return `${appendChildren(token.children, opts)}`; }, - motion(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - spin(token, opts) { - const attr = token.node.props?.attr; - const post = attr ? ` ${attr}` : ''; - return `${appendChildren(token.children, opts)}`; - }, - - jump(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - twitch(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - shake(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - flip(token, opts) { - return `${appendChildren(token.children, opts)}`; + fn(token, opts) { + const name = token.node.props?.name; + const args = token.node.props?.args || {}; + const argsStr = Object.entries(args).map(([k, v]) => v === true ? k : `${k}=${v}`).join(','); + return `[${name}${argsStr !== '' ? '.' + argsStr : ''} ${appendChildren(token.children, opts)}]`; }, blockCode(token) { @@ -104,10 +81,6 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin return `${appendChildren(token.children, {doNyaize: false}).replace(/^/gm,'>').trim()}\n`; }, - title(token, opts) { - return `[${appendChildren(token.children, opts)}]\n`; - }, - text(token, opts) { return (opts && opts.doNyaize) ? nyaize(token.node.props.text) : token.node.props.text; }, -- cgit v1.2.3-freya