Skip to content

Commit

Permalink
Merge branch 'main' into tanuj-22-feature-hideInDockOption
Browse files Browse the repository at this point in the history
  • Loading branch information
heyman committed Jan 1, 2024
2 parents 02de808 + 4274e62 commit a6c9536
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 24 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Available for Mac, Windows, and Linux.
- Block-based
- Syntax highlighting:

C++, C#, Clojure, CSS, Erlang, Go, HTML, Java, JavaScript, JSX, TypeScript, TOML, TSX, JSON, Lezer, Markdown, PHP, Python, Ruby, Rust, Shell, SQL, XML, YAML
C++, C#, Clojure, CSS, Erlang, Go, 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
Expand Down
61 changes: 60 additions & 1 deletion electron/main/buffer.js
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -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})
}
}
)
}
}
}
20 changes: 12 additions & 8 deletions electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { onBeforeInputEvent } from "../keymap"
import { isDev, isMac, isWindows } 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
Expand Down Expand Up @@ -251,20 +251,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) =>  {
Expand Down
4 changes: 4 additions & 0 deletions electron/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
2 changes: 2 additions & 0 deletions public/langdetect-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ GUESSLANG_LANGUAGES = [
"clj",
"erl",
"toml",
"swift",
"kt",
]

const guessLang = new self.GuessLang()
Expand Down
15 changes: 14 additions & 1 deletion src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
},
},
components: {},
data() {
return {
syntaxTreeDebugContent: null,
Expand All @@ -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,
Expand All @@ -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(() => {
Expand Down Expand Up @@ -142,7 +155,7 @@
</div>
</template>

<style lang="sass">
<style lang="sass" scoped>
.debug-syntax-tree
position: absolute
top: 0
Expand Down
35 changes: 27 additions & 8 deletions src/editor/block/math.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ class MathResult extends WidgetType {
eq(other) { return other.displayResult == this.displayResult }

toDOM() {
let wrap = document.createElement("span")
const wrap = document.createElement("span")
wrap.className = "heynote-math-result"
wrap.innerHTML = this.displayResult
wrap.addEventListener("click", (e) => {
const inner = document.createElement("span")
inner.className = "inner"
inner.innerHTML = this.displayResult
wrap.appendChild(inner)
inner.addEventListener("click", (e) => {
e.preventDefault()
navigator.clipboard.writeText(this.copyResult)
const copyElement = document.createElement("i")
Expand Down Expand Up @@ -64,18 +67,34 @@ function mathDeco(view) {

// if we got a result from math.js, add the result decoration
if (result !== undefined) {
builder.add(line.to, line.to, Decoration.widget({
widget: new MathResult(
let format = parser.get("format")

let resultWidget
if (typeof(result) === "string") {
resultWidget = new MathResult(result, result)
} else if (format !== undefined && typeof(format) === "function") {
try {
resultWidget = new MathResult(format(result), format(result))
} catch (e) {
// suppress any errors
}
}
if (resultWidget === undefined) {
resultWidget = new MathResult(
math.format(result, {
precision: 8,
upperExp: 8,
lowerExp: -6,
}),
math.format(result, {
notation: "fixed",
}),
), side: 1},
))
})
)
}
builder.add(line.to, line.to, Decoration.widget({
widget: resultWidget,
side: 1,
}))
}
}
pos = line.to + 1
Expand Down
9 changes: 9 additions & 0 deletions src/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/editor/lang-heynote/heynote.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
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" }
Auto { "-a" }
noteDelimiterEnter { "\n" }
//NoteContent { String }
Expand Down
2 changes: 1 addition & 1 deletion src/editor/lang-heynote/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const parser = LRParser.deserialize({
maxTerm: 10,
skippedNodes: [0],
repeatNodeCount: 1,
tokenData: "+_~R`YZ!T}!O!Y#V#W!e#X#Y$R#Z#[$q#[#]$w#^#_%Z#`#a&w#a#b'a#d#e(`#f#g({#g#h)b#h#i)w#l#m$}#m#n*v%&x%&y*|~!YOX~~!]P#T#U!`~!eOU~~!hR#`#a!q#d#e#f#g#h#l~!tP#c#d!w~!zP#^#_!}~#QP#i#j#T~#WP#f#g#Z~#^P#X#Y#a~#fOT~~#iP#d#e#a~#oQ#[#]#u#g#h#a~#xP#T#U#{~$OP#f#g#f~$UP#f#g$X~$[P#`#a$_~$bP#T#U$e~$hP#b#c$k~$nP#Z#[#a~$tP#c#d$X~$zP#h#i$}~%QP#a#b%T~%WP#`#a#a~%^Q#T#U%d#g#h&h~%gP#j#k%j~%mP#T#U%p~%uPT~#g#h%x~%{P#V#W&O~&RP#f#g&U~&XP#]#^&[~&_P#d#e&b~&eP#h#i#a~&kQ#c#d&q#l#m#a~&tP#b#c#a~&zP#X#Y&}~'QP#n#o'T~'WP#X#Y'Z~'^P#f#g#a~'dP#T#U'g~'jQ#f#g'p#h#i(Y~'sP#_#`'v~'yP#W#X'|~(PP#c#d(S~(VP#k#l&q~(]P#[#]#a~(cQ#[#]#f#m#n(i~(lP#h#i(o~(rP#[#](u~(xP#c#d&q~)OP#i#j)R~)UQ#U#V)[#g#h&b~)_P#m#n#a~)eQ#[#])k#e#f%T~)nP#X#Y)q~)tP#`#a%T~)zS#X#Y*W#c#d$}#g#h*^#m#n*d~*ZP#l#m&b~*aP#l#m#a~*gP#d#e*j~*mP#X#Y*p~*sP#g#h%x~*yP#T#U$}~+PP%&x%&y+S~+VP%&x%&y+Y~+_OY~",
tokenData: ",Z~RaYZ!W}!O!]#V#W!h#X#Y$U#Z#[$t#[#]$z#^#_%^#_#`&z#`#a'd#a#b'|#d#e({#f#g)h#g#h)}#h#i*s#l#m%Q#m#n+r%&x%&y+x~!]OX~~!`P#T#U!c~!hOU~~!kR#`#a!t#d#e#i#g#h#o~!wP#c#d!z~!}P#^#_#Q~#TP#i#j#W~#ZP#f#g#^~#aP#X#Y#d~#iOT~~#lP#d#e#d~#rQ#[#]#x#g#h#d~#{P#T#U$O~$RP#f#g#i~$XP#f#g$[~$_P#`#a$b~$eP#T#U$h~$kP#b#c$n~$qP#Z#[#d~$wP#c#d$[~$}P#h#i%Q~%TP#a#b%W~%ZP#`#a#d~%aQ#T#U%g#g#h&k~%jP#j#k%m~%pP#T#U%s~%xPT~#g#h%{~&OP#V#W&R~&UP#f#g&X~&[P#]#^&_~&bP#d#e&e~&hP#h#i#d~&nQ#c#d&t#l#m#d~&wP#b#c#d~&}P#c#d'Q~'TP#h#i'W~'ZP#`#a'^~'aP#]#^&t~'gP#X#Y'j~'mP#n#o'p~'sP#X#Y'v~'yP#f#g#d~(PP#T#U(S~(VQ#f#g(]#h#i(u~(`P#_#`(c~(fP#W#X(i~(lP#c#d(o~(rP#k#l&t~(xP#[#]#d~)OQ#[#]#i#m#n)U~)XP#h#i)[~)_P#[#])b~)eP#c#d&t~)kP#i#j)n~)qQ#U#V)w#g#h&e~)zP#m#n#d~*QR#[#]*Z#e#f%W#k#l*g~*^P#X#Y*a~*dP#`#a%W~*jP#]#^*m~*pP#Y#Z&e~*vS#X#Y+S#c#d%Q#g#h+Y#m#n+`~+VP#l#m&e~+]P#l#m#d~+cP#d#e+f~+iP#X#Y+l~+oP#g#h%{~+uP#T#U%Q~+{P%&x%&y,O~,RP%&x%&y,U~,ZOY~",
tokenizers: [0, noteContent],
topRules: {"Document":[0,2]},
tokenPrec: 0
Expand Down
14 changes: 14 additions & 0 deletions src/editor/languages.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { go } from "@codemirror/legacy-modes/mode/go"
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 typescriptPlugin from "prettier/plugins/typescript.mjs"
import babelPrettierPlugin from "prettier/plugins/babel.mjs"
Expand Down Expand Up @@ -218,6 +220,18 @@ export const LANGUAGES = [
guesslang: null,
prettier: {parser:"typescript", plugins: [typescriptPlugin, prettierPluginEstree]},
}),
new Language({
token: "swift",
name: "Swift",
parser: StreamLanguage.define(swift).parser,
guesslang: "swift",
}),
new Language({
token: "kotlin",
name: "Kotlin",
parser: StreamLanguage.define(kotlin).parser,
guesslang: "kt",
}),
]


Expand Down
6 changes: 4 additions & 2 deletions src/editor/theme/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,16 @@ export const heynoteBase = EditorView.theme({
height: '0px',
},
'.heynote-math-result': {
paddingLeft: "12px",
position: "relative",
},
'.heynote-math-result .inner': {
background: '#48b57e',
color: '#fff',
padding: '0px 4px',
borderRadius: '2px',
marginLeft: '12px',
boxShadow: '0 0 3px rgba(0,0,0, 0.1)',
cursor: 'pointer',
position: "relative",
whiteSpace: "nowrap",
},
'.heynote-math-result-copied': {
Expand Down
2 changes: 1 addition & 1 deletion src/editor/theme/dark.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const darkTheme = EditorView.theme({
background: "#213644",
borderTop: "1px solid #1e222a",
},
".heynote-math-result": {
".heynote-math-result .inner": {
background: "#0e1217",
color: "#a0e7c7",
boxShadow: '0 0 3px rgba(0,0,0, 0.3)',
Expand Down
36 changes: 36 additions & 0 deletions tests/math.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { test, expect } from "@playwright/test";
import { HeynotePage } from "./test-utils.js";

let heynotePage

test.beforeEach(async ({ page }) => {
console.log("beforeEach")
heynotePage = new HeynotePage(page)
await heynotePage.goto()
});

test("test math mode", async ({ page }) => {
await heynotePage.setContent(`
∞∞∞math
42*30+77
`)
await expect(page.locator("css=.heynote-math-result")).toHaveText("1337")
})

test("test math string result has no quotes", async ({ page }) => {
await heynotePage.setContent(`
∞∞∞math
format(1/3, 3)
`)
await expect(page.locator("css=.heynote-math-result")).toHaveText("0.333")
})

test("custom format function", async ({ page }) => {
await heynotePage.setContent(`
∞∞∞math
_format = format
format(x) = _format(x, {notation:"exponential"})
42
`)
await expect(page.locator("css=.heynote-math-result").last()).toHaveText("4.2e+1")
})
1 change: 1 addition & 0 deletions tests/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class HeynotePage {
}

async setContent(content) {
await expect(this.page.locator("css=.cm-editor")).toBeVisible()
await this.page.evaluate((content) => window._heynote_editor.setContent(content), content)
}

Expand Down
Loading

0 comments on commit a6c9536

Please sign in to comment.