From 79d2374d8ec1de10740d36309c26d00e5ab44c68 Mon Sep 17 00:00:00 2001
From: Aya Morisawa <AyaMorisawa4869@gmail.com>
Date: Fri, 25 Jan 2019 23:08:06 +0900
Subject: [PATCH] Add multiline math syntax

Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
---
 .../common/views/components/formula-core.vue  |  7 +++++-
 .../app/common/views/components/formula.vue   |  6 ++++-
 src/client/app/common/views/components/mfm.ts | 16 +++++++++++--
 src/mfm/html.ts                               |  8 ++++++-
 src/mfm/parser.ts                             | 23 ++++++++++++-------
 test/mfm.ts                                   | 19 +++++++++++----
 6 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/src/client/app/common/views/components/formula-core.vue b/src/client/app/common/views/components/formula-core.vue
index 254e0df308..69697d6df0 100644
--- a/src/client/app/common/views/components/formula-core.vue
+++ b/src/client/app/common/views/components/formula-core.vue
@@ -1,5 +1,6 @@
 <template>
-<span v-html="compiledFormula"></span>
+<div v-if="block" v-html="compiledFormula"></div>
+<span v-else v-html="compiledFormula"></span>
 </template>
 
 <script lang="ts">
@@ -11,6 +12,10 @@ export default Vue.extend({
 		formula: {
 			type: String,
 			required: true
+		},
+		block: {
+			type: Boolean,
+			required: true
 		}
 	},
 	computed: {
diff --git a/src/client/app/common/views/components/formula.vue b/src/client/app/common/views/components/formula.vue
index 02ed96daac..73572b72c6 100644
--- a/src/client/app/common/views/components/formula.vue
+++ b/src/client/app/common/views/components/formula.vue
@@ -1,5 +1,5 @@
 <template>
-<x-formula :formula="formula"/>
+<x-formula :formula="formula" :block="block" />
 </template>
 
 <script lang="ts">
@@ -14,6 +14,10 @@ export default Vue.extend({
 		formula: {
 			type: String,
 			required: true
+		},
+		block: {
+			type: Boolean,
+			required: true
 		}
 	}
 });
diff --git a/src/client/app/common/views/components/mfm.ts b/src/client/app/common/views/components/mfm.ts
index ad3d8204cc..7a875dc2b0 100644
--- a/src/client/app/common/views/components/mfm.ts
+++ b/src/client/app/common/views/components/mfm.ts
@@ -228,12 +228,24 @@ export default Vue.component('misskey-flavored-markdown', {
 					})];
 				}
 
-				case 'math': {
+				case 'mathInline': {
 					//const MkFormula = () => import('./formula.vue').then(m => m.default);
 					return [createElement(MkFormula, {
 						key: Math.random(),
 						props: {
-							formula: token.node.props.formula
+							formula: token.node.props.formula,
+							block: false
+						}
+					})];
+				}
+
+				case 'mathBlock': {
+					//const MkFormula = () => import('./formula.vue').then(m => m.default);
+					return [createElement(MkFormula, {
+						key: Math.random(),
+						props: {
+							formula: token.node.props.formula,
+							block: true
 						}
 					})];
 				}
diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index 6af2833858..b86d33a39a 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -87,7 +87,13 @@ export default (tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteU
 			return el;
 		},
 
-		math(token) {
+		mathInline(token) {
+			const el = doc.createElement('code');
+			el.textContent = token.node.props.formula;
+			return el;
+		},
+
+		mathBlock(token) {
 			const el = doc.createElement('code');
 			el.textContent = token.node.props.formula;
 			return el;
diff --git a/src/mfm/parser.ts b/src/mfm/parser.ts
index b86e1d5559..01b69c9690 100644
--- a/src/mfm/parser.ts
+++ b/src/mfm/parser.ts
@@ -103,7 +103,8 @@ const mfm = P.createLanguage({
 		r.blockCode,
 		r.inlineCode,
 		r.quote,
-		r.math,
+		r.mathInline,
+		r.mathBlock,
 		r.search,
 		r.title,
 		r.center,
@@ -121,7 +122,7 @@ const mfm = P.createLanguage({
 			r.mention,
 			r.hashtag,
 			r.emoji,
-			r.math,
+			r.mathInline,
 			r.text
 		).atLeast(1).tryParse(x), {})),
 	//#endregion
@@ -135,7 +136,7 @@ const mfm = P.createLanguage({
 			r.mention,
 			r.hashtag,
 			r.emoji,
-			r.math,
+			r.mathInline,
 			r.text
 		).atLeast(1).tryParse(x), {})),
 	//#endregion
@@ -180,7 +181,7 @@ const mfm = P.createLanguage({
 			r.mention,
 			r.hashtag,
 			r.emoji,
-			r.math,
+			r.mathInline,
 			r.url,
 			r.link,
 			r.text
@@ -274,10 +275,16 @@ const mfm = P.createLanguage({
 		}),
 	//#endregion
 
-	//#region Math
-	math: r =>
+	//#region Math (inline)
+	mathInline: r =>
 		P.regexp(/\\\((.+?)\\\)/, 1)
-		.map(x => createLeaf('math', { formula: x })),
+		.map(x => createLeaf('mathInline', { formula: x })),
+	//#endregion
+
+	//#region Math (block)
+	mathBlock: r =>
+		P.regexp(/\\\[([\s\S]+?)\\\]/, 1)
+		.map(x => createLeaf('mathBlock', { formula: x.trim() })),
 	//#endregion
 
 	//#region Mention
@@ -311,7 +318,7 @@ const mfm = P.createLanguage({
 			r.emoji,
 			r.url,
 			r.link,
-			r.math,
+			r.mathInline,
 			r.text
 		).atLeast(1).tryParse(x), {})),
 	//#endregion
diff --git a/test/mfm.ts b/test/mfm.ts
index a4b4a13973..f850e649a3 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -836,15 +836,26 @@ describe('MFM', () => {
 			});
 		});
 
-		it('math', () => {
+		it('mathInline', () => {
 			const fomula = 'x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}';
-			const text = `\\(${fomula}\\)`;
-			const tokens = analyze(text);
+			const content = `\\(${fomula}\\)`;
+			const tokens = analyze(content);
 			assert.deepStrictEqual(tokens, [
-				leaf('math', { formula: fomula })
+				leaf('mathInline', { formula: fomula })
 			]);
 		});
 
+		describe('mathBlock', () => {
+			it('simple', () => {
+				const fomula = 'x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}';
+				const content = `\\[\n${fomula}\n\\]`;
+				const tokens = analyze(content);
+				assert.deepStrictEqual(tokens, [
+					leaf('mathBlock', { formula: fomula })
+				]);
+			});
+		});
+
 		it('search', () => {
 			const tokens1 = analyze('a b c 検索');
 			assert.deepStrictEqual(tokens1, [