Skip to content

Commit c2e169b

Browse files
committed
feat: add commands to toggle the active node
close #47
1 parent 388e46f commit c2e169b

File tree

3 files changed

+88
-18
lines changed

3 files changed

+88
-18
lines changed

package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,22 @@
2323
"commands": [
2424
{
2525
"command": "markmap-vscode.open",
26+
"category": "Markmap",
2627
"title": "Open as markmap",
2728
"icon": {
2829
"light": "./assets/light.svg",
2930
"dark": "./assets/dark.svg"
3031
}
32+
},
33+
{
34+
"command": "markmap-vscode.toggle",
35+
"category": "Markmap",
36+
"title": "Toggle the active node"
37+
},
38+
{
39+
"command": "markmap-vscode.toggle-recursively",
40+
"category": "Markmap",
41+
"title": "Toggle the active node recursively"
3142
}
3243
],
3344
"customEditors": [
@@ -47,6 +58,14 @@
4758
{
4859
"when": "editorLangId == markdown",
4960
"command": "markmap-vscode.open"
61+
},
62+
{
63+
"when": "editorLangId == markdown",
64+
"command": "markmap-vscode.toggle"
65+
},
66+
{
67+
"when": "editorLangId == markdown",
68+
"command": "markmap-vscode.toggle-recursively"
5069
}
5170
],
5271
"explorer/context": [

src/app.ts

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ const vscode = acquireVsCodeApi();
1212
let firstTime = true;
1313
let root: INode | undefined;
1414
let style: HTMLStyleElement;
15-
let active: {
16-
node: INode;
17-
el: Element;
18-
} | undefined;
15+
let active:
16+
| {
17+
node: INode;
18+
el: Element;
19+
}
20+
| undefined;
1921

2022
const handlers = {
2123
async setData(data: { root?: INode; jsonOptions?: IMarkmapJSONOptions }) {
@@ -25,8 +27,11 @@ const handlers = {
2527
firstTime = false;
2628
}
2729
},
28-
setCursor(line: number) {
29-
const node = root && findActiveNode(line);
30+
async setCursor(options: { line: number; autoExpand?: boolean }) {
31+
const result = root && findActiveNode(options);
32+
if (!result) return;
33+
const { node, needRerender } = result;
34+
if (needRerender) await mm.renderData();
3035
if (node) highlightNode(node);
3136
},
3237
setCSS(data: string) {
@@ -127,18 +132,38 @@ function findHeading(id: string) {
127132
return target;
128133
}
129134

130-
function findActiveNode(line: number) {
131-
function dfs(node: INode) {
135+
function findActiveNode({
136+
line,
137+
autoExpand = true,
138+
}: {
139+
line: number;
140+
autoExpand?: boolean;
141+
}) {
142+
function dfs(node: INode, ancestors: INode[] = []) {
132143
const [start, end] =
133144
(node.payload?.lines as string)?.split(',').map((s) => +s) || [];
134145
if (start >= 0 && start <= line && line < end) {
135146
best = node;
147+
bestAncestors = ancestors;
136148
}
137-
node.children?.forEach(dfs);
149+
ancestors = [...ancestors, node];
150+
node.children?.forEach((child) => {
151+
dfs(child, ancestors);
152+
});
138153
}
139154
let best: INode | undefined;
155+
let bestAncestors: INode[] = [];
140156
dfs(root);
141-
return best;
157+
let needRerender = false;
158+
if (autoExpand) {
159+
bestAncestors.forEach((node) => {
160+
if (node.payload?.fold) {
161+
node.payload.fold = 0;
162+
needRerender = true;
163+
}
164+
});
165+
}
166+
return best && { node: best, needRerender };
142167
}
143168

144169
function highlightNode(node: INode) {

src/extension.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ async function writeFile(targetUri: Uri, text: string) {
4747
}
4848

4949
class MarkmapEditor implements CustomTextEditorProvider {
50-
constructor(private context: ExtensionContext) {}
50+
private webviewPanelMap = new Map<TextDocument, WebviewPanel>();
51+
52+
constructor(private context: ExtensionContext) { }
5153

5254
private resolveAssetPath(relPath: string) {
5355
return Utils.joinPath(this.context.extensionUri, relPath);
@@ -61,6 +63,7 @@ class MarkmapEditor implements CustomTextEditorProvider {
6163
}
6264

6365
resolveCustomTextEditor(document: TextDocument, webviewPanel: WebviewPanel) {
66+
this.webviewPanelMap.set(document, webviewPanel);
6467
webviewPanel.webview.options = {
6568
enableScripts: true,
6669
};
@@ -111,11 +114,16 @@ class MarkmapEditor implements CustomTextEditorProvider {
111114
if (editor?.document === document) {
112115
webviewPanel.webview.postMessage({
113116
type: 'setCursor',
114-
data: editor.selection.active.line,
117+
data: {
118+
line: editor.selection.active.line,
119+
autoExpand: globalOptions?.autoExpand,
120+
},
115121
});
116122
}
117123
};
118-
let globalOptions: IMarkmapJSONOptions;
124+
let globalOptions: IMarkmapJSONOptions & {
125+
autoExpand?: boolean;
126+
};
119127
let customCSS: string;
120128
const updateOptions = () => {
121129
const raw = workspace
@@ -185,11 +193,11 @@ class MarkmapEditor implements CustomTextEditorProvider {
185193
styles: [
186194
...(customCSS
187195
? [
188-
{
189-
type: 'style',
190-
data: customCSS,
191-
} as CSSItem,
192-
]
196+
{
197+
type: 'style',
198+
data: customCSS,
199+
} as CSSItem,
200+
]
193201
: []),
194202
],
195203
scripts: [
@@ -311,6 +319,16 @@ class MarkmapEditor implements CustomTextEditorProvider {
311319
];
312320
webviewPanel.onDidDispose(() => {
313321
disposables.forEach((disposable) => disposable.dispose());
322+
this.webviewPanelMap.delete(document);
323+
});
324+
}
325+
326+
toggleActiveNode(document: TextDocument, recursive = false) {
327+
const webviewPanel = this.webviewPanelMap.get(document);
328+
if (!webviewPanel) return;
329+
webviewPanel.webview.postMessage({
330+
type: 'toggleNode',
331+
data: recursive,
314332
});
315333
}
316334
}
@@ -327,6 +345,14 @@ export function activate(context: ExtensionContext) {
327345
ViewColumn.Beside,
328346
);
329347
}),
348+
commands.registerCommand(`${PREFIX}.toggle`, () => {
349+
const document = vscodeWindow.activeTextEditor?.document;
350+
if (document) markmapEditor.toggleActiveNode(document);
351+
}),
352+
commands.registerCommand(`${PREFIX}.toggle-recursively`, () => {
353+
const document = vscodeWindow.activeTextEditor?.document;
354+
if (document) markmapEditor.toggleActiveNode(document, true);
355+
}),
330356
);
331357
context.subscriptions.push(
332358
vscodeWindow.registerCustomEditorProvider(VIEW_TYPE, markmapEditor, {

0 commit comments

Comments
 (0)