From 0c567384ee9094702cfa2f2bddd4c442be0ca6c8 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Tue, 4 Jul 2023 14:01:59 +0200 Subject: [PATCH] Refresh Math blocks when new exchange rates are loaded --- README.md | 1 + electron/initial-content.ts | 7 +++++-- src/components/Editor.vue | 9 +++++++++ src/currency.js | 1 + src/editor/annotation.js | 1 + src/editor/block/commands.js | 11 ++++++++++- src/editor/block/math.js | 11 ++++++++++- src/editor/editor.js | 6 +++++- 8 files changed, 42 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1a7ae1e..602357b 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Available for Mac and Windows. Linux support coming soon (hopefully). - Language auto-detection - Auto-formatting - Math/Calculator mode +- Currency conversion - Multi-cursor editing - Dark & Light themes - Default or Emacs-like key bindings diff --git a/electron/initial-content.ts b/electron/initial-content.ts index fa866e8..5262fd5 100644 --- a/electron/initial-content.ts +++ b/electron/initial-content.ts @@ -22,11 +22,13 @@ radius = 5 volume = radius^2 * PI sqrt(9) -It also supports some basic unit conversions: +It also supports some basic unit conversions, including currencies: 13 inches in cm time = 3900 seconds to minutes time * 2 + +1 EUR in USD ∞∞∞markdown In Markdown blocks, lists with [x] and [ ] are rendered as checkboxes: @@ -119,4 +121,5 @@ Shopping list: - Milk - Eggs - Bread -- Cheese` \ No newline at end of file +- Cheese` + diff --git a/src/components/Editor.vue b/src/components/Editor.vue index b4f62a5..5ff1d74 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -54,6 +54,7 @@ showLineNumberGutter: this.showLineNumberGutter, showFoldGutter: this.showFoldGutter, }) + window.document.addEventListener("currenciesLoaded", this.onCurrenciesLoaded) }) // set up window close handler that will save the buffer and quit window.heynote.onWindowClose(() => { @@ -80,6 +81,10 @@ } }, + beforeUnmount() { + window.document.removeEventListener("currenciesLoaded", this.onCurrenciesLoaded) + }, + watch: { theme(newTheme) { this.editor.setTheme(newTheme) @@ -113,6 +118,10 @@ this.editor.focus() }, + onCurrenciesLoaded() { + this.editor.currenciesLoaded() + }, + focus() { this.editor.focus() }, diff --git a/src/currency.js b/src/currency.js index 123f94b..e5fa1b9 100644 --- a/src/currency.js +++ b/src/currency.js @@ -14,4 +14,5 @@ export async function loadCurrencies() { }, {override: currenciesLoaded}) }) currenciesLoaded = true + window.document.dispatchEvent(new Event("currenciesLoaded")) } diff --git a/src/editor/annotation.js b/src/editor/annotation.js index 03a8c27..3b4ca75 100644 --- a/src/editor/annotation.js +++ b/src/editor/annotation.js @@ -2,4 +2,5 @@ import { Annotation } from "@codemirror/state" export const heynoteEvent = Annotation.define() export const LANGUAGE_CHANGE = "heynote-change" +export const CURRENCIES_LOADED = "heynote-currencies-loaded" diff --git a/src/editor/block/commands.js b/src/editor/block/commands.js index 499ac15..4f08166 100644 --- a/src/editor/block/commands.js +++ b/src/editor/block/commands.js @@ -4,7 +4,7 @@ import { selectAll as defaultSelectAll, moveLineUp as defaultMoveLineUp, } from "@codemirror/commands" -import { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js"; +import { heynoteEvent, LANGUAGE_CHANGE, CURRENCIES_LOADED } from "../annotation.js"; import { blockState, getActiveNoteBlock, getNoteBlockFromPos } from "./block" import { levenshtein_distance } from "../language-detection/levenshtein" import { moveLineDown, moveLineUp } from "./move-lines.js"; @@ -277,3 +277,12 @@ export function newCursorBelow(view) { export function newCursorAbove(view) { newCursor(view, false) } + +export function triggerCurrenciesLoaded(state, dispatch) { + // Trigger empty change transaction that is annotated with CURRENCIES_LOADED + // This will make Math blocks re-render so that currency conversions are applied + dispatch(state.update({ + changes:{from: 0, to: 0, insert:""}, + annotations: [heynoteEvent.of(CURRENCIES_LOADED)], + })) +} diff --git a/src/editor/block/math.js b/src/editor/block/math.js index 42e599b..1e743e4 100644 --- a/src/editor/block/math.js +++ b/src/editor/block/math.js @@ -4,6 +4,7 @@ import { RangeSetBuilder } from "@codemirror/state" import { WidgetType } from "@codemirror/view" import { getNoteBlockFromPos } from "./block" +import { CURRENCIES_LOADED } from "../annotation" class MathResult extends WidgetType { @@ -84,6 +85,11 @@ function mathDeco(view) { } +// This function checks if any of the transactions has the given annotation +const transactionsHasAnnotation = (transactions, annotation) => { + return transactions.some(tr => tr.annotations.some(a => a.value === annotation)) +} + export const mathBlock = ViewPlugin.fromClass(class { decorations @@ -92,7 +98,10 @@ export const mathBlock = ViewPlugin.fromClass(class { } update(update) { - if (update.docChanged || update.viewportChanged) { + // If the document changed, the viewport changed, or the transaction was annotated with the CURRENCIES_LOADED annotation, + // update the decorations. The reason we need to check for CURRENCIES_LOADED annotations is because the currency rates are + // updated asynchronously + if (update.docChanged || update.viewportChanged || transactionsHasAnnotation(update.transactions, CURRENCIES_LOADED)) { this.decorations = mathDeco(update.view) } } diff --git a/src/editor/editor.js b/src/editor/editor.js index 541a7e3..9f518be 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -9,7 +9,7 @@ import { heynoteBase } from "./theme/base.js" import { customSetup } from "./setup.js" import { heynoteLang } from "./lang-heynote/heynote.js" import { noteBlockExtension, blockLineNumbers } from "./block/block.js" -import { changeCurrentBlockLanguage } from "./block/commands.js" +import { changeCurrentBlockLanguage, triggerCurrenciesLoaded } from "./block/commands.js" import { formatBlockContent } from "./block/format-code.js" import { heynoteKeymap } from "./keymap.js" import { emacsKeymap } from "./emacs.js" @@ -147,6 +147,10 @@ export class HeynoteEditor { dispatch: this.view.dispatch, }) } + + currenciesLoaded() { + triggerCurrenciesLoaded(this.view.state, this.view.dispatch) + } }