From 93e805152ef22a05f25f4b292a69030182cf8251 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 26 Feb 2024 18:18:36 +0100 Subject: [PATCH 01/26] Add .webmanifest to web app --- public/site.webmanifest | 11 +++++++++++ webapp/index.html | 1 + 2 files changed, 12 insertions(+) create mode 100644 public/site.webmanifest diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 0000000..a4b2915 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,11 @@ +{ + "name": "Heynote", + "short_name": "Heynote", + "icons": [ + { + "src": "/icon.ico", + "sizes": "256x256" + } + ], + "display": "standalone" +} diff --git a/webapp/index.html b/webapp/index.html index af26a93..fd0ecd0 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -5,6 +5,7 @@ + Heynote From 78e2bb2ec3f1928715b6c688f2c7362011da153c Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 25 Mar 2024 13:29:23 +0100 Subject: [PATCH 02/26] Add link to website and logo Signed-off-by: Jonatan Heyman --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 228dd3f..50569f2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/heyman/heynote)](https://github.com/heyman/heynote/releases) [![Build Status](https://github.com/heyman/heynote/workflows/Tests/badge.svg)](https://github.com/heyman/heynote/actions?query=workflow%3ATests) + + +**Website:** [heynote.com](https://heynote.com) Heynote is a dedicated scratchpad for developers. It functions as a large persistent text buffer where you can write down anything you like. Works great for that Slack message you don't want to accidentally send, a JSON response from an API you're working with, notes from a meeting, your daily to-do list, etc. From d943fc8015b063c38cedf492a86ba07839938963 Mon Sep 17 00:00:00 2001 From: Donghee Lee Date: Wed, 12 Jun 2024 07:47:45 +0200 Subject: [PATCH 03/26] Support Dart Syntax --- README.md | 2 +- public/langdetect-worker.js | 2 +- src/editor/lang-heynote/heynote.grammar | 2 +- src/editor/lang-heynote/parser.js | 2 +- src/editor/languages.js | 8 +++++++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 50569f2..1bc4a38 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Available for Mac, Windows, and Linux. - Block-based - Syntax highlighting: - C++, C#, Clojure, CSS, Erlang, Go, Groovy, HTML, Java, JavaScript, JSX, Kotlin, TypeScript, TOML, TSX, JSON, Lezer, Markdown, PHP, Python, Ruby, Rust, Shell, SQL, Swift, XML, YAML + C++, C#, Clojure, CSS, Erlang, Dart, Go, Groovy, HTML, Java, JavaScript, JSX, Kotlin, TypeScript, TOML, TSX, JSON, Lezer, Markdown, PHP, Python, Ruby, Rust, Shell, SQL, Swift, XML, YAML - Language auto-detection - Auto-formatting diff --git a/public/langdetect-worker.js b/public/langdetect-worker.js index 95ca257..a519b4a 100644 --- a/public/langdetect-worker.js +++ b/public/langdetect-worker.js @@ -1,6 +1,6 @@ importScripts("guesslang.min.js") -GUESSLANG_LANGUAGES = ["json","py","html","sql","md","java","php","css","xml","cpp","rs","cs","rb","sh","yaml","toml","go","clj","erl","js","ts","swift","kt","groovy","ps1"] +GUESSLANG_LANGUAGES = ["json","py","html","sql","md","java","php","css","xml","cpp","rs","cs","rb","sh","yaml","toml","go","clj","erl","js","ts","swift","kt","groovy","ps1","dart"] const guessLang = new self.GuessLang() diff --git a/src/editor/lang-heynote/heynote.grammar b/src/editor/lang-heynote/heynote.grammar index afaa8e6..77aa679 100644 --- a/src/editor/lang-heynote/heynote.grammar +++ b/src/editor/lang-heynote/heynote.grammar @@ -11,7 +11,7 @@ NoteDelimiter { @tokens { noteDelimiterMark { "∞∞∞" } - NoteLanguage { "text" | "math" | "javascript" | "typescript" | "jsx" | "tsx" | "json" | "python" | "html" | "sql" | "markdown" | "java" | "php" | "css" | "xml" | "cpp" | "rust" | "csharp" | "ruby" | "shell" | "yaml" | "golang" | "clojure" | "erlang" | "lezer" | "toml" | "swift" | "kotlin" | "groovy" | "diff" | "powershell" } + NoteLanguage { "text" | "math" | "javascript" | "typescript" | "jsx" | "tsx" | "json" | "python" | "html" | "sql" | "markdown" | "java" | "php" | "css" | "xml" | "cpp" | "rust" | "csharp" | "ruby" | "shell" | "yaml" | "golang" | "clojure" | "erlang" | "lezer" | "toml" | "swift" | "kotlin" | "groovy" | "diff" | "powershell" | "dart" } Auto { "-a" } noteDelimiterEnter { "\n" } //NoteContent { String } diff --git a/src/editor/lang-heynote/parser.js b/src/editor/lang-heynote/parser.js index e24be27..8091b82 100644 --- a/src/editor/lang-heynote/parser.js +++ b/src/editor/lang-heynote/parser.js @@ -10,7 +10,7 @@ export const parser = LRParser.deserialize({ maxTerm: 10, skippedNodes: [0], repeatNodeCount: 1, - tokenData: "-x~RbYZ!Z}!O!`#V#W!k#W#X$X#X#Y$k#Z#[%Z#[#]%|#^#_&`#_#`'|#`#a(f#a#b)O#d#e)}#f#g+i#g#h+x#h#i,b#l#m&S#m#n-a%&x%&y-g~!`OX~~!cP#T#U!f~!kOU~~!nR#`#a!w#d#e#l#g#h#r~!zP#c#d!}~#QP#^#_#T~#WP#i#j#Z~#^P#f#g#a~#dP#X#Y#g~#lOT~~#oP#d#e#g~#uQ#[#]#{#g#h#g~$OP#T#U$R~$UP#f#g#l~$[P#]#^$_~$bP#Y#Z$e~$hP#Y#Z#g~$nP#f#g$q~$tP#`#a$w~$zP#T#U$}~%QP#b#c%T~%WP#Z#[#g~%^Q#c#d$q#f#g%d~%gP#c#d%j~%mP#c#d%p~%sP#j#k%v~%yP#m#n#g~&PP#h#i&S~&VP#a#b&Y~&]P#`#a#g~&cQ#T#U&i#g#h'm~&lP#j#k&o~&rP#T#U&u~&zPT~#g#h&}~'QP#V#W'T~'WP#f#g'Z~'^P#]#^'a~'dP#d#e'g~'jP#h#i#g~'pQ#c#d'v#l#m#g~'yP#b#c#g~(PP#c#d(S~(VP#h#i(Y~(]P#`#a(`~(cP#]#^'v~(iP#X#Y(l~(oP#n#o(r~(uP#X#Y(x~({P#f#g#g~)RP#T#U)U~)XQ#f#g)_#h#i)w~)bP#_#`)e~)hP#W#X)k~)nP#c#d)q~)tP#k#l'v~)zP#[#]#g~*QR#[#]#l#c#d*Z#m#n+V~*^P#k#l*a~*dP#X#Y*g~*jP#f#g*m~*pP#g#h*s~*vP#[#]*y~*|P#X#Y+P~+SP#`#a&Y~+YP#h#i+]~+`P#[#]+c~+fP#c#d'v~+lP#i#j+o~+rQ#U#V%v#g#h'g~+{R#[#]*y#e#f&Y#k#l,U~,XP#]#^,[~,_P#Y#Z'g~,eS#X#Y,q#c#d&S#g#h,w#m#n,}~,tP#l#m'g~,zP#l#m#g~-QP#d#e-T~-WP#X#Y-Z~-^P#g#h&}~-dP#T#U&S~-jP%&x%&y-m~-pP%&x%&y-s~-xOY~", + tokenData: ".R~RbYZ!Z}!O!`#V#W!k#W#X$X#X#Y$z#Z#[%j#[#]&]#^#_&o#_#`(V#`#a(o#a#b)X#d#e*W#f#g+r#g#h,R#h#i,k#l#m&c#m#n-j%&x%&y-p~!`OX~~!cP#T#U!f~!kOU~~!nR#`#a!w#d#e#l#g#h#r~!zP#c#d!}~#QP#^#_#T~#WP#i#j#Z~#^P#f#g#a~#dP#X#Y#g~#lOT~~#oP#d#e#g~#uQ#[#]#{#g#h#g~$OP#T#U$R~$UP#f#g#l~$[Q#T#U$b#]#^$n~$eP#f#g$h~$kP#h#i#g~$qP#Y#Z$t~$wP#Y#Z#g~$}P#f#g%Q~%TP#`#a%W~%ZP#T#U%^~%aP#b#c%d~%gP#Z#[#g~%mQ#c#d%Q#f#g%s~%vP#c#d%y~%|P#c#d&P~&SP#j#k&V~&YP#m#n#g~&`P#h#i&c~&fP#a#b&i~&lP#`#a#g~&rQ#T#U&x#g#h'v~&{P#j#k'O~'RP#T#U'U~'ZPT~#g#h'^~'aP#V#W'd~'gP#f#g'j~'mP#]#^'p~'sP#d#e$h~'yQ#c#d(P#l#m#g~(SP#b#c#g~(YP#c#d(]~(`P#h#i(c~(fP#`#a(i~(lP#]#^(P~(rP#X#Y(u~(xP#n#o({~)OP#X#Y)R~)UP#f#g#g~)[P#T#U)_~)bQ#f#g)h#h#i*Q~)kP#_#`)n~)qP#W#X)t~)wP#c#d)z~)}P#k#l(P~*TP#[#]#g~*ZR#[#]#l#c#d*d#m#n+`~*gP#k#l*j~*mP#X#Y*p~*sP#f#g*v~*yP#g#h*|~+PP#[#]+S~+VP#X#Y+Y~+]P#`#a&i~+cP#h#i+f~+iP#[#]+l~+oP#c#d(P~+uP#i#j+x~+{Q#U#V&V#g#h$h~,UR#[#]+S#e#f&i#k#l,_~,bP#]#^,e~,hP#Y#Z$h~,nS#X#Y,z#c#d&c#g#h-Q#m#n-W~,}P#l#m$h~-TP#l#m#g~-ZP#d#e-^~-aP#X#Y-d~-gP#g#h'^~-mP#T#U&c~-sP%&x%&y-v~-yP%&x%&y-|~.ROY~", tokenizers: [0, noteContent], topRules: {"Document":[0,2]}, tokenPrec: 0 diff --git a/src/editor/languages.js b/src/editor/languages.js index a7d85ea..605c630 100644 --- a/src/editor/languages.js +++ b/src/editor/languages.js @@ -22,7 +22,7 @@ import { clojure } from "@codemirror/legacy-modes/mode/clojure" import { erlang } from "@codemirror/legacy-modes/mode/erlang" import { toml } from "@codemirror/legacy-modes/mode/toml" import { swift } from "@codemirror/legacy-modes/mode/swift" -import { kotlin } from "@codemirror/legacy-modes/mode/clike" +import { kotlin, dart } from "@codemirror/legacy-modes/mode/clike" import { groovy } from "@codemirror/legacy-modes/mode/groovy" import { diff } from "@codemirror/legacy-modes/mode/diff"; import { powerShell } from "@codemirror/legacy-modes/mode/powershell"; @@ -253,6 +253,12 @@ export const LANGUAGES = [ parser: StreamLanguage.define(powerShell).parser, guesslang: "ps1", }), + new Language({ + token: "dart", + name: "Dart", + parser: StreamLanguage.define(dart).parser, + guesslang: "dart", + }), ] From 387c842d631f1de3d83a9bc2b9b91b89124ae21b Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 30 Jun 2024 14:17:14 +0200 Subject: [PATCH 04/26] Upgrade to latest version of Electron --- package-lock.json | 19 +++++-------------- package.json | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ed82f3..552da9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "@types/node": "^20.10.5", "@vitejs/plugin-vue": "^4.0.0", "debounce": "^1.2.1", - "electron": "^28.0.0", + "electron": "^31.1.0", "electron-builder": "^23.6.0", "electron-builder-notarize": "^1.5.1", "electron-store": "^8.1.0", @@ -3078,14 +3078,14 @@ } }, "node_modules/electron": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-28.0.0.tgz", - "integrity": "sha512-eDhnCFBvG0PGFVEpNIEdBvyuGUBsFdlokd+CtuCe2ER3P+17qxaRfWRxMmksCOKgDHb5Wif5UxqOkZSlA4snlw==", + "version": "31.1.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-31.1.0.tgz", + "integrity": "sha512-TBOwqLxSxnx6+pH6GMri7R3JPH2AkuGJHfWZS0p1HsmN+Qr1T9b0IRJnnehSd/3NZAmAre4ft9Ljec7zjyKFJA==", "dev": true, "hasInstallScript": true, "dependencies": { "@electron/get": "^2.0.0", - "@types/node": "^18.11.18", + "@types/node": "^20.9.0", "extract-zip": "^2.0.1" }, "bin": { @@ -3474,15 +3474,6 @@ "node": ">= 10.0.0" } }, - "node_modules/electron/node_modules/@types/node": { - "version": "18.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", - "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", diff --git a/package.json b/package.json index 2730a80..cc1a611 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@types/node": "^20.10.5", "@vitejs/plugin-vue": "^4.0.0", "debounce": "^1.2.1", - "electron": "^28.0.0", + "electron": "^31.1.0", "electron-builder": "^23.6.0", "electron-builder-notarize": "^1.5.1", "electron-store": "^8.1.0", From 11df8ea86463d8952d356d86d7a39fcc651fb4cf Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 30 Jun 2024 14:18:44 +0200 Subject: [PATCH 05/26] Bump version to 1.7.1-beta --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 552da9e..9135ee8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Heynote", - "version": "1.7.0", + "version": "1.7.1-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Heynote", - "version": "1.7.0", + "version": "1.7.1-beta", "license": "Commons Clause MIT", "dependencies": { "electron-log": "^5.0.1" diff --git a/package.json b/package.json index cc1a611..ab7e9d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Heynote", - "version": "1.7.0", + "version": "1.7.1-beta", "main": "dist-electron/main/index.js", "description": "A dedicated scratch pad", "author": "Jonatan Heyman (https://heyman.info)", From 48a29c75524723fcdd1c72263efed5ce57605399 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Tue, 2 Jul 2024 19:00:34 +0200 Subject: [PATCH 06/26] Bump version to 1.7.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9135ee8..d3a68a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Heynote", - "version": "1.7.1-beta", + "version": "1.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Heynote", - "version": "1.7.1-beta", + "version": "1.7.1", "license": "Commons Clause MIT", "dependencies": { "electron-log": "^5.0.1" diff --git a/package.json b/package.json index ab7e9d6..65577ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Heynote", - "version": "1.7.1-beta", + "version": "1.7.1", "main": "dist-electron/main/index.js", "description": "A dedicated scratch pad", "author": "Jonatan Heyman (https://heyman.info)", From 29d4eb26cc974b88831404872722ede765bc4e18 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 7 Jul 2024 15:50:57 +0200 Subject: [PATCH 07/26] Optimize block parsing when syntax tree isn't available. If the syntax tree isn't available, use String.indexOf to parse the blocks. --- src/editor/block/block.js | 92 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/src/editor/block/block.js b/src/editor/block/block.js index bb86ecb..623c16e 100644 --- a/src/editor/block/block.js +++ b/src/editor/block/block.js @@ -1,7 +1,7 @@ import { ViewPlugin, EditorView, Decoration, WidgetType, lineNumbers } from "@codemirror/view" import { layer, RectangleMarker } from "@codemirror/view" import { EditorState, RangeSetBuilder, StateField, Facet , StateEffect, RangeSet} from "@codemirror/state"; -import { syntaxTree, ensureSyntaxTree } from "@codemirror/language" +import { syntaxTree, ensureSyntaxTree, syntaxTreeAvailable } from "@codemirror/language" import { Note, Document, NoteDelimiter } from "../lang-heynote/parser.terms.js" import { IterMode } from "@lezer/common"; import { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js"; @@ -10,12 +10,28 @@ import { mathBlock } from "./math.js" import { emptyBlockSelected } from "./select-all.js"; +function startTimer() { + const timeStart = performance.now(); + return function () { + return Math.round(performance.now() - timeStart); + }; +} + + // tracks the size of the first delimiter let firstBlockDelimiterSize -function getBlocks(state, timeout=50) { +/** + * Return a list of blocks in the document from the syntax tree. + * syntaxTreeAvailable() should have been called before this function to ensure the syntax tree is available. + * @param {*} state + * @param {*} timeout + * @returns + */ +function getBlocksFromSyntaxTree(state, timeout=50) { + //const timer = startTimer() const blocks = []; - const tree = ensureSyntaxTree(state, state.doc.length, timeout) + const tree = syntaxTree(state, state.doc.length, timeout) if (tree) { tree.iterate({ enter: (type) => { @@ -52,9 +68,79 @@ function getBlocks(state, timeout=50) { }); firstBlockDelimiterSize = blocks[0]?.delimiter.to } + //console.log("getBlocksSyntaxTree took", timer(), "ms") return blocks } +/** + * Get the blocks for the document state. + * If the syntax tree is available, we'll extract the blocks from that. Otherwise + * the blocks are parsed from the string contents of the document, which is much faster + * than waiting for the tree parsing to finnish. + */ +function getBlocks(state) { + if (syntaxTreeAvailable(state, state.doc.length)) { + return getBlocksFromSyntaxTree(state) + } + //const timer = startTimer() + const blocks = [] + const doc = state.doc + if (doc.length === 0) { + return []; + } + const content = doc.sliceString(0, doc.length) + const delim = "\n∞∞∞" + let pos = 0 + while (pos < doc.length) { + const blockStart = content.indexOf(delim, pos); + if (blockStart != pos) { + console.error("Error parsing blocks, expected delimiter at", pos) + break; + } + const langStart = blockStart + delim.length; + const delimiterEnd = content.indexOf("\n", langStart) + if (delimiterEnd < 0) { + console.error("Error parsing blocks. Delimiter didn't end with newline") + break + } + const langFull = content.substring(langStart, delimiterEnd); + let auto = false; + let lang = langFull; + if (langFull.endsWith("-a")) { + auto = true; + lang = langFull.substring(0, langFull.length - 2); + } + const contentFrom = delimiterEnd + 1; + let blockEnd = content.indexOf(delim, contentFrom); + if (blockEnd < 0) { + blockEnd = doc.length; + } + + const block = { + language: { + name: lang, + auto: auto, + }, + content: { + from: contentFrom, + to: blockEnd, + }, + delimiter: { + from: blockStart, + to: delimiterEnd + 1, + }, + range: { + from: blockStart, + to: blockEnd, + }, + }; + blocks.push(block); + pos = blockEnd; + } + //console.log("getBlocks (string parsing) took", timer(), "ms") + return blocks; +} + export const blockState = StateField.define({ create(state) { return getBlocks(state, 1000); From c3892163afeaf69275f7223ba149384b58f2e24f Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 7 Jul 2024 16:04:54 +0200 Subject: [PATCH 08/26] Remove timeout parameter for getBlocksFromSyntaxTree() since we now expect the syntax tree to already be available. --- src/editor/block/block.js | 133 ++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/src/editor/block/block.js b/src/editor/block/block.js index 623c16e..c93d98f 100644 --- a/src/editor/block/block.js +++ b/src/editor/block/block.js @@ -24,14 +24,11 @@ let firstBlockDelimiterSize /** * Return a list of blocks in the document from the syntax tree. * syntaxTreeAvailable() should have been called before this function to ensure the syntax tree is available. - * @param {*} state - * @param {*} timeout - * @returns */ -function getBlocksFromSyntaxTree(state, timeout=50) { +function getBlocksFromSyntaxTree(state) { //const timer = startTimer() const blocks = []; - const tree = syntaxTree(state, state.doc.length, timeout) + const tree = syntaxTree(state, state.doc.length) if (tree) { tree.iterate({ enter: (type) => { @@ -73,7 +70,70 @@ function getBlocksFromSyntaxTree(state, timeout=50) { } /** - * Get the blocks for the document state. + * Parse blocks from document's string contents using String.indexOf() + */ +function getBlocksFromString(state) { + //const timer = startTimer() + const blocks = [] + const doc = state.doc + if (doc.length === 0) { + return []; + } + const content = doc.sliceString(0, doc.length) + const delim = "\n∞∞∞" + let pos = 0 + while (pos < doc.length) { + const blockStart = content.indexOf(delim, pos); + if (blockStart != pos) { + console.error("Error parsing blocks, expected delimiter at", pos) + break; + } + const langStart = blockStart + delim.length; + const delimiterEnd = content.indexOf("\n", langStart) + if (delimiterEnd < 0) { + console.error("Error parsing blocks. Delimiter didn't end with newline") + break + } + const langFull = content.substring(langStart, delimiterEnd); + let auto = false; + let lang = langFull; + if (langFull.endsWith("-a")) { + auto = true; + lang = langFull.substring(0, langFull.length - 2); + } + const contentFrom = delimiterEnd + 1; + let blockEnd = content.indexOf(delim, contentFrom); + if (blockEnd < 0) { + blockEnd = doc.length; + } + + const block = { + language: { + name: lang, + auto: auto, + }, + content: { + from: contentFrom, + to: blockEnd, + }, + delimiter: { + from: blockStart, + to: delimiterEnd + 1, + }, + range: { + from: blockStart, + to: blockEnd, + }, + }; + blocks.push(block); + pos = blockEnd; + } + //console.log("getBlocksFromString() took", timer(), "ms") + return blocks; +} + +/** + * Get the blocks from the document state. * If the syntax tree is available, we'll extract the blocks from that. Otherwise * the blocks are parsed from the string contents of the document, which is much faster * than waiting for the tree parsing to finnish. @@ -81,69 +141,14 @@ function getBlocksFromSyntaxTree(state, timeout=50) { function getBlocks(state) { if (syntaxTreeAvailable(state, state.doc.length)) { return getBlocksFromSyntaxTree(state) + } else { + return getBlocksFromString(state) } - //const timer = startTimer() - const blocks = [] - const doc = state.doc - if (doc.length === 0) { - return []; - } - const content = doc.sliceString(0, doc.length) - const delim = "\n∞∞∞" - let pos = 0 - while (pos < doc.length) { - const blockStart = content.indexOf(delim, pos); - if (blockStart != pos) { - console.error("Error parsing blocks, expected delimiter at", pos) - break; - } - const langStart = blockStart + delim.length; - const delimiterEnd = content.indexOf("\n", langStart) - if (delimiterEnd < 0) { - console.error("Error parsing blocks. Delimiter didn't end with newline") - break - } - const langFull = content.substring(langStart, delimiterEnd); - let auto = false; - let lang = langFull; - if (langFull.endsWith("-a")) { - auto = true; - lang = langFull.substring(0, langFull.length - 2); - } - const contentFrom = delimiterEnd + 1; - let blockEnd = content.indexOf(delim, contentFrom); - if (blockEnd < 0) { - blockEnd = doc.length; - } - - const block = { - language: { - name: lang, - auto: auto, - }, - content: { - from: contentFrom, - to: blockEnd, - }, - delimiter: { - from: blockStart, - to: delimiterEnd + 1, - }, - range: { - from: blockStart, - to: blockEnd, - }, - }; - blocks.push(block); - pos = blockEnd; - } - //console.log("getBlocks (string parsing) took", timer(), "ms") - return blocks; } export const blockState = StateField.define({ create(state) { - return getBlocks(state, 1000); + return getBlocks(state); }, update(blocks, transaction) { // if blocks are empty it likely means we didn't get a parsed syntax tree, and then we want to update From 9bcf03d00c791602e3b86c5dbb4e298e8a3773b3 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 7 Jul 2024 19:29:17 +0200 Subject: [PATCH 09/26] Typo --- src/editor/block/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/block/block.js b/src/editor/block/block.js index c93d98f..2afd1cb 100644 --- a/src/editor/block/block.js +++ b/src/editor/block/block.js @@ -136,7 +136,7 @@ function getBlocksFromString(state) { * Get the blocks from the document state. * If the syntax tree is available, we'll extract the blocks from that. Otherwise * the blocks are parsed from the string contents of the document, which is much faster - * than waiting for the tree parsing to finnish. + * than waiting for the tree parsing to finish. */ function getBlocks(state) { if (syntaxTreeAvailable(state, state.doc.length)) { From a5252e12c48953233b5da22dc6d53c451c2e2215 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 7 Jul 2024 21:58:43 +0200 Subject: [PATCH 10/26] Update prettier to latest version --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d3a68a0..c42ab1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "electron-store": "^8.1.0", "electron-updater": "^6.1.7", "fs-jetpack": "^5.1.0", - "prettier": "^3.1.1", + "prettier": "^3.3.2", "rollup-plugin-license": "^3.0.1", "sass": "^1.57.1", "typescript": "^4.9.4", @@ -4996,9 +4996,9 @@ } }, "node_modules/prettier": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", - "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" diff --git a/package.json b/package.json index 65577ea..e4eef4e 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "electron-store": "^8.1.0", "electron-updater": "^6.1.7", "fs-jetpack": "^5.1.0", - "prettier": "^3.1.1", + "prettier": "^3.3.2", "rollup-plugin-license": "^3.0.1", "sass": "^1.57.1", "typescript": "^4.9.4", From 016422e7db8cea26d6c1980d4a352224237e9528 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 7 Jul 2024 21:59:47 +0200 Subject: [PATCH 11/26] Update imports so that that they also work in playwright tests --- src/editor/languages.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/editor/languages.js b/src/editor/languages.js index a7d85ea..804e62f 100644 --- a/src/editor/languages.js +++ b/src/editor/languages.js @@ -27,13 +27,13 @@ import { groovy } from "@codemirror/legacy-modes/mode/groovy" import { diff } from "@codemirror/legacy-modes/mode/diff"; import { powerShell } from "@codemirror/legacy-modes/mode/powershell"; -import typescriptPlugin from "prettier/plugins/typescript.mjs" -import babelPrettierPlugin from "prettier/plugins/babel.mjs" -import htmlPrettierPlugin from "prettier/esm/parser-html.mjs" -import cssPrettierPlugin from "prettier/esm/parser-postcss.mjs" -import markdownPrettierPlugin from "prettier/esm/parser-markdown.mjs" -import yamlPrettierPlugin from "prettier/plugins/yaml.mjs" -import * as prettierPluginEstree from "prettier/plugins/estree.mjs"; +import typescriptPlugin from "prettier/plugins/typescript" +import babelPrettierPlugin from "prettier/plugins/babel" +import htmlPrettierPlugin from "prettier/plugins/html" +import cssPrettierPlugin from "prettier/plugins/postcss" +import markdownPrettierPlugin from "prettier/plugins/markdown" +import yamlPrettierPlugin from "prettier/plugins/yaml" +import * as prettierPluginEstree from "prettier/plugins/estree"; class Language { From bc3a9b66a19141258a60fed00eb60e9428952bb9 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Sun, 7 Jul 2024 22:01:19 +0200 Subject: [PATCH 12/26] Add test that ensures that getBlocksFromSyntaxTree() and getBlocksFromString() functions produces the same results --- src/editor/block/block.js | 6 +++--- tests/block-parsing.spec.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tests/block-parsing.spec.js diff --git a/src/editor/block/block.js b/src/editor/block/block.js index 2afd1cb..57e2bb1 100644 --- a/src/editor/block/block.js +++ b/src/editor/block/block.js @@ -25,7 +25,7 @@ let firstBlockDelimiterSize * Return a list of blocks in the document from the syntax tree. * syntaxTreeAvailable() should have been called before this function to ensure the syntax tree is available. */ -function getBlocksFromSyntaxTree(state) { +export function getBlocksFromSyntaxTree(state) { //const timer = startTimer() const blocks = []; const tree = syntaxTree(state, state.doc.length) @@ -72,7 +72,7 @@ function getBlocksFromSyntaxTree(state) { /** * Parse blocks from document's string contents using String.indexOf() */ -function getBlocksFromString(state) { +export function getBlocksFromString(state) { //const timer = startTimer() const blocks = [] const doc = state.doc @@ -138,7 +138,7 @@ function getBlocksFromString(state) { * the blocks are parsed from the string contents of the document, which is much faster * than waiting for the tree parsing to finish. */ -function getBlocks(state) { +export function getBlocks(state) { if (syntaxTreeAvailable(state, state.doc.length)) { return getBlocksFromSyntaxTree(state) } else { diff --git a/tests/block-parsing.spec.js b/tests/block-parsing.spec.js new file mode 100644 index 0000000..ee55478 --- /dev/null +++ b/tests/block-parsing.spec.js @@ -0,0 +1,28 @@ +import { expect, test } from "@playwright/test" +import { EditorState } from "@codemirror/state" + +import { heynoteLang } from "../src/editor/lang-heynote/heynote.js" +import { getBlocksFromSyntaxTree, getBlocksFromString } from "../src/editor/block/block.js" + +test("parse blocks from both syntax tree and string contents", async ({page}) => { + const contents = ` +∞∞∞text +Text Block A +∞∞∞text-a +Text Block B +∞∞∞json-a +{ +"key": "value" +} +∞∞∞python +print("Hello, World!") +` + const state = EditorState.create({ + doc: contents, + extensions: heynoteLang(), + }) + const treeBlocks = getBlocksFromSyntaxTree(state) + const stringBlocks = getBlocksFromString(state) + + expect(treeBlocks).toEqual(stringBlocks) +}) From 478b78780dde1aeadb6888fd77e79f2563ba4999 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 8 Jul 2024 12:07:27 +0200 Subject: [PATCH 13/26] Add documentation, and update code that injects key bindings to also inject it into the docs --- README.md | 2 ++ docs/index.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ vite.config.mjs | 7 +++- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 docs/index.md diff --git a/README.md b/README.md index 50569f2..c7a28b9 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,8 @@ I can totally see the usefulness of such a feature, and it's definitely somethin ### What are the default keyboard shortcuts? + + **On Mac** ``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..ab7990d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,89 @@ +# Heynote Documentation + +Heynote is a dedicated scratchpad for developers. It functions as a large persistent text buffer where you can write down anything you like. Works great for that Slack message you don't want to accidentally send, a JSON response from an API you're working with, notes from a meeting, your daily to-do list, etc. + +The Heynote buffer is divided into blocks, and each block can have its own Language set (e.g. JavaScript, JSON, Markdown, etc.). This gives you syntax highlighting and lets you auto-format that JSON response. + +## Default Key Bindings + + + +**On Mac** + +``` +⌘ + Enter Add new block below the current block +⌥ + Enter Add new block before the current block +⌘ + Shift + Enter Add new block at the end of the buffer +⌥ + Shift + Enter Add new block at the start of the buffer +⌘ + ⌥ + Enter Split the current block at cursor position +⌘ + L Change block language +⌘ + Down Goto next block +⌘ + Up Goto previous block +⌘ + A Select all text in a note block. Press again to select the whole buffer +⌘ + ⌥ + Up/Down Add additional cursor above/below +⌥ + Shift + F Format block content (works for JSON, JavaScript, HTML, CSS and Markdown) +``` + +**On Windows and Linux** + +``` +Ctrl + Enter Add new block below the current block +Alt + Enter Add new block before the current block +Ctrl + Shift + Enter Add new block at the end of the buffer +Alt + Shift + Enter Add new block at the start of the buffer +Ctrl + Alt + Enter Split the current block at cursor position +Ctrl + L Change block language +Ctrl + Down Goto next block +Ctrl + Up Goto previous block +Ctrl + A Select all text in a note block. Press again to select the whole buffer +Ctrl + Alt + Up/Down Add additional cursor above/below +Alt + Shift + F Format block content (works for JSON, JavaScript, HTML, CSS and Markdown) +Alt Show menu +``` + +## Download/Installation + +Download the appropriate (Mac, Windows or Linux) version from [heynote.com](https://heynote.com). The Windows build is not signed, so you might see some scary warning (I can not justify paying a yearly fee for a certificate just to get rid of that). + +### Notes on Linux installation + +It's been reported [(#48)](https://github.com/heyman/heynote/issues/48) that ChromeOS's Debian VM need the following packages installed to run the Heynote AppImage: + +``` +libfuse2 +libnss3 +libnspr4 +``` + +## Math Blocks + +Heynote's Math blocks are powered by [Math.js expressions](https://mathjs.org/docs/expressions). Checkout their [documentation](https://mathjs.org/docs/) to see what [syntax](https://mathjs.org/docs/expressions/syntax.html), [functions](https://mathjs.org/docs/reference/functions.html), and [constants](https://mathjs.org/docs/reference/constants.html) are available. + +### Accessing the previous result + +The variable `prev` can be used to access the previous result. For example: + +``` +128 +prev * 2 # 256 +``` + +### Changing how the results of Math blocks are formatted + +You can define a custom `format` function within the Math block like this: + +``` +_format = format # store reference to the built in format +format(x) = _format(x, {notation:"exponential"}) +``` + +See the [Math.js format()](https://mathjs.org/docs/reference/functions/format.html) function for more info on what's supported. + +## The buffer file + +The default paths for the buffer data for the respective operating systems are: + +- Mac: `~/Library/Application Support/Heynote/buffer.txt` +- Windows: `%APPDATA%\Heynote\buffer.txt` +- Linux: `~/.config/Heynote/buffer.txt` + diff --git a/vite.config.mjs b/vite.config.mjs index a359119..3e2ccef 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -20,7 +20,7 @@ const isProduction = process.env.NODE_ENV === "production" const updateReadmeKeybinds = async () => { const readmePath = path.resolve(__dirname, 'README.md') let readme = fs.readFileSync(readmePath, 'utf-8') - const keybindsRegex = /^(### What are the default keyboard shortcuts\?\s*).*?^(```\s+#)/gms + const keybindsRegex = /^(\s*).*?^(```\s+#)/gms const shortcuts = `$1**On Mac** \`\`\` @@ -34,6 +34,11 @@ ${keyHelpStr('win32')} $2` readme = readme.replace(keybindsRegex, shortcuts) fs.writeFileSync(readmePath, readme) + + const docsPath = path.resolve(__dirname, 'docs', 'index.md') + let docs = fs.readFileSync(docsPath, 'utf-8') + docs = docs.replace(keybindsRegex, shortcuts) + fs.writeFileSync(docsPath, docs) } const updateGuesslangLanguagesInWebWorker = async () => { From 4890cd6a6bcc35e9adc592a8f46b3fc5e164ad7d Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 8 Jul 2024 14:14:21 +0200 Subject: [PATCH 14/26] Add menu item to Help menu that opens documentation page --- electron/main/menu.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/electron/main/menu.ts b/electron/main/menu.ts index 39f942c..9e4a2a4 100644 --- a/electron/main/menu.ts +++ b/electron/main/menu.ts @@ -131,7 +131,14 @@ const template = [ role: 'help', submenu: [ { - label: 'Learn More', + label: 'Documentation', + click: async () => { + const { shell } = require('electron') + await shell.openExternal('https://heynote.com/docs/') + } + }, + { + label: 'Website', click: async () => { const { shell } = require('electron') await shell.openExternal('https://heynote.com') From d6420e65e89669058eca3ea2e022a0643dbfbf73 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 8 Jul 2024 14:48:45 +0200 Subject: [PATCH 15/26] Add links to documentation in Readme --- README.md | 81 +++---------------------------------------------- vite.config.mjs | 9 ++---- 2 files changed, 6 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index c7a28b9..4b1b0b0 100644 --- a/README.md +++ b/README.md @@ -31,19 +31,9 @@ Available for Mac, Windows, and Linux. - Default or Emacs-like key bindings -## Installation +## Documentation -Download the appropriate (Mac, Windows or Linux) version from the latest Github release (or from [heynote.com](https://heynote.com)). The Windows build is not signed, so you might see some scary warning (I can not justify paying a yearly fee for a certificate just to get rid of that). - -### Notes on Linux installation - -It's been reported [(#48)](https://github.com/heyman/heynote/issues/48) that ChromeOS's Debian VM need the following packages installed to run the Heynote AppImage: - -``` -libfuse2 -libnss3 -libnspr4 -``` +[Documentation](https://heynote.com/docs/) is available on the Heynote website. ## Development @@ -73,42 +63,12 @@ To run the tests in the Playwright UI: I'm happy to merge contributions that fit my vision for the app. Bug fixes are always welcome. -## Math Blocks - -Heynote's Math blocks are powered by [Math.js expressions](https://mathjs.org/docs/expressions). Checkout their [documentation](https://mathjs.org/docs/) to see what [syntax](https://mathjs.org/docs/expressions/syntax.html), [functions](https://mathjs.org/docs/reference/functions.html), and [constants](https://mathjs.org/docs/reference/constants.html) are available. - -### Accessing the previous result - -The variable `prev` can be used to access the previous result. For example: - -``` -128 -prev * 2 # 256 -``` - -### Changing how the results of Math blocks are formatted? - -You can define a custom `format` function within the Math block like this: - -``` -_format = format # store reference to the built in format -format(x) = _format(x, {notation:"exponential"}) -``` - -See the [Math.js format()](https://mathjs.org/docs/reference/functions/format.html) function for more info on what's supported. - ## FAQ ### Where is the buffer data stored? -The default paths for the buffer data for the respective OS are: - -- Mac: `~/Library/Application Support/Heynote/buffer.txt` -- Windows: `%APPDATA%\Heynote\buffer.txt` -- Linux: `~/.config/Heynote/buffer.txt` - -From version >=1.5.0, symlinks will be supported and you'll be able to configure the path where `buffer.txt` is stored. +See the [documentation](https://heynote.com/docs/#user-content-the-buffer-file). ### Can you make a mobile app? @@ -122,40 +82,7 @@ I can totally see the usefulness of such a feature, and it's definitely somethin ### What are the default keyboard shortcuts? - - -**On Mac** - -``` -⌘ + Enter Add new block below the current block -⌥ + Enter Add new block before the current block -⌘ + Shift + Enter Add new block at the end of the buffer -⌥ + Shift + Enter Add new block at the start of the buffer -⌘ + ⌥ + Enter Split the current block at cursor position -⌘ + L Change block language -⌘ + Down Goto next block -⌘ + Up Goto previous block -⌘ + A Select all text in a note block. Press again to select the whole buffer -⌘ + ⌥ + Up/Down Add additional cursor above/below -⌥ + Shift + F Format block content (works for JSON, JavaScript, HTML, CSS and Markdown) -``` - -**On Windows and Linux** - -``` -Ctrl + Enter Add new block below the current block -Alt + Enter Add new block before the current block -Ctrl + Shift + Enter Add new block at the end of the buffer -Alt + Shift + Enter Add new block at the start of the buffer -Ctrl + Alt + Enter Split the current block at cursor position -Ctrl + L Change block language -Ctrl + Down Goto next block -Ctrl + Up Goto previous block -Ctrl + A Select all text in a note block. Press again to select the whole buffer -Ctrl + Alt + Up/Down Add additional cursor above/below -Alt + Shift + F Format block content (works for JSON, JavaScript, HTML, CSS and Markdown) -Alt Show menu -``` +See the [documentation](https://heynote.com/docs/#user-content-default-key-bindings). ## Thanks! diff --git a/vite.config.mjs b/vite.config.mjs index 3e2ccef..084827c 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -17,9 +17,7 @@ rmSync('dist-electron', { recursive: true, force: true }) const isDevelopment = process.env.NODE_ENV === "development" || !!process.env.VSCODE_DEBUG const isProduction = process.env.NODE_ENV === "production" -const updateReadmeKeybinds = async () => { - const readmePath = path.resolve(__dirname, 'README.md') - let readme = fs.readFileSync(readmePath, 'utf-8') +const injectKeybindsInDocs = async () => { const keybindsRegex = /^(\s*).*?^(```\s+#)/gms const shortcuts = `$1**On Mac** @@ -32,9 +30,6 @@ ${keyHelpStr('darwin')} \`\`\` ${keyHelpStr('win32')} $2` - readme = readme.replace(keybindsRegex, shortcuts) - fs.writeFileSync(readmePath, readme) - const docsPath = path.resolve(__dirname, 'docs', 'index.md') let docs = fs.readFileSync(docsPath, 'utf-8') docs = docs.replace(keybindsRegex, shortcuts) @@ -61,7 +56,7 @@ export default defineConfig({ plugins: [ vue(), - updateReadmeKeybinds(), + injectKeybindsInDocs(), updateGuesslangLanguagesInWebWorker(), electron([ { From 417394f0593c2162ad8cefee319de80bbaef2b52 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 8 Jul 2024 14:52:00 +0200 Subject: [PATCH 16/26] Add link to documentation to the top of the Readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b1b0b0..d946672 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,10 @@ -**Website:** [heynote.com](https://heynote.com) +## General Information + +- Website: [heynote.com](https://heynote.com) +- Documentation: [heynote.com](https://heynote.com/docs/) Heynote is a dedicated scratchpad for developers. It functions as a large persistent text buffer where you can write down anything you like. Works great for that Slack message you don't want to accidentally send, a JSON response from an API you're working with, notes from a meeting, your daily to-do list, etc. From a6746167d624e0785efd121f1b58f195f0f70855 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 8 Jul 2024 14:59:10 +0200 Subject: [PATCH 17/26] Bump version to 1.8.0-beta --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c42ab1e..2e492ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Heynote", - "version": "1.7.1", + "version": "1.8.0-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Heynote", - "version": "1.7.1", + "version": "1.8.0-beta", "license": "Commons Clause MIT", "dependencies": { "electron-log": "^5.0.1" diff --git a/package.json b/package.json index e4eef4e..ab1662a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Heynote", - "version": "1.7.1", + "version": "1.8.0-beta", "main": "dist-electron/main/index.js", "description": "A dedicated scratch pad", "author": "Jonatan Heyman (https://heyman.info)", From e8971a6733678238b2ba29a407bd033e64c03248 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 8 Jul 2024 13:00:31 -0700 Subject: [PATCH 18/26] Add default redo cmd that works on all Platforms. Mod+Shift+Z --- src/editor/keymap.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/editor/keymap.js b/src/editor/keymap.js index 745aaf3..fff0dbc 100644 --- a/src/editor/keymap.js +++ b/src/editor/keymap.js @@ -1,7 +1,7 @@ import { keymap } from "@codemirror/view" //import { EditorSelection, EditorState } from "@codemirror/state" import { - indentLess, indentMore, + indentLess, indentMore, redo, } from "@codemirror/commands" import { @@ -61,6 +61,7 @@ export function heynoteKeymap(editor) { ["Mod-Alt-ArrowDown", newCursorBelow], ["Mod-Alt-ArrowUp", newCursorAbove], ["Mod-Shift-k", deleteLine], + ["Mod-Shift-z", redo], {key:"Mod-ArrowUp", run:gotoPreviousBlock, shift:selectPreviousBlock}, {key:"Mod-ArrowDown", run:gotoNextBlock, shift:selectNextBlock}, {key:"Ctrl-ArrowUp", run:gotoPreviousParagraph, shift:selectPreviousParagraph}, From f33be7f3a4b0415be87941cf8510a459ac387a94 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Thu, 11 Jul 2024 14:30:07 +0200 Subject: [PATCH 19/26] Fix bug causing editing to break when there are empty blocks of a language that uses a StreamParser --- src/editor/lang-heynote/nested-parser.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/editor/lang-heynote/nested-parser.js b/src/editor/lang-heynote/nested-parser.js index 4b5aa8e..3a1c338 100644 --- a/src/editor/lang-heynote/nested-parser.js +++ b/src/editor/lang-heynote/nested-parser.js @@ -22,7 +22,13 @@ export function configureNesting() { if (id == NoteContent) { let noteLang = node.node.parent.firstChild.getChildren(NoteLanguage)[0] let langName = input.read(noteLang?.from, noteLang?.to) - //console.log("langName:", langName) + + // if the NoteContent is empty, we don't want to return a parser, since that seems to cause an + // error for StreamLanguage parsers when the buffer size is large (e.g >300 kb) + if (node.node.from == node.node.to) { + return null + } + if (langName in languageMapping && languageMapping[langName] !== null) { //console.log("found parser for language:", langName) return { From 71f6a033cff4bfca522e41e661186213737edbdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:50:27 +0000 Subject: [PATCH 20/26] Bump braces from 3.0.2 to 3.0.3 Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e492ca..2f9f30c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2262,12 +2262,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3675,9 +3675,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" From e5d4d31ca2456d37fd46037515f4caa1c9c8e607 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:53:19 +0000 Subject: [PATCH 21/26] Bump ejs from 3.1.9 to 3.1.10 Bumps [ejs](https://github.com/mde/ejs) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/mde/ejs/releases) - [Commits](https://github.com/mde/ejs/compare/v3.1.9...v3.1.10) --- updated-dependencies: - dependency-name: ejs dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f9f30c..0e1b376 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3063,9 +3063,9 @@ "dev": true }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "dependencies": { "jake": "^10.8.5" From d82b3920d7678e837de9da10c9850c1fe39167e2 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Fri, 12 Jul 2024 14:33:26 +0200 Subject: [PATCH 22/26] Add setting for configuring the default block language and language auto detection --- electron/config.js | 2 ++ src/components/App.vue | 2 ++ src/components/Editor.vue | 11 ++++++- src/components/settings/Settings.vue | 35 +++++++++++++++++++++ src/editor/block/commands.js | 29 ++++++++++------- src/editor/editor.js | 11 +++++-- src/editor/keymap.js | 10 +++--- src/editor/language-detection/autodetect.js | 14 +++++---- 8 files changed, 89 insertions(+), 25 deletions(-) diff --git a/electron/config.js b/electron/config.js index 7c443ea..f3ecd97 100644 --- a/electron/config.js +++ b/electron/config.js @@ -35,6 +35,8 @@ const schema = { "showInMenu": {type: "boolean", default: false}, "alwaysOnTop": {type: "boolean", default: false}, "bracketClosing": {type: "boolean", default: false}, + "defaultBlockLanguage": {type: "string"}, + "defaultBlockLanguageAutoDetect": {type: "boolean"}, // when default font settings are used, fontFamily and fontSize is not specified in the // settings file, so that it's possible for us to change the default settings in the diff --git a/src/components/App.vue b/src/components/App.vue index 4f400bc..08234d5 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -122,6 +122,8 @@ :bracketClosing="settings.bracketClosing" :fontFamily="settings.fontFamily" :fontSize="settings.fontSize" + :defaultBlockLanguage="settings.defaultBlockLanguage || 'text'" + :defaultBlockLanguageAutoDetect="settings.defaultBlockLanguageAutoDetect === undefined ? true : settings.defaultBlockLanguageAutoDetect" class="editor" ref="editor" @openLanguageSelector="openLanguageSelector" diff --git a/src/components/Editor.vue b/src/components/Editor.vue index 7171a80..b3bc938 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -29,6 +29,8 @@ }, fontFamily: String, fontSize: Number, + defaultBlockLanguage: String, + defaultBlockLanguageAutoDetect: Boolean, }, components: {}, @@ -78,6 +80,7 @@ }) window._heynote_editor = this.editor window.document.addEventListener("currenciesLoaded", this.onCurrenciesLoaded) + this.editor.setDefaultBlockLanguage(this.defaultBlockLanguage, this.defaultBlockLanguageAutoDetect) // set up buffer change listener window.heynote.buffer.onChangeCallback((event, content) => { @@ -145,12 +148,18 @@ fontSize() { this.editor.setFont(this.fontFamily, this.fontSize) }, + defaultBlockLanguage() { + this.editor.setDefaultBlockLanguage(this.defaultBlockLanguage, this.defaultBlockLanguageAutoDetect) + }, + defaultBlockLanguageAutoDetect() { + this.editor.setDefaultBlockLanguage(this.defaultBlockLanguage, this.defaultBlockLanguageAutoDetect) + }, }, methods: { setLanguage(language) { if (language === "auto") { - this.editor.setCurrentLanguage("text", true) + this.editor.setCurrentLanguage(null, true) } else { this.editor.setCurrentLanguage(language, false) } diff --git a/src/components/settings/Settings.vue b/src/components/settings/Settings.vue index 42c9ee6..3a7a45b 100644 --- a/src/components/settings/Settings.vue +++ b/src/components/settings/Settings.vue @@ -1,10 +1,14 @@