Skip to content

Commit 10c056c

Browse files
committed
fix bugs; add #40
1 parent 457dd60 commit 10c056c

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
lines changed

exampleVault/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,10 @@ main :: proc() {
131131
132132

133133
```cpp
134+
#include <foo>
134135
#include <iostream>
135136

137+
136138
int main() {
137139
std::cout << "Hello World!";
138140
return 0;

src/CodeBlock.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class CodeBlock extends MarkdownRenderChild {
2929
const startLine = lines[sectionInfo.lineStart];
3030

3131
// regexp to match the text after the code block language
32-
const regex = new RegExp('^[^`~]*?(```+|~~~+)' + this.language + ' (.*)', 'g');
32+
const regex = new RegExp('^[^`~]*?\\s*(```+|~~~+)' + this.language + ' (.*)', 'g');
3333
const match = regex.exec(startLine);
3434
if (match !== null) {
3535
return match[2];

src/codemirror/Cm6_ViewPlugin.ts

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@ import { Cm6_Util } from 'src/codemirror/Cm6_Util';
88
import { type ThemedToken } from 'shiki';
99
import { editorLivePreviewField } from 'obsidian';
1010

11-
interface DecoQueueNode {
11+
enum DecorationUpdateType {
12+
Insert,
13+
Remove,
14+
}
15+
16+
type DecorationUpdate = InsertDecoration | RemoveDecoration;
17+
18+
interface InsertDecoration {
19+
type: DecorationUpdateType.Insert;
1220
from: number;
1321
to: number;
1422
lang: string;
@@ -17,6 +25,12 @@ interface DecoQueueNode {
1725
hideTo?: number;
1826
}
1927

28+
interface RemoveDecoration {
29+
type: DecorationUpdateType.Remove;
30+
from: number;
31+
to: number;
32+
}
33+
2034
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
2135
export function createCm6Plugin(plugin: ShikiPlugin) {
2236
return ViewPlugin.fromClass(
@@ -30,7 +44,7 @@ export function createCm6Plugin(plugin: ShikiPlugin) {
3044
void this.updateWidgets(view);
3145

3246
plugin.updateCm6Plugin = (): Promise<void> => {
33-
return this.forceUpdate();
47+
return this.updateWidgets(this.view);
3448
};
3549
}
3650

@@ -50,12 +64,6 @@ export function createCm6Plugin(plugin: ShikiPlugin) {
5064
}
5165
}
5266

53-
async forceUpdate(): Promise<void> {
54-
await this.updateWidgets(this.view);
55-
56-
this.view.dispatch(this.view.state.update({}));
57-
}
58-
5967
isLivePreview(state: EditorState): boolean {
6068
// @ts-ignore some strange private field not being assignable
6169
return state.field(editorLivePreviewField);
@@ -70,7 +78,7 @@ export function createCm6Plugin(plugin: ShikiPlugin) {
7078
async updateWidgets(view: EditorView, docChanged: boolean = true): Promise<void> {
7179
let lang = '';
7280
let state: SyntaxNode[] = [];
73-
const decoQueue: DecoQueueNode[] = [];
81+
const decorationUpdates: DecorationUpdate[] = [];
7482

7583
// const t1 = performance.now();
7684

@@ -92,7 +100,8 @@ export function createCm6Plugin(plugin: ShikiPlugin) {
92100
if (match) {
93101
const hasSelectionOverlap = Cm6_Util.checkSelectionAndRangeOverlap(view.state.selection, node.from - 1, node.to + 1);
94102

95-
decoQueue.push({
103+
decorationUpdates.push({
104+
type: DecorationUpdateType.Insert,
96105
from: node.from,
97106
to: node.to,
98107
lang: match[1],
@@ -123,42 +132,63 @@ export function createCm6Plugin(plugin: ShikiPlugin) {
123132
if (props.has('HyperMD-codeblock-begin')) {
124133
const content = Cm6_Util.getContent(view.state, node.from, node.to);
125134

126-
lang = /^```(\S+)/.exec(content)?.[1] ?? '';
135+
lang = /^```\s*(\S+)/.exec(content)?.[1] ?? '';
127136
}
128137

129138
if (props.has('HyperMD-codeblock-end')) {
130139
if (state.length > 0 && lang !== '') {
131140
const start = state[0].from;
132141
const end = state[state.length - 1].to;
133142

134-
decoQueue.push({
143+
decorationUpdates.push({
144+
type: DecorationUpdateType.Insert,
135145
from: start,
136146
to: end,
137147
lang,
138148
content: Cm6_Util.getContent(view.state, start, end),
139149
});
140150
}
141151

152+
if (state.length > 0 && lang === '') {
153+
const start = state[0].from;
154+
const end = state[state.length - 1].to;
155+
156+
decorationUpdates.push({
157+
type: DecorationUpdateType.Remove,
158+
from: start,
159+
to: end,
160+
});
161+
}
162+
142163
lang = '';
143164
state = [];
144165
}
145166
},
146167
});
147168

148-
for (const node of decoQueue) {
169+
for (const node of decorationUpdates) {
149170
try {
150-
const decorations = await this.buildDecorations(node.hideTo ?? node.from, node.to, node.lang, node.content);
151-
this.removeDecoration(node.from, node.to);
152-
if (node.hideLang) {
153-
// add the decoration that hides the language tag
154-
decorations.unshift(Decoration.replace({}).range(node.from, node.hideTo));
171+
if (node.type === DecorationUpdateType.Remove) {
172+
this.removeDecoration(node.from, node.to);
173+
} else if (node.type === DecorationUpdateType.Insert) {
174+
const decorations = await this.buildDecorations(node.hideTo ?? node.from, node.to, node.lang, node.content);
175+
this.removeDecoration(node.from, node.to);
176+
if (node.hideLang) {
177+
// add the decoration that hides the language tag
178+
decorations.unshift(Decoration.replace({}).range(node.from, node.hideTo));
179+
}
180+
// add the highlight decorations
181+
this.addDecoration(node.from, node.to, decorations);
155182
}
156-
// add the highlight decorations
157-
this.addDecoration(node.from, node.to, decorations);
158183
} catch (e) {
159184
console.error(e);
160185
}
161186
}
187+
188+
if (decorationUpdates.length > 0) {
189+
this.view.dispatch(this.view.state.update({}));
190+
}
191+
162192
// console.log('Traversed syntax tree in', performance.now() - t1, 'ms');
163193
}
164194

0 commit comments

Comments
 (0)