diff --git a/modules/judge.js b/modules/judge.js index 89d9719..ebaab6b 100644 --- a/modules/judge.js +++ b/modules/judge.js @@ -66,7 +66,7 @@ app.get('/judge_detail/:id', async (req, res) => { if (!await judge.isAllowedSeeCodeBy(res.locals.user)) throw 'Permission denied'; - judge.code = syzoj.utils.highlight(judge.code, judge.language); + judge.code = await syzoj.utils.highlight(judge.code, judge.language); if (judge.result.compiler_output) judge.result.compiler_output = syzoj.utils.ansiToHTML(judge.result.compiler_output); res.render('judge_detail', { diff --git a/package.json b/package.json index a101598..f6646b4 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,11 @@ "gravatar": "^1.5.2", "highlight.js": "^9.6.0", "md5": "^2.2.1", - "moemark-renderer": "^1.1.3", + "moemark-renderer": "^1.2.0", "moment": "^2.15.0", "multer": "^1.2.0", "mysql": "^2.11.1", + "pygmentize-bundled-cached": "^1.1.0", "request": "^2.74.0", "sequelize": "^3.24.3", "session-file-store": "^1.0.0", diff --git a/static/tomorrow.css b/static/tomorrow.css new file mode 100644 index 0000000..4508e89 --- /dev/null +++ b/static/tomorrow.css @@ -0,0 +1,67 @@ +.hll { background-color: #d6d6d6 } +.pl-c { color: #8e908c } /* Comment */ +.pl-err { color: #c82829 } /* Error */ +.pl-k { color: #8959a8 } /* Keyword */ +.pl-l { color: #f5871f } /* Literal */ +.pl-n { color: #4d4d4c } /* Name */ +.pl-o { color: #3e999f } /* Operator */ +.pl-p { color: #4d4d4c } /* Punctuation */ +.pl-ch { color: #8e908c } /* Comment.Hashbang */ +.pl-cm { color: #8e908c } /* Comment.Multiline */ +.pl-cp { color: #8e908c } /* Comment.Preproc */ +.pl-cpf { color: #8e908c } /* Comment.PreprocFile */ +.pl-c1 { color: #8e908c } /* Comment.Single */ +.pl-cs { color: #8e908c } /* Comment.Special */ +.pl-gd { color: #c82829 } /* Generic.Deleted */ +.pl-ge { font-style: italic } /* Generic.Emph */ +.pl-gh { color: #4d4d4c; font-weight: bold } /* Generic.Heading */ +.pl-gi { color: #718c00 } /* Generic.Inserted */ +.pl-gp { color: #8e908c; font-weight: bold } /* Generic.Prompt */ +.pl-gs { font-weight: bold } /* Generic.Strong */ +.pl-gu { color: #3e999f; font-weight: bold } /* Generic.Subheading */ +.pl-kc { color: #8959a8 } /* Keyword.Constant */ +.pl-kd { color: #8959a8 } /* Keyword.Declaration */ +.pl-kn { color: #3e999f } /* Keyword.Namespace */ +.pl-kp { color: #8959a8 } /* Keyword.Pseudo */ +.pl-kr { color: #8959a8 } /* Keyword.Reserved */ +.pl-kt { color: #eab700 } /* Keyword.Type */ +.pl-ld { color: #718c00 } /* Literal.Date */ +.pl-m { color: #f5871f } /* Literal.Number */ +.pl-s { color: #718c00 } /* Literal.String */ +.pl-na { color: #4271ae } /* Name.Attribute */ +.pl-nb { color: #4d4d4c } /* Name.Builtin */ +.pl-nc { color: #eab700 } /* Name.Class */ +.pl-no { color: #c82829 } /* Name.Constant */ +.pl-nd { color: #3e999f } /* Name.Decorator */ +.pl-ni { color: #4d4d4c } /* Name.Entity */ +.pl-ne { color: #c82829 } /* Name.Exception */ +.pl-nf { color: #4271ae } /* Name.Function */ +.pl-nl { color: #4d4d4c } /* Name.Label */ +.pl-nn { color: #eab700 } /* Name.Namespace */ +.pl-nx { color: #4271ae } /* Name.Other */ +.pl-py { color: #4d4d4c } /* Name.Property */ +.pl-nt { color: #3e999f } /* Name.Tag */ +.pl-nv { color: #c82829 } /* Name.Variable */ +.pl-ow { color: #3e999f } /* Operator.Word */ +.pl-w { color: #4d4d4c } /* Text.Whitespace */ +.pl-mb { color: #f5871f } /* Literal.Number.Bin */ +.pl-mf { color: #f5871f } /* Literal.Number.Float */ +.pl-mh { color: #f5871f } /* Literal.Number.Hex */ +.pl-mi { color: #f5871f } /* Literal.Number.Integer */ +.pl-mo { color: #f5871f } /* Literal.Number.Oct */ +.pl-sb { color: #718c00 } /* Literal.String.Backtick */ +.pl-sc { color: #4d4d4c } /* Literal.String.Char */ +.pl-sd { color: #8e908c } /* Literal.String.Doc */ +.pl-s2 { color: #718c00 } /* Literal.String.Double */ +.pl-se { color: #f5871f } /* Literal.String.Escape */ +.pl-sh { color: #718c00 } /* Literal.String.Heredoc */ +.pl-si { color: #f5871f } /* Literal.String.Interpol */ +.pl-sx { color: #718c00 } /* Literal.String.Other */ +.pl-sr { color: #718c00 } /* Literal.String.Regex */ +.pl-s1 { color: #718c00 } /* Literal.String.Single */ +.pl-ss { color: #718c00 } /* Literal.String.Symbol */ +.pl-bp { color: #4d4d4c } /* Name.Builtin.Pseudo */ +.pl-vc { color: #c82829 } /* Name.Variable.Class */ +.pl-vg { color: #c82829 } /* Name.Variable.Global */ +.pl-vi { color: #c82829 } /* Name.Variable.Instance */ +.pl-il { color: #f5871f } /* Literal.Number.Integer.Long */ diff --git a/utility.js b/utility.js index 58556bf..f69578e 100644 --- a/utility.js +++ b/utility.js @@ -28,10 +28,37 @@ let renderer = require('moemark-renderer'); let moment = require('moment'); let url = require('url'); let querystring = require('querystring'); +let pygmentize = require('pygmentize-bundled-cached'); let highlightjs = require('highlight.js'); let gravatar = require('gravatar'); let AdmZip = require('adm-zip'); +function escapeHTML(s) { + // Code from http://stackoverflow.com/questions/5251520/how-do-i-escape-some-html-in-javascript/5251551 + return s.replace(/[^0-9A-Za-z ]/g, (c) => { + return "" + c.charCodeAt(0) + ";"; + }); +} + +function highlightPygmentize(code, lang, cb) { + pygmentize({ + lang: lang, + format: 'html', + options: { + nowrap: true, + classprefix: 'pl-' + } + }, code, (err, res) => { + if (err) { + cb(escapeHTML(code)); + } else { + cb(res); + } + }); +} + +renderer.config.highlight = highlightPygmentize; + module.exports = { resolvePath(s) { let a = Array.from(arguments); @@ -86,19 +113,13 @@ module.exports = { if (encoded) res += '?' + encoded; return res; }, - escapeHTML(s) { - // Code from http://stackoverflow.com/questions/5251520/how-do-i-escape-some-html-in-javascript/5251551 - return s.replace(/[^0-9A-Za-z ]/g, (c) => { - return "" + c.charCodeAt(0) + ";"; - }); - }, + escapeHTML: escapeHTML, highlight(code, lang) { - try { - if (!lang) return highlightjs.highlightAuto(code).value; - else return highlightjs.highlight(lang, code).value; - } catch (e) { - return escapeHTML(code); - } + return new Promise((resolve, reject) => { + highlightPygmentize(code, lang, res => { + resolve(res); + }); + }); }, gravatar(email, size) { return gravatar.url(email, { s: size, d: 'mm' }).replace('www', 'cn'); diff --git a/views/header.ejs b/views/header.ejs index cdec102..19553a5 100644 --- a/views/header.ejs +++ b/views/header.ejs @@ -5,7 +5,7 @@