Skip to content

Commit

Permalink
draw separate nodes for variable bindings
Browse files Browse the repository at this point in the history
Signed-off-by: George Thomas <[email protected]>
  • Loading branch information
georgefst committed Nov 29, 2023
1 parent eb1bbff commit 4dc8c4f
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 52 deletions.
2 changes: 1 addition & 1 deletion argocd/base/statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ spec:
# Note: use the *dev* version of the package here, so that
# PRs can deploy `primer-service` container images that have
# not yet been merged to `primer` `main`.
image: ghcr.io/hackworthltd/primer-service-dev:git-4a105b7c084cdbf599acb2bc5bb9283d0eae46ff
image: ghcr.io/hackworthltd/primer-service-dev:git-bff48a8433d9cc24e2de54f0622343c99f76cba2
ports:
- containerPort: 8081
env:
Expand Down
8 changes: 4 additions & 4 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

# Note: don't override any of primer's Nix flake inputs, or else
# we won't hit its binary cache.
primer.url = github:hackworthltd/primer/4a105b7c084cdbf599acb2bc5bb9283d0eae46ff;
primer.url = github:hackworthltd/primer/bff48a8433d9cc24e2de54f0622343c99f76cba2;

flake-parts.url = "github:hercules-ci/flake-parts";
};
Expand Down
54 changes: 40 additions & 14 deletions src/components/TreeReactFlow/Flavor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ export const flavorClasses = (flavor: NodeFlavor): string =>
);
case "Lam":
return classNames(
"border-blue-primary ring-blue-primary bg-white-primary",
"border-blue-primary ring-blue-primary bg-blue-primary",
"hover:ring-blue-primary",
commonHoverClasses
);
case "LAM":
return classNames(
"border-blue-secondary ring-blue-secondary bg-white-primary",
"border-blue-secondary ring-blue-secondary bg-blue-secondary",
"hover:ring-blue-secondary",
commonHoverClasses
);
Expand All @@ -92,6 +92,7 @@ export const flavorClasses = (flavor: NodeFlavor): string =>
"hover:ring-blue-quaternary",
commonHoverClasses
);
case "VarBind":
case "LocalVar":
return classNames(
"border-blue-quaternary ring-blue-quaternary bg-white-primary",
Expand Down Expand Up @@ -157,6 +158,7 @@ export const flavorClasses = (flavor: NodeFlavor): string =>
"hover:ring-blue-primary",
commonHoverClasses
);
case "TVarBind":
case "TVar":
return classNames(
"border-blue-quaternary ring-blue-quaternary bg-white-primary",
Expand All @@ -171,7 +173,7 @@ export const flavorClasses = (flavor: NodeFlavor): string =>
);
case "TForall":
return classNames(
"border-blue-secondary ring-blue-secondary bg-white-primary",
"border-blue-secondary ring-blue-secondary bg-blue-secondary",
"hover:ring-blue-secondary",
commonHoverClasses
);
Expand Down Expand Up @@ -231,11 +233,12 @@ export const flavorContentClasses = (
case "KFun":
return "text-white-primary";
case "Lam":
return "text-blue-primary";
return "text-white-primary";
case "LAM":
return "text-blue-secondary";
return "text-white-primary";
case "GlobalVar":
return "text-blue-primary";
case "VarBind":
case "LocalVar":
return "text-blue-primary";
case "Let":
Expand All @@ -258,12 +261,13 @@ export const flavorContentClasses = (
return "text-blue-primary";
case "TFun":
return "text-white-primary";
case "TVarBind":
case "TVar":
return "text-blue-primary";
case "TApp":
return "text-white-primary";
case "TForall":
return "text-blue-secondary";
return "text-white-primary";
case "TLet":
return "text-white-primary";
case "PatternCon":
Expand Down Expand Up @@ -310,6 +314,7 @@ export const flavorLabelClasses = (flavor: NodeFlavor): string =>
return "font-code bg-grey-tertiary bg-grey-tertiary text-white-primary";
case "KFun":
return "font-code bg-grey-tertiary bg-grey-tertiary text-white-primary";
case "VarBind":
case "LocalVar":
return "bg-blue-quaternary border-blue-quaternary text-white-primary";
case "Let":
Expand All @@ -332,6 +337,7 @@ export const flavorLabelClasses = (flavor: NodeFlavor): string =>
return "bg-green-primary border-green-primary text-white-primary";
case "TFun":
return "font-code bg-blue-primary border-blue-primary text-white-primary";
case "TVarBind":
case "TVar":
return "bg-blue-quaternary border-blue-quaternary text-white-primary";
case "TApp":
Expand Down Expand Up @@ -420,6 +426,10 @@ export const flavorEdgeClasses = (flavor: NodeFlavor): string => {
return "stroke-grey-secondary";
case "PatternBind":
return "stroke-blue-quaternary";
case "VarBind":
return "stroke-blue-quaternary";
case "TVarBind":
return "stroke-blue-quaternary";
}
};

Expand Down Expand Up @@ -489,29 +499,29 @@ export const flavorLabel = (flavor: NodeFlavor): string => {
return "?";
case "KFun":
return "➜";
case "VarBind":
return "bind";
case "TVarBind":
return "type bind";
}
};

/** This is a slightly shaky concept, but essentially it comes down to whether labels can be omitted
* without destroying the readability of the program.
* In other words, would we show this flavor's label in text mode?
*/
// TODO this is now always false...
// among other things, makes `inlineLabels` basically meaningless without `alwaysShowLabels`
export const flavorIsSyntax = (flavor: NodeFlavorTextBody): boolean => {
switch (flavor) {
case "Lam":
case "LAM":
case "Let":
case "LetType":
case "Letrec":
case "TForall":
case "TLet":
return true;
case "Con":
case "GlobalVar":
case "LocalVar":
case "TCon":
case "TVar":
case "PatternCon":
case "VarBind":
case "TVarBind":
case "PatternBind":
return false;
}
Expand Down Expand Up @@ -549,6 +559,20 @@ export const noBodyFlavorContents = (flavor: NodeFlavorNoBody): string => {
return "kind hole";
case "KFun":
return "type constructor";
case "LAM":
return "type lambda";
case "Lam":
return "lambda";
case "Let":
return "let";
case "LetType":
return "let type";
case "Letrec":
return "recursive let";
case "TForall":
return "forall";
case "TLet":
return "type let";
}
};

Expand Down Expand Up @@ -586,6 +610,7 @@ export const flavorSort = (flavor: NodeFlavor): "term" | "type" | "kind" => {
case "CaseWith":
case "PatternWildcard":
case "PrimPattern":
case "VarBind":
return "term";
case "TCon":
case "TVar":
Expand All @@ -595,6 +620,7 @@ export const flavorSort = (flavor: NodeFlavor): "term" | "type" | "kind" => {
case "THole":
case "TFun":
case "TApp":
case "TVarBind":
return "type";
case "KFun":
case "KHole":
Expand Down
23 changes: 23 additions & 0 deletions src/components/TreeReactFlow/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ export const treeMap = <N1, N2, E>(
: {}),
});

export const treeMap1 = <N1, N2, E>(
t: Tree<N1, E>,
f: (n: Tree<N1, E>) => N2
): Tree<N2, E> => ({
node: f(t),
childTrees: t.childTrees.map(([t, e]) => [treeMap1(t, f), e]),
...(t.rightChild
? { rightChild: (([t, e]) => [treeMap1(t, f), e])(t.rightChild) }
: {}),
});

export const treeMap2 = <N, E>(
t: Tree<N, E>,
f: (n: Tree<N, E>) => Tree<N, E>
): Tree<N, E> =>
f({
node: t.node,
childTrees: t.childTrees.map(([t, e]) => [treeMap2(t, f), e]),
...(t.rightChild
? { rightChild: (([t, e]) => [treeMap2(t, f), e])(t.rightChild) }
: {}),
});

export const treeNodes = <N, E>({
node,
rightChild,
Expand Down
35 changes: 33 additions & 2 deletions src/components/TreeReactFlow/layoutTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { WasmLayoutType } from "@zxch3n/tidy/wasm_dist";
import { unzip } from "fp-ts/lib/Array";
import { fst, mapFst, mapSnd } from "fp-ts/lib/Tuple";
import { treeMap, Tree, Positioned, Padding } from "./Types";
import { treeMap, Tree, Positioned, Padding, treeMap2 } from "./Types";

export type LayoutParams = {
type: WasmLayoutType;
Expand Down Expand Up @@ -53,7 +53,38 @@ export const layoutTree = <
const minY = Math.min(
...nodes.map((n) => n.position.y - (n.data.padding?.top || 0))
);
const tree = treeMap(treeUnNormalized, (n) => ({
// Ensure that where a node has a single right-child with no children of its own,
// that child is drawn close to its parent, rather than evenly dsitributed among its parents' siblings.
// We should consider patching Tidy to allow us to do this sort of thing.
// As it stands, this is a bit of a hack, bit it's extremely useful for positioning variable-binding nodes.
const tree0 = treeMap2(treeUnNormalized, (t) => ({
node: t.node,
childTrees: t.childTrees,
...(!t.rightChild
? {}
: {
rightChild: [
t.rightChild[0].childTrees.length == 0
? {
...t.rightChild[0],
node: {
...t.rightChild[0].node,
position: {
x:
t.node.position.x +
p.margins.sibling +
t.node.data.width,
y: t.rightChild[0].node.position.y,
},
},
}
: t.rightChild[0],
t.rightChild[1],
],
}),
...(!t.rightChild ? {} : t.rightChild),
}));
const tree = treeMap(tree0, (n) => ({
...n,
// Ensure top-left is at (0,0). This makes the result easier to work with.
position: { x: n.position.x - minX, y: n.position.y - minY },
Expand Down
Loading

0 comments on commit 4dc8c4f

Please sign in to comment.