Skip to content

Commit

Permalink
Merge pull request #78 from mindofmatthew/file-changes
Browse files Browse the repository at this point in the history
Improve save and close behavior for files
  • Loading branch information
matthewkaney authored May 10, 2024
2 parents 15a2e80 + f270e8f commit 69acbcd
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 9 deletions.
15 changes: 12 additions & 3 deletions app/desktop/src/main/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,19 @@ export class DesktopDocument extends EventEmitter<DocumentEvents> {
return this.fileStatus.path;
}

get saved() {
get needsSave() {
// Check for blank, unsaved documents
if (
!this.fileStatus.path &&
(!this.content || this.content.doc.eq(Text.empty))
) {
return false;
}

// Then check if the document has been edited
return this.fileStatus.version === this.content?.version
? this.fileStatus.saved
: false;
? !this.fileStatus.saved
: true;
}

constructor(
Expand Down
87 changes: 83 additions & 4 deletions app/desktop/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fixPath();

import { autoUpdater } from "electron-updater";

autoUpdater.checkForUpdatesAndNotify();
// autoUpdater.checkForUpdatesAndNotify();

import { StateManagement } from "@core/state";

Expand Down Expand Up @@ -49,10 +49,17 @@ const createWindow = (
})
);

listeners.push(
filesystem.on("current", (doc) => {
if (doc) send("setCurrent", { id: doc.id });
})
);

// Attach file handlers
listeners.push(
filesystem.on("open", (document) => {
let { id, path, content, saved } = document;
let { id, path, content, fileStatus } = document;
let { saved } = fileStatus;

let docListeners: typeof listeners = [];
docsListeners[id] = docListeners;
Expand Down Expand Up @@ -172,6 +179,23 @@ const createWindow = (

window.loadFile("./build/renderer/index.html");

window.on("close", async (event) => {
let docs = [...filesystem.docs.values()];

if (!docs.some((doc) => doc.needsSave)) return;

event.preventDefault();

try {
await closeAll(window);
window.close();
} catch (error) {
if (!(error instanceof CancelledError)) {
console.log("Unexpected Error: " + (error as Error).message);
}
}
});

window.on("closed", () => {
for (let listener of listeners) {
listener();
Expand Down Expand Up @@ -279,9 +303,14 @@ async function close({ window, id }: CloseOptions) {
id = id ?? filesystem.currentDocID;
let document = id ? filesystem.getDoc(id) : filesystem.currentDoc;

if (!id || !document) throw Error("Tried to close a non-existent document");
if (!id || !document) {
if (id) {
send("close", { id });
}
return;
}

if (!document.saved) {
if (document.needsSave) {
let { response } = await dialog.showMessageBox(window, {
type: "warning",
message: "Do you want to save your changes?",
Expand Down Expand Up @@ -312,6 +341,56 @@ async function close({ window, id }: CloseOptions) {
send("close", { id });
}

class CancelledError extends Error {
constructor() {
super("Close All action was cancelled");
}
}

async function closeAll(window?: BrowserWindow) {
if (!window) return;

let [send] = wrapIPC(window.webContents);

let docs = [...filesystem.docs.values()];

if (docs.some((doc) => doc.needsSave)) {
let { response } = await dialog.showMessageBox(window, {
type: "warning",
message: "Do you want to save your changes?",
buttons: ["Save", "Don't Save", "Cancel"],
});

// Cancelled
if (response === 2) throw new CancelledError();

// Save
if (response === 0) {
for (let doc of docs) {
if (doc.needsSave) {
if (doc.path !== null) {
doc.save();
} else {
filesystem.currentDocID = doc.id;
let { canceled, filePath } = await dialog.showSaveDialog(window);

if (!canceled && filePath) {
await doc.save(filePath);
} else {
throw new CancelledError();
}
}
}
}
}
}

// Close all documents
await Promise.all(
docs.map((doc) => doc.close().then(() => send("close", { id: doc.id })))
);
}

menu.on("about", showAbout);
function showAbout(window?: BrowserWindow) {
if (window) {
Expand Down
16 changes: 14 additions & 2 deletions app/desktop/src/renderer/file.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ElectronAPI } from "../preload";

import { EditorState, StateField, StateEffect, Facet } from "@codemirror/state";
import {
EditorState,
StateField,
StateEffect,
Facet,
Text,
} from "@codemirror/state";
import { ViewPlugin } from "@codemirror/view";

import { SavedStatus } from "../main/filesystem";
Expand Down Expand Up @@ -79,7 +85,13 @@ export function fileSync(
}

export function getSaveStatus(state: EditorState) {
const { version, thisVersion, saved } = state.field(saveState);
const { version, thisVersion, path, saved } = state.field(saveState);

// Empty docs are never unsaved
// TODO: Have this check be done in the main process
if (!path && state.doc.eq(Text.empty)) {
return true;
}

return version === thisVersion ? saved : false;
}
Expand Down

0 comments on commit 69acbcd

Please sign in to comment.