Skip to content

Commit

Permalink
fix: broken syntax highlighting of code block in markdown (fix #1032) (
Browse files Browse the repository at this point in the history
…#1031)

* fix: add space between two code blocks

* feat: change checking logic closed fence from regex to toastmark

* fix: wrong syntax highlighting when info of code block has padding

* fix: next line appears to be indented in code block using indentation

* feat: apply code review

* fix: change regex pattern to check closing fence

* feat: add test case for infoPadding value

* fix: change regex pattern and add test case
  • Loading branch information
seonim-ryu authored Jun 9, 2020
1 parent 1a87c50 commit ec405e2
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 21 deletions.
8 changes: 8 additions & 0 deletions apps/editor/src/css/md-syntax-highlighting.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@
background-color: #f5f7f8;
}

.tui-md-code-block.CodeMirror-linebackground.start {
top: 2px;
}

.tui-md-code-block.CodeMirror-linebackground.end {
bottom: 2px;
}

.tui-md-code,
.tui-md-code-block {
font-family: Consolas, Courier, 'Lucida Grande', '나눔바른고딕', 'Nanum Barun Gothic', '맑은고딕',
Expand Down
29 changes: 15 additions & 14 deletions apps/editor/src/js/markTextHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,28 +115,29 @@ function code({ tickCount }, start, end) {
}

function codeBlock(node, start, end, endLine) {
const { fenceOffset, fenceLength, fenceChar, info, parent } = node;
const { fenceOffset, fenceLength, fenceChar, info, infoPadding, parent } = node;
const fenceEnd = fenceOffset + fenceLength;
let openDelimEnd = addChPos(start, fenceEnd);
const marks = [markInfo(setChPos(start, 0), end, classNameMap.CODE_BLOCK)];

const marks = [
markInfo(start, end, classNameMap.CODE_BLOCK),
markInfo(start, openDelimEnd, classNameMap.DELIM)
];
if (fenceChar) {
marks.push(markInfo(start, addChPos(start, fenceEnd), classNameMap.DELIM));
}

if (info) {
openDelimEnd = setChPos(start, fenceEnd + info.length);
marks.push(markInfo(setChPos(start, fenceEnd), openDelimEnd, classNameMap.META));
marks.push(
markInfo(
setChPos(start, fenceEnd),
setChPos(start, fenceEnd + infoPadding + info.length),
classNameMap.META
)
);
}

const codeBlockEnd = `^(\\s{0,${fenceOffset}})(${fenceChar}{${fenceLength},})`;
const codeBlockEnd = `^(\\s{0,3})(${fenceChar}{${fenceLength},})`;
const CLOSED_RX = new RegExp(codeBlockEnd);

let closeDelimStart = end;

if (CLOSED_RX.test(endLine)) {
closeDelimStart = setChPos(end, 0);
marks.push(markInfo(closeDelimStart, end, classNameMap.DELIM));
marks.push(markInfo(setChPos(end, 0), end, classNameMap.DELIM));
}

const lineBackground =
Expand All @@ -149,7 +150,7 @@ function codeBlock(node, start, end, endLine) {
: null;

return {
marks: [...marks, markInfo(openDelimEnd, closeDelimStart, classNameMap.TEXT)],
marks,
lineBackground: { ...lineBackground }
};
}
Expand Down
23 changes: 18 additions & 5 deletions apps/editor/src/js/markdownEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,25 +352,38 @@ class MarkdownEditor extends CodeMirrorExt {
}
}

_markCodeBlockBackground(lineBackground) {
const { start, end, className } = lineBackground;

for (let index = start; index <= end; index += 1) {
let lineClassName = className;

if (index === start) {
lineClassName += ' start';
} else if (index === end) {
lineClassName += ' end';
}

this.cm.addLineClass(index, 'background', lineClassName);
this._markedLines[index] = true;
}
}

_markNode(node) {
const from = { line: getMdStartLine(node) - 1, ch: getMdStartCh(node) - 1 };
const to = { line: getMdEndLine(node) - 1, ch: getMdEndCh(node) };
const markInfo = getMarkInfo(node, from, to, this.cm.getLine(to.line));

if (markInfo) {
const { marks = [], lineBackground = {} } = markInfo;
const { start: startLine, end: endLine, className: lineClassName } = lineBackground;

marks.forEach(({ start, end, className }) => {
const attributes = { [ATTR_NAME_MARK]: '' };

this.cm.markText(start, end, { className, attributes });
});

for (let index = startLine; index <= endLine; index += 1) {
this.cm.addLineClass(index, 'background', lineClassName);
this._markedLines[index] = true;
}
this._markCodeBlockBackground(lineBackground);
}
}

Expand Down
25 changes: 24 additions & 1 deletion libs/toastmark/src/commonmark/__test__/syntax-info.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Parser } from '../blocks';
import { HeadingNode } from '../node';
import { HeadingNode, CodeBlockNode } from '../node';

const parser = new Parser();

Expand All @@ -18,3 +18,26 @@ describe('headingType ', () => {
expect(heading.headingType).toBe('setext');
});
});

describe('CodeBlockNode', () => {
it('infoPadding is none', () => {
const root = parser.parse('```js');
const codeBlock = root.firstChild as CodeBlockNode;

expect(codeBlock.infoPadding).toBe(0);
});

it('infoPadding is more than zero', () => {
const root = parser.parse('``` js');
const codeBlock = root.firstChild as CodeBlockNode;

expect(codeBlock.infoPadding).toBe(3);
});

it('info string', () => {
const root = parser.parse('``` javascript ');
const codeBlock = root.firstChild as CodeBlockNode;

expect(codeBlock.info).toBe('javascript');
});
});
4 changes: 3 additions & 1 deletion libs/toastmark/src/commonmark/blockHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ const codeBlock: BlockHandler = {
const newlinePos = content.indexOf('\n');
const firstLine = content.slice(0, newlinePos);
const rest = content.slice(newlinePos + 1);
block.info = unescapeString(firstLine.trim());
const infoString = firstLine.match(/^(\s*)(.*)/);
block.infoPadding = infoString![1].length;
block.info = unescapeString(infoString![2].trim());
block.literal = rest;
} else {
// indented
Expand Down
1 change: 1 addition & 0 deletions libs/toastmark/src/commonmark/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ export class CodeBlockNode extends BlockNode {
public fenceLength = 0;
public fenceOffset = -1;
public info: string | null = null;
public infoPadding = 0;
}

export class HtmlBlockNode extends BlockNode {
Expand Down

0 comments on commit ec405e2

Please sign in to comment.