self-host fonts; proper error bubbling
This commit is contained in:
parent
68104a8102
commit
46baad7cf4
8 changed files with 63 additions and 34 deletions
|
|
@ -10,6 +10,8 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/inconsolata": "^5.2.5",
|
||||
"@fontsource-variable/roboto": "^5.2.5",
|
||||
"dope2": "git+https://deemz.org/git/joeri/dope2.git",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0"
|
||||
|
|
|
|||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
|
|
@ -8,6 +8,12 @@ importers:
|
|||
|
||||
.:
|
||||
dependencies:
|
||||
'@fontsource-variable/inconsolata':
|
||||
specifier: ^5.2.5
|
||||
version: 5.2.5
|
||||
'@fontsource-variable/roboto':
|
||||
specifier: ^5.2.5
|
||||
version: 5.2.5
|
||||
dope2:
|
||||
specifier: git+https://deemz.org/git/joeri/dope2.git
|
||||
version: git+https://deemz.org/git/joeri/dope2.git#0096bb5559224b4c9bbe74317e07dc71cfc09c70
|
||||
|
|
@ -242,6 +248,12 @@ packages:
|
|||
resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@fontsource-variable/inconsolata@5.2.5':
|
||||
resolution: {integrity: sha512-CqYyjFNuArFv+cLRQodR+A9jJm2UMnBoP29yjYqjkd7Cgwz3pnMs3p68kmUb6VD/UqpDQR3deYTwa7RWFPOFew==}
|
||||
|
||||
'@fontsource-variable/roboto@5.2.5':
|
||||
resolution: {integrity: sha512-csqBSOWXv0h5IbPhEqYJua6/nxl7dSNZbBOMeXSO9aqzgPw3GpfgC9kL5M6ULFLRaoDoBD4U9QctoDLKMaTyMg==}
|
||||
|
||||
'@humanfs/core@0.19.1':
|
||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
|
|
@ -1403,6 +1415,10 @@ snapshots:
|
|||
'@eslint/core': 0.13.0
|
||||
levn: 0.4.1
|
||||
|
||||
'@fontsource-variable/inconsolata@5.2.5': {}
|
||||
|
||||
'@fontsource-variable/roboto@5.2.5': {}
|
||||
|
||||
'@humanfs/core@0.19.1': {}
|
||||
|
||||
'@humanfs/node@0.16.6':
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
.editor {
|
||||
padding: 2px;;
|
||||
}
|
||||
.editor.error {
|
||||
border: 1px solid red;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.offending .error {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.typeSignature {
|
||||
display: inline-block;
|
||||
/* display: none; */
|
||||
/* position: absolute; */
|
||||
z-index: 1;
|
||||
/* background-color: white; */
|
||||
/* border: 1px solid black; */
|
||||
}
|
||||
|
||||
.editor:hover > .typeSignature {
|
||||
|
|
@ -23,9 +27,4 @@
|
|||
.keyword {
|
||||
color: blue;
|
||||
font-weight: bold;
|
||||
/* vertical-align: top; */
|
||||
}
|
||||
|
||||
* {
|
||||
/* vertical-align: top; */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ export function Editor({state, setState, onCancel, suggestionPriority}: EditorPr
|
|||
}
|
||||
}
|
||||
const resolved = evalEditorBlock(state, env);
|
||||
return <span className="editor">
|
||||
return <span className={"editor" + ((resolved.kind==="error") ? " error" : "")}>
|
||||
{renderBlock()}
|
||||
<div className="typeSignature">
|
||||
:: <Type type={getType(resolved)} />
|
||||
|
|
|
|||
|
|
@ -1,26 +1,17 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@500&display=swap');
|
||||
|
||||
.inputBlock {
|
||||
position: relative;
|
||||
}
|
||||
.editable {
|
||||
position: relative;
|
||||
outline: 0px solid transparent;
|
||||
display: inline-block;
|
||||
border: 0;
|
||||
font-size: 13pt;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings: "wdth" 100;
|
||||
font-size: 10pt;
|
||||
font-family: var(--my-monospace-font);
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
.suggest {
|
||||
left: 0;
|
||||
top: 0;
|
||||
top: 2.4px;
|
||||
position: absolute;
|
||||
color: #aaa;
|
||||
}
|
||||
|
|
|
|||
37
src/eval.ts
37
src/eval.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { assignFnSubstitutions, dict, Double, fnType, getSymbol, growEnv, Int, makeGeneric, NotAFunctionError, prettyT, set, substitute, symbolFunction, trie, TYPE_VARS, UnifyError } from "dope2";
|
||||
import { assignFnSubstitutions, dict, Double, fnType, getSymbol, growEnv, Int, NotAFunctionError, prettyT, substitute, symbolFunction, trie, TYPE_VARS, UnifyError } from "dope2";
|
||||
|
||||
import type { EditorState } from "./Editor";
|
||||
import type { InputValueType, SuggestionType } from "./InputBlock";
|
||||
|
|
@ -68,13 +68,16 @@ export function evalInputBlock(text: string, value: InputValueType, env): Resolv
|
|||
...found,
|
||||
substitutions: new Map(),
|
||||
};
|
||||
} else {
|
||||
return entirelyUnknown(env);
|
||||
}
|
||||
}
|
||||
else { // kind === "text" -> unresolved
|
||||
return entirelyUnknown(env);
|
||||
}
|
||||
// kind === "text" -> unresolved
|
||||
return {
|
||||
kind: "error",
|
||||
t: getUnusedTypeVar(env),
|
||||
e: new Error(`'${text}' not found`),
|
||||
depth: 0,
|
||||
substitutions: new Map(),
|
||||
};
|
||||
}
|
||||
|
||||
const mergeMaps = (...maps: Map<Type,Type>[]) => {
|
||||
|
|
@ -166,7 +169,8 @@ export function evalCallBlock(fn: EditorState, input: EditorState, env): Resolve
|
|||
|
||||
export function evalLetInBlock(value: EditorState, name: string, inner: EditorState, env): ResolvedType {
|
||||
const valueResolved = evalEditorBlock(value, env);
|
||||
const innerEnv = makeInnerEnv(env, name, valueResolved)
|
||||
// console.log('eval', name, '...', valueResolved.kind, valueResolved.e);
|
||||
const innerEnv = makeInnerEnv(env, name, valueResolved);
|
||||
return evalEditorBlock(inner, innerEnv);
|
||||
}
|
||||
|
||||
|
|
@ -181,14 +185,29 @@ export function getUnusedTypeVar(env) {
|
|||
export function evalLambdaBlock(paramName: string, expr: EditorState, env): ResolvedType {
|
||||
const paramType = getUnusedTypeVar(env);
|
||||
// static env: we only know the name and the type
|
||||
const staticInnerEnv = makeInnerEnv(env, paramName, {
|
||||
const staticInnerEnv = growEnv(env)(paramName)({
|
||||
kind: "unknown", // parameter value is not statically known
|
||||
t: paramType,
|
||||
substitutions: new Map(),
|
||||
});
|
||||
})
|
||||
// const staticInnerEnv = makeInnerEnv(env, paramName, {
|
||||
// kind: "unknown", // parameter value is not statically known
|
||||
// t: paramType,
|
||||
// substitutions: new Map(),
|
||||
// });
|
||||
const exprResolved = evalEditorBlock(expr, staticInnerEnv);
|
||||
const lambdaT = fnType(_ => paramType)(_ => exprResolved.t);
|
||||
const lambdaTSubstituted = substitute(lambdaT, exprResolved.substitutions, []);
|
||||
// console.log('inner kind', exprResolved.kind, paramName);
|
||||
if (exprResolved.kind === "error") {
|
||||
return {
|
||||
kind: "error",
|
||||
t: lambdaTSubstituted,
|
||||
depth: 0,
|
||||
e: exprResolved.e,
|
||||
substitutions: staticInnerEnv.substitutions,
|
||||
}
|
||||
}
|
||||
const paramTypeSubstituted = lambdaTSubstituted.params[0](lambdaTSubstituted);
|
||||
const fn = (x: any) => {
|
||||
const innerEnv = makeInnerEnv(env, paramName, {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
|
||||
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Roboto", sans-serif;
|
||||
|
|
@ -8,6 +5,8 @@ body {
|
|||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-variation-settings: "wdth" 100;
|
||||
--my-monospace-font: 'Inconsolata', monospace;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
kbd {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ import { createRoot } from 'react-dom/client'
|
|||
import { App } from './App.tsx'
|
||||
import './index.css'
|
||||
|
||||
import '@fontsource-variable/inconsolata/standard.css';
|
||||
import '@fontsource-variable/roboto/standard.css';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue