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