diff --git a/packages/renderer/MdToHtml.ts b/packages/renderer/MdToHtml.ts index 6a81c04e8a8..db86baf2065 100644 --- a/packages/renderer/MdToHtml.ts +++ b/packages/renderer/MdToHtml.ts @@ -393,6 +393,24 @@ export default class MdToHtml { this.cachedOutputs_ = {}; } + private removeLastNewLine(s: string): string { + if (s[s.length - 1] === '\n') { + return s.substr(0, s.length - 1); + } else { + return s; + } + } + + // Rendering large code blocks can freeze the app so we disable it in + // certain cases: + // https://github.com/laurent22/joplin/issues/5593#issuecomment-947374218 + private shouldSkipHighlighting(str: string, lang: string): boolean { + if (lang && !hljs.getLanguage(lang)) lang = ''; + if (str.length >= 1000 && !lang) return true; + if (str.length >= 512000 && lang) return true; + return false; + } + // "theme" is the theme as returned by themeStyle() public async render(body: string, theme: any = null, options: RenderOptions = null): Promise { @@ -455,29 +473,32 @@ export default class MdToHtml { // The strings includes the last \n that is part of the fence, // so we remove it because we need the exact code in the source block - const trimmedStr = str.replace(/(.*)\n$/, '$1'); + const trimmedStr = this.removeLastNewLine(str); const sourceBlockHtml = `
${markdownIt.utils.escapeHtml(trimmedStr)}
`; - try { - let hlCode = ''; + if (this.shouldSkipHighlighting(trimmedStr, lang)) { + outputCodeHtml = markdownIt.utils.escapeHtml(trimmedStr); + } else { + try { + let hlCode = ''; - const cacheKey = md5(`${str}_${lang}`); + const cacheKey = md5(`${str}_${lang}`); - if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) { - hlCode = this.cachedHighlightedCode_[cacheKey]; - } else { - if (lang && hljs.getLanguage(lang)) { - // hlCode = hljs.highlight(lang, trimmedStr, true).value; - hlCode = hljs.highlight(trimmedStr, { language: lang, ignoreIllegals: true }).value; + if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) { + hlCode = this.cachedHighlightedCode_[cacheKey]; } else { - hlCode = hljs.highlightAuto(trimmedStr).value; + if (lang && hljs.getLanguage(lang)) { + hlCode = hljs.highlight(trimmedStr, { language: lang, ignoreIllegals: true }).value; + } else { + hlCode = hljs.highlightAuto(trimmedStr).value; + } + this.cachedHighlightedCode_[cacheKey] = hlCode; } - this.cachedHighlightedCode_[cacheKey] = hlCode; - } - outputCodeHtml = hlCode; - } catch (error) { - outputCodeHtml = markdownIt.utils.escapeHtml(trimmedStr); + outputCodeHtml = hlCode; + } catch (error) { + outputCodeHtml = markdownIt.utils.escapeHtml(trimmedStr); + } } const html = `
${sourceBlockHtml}
${outputCodeHtml}
`;