1use std::ops::Range;
4
5use gpui::{Context, EntityInputHandler, UTF16Selection, Window};
6use markdown::{Cursor, Selection};
7use ui::input::{composition_selection, offset_to_utf16, range_from_utf16, range_to_utf16};
8
9use crate::editor::Editor;
10
11impl EntityInputHandler for Editor {
15 fn text_for_range(
16 &mut self,
17 range: Range<usize>,
18 adjusted: &mut Option<Range<usize>>,
19 _: &mut Window,
20 _: &mut Context<Self>,
21 ) -> Option<String> {
22 let text = self.caret_text()?;
23 let range = range_from_utf16(&text.text, range);
24 *adjusted = Some(range_to_utf16(&text.text, range.clone()));
25 Some(text.text.get(range)?.to_string())
26 }
27
28 fn selected_text_range(
29 &mut self,
30 _: bool,
31 _: &mut Window,
32 _: &mut Context<Self>,
33 ) -> Option<UTF16Selection> {
34 let (start, end) = self.selection.ordered();
38 let spans_one = start.block == end.block && start.part == end.part;
39 let head = self.selection.head;
40 let range = if spans_one {
41 start.offset..end.offset
42 } else {
43 head.offset..head.offset
44 };
45 Some(UTF16Selection {
46 reversed: spans_one && self.selection.head == start,
47 range: range_to_utf16(&self.caret_text()?.text, range),
48 })
49 }
50
51 fn marked_text_range(&self, _: &mut Window, _: &mut Context<Self>) -> Option<Range<usize>> {
52 Some(range_to_utf16(
53 &self.caret_text()?.text,
54 self.marked.clone()?,
55 ))
56 }
57
58 fn unmark_text(&mut self, _: &mut Window, _: &mut Context<Self>) {
59 self.marked = None;
60 }
61
62 fn replace_text_in_range(
63 &mut self,
64 range: Option<Range<usize>>,
65 text: &str,
66 _: &mut Window,
67 cx: &mut Context<Self>,
68 ) {
69 if range.is_none() && self.marked.is_none() && markdown::is_url(text.trim()) {
76 return self.paste_url(text.trim().to_string(), cx);
77 }
78 if let Some(range) = range
81 .and_then(|range| {
82 self.caret_text()
83 .map(|text| range_from_utf16(&text.text, range))
84 })
85 .or_else(|| self.marked.clone())
86 {
87 let at = self.cursor();
88 self.selection = Selection::new(
89 Cursor {
90 offset: range.start,
91 ..at
92 },
93 Cursor {
94 offset: range.end,
95 ..at
96 },
97 );
98 }
99 self.marked = None;
100 self.insert(text, cx);
101 }
102
103 fn replace_and_mark_text_in_range(
104 &mut self,
105 range: Option<Range<usize>>,
106 text: &str,
107 marked: Option<Range<usize>>,
108 _: &mut Window,
109 cx: &mut Context<Self>,
110 ) {
111 if let Some(range) = range
112 .and_then(|range| {
113 self.caret_text()
114 .map(|text| range_from_utf16(&text.text, range))
115 })
116 .or_else(|| self.marked.clone())
117 {
118 let at = self.cursor();
119 self.doc.edit_at(at, |body| body.remove(range.clone()));
120 self.place(Cursor {
121 offset: range.start,
122 ..at
123 });
124 }
125 let at = self.cursor();
129 let start = at.offset;
130 self.doc.edit_at(at, |body| body.insert(start, text));
131 self.marked = (!text.is_empty()).then_some(start..start + text.len());
132 let selected = composition_selection(text, start, marked);
133 self.selection = Selection::new(
134 Cursor {
135 offset: selected.start,
136 ..at
137 },
138 Cursor {
139 offset: selected.end,
140 ..at
141 },
142 );
143 self.reveal = true;
144 self.caret_moved();
145 cx.notify();
146 }
147
148 fn bounds_for_range(
151 &mut self,
152 range: Range<usize>,
153 _: gpui::Bounds<gpui::Pixels>,
154 _: &mut Window,
155 _: &mut Context<Self>,
156 ) -> Option<gpui::Bounds<gpui::Pixels>> {
157 let range = range_from_utf16(&self.caret_text()?.text, range);
158 let at = self.cursor();
159 let start = Cursor {
160 offset: range.start,
161 ..at
162 };
163 let (origin, line_height) = self.layouts.position(start)?;
164 let end = self
165 .layouts
166 .position(Cursor {
167 offset: range.end,
168 ..at
169 })
170 .map(|(point, _)| point)
171 .filter(|point| point.y == origin.y);
172 let width = end.map_or(gpui::px(0.0), |point| point.x - origin.x);
173 Some(gpui::Bounds::new(origin, gpui::size(width, line_height)))
174 }
175
176 fn character_index_for_point(
177 &mut self,
178 point: gpui::Point<gpui::Pixels>,
179 _: &mut Window,
180 _: &mut Context<Self>,
181 ) -> Option<usize> {
182 let hit = self.layouts.hit(point)?;
183 let at = self.cursor();
184 (hit.block == at.block && hit.part == at.part)
185 .then_some(offset_to_utf16(&self.caret_text()?.text, hit.offset))
186 }
187}