mirror of
https://github.com/heyman/heynote.git
synced 2024-11-21 15:33:14 +01:00
Add support for Math blocks
This commit is contained in:
parent
cc6cda0217
commit
4d12404d77
@ -13,6 +13,19 @@ Welcome to Heynote!
|
|||||||
[${modChar} + Up] Goto previous block
|
[${modChar} + Up] Goto previous block
|
||||||
[${modChar} + A] Select all text in a note block. Press again to select the whole scratchpad
|
[${modChar} + A] Select all text in a note block. Press again to select the whole scratchpad
|
||||||
[${modChar} + ⌥ + Up/Down] Add additional cursor above/below
|
[${modChar} + ⌥ + Up/Down] Add additional cursor above/below
|
||||||
|
∞∞∞math
|
||||||
|
This is a Math block. Here, rows are evaluated as math expressions.
|
||||||
|
|
||||||
|
length = 10
|
||||||
|
radius = 5
|
||||||
|
volume = length * radius^2 * PI
|
||||||
|
sqrt(9)
|
||||||
|
|
||||||
|
It also supports some basic unit conversions:
|
||||||
|
|
||||||
|
13 inches in cm
|
||||||
|
time = 3900 seconds to minutes
|
||||||
|
time * 2
|
||||||
∞∞∞text-a
|
∞∞∞text-a
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -27,6 +40,20 @@ Welcome to Heynote!
|
|||||||
[${modChar} + Up] Goto previous block
|
[${modChar} + Up] Goto previous block
|
||||||
[${modChar} + A] Select all text in a note block. Press again to select the whole scratchpad
|
[${modChar} + A] Select all text in a note block. Press again to select the whole scratchpad
|
||||||
[${modChar} + ⌥ + Up/Down] Add additional cursor above/below
|
[${modChar} + ⌥ + Up/Down] Add additional cursor above/below
|
||||||
|
∞∞∞math
|
||||||
|
This is a Math block. Here, rows are evaluated as math expressions.
|
||||||
|
|
||||||
|
length = 10
|
||||||
|
radius = 5
|
||||||
|
volume = length * radius^2 * PI
|
||||||
|
sqrt(9)
|
||||||
|
|
||||||
|
It also supports some basic unit conversions:
|
||||||
|
|
||||||
|
13 inches in cm
|
||||||
|
time = 3900 seconds to minutes
|
||||||
|
time * 2
|
||||||
|
∞∞∞text-a
|
||||||
|
|
||||||
∞∞∞python-a
|
∞∞∞python-a
|
||||||
# hmm
|
# hmm
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="src/main.js"></script>
|
<script type="module" src="src/main.js"></script>
|
||||||
|
<script src="math.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<!--<div id="editor" class="editor"></div>
|
<!--<div id="editor" class="editor"></div>
|
||||||
<script type="module" src="src/editor/index.js"></script>-->
|
<script type="module" src="src/editor/index.js"></script>-->
|
||||||
|
3
public/math.js
Normal file
3
public/math.js
Normal file
File diff suppressed because one or more lines are too long
@ -7,6 +7,7 @@ import { Note, Document, NoteDelimiter } from "../lang-heynote/parser.terms.js"
|
|||||||
import { IterMode } from "@lezer/common";
|
import { IterMode } from "@lezer/common";
|
||||||
import { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js";
|
import { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js";
|
||||||
import { SelectionChangeEvent } from "../event.js"
|
import { SelectionChangeEvent } from "../event.js"
|
||||||
|
import { mathBlock } from "./math.js"
|
||||||
|
|
||||||
|
|
||||||
// tracks the size of the first delimiter
|
// tracks the size of the first delimiter
|
||||||
@ -310,5 +311,6 @@ export const noteBlockExtension = (editor) => {
|
|||||||
preventFirstBlockFromBeingDeleted,
|
preventFirstBlockFromBeingDeleted,
|
||||||
preventSelectionBeforeFirstBlock,
|
preventSelectionBeforeFirstBlock,
|
||||||
emitCursorChange(editor),
|
emitCursorChange(editor),
|
||||||
|
mathBlock,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
76
src/editor/block/math.js
Normal file
76
src/editor/block/math.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { ViewPlugin } from "@codemirror/view"
|
||||||
|
import { Decoration } from "@codemirror/view"
|
||||||
|
import { RangeSetBuilder } from "@codemirror/state"
|
||||||
|
import { WidgetType } from "@codemirror/view"
|
||||||
|
|
||||||
|
import { getNoteBlockFromPos } from "./block"
|
||||||
|
|
||||||
|
|
||||||
|
class MathResult extends WidgetType {
|
||||||
|
constructor(result) {
|
||||||
|
super()
|
||||||
|
this.result = result
|
||||||
|
}
|
||||||
|
|
||||||
|
eq(other) { return other.result == this.result }
|
||||||
|
|
||||||
|
toDOM() {
|
||||||
|
let wrap = document.createElement("span")
|
||||||
|
wrap.className = "heynote-math-result"
|
||||||
|
wrap.innerHTML = this.result
|
||||||
|
return wrap
|
||||||
|
}
|
||||||
|
ignoreEvent() { return false }
|
||||||
|
}
|
||||||
|
|
||||||
|
function mathDeco(view) {
|
||||||
|
let mathParsers = new WeakMap()
|
||||||
|
let builder = new RangeSetBuilder()
|
||||||
|
for (let { from, to } of view.visibleRanges) {
|
||||||
|
for (let pos = from; pos <= to;) {
|
||||||
|
let line = view.state.doc.lineAt(pos)
|
||||||
|
var block = getNoteBlockFromPos(view.state, pos)
|
||||||
|
|
||||||
|
if (block && block.language.name == "math") {
|
||||||
|
// get math.js parser and cache it for this block
|
||||||
|
let parser = mathParsers.get(block)
|
||||||
|
if (!parser) {
|
||||||
|
parser = math.parser()
|
||||||
|
mathParsers.set(block, parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate math line
|
||||||
|
let result
|
||||||
|
try {
|
||||||
|
result = parser.evaluate(line.text)
|
||||||
|
} catch (e) {
|
||||||
|
// suppress any errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(math.format(result, 8)), side: 1}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos = line.to + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const mathBlock = ViewPlugin.fromClass(class {
|
||||||
|
decorations
|
||||||
|
|
||||||
|
constructor(view) {
|
||||||
|
this.decorations = mathDeco(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
update(update) {
|
||||||
|
if (update.docChanged || update.viewportChanged) {
|
||||||
|
this.decorations = mathDeco(update.view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
decorations: v => v.decorations
|
||||||
|
})
|
@ -11,7 +11,7 @@ NoteDelimiter {
|
|||||||
|
|
||||||
@tokens {
|
@tokens {
|
||||||
noteDelimiterMark { "∞∞∞" }
|
noteDelimiterMark { "∞∞∞" }
|
||||||
NoteLanguage { "text" | "javascript" | "json" | "python" | "html" | "sql" | "markdown" | "java" | "php" | "css" | "xml" | "cpp" | "rust" }
|
NoteLanguage { "text" | "math" | "javascript" | "json" | "python" | "html" | "sql" | "markdown" | "java" | "php" | "css" | "xml" | "cpp" | "rust" }
|
||||||
Auto { "-a" }
|
Auto { "-a" }
|
||||||
noteDelimiterEnter { "\n" }
|
noteDelimiterEnter { "\n" }
|
||||||
//NoteContent { String }
|
//NoteContent { String }
|
||||||
|
@ -10,7 +10,7 @@ export const parser = LRParser.deserialize({
|
|||||||
maxTerm: 10,
|
maxTerm: 10,
|
||||||
skippedNodes: [0],
|
skippedNodes: [0],
|
||||||
repeatNodeCount: 1,
|
repeatNodeCount: 1,
|
||||||
tokenData: "&|~R[YZw}!O|#V#W!X#[#]!s#^#_#V#a#b$p#d#e%f#f#g%{#g#h&X#h#i&_#l#m!y%&x%&y&k~|OX~~!PP#T#U!S~!XOU~~![Q#d#e!b#g#h!m~!eP#d#e!h~!mOT~~!pP#g#h!h~!vP#h#i!y~!|P#a#b#P~#SP#`#a!h~#YQ#T#U#`#g#h$d~#cP#j#k#f~#iP#T#U#l~#qPT~#g#h#t~#wP#V#W#z~#}P#f#g$Q~$TP#]#^$W~$ZP#d#e$^~$aP#h#i!h~$gP#c#d$j~$mP#b#c!h~$sP#T#U$v~$yP#f#g$|~%PP#_#`%S~%VP#W#X%Y~%]P#c#d%`~%cP#k#l$j~%iQ#[#]!b#m#n%o~%rP#h#i%u~%xP#[#]$d~&OP#i#j&R~&UP#g#h$^~&[P#e#f#P~&bP#X#Y&e~&hP#l#m$^~&nP%&x%&y&q~&tP%&x%&y&w~&|OY~",
|
tokenData: "'V~R[YZw}!O|#V#W!X#[#]!s#^#_#V#a#b$p#d#e%o#f#g&U#g#h&b#h#i&h#l#m!y%&x%&y&t~|OX~~!PP#T#U!S~!XOU~~![Q#d#e!b#g#h!m~!eP#d#e!h~!mOT~~!pP#g#h!h~!vP#h#i!y~!|P#a#b#P~#SP#`#a!h~#YQ#T#U#`#g#h$d~#cP#j#k#f~#iP#T#U#l~#qPT~#g#h#t~#wP#V#W#z~#}P#f#g$Q~$TP#]#^$W~$ZP#d#e$^~$aP#h#i!h~$gP#c#d$j~$mP#b#c!h~$sP#T#U$v~$yQ#f#g%P#h#i%i~%SP#_#`%V~%YP#W#X%]~%`P#c#d%c~%fP#k#l$j~%lP#[#]!h~%rQ#[#]!b#m#n%x~%{P#h#i&O~&RP#[#]$d~&XP#i#j&[~&_P#g#h$^~&eP#e#f#P~&kP#X#Y&n~&qP#l#m$^~&wP%&x%&y&z~&}P%&x%&y'Q~'VOY~",
|
||||||
tokenizers: [0, noteContent],
|
tokenizers: [0, noteContent],
|
||||||
topRules: {"Document":[0,2]},
|
topRules: {"Document":[0,2]},
|
||||||
tokenPrec: 0
|
tokenPrec: 0
|
||||||
|
@ -24,6 +24,7 @@ class Language {
|
|||||||
|
|
||||||
export const LANGUAGES = [
|
export const LANGUAGES = [
|
||||||
new Language("text", "Plain Text", null, "plaintext"),
|
new Language("text", "Plain Text", null, "plaintext"),
|
||||||
|
new Language("math", "Math", null, null),
|
||||||
new Language("javascript", "JavaScript", javascriptLanguage.parser, "javascript"),
|
new Language("javascript", "JavaScript", javascriptLanguage.parser, "javascript"),
|
||||||
new Language("json", "JSON", jsonLanguage.parser, "json"),
|
new Language("json", "JSON", jsonLanguage.parser, "json"),
|
||||||
new Language("python", "Python", pythonLanguage.parser, "python"),
|
new Language("python", "Python", pythonLanguage.parser, "python"),
|
||||||
|
@ -43,4 +43,11 @@ export const heynoteBase = EditorView.theme({
|
|||||||
'.heynote-block-start.first': {
|
'.heynote-block-start.first': {
|
||||||
height: '0px',
|
height: '0px',
|
||||||
},
|
},
|
||||||
|
'.heynote-math-result': {
|
||||||
|
background: '#48b57e',
|
||||||
|
color: '#fff',
|
||||||
|
padding: '0px 4px',
|
||||||
|
borderRadius: '2px',
|
||||||
|
marginLeft: '12px',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
@ -111,6 +111,10 @@ const darkTheme = EditorView.theme({
|
|||||||
background: "#213644",
|
background: "#213644",
|
||||||
borderTop: "1px solid #1e222a",
|
borderTop: "1px solid #1e222a",
|
||||||
},
|
},
|
||||||
|
".heynote-math-result": {
|
||||||
|
background: "#0e1217",
|
||||||
|
color: "#7fcba9",
|
||||||
|
},
|
||||||
}, { dark: true });
|
}, { dark: true });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user