From b175c1fc940717215ca05dddc321c7584cced991 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 21 Jun 2019 08:28:59 +0100 Subject: [PATCH] Desktop: Resolves #1649: Cache code blocks in notes to speed up rendering --- ElectronClient/app/gui/NoteText.jsx | 1 + ReactNativeClient/lib/MdToHtml.js | 37 +++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx index 4392cb1bb..efce08cda 100644 --- a/ElectronClient/app/gui/NoteText.jsx +++ b/ElectronClient/app/gui/NoteText.jsx @@ -954,6 +954,7 @@ class NoteTextComponent extends React.Component { postMessageSyntax: 'ipcProxySendToHost', userCss: options.useCustomCss ? this.props.customCss : '', resources: await shared.attachedResources(bodyToRender), + codeHighlightCacheKey: this.state.note ? this.state.note.id : null, }; let bodyHtml = ''; diff --git a/ReactNativeClient/lib/MdToHtml.js b/ReactNativeClient/lib/MdToHtml.js index 3f5d51dac..52e31a2d8 100644 --- a/ReactNativeClient/lib/MdToHtml.js +++ b/ReactNativeClient/lib/MdToHtml.js @@ -22,7 +22,7 @@ const hljs = require('highlight.js'); const markdownItAnchor = require('markdown-it-anchor'); // The keys must match the corresponding entry in Setting.js const plugins = { - mark: {module: require('markdown-it-mark')}, + mark: {module: require('markdown-it-mark')}, footnote: {module: require('markdown-it-footnote')}, sub: {module: require('markdown-it-sub')}, sup: {module: require('markdown-it-sup')}, @@ -43,6 +43,9 @@ class MdToHtml { this.resourceBaseUrl_ = ('resourceBaseUrl' in options) ? options.resourceBaseUrl : null; this.cachedOutputs_ = {}; + + this.lastCodeHighlightCacheKey_ = null; + this.cachedHighlightedCode_ = {}; } render(body, style, options = null) { @@ -51,6 +54,15 @@ class MdToHtml { if (!options.paddingBottom) options.paddingBottom = '0'; if (!options.highlightedKeywords) options.highlightedKeywords = []; + // The "codeHighlightCacheKey" option indicates what set of cached object should be + // associated with this particular Markdown body. It is only used to allow us to + // clear the cache whenever switching to a different note. + // If "codeHighlightCacheKey" is not specified, code highlighting won't be cached. + if (options.codeHighlightCacheKey !== this.lastCodeHighlightCacheKey_ || !options.codeHighlightCacheKey) { + this.cachedHighlightedCode_ = {}; + this.lastCodeHighlightCacheKey_ = options.codeHighlightCacheKey; + } + const breaks_ = Setting.value('markdown.softbreaks') ? false : true; const cacheKey = md5(escape(body + JSON.stringify(options) + JSON.stringify(style))); @@ -67,14 +79,21 @@ class MdToHtml { breaks: breaks_, linkify: true, html: true, - highlight: function(str, lang) { + highlight: (str, lang) => { try { let hlCode = ''; - - if (lang && hljs.getLanguage(lang)) { - hlCode = hljs.highlight(lang, str, true).value; + + const cacheKey = md5(str + '_' + lang); + + if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) { + hlCode = this.cachedHighlightedCode_[cacheKey]; } else { - hlCode = hljs.highlightAuto(str).value; + if (lang && hljs.getLanguage(lang)) { + hlCode = hljs.highlight(lang, str, true).value; + } else { + hlCode = hljs.highlightAuto(str).value; + } + this.cachedHighlightedCode_[cacheKey] = hlCode; } if (shim.isReactNative()) { @@ -124,15 +143,13 @@ class MdToHtml { markdownIt.use(rules.checkbox(context, ruleOptions)); markdownIt.use(rules.link_open(context, ruleOptions)); markdownIt.use(rules.html_image(context, ruleOptions)); - if (Setting.value('markdown.plugin.katex')) - markdownIt.use(rules.katex(context, ruleOptions)); + if (Setting.value('markdown.plugin.katex')) markdownIt.use(rules.katex(context, ruleOptions)); markdownIt.use(rules.highlight_keywords(context, ruleOptions)); markdownIt.use(rules.code_inline(context, ruleOptions)); markdownIt.use(markdownItAnchor) for (let key in plugins) { - if (Setting.value('markdown.plugin.' + key)) - markdownIt.use(plugins[key].module, plugins[key].options); + if (Setting.value('markdown.plugin.' + key)) markdownIt.use(plugins[key].module, plugins[key].options); } setupLinkify(markdownIt);