Skip to content

Commit 4df6da8

Browse files
committed
do not save if no changes
1 parent 9e04ce0 commit 4df6da8

File tree

2 files changed

+67
-43
lines changed

2 files changed

+67
-43
lines changed

.changeset/happy-eels-wish.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"learningmap-studio": patch
3+
---
4+
5+
Do not save if there are no changes

platforms/vscode/src/LearningmapEditorProvider.ts

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import * as vscode from 'vscode';
1+
import * as vscode from "vscode";
22

33
/**
44
* Provider for learningmap custom editor.
55
* Handles the webview that displays the LearningMapEditor component.
66
*/
7-
export class LearningmapEditorProvider implements vscode.CustomTextEditorProvider {
8-
private static readonly viewType = 'learningmap.editor';
7+
export class LearningmapEditorProvider
8+
implements vscode.CustomTextEditorProvider
9+
{
10+
private static readonly viewType = "learningmap.editor";
911
private activeWebviewPanel: vscode.WebviewPanel | undefined;
1012

1113
constructor(private readonly context: vscode.ExtensionContext) {}
@@ -16,7 +18,7 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
1618
public sendCommandToActiveEditor(command: string): void {
1719
if (this.activeWebviewPanel) {
1820
this.activeWebviewPanel.webview.postMessage({
19-
type: 'command',
21+
type: "command",
2022
command: command,
2123
});
2224
}
@@ -28,25 +30,25 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
2830
public async resolveCustomTextEditor(
2931
document: vscode.TextDocument,
3032
webviewPanel: vscode.WebviewPanel,
31-
_token: vscode.CancellationToken
33+
_token: vscode.CancellationToken,
3234
): Promise<void> {
3335
// Track this as the active webview panel
3436
this.activeWebviewPanel = webviewPanel;
35-
37+
3638
// Clear active panel when disposed
3739
webviewPanel.onDidDispose(() => {
3840
if (this.activeWebviewPanel === webviewPanel) {
3941
this.activeWebviewPanel = undefined;
4042
}
4143
});
42-
44+
4345
// Update active panel on focus
4446
webviewPanel.onDidChangeViewState(() => {
4547
if (webviewPanel.active) {
4648
this.activeWebviewPanel = webviewPanel;
4749
}
4850
});
49-
51+
5052
// Setup initial webview content
5153
webviewPanel.webview.options = {
5254
enableScripts: true,
@@ -60,7 +62,7 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
6062
const updateWebview = () => {
6163
isUpdatingFromDocument = true;
6264
webviewPanel.webview.postMessage({
63-
type: 'update',
65+
type: "update",
6466
content: document.getText(),
6567
});
6668
// Reset flag after a short delay
@@ -73,38 +75,47 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
7375
updateWebview();
7476

7577
// Listen for changes in the document (from external sources)
76-
const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(e => {
77-
if (e.document.uri.toString() === document.uri.toString() && e.contentChanges.length > 0) {
78-
// Only update if change was from external source (not from us)
79-
if (!isUpdatingFromDocument) {
80-
updateWebview();
78+
const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(
79+
(e) => {
80+
if (
81+
e.document.uri.toString() === document.uri.toString() &&
82+
e.contentChanges.length > 0
83+
) {
84+
// Only update if change was from external source (not from us)
85+
if (!isUpdatingFromDocument) {
86+
updateWebview();
87+
}
8188
}
82-
}
83-
});
89+
},
90+
);
8491

8592
// Handle document save event
86-
const saveDocumentSubscription = vscode.workspace.onWillSaveTextDocument(async e => {
87-
if (e.document.uri.toString() === document.uri.toString()) {
88-
// Wait for the save event to complete
89-
e.waitUntil(new Promise<void>((resolve) => {
90-
// Send save command to webview
91-
webviewPanel.webview.postMessage({
92-
type: 'command',
93-
command: 'save',
94-
});
95-
96-
// Wait a bit for the webview to respond
97-
setTimeout(() => {
98-
resolve();
99-
}, 100);
100-
}));
101-
}
102-
});
93+
const saveDocumentSubscription = vscode.workspace.onWillSaveTextDocument(
94+
async (e) => {
95+
if (e.document.uri.toString() === document.uri.toString()) {
96+
// Wait for the save event to complete
97+
e.waitUntil(
98+
new Promise<void>((resolve) => {
99+
// Send save command to webview
100+
webviewPanel.webview.postMessage({
101+
type: "command",
102+
command: "save",
103+
});
104+
105+
// Wait a bit for the webview to respond
106+
setTimeout(() => {
107+
resolve();
108+
}, 100);
109+
}),
110+
);
111+
}
112+
},
113+
);
103114

104115
// Listen for messages from the webview
105-
webviewPanel.webview.onDidReceiveMessage(async e => {
116+
webviewPanel.webview.onDidReceiveMessage(async (e) => {
106117
switch (e.type) {
107-
case 'change':
118+
case "change":
108119
// Content changed in the webview - update the document to mark it as dirty
109120
// Set flag to prevent circular updates
110121
isUpdatingFromDocument = true;
@@ -114,12 +125,12 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
114125
isUpdatingFromDocument = false;
115126
}, 200);
116127
return;
117-
case 'save':
128+
case "save":
118129
if (!isUpdatingFromDocument) {
119130
await this.saveDocument(document, e.content);
120131
}
121132
return;
122-
case 'ready':
133+
case "ready":
123134
// Webview is ready, send initial content
124135
updateWebview();
125136
return;
@@ -136,17 +147,25 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
136147
/**
137148
* Write out the JSON to a given document.
138149
*/
139-
private async saveDocument(document: vscode.TextDocument, json: any): Promise<void> {
150+
private async saveDocument(
151+
document: vscode.TextDocument,
152+
json: any,
153+
): Promise<void> {
140154
const edit = new vscode.WorkspaceEdit();
141155

142156
// Format the JSON with 2-space indentation
143157
const text = JSON.stringify(json, null, 2);
144158

159+
if (document.getText() == text) {
160+
// No changes
161+
return;
162+
}
163+
145164
// Replace the entire document
146165
edit.replace(
147166
document.uri,
148167
new vscode.Range(0, 0, document.lineCount, 0),
149-
text
168+
text,
150169
);
151170

152171
await vscode.workspace.applyEdit(edit);
@@ -158,10 +177,10 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
158177
private getHtmlForWebview(webview: vscode.Webview): string {
159178
// Get URIs for scripts and styles
160179
const scriptUri = webview.asWebviewUri(
161-
vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'webview.js')
180+
vscode.Uri.joinPath(this.context.extensionUri, "dist", "webview.js"),
162181
);
163182
const styleUri = webview.asWebviewUri(
164-
vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'webview.css')
183+
vscode.Uri.joinPath(this.context.extensionUri, "dist", "webview.css"),
165184
);
166185

167186
// Use a nonce to only allow specific scripts to be run
@@ -201,7 +220,7 @@ function getNonce() {
201220
// Generate a cryptographically secure random string
202221
// This works in both Node.js and browser environments
203222
const array = new Uint32Array(8);
204-
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
223+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
205224
// Browser or modern Node.js with Web Crypto API
206225
crypto.getRandomValues(array);
207226
} else {
@@ -210,5 +229,5 @@ function getNonce() {
210229
array[i] = Math.floor(Math.random() * 0xffffffff);
211230
}
212231
}
213-
return Array.from(array, num => num.toString(16).padStart(8, '0')).join('');
232+
return Array.from(array, (num) => num.toString(16).padStart(8, "0")).join("");
214233
}

0 commit comments

Comments
 (0)