1use std::ops::Range;
10
11use gpui_kit::{Bounds, Context, EntityInputHandler, Pixels, Point, UTF16Selection, Window};
12
13use crate::terminal::input::TerminalInput;
14use crate::terminal::state::TerminalState;
15
16impl EntityInputHandler for TerminalState {
17 fn text_for_range(
18 &mut self,
19 range: Range<usize>,
20 adjusted: &mut Option<Range<usize>>,
21 _window: &mut Window,
22 _cx: &mut Context<Self>,
23 ) -> Option<String> {
24 let marked = self.marked_text.as_deref().unwrap_or_default();
25 let utf16: Vec<u16> = marked.encode_utf16().collect();
26 let start = range.start.min(utf16.len());
27 let end = range.end.min(utf16.len()).max(start);
28 if start != range.start || end != range.end {
29 *adjusted = Some(start..end);
30 }
31 Some(String::from_utf16_lossy(&utf16[start..end]))
32 }
33
34 fn selected_text_range(
35 &mut self,
36 _ignore_disabled_input: bool,
37 _window: &mut Window,
38 _cx: &mut Context<Self>,
39 ) -> Option<UTF16Selection> {
40 let length = self.marked_utf16_len();
41 Some(UTF16Selection {
42 range: length..length,
43 reversed: false,
44 })
45 }
46
47 fn marked_text_range(
48 &self,
49 _window: &mut Window,
50 _cx: &mut Context<Self>,
51 ) -> Option<Range<usize>> {
52 self.marked_text
53 .as_ref()
54 .map(|text| 0..text.encode_utf16().count())
55 }
56
57 fn unmark_text(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
58 if self.marked_text.take().is_some() {
59 cx.notify();
60 }
61 }
62
63 fn replace_text_in_range(
64 &mut self,
65 _range: Option<Range<usize>>,
66 text: &str,
67 _window: &mut Window,
68 cx: &mut Context<Self>,
69 ) {
70 self.marked_text = None;
71 if !text.is_empty() {
72 self.selection = None;
73 self.send(TerminalInput::Text(text.to_owned()), cx);
74 }
75 cx.notify();
76 }
77
78 fn replace_and_mark_text_in_range(
79 &mut self,
80 _range: Option<Range<usize>>,
81 new_text: &str,
82 _new_selected_range: Option<Range<usize>>,
83 _window: &mut Window,
84 cx: &mut Context<Self>,
85 ) {
86 self.marked_text = (!new_text.is_empty()).then(|| new_text.to_owned());
87 cx.notify();
88 }
89
90 fn bounds_for_range(
92 &mut self,
93 _range_utf16: Range<usize>,
94 element_bounds: Bounds<Pixels>,
95 _window: &mut Window,
96 _cx: &mut Context<Self>,
97 ) -> Option<Bounds<Pixels>> {
98 let geometry = self.geometry?;
99 let cursor = self.frame().cursor;
100 Some(
101 geometry
102 .cell_bounds(cursor.column, cursor.row)
103 .intersect(&element_bounds.union(&geometry.grid_bounds())),
104 )
105 }
106
107 fn character_index_for_point(
108 &mut self,
109 _point: Point<Pixels>,
110 _window: &mut Window,
111 _cx: &mut Context<Self>,
112 ) -> Option<usize> {
113 None
114 }
115}
116
117impl TerminalState {
118 fn marked_utf16_len(&self) -> usize {
119 self.marked_text
120 .as_ref()
121 .map_or(0, |text| text.encode_utf16().count())
122 }
123
124 #[must_use]
126 pub fn marked_text(&self) -> Option<&str> {
127 self.marked_text.as_deref()
128 }
129}