mirror of
https://github.com/heyman/heynote.git
synced 2024-11-21 15:33:14 +01:00
Watch buffer file for changes, and automatically reload it if changed (#76)
* Implement Buffer class in main process that watches for changes to the file, and notifies the editor in the renderer process so that it can update the buffer. * Add Editor.setReadOnly() method * Add dummy onChangeCallback function * Remove debug logging
This commit is contained in:
parent
0b6a1a49e8
commit
4274e6237b
@ -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,60 @@ 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
|
||||
}
|
||||
|
||||
// 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
|
||||
this.onChange({filename, eventType, content})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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"),
|
||||
|
@ -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 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
<style lang="sass" scoped>
|
||||
.debug-syntax-tree
|
||||
position: absolute
|
||||
top: 0
|
||||
|
@ -48,6 +48,7 @@ export class HeynoteEditor {
|
||||
this.lineNumberCompartmentPre = new Compartment
|
||||
this.lineNumberCompartment = new Compartment
|
||||
this.foldGutterCompartment = new Compartment
|
||||
this.readOnlyCompartment = new Compartment
|
||||
this.deselectOnCopy = keymap === "emacs"
|
||||
|
||||
const state = EditorState.create({
|
||||
@ -60,6 +61,8 @@ export class HeynoteEditor {
|
||||
this.lineNumberCompartment.of(showLineNumberGutter ? [lineNumbers(), blockLineNumbers] : []),
|
||||
customSetup,
|
||||
this.foldGutterCompartment.of(showFoldGutter ? [foldGutter()] : []),
|
||||
|
||||
this.readOnlyCompartment.of([]),
|
||||
|
||||
this.themeCompartment.of(theme === "dark" ? heynoteDark : heynoteLight),
|
||||
heynoteBase,
|
||||
@ -135,6 +138,12 @@ export class HeynoteEditor {
|
||||
this.view.focus()
|
||||
}
|
||||
|
||||
setReadOnly(readOnly) {
|
||||
this.view.dispatch({
|
||||
effects: this.readOnlyCompartment.reconfigure(readOnly ? [EditorState.readOnly.of(true)] : []),
|
||||
})
|
||||
}
|
||||
|
||||
setTheme(theme) {
|
||||
this.view.dispatch({
|
||||
effects: this.themeCompartment.reconfigure(theme === "dark" ? heynoteDark : heynoteLight),
|
||||
|
@ -47,6 +47,10 @@ const Heynote = {
|
||||
async saveAndQuit(content) {
|
||||
|
||||
},
|
||||
|
||||
onChangeCallback(callback) {
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
onWindowClose(callback) {
|
||||
|
Loading…
Reference in New Issue
Block a user