mirror of
https://github.com/heyman/heynote.git
synced 2024-11-21 23:43:22 +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} + A] Select all text in a note block. Press again to select the whole scratchpad
|
||||
[${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
|
||||
`
|
||||
|
||||
@ -27,6 +40,20 @@ Welcome to Heynote!
|
||||
[${modChar} + Up] Goto previous block
|
||||
[${modChar} + A] Select all text in a note block. Press again to select the whole scratchpad
|
||||
[${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
|
||||
# hmm
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
<div id="app"></div>
|
||||
<script type="module" src="src/main.js"></script>
|
||||
<script src="math.js" type="text/javascript"></script>
|
||||
|
||||
<!--<div id="editor" class="editor"></div>
|
||||
<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 { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js";
|
||||
import { SelectionChangeEvent } from "../event.js"
|
||||
import { mathBlock } from "./math.js"
|
||||
|
||||
|
||||
// tracks the size of the first delimiter
|
||||
@ -310,5 +311,6 @@ export const noteBlockExtension = (editor) => {
|
||||
preventFirstBlockFromBeingDeleted,
|
||||
preventSelectionBeforeFirstBlock,
|
||||
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 {
|
||||
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" }
|
||||
noteDelimiterEnter { "\n" }
|
||||
//NoteContent { String }
|
||||
|
@ -10,7 +10,7 @@ export const parser = LRParser.deserialize({
|
||||
maxTerm: 10,
|
||||
skippedNodes: [0],
|
||||
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],
|
||||
topRules: {"Document":[0,2]},
|
||||
tokenPrec: 0
|
||||
|
@ -24,6 +24,7 @@ class Language {
|
||||
|
||||
export const LANGUAGES = [
|
||||
new Language("text", "Plain Text", null, "plaintext"),
|
||||
new Language("math", "Math", null, null),
|
||||
new Language("javascript", "JavaScript", javascriptLanguage.parser, "javascript"),
|
||||
new Language("json", "JSON", jsonLanguage.parser, "json"),
|
||||
new Language("python", "Python", pythonLanguage.parser, "python"),
|
||||
|
@ -43,4 +43,11 @@ export const heynoteBase = EditorView.theme({
|
||||
'.heynote-block-start.first': {
|
||||
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",
|
||||
borderTop: "1px solid #1e222a",
|
||||
},
|
||||
".heynote-math-result": {
|
||||
background: "#0e1217",
|
||||
color: "#7fcba9",
|
||||
},
|
||||
}, { dark: true });
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user