Skip to content

Commit

Permalink
Add metadata to the beginning of the serialized buffer.
Browse files Browse the repository at this point in the history
Store the cursors' positions in the buffer metadata and restore the cursors when loading the buffer content.
  • Loading branch information
heyman committed Jul 15, 2024
1 parent 633ea63 commit 2e26224
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 21 deletions.
53 changes: 36 additions & 17 deletions src/editor/editor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Annotation, EditorState, Compartment, Facet } from "@codemirror/state"
import { Annotation, EditorState, Compartment, Facet, EditorSelection } from "@codemirror/state"
import { EditorView, keymap, drawSelection, ViewPlugin, lineNumbers } from "@codemirror/view"
import { indentUnit, forceParsing, foldGutter, ensureSyntaxTree } from "@codemirror/language"
import { markdown } from "@codemirror/lang-markdown"
Expand All @@ -21,6 +21,7 @@ import { languageDetection } from "./language-detection/autodetect.js"
import { autoSaveContent } from "./save.js"
import { todoCheckboxPlugin} from "./todo-checkbox.ts"
import { links } from "./links.js"
import { NoteFormat } from "./note-format.js"

export const LANGUAGE_SELECTOR_EVENT = "openLanguageSelector"

Expand Down Expand Up @@ -61,9 +62,10 @@ export class HeynoteEditor {
this.fontTheme = new Compartment
this.defaultBlockToken = "text"
this.defaultBlockAutoDetect = true
this.saveFunction = saveFunction

const state = EditorState.create({
doc: content || "",
doc: "",
extensions: [
this.keymapCompartment.of(getKeymapExtensions(this, keymap)),
heynoteCopyCut(this),
Expand Down Expand Up @@ -96,7 +98,7 @@ export class HeynoteEditor {
return {class: view.state.facet(EditorView.darkTheme) ? "dark-theme" : "light-theme"}
}),

saveFunction ? autoSaveContent(saveFunction, 2000) : [],
this.saveFunction ? autoSaveContent(this, 2000) : [],

todoCheckboxPlugin,
markdown(),
Expand All @@ -107,7 +109,7 @@ export class HeynoteEditor {
// make sure saveFunction is called when page is unloaded
if (saveFunction) {
window.addEventListener("beforeunload", () => {
saveFunction(this.getContent())
this.save()
})
}

Expand All @@ -116,36 +118,53 @@ export class HeynoteEditor {
parent: element,
})

// Ensure we have a parsed syntax tree when buffer is loaded. This prevents errors for large buffers
// when moving the cursor to the end of the buffer when the program starts
ensureSyntaxTree(state, state.doc.length, 5000)
this.setContent(content)

if (focus) {
this.view.dispatch({
selection: {anchor: this.view.state.doc.length, head: this.view.state.doc.length},
scrollIntoView: true,
})
this.view.focus()
}
}

save() {
this.saveFunction(this.getContent())
}

getContent() {
return this.view.state.sliceDoc()
this.note.content = this.view.state.sliceDoc()
this.note.cursors = this.view.state.selection.toJSON()
return this.note.serialize()
}

setContent(content) {
this.note = NoteFormat.load(content)

// set buffer content
this.view.dispatch({
changes: {
from: 0,
to: this.view.state.doc.length,
insert: content,
insert: this.note.content,
},
annotations: [heynoteEvent.of(SET_CONTENT)],
})
this.view.dispatch({
selection: {anchor: this.view.state.doc.length, head: this.view.state.doc.length},
scrollIntoView: true,
})

// Ensure we have a parsed syntax tree when buffer is loaded. This prevents errors for large buffers
// when moving the cursor to the end of the buffer when the program starts
ensureSyntaxTree(this.view.state, this.view.state.doc.length, 5000)

// set cursor positions
if (this.note.cursors) {
this.view.dispatch({
selection: EditorSelection.fromJSON(this.note.cursors),
scrollIntoView: true,
})
} else {
// if metadata doesn't contain cursor position, we set the cursor to the end of the buffer
this.view.dispatch({
selection: {anchor: this.view.state.doc.length, head: this.view.state.doc.length},
scrollIntoView: true,
})
}
}

getBlocks() {
Expand Down
35 changes: 35 additions & 0 deletions src/editor/note-format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export class NoteFormat {
constructor() {
this.content = '';
this.metadata = {};
}

static load(data) {
const note = new NoteFormat();

note.content = data
const firstSeparator = data.indexOf("\n∞∞∞")
if (firstSeparator !== -1) {
const metadataContent = data.slice(0, firstSeparator).trim()
if (metadataContent !== "") {
note.metadata = JSON.parse(metadataContent)
}
note.content = data.slice(firstSeparator)
}

return note
}

serialize() {
this.metadata.formatVersion = "1.0"
return JSON.stringify(this.metadata) + this.content
}

set cursors(cursors) {
this.metadata.cursors = cursors
}

get cursors() {
return this.metadata.cursors
}
}
8 changes: 4 additions & 4 deletions src/editor/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { ViewPlugin } from "@codemirror/view"
import { debounce } from "debounce"


export const autoSaveContent = (saveFunction, interval) => {
const save = debounce((view) => {
export const autoSaveContent = (editor, interval) => {
const save = debounce(() => {
//console.log("saving buffer")
saveFunction(view.state.sliceDoc())
editor.save()
}, interval);

return ViewPlugin.fromClass(
class {
update(update) {
if (update.docChanged) {
save(update.view)
save()
}
}
}
Expand Down

0 comments on commit 2e26224

Please sign in to comment.