self-host fonts; proper error bubbling

This commit is contained in:
Joeri Exelmans 2025-05-17 18:01:31 +02:00
parent 68104a8102
commit 46baad7cf4
8 changed files with 63 additions and 34 deletions

View file

@ -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
View file

@ -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':

View file

@ -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; */
}

View file

@ -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">
&nbsp;::&nbsp;<Type type={getType(resolved)} />

View file

@ -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;
}

View file

@ -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, {

View file

@ -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 {

View file

@ -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 />