summaryrefslogtreecommitdiff
path: root/src/common/text/elements
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2017-02-09 19:41:17 +0900
committersyuilo <syuilotan@yahoo.co.jp>2017-02-09 19:41:17 +0900
commit21b72f78546fe8fde457be780c57c5bed6fdb40a (patch)
treed25577bc54ea9ca2bc820b9d323ecff0f68a5bec /src/common/text/elements
parentMerge pull request #137 from syuilo/greenkeeper/typescript-2.1.6 (diff)
downloadmisskey-21b72f78546fe8fde457be780c57c5bed6fdb40a.tar.gz
misskey-21b72f78546fe8fde457be780c57c5bed6fdb40a.tar.bz2
misskey-21b72f78546fe8fde457be780c57c5bed6fdb40a.zip
#139
Diffstat (limited to 'src/common/text/elements')
-rw-r--r--src/common/text/elements/code.js186
1 files changed, 185 insertions, 1 deletions
diff --git a/src/common/text/elements/code.js b/src/common/text/elements/code.js
index d046716ed6..190a090d96 100644
--- a/src/common/text/elements/code.js
+++ b/src/common/text/elements/code.js
@@ -11,7 +11,191 @@ module.exports = {
return {
type: 'code',
content: code,
- code: code.substr(3, code.length - 6).trim()
+ code: code.substr(3, code.length - 6).trim(),
+ codeHtml: genHtml(code.substr(3, code.length - 6).trim())
};
}
};
+
+function escape(text) {
+ return text
+ .replace(/>/g, '&gt;')
+ .replace(/</g, '&lt;');
+}
+
+// 文字数が多い順にソートします
+// そうしないと、「function」という文字列が与えられたときに「func」が先にマッチしてしまう可能性があるためです
+const keywords = [
+ 'true',
+ 'false',
+ 'null',
+ 'nil',
+ 'undefined',
+ 'var',
+ 'const',
+ 'let',
+ 'mut',
+ 'if',
+ 'then',
+ 'else',
+ 'switch',
+ 'case',
+ 'for',
+ 'each',
+ 'in',
+ 'while',
+ 'loop',
+ 'continue',
+ 'break',
+ 'do',
+ 'goto',
+ 'end',
+ 'function',
+ 'func',
+ 'fn',
+ 'return',
+ 'async',
+ 'await',
+ 'require',
+ 'import',
+ 'export',
+ 'new',
+ 'this',
+ 'class',
+ 'constructor'
+].sort((a, b) => b.length - a.length);
+
+const symbols = [
+ '=',
+ '+',
+ '-',
+ '*',
+ '/',
+ '%',
+ '^',
+ '&',
+ '|',
+ '>',
+ '<',
+ '~'
+];
+
+const elements = [
+ // comment
+ code => {
+ if (code.substr(0, 2) != '//') return null;
+ const comment = code.match(/^\/\/(.+?)\n/)[0];
+ return {
+ html: `<span class="comment">${escape(comment)}</span>`,
+ next: comment.length
+ };
+ },
+
+ // string
+ code => {
+ if (!/^['"`]/.test(code)) return null;
+ const begin = code[0];
+ let str = begin;
+ let thisIsNotAString = false;
+ for (i = 1; i < code.length; i++) {
+ const char = code[i];
+ if (char == '\\') {
+ i++;
+ continue;
+ } else if (char == begin) {
+ str += char;
+ break;
+ } else if (char == '\n' || i == (code.length - 1)) {
+ thisIsNotAString = true;
+ break;
+ } else {
+ str += char;
+ }
+ }
+ if (thisIsNotAString) {
+ return null;
+ } else {
+ return {
+ html: `<span class="string">${escape(str)}</span>`,
+ next: str.length
+ };
+ }
+ },
+
+ // number
+ (code, i, source) => {
+ const prev = source[i - 1];
+ if (prev && /[a-zA-Z]/.test(prev)) return null;
+ if (!/^[0-9]+/.test(code)) return null;
+ const match = code.match(/^[0-9]+/)[0];
+ if (match) {
+ return {
+ html: `<span class="number">${match}</span>`,
+ next: match.length
+ };
+ } else {
+ return null;
+ }
+ },
+
+ // keyword
+ code => {
+ const match = keywords.filter(k => code.substr(0, k.length) == k)[0];
+ if (match) {
+ if (/^[a-zA-Z]/.test(code.substr(match.length))) return null;
+ return {
+ html: `<span class="keyword ${match}">${match}</span>`,
+ next: match.length
+ };
+ } else {
+ return null;
+ }
+ },
+
+ // symbol
+ code => {
+ const match = symbols.filter(s => code[0] == s)[0];
+ if (match) {
+ return {
+ html: `<span class="symbol">${match}</span>`,
+ next: 1
+ };
+ } else {
+ return null;
+ }
+ }
+];
+
+// specify lang is todo
+function genHtml(source, lang) {
+ let code = source;
+ let html = '';
+
+ function push(token) {
+ html += token.html;
+ code = code.substr(token.next);
+ }
+
+ let i = 0;
+
+ while (code != '') {
+ const parsed = elements.some(el => {
+ const e = el(code, i, source);
+ if (e) {
+ push(e);
+ return true;
+ }
+ });
+
+ if (!parsed) {
+ push({
+ html: escape(code[0]),
+ next: 1
+ });
+ }
+
+ i++;
+ }
+
+ return html;
+}