Compare commits
2 commits
8385f08923
...
7b6d18bc6a
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b6d18bc6a | |||
| 7fafa35b4b |
6 changed files with 55 additions and 46 deletions
|
|
@ -1,17 +1,15 @@
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { extendedEnv } from './environment';
|
|
||||||
import { GlobalContext } from '../../context/GlobalContext';
|
import { GlobalContext } from '../../context/GlobalContext';
|
||||||
|
import { deepEvalExpr } from '../../eval/deep_eval';
|
||||||
import { inferType, scoreTypeInfo } from '../../eval/infer_type';
|
import { inferType, scoreTypeInfo } from '../../eval/infer_type';
|
||||||
import { ExprBlock, type ExprBlockState } from '../expr/ExprBlock';
|
import { ExprBlock, type ExprBlockState } from '../expr/ExprBlock';
|
||||||
|
import { TypeInfoBlock } from '../other/Type';
|
||||||
|
import { Value } from '../other/Value';
|
||||||
import { actionShortcuts } from './actions';
|
import { actionShortcuts } from './actions';
|
||||||
import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, setOfListOfBool, tripleFunctionCallEditorState } from "./configurations";
|
import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, setOfListOfBool, tripleFunctionCallEditorState } from "./configurations";
|
||||||
|
import { extendedEnv } from './environment';
|
||||||
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { evalExpr } from '../../eval/eval';
|
|
||||||
import { Value } from '../other/Value';
|
|
||||||
import { Type, TypeInfoBlock } from '../other/Type';
|
|
||||||
import { deepEvalExpr } from '../../eval/deep_eval';
|
|
||||||
|
|
||||||
|
|
||||||
const examples: [string, ExprBlockState][] = [
|
const examples: [string, ExprBlockState][] = [
|
||||||
["empty editor" , initialEditorState ],
|
["empty editor" , initialEditorState ],
|
||||||
|
|
@ -140,10 +138,11 @@ export function App() {
|
||||||
|
|
||||||
// static evalution
|
// static evalution
|
||||||
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
||||||
// dynamic evalutions
|
|
||||||
const evalResult = evalExpr(currentState, extendedEnv);
|
// dynamic evalution
|
||||||
const deepEvalResult = deepEvalExpr(currentState, extendedEnv);
|
const deepEvalResult = deepEvalExpr(currentState, extendedEnv);
|
||||||
console.log({deepEvalResult});
|
|
||||||
|
const err = typeInfo.err || deepEvalResult.err;
|
||||||
|
|
||||||
const onCopy = () => {
|
const onCopy = () => {
|
||||||
const serialized = JSON.stringify(currentState);
|
const serialized = JSON.stringify(currentState);
|
||||||
|
|
@ -216,7 +215,7 @@ export function App() {
|
||||||
/>
|
/>
|
||||||
=
|
=
|
||||||
<Value dynamic={{
|
<Value dynamic={{
|
||||||
i: evalResult.val,
|
i: err ? undefined : deepEvalResult.val,
|
||||||
t: typeInfo.type,
|
t: typeInfo.type,
|
||||||
}}/>
|
}}/>
|
||||||
::
|
::
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ function nestedInputProperties({state, setState, score, typeInfo, evalResult}: C
|
||||||
setState(state => ({...state, input: callback(state.input)}));
|
setState(state => ({...state, input: callback(state.input)}));
|
||||||
};
|
};
|
||||||
const onInputCancel = () => {
|
const onInputCancel = () => {
|
||||||
|
|
||||||
setState(state => /*addFocusRightMost*/(state.fn)); // we become our function
|
setState(state => /*addFocusRightMost*/(state.fn)); // we become our function
|
||||||
};
|
};
|
||||||
const scoreInput = (inputSuggestion: ExprBlockState) => {
|
const scoreInput = (inputSuggestion: ExprBlockState) => {
|
||||||
|
|
@ -52,7 +53,9 @@ function nestedInputProperties({state, setState, score, typeInfo, evalResult}: C
|
||||||
export function CallBlock(props: CallBlockProps) {
|
export function CallBlock(props: CallBlockProps) {
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const addParam = getActions(globalContext, props.setState).c;
|
const addParam = getActions(globalContext, props.setState).c;
|
||||||
return <span className={"functionBlock"}>
|
const err = props.typeInfo.err || props.evalResult.err;
|
||||||
|
|
||||||
|
return <span className="functionBlock dropdownContainer">
|
||||||
<CallContext value={{addParam}}>
|
<CallContext value={{addParam}}>
|
||||||
<FunctionHeader {...props} addParam={addParam} />
|
<FunctionHeader {...props} addParam={addParam} />
|
||||||
<div className="functionParams">
|
<div className="functionParams">
|
||||||
|
|
@ -66,6 +69,12 @@ export function CallBlock(props: CallBlockProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CallContext>
|
</CallContext>
|
||||||
|
{(err !== undefined) &&
|
||||||
|
<span className="">
|
||||||
|
<div className="errorMessage">
|
||||||
|
{err.message.trim()}
|
||||||
|
</div>
|
||||||
|
</span>}
|
||||||
</span>;
|
</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
.errorMessage {
|
.errorMessage {
|
||||||
color: darkred;
|
color: darkred;
|
||||||
background-color: pink;
|
background-color: pink;
|
||||||
margin-top: 4px;
|
/* margin-top: 4px; */
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
font-family: var(--my-monospace-font);
|
font-family: var(--my-monospace-font);
|
||||||
white-space-collapse: preserve;
|
white-space-collapse: preserve;
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ const computeSuggestions = (
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InputBlock({ state, setState, score, onCancel, typeInfo }: InputBlockProps) {
|
export function InputBlock({ state, setState, score, onCancel, typeInfo, evalResult }: InputBlockProps) {
|
||||||
const {text, focus} = state;
|
const {text, focus} = state;
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const env = typeInfo.env;
|
const env = typeInfo.env;
|
||||||
|
|
@ -144,7 +144,7 @@ export function InputBlock({ state, setState, score, onCancel, typeInfo }: Input
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const err = typeInfo.err || evalExpr(state, env).err;
|
const err = typeInfo.err || evalResult.err;
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Input
|
<Input
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEffect, useRef, type ReactNode, type KeyboardEvent, useState } from "react";
|
import { useEffect, useRef, type ReactNode, type KeyboardEvent, useState } from "react";
|
||||||
|
|
||||||
import "./Input.css";
|
import "./Input.css";
|
||||||
|
import { focusPrevElement, focusNextElement, setRightMostCaretPosition } from "../../util/dom_trickery";
|
||||||
|
|
||||||
interface InputProps {
|
interface InputProps {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
|
|
@ -25,38 +26,6 @@ function getCaretPosition(ref: React.RefObject<HTMLInputElement| null>): number
|
||||||
return ref.current?.selectionStart || 0;
|
return ref.current?.selectionStart || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move caret all the way to the right in the currently focused element
|
|
||||||
function setRightMostCaretPosition(elem) {
|
|
||||||
const range = document.createRange();
|
|
||||||
range.selectNode(elem);
|
|
||||||
if (elem.lastChild) { // if no text is entered, there is no lastChild
|
|
||||||
range.setStart(elem.lastChild, elem.textContent.length);
|
|
||||||
range.setEnd(elem.lastChild, elem.textContent.length);
|
|
||||||
const selection = window.getSelection();
|
|
||||||
selection?.removeAllRanges();
|
|
||||||
selection?.addRange(range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function focusNextElement() {
|
|
||||||
const editable = Array.from<any>(document.querySelectorAll('input.editable'));
|
|
||||||
const index = editable.indexOf(document.activeElement);
|
|
||||||
const nextElem = editable[index+1];
|
|
||||||
if (nextElem) {
|
|
||||||
nextElem.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function focusPrevElement() {
|
|
||||||
const editable = Array.from<any>(document.querySelectorAll('input.editable'));
|
|
||||||
const index = editable.indexOf(document.activeElement);
|
|
||||||
const prevElem = editable[index-1]
|
|
||||||
if (prevElem) {
|
|
||||||
prevElem.focus();
|
|
||||||
setRightMostCaretPosition(prevElem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Input({placeholder, text, suggestion, onTextChange, onEnter, onCancel, extraHandlers, children}: InputProps) {
|
export function Input({placeholder, text, suggestion, onTextChange, onEnter, onCancel, extraHandlers, children}: InputProps) {
|
||||||
const ref = useRef<HTMLInputElement>(null);
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
const [focus, setFocus] = useState<"yes"|"hide"|"no">("no");
|
const [focus, setFocus] = useState<"yes"|"hide"|"no">("no");
|
||||||
|
|
|
||||||
32
src/util/dom_trickery.ts
Normal file
32
src/util/dom_trickery.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
// Move caret all the way to the right in the currently focused element
|
||||||
|
export function setRightMostCaretPosition(elem) {
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNode(elem);
|
||||||
|
if (elem.lastChild) { // if no text is entered, there is no lastChild
|
||||||
|
range.setStart(elem.lastChild, elem.textContent.length);
|
||||||
|
range.setEnd(elem.lastChild, elem.textContent.length);
|
||||||
|
const selection = window.getSelection();
|
||||||
|
selection?.removeAllRanges();
|
||||||
|
selection?.addRange(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function focusNextElement() {
|
||||||
|
const editable = Array.from<any>(document.querySelectorAll('input.editable'));
|
||||||
|
const index = editable.indexOf(document.activeElement);
|
||||||
|
const nextElem = editable[index + 1];
|
||||||
|
if (nextElem) {
|
||||||
|
nextElem.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function focusPrevElement() {
|
||||||
|
const editable = Array.from<any>(document.querySelectorAll('input.editable'));
|
||||||
|
const index = editable.indexOf(document.activeElement);
|
||||||
|
const prevElem = editable[index - 1];
|
||||||
|
if (prevElem) {
|
||||||
|
prevElem.focus();
|
||||||
|
setRightMostCaretPosition(prevElem);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue