Чото поменял

This commit is contained in:
2023-11-20 18:00:24 +03:00
parent 6f147ca8b7
commit e164248d9c
7 changed files with 167 additions and 49 deletions

View File

@@ -1,49 +1,16 @@
import { defaultKeymap, historyKeymap, history } from '@codemirror/commands' import { noop } from 'lodash'
import { EditorView, drawSelection, dropCursor, keymap } from '@codemirror/view' import { Editor } from './Editor'
import { defaultHighlightStyle, indentOnInput, syntaxHighlighting } from '@codemirror/language'
import { Extension } from '@codemirror/state'
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete'
import { searchKeymap } from '@codemirror/search'
import { useEffect, useRef, useState } from 'react'
import { getTextPlugin } from './getTextPlugin'
import { mathPlugin } from './mathPlugin'
const basicSetup: Extension = [
history(),
drawSelection(),
dropCursor(),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
closeBrackets(),
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...searchKeymap, ...historyKeymap]),
mathPlugin(),
]
export const App = () => { export const App = () => {
const ref = useRef<HTMLDivElement>(null) return <Editor text={testText} onChange={noop} />
const view = useRef<EditorView>()
const [text, setText] = useState(testText)
useEffect(() => {
view.current = new EditorView({
doc: text,
extensions: [basicSetup, getTextPlugin(setText)],
parent: ref.current!,
})
return () => view.current?.destroy()
}, [])
return <div className="cm-editor-mount" ref={ref}></div>
} }
export default App
const testText = ` const testText = `
2 + 2 * 2 2 + 2 * 2
sqrt(3^2 + 4^2) sqrt(3^2 + 4^2)
2 inch to cm 5cm + 0.2 m in inch
cos(45 deg) cos(45 deg)
0.1 + 0.2
a = 25 a = 25
b = a * 2 b = a * 2
@@ -53,4 +20,13 @@ pow2(6)
2 * 2 2 * 2
last + 1 last + 1
f(x) = (sin(x) + cos(x/2)) * 5
a = [1, 2, 3; 2+2, 5, 6]
a[2, 3]
a[1:2, 2]
b = [1, 2; 3, 4]
b * a
a[3, 1:3] = [7, 8, 9]
` `

42
src/Editor.tsx Normal file
View File

@@ -0,0 +1,42 @@
import { defaultKeymap, historyKeymap, history } from '@codemirror/commands'
import { EditorView, drawSelection, dropCursor, keymap } from '@codemirror/view'
import { defaultHighlightStyle, indentOnInput, syntaxHighlighting } from '@codemirror/language'
import { Extension } from '@codemirror/state'
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete'
import { searchKeymap } from '@codemirror/search'
import { useEffect, useRef } from 'react'
import { textObserverPlugin } from './textObserverPlugin'
import { mathPlugin } from './mathPlugin'
type Props = {
text: string
onChange: (text: string) => void
}
export const Editor = ({ text, onChange }: Props) => {
const ref = useRef<HTMLDivElement>(null)
const view = useRef<EditorView>()
useEffect(() => {
view.current = new EditorView({
doc: text,
extensions: [basicSetup, textObserverPlugin(onChange)],
parent: ref.current!,
})
return () => view.current?.destroy()
}, [])
return <div className="cm-editor-mount" ref={ref}></div>
}
const basicSetup: Extension = [
history(),
drawSelection(),
dropCursor(),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
closeBrackets(),
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...searchKeymap, ...historyKeymap]),
mathPlugin(),
]

View File

@@ -17,6 +17,32 @@ body {
} }
.math-result { .math-result {
color: grey; color: rgb(80, 80, 80);
margin-left: 8px; margin-left: 8px;
} }
.matrix-wrapper {
display: flex;
margin-left: 8px;
margin-top: 4px;
}
.matrix-result {
color: rgb(80, 80, 80);
}
.matrix-wrapper::before {
min-width: 4px;
content: ' ';
border: 1px solid rgb(140, 140, 140);
border-right: 0;
margin-right: 6px;
}
.matrix-wrapper::after {
min-width: 4px;
content: ' ';
border: 1px solid rgb(140, 140, 140);
border-left: 0;
margin-left: 6px;
}

View File

@@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client'
import App from './App.tsx' import { App } from './App.tsx'
import './index.css' import './index.css'
const root = document.getElementById('root') const root = document.getElementById('root')

3
src/math.ts Normal file
View File

@@ -0,0 +1,3 @@
import { create, all } from 'mathjs'
export const math = create(all, { number: 'BigNumber', precision: 16 })

View File

@@ -1,7 +1,5 @@
import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate, WidgetType } from '@codemirror/view' import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate, WidgetType } from '@codemirror/view'
import { create, all } from 'mathjs' import { math } from './math'
export const math = create(all, { number: 'BigNumber' })
export const mathPlugin = () => export const mathPlugin = () =>
ViewPlugin.fromClass( ViewPlugin.fromClass(
@@ -30,21 +28,53 @@ const createDecorations = (view: EditorView) => {
for (let i = 1; i <= view.state.doc.lines; i++) { for (let i = 1; i <= view.state.doc.lines; i++) {
const { text, to } = view.state.doc.line(i) const { text, to } = view.state.doc.line(i)
let decoration: Decoration | null = null
try { try {
const result = parser.evaluate(text) const result = parser.evaluate(text)
if (result?.isBigNumber) { if (result?.isBigNumber || result?.type === 'Unit') {
parser.set('last', result) parser.set('last', result)
const decoration = Decoration.widget({ decoration = Decoration.widget({
widget: new MathResult(result.toPrecision()), widget: new MathResult(result.toString()),
side: 1, side: 1,
}) })
}
widgets.push(decoration.range(to)) if (result?.type === 'DenseMatrix') {
parser.set('last', result)
const size = result.size()
switch (size.length) {
case 1:
decoration = Decoration.widget({
widget: new MathResult(result.toString()),
side: 1,
})
break
case 2:
decoration = Decoration.widget({
widget: new Matrix(result),
side: 1,
})
break
}
}
if (typeof result === 'function') {
decoration = Decoration.widget({
widget: new MathResult(result.syntax),
side: 1,
})
} }
} catch (e) {} } catch (e) {}
if (decoration) {
widgets.push(decoration.range(to))
}
} }
return Decoration.set(widgets) return Decoration.set(widgets)
@@ -72,6 +102,47 @@ class MathResult extends WidgetType {
} }
} }
class Matrix extends WidgetType {
constructor(readonly result: any) {
super()
}
eq(other: MathResult) {
return other.result == this.result
}
toDOM() {
const wrapper = document.createElement('div')
wrapper.className = 'matrix-wrapper'
const table = document.createElement('table')
table.className = 'matrix-result'
wrapper.appendChild(table)
const array = this.result.toArray()
for (const row of array) {
const tr = document.createElement('tr')
tr.className = 'matrix-row'
for (const col of row) {
const td = document.createElement('td')
td.className = 'matrix-col'
td.innerText = col.toString()
tr.appendChild(td)
}
table.appendChild(tr)
}
return wrapper
}
ignoreEvent() {
return false
}
}
type Range<T> = { type Range<T> = {
readonly from: number readonly from: number
readonly to: number readonly to: number

View File

@@ -1,6 +1,6 @@
import { ViewPlugin, ViewUpdate } from '@codemirror/view' import { ViewPlugin, ViewUpdate } from '@codemirror/view'
export const getTextPlugin = (callback: (text: string) => void) => export const textObserverPlugin = (callback: (text: string) => void) =>
ViewPlugin.define(() => ({ ViewPlugin.define(() => ({
update(update: ViewUpdate) { update(update: ViewUpdate) {
if (update.docChanged) { if (update.docChanged) {