1use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7
8use ravenrs_live::{Fallback, FromLive, Host, Record, Registry, Value, bridge};
9use ravenrs_reactive::State;
10
11use crate::context::{BuildCx, NodeId};
12use crate::{AnyView, CodeDiagnostic, Runner, Spacer, Text, View};
13
14pub fn view<T: View + 'static>(registry: &mut Registry) {
16 registry.conversion::<T, AnyView>(bridge::host_name::<T>(), |view| Box::new(view));
17}
18
19impl FromLive for AnyView {
20 fn from_live(value: Value) -> Result<Self, String> {
21 match value.read() {
22 Value::Host(host) => host.take_as::<AnyView>(),
23 Value::Str(text) => Ok(Box::new(Text::new(text))),
25 Value::Unit | Value::Option(None) => Ok(Box::new(Spacer::new())),
26 Value::Option(Some(inner)) => AnyView::from_live(*inner),
27 Value::Record(record) if record.has_method("build") => Ok(Box::new(LiveView { record })),
29 other => Err(format!("expected a view, found {}", other.kind())),
30 }
31 }
32}
33
34impl Fallback for AnyView {
35 fn fallback() -> Self {
36 Box::new(Spacer::new())
37 }
38}
39
40fn generic_functions(registry: &mut Registry) {
42 registry.function("Text", "bound", |args: Vec<Value>| {
43 let [state, format] =
44 <[Value; 2]>::try_from(args).map_err(|_| "`bound` takes a state and a closure")?;
45 let state: State<Value> = State::<Value>::from_live(state)?;
46 let Value::Closure(format) = format.read() else { return Err("`bound` takes a closure".into()) };
47 let text = Text::bound(&state, move |value: &Value| match format.call(vec![value.clone()]) {
48 Ok(Value::Str(text)) => text,
49 Ok(other) => format!("{other:?}"),
50 Err(problem) => problem.message,
51 });
52 Ok(Value::Host(ravenrs_live::Host::new("Text", text)))
53 });
54}
55
56fn view_methods(registry: &mut Registry) {
58 use crate::ViewExt;
59 use ravenrs_core::Insets;
60
61 fn this(args: &[Value]) -> Result<AnyView, String> {
62 AnyView::from_live(args.first().cloned().unwrap_or(Value::Unit))
63 }
64 fn arg<T: FromLive>(args: &[Value], i: usize) -> Result<T, String> {
65 T::from_live(args.get(i).cloned().ok_or("an argument is missing")?)
66 }
67 fn styled(view: crate::Styled<AnyView>) -> Result<Value, String> {
68 Ok(Value::Host(ravenrs_live::Host::new("Styled", view)))
69 }
70 registry.method("View", "padding", |a| styled(this(&a)?.padding(arg::<Insets>(&a, 1)?)));
71 registry.method("View", "background", |a| {
72 let fill = match a.get(1).map(Value::read) {
73 Some(Value::Host(host)) => host.take_as::<crate::Fill>()?,
74 _ => return Err("a color or a semantic color goes here".to_owned()),
75 };
76 styled(this(&a)?.background(fill))
77 });
78 registry.method("View", "frame", |a| styled(this(&a)?.frame(arg(&a, 1)?, arg(&a, 2)?)));
79 registry.method("View", "width", |a| styled(this(&a)?.width(arg(&a, 1)?)));
80 registry.method("View", "height", |a| styled(this(&a)?.height(arg(&a, 1)?)));
81 registry.method("View", "grow", |a| styled(this(&a)?.grow(arg(&a, 1)?)));
82 registry.method("View", "stretch", |a| styled(this(&a)?.stretch()));
83 registry.method("View", "centered", |a| styled(this(&a)?.centered()));
84 registry.method("View", "tooltip", |a| {
85 let view = this(&a)?.tooltip(arg::<String>(&a, 1)?);
86 Ok(Value::Host(ravenrs_live::Host::new("Tooltip", view)))
87 });
88 registry.conversion::<ravenrs_style::Semantic, crate::Fill>("Semantic", crate::Fill::from);
89 registry.conversion::<ravenrs_core::Color, crate::Fill>("Color", crate::Fill::from);
90 registry.free_function("view_fn", |args: Vec<Value>| {
92 let Some(Value::Closure(make)) = args.first().map(Value::read) else {
93 return Err("`view_fn` takes a closure".into());
94 };
95 let view = crate::view_fn(move || {
96 match make.call(Vec::new()).and_then(|v| AnyView::from_live(v).map_err(|e| make.error(e))) {
97 Ok(view) => view,
98 Err(problem) => {
99 let shown: AnyView = Box::new(Text::new(problem.message));
100 shown
101 }
102 }
103 });
104 let view: AnyView = Box::new(view);
105 Ok(Value::Host(ravenrs_live::Host::new("AnyView", view)))
106 });
107}
108
109fn canvas(registry: &mut Registry) {
112 use ravenrs_core::{Rect, Scene};
113 registry.function("Canvas", "new", |args: Vec<Value>| {
114 let Some(Value::Closure(draw)) = args.first().map(Value::read) else {
115 return Err("`Canvas::new` takes a closure of the frame and the scene".into());
116 };
117 let canvas = crate::Canvas::new(move |frame: Rect, scene: &mut Scene| {
118 let own = ravenrs_live::Host::new("Scene", Scene::new());
119 let frame = Value::Host(ravenrs_live::Host::cloneable("Rect", frame));
120 if let Err(problem) = draw.call(vec![frame, Value::Host(own.clone())]) {
121 ravenrs_live::report(problem);
122 }
123 if let Ok(drawn) = own.take::<Scene>() {
124 scene.extend_from_slice(drawn.primitives());
125 }
126 });
127 Ok(Value::Host(ravenrs_live::Host::new("Canvas", canvas)))
128 });
129}
130
131struct LiveView {
134 record: Rc<Record>,
135}
136
137#[derive(Clone)]
140struct LiveCx {
141 states: Rc<RefCell<Vec<State<Value>>>>,
142 next: Rc<Cell<usize>>,
143 now: f64,
144 wake: Rc<Cell<Option<f64>>>,
145 child: Rc<RefCell<Option<AnyView>>>,
146}
147
148impl View for LiveView {
149 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
150 let states = cx.use_state(|| Rc::new(RefCell::new(Vec::<State<Value>>::new()))).get();
151 let live = LiveCx {
152 states,
153 next: Rc::new(Cell::new(0)),
154 now: cx.now(),
155 wake: Rc::new(Cell::new(None)),
156 child: Rc::new(RefCell::new(None)),
157 };
158 let given = Value::Host(Host::cloneable("BuildCx", live.clone()));
159 let built = Record::call_method(&self.record, "build", vec![given]);
160 if let Some(time) = live.wake.get() {
161 cx.wake_at(time);
162 }
163 let child = live.child.borrow_mut().take();
164 match (built, child) {
165 (Ok(_), Some(view)) => cx.child(&*view),
166 (Err(problem), _) => {
167 let text = Text::new(problem.to_string());
168 ravenrs_live::report(problem);
169 cx.child(&text)
170 }
171 (Ok(_), None) => cx.child(&Text::new("`build` gives its view with `cx.child(&view)`")),
172 }
173 }
174}
175
176fn build_cx(registry: &mut Registry) {
178 fn this(args: &[Value]) -> Result<LiveCx, String> {
179 match args.first().map(Value::read) {
180 Some(Value::Host(host)) => host.take::<LiveCx>(),
181 _ => Err("this is a method of `cx`".to_owned()),
182 }
183 }
184 registry.method("BuildCx", "use_state", |args| {
185 let cx = this(&args)?;
186 let at = cx.next.get();
187 cx.next.set(at + 1);
188 if let Some(state) = cx.states.borrow().get(at) {
189 return Ok(Value::State(state.clone()));
190 }
191 let first = match args.get(1).map(Value::read) {
192 Some(Value::Closure(init)) => init.call(Vec::new()).map_err(|e| e.message)?,
193 Some(other) => other,
194 None => Value::Unit,
195 };
196 let state = State::new(first);
197 cx.states.borrow_mut().push(state.clone());
198 Ok(Value::State(state))
199 });
200 registry.method("BuildCx", "child", |args| {
201 let cx = this(&args)?;
202 let view = AnyView::from_live(args.get(1).cloned().unwrap_or(Value::Unit))?;
203 *cx.child.borrow_mut() = Some(view);
204 Ok(Value::Host(Host::cloneable("NodeId", ())))
205 });
206 registry.method("BuildCx", "now", |args| Ok(Value::Float(this(&args)?.now)));
207 registry.method("BuildCx", "wake_at", |args| {
208 let cx = this(&args)?;
209 let time = f64::from_live(args.get(1).cloned().unwrap_or(Value::Unit))?;
210 cx.wake.set(Some(cx.wake.get().map_or(time, |t| t.min(time))));
211 Ok(Value::Unit)
212 });
213}
214
215fn playground(registry: &mut Registry) {
217 registry.function("Playground", "new", |args: Vec<Value>| {
218 let Some(Value::Closure(run)) = args.first().map(Value::read) else {
219 return Err("`Playground::new` takes a closure of the code".into());
220 };
221 let problem = |message: String| vec![CodeDiagnostic::error(1, 1, 1, message)];
222 let playground =
223 crate::Playground::new(move |source: &str| -> Result<AnyView, Vec<CodeDiagnostic>> {
224 let value = run.call(vec![Value::Str(source.to_owned())]).map_err(|e| problem(e.message))?;
225 match bridge::result(&value) {
226 Ok(view) => AnyView::from_live(view).map_err(problem),
227 Err(errors) => Err(errors
228 .items()
229 .map_err(problem)?
230 .into_iter()
231 .map(|e| match e.read() {
232 Value::Host(host) => host.take_as::<CodeDiagnostic>().map_err(problem),
233 other => {
234 Err(problem(format!("expected a CodeDiagnostic, found {}", other.kind())))
235 }
236 })
237 .collect::<Result<Vec<_>, _>>()?),
238 }
239 });
240 Ok(Value::Host(Host::new("Playground", playground)))
241 });
242}
243
244pub fn live_registry() -> Registry {
246 let mut registry = Registry::new();
247 crate::live_list::expose_all(&mut registry);
248 crate::VStack::<Vec<AnyView>>::__live_expose(&mut registry);
250 crate::HStack::<Vec<AnyView>>::__live_expose(&mut registry);
251 view::<crate::VStack<Vec<AnyView>>>(&mut registry);
252 view::<crate::HStack<Vec<AnyView>>>(&mut registry);
253 generic_functions(&mut registry);
254 view_methods(&mut registry);
255 canvas(&mut registry);
256 build_cx(&mut registry);
257 playground(&mut registry);
258 registry
259}
260
261#[derive(Clone)]
272pub struct LiveRunner {
273 registry: Rc<Registry>,
274}
275
276impl std::fmt::Debug for LiveRunner {
277 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278 f.debug_struct("LiveRunner").finish_non_exhaustive()
279 }
280}
281
282impl Default for LiveRunner {
283 fn default() -> Self {
284 Self::new()
285 }
286}
287
288impl LiveRunner {
289 pub fn new() -> Self {
291 Self::with_registry(live_registry())
292 }
293
294 pub fn with_registry(registry: Registry) -> Self {
296 Self { registry: Rc::new(registry) }
297 }
298}
299
300fn diagnostic(error: ravenrs_live::LiveError) -> CodeDiagnostic {
301 CodeDiagnostic::error(error.line, error.column, error.length, error.message)
302}
303
304impl Runner for LiveRunner {
305 fn run(&self, source: &str) -> Result<AnyView, Vec<CodeDiagnostic>> {
306 let value = ravenrs_live::run(source, None, self.registry.clone())
307 .map_err(|errors| errors.into_iter().map(diagnostic).collect::<Vec<_>>())?;
308 AnyView::from_live(value).map_err(|message| vec![CodeDiagnostic::error(1, 1, 1, message)])
309 }
310
311 fn take_output(&self) -> crate::RunOutput {
312 let problems = ravenrs_live::late_problems().into_iter().map(diagnostic).collect();
313 crate::RunOutput::new(ravenrs_live::printed(), problems)
314 }
315
316 fn watch(&self, wake: Rc<dyn Fn()>) {
317 ravenrs_live::on_output(move || wake());
318 }
319}