Skip to content

Commit 5a81955

Browse files
committed
feat: add initial support for inline rant blocks
1 parent 9d0b43c commit 5a81955

File tree

2 files changed

+139
-40
lines changed

2 files changed

+139
-40
lines changed

src/main.ts

+104-40
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,124 @@
1-
import { Plugin, Notice, MarkdownView, TFile } from "obsidian";
1+
import {
2+
Plugin,
3+
Notice,
4+
MarkdownView,
5+
TFile,
6+
MarkdownPostProcessorContext,
7+
} from "obsidian";
28
// @ts-ignore
39
import rustPlugin from "../pkg/obsidian_rantlang_plugin_bg.wasm";
410
import { around } from "monkey-around";
511
import init from "../pkg/obsidian_rantlang_plugin.js";
6-
import RantProcessor from "./processor";
12+
import RantProcessor, { InlineRantProcessor } from "./processor";
713
import { randomSeed } from "./utils";
814

15+
type RantProcessorType = RantProcessor | InlineRantProcessor;
16+
917
export default class RantLangPlugin extends Plugin {
10-
fileMap: Map<TFile, RantProcessor[]> = new Map();
18+
fileMap: Map<TFile, RantProcessorType[]> = new Map();
1119

1220
async onload() {
1321
const buffer = Uint8Array.from(atob(rustPlugin), (c) => c.charCodeAt(0));
1422
await init(Promise.resolve(buffer));
1523

16-
this.registerMarkdownCodeBlockProcessor("rant", (source, el, ctx) => {
17-
const file = this.app.vault.getAbstractFileByPath(ctx.sourcePath);
18-
if (!file || !(file instanceof TFile)) return;
24+
this.registerMarkdownCodeBlockProcessor(
25+
"rant",
26+
(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => {
27+
const file = this.app.vault.getAbstractFileByPath(ctx.sourcePath);
28+
if (!file || !(file instanceof TFile)) return;
29+
30+
const processor = new RantProcessor(
31+
source,
32+
el.createDiv({ cls: "rant" })
33+
);
34+
processor.rant(randomSeed());
35+
36+
/* File-based tracking of registered processors inspired by javalent's excellent dice roller plugin: https://github.com/valentine195/obsidian-dice-roller */
37+
38+
if (!this.fileMap.has(file)) {
39+
this.fileMap.set(file, []);
40+
}
41+
this.fileMap.set(file, [...this.fileMap.get(file), processor]);
42+
43+
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
44+
if (
45+
view &&
46+
this.fileMap.has(file) &&
47+
this.fileMap.get(file).length === 1
48+
) {
49+
const self = this;
1950

20-
const processor = new RantProcessor(
21-
source,
22-
el.createDiv({ cls: "rant" })
23-
);
24-
processor.rant(randomSeed());
51+
let unregisterOnUnloadFile = around(view, {
52+
onUnloadFile: function (next) {
53+
return async function (unloaded: TFile) {
54+
if (unloaded == file) {
55+
self.fileMap.delete(file);
56+
unregisterOnUnloadFile();
57+
}
2558

26-
/* File-based tracking of registered processors inspired by javalent's excellent dice roller plugin: https://github.com/valentine195/obsidian-dice-roller */
59+
return await next.call(this, unloaded);
60+
};
61+
},
62+
});
2763

28-
if (!this.fileMap.has(file)) {
29-
this.fileMap.set(file, []);
64+
view.register(unregisterOnUnloadFile);
65+
view.register(() => this.fileMap.delete(file));
66+
}
3067
}
31-
this.fileMap.set(file, [...this.fileMap.get(file), processor]);
32-
33-
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
34-
if (
35-
view &&
36-
this.fileMap.has(file) &&
37-
this.fileMap.get(file).length === 1
38-
) {
39-
const self = this;
40-
41-
let unregisterOnUnloadFile = around(view, {
42-
onUnloadFile: function (next) {
43-
return async function (unloaded: TFile) {
44-
if (unloaded == file) {
45-
self.fileMap.delete(file);
46-
unregisterOnUnloadFile();
47-
}
48-
49-
return await next.call(this, unloaded);
50-
};
51-
},
52-
});
53-
54-
view.register(unregisterOnUnloadFile);
55-
view.register(() => this.fileMap.delete(file));
68+
);
69+
70+
this.registerMarkdownPostProcessor(
71+
(el: HTMLElement, ctx: MarkdownPostProcessorContext) => {
72+
const file = this.app.vault.getAbstractFileByPath(ctx.sourcePath);
73+
if (!file || !(file instanceof TFile)) return;
74+
75+
const inlineRantQueryPrefix = "rant:";
76+
const codeblocks = el.querySelectorAll("code");
77+
for (let index = 0; index < codeblocks.length; index++) {
78+
const codeblock = codeblocks.item(index);
79+
const text = codeblock.innerText.trim();
80+
if (text.startsWith(inlineRantQueryPrefix)) {
81+
const code = text.substring(inlineRantQueryPrefix.length).trim();
82+
83+
const processor = new InlineRantProcessor(code, el, codeblock);
84+
ctx.addChild(processor);
85+
processor.rant(randomSeed());
86+
87+
/* File-based tracking of registered processors inspired by javalent's excellent dice roller plugin: https://github.com/valentine195/obsidian-dice-roller */
88+
89+
if (!this.fileMap.has(file)) {
90+
this.fileMap.set(file, []);
91+
}
92+
this.fileMap.set(file, [...this.fileMap.get(file), processor]);
93+
94+
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
95+
if (
96+
view &&
97+
this.fileMap.has(file) &&
98+
this.fileMap.get(file).length === 1
99+
) {
100+
const self = this;
101+
102+
let unregisterOnUnloadFile = around(view, {
103+
onUnloadFile: function (next) {
104+
return async function (unloaded: TFile) {
105+
if (unloaded == file) {
106+
self.fileMap.delete(file);
107+
unregisterOnUnloadFile();
108+
}
109+
110+
return await next.call(this, unloaded);
111+
};
112+
},
113+
});
114+
115+
view.register(unregisterOnUnloadFile);
116+
view.register(() => this.fileMap.delete(file));
117+
}
118+
}
119+
}
56120
}
57-
});
121+
);
58122

59123
this.addCommand({
60124
id: "rerant",

src/processor.ts

+35
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { MarkdownRenderChild } from "obsidian";
12
import { rant } from "../pkg/obsidian_rantlang_plugin.js";
23

34
export default class RantProcessor {
@@ -30,3 +31,37 @@ export default class RantProcessor {
3031
this.renderResult();
3132
}
3233
}
34+
35+
/** Processes inline Rant blocks. */
36+
export class InlineRantProcessor extends MarkdownRenderChild {
37+
result: string = "";
38+
39+
constructor(
40+
public input: string,
41+
public container: HTMLElement,
42+
public target: HTMLElement
43+
) {
44+
super(container);
45+
}
46+
47+
processInput(seed: number) {
48+
try {
49+
this.result = rant(this.input, seed);
50+
} catch (error) {
51+
this.result = "ERROR processing Rant block (see console for details)";
52+
console.error(error);
53+
}
54+
}
55+
56+
renderResult() {
57+
let temp = document.createElement("span");
58+
temp.appendText(this.result);
59+
this.target.replaceWith(temp);
60+
this.target = temp;
61+
}
62+
63+
rant(seed: number) {
64+
this.processInput(seed);
65+
this.renderResult();
66+
}
67+
}

0 commit comments

Comments
 (0)