From eb56da7871be3baf20a390f452573307874e2695 Mon Sep 17 00:00:00 2001 From: mrdrogdrog Date: Tue, 23 Jun 2020 22:09:56 +0200 Subject: [PATCH] Restructure highlight code to enable line wrapping (#265) * Restructure highlight code to enable line wrapping Signed-off-by: Tilman Vatteroth --- CHANGELOG.md | 1 + .../highlighted-code/highlighted-code.scss | 57 +++++++++++-------- .../highlighted-code/highlighted-code.tsx | 41 ++++++------- .../markdown-it-plugins/highlighted-code.ts | 5 +- .../markdown-renderer/markdown-renderer.tsx | 10 ++-- .../highlighted-code/highlighted-code.scss | 3 - .../highlighted-fence.tsx} | 6 +- 7 files changed, 63 insertions(+), 60 deletions(-) delete mode 100644 src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.scss rename src/components/editor/markdown-renderer/replace-components/{highlighted-code/highlighted-code.tsx => highlighted-fence/highlighted-fence.tsx} (76%) diff --git a/CHANGELOG.md b/CHANGELOG.md index b838e368a..e3b73bafc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - A new table view for the history (besides the card view) - Better support for RTL-languages (and LTR-content in a RTL-page) - Users may now change their display name and password (only email accounts) on the new profile page +- Highlighted code blocks can now use line wrapping and line numbers at once ### Changed diff --git a/src/components/common/highlighted-code/highlighted-code.scss b/src/components/common/highlighted-code/highlighted-code.scss index 1ae131ac9..1f7c7d7ae 100644 --- a/src/components/common/highlighted-code/highlighted-code.scss +++ b/src/components/common/highlighted-code/highlighted-code.scss @@ -1,33 +1,42 @@ -.markdown-body pre code { +.markdown-body { + @import '../../../../node_modules/highlight.js/styles/github-gist'; +} - &.hljs { - display: flex; - flex-direction: row; - } +.markdown-body pre code.hljs { - .linenumbers { - text-align: right; - position: relative; - cursor: default; - z-index: 4; - padding: 0 8px 0 0; - min-width: 20px; - box-sizing: content-box; - color: #afafaf; - border-right: 3px solid #6ce26c; - display: flex; - flex-direction: column; - float: left; - overflow: hidden; - user-select: none; + padding: 16px; + display: grid; + grid-template-columns: auto minmax(0, 1fr); - & > span:before { - content: attr(data-line-number); + &.showGutter { + .linenumber { + position: relative; + cursor: default; + z-index: 4; + padding: 0 8px 0 0; + min-width: 20px; + box-sizing: content-box; + color: #afafaf; + border-right: 3px solid #6ce26c; + flex-direction: column; + overflow: hidden; + user-select: none; + + display: flex; + align-items: flex-end; + + + &:before { + content: attr(data-line-number); + } } } - .code { - float: left; + &.showGutter .line { margin: 0 0 0 16px; } + &.wrapLines .line { + white-space: pre-wrap; + } + } diff --git a/src/components/common/highlighted-code/highlighted-code.tsx b/src/components/common/highlighted-code/highlighted-code.tsx index 29fdb9c1e..f02ab4ee7 100644 --- a/src/components/common/highlighted-code/highlighted-code.tsx +++ b/src/components/common/highlighted-code/highlighted-code.tsx @@ -1,13 +1,13 @@ import hljs from 'highlight.js' -import React, { useMemo } from 'react' +import React, { Fragment, useMemo } from 'react' import ReactHtmlParser from 'react-html-parser' -import { ShowIf } from '../show-if/show-if' import './highlighted-code.scss' export interface HighlightedCodeProps { code: string, language?: string, showGutter: boolean + wrapLines: boolean } export const escapeHtml = (unsafe: string): string => { @@ -19,11 +19,11 @@ export const escapeHtml = (unsafe: string): string => { .replace(/'/g, ''') } -const checkIfLanguageIsSupported = (language: string):boolean => { +const checkIfLanguageIsSupported = (language: string): boolean => { return hljs.listLanguages().indexOf(language) > -1 } -const correctLanguage = (language: string|undefined): string|undefined => { +const correctLanguage = (language: string | undefined): string | undefined => { switch (language) { case 'html': return 'xml' @@ -32,7 +32,7 @@ const correctLanguage = (language: string|undefined): string|undefined => { } } -export const HighlightedCode: React.FC = ({ code, language, showGutter }) => { +export const HighlightedCode: React.FC = ({ code, language, showGutter, wrapLines }) => { const highlightedCode = useMemo(() => { const replacedLanguage = correctLanguage(language) return ((!!replacedLanguage && checkIfLanguageIsSupported(replacedLanguage)) ? hljs.highlight(replacedLanguage, code).value : escapeHtml(code)) @@ -42,25 +42,18 @@ export const HighlightedCode: React.FC = ({ code, language }, [code, language]) return ( - - - - { - highlightedCode - .map((line, index) => { - return - }) - } - - - - { - highlightedCode - .map((line, index) => -
+ + { + highlightedCode + .map((line, index) => { + return + +
{line} -
) - } -
+
+ + }) + } + ) } diff --git a/src/components/editor/markdown-renderer/markdown-it-plugins/highlighted-code.ts b/src/components/editor/markdown-renderer/markdown-it-plugins/highlighted-code.ts index b2ea8e57e..c2dea93e7 100644 --- a/src/components/editor/markdown-renderer/markdown-it-plugins/highlighted-code.ts +++ b/src/components/editor/markdown-renderer/markdown-it-plugins/highlighted-code.ts @@ -1,6 +1,6 @@ import MarkdownIt from 'markdown-it/lib' -const highlightRegex = /^(\w*)(=?)$/ +const highlightRegex = /^(\w*)(=?)(!?)$/ export const highlightedCode: MarkdownIt.PluginSimple = (md: MarkdownIt) => { md.core.ruler.push('highlighted-code', (state) => { @@ -16,6 +16,9 @@ export const highlightedCode: MarkdownIt.PluginSimple = (md: MarkdownIt) => { if (highlightInfos[2]) { token.attrJoin('data-show-gutter', '') } + if (highlightInfos[3]) { + token.attrJoin('data-wrap-lines', '') + } } }) return true diff --git a/src/components/editor/markdown-renderer/markdown-renderer.tsx b/src/components/editor/markdown-renderer/markdown-renderer.tsx index 6bd4844df..c02cde773 100644 --- a/src/components/editor/markdown-renderer/markdown-renderer.tsx +++ b/src/components/editor/markdown-renderer/markdown-renderer.tsx @@ -9,15 +9,15 @@ import footnote from 'markdown-it-footnote' import imsize from 'markdown-it-imsize' import inserted from 'markdown-it-ins' import marked from 'markdown-it-mark' +import mathJax from 'markdown-it-mathjax' import markdownItRegex from 'markdown-it-regex' import subscript from 'markdown-it-sub' import superscript from 'markdown-it-sup' import toc from 'markdown-it-table-of-contents' import taskList from 'markdown-it-task-lists' -import mathJax from 'markdown-it-mathjax' import React, { ReactElement, useMemo } from 'react' -import MathJaxReact from 'react-mathjax' import ReactHtmlParser, { convertNodeToElement, Transform } from 'react-html-parser' +import MathJaxReact from 'react-mathjax' import { createRenderContainer, validAlertLevels } from './container-plugins/alert' import { highlightedCode } from './markdown-it-plugins/highlighted-code' import { MarkdownItParserDebugger } from './markdown-it-plugins/parser-debugger' @@ -35,12 +35,12 @@ import { replaceQuoteExtraTime } from './regex-plugins/replace-quote-extra-time' import { replaceVimeoLink } from './regex-plugins/replace-vimeo-link' import { replaceYouTubeLink } from './regex-plugins/replace-youtube-link' import { getGistReplacement } from './replace-components/gist/gist-frame' +import { getHighlightedFence } from './replace-components/highlighted-fence/highlighted-fence' import { getMathJaxReplacement } from './replace-components/mathjax/mathjax-replacer' -import { getHighlightedCodeBlock } from './replace-components/highlighted-code/highlighted-code' import { getPDFReplacement } from './replace-components/pdf/pdf-frame' +import { getQuoteOptionsReplacement } from './replace-components/quote-options/quote-options' import { getTOCReplacement } from './replace-components/toc/toc-replacer' import { getVimeoReplacement } from './replace-components/vimeo/vimeo-frame' -import { getQuoteOptionsReplacement } from './replace-components/quote-options/quote-options' import { getYouTubeReplacement } from './replace-components/youtube/youtube-frame' export interface MarkdownPreviewProps { @@ -51,7 +51,7 @@ export type SubNodeConverter = (node: DomElement, index: number) => ReactElement export type ComponentReplacer = (node: DomElement, index: number, counterMap: Map, nodeConverter: SubNodeConverter) => (ReactElement | undefined); type ComponentReplacer2Identifier2CounterMap = Map> -const allComponentReplacers: ComponentReplacer[] = [getYouTubeReplacement, getVimeoReplacement, getGistReplacement, getPDFReplacement, getTOCReplacement, getHighlightedCodeBlock, getQuoteOptionsReplacement, getMathJaxReplacement] +const allComponentReplacers: ComponentReplacer[] = [getYouTubeReplacement, getVimeoReplacement, getGistReplacement, getPDFReplacement, getTOCReplacement, getHighlightedFence, getQuoteOptionsReplacement, getMathJaxReplacement] const tryToReplaceNode = (node: DomElement, index:number, componentReplacer2Identifier2CounterMap: ComponentReplacer2Identifier2CounterMap, nodeConverter: SubNodeConverter) => { return allComponentReplacers diff --git a/src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.scss b/src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.scss deleted file mode 100644 index c954bdca5..000000000 --- a/src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.scss +++ /dev/null @@ -1,3 +0,0 @@ -.markdown-body { - @import '../../../../../../node_modules/highlight.js/styles/github-gist'; -} diff --git a/src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.tsx b/src/components/editor/markdown-renderer/replace-components/highlighted-fence/highlighted-fence.tsx similarity index 76% rename from src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.tsx rename to src/components/editor/markdown-renderer/replace-components/highlighted-fence/highlighted-fence.tsx index 521006759..9e880b0ec 100644 --- a/src/components/editor/markdown-renderer/replace-components/highlighted-code/highlighted-code.tsx +++ b/src/components/editor/markdown-renderer/replace-components/highlighted-fence/highlighted-fence.tsx @@ -1,7 +1,6 @@ import { DomElement } from 'domhandler' import React, { ReactElement } from 'react' import { HighlightedCode } from '../../../../common/highlighted-code/highlighted-code' -import './highlighted-code.scss' const getElementReplacement = (codeNode: DomElement, index: number, counterMap: Map): (ReactElement | undefined) => { if (codeNode.name !== 'code' || !codeNode.attribs || !codeNode.attribs['data-highlight-language'] || !codeNode.children || !codeNode.children[0]) { @@ -10,7 +9,8 @@ const getElementReplacement = (codeNode: DomElement, index: number, counterMap: const language = codeNode.attribs['data-highlight-language'] const showGutter = codeNode.attribs['data-show-gutter'] !== undefined - return + const wrapLines = codeNode.attribs['data-wrap-lines'] !== undefined + return } -export { getElementReplacement as getHighlightedCodeBlock } +export { getElementReplacement as getHighlightedFence }