Чото поменял
This commit is contained in:
52
src/App.tsx
52
src/App.tsx
@@ -1,49 +1,16 @@
|
||||
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, 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(),
|
||||
]
|
||||
import { noop } from 'lodash'
|
||||
import { Editor } from './Editor'
|
||||
|
||||
export const App = () => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
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>
|
||||
return <Editor text={testText} onChange={noop} />
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
const testText = `
|
||||
2 + 2 * 2
|
||||
sqrt(3^2 + 4^2)
|
||||
2 inch to cm
|
||||
5cm + 0.2 m in inch
|
||||
cos(45 deg)
|
||||
0.1 + 0.2
|
||||
|
||||
a = 25
|
||||
b = a * 2
|
||||
@@ -53,4 +20,13 @@ pow2(6)
|
||||
|
||||
2 * 2
|
||||
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
42
src/Editor.tsx
Normal 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(),
|
||||
]
|
||||
@@ -17,6 +17,32 @@ body {
|
||||
}
|
||||
|
||||
.math-result {
|
||||
color: grey;
|
||||
color: rgb(80, 80, 80);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import { App } from './App.tsx'
|
||||
import './index.css'
|
||||
|
||||
const root = document.getElementById('root')
|
||||
|
||||
3
src/math.ts
Normal file
3
src/math.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { create, all } from 'mathjs'
|
||||
|
||||
export const math = create(all, { number: 'BigNumber', precision: 16 })
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate, WidgetType } from '@codemirror/view'
|
||||
import { create, all } from 'mathjs'
|
||||
|
||||
export const math = create(all, { number: 'BigNumber' })
|
||||
import { math } from './math'
|
||||
|
||||
export const mathPlugin = () =>
|
||||
ViewPlugin.fromClass(
|
||||
@@ -30,21 +28,53 @@ const createDecorations = (view: EditorView) => {
|
||||
|
||||
for (let i = 1; i <= view.state.doc.lines; i++) {
|
||||
const { text, to } = view.state.doc.line(i)
|
||||
let decoration: Decoration | null = null
|
||||
|
||||
try {
|
||||
const result = parser.evaluate(text)
|
||||
|
||||
if (result?.isBigNumber) {
|
||||
if (result?.isBigNumber || result?.type === 'Unit') {
|
||||
parser.set('last', result)
|
||||
|
||||
const decoration = Decoration.widget({
|
||||
widget: new MathResult(result.toPrecision()),
|
||||
decoration = Decoration.widget({
|
||||
widget: new MathResult(result.toString()),
|
||||
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) {}
|
||||
|
||||
if (decoration) {
|
||||
widgets.push(decoration.range(to))
|
||||
}
|
||||
}
|
||||
|
||||
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> = {
|
||||
readonly from: number
|
||||
readonly to: number
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ViewPlugin, ViewUpdate } from '@codemirror/view'
|
||||
|
||||
export const getTextPlugin = (callback: (text: string) => void) =>
|
||||
export const textObserverPlugin = (callback: (text: string) => void) =>
|
||||
ViewPlugin.define(() => ({
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged) {
|
||||
Reference in New Issue
Block a user