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