1use std::{fmt, path::Path};
2
3use crate::{
4 buffer::{BufferCollection, BufferHandle, BufferProperties, CharDisplayDistances},
5 buffer_position::BufferPositionIndex,
6 buffer_view::{BufferView, BufferViewCollection, BufferViewHandle},
7 editor::Editor,
8 editor_utils::ResidualStrBytes,
9 navigation_history::{NavigationHistory, NavigationMovement},
10 serialization::{DeserializeError, Deserializer, Serialize, Serializer},
11};
12
13#[derive(Clone, Copy, Eq, PartialEq)]
14pub struct ClientHandle(pub u8);
15
16impl<'de> Serialize<'de> for ClientHandle {
17 fn serialize(&self, serializer: &mut dyn Serializer) {
18 self.0.serialize(serializer);
19 }
20
21 fn deserialize(deserializer: &mut dyn Deserializer<'de>) -> Result<Self, DeserializeError> {
22 Ok(Self(u8::deserialize(deserializer)?))
23 }
24}
25
26pub enum ViewAnchor {
27 Top,
28 Center,
29 Bottom,
30}
31
32pub struct Client {
33 active: bool,
34 handle: ClientHandle,
35
36 pub viewport_size: (u16, u16),
37
38 pub(crate) navigation_history: NavigationHistory,
39
40 buffer_view_handle: Option<BufferViewHandle>,
41 stdin_buffer_handle: Option<BufferHandle>,
42 stdin_residual_bytes: ResidualStrBytes,
43}
44
45impl Client {
46 pub(crate) fn new() -> Self {
47 Self {
48 active: false,
49 handle: ClientHandle(0),
50
51 viewport_size: (0, 0),
52
53 navigation_history: NavigationHistory::default(),
54
55 buffer_view_handle: None,
56 stdin_buffer_handle: None,
57 stdin_residual_bytes: ResidualStrBytes::default(),
58 }
59 }
60
61 fn dispose(&mut self) {
62 self.active = false;
63
64 self.viewport_size = (0, 0);
65
66 self.navigation_history.clear();
67
68 self.buffer_view_handle = None;
69 self.stdin_buffer_handle = None;
70 self.stdin_residual_bytes = ResidualStrBytes::default();
71 }
72
73 pub fn handle(&self) -> ClientHandle {
74 self.handle
75 }
76
77 pub fn buffer_view_handle(&self) -> Option<BufferViewHandle> {
78 self.buffer_view_handle
79 }
80
81 pub fn stdin_buffer_handle(&self) -> Option<BufferHandle> {
82 self.stdin_buffer_handle
83 }
84
85 pub fn set_buffer_view_handle(
86 &mut self,
87 handle: Option<BufferViewHandle>,
88 buffer_views: &BufferViewCollection,
89 ) {
90 NavigationHistory::save_snapshot(self, buffer_views);
91 self.set_buffer_view_handle_no_history(handle);
92 }
93
94 pub(crate) fn set_buffer_view_handle_no_history(&mut self, handle: Option<BufferViewHandle>) {
95 self.buffer_view_handle = handle;
96 }
97
98 pub fn has_ui(&self) -> bool {
99 self.viewport_size.0 != 0 && self.viewport_size.1 != 0
100 }
101
102 pub fn set_view_anchor(&self, editor: &mut Editor, anchor: ViewAnchor) {
103 if !self.has_ui() {
104 return;
105 }
106
107 if let Some(buffer_view_handle) = self.buffer_view_handle {
108 let height = self.viewport_size.1.saturating_sub(1) as usize;
109 let height_offset = match anchor {
110 ViewAnchor::Top => 0,
111 ViewAnchor::Center => height / 2,
112 ViewAnchor::Bottom => height.saturating_sub(1),
113 };
114
115 let buffer_view = editor.buffer_views.get_mut(buffer_view_handle);
116 let main_cursor_padding_top = self.find_main_cursor_padding_top(
117 buffer_view,
118 &editor.buffers,
119 editor.config.tab_size,
120 );
121 buffer_view.scroll = main_cursor_padding_top.saturating_sub(height_offset) as _;
122 }
123 }
124
125 pub(crate) fn scroll_to_main_cursor(
126 &self,
127 buffer_views: &mut BufferViewCollection,
128 buffers: &BufferCollection,
129 tab_size: u8,
130 margin_bottom: usize,
131 ) -> BufferPositionIndex {
132 if !self.has_ui() {
133 return 0;
134 }
135
136 let height = self.viewport_size.1.saturating_sub(1) as usize;
137 let height = height.saturating_sub(margin_bottom);
138 let half_height = height / 2;
139
140 match self.buffer_view_handle {
141 Some(buffer_view_handle) => {
142 let buffer_view = buffer_views.get_mut(buffer_view_handle);
143 let main_cursor_padding_top =
144 self.find_main_cursor_padding_top(buffer_view, buffers, tab_size);
145
146 let mut scroll = buffer_view.scroll as usize;
147 if main_cursor_padding_top < scroll.saturating_sub(half_height) {
148 scroll = main_cursor_padding_top.saturating_sub(half_height) as _;
149 } else if main_cursor_padding_top < scroll {
150 scroll = main_cursor_padding_top as _;
151 } else if main_cursor_padding_top >= scroll + height + half_height {
152 scroll = (main_cursor_padding_top + 1 - half_height) as _;
153 } else if main_cursor_padding_top >= scroll + height {
154 scroll = (main_cursor_padding_top + 1 - height) as _;
155 }
156 let scroll = scroll as _;
157 buffer_view.scroll = scroll;
158 scroll
159 }
160 None => 0,
161 }
162 }
163
164 pub(crate) fn on_stdin_input(&mut self, editor: &mut Editor, bytes: &[u8]) {
165 let mut buf = Default::default();
166 let texts = self.stdin_residual_bytes.receive_bytes(&mut buf, bytes);
167
168 let buffer_handle = match self.stdin_buffer_handle() {
169 Some(handle) => handle,
170 None => {
171 use fmt::Write;
172
173 let buffer = editor.buffers.add_new();
174
175 let mut path = editor.string_pool.acquire_with("pipe.");
176 let _ = write!(path, "{}", self.handle().0);
177 buffer.set_path(Path::new(&path));
178 editor.string_pool.release(path);
179
180 buffer.properties = BufferProperties::text();
181 buffer.properties.file_backed_enabled = false;
182
183 let buffer_view_handle =
184 editor.buffer_views.add_new(self.handle(), buffer.handle());
185 self.set_buffer_view_handle(Some(buffer_view_handle), &editor.buffer_views);
186
187 self.stdin_buffer_handle = Some(buffer.handle());
188 buffer.handle()
189 }
190 };
191
192 let buffer = editor.buffers.get_mut(buffer_handle);
193 let mut events = editor
194 .events
195 .writer()
196 .buffer_text_inserts_mut_guard(buffer_handle);
197 for text in texts {
198 let position = buffer.content().end();
199 buffer.insert_text(&mut editor.word_database, position, text, &mut events);
200 }
201 }
202
203 pub(crate) fn on_buffer_close(&mut self, editor: &mut Editor, buffer_handle: BufferHandle) {
204 self.navigation_history
205 .remove_snapshots_with_buffer_handle(buffer_handle);
206
207 if let Some(handle) = self.buffer_view_handle {
208 let buffer_view = editor.buffer_views.get(handle);
209 if buffer_view.buffer_handle == buffer_handle {
210 self.buffer_view_handle = None;
211 NavigationHistory::move_in_history(self, editor, NavigationMovement::Backward);
212 NavigationHistory::move_in_history(self, editor, NavigationMovement::Forward);
213 }
214 }
215
216 if self.stdin_buffer_handle == Some(buffer_handle) {
217 self.stdin_buffer_handle = None;
218 }
219 }
220
221 fn find_main_cursor_padding_top(
222 &self,
223 buffer_view: &BufferView,
224 buffers: &BufferCollection,
225 tab_size: u8,
226 ) -> usize {
227 let width = self.viewport_size.0 as usize;
228
229 let buffer = buffers.get(buffer_view.buffer_handle).content();
230 let position = buffer_view.cursors.main_cursor().position;
231
232 let mut height = position.line_index as usize;
233 for display_len in &buffer.line_display_lens()[..position.line_index as usize] {
234 height += display_len.total_len(tab_size) / width;
235 }
236
237 let cursor_line = buffer.lines()[position.line_index as usize].as_str();
238 let cursor_line = &cursor_line[..position.column_byte_index as usize];
239 if let Some(d) = CharDisplayDistances::new(cursor_line, tab_size).last() {
240 height += d.distance as usize / width;
241 }
242
243 height
244 }
245}
246
247#[derive(Default)]
248pub struct ClientManager {
249 focused_client: Option<ClientHandle>,
250 previous_focused_client: Option<ClientHandle>,
251 clients: Vec<Client>,
252}
253
254impl ClientManager {
255 pub fn focused_client(&self) -> Option<ClientHandle> {
256 self.focused_client
257 }
258
259 pub fn previous_focused_client(&self) -> Option<ClientHandle> {
260 self.previous_focused_client
261 }
262
263 pub fn focus_client(&mut self, handle: ClientHandle) -> bool {
264 let client = self.get(handle);
265 if !client.has_ui() {
266 return false;
267 }
268
269 let changed = Some(handle) != self.focused_client;
270 if changed {
271 self.previous_focused_client = self.focused_client;
272 }
273 self.focused_client = Some(handle);
274 changed
275 }
276
277 pub fn get(&self, handle: ClientHandle) -> &Client {
278 &self.clients[handle.0 as usize]
279 }
280
281 pub fn get_mut(&mut self, handle: ClientHandle) -> &mut Client {
282 &mut self.clients[handle.0 as usize]
283 }
284
285 pub fn iter(&self) -> impl Clone + Iterator<Item = &Client> {
286 self.clients.iter().filter(|c| c.active)
287 }
288
289 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Client> {
290 self.clients.iter_mut().filter(|c| c.active)
291 }
292
293 pub(crate) fn on_client_joined(&mut self, handle: ClientHandle) {
294 let min_len = handle.0 as usize + 1;
295 if min_len > self.clients.len() {
296 self.clients.resize_with(min_len, Client::new);
297 }
298
299 let client = &mut self.clients[handle.0 as usize];
300 client.active = true;
301 client.handle = handle;
302 }
303
304 pub(crate) fn on_client_left(&mut self, handle: ClientHandle) {
305 self.clients[handle.0 as usize].dispose();
306 if self.focused_client == Some(handle) {
307 self.focused_client = None;
308 }
309 }
310}