window_input_handler.rs

 1use std::{cell::RefCell, ops::Range, rc::Rc};
 2
 3use pathfinder_geometry::rect::RectF;
 4
 5use crate::{platform::InputHandler, AnyView, AppContext};
 6
 7pub struct WindowInputHandler {
 8    pub app: Rc<RefCell<AppContext>>,
 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.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 AppContext) -> 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.views.remove(&(self.window_id, view_id))?;
39            let result = f(self.window_id, view_id, view.as_mut(), &mut *app);
40            app.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}