further improved keyboard handling
This commit is contained in:
parent
95eb8aef84
commit
fa70d2f3f4
5 changed files with 38 additions and 13 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { apply, UnifyError, assignFn, getType } from "dope2";
|
import { apply, UnifyError, assignFn, getType, getSymbol, symbolFunction } from "dope2";
|
||||||
|
|
||||||
import { Editor, type EditorState } from "./Editor";
|
import { Editor, type EditorState } from "./Editor";
|
||||||
import { Value } from "./Value";
|
import { Value } from "./Value";
|
||||||
|
|
@ -97,7 +97,8 @@ export function CallBlock({ state, setState, onResolve }: CallBlockProps) {
|
||||||
<FunctionHeader
|
<FunctionHeader
|
||||||
fn={state.fn}
|
fn={state.fn}
|
||||||
setFn={setFn}
|
setFn={setFn}
|
||||||
onFnResolve={onFnResolve} />
|
onFnResolve={onFnResolve}
|
||||||
|
input={state.input} />
|
||||||
<div className="functionParams">
|
<div className="functionParams">
|
||||||
<div className="outputParam">
|
<div className="outputParam">
|
||||||
{/* Sequence of input parameters */}
|
{/* Sequence of input parameters */}
|
||||||
|
|
@ -116,7 +117,7 @@ export function CallBlock({ state, setState, onResolve }: CallBlockProps) {
|
||||||
</span>;
|
</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FunctionHeader({ fn, setFn, onFnResolve }) {
|
function FunctionHeader({ fn, setFn, input, onFnResolve }) {
|
||||||
if (fn.kind === "call") {
|
if (fn.kind === "call") {
|
||||||
// if the function we're calling is itself the result of a function call,
|
// if the function we're calling is itself the result of a function call,
|
||||||
// then we are anonymous, and so we don't draw a function name
|
// then we are anonymous, and so we don't draw a function name
|
||||||
|
|
@ -129,9 +130,28 @@ function FunctionHeader({ fn, setFn, onFnResolve }) {
|
||||||
return <FunctionHeader
|
return <FunctionHeader
|
||||||
fn={fn.fn}
|
fn={fn.fn}
|
||||||
setFn={fnFn => setFn({...fn, fn: fnFn})}
|
setFn={fnFn => setFn({...fn, fn: fnFn})}
|
||||||
onFnResolve={onFnFnResolve} />;
|
onFnResolve={onFnFnResolve}
|
||||||
|
input={fn.input} />;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const filterCompatibleFns = ([_name, dynamic]: [string, Dynamic]) => {
|
||||||
|
if (input.resolved) {
|
||||||
|
try {
|
||||||
|
const type = getType(dynamic);
|
||||||
|
if (getSymbol(type) !== symbolFunction) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assignFn(type, getType(input.resolved));
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof UnifyError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// end of recursion - draw function name
|
// end of recursion - draw function name
|
||||||
return <div className="functionName">
|
return <div className="functionName">
|
||||||
𝑓𝑛
|
𝑓𝑛
|
||||||
|
|
@ -141,7 +161,7 @@ function FunctionHeader({ fn, setFn, onFnResolve }) {
|
||||||
focus={false}
|
focus={false}
|
||||||
onResolve={onFnResolve}
|
onResolve={onFnResolve}
|
||||||
onCancel={() => {/*todo*/}}
|
onCancel={() => {/*todo*/}}
|
||||||
filter={() => true} />
|
filter={filterCompatibleFns} />
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,14 @@ export function Editor({state, setState, onResolve, onCancel, filter, focus}: Ed
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setNeedCommand(false);
|
setNeedCommand(false);
|
||||||
// u -> pass Up
|
// u -> pass Up
|
||||||
if (e.key === "u" || e.key === "Enter" || e.key === "Tab") {
|
if (e.key === "u" || e.key === "Enter" || e.key === "Tab" && !e.shiftKey) {
|
||||||
onResolve(state);
|
onResolve(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (e.key === "Tab" && e.shiftKey) {
|
||||||
|
setNeedCommand(false);
|
||||||
|
focusPrevElement();
|
||||||
|
}
|
||||||
// c -> Call
|
// c -> Call
|
||||||
if (e.key === "c") {
|
if (e.key === "c") {
|
||||||
// we become CallBlock
|
// we become CallBlock
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
border: solid 1px dodgerblue;
|
border: solid 1px dodgerblue;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
max-height: calc(100vh - 44px);
|
max-height: calc(100vh - 64px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { Double, getType, Int, newDynamic, trie } from "dope2";
|
||||||
import { focusNextElement, focusPrevElement, setRightMostCaretPosition } from "./util/dom_trickery";
|
import { focusNextElement, focusPrevElement, setRightMostCaretPosition } from "./util/dom_trickery";
|
||||||
import { parseDouble, parseInt } from "./util/parse";
|
import { parseDouble, parseInt } from "./util/parse";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { Type } from "./Type";
|
import { Type } from "./Type";
|
||||||
|
|
||||||
import "./InputBlock.css";
|
import "./InputBlock.css";
|
||||||
|
|
@ -29,12 +29,13 @@ const computeSuggestions = (text, env, filter) => {
|
||||||
const ls = [
|
const ls = [
|
||||||
... (asDouble ? [[asDouble.toString(), newDynamic(asDouble)(Double)]] : []),
|
... (asDouble ? [[asDouble.toString(), newDynamic(asDouble)(Double)]] : []),
|
||||||
... (asInt ? [[asInt.toString(), newDynamic(BigInt(asInt))(Int)]] : []),
|
... (asInt ? [[asInt.toString(), newDynamic(BigInt(asInt))(Int)]] : []),
|
||||||
... trie.suggest(env.name2dyn)(text)(10),
|
... trie.suggest(env.name2dyn)(text)(Infinity),
|
||||||
]
|
]
|
||||||
return [
|
return [
|
||||||
...ls.filter(filter), // ones that match filter come first
|
...ls.filter(filter), // ones that match filter come first
|
||||||
...ls.filter(s => !filter(s)),
|
...ls.filter(s => !filter(s)),
|
||||||
];
|
]
|
||||||
|
// .slice(0,30);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InputBlock({ state, setState, filter, onResolve, onCancel }: InputBlockProps) {
|
export function InputBlock({ state, setState, filter, onResolve, onCancel }: InputBlockProps) {
|
||||||
|
|
@ -48,7 +49,7 @@ export function InputBlock({ state, setState, filter, onResolve, onCancel }: Inp
|
||||||
}
|
}
|
||||||
|
|
||||||
const singleSuggestion = trie.growPrefix(env.name2dyn)(text);
|
const singleSuggestion = trie.growPrefix(env.name2dyn)(text);
|
||||||
const suggestions = computeSuggestions(text, env, filter);
|
const suggestions = useMemo(() => computeSuggestions(text, env, filter), [text]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setI(0); // reset
|
setI(0); // reset
|
||||||
|
|
@ -186,7 +187,7 @@ function Suggestions({ suggestions, onSelect, i, setI }) {
|
||||||
{suggestions.map(([name, dynamic], j) =>
|
{suggestions.map(([name, dynamic], j) =>
|
||||||
<div
|
<div
|
||||||
key={`${j}_${name}`}
|
key={`${j}_${name}`}
|
||||||
className={i === j ? "selected" : ""}
|
className={(i === j ? " selected" : "")}
|
||||||
onMouseEnter={onMouseEnter(j)}
|
onMouseEnter={onMouseEnter(j)}
|
||||||
onMouseDown={onMouseDown(j)}>
|
onMouseDown={onMouseDown(j)}>
|
||||||
{name} :: <Type type={getType(dynamic)} />
|
{name} :: <Type type={getType(dynamic)} />
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
|
|
||||||
.iteratorType {
|
.iteratorType {
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
animation: flickerAnimation 500ms steps(1) normal infinite;
|
/* animation: flickerAnimation 500ms steps(1) normal infinite; */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Animations */
|
/* Animations */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue