diff --git a/electron/main/buffer.js b/electron/main/buffer.js index a3cbcd52..96cc99b8 100644 --- a/electron/main/buffer.js +++ b/electron/main/buffer.js @@ -1,6 +1,8 @@ import fs from "fs" -import { join } from "path" +import { join, dirname, basename } from "path" import { app } from "electron" +import * as jetpack from "fs-jetpack"; + import CONFIG from "../config" import { isDev } from "../detect-platform" @@ -21,3 +23,61 @@ export function getBufferFilePath() { return bufferFilePath } } + + +export class Buffer { + constructor({filePath, onChange}) { + this.filePath = filePath + this.onChange = onChange + this.watcher = null + this.setupWatcher() + this._lastSavedContent = null + } + + async load() { + const content = await jetpack.read(this.filePath, 'utf8') + this.setupWatcher() + return content + } + + async save(content) { + this._lastSavedContent = content + const saveResult = await jetpack.write(this.filePath, content, { + atomic: true, + mode: '600', + }) + return saveResult + } + + exists() { + return jetpack.exists(this.filePath) === "file" + } + + setupWatcher() { + if (!this.watcher && this.exists()) { + this.watcher = fs.watch( + dirname(this.filePath), + { + persistent: true, + recursive: false, + encoding: "utf8", + }, + async (eventType, filename) => { + if (filename !== basename(this.filePath)) { + return + } + //console.log("Buffer watcher event:", eventType, filename) + + // read the file content and compare it to the last saved content + // (if the content is the same, then we can ignore the event) + const content = await jetpack.read(this.filePath, 'utf8') + if (this._lastSavedContent !== content) { + // file has changed on disk, trigger onChange + //console.log("real change detected") + this.onChange({filename, eventType, content}) + } + } + ) + } + } +} diff --git a/electron/main/index.ts b/electron/main/index.ts index 572f5759..f05efd43 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -11,7 +11,7 @@ import { onBeforeInputEvent } from "../keymap" import { isDev } from '../detect-platform'; import { initializeAutoUpdate, checkForUpdates } from './auto-update'; import { fixElectronCors } from './cors'; -import { getBufferFilePath } from './buffer'; +import { getBufferFilePath, Buffer } from './buffer'; // The built directory structure @@ -210,20 +210,24 @@ ipcMain.handle('dark-mode:set', (event, mode) => { ipcMain.handle('dark-mode:get', () => nativeTheme.themeSource) + +const buffer = new Buffer({ + filePath: getBufferFilePath(), + onChange: (eventData) => { + win?.webContents.send("buffer-content:change", eventData) + }, +}) + ipcMain.handle('buffer-content:load', async () => { - let bufferPath = getBufferFilePath() - if (jetpack.exists(bufferPath) === "file") { - return await jetpack.read(bufferPath, 'utf8') + if (buffer.exists()) { + return await buffer.load() } else { return isDev? initialDevContent : initialContent } }); async function save(content) { - return await jetpack.write(getBufferFilePath(), content, { - atomic: true, - mode: '600', - }) + return await buffer.save(content) } ipcMain.handle('buffer-content:save', async (event, content) =>  { diff --git a/electron/preload/index.ts b/electron/preload/index.ts index c3db29f7..71267eff 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -53,6 +53,10 @@ contextBridge.exposeInMainWorld("heynote", { async saveAndQuit(content) { return await ipcRenderer.invoke("buffer-content:saveAndQuit", content) }, + + onChangeCallback(callback) { + ipcRenderer.on("buffer-content:change", callback) + }, }, settings: CONFIG.get("settings"), diff --git a/src/components/Editor.vue b/src/components/Editor.vue index f65a80c2..95ca6838 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -21,6 +21,8 @@ }, }, + components: {}, + data() { return { syntaxTreeDebugContent: null, @@ -44,11 +46,16 @@ // load buffer content and create editor window.heynote.buffer.load().then((content) => { + let diskContent = content this.editor = new HeynoteEditor({ element: this.$refs.editor, content: content, theme: this.theme, saveFunction: (content) => { + if (content === diskContent) { + return + } + diskContent = content window.heynote.buffer.save(content) }, keymap: this.keymap, @@ -57,6 +64,12 @@ }) window._heynote_editor = this.editor window.document.addEventListener("currenciesLoaded", this.onCurrenciesLoaded) + + // set up buffer change listener + window.heynote.buffer.onChangeCallback((event, {filename, content, eventType}) => { + diskContent = content + this.editor.setContent(content) + }) }) // set up window close handler that will save the buffer and quit window.heynote.onWindowClose(() => { @@ -142,7 +155,7 @@ -