Skip to content

Commit 205a8ad

Browse files
authored
Use block wrappers for block elements (#1216)
1 parent 379569f commit 205a8ad

File tree

4 files changed

+63
-21
lines changed

4 files changed

+63
-21
lines changed

CoreEditor/src/styling/helper.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
import { Decoration, DOMEventHandlers, EditorView, ViewPlugin } from '@codemirror/view';
1+
import { BlockWrapper, Decoration, DOMEventHandlers, EditorView, ViewPlugin } from '@codemirror/view';
22
import { Range, RangeSet } from '@codemirror/state';
33

4+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5+
export function createBlockPlugin(builder: () => RangeSet<BlockWrapper>, eventHandlers?: DOMEventHandlers<any>) {
6+
return ViewPlugin.fromClass(class {}, {
7+
provide: () => EditorView.blockWrappers.of(editor => {
8+
window.editor = editor;
9+
return builder();
10+
}),
11+
eventHandlers,
12+
});
13+
}
14+
415
// eslint-disable-next-line @typescript-eslint/no-explicit-any
516
export function createDecoPlugin(builder: () => RangeSet<Decoration>, eventHandlers?: DOMEventHandlers<any>) {
617
return ViewPlugin.fromClass(class {}, {

CoreEditor/src/styling/matchers/lezer.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
1-
import { Decoration } from '@codemirror/view';
2-
import { Range } from '@codemirror/state';
1+
import { BlockWrapper, Decoration } from '@codemirror/view';
2+
import { Range, RangeValue } from '@codemirror/state';
33
import { syntaxTree } from '@codemirror/language';
44
import { SyntaxNodeRef } from '@lezer/common';
55
import { WidgetView } from '../views/types';
66
import { lineDecoRanges } from '../helper';
77

8+
/**
9+
* Build block wrappers by leveraging language lexers.
10+
*
11+
* @param nodeName Node name(s), such as "CodeBlock" for code blocks
12+
* @param className Class to decorate the node
13+
*/
14+
export function createBlockWrappers(nodeName: string | string[], className: string, attributes?: { [key: string]: string }) {
15+
return BlockWrapper.set(createNodeRanges(nodeName, node => BlockWrapper.create({
16+
tagName: 'div',
17+
attributes: {
18+
'class': className,
19+
...attributes,
20+
},
21+
}).range(node.from, node.to)));
22+
}
23+
824
/**
925
* Create mark decorations.
1026
*
@@ -53,8 +69,18 @@ export function createLineDeco(nodeName: string | string[], className: string, a
5369
* @param builder Closure to create the Decoration(s)
5470
*/
5571
export function createDecos(nodeName: string | string[], builder: (node: SyntaxNodeRef) => Range<Decoration> | Range<Decoration>[] | null) {
72+
return Decoration.set(createNodeRanges(nodeName, builder));
73+
}
74+
75+
/**
76+
* Build generic node ranges by leveraging language lexers.
77+
*
78+
* @param nodeName Node name(s), such as "ATXHeading1" for headings
79+
* @param builder Closure to create the range(s)
80+
*/
81+
function createNodeRanges<T extends RangeValue>(nodeName: string | string[], builder: (node: SyntaxNodeRef) => Range<T> | Range<T>[] | null) {
5682
const editor = window.editor;
57-
const ranges: Range<Decoration>[] = [];
83+
const ranges: Range<T>[] = [];
5884
const nodeNames = Array.isArray(nodeName) ? nodeName : [nodeName];
5985

6086
for (const { from, to } of editor.visibleRanges) {
@@ -69,5 +95,5 @@ export function createDecos(nodeName: string | string[], builder: (node: SyntaxN
6995
});
7096
}
7197

72-
return Decoration.set(ranges.sort((lhs, rhs) => lhs.from - rhs.from));
98+
return ranges.sort((lhs, rhs) => lhs.from - rhs.from);
7399
}

CoreEditor/src/styling/nodes/code.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { createMarkDeco, createWidgetDeco, createLineDeco } from '../matchers/lezer';
2-
import { createDecoPlugin } from '../helper';
1+
import { createBlockWrappers, createMarkDeco, createWidgetDeco, createLineDeco } from '../matchers/lezer';
2+
import { createBlockPlugin, createDecoPlugin } from '../helper';
33
import { PreviewWidget } from '../views';
44
import { cancelDefaultEvent, PreviewType, showPreview } from '../../modules/preview';
55

@@ -11,16 +11,20 @@ export const inlineCodeStyle = createDecoPlugin(() => {
1111
});
1212

1313
/**
14-
* Always use monospace font for FencedCode.
14+
* Always use monospace font for FencedCode and CodeBlock.
1515
*/
16-
export const codeBlockStyle = createDecoPlugin(() => {
17-
return createLineDeco(['FencedCode', 'CodeBlock'], 'cm-md-monospace cm-md-codeBlock', {
18-
'spellcheck': 'false',
19-
'autocorrect': 'off',
20-
'autocomplete': 'off',
21-
'autocapitalize': 'off',
22-
});
23-
});
16+
export const codeBlockStyle = (() => {
17+
const nodeNames = ['FencedCode', 'CodeBlock'];
18+
return [
19+
createBlockPlugin(() => createBlockWrappers(nodeNames, 'cm-md-codeBlockWrapper', {
20+
'spellcheck': 'false',
21+
'autocorrect': 'off',
22+
'autocomplete': 'off',
23+
'autocapitalize': 'off',
24+
})),
25+
createDecoPlugin(() => createLineDeco(nodeNames, 'cm-md-monospace cm-md-codeBlock')),
26+
];
27+
})();
2428

2529
/**
2630
* Enable [preview] button for https://mermaid.js.org/.

CoreEditor/src/styling/nodes/table.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { createLineDeco, createWidgetDeco } from '../matchers/lezer';
2-
import { createDecoPlugin } from '../helper';
1+
import { createBlockWrappers, createLineDeco, createWidgetDeco } from '../matchers/lezer';
2+
import { createBlockPlugin, createDecoPlugin } from '../helper';
33
import { PreviewWidget } from '../views';
44
import { cancelDefaultEvent, PreviewType, showPreview } from '../../modules/preview';
55

66
/**
77
* Always use monospace font for Table.
88
*/
9-
export const tableStyle = createDecoPlugin(() => {
10-
return createLineDeco('Table', 'cm-md-monospace cm-md-table');
11-
});
9+
export const tableStyle = [
10+
createBlockPlugin(() => createBlockWrappers('Table', 'cm-md-tableWrapper')),
11+
createDecoPlugin(() => createLineDeco('Table', 'cm-md-monospace cm-md-table')),
12+
];
1213

1314
/**
1415
* Enable [preview] button for GFM tables.

0 commit comments

Comments
 (0)