From 085325e65fa47c9dd9f2d261faeb7775f9f2486f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Jan 2019 13:40:38 +0900 Subject: [MFM] Improve title syntax detection --- test/mfm.ts | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/mfm.ts b/test/mfm.ts index a4b4a13973..2124f592fe 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -894,6 +894,13 @@ describe('MFM', () => { text('after') ]); }); + + it('ignore multiple title blocks', () => { + const tokens = analyze('【foo】bar【baz】'); + assert.deepStrictEqual(tokens, [ + text('【foo】bar【baz】') + ]); + }); }); describe('center', () => { -- cgit v1.2.3-freya From 71210595d2fade60c6f84041402d5627ac700928 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Jan 2019 13:48:56 +0900 Subject: [Test] Add a MFM test --- test/mfm.ts | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/mfm.ts b/test/mfm.ts index 2124f592fe..8eadfc7288 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -901,6 +901,13 @@ describe('MFM', () => { text('【foo】bar【baz】') ]); }); + + it('disallow linebreak in title', () => { + const tokens = analyze('【foo\nbar】'); + assert.deepStrictEqual(tokens, [ + text('【foo\nbar】') + ]); + }); }); describe('center', () => { -- cgit v1.2.3-freya From 50b809784fca1b9933fd8b1ef766228c959b5c45 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Jan 2019 13:55:11 +0900 Subject: Improve readability and some cleanups --- test/mfm.ts | 89 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 21 deletions(-) (limited to 'test') diff --git a/test/mfm.ts b/test/mfm.ts index 8eadfc7288..a5ea4b2933 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -152,9 +152,19 @@ describe('MFM', () => { it('can be analyzed', () => { const tokens = analyze('@himawari @hima_sub@namori.net お腹ペコい :cat: #yryr'); assert.deepStrictEqual(tokens, [ - leaf('mention', { acct: '@himawari', canonical: '@himawari', username: 'himawari', host: null }), + leaf('mention', { + acct: '@himawari', + canonical: '@himawari', + username: 'himawari', + host: null + }), text(' '), - leaf('mention', { acct: '@hima_sub@namori.net', canonical: '@hima_sub@namori.net', username: 'hima_sub', host: 'namori.net' }), + leaf('mention', { + acct: '@hima_sub@namori.net', + canonical: '@hima_sub@namori.net', + username: 'hima_sub', + host: 'namori.net' + }), text(' お腹ペコい '), leaf('emoji', { name: 'cat' }), text(' '), @@ -280,7 +290,12 @@ describe('MFM', () => { it('local', () => { const tokens = analyze('@himawari foo'); assert.deepStrictEqual(tokens, [ - leaf('mention', { acct: '@himawari', canonical: '@himawari', username: 'himawari', host: null }), + leaf('mention', { + acct: '@himawari', + canonical: '@himawari', + username: 'himawari', + host: null + }), text(' foo') ]); }); @@ -288,7 +303,12 @@ describe('MFM', () => { it('remote', () => { const tokens = analyze('@hima_sub@namori.net foo'); assert.deepStrictEqual(tokens, [ - leaf('mention', { acct: '@hima_sub@namori.net', canonical: '@hima_sub@namori.net', username: 'hima_sub', host: 'namori.net' }), + leaf('mention', { + acct: '@hima_sub@namori.net', + canonical: '@hima_sub@namori.net', + username: 'hima_sub', + host: 'namori.net' + }), text(' foo') ]); }); @@ -296,7 +316,12 @@ describe('MFM', () => { it('remote punycode', () => { const tokens = analyze('@hima_sub@xn--q9j5bya.xn--zckzah foo'); assert.deepStrictEqual(tokens, [ - leaf('mention', { acct: '@hima_sub@xn--q9j5bya.xn--zckzah', canonical: '@hima_sub@なもり.テスト', username: 'hima_sub', host: 'xn--q9j5bya.xn--zckzah' }), + leaf('mention', { + acct: '@hima_sub@xn--q9j5bya.xn--zckzah', + canonical: '@hima_sub@なもり.テスト', + username: 'hima_sub', + host: 'xn--q9j5bya.xn--zckzah' + }), text(' foo') ]); }); @@ -309,11 +334,26 @@ describe('MFM', () => { const tokens2 = analyze('@a\n@b\n@c'); assert.deepStrictEqual(tokens2, [ - leaf('mention', { acct: '@a', canonical: '@a', username: 'a', host: null }), + leaf('mention', { + acct: '@a', + canonical: '@a', + username: 'a', + host: null + }), text('\n'), - leaf('mention', { acct: '@b', canonical: '@b', username: 'b', host: null }), + leaf('mention', { + acct: '@b', + canonical: '@b', + username: 'b', + host: null + }), text('\n'), - leaf('mention', { acct: '@c', canonical: '@c', username: 'c', host: null }) + leaf('mention', { + acct: '@c', + canonical: '@c', + username: 'c', + host: null + }) ]); const tokens3 = analyze('**x**@a'); @@ -321,24 +361,31 @@ describe('MFM', () => { tree('bold', [ text('x') ], {}), - leaf('mention', { acct: '@a', canonical: '@a', username: 'a', host: null }) + leaf('mention', { + acct: '@a', + canonical: '@a', + username: 'a', + host: null + }) ]); - const tokens4 = analyze('@\n@v\n@veryverylongusername' /* \n@toolongtobeasamention */); + const tokens4 = analyze('@\n@v\n@veryverylongusername'); assert.deepStrictEqual(tokens4, [ text('@\n'), - leaf('mention', { acct: '@v', canonical: '@v', username: 'v', host: null }), + leaf('mention', { + acct: '@v', + canonical: '@v', + username: 'v', + host: null + }), text('\n'), - leaf('mention', { acct: '@veryverylongusername', canonical: '@veryverylongusername', username: 'veryverylongusername', host: null }), - // text('\n@toolongtobeasamention') - ]); - /* - const tokens5 = analyze('@domain_is@valid.example.com\n@domain_is@.invalid\n@domain_is@invali.d\n@domain_is@invali.d\n@domain_is@-invalid.com\n@domain_is@invalid-.com'); - assert.deepStrictEqual([ - leaf('mention', { acct: '@domain_is@valid.example.com', canonical: '@domain_is@valid.example.com', username: 'domain_is', host: 'valid.example.com' }), - text('\n@domain_is@.invalid\n@domain_is@invali.d\n@domain_is@invali.d\n@domain_is@-invalid.com\n@domain_is@invalid-.com') - ], tokens5); - */ + leaf('mention', { + acct: '@veryverylongusername', + canonical: '@veryverylongusername', + username: 'veryverylongusername', + host: null + }), + ]); }); }); -- cgit v1.2.3-freya From e5d938150386b32d2aa49e1a825453309209d9e4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Jan 2019 16:18:04 +0900 Subject: [MFM] Add spin syntax Resolve #4003 --- CHANGELOG.md | 1 + src/client/app/animation.styl | 5 +++++ src/client/app/common/views/components/mfm.ts | 11 +++++++++++ src/mfm/html.ts | 6 ++++++ src/mfm/parser.ts | 15 +++++++++++++++ test/mfm.ts | 9 +++++++++ 6 files changed, 47 insertions(+) (limited to 'test') diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e69e8f0a..f8291a1357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ unreleased * 外部サービス認証情報の配信 * 管理画面のモデレーションのUIを強化 * 管理画面からリモートユーザーの情報を更新できるように +* 回転構文の追加 * シンタックスハイライトの強化 * 引用投稿を削除したとき単なるRenoteとしてタイムラインに残る問題を修正 * イタリック構文の判定の改善 diff --git a/src/client/app/animation.styl b/src/client/app/animation.styl index a629165207..9cbd3ec6c8 100644 --- a/src/client/app/animation.styl +++ b/src/client/app/animation.styl @@ -26,3 +26,8 @@ transform: translateY(0); } } + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} diff --git a/src/client/app/common/views/components/mfm.ts b/src/client/app/common/views/components/mfm.ts index 8ffa566666..f6f95deb24 100644 --- a/src/client/app/common/views/components/mfm.ts +++ b/src/client/app/common/views/components/mfm.ts @@ -124,6 +124,17 @@ export default Vue.component('misskey-flavored-markdown', { }, genEl(token.children)); } + case 'spin': { + motionCount++; + const isLong = sumTextsLength(token.children) > 5 || countNodesF(token.children) > 3; + const isMany = motionCount > 3; + return (createElement as any)('span', { + attrs: { + style: (this.$store.state.settings.disableAnimatedMfm || isLong || isMany) ? 'display: inline-block;' : 'display: inline-block; animation: spin 1.5s linear infinite;' + }, + }, genEl(token.children)); + } + case 'url': { return [createElement(MkUrl, { key: Math.random(), diff --git a/src/mfm/html.ts b/src/mfm/html.ts index 6af2833858..a40ff19ac8 100644 --- a/src/mfm/html.ts +++ b/src/mfm/html.ts @@ -55,6 +55,12 @@ export default (tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteU return el; }, + spin(token) { + const el = doc.createElement('i'); + appendChildren(token.children, el); + return el; + }, + blockCode(token) { const pre = doc.createElement('pre'); const inner = doc.createElement('code'); diff --git a/src/mfm/parser.ts b/src/mfm/parser.ts index 560e226af9..5cd9fc04c2 100644 --- a/src/mfm/parser.ts +++ b/src/mfm/parser.ts @@ -91,6 +91,7 @@ const mfm = P.createLanguage({ root: r => P.alt( r.big, r.small, + r.spin, r.bold, r.strike, r.italic, @@ -122,6 +123,7 @@ const mfm = P.createLanguage({ r.hashtag, r.emoji, r.math, + r.spin, r.text ).atLeast(1).tryParse(x), {})), //#endregion @@ -140,6 +142,15 @@ const mfm = P.createLanguage({ ).atLeast(1).tryParse(x), {})), //#endregion + //#region Spin + spin: r => + P.regexp(/(.+?)<\/spin>/, 1) + .map(x => createTree('spin', P.alt( + r.emoji, + r.text + ).atLeast(1).tryParse(x), {})), + //#endregion + //#region Block code blockCode: r => newline.then( @@ -173,6 +184,7 @@ const mfm = P.createLanguage({ .map(x => createTree('center', P.alt( r.big, r.small, + r.spin, r.bold, r.strike, r.italic, @@ -261,6 +273,7 @@ const mfm = P.createLanguage({ return createTree('link', P.alt( r.big, r.small, + r.spin, r.bold, r.strike, r.italic, @@ -304,6 +317,7 @@ const mfm = P.createLanguage({ .map(x => createTree('motion', P.alt( r.bold, r.small, + r.spin, r.strike, r.italic, r.mention, @@ -364,6 +378,7 @@ const mfm = P.createLanguage({ const contents = P.alt( r.big, r.small, + r.spin, r.bold, r.strike, r.italic, diff --git a/test/mfm.ts b/test/mfm.ts index a5ea4b2933..d8cba8ee15 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -244,6 +244,15 @@ describe('MFM', () => { ]); }); + it('spin', () => { + const tokens = analyze(':foo:'); + assert.deepStrictEqual(tokens, [ + tree('spin', [ + leaf('emoji', { name: 'foo' }) + ], {}), + ]); + }); + describe('motion', () => { it('by triple brackets', () => { const tokens = analyze('(((foo)))'); -- cgit v1.2.3-freya From 4de62220e3f0e2ed759d31b633ef267b12ec16b3 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Jan 2019 16:31:00 +0900 Subject: [MFM] Add flip syntax Resolve #4002 --- CHANGELOG.md | 1 + src/client/app/common/views/components/mfm.ts | 8 ++++++++ src/mfm/html.ts | 6 ++++++ src/mfm/parser.ts | 24 ++++++++++++++++++++++++ test/mfm.ts | 9 +++++++++ 5 files changed, 48 insertions(+) (limited to 'test') diff --git a/CHANGELOG.md b/CHANGELOG.md index f8291a1357..e9319075c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ unreleased * 管理画面のモデレーションのUIを強化 * 管理画面からリモートユーザーの情報を更新できるように * 回転構文の追加 +* 左右反転構文の追加 * シンタックスハイライトの強化 * 引用投稿を削除したとき単なるRenoteとしてタイムラインに残る問題を修正 * イタリック構文の判定の改善 diff --git a/src/client/app/common/views/components/mfm.ts b/src/client/app/common/views/components/mfm.ts index f6f95deb24..a3849e9607 100644 --- a/src/client/app/common/views/components/mfm.ts +++ b/src/client/app/common/views/components/mfm.ts @@ -135,6 +135,14 @@ export default Vue.component('misskey-flavored-markdown', { }, genEl(token.children)); } + case 'flip': { + return (createElement as any)('span', { + attrs: { + style: 'display: inline-block; transform: scaleX(-1);' + }, + }, genEl(token.children)); + } + case 'url': { return [createElement(MkUrl, { key: Math.random(), diff --git a/src/mfm/html.ts b/src/mfm/html.ts index a40ff19ac8..568a39bc7b 100644 --- a/src/mfm/html.ts +++ b/src/mfm/html.ts @@ -61,6 +61,12 @@ export default (tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteU 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'); diff --git a/src/mfm/parser.ts b/src/mfm/parser.ts index 5cd9fc04c2..1cf1edfa4e 100644 --- a/src/mfm/parser.ts +++ b/src/mfm/parser.ts @@ -102,6 +102,7 @@ const mfm = P.createLanguage({ r.hashtag, r.emoji, r.blockCode, + r.flip, r.inlineCode, r.quote, r.math, @@ -173,6 +174,7 @@ const mfm = P.createLanguage({ r.hashtag, r.url, r.link, + r.flip, r.emoji, r.text ).atLeast(1).tryParse(x), {})), @@ -195,6 +197,7 @@ const mfm = P.createLanguage({ r.math, r.url, r.link, + r.flip, r.text ).atLeast(1).tryParse(x), {})), //#endregion @@ -228,6 +231,23 @@ const mfm = P.createLanguage({ }), //#endregion + //#region Flip + flip: r => + P.regexp(/(.+?)<\/flip>/, 1) + .map(x => createTree('flip', P.alt( + r.big, + r.small, + r.spin, + r.bold, + r.strike, + r.link, + r.italic, + r.motion, + r.emoji, + r.text + ).atLeast(1).tryParse(x), {})), + //#endregion + //#region Inline code inlineCode: r => P.regexp(/`([^´\n]+?)`/, 1) @@ -253,6 +273,7 @@ const mfm = P.createLanguage({ r.hashtag, r.url, r.link, + r.flip, r.emoji, r.text ).atLeast(1).tryParse(x), {})), @@ -325,6 +346,7 @@ const mfm = P.createLanguage({ r.emoji, r.url, r.link, + r.flip, r.math, r.text ).atLeast(1).tryParse(x), {})), @@ -363,6 +385,7 @@ const mfm = P.createLanguage({ r.hashtag, r.url, r.link, + r.flip, r.emoji, r.text ).atLeast(1).tryParse(x), {})), @@ -385,6 +408,7 @@ const mfm = P.createLanguage({ r.motion, r.url, r.link, + r.flip, r.mention, r.hashtag, r.emoji, diff --git a/test/mfm.ts b/test/mfm.ts index d8cba8ee15..e48bba09ef 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -244,6 +244,15 @@ describe('MFM', () => { ]); }); + it('flip', () => { + const tokens = analyze('foo'); + assert.deepStrictEqual(tokens, [ + tree('flip', [ + text('flip') + ], {}), + ]); + }); + it('spin', () => { const tokens = analyze(':foo:'); assert.deepStrictEqual(tokens, [ -- cgit v1.2.3-freya From 8c62aafa973457bd5abbe43747e69b9655a5761f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 27 Jan 2019 16:36:01 +0900 Subject: Fix test --- test/mfm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/mfm.ts b/test/mfm.ts index e48bba09ef..2eeaeb2e5a 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -248,7 +248,7 @@ describe('MFM', () => { const tokens = analyze('foo'); assert.deepStrictEqual(tokens, [ tree('flip', [ - text('flip') + text('foo') ], {}), ]); }); -- cgit v1.2.3-freya