Compare commits
No commits in common. "7b6d18bc6a2af175471bf9295f2e50928ea61cbe" and "8385f08923f4478b9125c9fc69c9e725279d4306" have entirely different histories.
7b6d18bc6a
...
8385f08923
6 changed files with 46 additions and 55 deletions
|
|
@ -1,15 +1,17 @@
|
||||||
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 ],
|
||||||
|
|
@ -138,11 +140,10 @@ export function App() {
|
||||||
|
|
||||||
// static evalution
|
// static evalution
|
||||||
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
||||||
|
// dynamic evalutions
|
||||||
// dynamic evalution
|
const evalResult = evalExpr(currentState, extendedEnv);
|
||||||
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);
|
||||||
|
|
@ -215,7 +216,7 @@ export function App() {
|
||||||
/>
|
/>
|
||||||
=
|
=
|
||||||
<Value dynamic={{
|
<Value dynamic={{
|
||||||
i: err ? undefined : deepEvalResult.val,
|
i: evalResult.val,
|
||||||
t: typeInfo.type,
|
t: typeInfo.type,
|
||||||
}}/>
|
}}/>
|
||||||
::
|
::
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ 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) => {
|
||||||
|
|
@ -53,9 +52,7 @@ 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;
|
||||||
const err = props.typeInfo.err || props.evalResult.err;
|
return <span className={"functionBlock"}>
|
||||||
|
|
||||||
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">
|
||||||
|
|
@ -69,12 +66,6 @@ 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, evalResult }: InputBlockProps) {
|
export function InputBlock({ state, setState, score, onCancel, typeInfo }: 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, evalRes
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const err = typeInfo.err || evalResult.err;
|
const err = typeInfo.err || evalExpr(state, env).err;
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Input
|
<Input
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
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;
|
||||||
|
|
@ -26,6 +25,38 @@ 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");
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
|
|
||||||
// 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