1use super::{
2 display_map::ToDisplayPoint, DisplayPoint, Editor, EditorSnapshot, ToPoint, MAX_LINE_LEN,
3};
4use crate::{
5 display_map::{BlockStyle, DisplaySnapshot},
6 EditorStyle,
7};
8use anyhow::Result;
9use gpui::{
10 black, px, relative, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun,
11 TextSystem,
12};
13use language::{CursorShape, Selection};
14use smallvec::SmallVec;
15use std::{ops::Range, sync::Arc};
16use sum_tree::Bias;
17
18enum FoldMarkers {}
19
20struct SelectionLayout {
21 head: DisplayPoint,
22 cursor_shape: CursorShape,
23 is_newest: bool,
24 is_local: bool,
25 range: Range<DisplayPoint>,
26 active_rows: Range<u32>,
27}
28
29impl SelectionLayout {
30 fn new<T: ToPoint + ToDisplayPoint + Clone>(
31 selection: Selection<T>,
32 line_mode: bool,
33 cursor_shape: CursorShape,
34 map: &DisplaySnapshot,
35 is_newest: bool,
36 is_local: bool,
37 ) -> Self {
38 let point_selection = selection.map(|p| p.to_point(&map.buffer_snapshot));
39 let display_selection = point_selection.map(|p| p.to_display_point(map));
40 let mut range = display_selection.range();
41 let mut head = display_selection.head();
42 let mut active_rows = map.prev_line_boundary(point_selection.start).1.row()
43 ..map.next_line_boundary(point_selection.end).1.row();
44
45 // vim visual line mode
46 if line_mode {
47 let point_range = map.expand_to_line(point_selection.range());
48 range = point_range.start.to_display_point(map)..point_range.end.to_display_point(map);
49 }
50
51 // any vim visual mode (including line mode)
52 if cursor_shape == CursorShape::Block && !range.is_empty() && !selection.reversed {
53 if head.column() > 0 {
54 head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left)
55 } else if head.row() > 0 && head != map.max_point() {
56 head = map.clip_point(
57 DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)),
58 Bias::Left,
59 );
60 // updating range.end is a no-op unless you're cursor is
61 // on the newline containing a multi-buffer divider
62 // in which case the clip_point may have moved the head up
63 // an additional row.
64 range.end = DisplayPoint::new(head.row() + 1, 0);
65 active_rows.end = head.row();
66 }
67 }
68
69 Self {
70 head,
71 cursor_shape,
72 is_newest,
73 is_local,
74 range,
75 active_rows,
76 }
77 }
78}
79
80pub struct EditorElement {
81 style: Arc<EditorStyle>,
82}
83
84impl EditorElement {
85 pub fn new(style: EditorStyle) -> Self {
86 Self {
87 style: Arc::new(style),
88 }
89 }
90
91 // fn attach_mouse_handlers(
92 // position_map: &Arc<PositionMap>,
93 // has_popovers: bool,
94 // visible_bounds: Bounds<Pixels>,
95 // text_bounds: Bounds<Pixels>,
96 // gutter_bounds: Bounds<Pixels>,
97 // bounds: Bounds<Pixels>,
98 // cx: &mut ViewContext<Editor>,
99 // ) {
100 // enum EditorElementMouseHandlers {}
101 // let view_id = cx.view_id();
102 // cx.scene().push_mouse_region(
103 // MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
104 // .on_down(MouseButton::Left, {
105 // let position_map = position_map.clone();
106 // move |event, editor, cx| {
107 // if !Self::mouse_down(
108 // editor,
109 // event.platform_event,
110 // position_map.as_ref(),
111 // text_bounds,
112 // gutter_bounds,
113 // cx,
114 // ) {
115 // cx.propagate_event();
116 // }
117 // }
118 // })
119 // .on_down(MouseButton::Right, {
120 // let position_map = position_map.clone();
121 // move |event, editor, cx| {
122 // if !Self::mouse_right_down(
123 // editor,
124 // event.position,
125 // position_map.as_ref(),
126 // text_bounds,
127 // cx,
128 // ) {
129 // cx.propagate_event();
130 // }
131 // }
132 // })
133 // .on_up(MouseButton::Left, {
134 // let position_map = position_map.clone();
135 // move |event, editor, cx| {
136 // if !Self::mouse_up(
137 // editor,
138 // event.position,
139 // event.cmd,
140 // event.shift,
141 // event.alt,
142 // position_map.as_ref(),
143 // text_bounds,
144 // cx,
145 // ) {
146 // cx.propagate_event()
147 // }
148 // }
149 // })
150 // .on_drag(MouseButton::Left, {
151 // let position_map = position_map.clone();
152 // move |event, editor, cx| {
153 // if event.end {
154 // return;
155 // }
156
157 // if !Self::mouse_dragged(
158 // editor,
159 // event.platform_event,
160 // position_map.as_ref(),
161 // text_bounds,
162 // cx,
163 // ) {
164 // cx.propagate_event()
165 // }
166 // }
167 // })
168 // .on_move({
169 // let position_map = position_map.clone();
170 // move |event, editor, cx| {
171 // if !Self::mouse_moved(
172 // editor,
173 // event.platform_event,
174 // &position_map,
175 // text_bounds,
176 // cx,
177 // ) {
178 // cx.propagate_event()
179 // }
180 // }
181 // })
182 // .on_move_out(move |_, editor: &mut Editor, cx| {
183 // if has_popovers {
184 // hide_hover(editor, cx);
185 // }
186 // })
187 // .on_scroll({
188 // let position_map = position_map.clone();
189 // move |event, editor, cx| {
190 // if !Self::scroll(
191 // editor,
192 // event.position,
193 // *event.delta.raw(),
194 // event.delta.precise(),
195 // &position_map,
196 // bounds,
197 // cx,
198 // ) {
199 // cx.propagate_event()
200 // }
201 // }
202 // }),
203 // );
204
205 // enum GutterHandlers {}
206 // let view_id = cx.view_id();
207 // let region_id = cx.view_id() + 1;
208 // cx.scene().push_mouse_region(
209 // MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
210 // |hover, editor: &mut Editor, cx| {
211 // editor.gutter_hover(
212 // &GutterHover {
213 // hovered: hover.started,
214 // },
215 // cx,
216 // );
217 // },
218 // ),
219 // )
220 // }
221
222 // fn mouse_down(
223 // editor: &mut Editor,
224 // MouseButtonEvent {
225 // position,
226 // modifiers:
227 // Modifiers {
228 // shift,
229 // ctrl,
230 // alt,
231 // cmd,
232 // ..
233 // },
234 // mut click_count,
235 // ..
236 // }: MouseButtonEvent,
237 // position_map: &PositionMap,
238 // text_bounds: Bounds<Pixels>,
239 // gutter_bounds: Bounds<Pixels>,
240 // cx: &mut EventContext<Editor>,
241 // ) -> bool {
242 // if gutter_bounds.contains_point(position) {
243 // click_count = 3; // Simulate triple-click when clicking the gutter to select lines
244 // } else if !text_bounds.contains_point(position) {
245 // return false;
246 // }
247
248 // let point_for_position = position_map.point_for_position(text_bounds, position);
249 // let position = point_for_position.previous_valid;
250 // if shift && alt {
251 // editor.select(
252 // SelectPhase::BeginColumnar {
253 // position,
254 // goal_column: point_for_position.exact_unclipped.column(),
255 // },
256 // cx,
257 // );
258 // } else if shift && !ctrl && !alt && !cmd {
259 // editor.select(
260 // SelectPhase::Extend {
261 // position,
262 // click_count,
263 // },
264 // cx,
265 // );
266 // } else {
267 // editor.select(
268 // SelectPhase::Begin {
269 // position,
270 // add: alt,
271 // click_count,
272 // },
273 // cx,
274 // );
275 // }
276
277 // true
278 // }
279
280 // fn mouse_right_down(
281 // editor: &mut Editor,
282 // position: gpui::Point<Pixels>,
283 // position_map: &PositionMap,
284 // text_bounds: Bounds<Pixels>,
285 // cx: &mut EventContext<Editor>,
286 // ) -> bool {
287 // if !text_bounds.contains_point(position) {
288 // return false;
289 // }
290 // let point_for_position = position_map.point_for_position(text_bounds, position);
291 // mouse_context_menu::deploy_context_menu(
292 // editor,
293 // position,
294 // point_for_position.previous_valid,
295 // cx,
296 // );
297 // true
298 // }
299
300 // fn mouse_up(
301 // editor: &mut Editor,
302 // position: gpui::Point<Pixels>,
303 // cmd: bool,
304 // shift: bool,
305 // alt: bool,
306 // position_map: &PositionMap,
307 // text_bounds: Bounds<Pixels>,
308 // cx: &mut EventContext<Editor>,
309 // ) -> bool {
310 // let end_selection = editor.has_pending_selection();
311 // let pending_nonempty_selections = editor.has_pending_nonempty_selection();
312
313 // if end_selection {
314 // editor.select(SelectPhase::End, cx);
315 // }
316
317 // if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
318 // let point = position_map.point_for_position(text_bounds, position);
319 // let could_be_inlay = point.as_valid().is_none();
320 // if shift || could_be_inlay {
321 // go_to_fetched_type_definition(editor, point, alt, cx);
322 // } else {
323 // go_to_fetched_definition(editor, point, alt, cx);
324 // }
325
326 // return true;
327 // }
328
329 // end_selection
330 // }
331
332 // fn mouse_dragged(
333 // editor: &mut Editor,
334 // MouseMovedEvent {
335 // modifiers: Modifiers { cmd, shift, .. },
336 // position,
337 // ..
338 // }: MouseMovedEvent,
339 // position_map: &PositionMap,
340 // text_bounds: Bounds<Pixels>,
341 // cx: &mut EventContext<Editor>,
342 // ) -> bool {
343 // // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
344 // // Don't trigger hover popover if mouse is hovering over context menu
345 // let point = if text_bounds.contains_point(position) {
346 // position_map
347 // .point_for_position(text_bounds, position)
348 // .as_valid()
349 // } else {
350 // None
351 // };
352
353 // update_go_to_definition_link(
354 // editor,
355 // point.map(GoToDefinitionTrigger::Text),
356 // cmd,
357 // shift,
358 // cx,
359 // );
360
361 // if editor.has_pending_selection() {
362 // let mut scroll_delta = gpui::Point<Pixels>::zero();
363
364 // let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
365 // let top = text_bounds.origin_y() + vertical_margin;
366 // let bottom = text_bounds.lower_left().y() - vertical_margin;
367 // if position.y() < top {
368 // scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
369 // }
370 // if position.y() > bottom {
371 // scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
372 // }
373
374 // let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
375 // let left = text_bounds.origin_x() + horizontal_margin;
376 // let right = text_bounds.upper_right().x() - horizontal_margin;
377 // if position.x() < left {
378 // scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
379 // left - position.x(),
380 // ))
381 // }
382 // if position.x() > right {
383 // scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
384 // position.x() - right,
385 // ))
386 // }
387
388 // let point_for_position = position_map.point_for_position(text_bounds, position);
389
390 // editor.select(
391 // SelectPhase::Update {
392 // position: point_for_position.previous_valid,
393 // goal_column: point_for_position.exact_unclipped.column(),
394 // scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
395 // .clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max),
396 // },
397 // cx,
398 // );
399 // hover_at(editor, point, cx);
400 // true
401 // } else {
402 // hover_at(editor, point, cx);
403 // false
404 // }
405 // }
406
407 // fn mouse_moved(
408 // editor: &mut Editor,
409 // MouseMovedEvent {
410 // modifiers: Modifiers { shift, cmd, .. },
411 // position,
412 // ..
413 // }: MouseMovedEvent,
414 // position_map: &PositionMap,
415 // text_bounds: Bounds<Pixels>,
416 // cx: &mut ViewContext<Editor>,
417 // ) -> bool {
418 // // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
419 // // Don't trigger hover popover if mouse is hovering over context menu
420 // if text_bounds.contains_point(position) {
421 // let point_for_position = position_map.point_for_position(text_bounds, position);
422 // match point_for_position.as_valid() {
423 // Some(point) => {
424 // update_go_to_definition_link(
425 // editor,
426 // Some(GoToDefinitionTrigger::Text(point)),
427 // cmd,
428 // shift,
429 // cx,
430 // );
431 // hover_at(editor, Some(point), cx);
432 // }
433 // None => {
434 // update_inlay_link_and_hover_points(
435 // &position_map.snapshot,
436 // point_for_position,
437 // editor,
438 // cmd,
439 // shift,
440 // cx,
441 // );
442 // }
443 // }
444 // } else {
445 // update_go_to_definition_link(editor, None, cmd, shift, cx);
446 // hover_at(editor, None, cx);
447 // }
448
449 // true
450 // }
451
452 // fn scroll(
453 // editor: &mut Editor,
454 // position: gpui::Point<Pixels>,
455 // mut delta: gpui::Point<Pixels>,
456 // precise: bool,
457 // position_map: &PositionMap,
458 // bounds: Bounds<Pixels>,
459 // cx: &mut ViewContext<Editor>,
460 // ) -> bool {
461 // if !bounds.contains_point(position) {
462 // return false;
463 // }
464
465 // let line_height = position_map.line_height;
466 // let max_glyph_width = position_map.em_width;
467
468 // let axis = if precise {
469 // //Trackpad
470 // position_map.snapshot.ongoing_scroll.filter(&mut delta)
471 // } else {
472 // //Not trackpad
473 // delta *= vec2f(max_glyph_width, line_height);
474 // None //Resets ongoing scroll
475 // };
476
477 // let scroll_position = position_map.snapshot.scroll_position();
478 // let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
479 // let y = (scroll_position.y() * line_height - delta.y()) / line_height;
480 // let scroll_position = vec2f(x, y).clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max);
481 // editor.scroll(scroll_position, axis, cx);
482
483 // true
484 // }
485
486 // fn paint_background(
487 // &self,
488 // gutter_bounds: Bounds<Pixels>,
489 // text_bounds: Bounds<Pixels>,
490 // layout: &LayoutState,
491 // cx: &mut ViewContext<Editor>,
492 // ) {
493 // let bounds = gutter_bounds.union_rect(text_bounds);
494 // let scroll_top =
495 // layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height;
496 // cx.scene().push_quad(Quad {
497 // bounds: gutter_bounds,
498 // background: Some(self.style.gutter_background),
499 // border: Border::new(0., Color::transparent_black()).into(),
500 // corner_radii: Default::default(),
501 // });
502 // cx.scene().push_quad(Quad {
503 // bounds: text_bounds,
504 // background: Some(self.style.background),
505 // border: Border::new(0., Color::transparent_black()).into(),
506 // corner_radii: Default::default(),
507 // });
508
509 // if let EditorMode::Full = layout.mode {
510 // let mut active_rows = layout.active_rows.iter().peekable();
511 // while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
512 // let mut end_row = *start_row;
513 // while active_rows.peek().map_or(false, |r| {
514 // *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
515 // }) {
516 // active_rows.next().unwrap();
517 // end_row += 1;
518 // }
519
520 // if !contains_non_empty_selection {
521 // let origin = vec2f(
522 // bounds.origin_x(),
523 // bounds.origin_y() + (layout.position_map.line_height * *start_row as f32)
524 // - scroll_top,
525 // );
526 // let size = vec2f(
527 // bounds.width(),
528 // layout.position_map.line_height * (end_row - start_row + 1) as f32,
529 // );
530 // cx.scene().push_quad(Quad {
531 // bounds: Bounds<Pixels>::new(origin, size),
532 // background: Some(self.style.active_line_background),
533 // border: Border::default().into(),
534 // corner_radii: Default::default(),
535 // });
536 // }
537 // }
538
539 // if let Some(highlighted_rows) = &layout.highlighted_rows {
540 // let origin = vec2f(
541 // bounds.origin_x(),
542 // bounds.origin_y()
543 // + (layout.position_map.line_height * highlighted_rows.start as f32)
544 // - scroll_top,
545 // );
546 // let size = vec2f(
547 // bounds.width(),
548 // layout.position_map.line_height * highlighted_rows.len() as f32,
549 // );
550 // cx.scene().push_quad(Quad {
551 // bounds: Bounds<Pixels>::new(origin, size),
552 // background: Some(self.style.highlighted_line_background),
553 // border: Border::default().into(),
554 // corner_radii: Default::default(),
555 // });
556 // }
557
558 // let scroll_left =
559 // layout.position_map.snapshot.scroll_position().x() * layout.position_map.em_width;
560
561 // for (wrap_position, active) in layout.wrap_guides.iter() {
562 // let x =
563 // (text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.)
564 // - scroll_left;
565
566 // if x < text_bounds.origin_x()
567 // || (layout.show_scrollbars && x > self.scrollbar_left(&bounds))
568 // {
569 // continue;
570 // }
571
572 // let color = if *active {
573 // self.style.active_wrap_guide
574 // } else {
575 // self.style.wrap_guide
576 // };
577 // cx.scene().push_quad(Quad {
578 // bounds: Bounds<Pixels>::new(
579 // vec2f(x, text_bounds.origin_y()),
580 // vec2f(1., text_bounds.height()),
581 // ),
582 // background: Some(color),
583 // border: Border::new(0., Color::transparent_black()).into(),
584 // corner_radii: Default::default(),
585 // });
586 // }
587 // }
588 // }
589
590 // fn paint_gutter(
591 // &mut self,
592 // bounds: Bounds<Pixels>,
593 // visible_bounds: Bounds<Pixels>,
594 // layout: &mut LayoutState,
595 // editor: &mut Editor,
596 // cx: &mut ViewContext<Editor>,
597 // ) {
598 // let line_height = layout.position_map.line_height;
599
600 // let scroll_position = layout.position_map.snapshot.scroll_position();
601 // let scroll_top = scroll_position.y() * line_height;
602
603 // let show_gutter = matches!(
604 // settings::get::<ProjectSettings>(cx).git.git_gutter,
605 // Some(GitGutterSetting::TrackedFiles)
606 // );
607
608 // if show_gutter {
609 // Self::paint_diff_hunks(bounds, layout, cx);
610 // }
611
612 // for (ix, line) in layout.line_number_layouts.iter().enumerate() {
613 // if let Some(line) = line {
614 // let line_origin = bounds.origin()
615 // + vec2f(
616 // bounds.width() - line.width() - layout.gutter_padding,
617 // ix as f32 * line_height - (scroll_top % line_height),
618 // );
619
620 // line.paint(line_origin, visible_bounds, line_height, cx);
621 // }
622 // }
623
624 // for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
625 // if let Some(indicator) = fold_indicator.as_mut() {
626 // let position = vec2f(
627 // bounds.width() - layout.gutter_padding,
628 // ix as f32 * line_height - (scroll_top % line_height),
629 // );
630 // let centering_offset = vec2f(
631 // (layout.gutter_padding + layout.gutter_margin - indicator.size().x()) / 2.,
632 // (line_height - indicator.size().y()) / 2.,
633 // );
634
635 // let indicator_origin = bounds.origin() + position + centering_offset;
636
637 // indicator.paint(indicator_origin, visible_bounds, editor, cx);
638 // }
639 // }
640
641 // if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
642 // let mut x = 0.;
643 // let mut y = *row as f32 * line_height - scroll_top;
644 // x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
645 // y += (line_height - indicator.size().y()) / 2.;
646 // indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, editor, cx);
647 // }
648 // }
649
650 // fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &mut LayoutState, cx: &mut ViewContext<Editor>) {
651 // let diff_style = &theme::current(cx).editor.diff.clone();
652 // let line_height = layout.position_map.line_height;
653
654 // let scroll_position = layout.position_map.snapshot.scroll_position();
655 // let scroll_top = scroll_position.y() * line_height;
656
657 // for hunk in &layout.display_hunks {
658 // let (display_row_range, status) = match hunk {
659 // //TODO: This rendering is entirely a horrible hack
660 // &DisplayDiffHunk::Folded { display_row: row } => {
661 // let start_y = row as f32 * line_height - scroll_top;
662 // let end_y = start_y + line_height;
663
664 // let width = diff_style.removed_width_em * line_height;
665 // let highlight_origin = bounds.origin() + vec2f(-width, start_y);
666 // let highlight_size = vec2f(width * 2., end_y - start_y);
667 // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
668
669 // cx.scene().push_quad(Quad {
670 // bounds: highlight_bounds,
671 // background: Some(diff_style.modified),
672 // border: Border::new(0., Color::transparent_black()).into(),
673 // corner_radii: (1. * line_height).into(),
674 // });
675
676 // continue;
677 // }
678
679 // DisplayDiffHunk::Unfolded {
680 // display_row_range,
681 // status,
682 // } => (display_row_range, status),
683 // };
684
685 // let color = match status {
686 // DiffHunkStatus::Added => diff_style.inserted,
687 // DiffHunkStatus::Modified => diff_style.modified,
688
689 // //TODO: This rendering is entirely a horrible hack
690 // DiffHunkStatus::Removed => {
691 // let row = display_row_range.start;
692
693 // let offset = line_height / 2.;
694 // let start_y = row as f32 * line_height - offset - scroll_top;
695 // let end_y = start_y + line_height;
696
697 // let width = diff_style.removed_width_em * line_height;
698 // let highlight_origin = bounds.origin() + vec2f(-width, start_y);
699 // let highlight_size = vec2f(width * 2., end_y - start_y);
700 // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
701
702 // cx.scene().push_quad(Quad {
703 // bounds: highlight_bounds,
704 // background: Some(diff_style.deleted),
705 // border: Border::new(0., Color::transparent_black()).into(),
706 // corner_radii: (1. * line_height).into(),
707 // });
708
709 // continue;
710 // }
711 // };
712
713 // let start_row = display_row_range.start;
714 // let end_row = display_row_range.end;
715
716 // let start_y = start_row as f32 * line_height - scroll_top;
717 // let end_y = end_row as f32 * line_height - scroll_top;
718
719 // let width = diff_style.width_em * line_height;
720 // let highlight_origin = bounds.origin() + vec2f(-width, start_y);
721 // let highlight_size = vec2f(width * 2., end_y - start_y);
722 // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
723
724 // cx.scene().push_quad(Quad {
725 // bounds: highlight_bounds,
726 // background: Some(color),
727 // border: Border::new(0., Color::transparent_black()).into(),
728 // corner_radii: (diff_style.corner_radius * line_height).into(),
729 // });
730 // }
731 // }
732
733 // fn paint_text(
734 // &mut self,
735 // bounds: Bounds<Pixels>,
736 // visible_bounds: Bounds<Pixels>,
737 // layout: &mut LayoutState,
738 // editor: &mut Editor,
739 // cx: &mut ViewContext<Editor>,
740 // ) {
741 // let style = &self.style;
742 // let scroll_position = layout.position_map.snapshot.scroll_position();
743 // let start_row = layout.visible_display_row_range.start;
744 // let scroll_top = scroll_position.y() * layout.position_map.line_height;
745 // let max_glyph_width = layout.position_map.em_width;
746 // let scroll_left = scroll_position.x() * max_glyph_width;
747 // let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
748 // let line_end_overshoot = 0.15 * layout.position_map.line_height;
749 // let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
750
751 // cx.scene().push_layer(Some(bounds));
752
753 // cx.scene().push_cursor_region(CursorRegion {
754 // bounds,
755 // style: if !editor.link_go_to_definition_state.definitions.is_empty() {
756 // CursorStyle::PointingHand
757 // } else {
758 // CursorStyle::IBeam
759 // },
760 // });
761
762 // let fold_corner_radius =
763 // self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
764 // for (id, range, color) in layout.fold_ranges.iter() {
765 // self.paint_highlighted_range(
766 // range.clone(),
767 // *color,
768 // fold_corner_radius,
769 // fold_corner_radius * 2.,
770 // layout,
771 // content_origin,
772 // scroll_top,
773 // scroll_left,
774 // bounds,
775 // cx,
776 // );
777
778 // for bound in range_to_bounds(
779 // &range,
780 // content_origin,
781 // scroll_left,
782 // scroll_top,
783 // &layout.visible_display_row_range,
784 // line_end_overshoot,
785 // &layout.position_map,
786 // ) {
787 // cx.scene().push_cursor_region(CursorRegion {
788 // bounds: bound,
789 // style: CursorStyle::PointingHand,
790 // });
791
792 // let display_row = range.start.row();
793
794 // let buffer_row = DisplayPoint::new(display_row, 0)
795 // .to_point(&layout.position_map.snapshot.display_snapshot)
796 // .row;
797
798 // let view_id = cx.view_id();
799 // cx.scene().push_mouse_region(
800 // MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
801 // .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
802 // editor.unfold_at(&UnfoldAt { buffer_row }, cx)
803 // })
804 // .with_notify_on_hover(true)
805 // .with_notify_on_click(true),
806 // )
807 // }
808 // }
809
810 // for (range, color) in &layout.highlighted_ranges {
811 // self.paint_highlighted_range(
812 // range.clone(),
813 // *color,
814 // 0.,
815 // line_end_overshoot,
816 // layout,
817 // content_origin,
818 // scroll_top,
819 // scroll_left,
820 // bounds,
821 // cx,
822 // );
823 // }
824
825 // let mut cursors = SmallVec::<[Cursor; 32]>::new();
826 // let corner_radius = 0.15 * layout.position_map.line_height;
827 // let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
828
829 // for (selection_style, selections) in &layout.selections {
830 // for selection in selections {
831 // self.paint_highlighted_range(
832 // selection.range.clone(),
833 // selection_style.selection,
834 // corner_radius,
835 // corner_radius * 2.,
836 // layout,
837 // content_origin,
838 // scroll_top,
839 // scroll_left,
840 // bounds,
841 // cx,
842 // );
843
844 // if selection.is_local && !selection.range.is_empty() {
845 // invisible_display_ranges.push(selection.range.clone());
846 // }
847 // if !selection.is_local || editor.show_local_cursors(cx) {
848 // let cursor_position = selection.head;
849 // if layout
850 // .visible_display_row_range
851 // .contains(&cursor_position.row())
852 // {
853 // let cursor_row_layout = &layout.position_map.line_layouts
854 // [(cursor_position.row() - start_row) as usize]
855 // .line;
856 // let cursor_column = cursor_position.column() as usize;
857
858 // let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
859 // let mut block_width =
860 // cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
861 // if block_width == 0.0 {
862 // block_width = layout.position_map.em_width;
863 // }
864 // let block_text = if let CursorShape::Block = selection.cursor_shape {
865 // layout
866 // .position_map
867 // .snapshot
868 // .chars_at(cursor_position)
869 // .next()
870 // .and_then(|(character, _)| {
871 // let font_id =
872 // cursor_row_layout.font_for_index(cursor_column)?;
873 // let text = character.to_string();
874
875 // Some(cx.text_layout_cache().layout_str(
876 // &text,
877 // cursor_row_layout.font_size(),
878 // &[(
879 // text.chars().count(),
880 // RunStyle {
881 // font_id,
882 // color: style.background,
883 // underline: Default::default(),
884 // },
885 // )],
886 // ))
887 // })
888 // } else {
889 // None
890 // };
891
892 // let x = cursor_character_x - scroll_left;
893 // let y = cursor_position.row() as f32 * layout.position_map.line_height
894 // - scroll_top;
895 // if selection.is_newest {
896 // editor.pixel_position_of_newest_cursor = Some(vec2f(
897 // bounds.origin_x() + x + block_width / 2.,
898 // bounds.origin_y() + y + layout.position_map.line_height / 2.,
899 // ));
900 // }
901 // cursors.push(Cursor {
902 // color: selection_style.cursor,
903 // block_width,
904 // origin: vec2f(x, y),
905 // line_height: layout.position_map.line_height,
906 // shape: selection.cursor_shape,
907 // block_text,
908 // });
909 // }
910 // }
911 // }
912 // }
913
914 // if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
915 // for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
916 // let row = start_row + ix as u32;
917 // line_with_invisibles.draw(
918 // layout,
919 // row,
920 // scroll_top,
921 // content_origin,
922 // scroll_left,
923 // visible_text_bounds,
924 // whitespace_setting,
925 // &invisible_display_ranges,
926 // visible_bounds,
927 // cx,
928 // )
929 // }
930 // }
931
932 // cx.scene().push_layer(Some(bounds));
933 // for cursor in cursors {
934 // cursor.paint(content_origin, cx);
935 // }
936 // cx.scene().pop_layer();
937
938 // if let Some((position, context_menu)) = layout.context_menu.as_mut() {
939 // cx.scene().push_stacking_context(None, None);
940 // let cursor_row_layout =
941 // &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
942 // let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
943 // let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
944 // let mut list_origin = content_origin + vec2f(x, y);
945 // let list_width = context_menu.size().x();
946 // let list_height = context_menu.size().y();
947
948 // // Snap the right edge of the list to the right edge of the window if
949 // // its horizontal bounds overflow.
950 // if list_origin.x() + list_width > cx.window_size().x() {
951 // list_origin.set_x((cx.window_size().x() - list_width).max(0.));
952 // }
953
954 // if list_origin.y() + list_height > bounds.max_y() {
955 // list_origin.set_y(list_origin.y() - layout.position_map.line_height - list_height);
956 // }
957
958 // context_menu.paint(
959 // list_origin,
960 // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
961 // editor,
962 // cx,
963 // );
964
965 // cx.scene().pop_stacking_context();
966 // }
967
968 // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
969 // cx.scene().push_stacking_context(None, None);
970
971 // // This is safe because we check on layout whether the required row is available
972 // let hovered_row_layout =
973 // &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
974
975 // // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
976 // // height. This is the size we will use to decide whether to render popovers above or below
977 // // the hovered line.
978 // let first_size = hover_popovers[0].size();
979 // let height_to_reserve = first_size.y()
980 // + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
981
982 // // Compute Hovered Point
983 // let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
984 // let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
985 // let hovered_point = content_origin + vec2f(x, y);
986
987 // if hovered_point.y() - height_to_reserve > 0.0 {
988 // // There is enough space above. Render popovers above the hovered point
989 // let mut current_y = hovered_point.y();
990 // for hover_popover in hover_popovers {
991 // let size = hover_popover.size();
992 // let mut popover_origin = vec2f(hovered_point.x(), current_y - size.y());
993
994 // let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
995 // if x_out_of_bounds < 0.0 {
996 // popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
997 // }
998
999 // hover_popover.paint(
1000 // popover_origin,
1001 // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
1002 // editor,
1003 // cx,
1004 // );
1005
1006 // current_y = popover_origin.y() - HOVER_POPOVER_GAP;
1007 // }
1008 // } else {
1009 // // There is not enough space above. Render popovers below the hovered point
1010 // let mut current_y = hovered_point.y() + layout.position_map.line_height;
1011 // for hover_popover in hover_popovers {
1012 // let size = hover_popover.size();
1013 // let mut popover_origin = vec2f(hovered_point.x(), current_y);
1014
1015 // let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
1016 // if x_out_of_bounds < 0.0 {
1017 // popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
1018 // }
1019
1020 // hover_popover.paint(
1021 // popover_origin,
1022 // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
1023 // editor,
1024 // cx,
1025 // );
1026
1027 // current_y = popover_origin.y() + size.y() + HOVER_POPOVER_GAP;
1028 // }
1029 // }
1030
1031 // cx.scene().pop_stacking_context();
1032 // }
1033
1034 // cx.scene().pop_layer();
1035 // }
1036
1037 // fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> f32 {
1038 // bounds.max_x() - self.style.theme.scrollbar.width
1039 // }
1040
1041 // fn paint_scrollbar(
1042 // &mut self,
1043 // bounds: Bounds<Pixels>,
1044 // layout: &mut LayoutState,
1045 // editor: &Editor,
1046 // cx: &mut ViewContext<Editor>,
1047 // ) {
1048 // enum ScrollbarMouseHandlers {}
1049 // if layout.mode != EditorMode::Full {
1050 // return;
1051 // }
1052
1053 // let style = &self.style.theme.scrollbar;
1054
1055 // let top = bounds.min_y();
1056 // let bottom = bounds.max_y();
1057 // let right = bounds.max_x();
1058 // let left = self.scrollbar_left(&bounds);
1059 // let row_range = &layout.scrollbar_row_range;
1060 // let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
1061
1062 // let mut height = bounds.height();
1063 // let mut first_row_y_offset = 0.0;
1064
1065 // // Impose a minimum height on the scrollbar thumb
1066 // let row_height = height / max_row;
1067 // let min_thumb_height =
1068 // style.min_height_factor * cx.font_cache.line_height(self.style.text.font_size);
1069 // let thumb_height = (row_range.end - row_range.start) * row_height;
1070 // if thumb_height < min_thumb_height {
1071 // first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
1072 // height -= min_thumb_height - thumb_height;
1073 // }
1074
1075 // let y_for_row = |row: f32| -> f32 { top + first_row_y_offset + row * row_height };
1076
1077 // let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
1078 // let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
1079 // let track_bounds = Bounds<Pixels>::from_points(vec2f(left, top), vec2f(right, bottom));
1080 // let thumb_bounds = Bounds<Pixels>::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom));
1081
1082 // if layout.show_scrollbars {
1083 // cx.scene().push_quad(Quad {
1084 // bounds: track_bounds,
1085 // border: style.track.border.into(),
1086 // background: style.track.background_color,
1087 // ..Default::default()
1088 // });
1089 // let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
1090 // let theme = theme::current(cx);
1091 // let scrollbar_theme = &theme.editor.scrollbar;
1092 // if layout.is_singleton && scrollbar_settings.selections {
1093 // let start_anchor = Anchor::min();
1094 // let end_anchor = Anchor::max();
1095 // let color = scrollbar_theme.selections;
1096 // let border = Border {
1097 // width: 1.,
1098 // color: style.thumb.border.color,
1099 // overlay: false,
1100 // top: false,
1101 // right: true,
1102 // bottom: false,
1103 // left: true,
1104 // };
1105 // let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
1106 // let start_y = y_for_row(start.row() as f32);
1107 // let mut end_y = y_for_row(end.row() as f32);
1108 // if end_y - start_y < 1. {
1109 // end_y = start_y + 1.;
1110 // }
1111 // let bounds = Bounds<Pixels>::from_points(vec2f(left, start_y), vec2f(right, end_y));
1112
1113 // cx.scene().push_quad(Quad {
1114 // bounds,
1115 // background: Some(color),
1116 // border: border.into(),
1117 // corner_radii: style.thumb.corner_radii.into(),
1118 // })
1119 // };
1120 // let background_ranges = editor
1121 // .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
1122 // start_anchor..end_anchor,
1123 // &layout.position_map.snapshot,
1124 // 50000,
1125 // );
1126 // for row in background_ranges {
1127 // let start = row.start();
1128 // let end = row.end();
1129 // push_region(*start, *end);
1130 // }
1131 // }
1132
1133 // if layout.is_singleton && scrollbar_settings.git_diff {
1134 // let diff_style = scrollbar_theme.git.clone();
1135 // for hunk in layout
1136 // .position_map
1137 // .snapshot
1138 // .buffer_snapshot
1139 // .git_diff_hunks_in_range(0..(max_row.floor() as u32))
1140 // {
1141 // let start_display = Point::new(hunk.buffer_range.start, 0)
1142 // .to_display_point(&layout.position_map.snapshot.display_snapshot);
1143 // let end_display = Point::new(hunk.buffer_range.end, 0)
1144 // .to_display_point(&layout.position_map.snapshot.display_snapshot);
1145 // let start_y = y_for_row(start_display.row() as f32);
1146 // let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
1147 // y_for_row((end_display.row() + 1) as f32)
1148 // } else {
1149 // y_for_row((end_display.row()) as f32)
1150 // };
1151
1152 // if end_y - start_y < 1. {
1153 // end_y = start_y + 1.;
1154 // }
1155 // let bounds = Bounds<Pixels>::from_points(vec2f(left, start_y), vec2f(right, end_y));
1156
1157 // let color = match hunk.status() {
1158 // DiffHunkStatus::Added => diff_style.inserted,
1159 // DiffHunkStatus::Modified => diff_style.modified,
1160 // DiffHunkStatus::Removed => diff_style.deleted,
1161 // };
1162
1163 // let border = Border {
1164 // width: 1.,
1165 // color: style.thumb.border.color,
1166 // overlay: false,
1167 // top: false,
1168 // right: true,
1169 // bottom: false,
1170 // left: true,
1171 // };
1172
1173 // cx.scene().push_quad(Quad {
1174 // bounds,
1175 // background: Some(color),
1176 // border: border.into(),
1177 // corner_radii: style.thumb.corner_radii.into(),
1178 // })
1179 // }
1180 // }
1181
1182 // cx.scene().push_quad(Quad {
1183 // bounds: thumb_bounds,
1184 // border: style.thumb.border.into(),
1185 // background: style.thumb.background_color,
1186 // corner_radii: style.thumb.corner_radii.into(),
1187 // });
1188 // }
1189
1190 // cx.scene().push_cursor_region(CursorRegion {
1191 // bounds: track_bounds,
1192 // style: CursorStyle::Arrow,
1193 // });
1194 // let region_id = cx.view_id();
1195 // cx.scene().push_mouse_region(
1196 // MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
1197 // .on_move(move |event, editor: &mut Editor, cx| {
1198 // if event.pressed_button.is_none() {
1199 // editor.scroll_manager.show_scrollbar(cx);
1200 // }
1201 // })
1202 // .on_down(MouseButton::Left, {
1203 // let row_range = row_range.clone();
1204 // move |event, editor: &mut Editor, cx| {
1205 // let y = event.position.y();
1206 // if y < thumb_top || thumb_bottom < y {
1207 // let center_row = ((y - top) * max_row as f32 / height).round() as u32;
1208 // let top_row = center_row
1209 // .saturating_sub((row_range.end - row_range.start) as u32 / 2);
1210 // let mut position = editor.scroll_position(cx);
1211 // position.set_y(top_row as f32);
1212 // editor.set_scroll_position(position, cx);
1213 // } else {
1214 // editor.scroll_manager.show_scrollbar(cx);
1215 // }
1216 // }
1217 // })
1218 // .on_drag(MouseButton::Left, {
1219 // move |event, editor: &mut Editor, cx| {
1220 // if event.end {
1221 // return;
1222 // }
1223
1224 // let y = event.prev_mouse_position.y();
1225 // let new_y = event.position.y();
1226 // if thumb_top < y && y < thumb_bottom {
1227 // let mut position = editor.scroll_position(cx);
1228 // position.set_y(position.y() + (new_y - y) * (max_row as f32) / height);
1229 // if position.y() < 0.0 {
1230 // position.set_y(0.);
1231 // }
1232 // editor.set_scroll_position(position, cx);
1233 // }
1234 // }
1235 // }),
1236 // );
1237 // }
1238
1239 // #[allow(clippy::too_many_arguments)]
1240 // fn paint_highlighted_range(
1241 // &self,
1242 // range: Range<DisplayPoint>,
1243 // color: Color,
1244 // corner_radius: f32,
1245 // line_end_overshoot: f32,
1246 // layout: &LayoutState,
1247 // content_origin: gpui::Point<Pixels>,
1248 // scroll_top: f32,
1249 // scroll_left: f32,
1250 // bounds: Bounds<Pixels>,
1251 // cx: &mut ViewContext<Editor>,
1252 // ) {
1253 // let start_row = layout.visible_display_row_range.start;
1254 // let end_row = layout.visible_display_row_range.end;
1255 // if range.start != range.end {
1256 // let row_range = if range.end.column() == 0 {
1257 // cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
1258 // } else {
1259 // cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
1260 // };
1261
1262 // let highlighted_range = HighlightedRange {
1263 // color,
1264 // line_height: layout.position_map.line_height,
1265 // corner_radius,
1266 // start_y: content_origin.y()
1267 // + row_range.start as f32 * layout.position_map.line_height
1268 // - scroll_top,
1269 // lines: row_range
1270 // .into_iter()
1271 // .map(|row| {
1272 // let line_layout =
1273 // &layout.position_map.line_layouts[(row - start_row) as usize].line;
1274 // HighlightedRangeLine {
1275 // start_x: if row == range.start.row() {
1276 // content_origin.x()
1277 // + line_layout.x_for_index(range.start.column() as usize)
1278 // - scroll_left
1279 // } else {
1280 // content_origin.x() - scroll_left
1281 // },
1282 // end_x: if row == range.end.row() {
1283 // content_origin.x()
1284 // + line_layout.x_for_index(range.end.column() as usize)
1285 // - scroll_left
1286 // } else {
1287 // content_origin.x() + line_layout.width() + line_end_overshoot
1288 // - scroll_left
1289 // },
1290 // }
1291 // })
1292 // .collect(),
1293 // };
1294
1295 // highlighted_range.paint(bounds, cx);
1296 // }
1297 // }
1298
1299 // fn paint_blocks(
1300 // &mut self,
1301 // bounds: Bounds<Pixels>,
1302 // visible_bounds: Bounds<Pixels>,
1303 // layout: &mut LayoutState,
1304 // editor: &mut Editor,
1305 // cx: &mut ViewContext<Editor>,
1306 // ) {
1307 // let scroll_position = layout.position_map.snapshot.scroll_position();
1308 // let scroll_left = scroll_position.x() * layout.position_map.em_width;
1309 // let scroll_top = scroll_position.y() * layout.position_map.line_height;
1310
1311 // for block in &mut layout.blocks {
1312 // let mut origin = bounds.origin()
1313 // + vec2f(
1314 // 0.,
1315 // block.row as f32 * layout.position_map.line_height - scroll_top,
1316 // );
1317 // if !matches!(block.style, BlockStyle::Sticky) {
1318 // origin += vec2f(-scroll_left, 0.);
1319 // }
1320 // block.element.paint(origin, visible_bounds, editor, cx);
1321 // }
1322 // }
1323
1324 // fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> f32 {
1325 // let style = &self.style;
1326
1327 // cx.text_layout_cache()
1328 // .layout_str(
1329 // " ".repeat(column).as_str(),
1330 // style.text.font_size,
1331 // &[(
1332 // column,
1333 // RunStyle {
1334 // font_id: style.text.font_id,
1335 // color: Color::black(),
1336 // underline: Default::default(),
1337 // },
1338 // )],
1339 // )
1340 // .width()
1341 // }
1342
1343 // fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> f32 {
1344 // let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
1345 // self.column_pixels(digit_count, cx)
1346 // }
1347
1348 //Folds contained in a hunk are ignored apart from shrinking visual size
1349 //If a fold contains any hunks then that fold line is marked as modified
1350 // fn layout_git_gutters(
1351 // &self,
1352 // display_rows: Range<u32>,
1353 // snapshot: &EditorSnapshot,
1354 // ) -> Vec<DisplayDiffHunk> {
1355 // let buffer_snapshot = &snapshot.buffer_snapshot;
1356
1357 // let buffer_start_row = DisplayPoint::new(display_rows.start, 0)
1358 // .to_point(snapshot)
1359 // .row;
1360 // let buffer_end_row = DisplayPoint::new(display_rows.end, 0)
1361 // .to_point(snapshot)
1362 // .row;
1363
1364 // buffer_snapshot
1365 // .git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
1366 // .map(|hunk| diff_hunk_to_display(hunk, snapshot))
1367 // .dedup()
1368 // .collect()
1369 // }
1370
1371 // fn calculate_relative_line_numbers(
1372 // &self,
1373 // snapshot: &EditorSnapshot,
1374 // rows: &Range<u32>,
1375 // relative_to: Option<u32>,
1376 // ) -> HashMap<u32, u32> {
1377 // let mut relative_rows: HashMap<u32, u32> = Default::default();
1378 // let Some(relative_to) = relative_to else {
1379 // return relative_rows;
1380 // };
1381
1382 // let start = rows.start.min(relative_to);
1383 // let end = rows.end.max(relative_to);
1384
1385 // let buffer_rows = snapshot
1386 // .buffer_rows(start)
1387 // .take(1 + (end - start) as usize)
1388 // .collect::<Vec<_>>();
1389
1390 // let head_idx = relative_to - start;
1391 // let mut delta = 1;
1392 // let mut i = head_idx + 1;
1393 // while i < buffer_rows.len() as u32 {
1394 // if buffer_rows[i as usize].is_some() {
1395 // if rows.contains(&(i + start)) {
1396 // relative_rows.insert(i + start, delta);
1397 // }
1398 // delta += 1;
1399 // }
1400 // i += 1;
1401 // }
1402 // delta = 1;
1403 // i = head_idx.min(buffer_rows.len() as u32 - 1);
1404 // while i > 0 && buffer_rows[i as usize].is_none() {
1405 // i -= 1;
1406 // }
1407
1408 // while i > 0 {
1409 // i -= 1;
1410 // if buffer_rows[i as usize].is_some() {
1411 // if rows.contains(&(i + start)) {
1412 // relative_rows.insert(i + start, delta);
1413 // }
1414 // delta += 1;
1415 // }
1416 // }
1417
1418 // relative_rows
1419 // }
1420
1421 // fn layout_line_numbers(
1422 // &self,
1423 // rows: Range<u32>,
1424 // active_rows: &BTreeMap<u32, bool>,
1425 // newest_selection_head: DisplayPoint,
1426 // is_singleton: bool,
1427 // snapshot: &EditorSnapshot,
1428 // cx: &ViewContext<Editor>,
1429 // ) -> (
1430 // Vec<Option<text_layout::Line>>,
1431 // Vec<Option<(FoldStatus, BufferRow, bool)>>,
1432 // ) {
1433 // let style = &self.style;
1434 // let include_line_numbers = snapshot.mode == EditorMode::Full;
1435 // let mut line_number_layouts = Vec::with_capacity(rows.len());
1436 // let mut fold_statuses = Vec::with_capacity(rows.len());
1437 // let mut line_number = String::new();
1438 // let is_relative = settings::get::<EditorSettings>(cx).relative_line_numbers;
1439 // let relative_to = if is_relative {
1440 // Some(newest_selection_head.row())
1441 // } else {
1442 // None
1443 // };
1444
1445 // let relative_rows = self.calculate_relative_line_numbers(&snapshot, &rows, relative_to);
1446
1447 // for (ix, row) in snapshot
1448 // .buffer_rows(rows.start)
1449 // .take((rows.end - rows.start) as usize)
1450 // .enumerate()
1451 // {
1452 // let display_row = rows.start + ix as u32;
1453 // let (active, color) = if active_rows.contains_key(&display_row) {
1454 // (true, style.line_number_active)
1455 // } else {
1456 // (false, style.line_number)
1457 // };
1458 // if let Some(buffer_row) = row {
1459 // if include_line_numbers {
1460 // line_number.clear();
1461 // let default_number = buffer_row + 1;
1462 // let number = relative_rows
1463 // .get(&(ix as u32 + rows.start))
1464 // .unwrap_or(&default_number);
1465 // write!(&mut line_number, "{}", number).unwrap();
1466 // line_number_layouts.push(Some(cx.text_layout_cache().layout_str(
1467 // &line_number,
1468 // style.text.font_size,
1469 // &[(
1470 // line_number.len(),
1471 // RunStyle {
1472 // font_id: style.text.font_id,
1473 // color,
1474 // underline: Default::default(),
1475 // },
1476 // )],
1477 // )));
1478 // fold_statuses.push(
1479 // is_singleton
1480 // .then(|| {
1481 // snapshot
1482 // .fold_for_line(buffer_row)
1483 // .map(|fold_status| (fold_status, buffer_row, active))
1484 // })
1485 // .flatten(),
1486 // )
1487 // }
1488 // } else {
1489 // fold_statuses.push(None);
1490 // line_number_layouts.push(None);
1491 // }
1492 // }
1493
1494 // (line_number_layouts, fold_statuses)
1495 // }
1496
1497 // fn layout_lines(
1498 // &mut self,
1499 // rows: Range<u32>,
1500 // line_number_layouts: &[Option<Line>],
1501 // snapshot: &EditorSnapshot,
1502 // cx: &ViewContext<Editor>,
1503 // ) -> Vec<LineWithInvisibles> {
1504 // if rows.start >= rows.end {
1505 // return Vec::new();
1506 // }
1507
1508 // // When the editor is empty and unfocused, then show the placeholder.
1509 // if snapshot.is_empty() {
1510 // let placeholder_style = self
1511 // .style
1512 // .placeholder_text
1513 // .as_ref()
1514 // .unwrap_or(&self.style.text);
1515 // let placeholder_text = snapshot.placeholder_text();
1516 // let placeholder_lines = placeholder_text
1517 // .as_ref()
1518 // .map_or("", AsRef::as_ref)
1519 // .split('\n')
1520 // .skip(rows.start as usize)
1521 // .chain(iter::repeat(""))
1522 // .take(rows.len());
1523 // placeholder_lines
1524 // .map(|line| {
1525 // cx.text_layout_cache().layout_str(
1526 // line,
1527 // placeholder_style.font_size,
1528 // &[(
1529 // line.len(),
1530 // RunStyle {
1531 // font_id: placeholder_style.font_id,
1532 // color: placeholder_style.color,
1533 // underline: Default::default(),
1534 // },
1535 // )],
1536 // )
1537 // })
1538 // .map(|line| LineWithInvisibles {
1539 // line,
1540 // invisibles: Vec::new(),
1541 // })
1542 // .collect()
1543 // } else {
1544 // let style = &self.style;
1545 // let chunks = snapshot.highlighted_chunks(rows.clone(), true, style);
1546
1547 // LineWithInvisibles::from_chunks(
1548 // chunks,
1549 // &style.text,
1550 // cx.text_layout_cache(),
1551 // cx.font_cache(),
1552 // MAX_LINE_LEN,
1553 // rows.len() as usize,
1554 // line_number_layouts,
1555 // snapshot.mode,
1556 // )
1557 // }
1558 // }
1559
1560 // #[allow(clippy::too_many_arguments)]
1561 // fn layout_blocks(
1562 // &mut self,
1563 // rows: Range<u32>,
1564 // snapshot: &EditorSnapshot,
1565 // editor_width: f32,
1566 // scroll_width: f32,
1567 // gutter_padding: f32,
1568 // gutter_width: f32,
1569 // em_width: f32,
1570 // text_x: f32,
1571 // line_height: f32,
1572 // style: &EditorStyle,
1573 // line_layouts: &[LineWithInvisibles],
1574 // editor: &mut Editor,
1575 // cx: &mut ViewContext<Editor>,
1576 // ) -> (f32, Vec<BlockLayout>) {
1577 // let mut block_id = 0;
1578 // let scroll_x = snapshot.scroll_anchor.offset.x();
1579 // let (fixed_blocks, non_fixed_blocks) = snapshot
1580 // .blocks_in_range(rows.clone())
1581 // .partition::<Vec<_>, _>(|(_, block)| match block {
1582 // TransformBlock::ExcerptHeader { .. } => false,
1583 // TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed,
1584 // });
1585 // let mut render_block = |block: &TransformBlock, width: f32, block_id: usize| {
1586 // let mut element = match block {
1587 // TransformBlock::Custom(block) => {
1588 // let align_to = block
1589 // .position()
1590 // .to_point(&snapshot.buffer_snapshot)
1591 // .to_display_point(snapshot);
1592 // let anchor_x = text_x
1593 // + if rows.contains(&align_to.row()) {
1594 // line_layouts[(align_to.row() - rows.start) as usize]
1595 // .line
1596 // .x_for_index(align_to.column() as usize)
1597 // } else {
1598 // layout_line(align_to.row(), snapshot, style, cx.text_layout_cache())
1599 // .x_for_index(align_to.column() as usize)
1600 // };
1601
1602 // block.render(&mut BlockContext {
1603 // view_context: cx,
1604 // anchor_x,
1605 // gutter_padding,
1606 // line_height,
1607 // scroll_x,
1608 // gutter_width,
1609 // em_width,
1610 // block_id,
1611 // })
1612 // }
1613 // TransformBlock::ExcerptHeader {
1614 // id,
1615 // buffer,
1616 // range,
1617 // starts_new_buffer,
1618 // ..
1619 // } => {
1620 // let tooltip_style = theme::current(cx).tooltip.clone();
1621 // let include_root = editor
1622 // .project
1623 // .as_ref()
1624 // .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
1625 // .unwrap_or_default();
1626 // let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
1627 // let jump_path = ProjectPath {
1628 // worktree_id: file.worktree_id(cx),
1629 // path: file.path.clone(),
1630 // };
1631 // let jump_anchor = range
1632 // .primary
1633 // .as_ref()
1634 // .map_or(range.context.start, |primary| primary.start);
1635 // let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
1636
1637 // enum JumpIcon {}
1638 // MouseEventHandler::new::<JumpIcon, _>((*id).into(), cx, |state, _| {
1639 // let style = style.jump_icon.style_for(state);
1640 // Svg::new("icons/arrow_up_right.svg")
1641 // .with_color(style.color)
1642 // .constrained()
1643 // .with_width(style.icon_width)
1644 // .aligned()
1645 // .contained()
1646 // .with_style(style.container)
1647 // .constrained()
1648 // .with_width(style.button_width)
1649 // .with_height(style.button_width)
1650 // })
1651 // .with_cursor_style(CursorStyle::PointingHand)
1652 // .on_click(MouseButton::Left, move |_, editor, cx| {
1653 // if let Some(workspace) = editor
1654 // .workspace
1655 // .as_ref()
1656 // .and_then(|(workspace, _)| workspace.upgrade(cx))
1657 // {
1658 // workspace.update(cx, |workspace, cx| {
1659 // Editor::jump(
1660 // workspace,
1661 // jump_path.clone(),
1662 // jump_position,
1663 // jump_anchor,
1664 // cx,
1665 // );
1666 // });
1667 // }
1668 // })
1669 // .with_tooltip::<JumpIcon>(
1670 // (*id).into(),
1671 // "Jump to Buffer".to_string(),
1672 // Some(Box::new(crate::OpenExcerpts)),
1673 // tooltip_style.clone(),
1674 // cx,
1675 // )
1676 // .aligned()
1677 // .flex_float()
1678 // });
1679
1680 // if *starts_new_buffer {
1681 // let editor_font_size = style.text.font_size;
1682 // let style = &style.diagnostic_path_header;
1683 // let font_size = (style.text_scale_factor * editor_font_size).round();
1684
1685 // let path = buffer.resolve_file_path(cx, include_root);
1686 // let mut filename = None;
1687 // let mut parent_path = None;
1688 // // Can't use .and_then() because `.file_name()` and `.parent()` return references :(
1689 // if let Some(path) = path {
1690 // filename = path.file_name().map(|f| f.to_string_lossy().to_string());
1691 // parent_path =
1692 // path.parent().map(|p| p.to_string_lossy().to_string() + "/");
1693 // }
1694
1695 // Flex::row()
1696 // .with_child(
1697 // Label::new(
1698 // filename.unwrap_or_else(|| "untitled".to_string()),
1699 // style.filename.text.clone().with_font_size(font_size),
1700 // )
1701 // .contained()
1702 // .with_style(style.filename.container)
1703 // .aligned(),
1704 // )
1705 // .with_children(parent_path.map(|path| {
1706 // Label::new(path, style.path.text.clone().with_font_size(font_size))
1707 // .contained()
1708 // .with_style(style.path.container)
1709 // .aligned()
1710 // }))
1711 // .with_children(jump_icon)
1712 // .contained()
1713 // .with_style(style.container)
1714 // .with_padding_left(gutter_padding)
1715 // .with_padding_right(gutter_padding)
1716 // .expanded()
1717 // .into_any_named("path header block")
1718 // } else {
1719 // let text_style = style.text.clone();
1720 // Flex::row()
1721 // .with_child(Label::new("⋯", text_style))
1722 // .with_children(jump_icon)
1723 // .contained()
1724 // .with_padding_left(gutter_padding)
1725 // .with_padding_right(gutter_padding)
1726 // .expanded()
1727 // .into_any_named("collapsed context")
1728 // }
1729 // }
1730 // };
1731
1732 // element.layout(
1733 // SizeConstraint {
1734 // min: gpui::Point<Pixels>::zero(),
1735 // max: vec2f(width, block.height() as f32 * line_height),
1736 // },
1737 // editor,
1738 // cx,
1739 // );
1740 // element
1741 // };
1742
1743 // let mut fixed_block_max_width = 0f32;
1744 // let mut blocks = Vec::new();
1745 // for (row, block) in fixed_blocks {
1746 // let element = render_block(block, f32::INFINITY, block_id);
1747 // block_id += 1;
1748 // fixed_block_max_width = fixed_block_max_width.max(element.size().x() + em_width);
1749 // blocks.push(BlockLayout {
1750 // row,
1751 // element,
1752 // style: BlockStyle::Fixed,
1753 // });
1754 // }
1755 // for (row, block) in non_fixed_blocks {
1756 // let style = match block {
1757 // TransformBlock::Custom(block) => block.style(),
1758 // TransformBlock::ExcerptHeader { .. } => BlockStyle::Sticky,
1759 // };
1760 // let width = match style {
1761 // BlockStyle::Sticky => editor_width,
1762 // BlockStyle::Flex => editor_width
1763 // .max(fixed_block_max_width)
1764 // .max(gutter_width + scroll_width),
1765 // BlockStyle::Fixed => unreachable!(),
1766 // };
1767 // let element = render_block(block, width, block_id);
1768 // block_id += 1;
1769 // blocks.push(BlockLayout {
1770 // row,
1771 // element,
1772 // style,
1773 // });
1774 // }
1775 // (
1776 // scroll_width.max(fixed_block_max_width - gutter_width),
1777 // blocks,
1778 // )
1779 // }
1780}
1781
1782#[derive(Debug)]
1783pub struct LineWithInvisibles {
1784 pub line: Line,
1785 invisibles: Vec<Invisible>,
1786}
1787
1788// impl LineWithInvisibles {
1789// fn from_chunks<'a>(
1790// chunks: impl Iterator<Item = HighlightedChunk<'a>>,
1791// text_style: &TextStyle,
1792// text_layout_cache: &TextLayoutCache,
1793// font_cache: &Arc<FontCache>,
1794// max_line_len: usize,
1795// max_line_count: usize,
1796// line_number_layouts: &[Option<Line>],
1797// editor_mode: EditorMode,
1798// ) -> Vec<Self> {
1799// let mut layouts = Vec::with_capacity(max_line_count);
1800// let mut line = String::new();
1801// let mut invisibles = Vec::new();
1802// let mut styles = Vec::new();
1803// let mut non_whitespace_added = false;
1804// let mut row = 0;
1805// let mut line_exceeded_max_len = false;
1806// for highlighted_chunk in chunks.chain([HighlightedChunk {
1807// chunk: "\n",
1808// style: None,
1809// is_tab: false,
1810// }]) {
1811// for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
1812// if ix > 0 {
1813// layouts.push(Self {
1814// line: text_layout_cache.layout_str(&line, text_style.font_size, &styles),
1815// invisibles: invisibles.drain(..).collect(),
1816// });
1817
1818// line.clear();
1819// styles.clear();
1820// row += 1;
1821// line_exceeded_max_len = false;
1822// non_whitespace_added = false;
1823// if row == max_line_count {
1824// return layouts;
1825// }
1826// }
1827
1828// if !line_chunk.is_empty() && !line_exceeded_max_len {
1829// let text_style = if let Some(style) = highlighted_chunk.style {
1830// text_style
1831// .clone()
1832// .highlight(style, font_cache)
1833// .map(Cow::Owned)
1834// .unwrap_or_else(|_| Cow::Borrowed(text_style))
1835// } else {
1836// Cow::Borrowed(text_style)
1837// };
1838
1839// if line.len() + line_chunk.len() > max_line_len {
1840// let mut chunk_len = max_line_len - line.len();
1841// while !line_chunk.is_char_boundary(chunk_len) {
1842// chunk_len -= 1;
1843// }
1844// line_chunk = &line_chunk[..chunk_len];
1845// line_exceeded_max_len = true;
1846// }
1847
1848// styles.push((
1849// line_chunk.len(),
1850// RunStyle {
1851// font_id: text_style.font_id,
1852// color: text_style.color,
1853// underline: text_style.underline,
1854// },
1855// ));
1856
1857// if editor_mode == EditorMode::Full {
1858// // Line wrap pads its contents with fake whitespaces,
1859// // avoid printing them
1860// let inside_wrapped_string = line_number_layouts
1861// .get(row)
1862// .and_then(|layout| layout.as_ref())
1863// .is_none();
1864// if highlighted_chunk.is_tab {
1865// if non_whitespace_added || !inside_wrapped_string {
1866// invisibles.push(Invisible::Tab {
1867// line_start_offset: line.len(),
1868// });
1869// }
1870// } else {
1871// invisibles.extend(
1872// line_chunk
1873// .chars()
1874// .enumerate()
1875// .filter(|(_, line_char)| {
1876// let is_whitespace = line_char.is_whitespace();
1877// non_whitespace_added |= !is_whitespace;
1878// is_whitespace
1879// && (non_whitespace_added || !inside_wrapped_string)
1880// })
1881// .map(|(whitespace_index, _)| Invisible::Whitespace {
1882// line_offset: line.len() + whitespace_index,
1883// }),
1884// )
1885// }
1886// }
1887
1888// line.push_str(line_chunk);
1889// }
1890// }
1891// }
1892
1893// layouts
1894// }
1895
1896// fn draw(
1897// &self,
1898// layout: &LayoutState,
1899// row: u32,
1900// scroll_top: f32,
1901// content_origin: gpui::Point<Pixels>,
1902// scroll_left: f32,
1903// visible_text_bounds: Bounds<Pixels>,
1904// whitespace_setting: ShowWhitespaceSetting,
1905// selection_ranges: &[Range<DisplayPoint>],
1906// visible_bounds: Bounds<Pixels>,
1907// cx: &mut ViewContext<Editor>,
1908// ) {
1909// let line_height = layout.position_map.line_height;
1910// let line_y = row as f32 * line_height - scroll_top;
1911
1912// self.line.paint(
1913// content_origin + vec2f(-scroll_left, line_y),
1914// visible_text_bounds,
1915// line_height,
1916// cx,
1917// );
1918
1919// self.draw_invisibles(
1920// &selection_ranges,
1921// layout,
1922// content_origin,
1923// scroll_left,
1924// line_y,
1925// row,
1926// visible_bounds,
1927// line_height,
1928// whitespace_setting,
1929// cx,
1930// );
1931// }
1932
1933// fn draw_invisibles(
1934// &self,
1935// selection_ranges: &[Range<DisplayPoint>],
1936// layout: &LayoutState,
1937// content_origin: gpui::Point<Pixels>,
1938// scroll_left: f32,
1939// line_y: f32,
1940// row: u32,
1941// visible_bounds: Bounds<Pixels>,
1942// line_height: f32,
1943// whitespace_setting: ShowWhitespaceSetting,
1944// cx: &mut ViewContext<Editor>,
1945// ) {
1946// let allowed_invisibles_regions = match whitespace_setting {
1947// ShowWhitespaceSetting::None => return,
1948// ShowWhitespaceSetting::Selection => Some(selection_ranges),
1949// ShowWhitespaceSetting::All => None,
1950// };
1951
1952// for invisible in &self.invisibles {
1953// let (&token_offset, invisible_symbol) = match invisible {
1954// Invisible::Tab { line_start_offset } => (line_start_offset, &layout.tab_invisible),
1955// Invisible::Whitespace { line_offset } => (line_offset, &layout.space_invisible),
1956// };
1957
1958// let x_offset = self.line.x_for_index(token_offset);
1959// let invisible_offset =
1960// (layout.position_map.em_width - invisible_symbol.width()).max(0.0) / 2.0;
1961// let origin = content_origin + vec2f(-scroll_left + x_offset + invisible_offset, line_y);
1962
1963// if let Some(allowed_regions) = allowed_invisibles_regions {
1964// let invisible_point = DisplayPoint::new(row, token_offset as u32);
1965// if !allowed_regions
1966// .iter()
1967// .any(|region| region.start <= invisible_point && invisible_point < region.end)
1968// {
1969// continue;
1970// }
1971// }
1972// invisible_symbol.paint(origin, visible_bounds, line_height, cx);
1973// }
1974// }
1975// }
1976
1977#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1978enum Invisible {
1979 Tab { line_start_offset: usize },
1980 Whitespace { line_offset: usize },
1981}
1982
1983impl Element<Editor> for EditorElement {
1984 type ElementState = ();
1985
1986 fn id(&self) -> Option<gpui::ElementId> {
1987 None
1988 }
1989
1990 fn initialize(
1991 &mut self,
1992 view_state: &mut Editor,
1993 element_state: Option<Self::ElementState>,
1994 cx: &mut gpui::ViewContext<Editor>,
1995 ) -> Self::ElementState {
1996 ()
1997 }
1998
1999 fn layout(
2000 &mut self,
2001 view_state: &mut Editor,
2002 element_state: &mut Self::ElementState,
2003 cx: &mut gpui::ViewContext<Editor>,
2004 ) -> gpui::LayoutId {
2005 let mut style = Style::default();
2006 style.size.width = relative(1.).into();
2007 style.size.height = relative(1.).into();
2008 cx.request_layout(&style, None)
2009 }
2010
2011 fn paint(
2012 &mut self,
2013 bounds: Bounds<gpui::Pixels>,
2014 view_state: &mut Editor,
2015 element_state: &mut Self::ElementState,
2016 cx: &mut gpui::ViewContext<Editor>,
2017 ) {
2018 let text_style = cx.text_style();
2019
2020 let layout_text = cx.text_system().layout_text(
2021 "hello world",
2022 text_style.font_size * cx.rem_size(),
2023 &[text_style.to_run("hello world".len())],
2024 None,
2025 );
2026 }
2027}
2028
2029// impl EditorElement {
2030// type LayoutState = LayoutState;
2031// type PaintState = ();
2032
2033// fn layout(
2034// &mut self,
2035// constraint: SizeConstraint,
2036// editor: &mut Editor,
2037// cx: &mut ViewContext<Editor>,
2038// ) -> (gpui::Point<Pixels>, Self::LayoutState) {
2039// let mut size = constraint.max;
2040// if size.x().is_infinite() {
2041// unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
2042// }
2043
2044// let snapshot = editor.snapshot(cx);
2045// let style = self.style.clone();
2046
2047// let line_height = (style.text.font_size * style.line_height_scalar).round();
2048
2049// let gutter_padding;
2050// let gutter_width;
2051// let gutter_margin;
2052// if snapshot.show_gutter {
2053// let em_width = style.text.em_width(cx.font_cache());
2054// gutter_padding = (em_width * style.gutter_padding_factor).round();
2055// gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
2056// gutter_margin = -style.text.descent(cx.font_cache());
2057// } else {
2058// gutter_padding = 0.0;
2059// gutter_width = 0.0;
2060// gutter_margin = 0.0;
2061// };
2062
2063// let text_width = size.x() - gutter_width;
2064// let em_width = style.text.em_width(cx.font_cache());
2065// let em_advance = style.text.em_advance(cx.font_cache());
2066// let overscroll = vec2f(em_width, 0.);
2067// let snapshot = {
2068// editor.set_visible_line_count(size.y() / line_height, cx);
2069
2070// let editor_width = text_width - gutter_margin - overscroll.x() - em_width;
2071// let wrap_width = match editor.soft_wrap_mode(cx) {
2072// SoftWrap::None => (MAX_LINE_LEN / 2) as f32 * em_advance,
2073// SoftWrap::EditorWidth => editor_width,
2074// SoftWrap::Column(column) => editor_width.min(column as f32 * em_advance),
2075// };
2076
2077// if editor.set_wrap_width(Some(wrap_width), cx) {
2078// editor.snapshot(cx)
2079// } else {
2080// snapshot
2081// }
2082// };
2083
2084// let wrap_guides = editor
2085// .wrap_guides(cx)
2086// .iter()
2087// .map(|(guide, active)| (self.column_pixels(*guide, cx), *active))
2088// .collect();
2089
2090// let scroll_height = (snapshot.max_point().row() + 1) as f32 * line_height;
2091// if let EditorMode::AutoHeight { max_lines } = snapshot.mode {
2092// size.set_y(
2093// scroll_height
2094// .min(constraint.max_along(Axis::Vertical))
2095// .max(constraint.min_along(Axis::Vertical))
2096// .max(line_height)
2097// .min(line_height * max_lines as f32),
2098// )
2099// } else if let EditorMode::SingleLine = snapshot.mode {
2100// size.set_y(line_height.max(constraint.min_along(Axis::Vertical)))
2101// } else if size.y().is_infinite() {
2102// size.set_y(scroll_height);
2103// }
2104// let gutter_size = vec2f(gutter_width, size.y());
2105// let text_size = vec2f(text_width, size.y());
2106
2107// let autoscroll_horizontally = editor.autoscroll_vertically(size.y(), line_height, cx);
2108// let mut snapshot = editor.snapshot(cx);
2109
2110// let scroll_position = snapshot.scroll_position();
2111// // The scroll position is a fractional point, the whole number of which represents
2112// // the top of the window in terms of display rows.
2113// let start_row = scroll_position.y() as u32;
2114// let height_in_lines = size.y() / line_height;
2115// let max_row = snapshot.max_point().row();
2116
2117// // Add 1 to ensure selections bleed off screen
2118// let end_row = 1 + cmp::min(
2119// (scroll_position.y() + height_in_lines).ceil() as u32,
2120// max_row,
2121// );
2122
2123// let start_anchor = if start_row == 0 {
2124// Anchor::min()
2125// } else {
2126// snapshot
2127// .buffer_snapshot
2128// .anchor_before(DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left))
2129// };
2130// let end_anchor = if end_row > max_row {
2131// Anchor::max()
2132// } else {
2133// snapshot
2134// .buffer_snapshot
2135// .anchor_before(DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right))
2136// };
2137
2138// let mut selections: Vec<(SelectionStyle, Vec<SelectionLayout>)> = Vec::new();
2139// let mut active_rows = BTreeMap::new();
2140// let mut fold_ranges = Vec::new();
2141// let is_singleton = editor.is_singleton(cx);
2142
2143// let highlighted_rows = editor.highlighted_rows();
2144// let theme = theme::current(cx);
2145// let highlighted_ranges = editor.background_highlights_in_range(
2146// start_anchor..end_anchor,
2147// &snapshot.display_snapshot,
2148// theme.as_ref(),
2149// );
2150
2151// fold_ranges.extend(
2152// snapshot
2153// .folds_in_range(start_anchor..end_anchor)
2154// .map(|anchor| {
2155// let start = anchor.start.to_point(&snapshot.buffer_snapshot);
2156// (
2157// start.row,
2158// start.to_display_point(&snapshot.display_snapshot)
2159// ..anchor.end.to_display_point(&snapshot),
2160// )
2161// }),
2162// );
2163
2164// let mut newest_selection_head = None;
2165
2166// if editor.show_local_selections {
2167// let mut local_selections: Vec<Selection<Point>> = editor
2168// .selections
2169// .disjoint_in_range(start_anchor..end_anchor, cx);
2170// local_selections.extend(editor.selections.pending(cx));
2171// let mut layouts = Vec::new();
2172// let newest = editor.selections.newest(cx);
2173// for selection in local_selections.drain(..) {
2174// let is_empty = selection.start == selection.end;
2175// let is_newest = selection == newest;
2176
2177// let layout = SelectionLayout::new(
2178// selection,
2179// editor.selections.line_mode,
2180// editor.cursor_shape,
2181// &snapshot.display_snapshot,
2182// is_newest,
2183// true,
2184// );
2185// if is_newest {
2186// newest_selection_head = Some(layout.head);
2187// }
2188
2189// for row in cmp::max(layout.active_rows.start, start_row)
2190// ..=cmp::min(layout.active_rows.end, end_row)
2191// {
2192// let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty);
2193// *contains_non_empty_selection |= !is_empty;
2194// }
2195// layouts.push(layout);
2196// }
2197
2198// selections.push((style.selection, layouts));
2199// }
2200
2201// if let Some(collaboration_hub) = &editor.collaboration_hub {
2202// // When following someone, render the local selections in their color.
2203// if let Some(leader_id) = editor.leader_peer_id {
2204// if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id) {
2205// if let Some(participant_index) = collaboration_hub
2206// .user_participant_indices(cx)
2207// .get(&collaborator.user_id)
2208// {
2209// if let Some((local_selection_style, _)) = selections.first_mut() {
2210// *local_selection_style =
2211// style.selection_style_for_room_participant(participant_index.0);
2212// }
2213// }
2214// }
2215// }
2216
2217// let mut remote_selections = HashMap::default();
2218// for selection in snapshot.remote_selections_in_range(
2219// &(start_anchor..end_anchor),
2220// collaboration_hub.as_ref(),
2221// cx,
2222// ) {
2223// let selection_style = if let Some(participant_index) = selection.participant_index {
2224// style.selection_style_for_room_participant(participant_index.0)
2225// } else {
2226// style.absent_selection
2227// };
2228
2229// // Don't re-render the leader's selections, since the local selections
2230// // match theirs.
2231// if Some(selection.peer_id) == editor.leader_peer_id {
2232// continue;
2233// }
2234
2235// remote_selections
2236// .entry(selection.replica_id)
2237// .or_insert((selection_style, Vec::new()))
2238// .1
2239// .push(SelectionLayout::new(
2240// selection.selection,
2241// selection.line_mode,
2242// selection.cursor_shape,
2243// &snapshot.display_snapshot,
2244// false,
2245// false,
2246// ));
2247// }
2248
2249// selections.extend(remote_selections.into_values());
2250// }
2251
2252// let scrollbar_settings = &settings::get::<EditorSettings>(cx).scrollbar;
2253// let show_scrollbars = match scrollbar_settings.show {
2254// ShowScrollbar::Auto => {
2255// // Git
2256// (is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs())
2257// ||
2258// // Selections
2259// (is_singleton && scrollbar_settings.selections && !highlighted_ranges.is_empty())
2260// // Scrollmanager
2261// || editor.scroll_manager.scrollbars_visible()
2262// }
2263// ShowScrollbar::System => editor.scroll_manager.scrollbars_visible(),
2264// ShowScrollbar::Always => true,
2265// ShowScrollbar::Never => false,
2266// };
2267
2268// let fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Color)> = fold_ranges
2269// .into_iter()
2270// .map(|(id, fold)| {
2271// let color = self
2272// .style
2273// .folds
2274// .ellipses
2275// .background
2276// .style_for(&mut cx.mouse_state::<FoldMarkers>(id as usize))
2277// .color;
2278
2279// (id, fold, color)
2280// })
2281// .collect();
2282
2283// let head_for_relative = newest_selection_head.unwrap_or_else(|| {
2284// let newest = editor.selections.newest::<Point>(cx);
2285// SelectionLayout::new(
2286// newest,
2287// editor.selections.line_mode,
2288// editor.cursor_shape,
2289// &snapshot.display_snapshot,
2290// true,
2291// true,
2292// )
2293// .head
2294// });
2295
2296// let (line_number_layouts, fold_statuses) = self.layout_line_numbers(
2297// start_row..end_row,
2298// &active_rows,
2299// head_for_relative,
2300// is_singleton,
2301// &snapshot,
2302// cx,
2303// );
2304
2305// let display_hunks = self.layout_git_gutters(start_row..end_row, &snapshot);
2306
2307// let scrollbar_row_range = scroll_position.y()..(scroll_position.y() + height_in_lines);
2308
2309// let mut max_visible_line_width = 0.0;
2310// let line_layouts =
2311// self.layout_lines(start_row..end_row, &line_number_layouts, &snapshot, cx);
2312// for line_with_invisibles in &line_layouts {
2313// if line_with_invisibles.line.width() > max_visible_line_width {
2314// max_visible_line_width = line_with_invisibles.line.width();
2315// }
2316// }
2317
2318// let style = self.style.clone();
2319// let longest_line_width = layout_line(
2320// snapshot.longest_row(),
2321// &snapshot,
2322// &style,
2323// cx.text_layout_cache(),
2324// )
2325// .width();
2326// let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.x();
2327// let em_width = style.text.em_width(cx.font_cache());
2328// let (scroll_width, blocks) = self.layout_blocks(
2329// start_row..end_row,
2330// &snapshot,
2331// size.x(),
2332// scroll_width,
2333// gutter_padding,
2334// gutter_width,
2335// em_width,
2336// gutter_width + gutter_margin,
2337// line_height,
2338// &style,
2339// &line_layouts,
2340// editor,
2341// cx,
2342// );
2343
2344// let scroll_max = vec2f(
2345// ((scroll_width - text_size.x()) / em_width).max(0.0),
2346// max_row as f32,
2347// );
2348
2349// let clamped = editor.scroll_manager.clamp_scroll_left(scroll_max.x());
2350
2351// let autoscrolled = if autoscroll_horizontally {
2352// editor.autoscroll_horizontally(
2353// start_row,
2354// text_size.x(),
2355// scroll_width,
2356// em_width,
2357// &line_layouts,
2358// cx,
2359// )
2360// } else {
2361// false
2362// };
2363
2364// if clamped || autoscrolled {
2365// snapshot = editor.snapshot(cx);
2366// }
2367
2368// let style = editor.style(cx);
2369
2370// let mut context_menu = None;
2371// let mut code_actions_indicator = None;
2372// if let Some(newest_selection_head) = newest_selection_head {
2373// if (start_row..end_row).contains(&newest_selection_head.row()) {
2374// if editor.context_menu_visible() {
2375// context_menu =
2376// editor.render_context_menu(newest_selection_head, style.clone(), cx);
2377// }
2378
2379// let active = matches!(
2380// editor.context_menu.read().as_ref(),
2381// Some(crate::ContextMenu::CodeActions(_))
2382// );
2383
2384// code_actions_indicator = editor
2385// .render_code_actions_indicator(&style, active, cx)
2386// .map(|indicator| (newest_selection_head.row(), indicator));
2387// }
2388// }
2389
2390// let visible_rows = start_row..start_row + line_layouts.len() as u32;
2391// let mut hover = editor.hover_state.render(
2392// &snapshot,
2393// &style,
2394// visible_rows,
2395// editor.workspace.as_ref().map(|(w, _)| w.clone()),
2396// cx,
2397// );
2398// let mode = editor.mode;
2399
2400// let mut fold_indicators = editor.render_fold_indicators(
2401// fold_statuses,
2402// &style,
2403// editor.gutter_hovered,
2404// line_height,
2405// gutter_margin,
2406// cx,
2407// );
2408
2409// if let Some((_, context_menu)) = context_menu.as_mut() {
2410// context_menu.layout(
2411// SizeConstraint {
2412// min: gpui::Point<Pixels>::zero(),
2413// max: vec2f(
2414// cx.window_size().x() * 0.7,
2415// (12. * line_height).min((size.y() - line_height) / 2.),
2416// ),
2417// },
2418// editor,
2419// cx,
2420// );
2421// }
2422
2423// if let Some((_, indicator)) = code_actions_indicator.as_mut() {
2424// indicator.layout(
2425// SizeConstraint::strict_along(
2426// Axis::Vertical,
2427// line_height * style.code_actions.vertical_scale,
2428// ),
2429// editor,
2430// cx,
2431// );
2432// }
2433
2434// for fold_indicator in fold_indicators.iter_mut() {
2435// if let Some(indicator) = fold_indicator.as_mut() {
2436// indicator.layout(
2437// SizeConstraint::strict_along(
2438// Axis::Vertical,
2439// line_height * style.code_actions.vertical_scale,
2440// ),
2441// editor,
2442// cx,
2443// );
2444// }
2445// }
2446
2447// if let Some((_, hover_popovers)) = hover.as_mut() {
2448// for hover_popover in hover_popovers.iter_mut() {
2449// hover_popover.layout(
2450// SizeConstraint {
2451// min: gpui::Point<Pixels>::zero(),
2452// max: vec2f(
2453// (120. * em_width) // Default size
2454// .min(size.x() / 2.) // Shrink to half of the editor width
2455// .max(MIN_POPOVER_CHARACTER_WIDTH * em_width), // Apply minimum width of 20 characters
2456// (16. * line_height) // Default size
2457// .min(size.y() / 2.) // Shrink to half of the editor height
2458// .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
2459// ),
2460// },
2461// editor,
2462// cx,
2463// );
2464// }
2465// }
2466
2467// let invisible_symbol_font_size = self.style.text.font_size / 2.0;
2468// let invisible_symbol_style = RunStyle {
2469// color: self.style.whitespace,
2470// font_id: self.style.text.font_id,
2471// underline: Default::default(),
2472// };
2473
2474// (
2475// size,
2476// LayoutState {
2477// mode,
2478// position_map: Arc::new(PositionMap {
2479// size,
2480// scroll_max,
2481// line_layouts,
2482// line_height,
2483// em_width,
2484// em_advance,
2485// snapshot,
2486// }),
2487// visible_display_row_range: start_row..end_row,
2488// wrap_guides,
2489// gutter_size,
2490// gutter_padding,
2491// text_size,
2492// scrollbar_row_range,
2493// show_scrollbars,
2494// is_singleton,
2495// max_row,
2496// gutter_margin,
2497// active_rows,
2498// highlighted_rows,
2499// highlighted_ranges,
2500// fold_ranges,
2501// line_number_layouts,
2502// display_hunks,
2503// blocks,
2504// selections,
2505// context_menu,
2506// code_actions_indicator,
2507// fold_indicators,
2508// tab_invisible: cx.text_layout_cache().layout_str(
2509// "→",
2510// invisible_symbol_font_size,
2511// &[("→".len(), invisible_symbol_style)],
2512// ),
2513// space_invisible: cx.text_layout_cache().layout_str(
2514// "•",
2515// invisible_symbol_font_size,
2516// &[("•".len(), invisible_symbol_style)],
2517// ),
2518// hover_popovers: hover,
2519// },
2520// )
2521// }
2522
2523// fn paint(
2524// &mut self,
2525// bounds: Bounds<Pixels>,
2526// visible_bounds: Bounds<Pixels>,
2527// layout: &mut Self::LayoutState,
2528// editor: &mut Editor,
2529// cx: &mut ViewContext<Editor>,
2530// ) -> Self::PaintState {
2531// let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
2532// cx.scene().push_layer(Some(visible_bounds));
2533
2534// let gutter_bounds = Bounds<Pixels>::new(bounds.origin(), layout.gutter_size);
2535// let text_bounds = Bounds<Pixels>::new(
2536// bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
2537// layout.text_size,
2538// );
2539
2540// Self::attach_mouse_handlers(
2541// &layout.position_map,
2542// layout.hover_popovers.is_some(),
2543// visible_bounds,
2544// text_bounds,
2545// gutter_bounds,
2546// bounds,
2547// cx,
2548// );
2549
2550// self.paint_background(gutter_bounds, text_bounds, layout, cx);
2551// if layout.gutter_size.x() > 0. {
2552// self.paint_gutter(gutter_bounds, visible_bounds, layout, editor, cx);
2553// }
2554// self.paint_text(text_bounds, visible_bounds, layout, editor, cx);
2555
2556// cx.scene().push_layer(Some(bounds));
2557// if !layout.blocks.is_empty() {
2558// self.paint_blocks(bounds, visible_bounds, layout, editor, cx);
2559// }
2560// self.paint_scrollbar(bounds, layout, &editor, cx);
2561// cx.scene().pop_layer();
2562// cx.scene().pop_layer();
2563// }
2564
2565// fn rect_for_text_range(
2566// &self,
2567// range_utf16: Range<usize>,
2568// bounds: Bounds<Pixels>,
2569// _: Bounds<Pixels>,
2570// layout: &Self::LayoutState,
2571// _: &Self::PaintState,
2572// _: &Editor,
2573// _: &ViewContext<Editor>,
2574// ) -> Option<Bounds<Pixels>> {
2575// let text_bounds = Bounds<Pixels>::new(
2576// bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
2577// layout.text_size,
2578// );
2579// let content_origin = text_bounds.origin() + vec2f(layout.gutter_margin, 0.);
2580// let scroll_position = layout.position_map.snapshot.scroll_position();
2581// let start_row = scroll_position.y() as u32;
2582// let scroll_top = scroll_position.y() * layout.position_map.line_height;
2583// let scroll_left = scroll_position.x() * layout.position_map.em_width;
2584
2585// let range_start = OffsetUtf16(range_utf16.start)
2586// .to_display_point(&layout.position_map.snapshot.display_snapshot);
2587// if range_start.row() < start_row {
2588// return None;
2589// }
2590
2591// let line = &layout
2592// .position_map
2593// .line_layouts
2594// .get((range_start.row() - start_row) as usize)?
2595// .line;
2596// let range_start_x = line.x_for_index(range_start.column() as usize);
2597// let range_start_y = range_start.row() as f32 * layout.position_map.line_height;
2598// Some(Bounds<Pixels>::new(
2599// content_origin
2600// + vec2f(
2601// range_start_x,
2602// range_start_y + layout.position_map.line_height,
2603// )
2604// - vec2f(scroll_left, scroll_top),
2605// vec2f(
2606// layout.position_map.em_width,
2607// layout.position_map.line_height,
2608// ),
2609// ))
2610// }
2611
2612// fn debug(
2613// &self,
2614// bounds: Bounds<Pixels>,
2615// _: &Self::LayoutState,
2616// _: &Self::PaintState,
2617// _: &Editor,
2618// _: &ViewContext<Editor>,
2619// ) -> json::Value {
2620// json!({
2621// "type": "BufferElement",
2622// "bounds": bounds.to_json()
2623// })
2624// }
2625// }
2626
2627type BufferRow = u32;
2628
2629// pub struct LayoutState {
2630// position_map: Arc<PositionMap>,
2631// gutter_size: gpui::Point<Pixels>,
2632// gutter_padding: f32,
2633// gutter_margin: f32,
2634// text_size: gpui::Point<Pixels>,
2635// mode: EditorMode,
2636// wrap_guides: SmallVec<[(f32, bool); 2]>,
2637// visible_display_row_range: Range<u32>,
2638// active_rows: BTreeMap<u32, bool>,
2639// highlighted_rows: Option<Range<u32>>,
2640// line_number_layouts: Vec<Option<text_layout::Line>>,
2641// display_hunks: Vec<DisplayDiffHunk>,
2642// blocks: Vec<BlockLayout>,
2643// highlighted_ranges: Vec<(Range<DisplayPoint>, Color)>,
2644// fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Color)>,
2645// selections: Vec<(SelectionStyle, Vec<SelectionLayout>)>,
2646// scrollbar_row_range: Range<f32>,
2647// show_scrollbars: bool,
2648// is_singleton: bool,
2649// max_row: u32,
2650// context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
2651// code_actions_indicator: Option<(u32, AnyElement<Editor>)>,
2652// hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
2653// fold_indicators: Vec<Option<AnyElement<Editor>>>,
2654// tab_invisible: Line,
2655// space_invisible: Line,
2656// }
2657
2658struct PositionMap {
2659 size: Size<Pixels>,
2660 line_height: Pixels,
2661 scroll_max: Size<Pixels>,
2662 em_width: Pixels,
2663 em_advance: Pixels,
2664 line_layouts: Vec<LineWithInvisibles>,
2665 snapshot: EditorSnapshot,
2666}
2667
2668#[derive(Debug, Copy, Clone)]
2669pub struct PointForPosition {
2670 pub previous_valid: DisplayPoint,
2671 pub next_valid: DisplayPoint,
2672 pub exact_unclipped: DisplayPoint,
2673 pub column_overshoot_after_line_end: u32,
2674}
2675
2676impl PointForPosition {
2677 #[cfg(test)]
2678 pub fn valid(valid: DisplayPoint) -> Self {
2679 Self {
2680 previous_valid: valid,
2681 next_valid: valid,
2682 exact_unclipped: valid,
2683 column_overshoot_after_line_end: 0,
2684 }
2685 }
2686
2687 pub fn as_valid(&self) -> Option<DisplayPoint> {
2688 if self.previous_valid == self.exact_unclipped && self.next_valid == self.exact_unclipped {
2689 Some(self.previous_valid)
2690 } else {
2691 None
2692 }
2693 }
2694}
2695
2696impl PositionMap {
2697 fn point_for_position(
2698 &self,
2699 text_bounds: Bounds<Pixels>,
2700 position: gpui::Point<Pixels>,
2701 ) -> PointForPosition {
2702 let scroll_position = self.snapshot.scroll_position();
2703 let position = position - text_bounds.origin;
2704 let y = position.y.max(px(0.)).min(self.size.width);
2705 let x = position.x + (scroll_position.x * self.em_width);
2706 let row = (f32::from(y / self.line_height) + scroll_position.y) as u32;
2707
2708 let (column, x_overshoot_after_line_end) = if let Some(line) = self
2709 .line_layouts
2710 .get(row as usize - scroll_position.y as usize)
2711 .map(|&LineWithInvisibles { ref line, .. }| line)
2712 {
2713 if let Some(ix) = line.index_for_x(x) {
2714 (ix as u32, px(0.))
2715 } else {
2716 (line.len as u32, px(0.).max(x - line.width()))
2717 }
2718 } else {
2719 (0, x)
2720 };
2721
2722 let mut exact_unclipped = DisplayPoint::new(row, column);
2723 let previous_valid = self.snapshot.clip_point(exact_unclipped, Bias::Left);
2724 let next_valid = self.snapshot.clip_point(exact_unclipped, Bias::Right);
2725
2726 let column_overshoot_after_line_end = (x_overshoot_after_line_end / self.em_advance).into();
2727 *exact_unclipped.column_mut() += column_overshoot_after_line_end;
2728 PointForPosition {
2729 previous_valid,
2730 next_valid,
2731 exact_unclipped,
2732 column_overshoot_after_line_end,
2733 }
2734 }
2735}
2736
2737struct BlockLayout {
2738 row: u32,
2739 element: AnyElement<Editor>,
2740 style: BlockStyle,
2741}
2742
2743fn layout_line(
2744 row: u32,
2745 snapshot: &EditorSnapshot,
2746 style: &EditorStyle,
2747 rem_size: Pixels,
2748 text_system: &TextSystem,
2749) -> Result<SmallVec<[Line; 1]>> {
2750 let mut line = snapshot.line(row);
2751
2752 if line.len() > MAX_LINE_LEN {
2753 let mut len = MAX_LINE_LEN;
2754 while !line.is_char_boundary(len) {
2755 len -= 1;
2756 }
2757
2758 line.truncate(len);
2759 }
2760
2761 text_system.layout_text(
2762 &line,
2763 style.text.font_size * rem_size,
2764 &[TextRun {
2765 len: snapshot.line_len(row) as usize,
2766 font: style.text.font(),
2767 color: black(),
2768 underline: Default::default(),
2769 }],
2770 None,
2771 )
2772}
2773
2774#[derive(Debug)]
2775pub struct Cursor {
2776 origin: gpui::Point<Pixels>,
2777 block_width: Pixels,
2778 line_height: Pixels,
2779 color: Hsla,
2780 shape: CursorShape,
2781 block_text: Option<Line>,
2782}
2783
2784impl Cursor {
2785 // pub fn new(
2786 // origin: gpui::Point<Pixels>,
2787 // block_width: f32,
2788 // line_height: f32,
2789 // color: Color,
2790 // shape: CursorShape,
2791 // block_text: Option<Line>,
2792 // ) -> Cursor {
2793 // Cursor {
2794 // origin,
2795 // block_width,
2796 // line_height,
2797 // color,
2798 // shape,
2799 // block_text,
2800 // }
2801 // }
2802
2803 // pub fn bounding_rect(&self, origin: gpui::Point<Pixels>) -> Bounds<Pixels> {
2804 // Bounds<Pixels>::new(
2805 // self.origin + origin,
2806 // vec2f(self.block_width, self.line_height),
2807 // )
2808 // }
2809
2810 // pub fn paint(&self, origin: gpui::Point<Pixels>, cx: &mut WindowContext) {
2811 // let bounds = match self.shape {
2812 // CursorShape::Bar => Bounds<Pixels>::new(self.origin + origin, vec2f(2.0, self.line_height)),
2813 // CursorShape::Block | CursorShape::Hollow => Bounds<Pixels>::new(
2814 // self.origin + origin,
2815 // vec2f(self.block_width, self.line_height),
2816 // ),
2817 // CursorShape::Underscore => Bounds<Pixels>::new(
2818 // self.origin + origin + gpui::Point<Pixels>::new(0.0, self.line_height - 2.0),
2819 // vec2f(self.block_width, 2.0),
2820 // ),
2821 // };
2822
2823 // //Draw background or border quad
2824 // if matches!(self.shape, CursorShape::Hollow) {
2825 // cx.scene().push_quad(Quad {
2826 // bounds,
2827 // background: None,
2828 // border: Border::all(1., self.color).into(),
2829 // corner_radii: Default::default(),
2830 // });
2831 // } else {
2832 // cx.scene().push_quad(Quad {
2833 // bounds,
2834 // background: Some(self.color),
2835 // border: Default::default(),
2836 // corner_radii: Default::default(),
2837 // });
2838 // }
2839
2840 // if let Some(block_text) = &self.block_text {
2841 // block_text.paint(self.origin + origin, bounds, self.line_height, cx);
2842 // }
2843 // }
2844
2845 // pub fn shape(&self) -> CursorShape {
2846 // self.shape
2847 // }
2848}
2849
2850#[derive(Debug)]
2851pub struct HighlightedRange {
2852 pub start_y: Pixels,
2853 pub line_height: Pixels,
2854 pub lines: Vec<HighlightedRangeLine>,
2855 pub color: Hsla,
2856 pub corner_radius: Pixels,
2857}
2858
2859#[derive(Debug)]
2860pub struct HighlightedRangeLine {
2861 pub start_x: f32,
2862 pub end_x: f32,
2863}
2864
2865impl HighlightedRange {
2866 // pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
2867 // if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
2868 // self.paint_lines(self.start_y, &self.lines[0..1], bounds, cx);
2869 // self.paint_lines(
2870 // self.start_y + self.line_height,
2871 // &self.lines[1..],
2872 // bounds,
2873 // cx,
2874 // );
2875 // } else {
2876 // self.paint_lines(self.start_y, &self.lines, bounds, cx);
2877 // }
2878 // }
2879
2880 // fn paint_lines(
2881 // &self,
2882 // start_y: f32,
2883 // lines: &[HighlightedRangeLine],
2884 // bounds: Bounds<Pixels>,
2885 // cx: &mut WindowContext,
2886 // ) {
2887 // if lines.is_empty() {
2888 // return;
2889 // }
2890
2891 // let mut path = PathBuilder::new();
2892 // let first_line = lines.first().unwrap();
2893 // let last_line = lines.last().unwrap();
2894
2895 // let first_top_left = vec2f(first_line.start_x, start_y);
2896 // let first_top_right = vec2f(first_line.end_x, start_y);
2897
2898 // let curve_height = vec2f(0., self.corner_radius);
2899 // let curve_width = |start_x: f32, end_x: f32| {
2900 // let max = (end_x - start_x) / 2.;
2901 // let width = if max < self.corner_radius {
2902 // max
2903 // } else {
2904 // self.corner_radius
2905 // };
2906
2907 // vec2f(width, 0.)
2908 // };
2909
2910 // let top_curve_width = curve_width(first_line.start_x, first_line.end_x);
2911 // path.reset(first_top_right - top_curve_width);
2912 // path.curve_to(first_top_right + curve_height, first_top_right);
2913
2914 // let mut iter = lines.iter().enumerate().peekable();
2915 // while let Some((ix, line)) = iter.next() {
2916 // let bottom_right = vec2f(line.end_x, start_y + (ix + 1) as f32 * self.line_height);
2917
2918 // if let Some((_, next_line)) = iter.peek() {
2919 // let next_top_right = vec2f(next_line.end_x, bottom_right.y());
2920
2921 // match next_top_right.x().partial_cmp(&bottom_right.x()).unwrap() {
2922 // Ordering::Equal => {
2923 // path.line_to(bottom_right);
2924 // }
2925 // Ordering::Less => {
2926 // let curve_width = curve_width(next_top_right.x(), bottom_right.x());
2927 // path.line_to(bottom_right - curve_height);
2928 // if self.corner_radius > 0. {
2929 // path.curve_to(bottom_right - curve_width, bottom_right);
2930 // }
2931 // path.line_to(next_top_right + curve_width);
2932 // if self.corner_radius > 0. {
2933 // path.curve_to(next_top_right + curve_height, next_top_right);
2934 // }
2935 // }
2936 // Ordering::Greater => {
2937 // let curve_width = curve_width(bottom_right.x(), next_top_right.x());
2938 // path.line_to(bottom_right - curve_height);
2939 // if self.corner_radius > 0. {
2940 // path.curve_to(bottom_right + curve_width, bottom_right);
2941 // }
2942 // path.line_to(next_top_right - curve_width);
2943 // if self.corner_radius > 0. {
2944 // path.curve_to(next_top_right + curve_height, next_top_right);
2945 // }
2946 // }
2947 // }
2948 // } else {
2949 // let curve_width = curve_width(line.start_x, line.end_x);
2950 // path.line_to(bottom_right - curve_height);
2951 // if self.corner_radius > 0. {
2952 // path.curve_to(bottom_right - curve_width, bottom_right);
2953 // }
2954
2955 // let bottom_left = vec2f(line.start_x, bottom_right.y());
2956 // path.line_to(bottom_left + curve_width);
2957 // if self.corner_radius > 0. {
2958 // path.curve_to(bottom_left - curve_height, bottom_left);
2959 // }
2960 // }
2961 // }
2962
2963 // if first_line.start_x > last_line.start_x {
2964 // let curve_width = curve_width(last_line.start_x, first_line.start_x);
2965 // let second_top_left = vec2f(last_line.start_x, start_y + self.line_height);
2966 // path.line_to(second_top_left + curve_height);
2967 // if self.corner_radius > 0. {
2968 // path.curve_to(second_top_left + curve_width, second_top_left);
2969 // }
2970 // let first_bottom_left = vec2f(first_line.start_x, second_top_left.y());
2971 // path.line_to(first_bottom_left - curve_width);
2972 // if self.corner_radius > 0. {
2973 // path.curve_to(first_bottom_left - curve_height, first_bottom_left);
2974 // }
2975 // }
2976
2977 // path.line_to(first_top_left + curve_height);
2978 // if self.corner_radius > 0. {
2979 // path.curve_to(first_top_left + top_curve_width, first_top_left);
2980 // }
2981 // path.line_to(first_top_right - top_curve_width);
2982
2983 // cx.scene().push_path(path.build(self.color, Some(bounds)));
2984 // }
2985}
2986
2987// fn range_to_bounds(
2988// range: &Range<DisplayPoint>,
2989// content_origin: gpui::Point<Pixels>,
2990// scroll_left: f32,
2991// scroll_top: f32,
2992// visible_row_range: &Range<u32>,
2993// line_end_overshoot: f32,
2994// position_map: &PositionMap,
2995// ) -> impl Iterator<Item = Bounds<Pixels>> {
2996// let mut bounds: SmallVec<[Bounds<Pixels>; 1]> = SmallVec::new();
2997
2998// if range.start == range.end {
2999// return bounds.into_iter();
3000// }
3001
3002// let start_row = visible_row_range.start;
3003// let end_row = visible_row_range.end;
3004
3005// let row_range = if range.end.column() == 0 {
3006// cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
3007// } else {
3008// cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
3009// };
3010
3011// let first_y =
3012// content_origin.y() + row_range.start as f32 * position_map.line_height - scroll_top;
3013
3014// for (idx, row) in row_range.enumerate() {
3015// let line_layout = &position_map.line_layouts[(row - start_row) as usize].line;
3016
3017// let start_x = if row == range.start.row() {
3018// content_origin.x() + line_layout.x_for_index(range.start.column() as usize)
3019// - scroll_left
3020// } else {
3021// content_origin.x() - scroll_left
3022// };
3023
3024// let end_x = if row == range.end.row() {
3025// content_origin.x() + line_layout.x_for_index(range.end.column() as usize) - scroll_left
3026// } else {
3027// content_origin.x() + line_layout.width() + line_end_overshoot - scroll_left
3028// };
3029
3030// bounds.push(Bounds<Pixels>::from_points(
3031// vec2f(start_x, first_y + position_map.line_height * idx as f32),
3032// vec2f(end_x, first_y + position_map.line_height * (idx + 1) as f32),
3033// ))
3034// }
3035
3036// bounds.into_iter()
3037// }
3038
3039pub fn scale_vertical_mouse_autoscroll_delta(delta: f32) -> f32 {
3040 delta.powf(1.5) / 100.0
3041}
3042
3043fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
3044 delta.powf(1.2) / 300.0
3045}
3046
3047// #[cfg(test)]
3048// mod tests {
3049// use super::*;
3050// use crate::{
3051// display_map::{BlockDisposition, BlockProperties},
3052// editor_tests::{init_test, update_test_language_settings},
3053// Editor, MultiBuffer,
3054// };
3055// use gpui::TestAppContext;
3056// use language::language_settings;
3057// use log::info;
3058// use std::{num::NonZeroU32, sync::Arc};
3059// use util::test::sample_text;
3060
3061// #[gpui::test]
3062// fn test_layout_line_numbers(cx: &mut TestAppContext) {
3063// init_test(cx, |_| {});
3064// let editor = cx
3065// .add_window(|cx| {
3066// let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
3067// Editor::new(EditorMode::Full, buffer, None, None, cx)
3068// })
3069// .root(cx);
3070// let element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3071
3072// let layouts = editor.update(cx, |editor, cx| {
3073// let snapshot = editor.snapshot(cx);
3074// element
3075// .layout_line_numbers(
3076// 0..6,
3077// &Default::default(),
3078// DisplayPoint::new(0, 0),
3079// false,
3080// &snapshot,
3081// cx,
3082// )
3083// .0
3084// });
3085// assert_eq!(layouts.len(), 6);
3086
3087// let relative_rows = editor.update(cx, |editor, cx| {
3088// let snapshot = editor.snapshot(cx);
3089// element.calculate_relative_line_numbers(&snapshot, &(0..6), Some(3))
3090// });
3091// assert_eq!(relative_rows[&0], 3);
3092// assert_eq!(relative_rows[&1], 2);
3093// assert_eq!(relative_rows[&2], 1);
3094// // current line has no relative number
3095// assert_eq!(relative_rows[&4], 1);
3096// assert_eq!(relative_rows[&5], 2);
3097
3098// // works if cursor is before screen
3099// let relative_rows = editor.update(cx, |editor, cx| {
3100// let snapshot = editor.snapshot(cx);
3101
3102// element.calculate_relative_line_numbers(&snapshot, &(3..6), Some(1))
3103// });
3104// assert_eq!(relative_rows.len(), 3);
3105// assert_eq!(relative_rows[&3], 2);
3106// assert_eq!(relative_rows[&4], 3);
3107// assert_eq!(relative_rows[&5], 4);
3108
3109// // works if cursor is after screen
3110// let relative_rows = editor.update(cx, |editor, cx| {
3111// let snapshot = editor.snapshot(cx);
3112
3113// element.calculate_relative_line_numbers(&snapshot, &(0..3), Some(6))
3114// });
3115// assert_eq!(relative_rows.len(), 3);
3116// assert_eq!(relative_rows[&0], 5);
3117// assert_eq!(relative_rows[&1], 4);
3118// assert_eq!(relative_rows[&2], 3);
3119// }
3120
3121// #[gpui::test]
3122// async fn test_vim_visual_selections(cx: &mut TestAppContext) {
3123// init_test(cx, |_| {});
3124
3125// let editor = cx
3126// .add_window(|cx| {
3127// let buffer = MultiBuffer::build_simple(&(sample_text(6, 6, 'a') + "\n"), cx);
3128// Editor::new(EditorMode::Full, buffer, None, None, cx)
3129// })
3130// .root(cx);
3131// let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3132// let (_, state) = editor.update(cx, |editor, cx| {
3133// editor.cursor_shape = CursorShape::Block;
3134// editor.change_selections(None, cx, |s| {
3135// s.select_ranges([
3136// Point::new(0, 0)..Point::new(1, 0),
3137// Point::new(3, 2)..Point::new(3, 3),
3138// Point::new(5, 6)..Point::new(6, 0),
3139// ]);
3140// });
3141// element.layout(
3142// SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
3143// editor,
3144// cx,
3145// )
3146// });
3147// assert_eq!(state.selections.len(), 1);
3148// let local_selections = &state.selections[0].1;
3149// assert_eq!(local_selections.len(), 3);
3150// // moves cursor back one line
3151// assert_eq!(local_selections[0].head, DisplayPoint::new(0, 6));
3152// assert_eq!(
3153// local_selections[0].range,
3154// DisplayPoint::new(0, 0)..DisplayPoint::new(1, 0)
3155// );
3156
3157// // moves cursor back one column
3158// assert_eq!(
3159// local_selections[1].range,
3160// DisplayPoint::new(3, 2)..DisplayPoint::new(3, 3)
3161// );
3162// assert_eq!(local_selections[1].head, DisplayPoint::new(3, 2));
3163
3164// // leaves cursor on the max point
3165// assert_eq!(
3166// local_selections[2].range,
3167// DisplayPoint::new(5, 6)..DisplayPoint::new(6, 0)
3168// );
3169// assert_eq!(local_selections[2].head, DisplayPoint::new(6, 0));
3170
3171// // active lines does not include 1 (even though the range of the selection does)
3172// assert_eq!(
3173// state.active_rows.keys().cloned().collect::<Vec<u32>>(),
3174// vec![0, 3, 5, 6]
3175// );
3176
3177// // multi-buffer support
3178// // in DisplayPoint co-ordinates, this is what we're dealing with:
3179// // 0: [[file
3180// // 1: header]]
3181// // 2: aaaaaa
3182// // 3: bbbbbb
3183// // 4: cccccc
3184// // 5:
3185// // 6: ...
3186// // 7: ffffff
3187// // 8: gggggg
3188// // 9: hhhhhh
3189// // 10:
3190// // 11: [[file
3191// // 12: header]]
3192// // 13: bbbbbb
3193// // 14: cccccc
3194// // 15: dddddd
3195// let editor = cx
3196// .add_window(|cx| {
3197// let buffer = MultiBuffer::build_multi(
3198// [
3199// (
3200// &(sample_text(8, 6, 'a') + "\n"),
3201// vec![
3202// Point::new(0, 0)..Point::new(3, 0),
3203// Point::new(4, 0)..Point::new(7, 0),
3204// ],
3205// ),
3206// (
3207// &(sample_text(8, 6, 'a') + "\n"),
3208// vec![Point::new(1, 0)..Point::new(3, 0)],
3209// ),
3210// ],
3211// cx,
3212// );
3213// Editor::new(EditorMode::Full, buffer, None, None, cx)
3214// })
3215// .root(cx);
3216// let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3217// let (_, state) = editor.update(cx, |editor, cx| {
3218// editor.cursor_shape = CursorShape::Block;
3219// editor.change_selections(None, cx, |s| {
3220// s.select_display_ranges([
3221// DisplayPoint::new(4, 0)..DisplayPoint::new(7, 0),
3222// DisplayPoint::new(10, 0)..DisplayPoint::new(13, 0),
3223// ]);
3224// });
3225// element.layout(
3226// SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
3227// editor,
3228// cx,
3229// )
3230// });
3231
3232// assert_eq!(state.selections.len(), 1);
3233// let local_selections = &state.selections[0].1;
3234// assert_eq!(local_selections.len(), 2);
3235
3236// // moves cursor on excerpt boundary back a line
3237// // and doesn't allow selection to bleed through
3238// assert_eq!(
3239// local_selections[0].range,
3240// DisplayPoint::new(4, 0)..DisplayPoint::new(6, 0)
3241// );
3242// assert_eq!(local_selections[0].head, DisplayPoint::new(5, 0));
3243
3244// // moves cursor on buffer boundary back two lines
3245// // and doesn't allow selection to bleed through
3246// assert_eq!(
3247// local_selections[1].range,
3248// DisplayPoint::new(10, 0)..DisplayPoint::new(11, 0)
3249// );
3250// assert_eq!(local_selections[1].head, DisplayPoint::new(10, 0));
3251// }
3252
3253// #[gpui::test]
3254// fn test_layout_with_placeholder_text_and_blocks(cx: &mut TestAppContext) {
3255// init_test(cx, |_| {});
3256
3257// let editor = cx
3258// .add_window(|cx| {
3259// let buffer = MultiBuffer::build_simple("", cx);
3260// Editor::new(EditorMode::Full, buffer, None, None, cx)
3261// })
3262// .root(cx);
3263
3264// editor.update(cx, |editor, cx| {
3265// editor.set_placeholder_text("hello", cx);
3266// editor.insert_blocks(
3267// [BlockProperties {
3268// style: BlockStyle::Fixed,
3269// disposition: BlockDisposition::Above,
3270// height: 3,
3271// position: Anchor::min(),
3272// render: Arc::new(|_| Empty::new().into_any()),
3273// }],
3274// None,
3275// cx,
3276// );
3277
3278// // Blur the editor so that it displays placeholder text.
3279// cx.blur();
3280// });
3281
3282// let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3283// let (size, mut state) = editor.update(cx, |editor, cx| {
3284// element.layout(
3285// SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
3286// editor,
3287// cx,
3288// )
3289// });
3290
3291// assert_eq!(state.position_map.line_layouts.len(), 4);
3292// assert_eq!(
3293// state
3294// .line_number_layouts
3295// .iter()
3296// .map(Option::is_some)
3297// .collect::<Vec<_>>(),
3298// &[false, false, false, true]
3299// );
3300
3301// // Don't panic.
3302// let bounds = Bounds<Pixels>::new(Default::default(), size);
3303// editor.update(cx, |editor, cx| {
3304// element.paint(bounds, bounds, &mut state, editor, cx);
3305// });
3306// }
3307
3308// #[gpui::test]
3309// fn test_all_invisibles_drawing(cx: &mut TestAppContext) {
3310// const TAB_SIZE: u32 = 4;
3311
3312// let input_text = "\t \t|\t| a b";
3313// let expected_invisibles = vec![
3314// Invisible::Tab {
3315// line_start_offset: 0,
3316// },
3317// Invisible::Whitespace {
3318// line_offset: TAB_SIZE as usize,
3319// },
3320// Invisible::Tab {
3321// line_start_offset: TAB_SIZE as usize + 1,
3322// },
3323// Invisible::Tab {
3324// line_start_offset: TAB_SIZE as usize * 2 + 1,
3325// },
3326// Invisible::Whitespace {
3327// line_offset: TAB_SIZE as usize * 3 + 1,
3328// },
3329// Invisible::Whitespace {
3330// line_offset: TAB_SIZE as usize * 3 + 3,
3331// },
3332// ];
3333// assert_eq!(
3334// expected_invisibles.len(),
3335// input_text
3336// .chars()
3337// .filter(|initial_char| initial_char.is_whitespace())
3338// .count(),
3339// "Hardcoded expected invisibles differ from the actual ones in '{input_text}'"
3340// );
3341
3342// init_test(cx, |s| {
3343// s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
3344// s.defaults.tab_size = NonZeroU32::new(TAB_SIZE);
3345// });
3346
3347// let actual_invisibles =
3348// collect_invisibles_from_new_editor(cx, EditorMode::Full, &input_text, 500.0);
3349
3350// assert_eq!(expected_invisibles, actual_invisibles);
3351// }
3352
3353// #[gpui::test]
3354// fn test_invisibles_dont_appear_in_certain_editors(cx: &mut TestAppContext) {
3355// init_test(cx, |s| {
3356// s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
3357// s.defaults.tab_size = NonZeroU32::new(4);
3358// });
3359
3360// for editor_mode_without_invisibles in [
3361// EditorMode::SingleLine,
3362// EditorMode::AutoHeight { max_lines: 100 },
3363// ] {
3364// let invisibles = collect_invisibles_from_new_editor(
3365// cx,
3366// editor_mode_without_invisibles,
3367// "\t\t\t| | a b",
3368// 500.0,
3369// );
3370// assert!(invisibles.is_empty(),
3371// "For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}");
3372// }
3373// }
3374
3375// #[gpui::test]
3376// fn test_wrapped_invisibles_drawing(cx: &mut TestAppContext) {
3377// let tab_size = 4;
3378// let input_text = "a\tbcd ".repeat(9);
3379// let repeated_invisibles = [
3380// Invisible::Tab {
3381// line_start_offset: 1,
3382// },
3383// Invisible::Whitespace {
3384// line_offset: tab_size as usize + 3,
3385// },
3386// Invisible::Whitespace {
3387// line_offset: tab_size as usize + 4,
3388// },
3389// Invisible::Whitespace {
3390// line_offset: tab_size as usize + 5,
3391// },
3392// ];
3393// let expected_invisibles = std::iter::once(repeated_invisibles)
3394// .cycle()
3395// .take(9)
3396// .flatten()
3397// .collect::<Vec<_>>();
3398// assert_eq!(
3399// expected_invisibles.len(),
3400// input_text
3401// .chars()
3402// .filter(|initial_char| initial_char.is_whitespace())
3403// .count(),
3404// "Hardcoded expected invisibles differ from the actual ones in '{input_text}'"
3405// );
3406// info!("Expected invisibles: {expected_invisibles:?}");
3407
3408// init_test(cx, |_| {});
3409
3410// // Put the same string with repeating whitespace pattern into editors of various size,
3411// // take deliberately small steps during resizing, to put all whitespace kinds near the wrap point.
3412// let resize_step = 10.0;
3413// let mut editor_width = 200.0;
3414// while editor_width <= 1000.0 {
3415// update_test_language_settings(cx, |s| {
3416// s.defaults.tab_size = NonZeroU32::new(tab_size);
3417// s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
3418// s.defaults.preferred_line_length = Some(editor_width as u32);
3419// s.defaults.soft_wrap = Some(language_settings::SoftWrap::PreferredLineLength);
3420// });
3421
3422// let actual_invisibles =
3423// collect_invisibles_from_new_editor(cx, EditorMode::Full, &input_text, editor_width);
3424
3425// // Whatever the editor size is, ensure it has the same invisible kinds in the same order
3426// // (no good guarantees about the offsets: wrapping could trigger padding and its tests should check the offsets).
3427// let mut i = 0;
3428// for (actual_index, actual_invisible) in actual_invisibles.iter().enumerate() {
3429// i = actual_index;
3430// match expected_invisibles.get(i) {
3431// Some(expected_invisible) => match (expected_invisible, actual_invisible) {
3432// (Invisible::Whitespace { .. }, Invisible::Whitespace { .. })
3433// | (Invisible::Tab { .. }, Invisible::Tab { .. }) => {}
3434// _ => {
3435// panic!("At index {i}, expected invisible {expected_invisible:?} does not match actual {actual_invisible:?} by kind. Actual invisibles: {actual_invisibles:?}")
3436// }
3437// },
3438// None => panic!("Unexpected extra invisible {actual_invisible:?} at index {i}"),
3439// }
3440// }
3441// let missing_expected_invisibles = &expected_invisibles[i + 1..];
3442// assert!(
3443// missing_expected_invisibles.is_empty(),
3444// "Missing expected invisibles after index {i}: {missing_expected_invisibles:?}"
3445// );
3446
3447// editor_width += resize_step;
3448// }
3449// }
3450
3451// fn collect_invisibles_from_new_editor(
3452// cx: &mut TestAppContext,
3453// editor_mode: EditorMode,
3454// input_text: &str,
3455// editor_width: f32,
3456// ) -> Vec<Invisible> {
3457// info!(
3458// "Creating editor with mode {editor_mode:?}, width {editor_width} and text '{input_text}'"
3459// );
3460// let editor = cx
3461// .add_window(|cx| {
3462// let buffer = MultiBuffer::build_simple(&input_text, cx);
3463// Editor::new(editor_mode, buffer, None, None, cx)
3464// })
3465// .root(cx);
3466
3467// let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3468// let (_, layout_state) = editor.update(cx, |editor, cx| {
3469// editor.set_soft_wrap_mode(language_settings::SoftWrap::EditorWidth, cx);
3470// editor.set_wrap_width(Some(editor_width), cx);
3471
3472// element.layout(
3473// SizeConstraint::new(vec2f(editor_width, 500.), vec2f(editor_width, 500.)),
3474// editor,
3475// cx,
3476// )
3477// });
3478
3479// layout_state
3480// .position_map
3481// .line_layouts
3482// .iter()
3483// .map(|line_with_invisibles| &line_with_invisibles.invisibles)
3484// .flatten()
3485// .cloned()
3486// .collect()
3487// }
3488// }