1use std::{env, fs, io, panic, path::Path, time::Duration};
2
3use crate::{
4 client::ClientManager,
5 command::CommandManager,
6 editor::{Editor, EditorContext, EditorFlow},
7 editor_utils::{LogKind, REGISTER_READLINE_INPUT},
8 events::{ClientEvent, ClientEventReceiver, ServerEvent, TargetClient},
9 platform::{Key, Platform, PlatformEvent, PlatformRequest, ProcessTag},
10 plugin::{PluginCollection, PluginDefinition},
11 serialization::{DeserializeError, Serialize},
12 ui, Args, ResourceFile,
13};
14
15#[derive(Default, Clone, Copy)]
16pub struct OnPanicConfig {
17 pub write_info_to_file: Option<&'static Path>,
18 pub try_attaching_debugger: bool,
19}
20
21pub struct ApplicationConfig {
22 pub args: Args,
23 pub plugin_definitions: Vec<PluginDefinition>,
24 pub static_configs: Vec<ResourceFile>,
25 pub on_panic_config: OnPanicConfig,
26}
27impl Default for ApplicationConfig {
28 fn default() -> Self {
29 Self {
30 args: Args::parse(),
31 static_configs: vec![crate::DEFAULT_CONFIGS, crate::DEFAULT_SYNTAXES],
32 plugin_definitions: Vec::new(),
33 on_panic_config: OnPanicConfig::default(),
34 }
35 }
36}
37
38pub const SERVER_CONNECTION_BUFFER_LEN: usize = 4 * 1024;
39pub const SERVER_IDLE_DURATION: Duration = Duration::from_secs(1);
40
41pub struct ServerApplication {
42 pub ctx: EditorContext,
43 client_event_receiver: ClientEventReceiver,
44}
45impl ServerApplication {
46 pub fn new(config: ApplicationConfig) -> Option<Self> {
47 let current_dir = env::current_dir().unwrap_or_default();
48
49 let mut ctx = EditorContext {
50 editor: Editor::new(current_dir, config.args.session_name),
51 platform: Platform::default(),
52 clients: ClientManager::default(),
53 plugins: PluginCollection::default(),
54 };
55
56 for definition in config.plugin_definitions {
57 PluginCollection::add(&mut ctx, definition);
58 }
59
60 for config in &config.static_configs {
61 let result = CommandManager::eval(&mut ctx, None, config.name, config.content);
62 let flow = CommandManager::unwrap_eval_result(&mut ctx, result);
63 if !matches!(flow, EditorFlow::Continue) {
64 return None;
65 }
66 }
67
68 for config in config.args.configs {
69 let path = Path::new(&config.path);
70 if config.suppress_file_not_found && !path.exists() {
71 continue;
72 }
73 match fs::read_to_string(path) {
74 Ok(source) => {
75 let path = path.to_str().unwrap_or("");
76 let result = CommandManager::eval(&mut ctx, None, path, &source);
77 let flow = CommandManager::unwrap_eval_result(&mut ctx, result);
78 if !matches!(flow, EditorFlow::Continue) {
79 return None;
80 }
81 }
82 Err(_) => ctx
83 .editor
84 .logger
85 .write(LogKind::Error)
86 .fmt(format_args!("could not load config '{}'", config.path)),
87 }
88 }
89
90 Some(Self {
91 ctx,
92 client_event_receiver: ClientEventReceiver::default(),
93 })
94 }
95
96 pub fn update<I>(&mut self, events: I)
97 where
98 I: Iterator<Item = PlatformEvent>,
99 {
100 for event in events {
101 match event {
102 PlatformEvent::Idle => {
103 self.ctx.editor.on_idle();
104 self.ctx.trigger_event_handlers();
105 }
106 PlatformEvent::ConnectionOpen { handle } => {
107 self.ctx.clients.on_client_joined(handle)
108 }
109 PlatformEvent::ConnectionClose { handle } => {
110 self.ctx
111 .editor
112 .buffer_views
113 .remove_buffer_views_with_client(handle);
114 self.ctx.clients.on_client_left(handle);
115 if self.ctx.clients.iter().next().is_none() {
116 self.ctx.platform.requests.enqueue(PlatformRequest::Quit);
117 }
118 }
119 PlatformEvent::ConnectionOutput { handle, buf } => {
120 let mut events = self
121 .client_event_receiver
122 .receive_events(handle, buf.as_bytes());
123 self.ctx.platform.buf_pool.release(buf);
124
125 while let Some(event) = events.next(&self.client_event_receiver) {
126 match Editor::on_client_event(&mut self.ctx, handle, event) {
127 EditorFlow::Continue => (),
128 EditorFlow::Suspend => {
129 let mut buf = self.ctx.platform.buf_pool.acquire();
130 ServerEvent::Suspend.serialize(buf.write());
131 self.ctx
132 .platform
133 .requests
134 .enqueue(PlatformRequest::WriteToClient { handle, buf });
135 }
136 EditorFlow::Quit => self
137 .ctx
138 .platform
139 .requests
140 .enqueue(PlatformRequest::CloseClient { handle }),
141 EditorFlow::QuitAll => {
142 self.ctx.platform.requests.enqueue(PlatformRequest::Quit)
143 }
144 }
145 }
146 events.finish(&mut self.client_event_receiver);
147 }
148 PlatformEvent::ProcessSpawned { tag, handle } => {
149 match tag {
150 ProcessTag::Ignored => (),
151 ProcessTag::Buffer(index) => self.ctx.editor.buffers.on_process_spawned(
152 &mut self.ctx.platform,
153 index,
154 handle,
155 ),
156 ProcessTag::PickerEntries => self
157 .ctx
158 .editor
159 .picker_entries_process_buf
160 .on_process_spawned(),
161 ProcessTag::Plugin { plugin_handle, id } => {
162 PluginCollection::on_process_spawned(
163 &mut self.ctx,
164 plugin_handle,
165 id,
166 handle,
167 )
168 }
169 }
170 self.ctx.trigger_event_handlers();
171 }
172 PlatformEvent::ProcessOutput { tag, buf } => {
173 let bytes = buf.as_bytes();
174 match tag {
175 ProcessTag::Ignored => (),
176 ProcessTag::Buffer(index) => self.ctx.editor.buffers.on_process_output(
177 &mut self.ctx.editor.word_database,
178 index,
179 bytes,
180 self.ctx.editor.events.writer(),
181 ),
182 ProcessTag::PickerEntries => self
183 .ctx
184 .editor
185 .picker_entries_process_buf
186 .on_process_output(
187 &mut self.ctx.editor.picker,
188 self.ctx.editor.registers.get(REGISTER_READLINE_INPUT),
189 bytes,
190 ),
191 ProcessTag::Plugin { plugin_handle, id } => {
192 PluginCollection::on_process_output(
193 &mut self.ctx,
194 plugin_handle,
195 id,
196 bytes,
197 )
198 }
199 }
200 self.ctx.trigger_event_handlers();
201 self.ctx.platform.buf_pool.release(buf);
202 }
203 PlatformEvent::ProcessExit { tag } => {
204 match tag {
205 ProcessTag::Ignored => (),
206 ProcessTag::Buffer(index) => self.ctx.editor.buffers.on_process_exit(
207 &mut self.ctx.editor.word_database,
208 index,
209 self.ctx.editor.events.writer(),
210 ),
211 ProcessTag::PickerEntries => {
212 self.ctx.editor.picker_entries_process_buf.on_process_exit(
213 &mut self.ctx.editor.picker,
214 self.ctx.editor.registers.get(REGISTER_READLINE_INPUT),
215 )
216 }
217 ProcessTag::Plugin { plugin_handle, id } => {
218 PluginCollection::on_process_exit(&mut self.ctx, plugin_handle, id)
219 }
220 }
221 self.ctx.trigger_event_handlers();
222 }
223 PlatformEvent::IpcConnected { tag, handle } => {
224 PluginCollection::on_ipc_connected(
225 &mut self.ctx,
226 tag.plugin_handle,
227 tag.id,
228 handle,
229 );
230 self.ctx.trigger_event_handlers();
231 }
232 PlatformEvent::IpcOutput { tag, buf } => {
233 PluginCollection::on_ipc_output(
234 &mut self.ctx,
235 tag.plugin_handle,
236 tag.id,
237 buf.as_bytes(),
238 );
239 self.ctx.trigger_event_handlers();
240 self.ctx.platform.buf_pool.release(buf);
241 }
242 PlatformEvent::IpcClose { tag } => {
243 PluginCollection::on_ipc_close(&mut self.ctx, tag.plugin_handle, tag.id);
244 self.ctx.trigger_event_handlers();
245 }
246 }
247 }
248
249 self.ctx.editor.events.assert_empty();
250 self.ctx.render();
251 }
252}
253
254pub const CLIENT_STDIN_BUFFER_LEN: usize = 4 * 1024;
255pub const CLIENT_CONNECTION_BUFFER_LEN: usize = 4 * 1024;
256
257pub struct ClientApplication<O>
258where
259 O: io::Write,
260{
261 target_client: TargetClient,
262 server_read_buf: Vec<u8>,
263 server_write_buf: Vec<u8>,
264 pub output: Option<O>,
265 stdout_buf: Vec<u8>,
266}
267impl<O> ClientApplication<O>
268where
269 O: io::Write,
270{
271 pub fn new() -> Self {
272 Self {
273 target_client: TargetClient::Sender,
274 server_read_buf: Vec::new(),
275 server_write_buf: Vec::new(),
276 output: None,
277 stdout_buf: Vec::new(),
278 }
279 }
280
281 pub fn init(&mut self, args: Args) -> &[u8] {
282 if args.as_focused_client {
283 self.target_client = TargetClient::Focused;
284 }
285
286 self.server_write_buf.clear();
287
288 self.reinit_screen();
289 if !args.quit && !args.as_focused_client {
290 ClientEvent::Key(self.target_client, Key::default())
291 .serialize(&mut self.server_write_buf);
292 }
293
294 let mut commands = String::new();
295 for path in &args.files {
296 commands.clear();
297 commands.push_str("open \"");
298 for c in path.chars() {
299 match c {
300 '\\' => commands.push_str("\\\\"),
301 '"' => commands.push_str("\\\""),
302 c => commands.push(c),
303 }
304 }
305 commands.push('"');
306 ClientEvent::Commands(self.target_client, &commands)
307 .serialize(&mut self.server_write_buf);
308 }
309
310 if args.quit {
311 ClientEvent::Commands(TargetClient::Sender, "quit")
312 .serialize(&mut self.server_write_buf);
313 }
314
315 self.server_write_buf.as_slice()
316 }
317
318 pub fn reinit_screen(&mut self) {
319 if let Some(output) = &mut self.output {
320 let _ = output.write_all(ui::ENTER_ALTERNATE_BUFFER_CODE);
321 let _ = output.write_all(ui::HIDE_CURSOR_CODE);
322 let _ = output.write_all(ui::MODE_256_COLORS_CODE);
323 let _ = output.flush();
324 }
325 }
326
327 pub fn restore_screen(&mut self) {
328 if let Some(output) = &mut self.output {
329 let _ = output.write_all(ui::EXIT_ALTERNATE_BUFFER_CODE);
330 let _ = output.write_all(ui::SHOW_CURSOR_CODE);
331 let _ = output.write_all(ui::RESET_STYLE_CODE);
332 let _ = output.flush();
333 }
334 }
335
336 pub fn update(
337 &mut self,
338 resize: Option<(u16, u16)>,
339 keys: &[Key],
340 stdin_bytes: Option<&[u8]>,
341 server_bytes: &[u8],
342 ) -> (bool, &'_ [u8]) {
343 self.server_write_buf.clear();
344
345 if let Some((width, height)) = resize {
346 ClientEvent::Resize(width, height).serialize(&mut self.server_write_buf);
347 }
348
349 for key in keys {
350 ClientEvent::Key(self.target_client, *key).serialize(&mut self.server_write_buf);
351 }
352
353 if let Some(bytes) = stdin_bytes {
354 ClientEvent::StdinInput(self.target_client, bytes)
355 .serialize(&mut self.server_write_buf);
356 }
357
358 let mut suspend = false;
359 if !server_bytes.is_empty() {
360 self.server_read_buf.extend_from_slice(server_bytes);
361 let mut read_slice = &self.server_read_buf[..];
362
363 loop {
364 let previous_slice = read_slice;
365 match ServerEvent::deserialize(&mut read_slice) {
366 Ok(ServerEvent::Display(display)) => {
367 if let Some(output) = &mut self.output {
368 output.write_all(display).unwrap();
369 }
370 }
371 Ok(ServerEvent::Suspend) => suspend = true,
372 Ok(ServerEvent::StdoutOutput(bytes)) => {
373 self.stdout_buf.clear();
374 self.stdout_buf.extend_from_slice(bytes);
375 }
376 Err(DeserializeError::InsufficientData) => {
377 let read_len = self.server_read_buf.len() - previous_slice.len();
378 self.server_read_buf.drain(..read_len);
379 break;
380 }
381 Err(DeserializeError::InvalidData) => {
382 panic!("client received invalid data from server")
383 }
384 }
385 }
386
387 if let Some(output) = &mut self.output {
388 output.flush().unwrap();
389 }
390 }
391
392 (suspend, self.server_write_buf.as_slice())
393 }
394
395 pub fn get_stdout_bytes(&self) -> &[u8] {
396 &self.stdout_buf
397 }
398}
399impl<O> Drop for ClientApplication<O>
400where
401 O: io::Write,
402{
403 fn drop(&mut self) {
404 self.restore_screen();
405 }
406}