Finally can run the UI
This commit is contained in:
parent
115b457173
commit
49ef33f113
3 changed files with 95 additions and 159 deletions
|
|
@ -11,6 +11,7 @@ import { PriorityQueue } from "./priority_queue"
|
||||||
export type SignalRuntime = {
|
export type SignalRuntime = {
|
||||||
// Named signals (there are also nameless ones - and the distinction matters for garbage collection)
|
// Named signals (there are also nameless ones - and the distinction matters for garbage collection)
|
||||||
store: Map<SignalName, SignalRuntime.DAGNode>,
|
store: Map<SignalName, SignalRuntime.DAGNode>,
|
||||||
|
// TODO: consider tracking root nodes (and even the signal-closures with 0 bindings). Would be useful to build a global visualization of the DAG.
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExternalObserver = (state: Value) => void;
|
export type ExternalObserver = (state: Value) => void;
|
||||||
|
|
@ -18,6 +19,7 @@ export type UnsubscribeCapability = () => void;
|
||||||
|
|
||||||
export namespace SignalRuntime {
|
export namespace SignalRuntime {
|
||||||
// TODO: This is a terrible name. Looking for a new name... Just don't call it `Node`, which clashes with the builtin ts `Node` type all the time.
|
// TODO: This is a terrible name. Looking for a new name... Just don't call it `Node`, which clashes with the builtin ts `Node` type all the time.
|
||||||
|
// TODO: consider naming this `SignalId` actually...
|
||||||
export type DAGNode = {
|
export type DAGNode = {
|
||||||
signalName?: SignalName,
|
signalName?: SignalName,
|
||||||
signal: SignalValue,
|
signal: SignalValue,
|
||||||
|
|
@ -53,7 +55,7 @@ export function externalSubscribe(node: SignalRuntime.DAGNode, observer: Externa
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNode(program: Program, signalName: SignalName): SignalRuntime.DAGNode {
|
export function getNode(program: Program, signalName: SignalName): SignalRuntime.DAGNode {
|
||||||
const maybeNode = program.signal_runtimeNew.store.get(signalName);
|
const maybeNode = program.signal_runtime.store.get(signalName);
|
||||||
if (maybeNode === undefined) {
|
if (maybeNode === undefined) {
|
||||||
// TODO: Make this into a proper error
|
// TODO: Make this into a proper error
|
||||||
throw Error(`Signal '${signalName}' not found!`);
|
throw Error(`Signal '${signalName}' not found!`);
|
||||||
|
|
@ -63,19 +65,19 @@ export function getNode(program: Program, signalName: SignalName): SignalRuntime
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spawnSignal(program: Program, signalName: SignalName, expr: SignalExpr): SignalRuntime.DAGNode {
|
export function spawnSignal(program: Program, signalName: SignalName, expr: SignalExpr): SignalRuntime.DAGNode {
|
||||||
const maybeNode = program.signal_runtimeNew.store.get(signalName);
|
const maybeNode = program.signal_runtime.store.get(signalName);
|
||||||
if (maybeNode !== undefined) {
|
if (maybeNode !== undefined) {
|
||||||
// TODO: Make this into a proper error
|
// TODO: Make this into a proper error
|
||||||
throw Error(`Attempt to spawn a signal '${signalName}' that already exists`);
|
throw Error(`Attempt to spawn a signal '${signalName}' that already exists`);
|
||||||
}
|
}
|
||||||
const node = eval_signal_expression(program, Env.nil(), expr);
|
const node = eval_signal_expression(program, Env.nil(), expr);
|
||||||
node.signalName = signalName;
|
node.signalName = signalName;
|
||||||
program.signal_runtimeNew.store.set(signalName, node);
|
program.signal_runtime.store.set(signalName, node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spawnSource(program: Program, signalName: SignalName, initValue: Value): [SignalRuntime.DAGNode, (value: Value) => void] {
|
export function spawnSource(program: Program, signalName: SignalName, initValue: Value): [SignalRuntime.DAGNode, (value: Value) => void] {
|
||||||
const maybeNode = program.signal_runtimeNew.store.get(signalName);
|
const maybeNode = program.signal_runtime.store.get(signalName);
|
||||||
if (maybeNode !== undefined) {
|
if (maybeNode !== undefined) {
|
||||||
// TODO: Make this into a proper error
|
// TODO: Make this into a proper error
|
||||||
throw Error(`Attempt to spawn a signal '${signalName}' that already exists`);
|
throw Error(`Attempt to spawn a signal '${signalName}' that already exists`);
|
||||||
|
|
@ -90,7 +92,7 @@ export function spawnSource(program: Program, signalName: SignalName, initValue:
|
||||||
externalOutputs: [],
|
externalOutputs: [],
|
||||||
currentValue: initValue,
|
currentValue: initValue,
|
||||||
};
|
};
|
||||||
program.signal_runtimeNew.store.set(signalName, node);
|
program.signal_runtime.store.set(signalName, node);
|
||||||
|
|
||||||
|
|
||||||
function setValue(value: Value) {
|
function setValue(value: Value) {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import { eval_signal_expression, makeTickSignal, signal, Signal, SignalId, SignalRuntime } from "./eval/signal";
|
|
||||||
import { ThrownRuntimeError } from "./eval/error";
|
import { ThrownRuntimeError } from "./eval/error";
|
||||||
import { Env, Value } from "./eval/value";
|
import { Env, Value } from "./eval/value";
|
||||||
import { Expr, FunctionName, SignalName, ProductPattern, SignalExpr } from "./expr";
|
import { Expr, FunctionName, SignalName, ProductPattern, SignalExpr } from "./expr";
|
||||||
import { installPrimitives } from "./primitive";
|
import { installPrimitives } from "./primitive";
|
||||||
import { eval_expr } from "./eval/evaluator";
|
import { eval_expr } from "./eval/evaluator";
|
||||||
import { SignalRuntime as SignalRuntimeNew} from "./eval/signalValue"
|
import { eval_signal_expression, spawnTick, spawnSignal, SignalRuntime, getNode, spawnSource } from "./eval/signalValue"
|
||||||
|
|
||||||
export type Timestamp = number;
|
export type Timestamp = number;
|
||||||
|
|
||||||
|
type SignalId = SignalRuntime.DAGNode;
|
||||||
|
|
||||||
export type Program = {
|
export type Program = {
|
||||||
function_definitions: Map<FunctionName, FunctionDefinition>,
|
function_definitions: Map<FunctionName, FunctionDefinition>,
|
||||||
function_definition_order: FunctionName[],
|
function_definition_order: FunctionName[],
|
||||||
|
|
@ -15,9 +16,6 @@ export type Program = {
|
||||||
signal_definitions: Map<SignalName, SignalDefinition>,
|
signal_definitions: Map<SignalName, SignalDefinition>,
|
||||||
signal_definition_order: SignalName[],
|
signal_definition_order: SignalName[],
|
||||||
|
|
||||||
signal_runtimeNew: SignalRuntimeNew,
|
|
||||||
|
|
||||||
// TODO: Get rid of the old Runtime
|
|
||||||
signal_runtime: SignalRuntime,
|
signal_runtime: SignalRuntime,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -74,7 +72,7 @@ type CellDefinition = {
|
||||||
|
|
||||||
body: Expr,
|
body: Expr,
|
||||||
|
|
||||||
signalId?: SignalId,
|
cell?: [SignalId, (value: Value) => void],
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
createdAt: Timestamp,
|
createdAt: Timestamp,
|
||||||
|
|
@ -82,7 +80,7 @@ type CellDefinition = {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrimitiveSignalDefinition = {
|
type PrimitiveSignalDefinition = {
|
||||||
name: FunctionName,
|
name: SignalName,
|
||||||
signalId: SignalId,
|
signalId: SignalId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +127,6 @@ export namespace Program {
|
||||||
function_definitions: new Map(),
|
function_definitions: new Map(),
|
||||||
function_definition_order: [],
|
function_definition_order: [],
|
||||||
|
|
||||||
signal_runtimeNew: SignalRuntimeNew.make(),
|
|
||||||
signal_runtime: SignalRuntime.make(),
|
signal_runtime: SignalRuntime.make(),
|
||||||
signal_definitions: new Map(),
|
signal_definitions: new Map(),
|
||||||
signal_definition_order: [],
|
signal_definition_order: [],
|
||||||
|
|
@ -167,11 +164,11 @@ export namespace Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_primitive_signals(program: Program) {
|
function install_primitive_signals(program: Program) {
|
||||||
install_primitive_signal(program, "tick",makeTickSignal(1000));
|
const signalId = spawnTick(program, "tick", 1000);
|
||||||
|
install_primitive_signal(program, "tick", signalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_primitive_signal(program: Program, name: SignalName, signal: Signal<Value>) {
|
function install_primitive_signal(program: Program, name: SignalName, signalId: SignalId) {
|
||||||
const signalId = attachNewSignal(program, signal);
|
|
||||||
const def: SignalDefinition = {
|
const def: SignalDefinition = {
|
||||||
tag: "primitive",
|
tag: "primitive",
|
||||||
def: { name, signalId }
|
def: { name, signalId }
|
||||||
|
|
@ -180,19 +177,14 @@ export namespace Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
// may throw `ThrownRuntimeError`. This is used during initialization.
|
// may throw `ThrownRuntimeError`. This is used during initialization.
|
||||||
export function get_or_create_signal(program: Program, name: SignalName): Signal<Value> {
|
export function get_or_create_signal(program: Program, name: SignalName): SignalId {
|
||||||
const sigDef = lookup_signal_definition(program, name);
|
const sigDef = lookup_signal_definition(program, name);
|
||||||
|
|
||||||
switch (sigDef.tag) {
|
switch (sigDef.tag) {
|
||||||
case "user": {
|
case "user": {
|
||||||
const def = sigDef.def;
|
const def = sigDef.def;
|
||||||
if (def.signalId !== undefined) {
|
if (def.signalId !== undefined) {
|
||||||
const signal = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
return def.signalId;
|
||||||
if (signal === undefined) {
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name, });
|
|
||||||
} else {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to create the signal for the first time.
|
// We need to create the signal for the first time.
|
||||||
|
|
@ -202,90 +194,28 @@ export namespace Program {
|
||||||
def.is_initializing = true;
|
def.is_initializing = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const newSignal = eval_signal_expression(program, Env.nil(), def.body);
|
const newId = spawnSignal(program, name, def.body);
|
||||||
const newId = attachNewSignal(program, newSignal);
|
|
||||||
program.signal_runtime.store.set(newId, newSignal);
|
|
||||||
def.signalId = newId;
|
def.signalId = newId;
|
||||||
|
|
||||||
return newSignal;
|
return newId;
|
||||||
} finally {
|
} finally {
|
||||||
def.is_initializing = false;
|
def.is_initializing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "cell": {
|
case "cell": {
|
||||||
const def = sigDef.def;
|
const def = sigDef.def;
|
||||||
if (def.signalId !== undefined) {
|
if (def.cell !== undefined) {
|
||||||
const signal = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
return def.cell[0];
|
||||||
if (signal === undefined) {
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name, });
|
|
||||||
} else {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to create the cell-signal for the first time.
|
// We need to create the cell-signal for the first time.
|
||||||
const initialValue = eval_expr(program, Env.nil(), def.body);
|
const initialValue = eval_expr(program, Env.nil(), def.body);
|
||||||
const sig = signal(initialValue);
|
const cell = spawnSource(program, name, initialValue)
|
||||||
const id = attachNewSignal(program, sig);
|
def.cell = cell;
|
||||||
def.signalId = id;
|
return cell[0];
|
||||||
return sig;
|
|
||||||
}
|
}
|
||||||
case "primitive": {
|
case "primitive": {
|
||||||
const def = sigDef.def;
|
return sigDef.def.signalId;
|
||||||
const signal = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
|
||||||
if (signal === undefined) {
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name, });
|
|
||||||
} else {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function attachNewSignal(program: Program, signal: Signal<Value>): SignalId {
|
|
||||||
const newId = SignalRuntime.generateSignalId(program.signal_runtime);
|
|
||||||
program.signal_runtime.store.set(newId, signal);
|
|
||||||
return newId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Is this necessary? Maybe `get_or_create_signal` is sufficient for all cases.
|
|
||||||
// may throw `ThrownRuntimeError`. This is used by evaluator.
|
|
||||||
export function lookup_signal(program: Program, name: SignalName): Signal<Value> {
|
|
||||||
const sigDef = lookup_signal_definition(program, name);
|
|
||||||
|
|
||||||
switch (sigDef.tag) {
|
|
||||||
case "user": {
|
|
||||||
const def = sigDef.def;
|
|
||||||
if (def.signalId === undefined) {
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalLookupFailure", name, });
|
|
||||||
}
|
|
||||||
const signal = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
|
||||||
if (signal === undefined){
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalLookupFailure", name, });
|
|
||||||
} else {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "cell": {
|
|
||||||
const def = sigDef.def;
|
|
||||||
if (def.signalId === undefined) {
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalLookupFailure", name, });
|
|
||||||
}
|
|
||||||
const signal = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
|
||||||
if (signal === undefined){
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalLookupFailure", name, });
|
|
||||||
} else {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "primitive": {
|
|
||||||
const def = sigDef.def;
|
|
||||||
const signal = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
|
||||||
if (signal === undefined) {
|
|
||||||
throw ThrownRuntimeError.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name, });
|
|
||||||
} else {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -431,7 +361,7 @@ export namespace Program {
|
||||||
raw_body: string,
|
raw_body: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateSignal(
|
export function updateSignal(
|
||||||
program: Program,
|
program: Program,
|
||||||
name: SignalName,
|
name: SignalName,
|
||||||
{ body, raw_body }: UpdateSignal
|
{ body, raw_body }: UpdateSignal
|
||||||
|
|
@ -468,32 +398,33 @@ export function updateSignal(
|
||||||
return Result.ok(undefined);
|
return Result.ok(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteSignal(program: Program, name: SignalName): Result<void> {
|
// TODO: This needs careful thought about transitive dependencies of a signal
|
||||||
const existingEntry = program.signal_definitions.get(name);
|
// export function deleteSignal(program: Program, name: SignalName): Result<void> {
|
||||||
|
// const existingEntry = program.signal_definitions.get(name);
|
||||||
|
|
||||||
if (!existingEntry) {
|
// if (!existingEntry) {
|
||||||
return Result.error({ tag: "SignalNotFound", name } as any);
|
// return Result.error({ tag: "SignalNotFound", name } as any);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (existingEntry.tag === "primitive") {
|
// if (existingEntry.tag === "primitive") {
|
||||||
return Result.error({ tag: "CannotDeletePrimitiveSignal", name } as any);
|
// return Result.error({ tag: "CannotDeletePrimitiveSignal", name } as any);
|
||||||
}
|
// }
|
||||||
|
|
||||||
program.signal_definitions.delete(name);
|
// program.signal_definitions.delete(name);
|
||||||
|
|
||||||
const orderIndex = program.signal_definition_order.indexOf(name);
|
// const orderIndex = program.signal_definition_order.indexOf(name);
|
||||||
if (orderIndex !== -1) {
|
// if (orderIndex !== -1) {
|
||||||
program.signal_definition_order.splice(orderIndex, 1);
|
// program.signal_definition_order.splice(orderIndex, 1);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// TODO:
|
// // TODO:
|
||||||
// Note: The old signal instance still exists in program.signal_runtime.store
|
// // Note: The old signal instance still exists in program.signal_runtime.store
|
||||||
// We technically leak memory here unless we also remove it from the runtime store.
|
// // We technically leak memory here unless we also remove it from the runtime store.
|
||||||
// However, since other signals might still depend on that ID,
|
// // However, since other signals might still depend on that ID,
|
||||||
// leaving it is actually safer for now to prevent crashes.
|
// // leaving it is actually safer for now to prevent crashes.
|
||||||
|
|
||||||
return Result.ok(undefined);
|
// return Result.ok(undefined);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// === Cells ===
|
// === Cells ===
|
||||||
export type CreateCell = {
|
export type CreateCell = {
|
||||||
|
|
@ -502,34 +433,35 @@ export function updateSignal(
|
||||||
raw_body: string,
|
raw_body: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor pending
|
||||||
export function registerCell(
|
export function registerCell(
|
||||||
program: Program,
|
program: Program,
|
||||||
{ name, body, raw_body }: CreateCell
|
{ name, body, raw_body }: CreateCell
|
||||||
): Result<void> {
|
): Result<void> {
|
||||||
|
|
||||||
if (program.signal_definitions.has(name)) {
|
// if (program.signal_definitions.has(name)) {
|
||||||
return Result.error({ tag: "DuplicateSignalName", name });
|
// return Result.error({ tag: "DuplicateSignalName", name });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const now: Timestamp = Date.now();
|
// const now: Timestamp = Date.now();
|
||||||
|
|
||||||
// TODO: MAY THROW RuntimeError. Should probably switch to `eval_start` - and extend the `Program.Error` with runtime errors.
|
// // TODO: MAY THROW RuntimeError. Should probably switch to `eval_start` - and extend the `Program.Error` with runtime errors.
|
||||||
const initialValue = eval_expr(program, Env.nil(), body);
|
// const initialValue = eval_expr(program, Env.nil(), body);
|
||||||
|
|
||||||
const sig = signal(initialValue);
|
// const sig = signal(initialValue);
|
||||||
const signalId = attachNewSignal(program, sig);
|
// const signalId = attachNewSignal(program, sig);
|
||||||
|
|
||||||
const newCell: CellDefinition = {
|
// const newCell: CellDefinition = {
|
||||||
name,
|
// name,
|
||||||
raw_body,
|
// raw_body,
|
||||||
body,
|
// body,
|
||||||
signalId,
|
// signalId,
|
||||||
createdAt: now,
|
// createdAt: now,
|
||||||
lastModifiedAt: now,
|
// lastModifiedAt: now,
|
||||||
};
|
// };
|
||||||
|
|
||||||
program.signal_definitions.set(name, { tag: "cell", def: newCell });
|
// program.signal_definitions.set(name, { tag: "cell", def: newCell });
|
||||||
program.signal_definition_order.push(name);
|
// program.signal_definition_order.push(name);
|
||||||
|
|
||||||
return Result.ok(undefined);
|
return Result.ok(undefined);
|
||||||
}
|
}
|
||||||
|
|
@ -539,44 +471,45 @@ export function updateSignal(
|
||||||
raw_body: string,
|
raw_body: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor pending
|
||||||
export function updateCell(
|
export function updateCell(
|
||||||
program: Program,
|
program: Program,
|
||||||
name: SignalName,
|
name: SignalName,
|
||||||
{ body, raw_body }: UpdateCell
|
{ body, raw_body }: UpdateCell
|
||||||
): Result<void> {
|
): Result<void> {
|
||||||
const existingEntry = program.signal_definitions.get(name);
|
// const existingEntry = program.signal_definitions.get(name);
|
||||||
|
|
||||||
if (!existingEntry) {
|
// if (!existingEntry) {
|
||||||
return Result.error({ tag: "SignalNotFound", name } as any);
|
// return Result.error({ tag: "SignalNotFound", name } as any);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Ensure we are editing a Cell
|
// // Ensure we are editing a Cell
|
||||||
if (existingEntry.tag !== "cell") {
|
// if (existingEntry.tag !== "cell") {
|
||||||
return Result.error({ tag: "CannotEditCell", name } as any);
|
// return Result.error({ tag: "CannotEditCell", name } as any);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const def = existingEntry.def;
|
// const def = existingEntry.def;
|
||||||
|
|
||||||
// TODO: MAY THROW RuntimeError. Should probably switch to `eval_start` - and extend the `Program.Error` with runtime errors.
|
// // TODO: MAY THROW RuntimeError. Should probably switch to `eval_start` - and extend the `Program.Error` with runtime errors.
|
||||||
const newValue = eval_expr(program, Env.nil(), body);
|
// const newValue = eval_expr(program, Env.nil(), body);
|
||||||
|
|
||||||
// Find the existing runtime signal
|
// // Find the existing runtime signal
|
||||||
if (def.signalId === undefined) {
|
// if (def.signalId === undefined) {
|
||||||
// This should theoretically not happen for cells since we initialize them eagerly,
|
// // This should theoretically not happen for cells since we initialize them eagerly,
|
||||||
// but good to be safe.
|
// // but good to be safe.
|
||||||
return Result.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name } as any);
|
// return Result.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name } as any);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const sig = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
// const sig = SignalRuntime.getSignal(program.signal_runtime, def.signalId);
|
||||||
if (!sig) {
|
// if (!sig) {
|
||||||
return Result.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name } as any);
|
// return Result.error({ tag: "SignalDefinitionHasSignalIdWithoutSignal", name } as any);
|
||||||
}
|
// }
|
||||||
|
|
||||||
sig.set(() => newValue);
|
// sig.set(() => newValue);
|
||||||
|
|
||||||
def.body = body;
|
// def.body = body;
|
||||||
def.raw_body = raw_body;
|
// def.raw_body = raw_body;
|
||||||
def.lastModifiedAt = Date.now();
|
// def.lastModifiedAt = Date.now();
|
||||||
|
|
||||||
return Result.ok(undefined);
|
return Result.ok(undefined);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { updateDigith } from "src/ui/Scrowl/scrowlStore";
|
||||||
import { DigithError } from "src/ui/Digith/DigithError";
|
import { DigithError } from "src/ui/Digith/DigithError";
|
||||||
import { Value } from "src/lang/eval/value";
|
import { Value } from "src/lang/eval/value";
|
||||||
import { Val } from "src/ui/Component/Value";
|
import { Val } from "src/ui/Component/Value";
|
||||||
|
import { externalSubscribe } from "src/lang/eval/signalValue";
|
||||||
|
|
||||||
type Input = {
|
type Input = {
|
||||||
raw_body: string,
|
raw_body: string,
|
||||||
|
|
@ -50,9 +51,9 @@ export function SignalDigith(props: { signal: Digith.Signal }) {
|
||||||
const signal = Program.get_or_create_signal(program, props.signal.name);
|
const signal = Program.get_or_create_signal(program, props.signal.name);
|
||||||
|
|
||||||
// TODO: Not sure about this one. Setting a signal in `setValue` is discouraged.
|
// TODO: Not sure about this one. Setting a signal in `setValue` is discouraged.
|
||||||
setTimeout(() => setValue(signal.read()), 0);
|
setTimeout(() => setValue(signal.currentValue), 0);
|
||||||
|
|
||||||
const cancel = signal.subscribe((newValue) => {
|
const cancel = externalSubscribe(signal, (newValue) => {
|
||||||
setValue(newValue);
|
setValue(newValue);
|
||||||
});
|
});
|
||||||
onCleanup(cancel);
|
onCleanup(cancel);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue