yggdrasil/components/code_runner/runner/
body.rs1use super::{execution::Execution, RunnerExample};
10use crate::bridges::library::LibraryResource;
11use crate::theme::ResolvedTheme;
12use leptos::prelude::*;
13
14#[cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
16#[derive(Clone)]
17pub(super) struct RunnerBody {
18 pub language: String,
19 pub editor_mount: NodeRef<leptos::html::Div>,
20 pub output_mount: NodeRef<leptos::html::Div>,
21 pub example_output: Option<RunnerExample>,
22 pub source_signal: RwSignal<String>,
23 pub vim_enabled: RwSignal<bool>,
24 pub vim_mode: RwSignal<Option<String>>,
25 pub run: Callback<()>,
26 pub activated: RwSignal<bool>,
27 pub editor_ready: RwSignal<bool>,
28 pub editor_failed: RwSignal<bool>,
29 pub terminal_failed: RwSignal<bool>,
30 pub mount_retry: RwSignal<u32>,
31 pub editor_command: RwSignal<Option<String>>,
32 pub editor_library: LibraryResource,
33 pub terminal_library: LibraryResource,
34 pub execution: Execution,
35 pub resolved_theme: Memo<ResolvedTheme>,
36}
37
38#[leptos::lazy]
42pub(super) fn code_runner_body(args: RunnerBody) -> AnyView {
43 #[cfg(target_arch = "wasm32")]
44 mount(args);
45 #[cfg(not(target_arch = "wasm32"))]
46 let _ = args;
47 ().into_any()
48}
49
50#[cfg(target_arch = "wasm32")]
51fn mount(args: RunnerBody) {
52 use super::state::RunState;
53 use super::stream::{self, StreamHandle, TerminalSlot};
54 use super::{editor, terminal};
55
56 let RunnerBody {
57 language,
58 editor_mount,
59 output_mount,
60 example_output,
61 source_signal,
62 vim_enabled,
63 vim_mode,
64 run,
65 activated,
66 editor_ready,
67 editor_failed,
68 terminal_failed,
69 mount_retry,
70 editor_command,
71 editor_library,
72 terminal_library,
73 execution,
74 resolved_theme,
75 } = args;
76
77 editor::use_editor(
78 language,
79 editor_mount,
80 source_signal,
81 vim_enabled,
82 vim_mode,
83 run,
84 editor_ready,
85 editor_library,
86 activated,
87 editor_failed,
88 mount_retry,
89 editor_command,
90 resolved_theme,
91 );
92
93 let term_handle: TerminalSlot = StoredValue::new_local(None);
94 let terminal_ready = RwSignal::new(false);
95 terminal::use_terminal(
96 output_mount,
97 example_output,
98 execution,
99 terminal_library,
100 term_handle,
101 terminal_ready,
102 terminal_failed,
103 mount_retry,
104 resolved_theme,
105 );
106
107 let stream_handle: StoredValue<Option<StreamHandle>, LocalStorage> =
109 StoredValue::new_local(None);
110 on_cleanup(move || {
111 let _ = stream_handle.try_set_value(None);
112 });
113 Effect::new(move |_| {
114 if !execution.state.with(RunState::is_running) {
115 let _ = stream_handle.try_set_value(None);
116 }
117 });
118
119 Effect::new(move |_| {
122 if !terminal_ready.get() {
123 return;
124 }
125 let Some(request) = execution.pending.get() else {
126 return;
127 };
128 execution.pending.set(None);
129 stream_handle.set_value(None);
130 leptos::task::spawn_local(async move {
131 match crate::api::code_runner::execute::start_exec_stream(request).await {
132 Ok(id) => match stream::start(&id, execution, term_handle) {
133 Ok(handle) => drop(stream_handle.try_set_value(Some(handle))),
135 Err(_) => stream::poll_result(&id, execution, term_handle).await,
136 },
137 Err(error) => {
138 let _ = execution.state.try_set(RunState::rejected(&error));
139 }
140 }
141 });
142 });
143}