1use std::{cell::RefCell, ops::Range, rc::Rc};
2
3use pathfinder_geometry::rect::RectF;
4
5use crate::{AnyView, AppContext, InputHandler, MutableAppContext};
6
7pub struct WindowInputHandler {
8 pub app: Rc<RefCell<MutableAppContext>>,
9 pub window_id: usize,
10}
11
12impl WindowInputHandler {
13 fn read_focused_view<T, F>(&self, f: F) -> Option<T>
14 where
15 F: FnOnce(&dyn AnyView, &AppContext) -> T,
16 {
17 // Input-related application hooks are sometimes called by the OS during
18 // a call to a window-manipulation API, like prompting the user for file
19 // paths. In that case, the AppContext will already be borrowed, so any
20 // InputHandler methods need to fail gracefully.
21 //
22 // See https://github.com/zed-industries/community/issues/444
23 let app = self.app.try_borrow().ok()?;
24
25 let view_id = app.focused_view_id(self.window_id)?;
26 let view = app.cx.views.get(&(self.window_id, view_id))?;
27 let result = f(view.as_ref(), &app);
28 Some(result)
29 }
30
31 fn update_focused_view<T, F>(&mut self, f: F) -> Option<T>
32 where
33 F: FnOnce(usize, usize, &mut dyn AnyView, &mut MutableAppContext) -> T,
34 {
35 let mut app = self.app.try_borrow_mut().ok()?;
36 app.update(|app| {
37 let view_id = app.focused_view_id(self.window_id)?;
38 let mut view = app.cx.views.remove(&(self.window_id, view_id))?;
39 let result = f(self.window_id, view_id, view.as_mut(), &mut *app);
40 app.cx.views.insert((self.window_id, view_id), view);
41 Some(result)
42 })
43 }
44}
45
46impl InputHandler for WindowInputHandler {
47 fn text_for_range(&self, range: Range<usize>) -> Option<String> {
48 self.read_focused_view(|view, cx| view.text_for_range(range.clone(), cx))
49 .flatten()
50 }
51
52 fn selected_text_range(&self) -> Option<Range<usize>> {
53 self.read_focused_view(|view, cx| view.selected_text_range(cx))
54 .flatten()
55 }
56
57 fn replace_text_in_range(&mut self, range: Option<Range<usize>>, text: &str) {
58 self.update_focused_view(|window_id, view_id, view, cx| {
59 view.replace_text_in_range(range, text, cx, window_id, view_id);
60 });
61 }
62
63 fn marked_text_range(&self) -> Option<Range<usize>> {
64 self.read_focused_view(|view, cx| view.marked_text_range(cx))
65 .flatten()
66 }
67
68 fn unmark_text(&mut self) {
69 self.update_focused_view(|window_id, view_id, view, cx| {
70 view.unmark_text(cx, window_id, view_id);
71 });
72 }
73
74 fn replace_and_mark_text_in_range(
75 &mut self,
76 range: Option<Range<usize>>,
77 new_text: &str,
78 new_selected_range: Option<Range<usize>>,
79 ) {
80 self.update_focused_view(|window_id, view_id, view, cx| {
81 view.replace_and_mark_text_in_range(
82 range,
83 new_text,
84 new_selected_range,
85 cx,
86 window_id,
87 view_id,
88 );
89 });
90 }
91
92 fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
93 let app = self.app.borrow();
94 let (presenter, _) = app.presenters_and_platform_windows.get(&self.window_id)?;
95 let presenter = presenter.borrow();
96 presenter.rect_for_text_range(range_utf16, &app)
97 }
98}