From 6e343d50f10f2f381aed94853c41d59b33c1ee03 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 4 Dec 2018 01:28:21 +0900
Subject: [PATCH] [MFM] Implement strike syntax

Resolve #3485
---
 src/client/app/common/views/components/mfm.ts |  4 ++++
 src/mfm/html.ts                               |  6 ++++++
 src/mfm/parser.ts                             | 19 +++++++++++++++++++
 test/mfm.ts                                   | 11 +++++++++++
 4 files changed, 40 insertions(+)

diff --git a/src/client/app/common/views/components/mfm.ts b/src/client/app/common/views/components/mfm.ts
index d1ce4873fe..dbc874c53d 100644
--- a/src/client/app/common/views/components/mfm.ts
+++ b/src/client/app/common/views/components/mfm.ts
@@ -96,6 +96,10 @@ export default Vue.component('misskey-flavored-markdown', {
 					return [createElement('b', genEl(token.children))];
 				}
 
+				case 'strike': {
+					return [createElement('del', genEl(token.children))];
+				}
+
 				case 'big': {
 					bigCount++;
 					const isLong = getTextCount(token.children) > 10 || getChildrenCount(token.children) > 5;
diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index 8b63d8f824..083150ab70 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -31,6 +31,12 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
 			return el;
 		},
 
+		strike(token) {
+			const el = doc.createElement('del');
+			dive(token.children).forEach(child => el.appendChild(child));
+			return el;
+		},
+
 		motion(token) {
 			const el = doc.createElement('i');
 			dive(token.children).forEach(child => el.appendChild(child));
diff --git a/src/mfm/parser.ts b/src/mfm/parser.ts
index 3f9d68df3b..4bd45516a0 100644
--- a/src/mfm/parser.ts
+++ b/src/mfm/parser.ts
@@ -68,6 +68,7 @@ const mfm = P.createLanguage({
 	root: r => P.alt(
 		r.big,
 		r.bold,
+		r.strike,
 		r.motion,
 		r.url,
 		r.link,
@@ -129,6 +130,7 @@ const mfm = P.createLanguage({
 		.map(x => makeNodeWithChildren('center', P.alt(
 			r.big,
 			r.bold,
+			r.strike,
 			r.motion,
 			r.mention,
 			r.hashtag,
@@ -189,6 +191,7 @@ const mfm = P.createLanguage({
 			return makeNodeWithChildren('link', P.alt(
 				r.big,
 				r.bold,
+				r.strike,
 				r.motion,
 				r.emoji,
 				r.text
@@ -228,6 +231,7 @@ const mfm = P.createLanguage({
 		P.alt(P.regexp(/\(\(\(([\s\S]+?)\)\)\)/, 1), P.regexp(/<motion>(.+?)<\/motion>/, 1))
 		.map(x => makeNodeWithChildren('motion', P.alt(
 			r.bold,
+			r.strike,
 			r.mention,
 			r.hashtag,
 			r.emoji,
@@ -261,6 +265,20 @@ const mfm = P.createLanguage({
 		})),
 	//#endregion
 
+	//#region Strike
+	strike: r =>
+		P.regexp(/~~(.+?)~~/, 1)
+		.map(x => makeNodeWithChildren('strike', P.alt(
+			r.bold,
+			r.mention,
+			r.hashtag,
+			r.url,
+			r.link,
+			r.emoji,
+			r.text
+		).atLeast(1).tryParse(x))),
+	//#endregion
+
 	//#region Title
 	title: r =>
 		newline.then(P((input, i) => {
@@ -271,6 +289,7 @@ const mfm = P.createLanguage({
 			const contents = P.alt(
 				r.big,
 				r.bold,
+				r.strike,
 				r.motion,
 				r.url,
 				r.link,
diff --git a/test/mfm.ts b/test/mfm.ts
index eeb92aa2af..111f70bef1 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -702,6 +702,17 @@ describe('Text', () => {
 				], tokens);
 			});
 		});
+
+		describe('strike', () => {
+			it('simple', () => {
+				const tokens = analyze('~~foo~~');
+				assert.deepEqual([
+					nodeWithChildren('strike', [
+						text('foo')
+					]),
+				], tokens);
+			});
+		});
 	});
 
 	describe('toHtml', () => {