1use super::{
2 display_map::ToDisplayPoint, DisplayPoint, Editor, EditorSnapshot, ToPoint, MAX_LINE_LEN,
3};
4use crate::{
5 display_map::{BlockStyle, DisplaySnapshot},
6 mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,
7};
8use gpui::{AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun, TextSystem};
9use language::{CursorShape, Selection};
10use std::{ops::Range, sync::Arc};
11use sum_tree::Bias;
12
13enum FoldMarkers {}
14
15struct SelectionLayout {
16 head: DisplayPoint,
17 cursor_shape: CursorShape,
18 is_newest: bool,
19 is_local: bool,
20 range: Range<DisplayPoint>,
21 active_rows: Range<u32>,
22}
23
24impl SelectionLayout {
25 fn new<T: ToPoint + ToDisplayPoint + Clone>(
26 selection: Selection<T>,
27 line_mode: bool,
28 cursor_shape: CursorShape,
29 map: &DisplaySnapshot,
30 is_newest: bool,
31 is_local: bool,
32 ) -> Self {
33 let point_selection = selection.map(|p| p.to_point(&map.buffer_snapshot));
34 let display_selection = point_selection.map(|p| p.to_display_point(map));
35 let mut range = display_selection.range();
36 let mut head = display_selection.head();
37 let mut active_rows = map.prev_line_boundary(point_selection.start).1.row()
38 ..map.next_line_boundary(point_selection.end).1.row();
39
40 // vim visual line mode
41 if line_mode {
42 let point_range = map.expand_to_line(point_selection.range());
43 range = point_range.start.to_display_point(map)..point_range.end.to_display_point(map);
44 }
45
46 // any vim visual mode (including line mode)
47 if cursor_shape == CursorShape::Block && !range.is_empty() && !selection.reversed {
48 if head.column() > 0 {
49 head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left)
50 } else if head.row() > 0 && head != map.max_point() {
51 head = map.clip_point(
52 DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)),
53 Bias::Left,
54 );
55 // updating range.end is a no-op unless you're cursor is
56 // on the newline containing a multi-buffer divider
57 // in which case the clip_point may have moved the head up
58 // an additional row.
59 range.end = DisplayPoint::new(head.row() + 1, 0);
60 active_rows.end = head.row();
61 }
62 }
63
64 Self {
65 head,
66 cursor_shape,
67 is_newest,
68 is_local,
69 range,
70 active_rows,
71 }
72 }
73}
74
75pub struct EditorElement {
76 style: Arc<EditorStyle>,
77}
78
79impl EditorElement {
80 pub fn new(style: EditorStyle) -> Self {
81 Self {
82 style: Arc::new(style),
83 }
84 }
85
86 // fn attach_mouse_handlers(
87 // position_map: &Arc<PositionMap>,
88 // has_popovers: bool,
89 // visible_bounds: Bounds<Pixels>,
90 // text_bounds: Bounds<Pixels>,
91 // gutter_bounds: Bounds<Pixels>,
92 // bounds: Bounds<Pixels>,
93 // cx: &mut ViewContext<Editor>,
94 // ) {
95 // enum EditorElementMouseHandlers {}
96 // let view_id = cx.view_id();
97 // cx.scene().push_mouse_region(
98 // MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
99 // .on_down(MouseButton::Left, {
100 // let position_map = position_map.clone();
101 // move |event, editor, cx| {
102 // if !Self::mouse_down(
103 // editor,
104 // event.platform_event,
105 // position_map.as_ref(),
106 // text_bounds,
107 // gutter_bounds,
108 // cx,
109 // ) {
110 // cx.propagate_event();
111 // }
112 // }
113 // })
114 // .on_down(MouseButton::Right, {
115 // let position_map = position_map.clone();
116 // move |event, editor, cx| {
117 // if !Self::mouse_right_down(
118 // editor,
119 // event.position,
120 // position_map.as_ref(),
121 // text_bounds,
122 // cx,
123 // ) {
124 // cx.propagate_event();
125 // }
126 // }
127 // })
128 // .on_up(MouseButton::Left, {
129 // let position_map = position_map.clone();
130 // move |event, editor, cx| {
131 // if !Self::mouse_up(
132 // editor,
133 // event.position,
134 // event.cmd,
135 // event.shift,
136 // event.alt,
137 // position_map.as_ref(),
138 // text_bounds,
139 // cx,
140 // ) {
141 // cx.propagate_event()
142 // }
143 // }
144 // })
145 // .on_drag(MouseButton::Left, {
146 // let position_map = position_map.clone();
147 // move |event, editor, cx| {
148 // if event.end {
149 // return;
150 // }
151
152 // if !Self::mouse_dragged(
153 // editor,
154 // event.platform_event,
155 // position_map.as_ref(),
156 // text_bounds,
157 // cx,
158 // ) {
159 // cx.propagate_event()
160 // }
161 // }
162 // })
163 // .on_move({
164 // let position_map = position_map.clone();
165 // move |event, editor, cx| {
166 // if !Self::mouse_moved(
167 // editor,
168 // event.platform_event,
169 // &position_map,
170 // text_bounds,
171 // cx,
172 // ) {
173 // cx.propagate_event()
174 // }
175 // }
176 // })
177 // .on_move_out(move |_, editor: &mut Editor, cx| {
178 // if has_popovers {
179 // hide_hover(editor, cx);
180 // }
181 // })
182 // .on_scroll({
183 // let position_map = position_map.clone();
184 // move |event, editor, cx| {
185 // if !Self::scroll(
186 // editor,
187 // event.position,
188 // *event.delta.raw(),
189 // event.delta.precise(),
190 // &position_map,
191 // bounds,
192 // cx,
193 // ) {
194 // cx.propagate_event()
195 // }
196 // }
197 // }),
198 // );
199
200 // enum GutterHandlers {}
201 // let view_id = cx.view_id();
202 // let region_id = cx.view_id() + 1;
203 // cx.scene().push_mouse_region(
204 // MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
205 // |hover, editor: &mut Editor, cx| {
206 // editor.gutter_hover(
207 // &GutterHover {
208 // hovered: hover.started,
209 // },
210 // cx,
211 // );
212 // },
213 // ),
214 // )
215 // }
216
217 // fn mouse_down(
218 // editor: &mut Editor,
219 // MouseButtonEvent {
220 // position,
221 // modifiers:
222 // Modifiers {
223 // shift,
224 // ctrl,
225 // alt,
226 // cmd,
227 // ..
228 // },
229 // mut click_count,
230 // ..
231 // }: MouseButtonEvent,
232 // position_map: &PositionMap,
233 // text_bounds: Bounds<Pixels>,
234 // gutter_bounds: Bounds<Pixels>,
235 // cx: &mut EventContext<Editor>,
236 // ) -> bool {
237 // if gutter_bounds.contains_point(position) {
238 // click_count = 3; // Simulate triple-click when clicking the gutter to select lines
239 // } else if !text_bounds.contains_point(position) {
240 // return false;
241 // }
242
243 // let point_for_position = position_map.point_for_position(text_bounds, position);
244 // let position = point_for_position.previous_valid;
245 // if shift && alt {
246 // editor.select(
247 // SelectPhase::BeginColumnar {
248 // position,
249 // goal_column: point_for_position.exact_unclipped.column(),
250 // },
251 // cx,
252 // );
253 // } else if shift && !ctrl && !alt && !cmd {
254 // editor.select(
255 // SelectPhase::Extend {
256 // position,
257 // click_count,
258 // },
259 // cx,
260 // );
261 // } else {
262 // editor.select(
263 // SelectPhase::Begin {
264 // position,
265 // add: alt,
266 // click_count,
267 // },
268 // cx,
269 // );
270 // }
271
272 // true
273 // }
274
275 // fn mouse_right_down(
276 // editor: &mut Editor,
277 // position: gpui::Point<Pixels>,
278 // position_map: &PositionMap,
279 // text_bounds: Bounds<Pixels>,
280 // cx: &mut EventContext<Editor>,
281 // ) -> bool {
282 // if !text_bounds.contains_point(position) {
283 // return false;
284 // }
285 // let point_for_position = position_map.point_for_position(text_bounds, position);
286 // mouse_context_menu::deploy_context_menu(
287 // editor,
288 // position,
289 // point_for_position.previous_valid,
290 // cx,
291 // );
292 // true
293 // }
294
295 // fn mouse_up(
296 // editor: &mut Editor,
297 // position: gpui::Point<Pixels>,
298 // cmd: bool,
299 // shift: bool,
300 // alt: bool,
301 // position_map: &PositionMap,
302 // text_bounds: Bounds<Pixels>,
303 // cx: &mut EventContext<Editor>,
304 // ) -> bool {
305 // let end_selection = editor.has_pending_selection();
306 // let pending_nonempty_selections = editor.has_pending_nonempty_selection();
307
308 // if end_selection {
309 // editor.select(SelectPhase::End, cx);
310 // }
311
312 // if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
313 // let point = position_map.point_for_position(text_bounds, position);
314 // let could_be_inlay = point.as_valid().is_none();
315 // if shift || could_be_inlay {
316 // go_to_fetched_type_definition(editor, point, alt, cx);
317 // } else {
318 // go_to_fetched_definition(editor, point, alt, cx);
319 // }
320
321 // return true;
322 // }
323
324 // end_selection
325 // }
326
327 // fn mouse_dragged(
328 // editor: &mut Editor,
329 // MouseMovedEvent {
330 // modifiers: Modifiers { cmd, shift, .. },
331 // position,
332 // ..
333 // }: MouseMovedEvent,
334 // position_map: &PositionMap,
335 // text_bounds: Bounds<Pixels>,
336 // cx: &mut EventContext<Editor>,
337 // ) -> bool {
338 // // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
339 // // Don't trigger hover popover if mouse is hovering over context menu
340 // let point = if text_bounds.contains_point(position) {
341 // position_map
342 // .point_for_position(text_bounds, position)
343 // .as_valid()
344 // } else {
345 // None
346 // };
347
348 // update_go_to_definition_link(
349 // editor,
350 // point.map(GoToDefinitionTrigger::Text),
351 // cmd,
352 // shift,
353 // cx,
354 // );
355
356 // if editor.has_pending_selection() {
357 // let mut scroll_delta = gpui::Point<Pixels>::zero();
358
359 // let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
360 // let top = text_bounds.origin_y() + vertical_margin;
361 // let bottom = text_bounds.lower_left().y() - vertical_margin;
362 // if position.y() < top {
363 // scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
364 // }
365 // if position.y() > bottom {
366 // scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
367 // }
368
369 // let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
370 // let left = text_bounds.origin_x() + horizontal_margin;
371 // let right = text_bounds.upper_right().x() - horizontal_margin;
372 // if position.x() < left {
373 // scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
374 // left - position.x(),
375 // ))
376 // }
377 // if position.x() > right {
378 // scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
379 // position.x() - right,
380 // ))
381 // }
382
383 // let point_for_position = position_map.point_for_position(text_bounds, position);
384
385 // editor.select(
386 // SelectPhase::Update {
387 // position: point_for_position.previous_valid,
388 // goal_column: point_for_position.exact_unclipped.column(),
389 // scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
390 // .clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max),
391 // },
392 // cx,
393 // );
394 // hover_at(editor, point, cx);
395 // true
396 // } else {
397 // hover_at(editor, point, cx);
398 // false
399 // }
400 // }
401
402 // fn mouse_moved(
403 // editor: &mut Editor,
404 // MouseMovedEvent {
405 // modifiers: Modifiers { shift, cmd, .. },
406 // position,
407 // ..
408 // }: MouseMovedEvent,
409 // position_map: &PositionMap,
410 // text_bounds: Bounds<Pixels>,
411 // cx: &mut ViewContext<Editor>,
412 // ) -> bool {
413 // // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
414 // // Don't trigger hover popover if mouse is hovering over context menu
415 // if text_bounds.contains_point(position) {
416 // let point_for_position = position_map.point_for_position(text_bounds, position);
417 // match point_for_position.as_valid() {
418 // Some(point) => {
419 // update_go_to_definition_link(
420 // editor,
421 // Some(GoToDefinitionTrigger::Text(point)),
422 // cmd,
423 // shift,
424 // cx,
425 // );
426 // hover_at(editor, Some(point), cx);
427 // }
428 // None => {
429 // update_inlay_link_and_hover_points(
430 // &position_map.snapshot,
431 // point_for_position,
432 // editor,
433 // cmd,
434 // shift,
435 // cx,
436 // );
437 // }
438 // }
439 // } else {
440 // update_go_to_definition_link(editor, None, cmd, shift, cx);
441 // hover_at(editor, None, cx);
442 // }
443
444 // true
445 // }
446
447 // fn scroll(
448 // editor: &mut Editor,
449 // position: gpui::Point<Pixels>,
450 // mut delta: gpui::Point<Pixels>,
451 // precise: bool,
452 // position_map: &PositionMap,
453 // bounds: Bounds<Pixels>,
454 // cx: &mut ViewContext<Editor>,
455 // ) -> bool {
456 // if !bounds.contains_point(position) {
457 // return false;
458 // }
459
460 // let line_height = position_map.line_height;
461 // let max_glyph_width = position_map.em_width;
462
463 // let axis = if precise {
464 // //Trackpad
465 // position_map.snapshot.ongoing_scroll.filter(&mut delta)
466 // } else {
467 // //Not trackpad
468 // delta *= vec2f(max_glyph_width, line_height);
469 // None //Resets ongoing scroll
470 // };
471
472 // let scroll_position = position_map.snapshot.scroll_position();
473 // let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
474 // let y = (scroll_position.y() * line_height - delta.y()) / line_height;
475 // let scroll_position = vec2f(x, y).clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max);
476 // editor.scroll(scroll_position, axis, cx);
477
478 // true
479 // }
480
481 // fn paint_background(
482 // &self,
483 // gutter_bounds: Bounds<Pixels>,
484 // text_bounds: Bounds<Pixels>,
485 // layout: &LayoutState,
486 // cx: &mut ViewContext<Editor>,
487 // ) {
488 // let bounds = gutter_bounds.union_rect(text_bounds);
489 // let scroll_top =
490 // layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height;
491 // cx.scene().push_quad(Quad {
492 // bounds: gutter_bounds,
493 // background: Some(self.style.gutter_background),
494 // border: Border::new(0., Color::transparent_black()).into(),
495 // corner_radii: Default::default(),
496 // });
497 // cx.scene().push_quad(Quad {
498 // bounds: text_bounds,
499 // background: Some(self.style.background),
500 // border: Border::new(0., Color::transparent_black()).into(),
501 // corner_radii: Default::default(),
502 // });
503
504 // if let EditorMode::Full = layout.mode {
505 // let mut active_rows = layout.active_rows.iter().peekable();
506 // while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
507 // let mut end_row = *start_row;
508 // while active_rows.peek().map_or(false, |r| {
509 // *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
510 // }) {
511 // active_rows.next().unwrap();
512 // end_row += 1;
513 // }
514
515 // if !contains_non_empty_selection {
516 // let origin = vec2f(
517 // bounds.origin_x(),
518 // bounds.origin_y() + (layout.position_map.line_height * *start_row as f32)
519 // - scroll_top,
520 // );
521 // let size = vec2f(
522 // bounds.width(),
523 // layout.position_map.line_height * (end_row - start_row + 1) as f32,
524 // );
525 // cx.scene().push_quad(Quad {
526 // bounds: Bounds<Pixels>::new(origin, size),
527 // background: Some(self.style.active_line_background),
528 // border: Border::default().into(),
529 // corner_radii: Default::default(),
530 // });
531 // }
532 // }
533
534 // if let Some(highlighted_rows) = &layout.highlighted_rows {
535 // let origin = vec2f(
536 // bounds.origin_x(),
537 // bounds.origin_y()
538 // + (layout.position_map.line_height * highlighted_rows.start as f32)
539 // - scroll_top,
540 // );
541 // let size = vec2f(
542 // bounds.width(),
543 // layout.position_map.line_height * highlighted_rows.len() as f32,
544 // );
545 // cx.scene().push_quad(Quad {
546 // bounds: Bounds<Pixels>::new(origin, size),
547 // background: Some(self.style.highlighted_line_background),
548 // border: Border::default().into(),
549 // corner_radii: Default::default(),
550 // });
551 // }
552
553 // let scroll_left =
554 // layout.position_map.snapshot.scroll_position().x() * layout.position_map.em_width;
555
556 // for (wrap_position, active) in layout.wrap_guides.iter() {
557 // let x =
558 // (text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.)
559 // - scroll_left;
560
561 // if x < text_bounds.origin_x()
562 // || (layout.show_scrollbars && x > self.scrollbar_left(&bounds))
563 // {
564 // continue;
565 // }
566
567 // let color = if *active {
568 // self.style.active_wrap_guide
569 // } else {
570 // self.style.wrap_guide
571 // };
572 // cx.scene().push_quad(Quad {
573 // bounds: Bounds<Pixels>::new(
574 // vec2f(x, text_bounds.origin_y()),
575 // vec2f(1., text_bounds.height()),
576 // ),
577 // background: Some(color),
578 // border: Border::new(0., Color::transparent_black()).into(),
579 // corner_radii: Default::default(),
580 // });
581 // }
582 // }
583 // }
584
585 // fn paint_gutter(
586 // &mut self,
587 // bounds: Bounds<Pixels>,
588 // visible_bounds: Bounds<Pixels>,
589 // layout: &mut LayoutState,
590 // editor: &mut Editor,
591 // cx: &mut ViewContext<Editor>,
592 // ) {
593 // let line_height = layout.position_map.line_height;
594
595 // let scroll_position = layout.position_map.snapshot.scroll_position();
596 // let scroll_top = scroll_position.y() * line_height;
597
598 // let show_gutter = matches!(
599 // settings::get::<ProjectSettings>(cx).git.git_gutter,
600 // Some(GitGutterSetting::TrackedFiles)
601 // );
602
603 // if show_gutter {
604 // Self::paint_diff_hunks(bounds, layout, cx);
605 // }
606
607 // for (ix, line) in layout.line_number_layouts.iter().enumerate() {
608 // if let Some(line) = line {
609 // let line_origin = bounds.origin()
610 // + vec2f(
611 // bounds.width() - line.width() - layout.gutter_padding,
612 // ix as f32 * line_height - (scroll_top % line_height),
613 // );
614
615 // line.paint(line_origin, visible_bounds, line_height, cx);
616 // }
617 // }
618
619 // for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
620 // if let Some(indicator) = fold_indicator.as_mut() {
621 // let position = vec2f(
622 // bounds.width() - layout.gutter_padding,
623 // ix as f32 * line_height - (scroll_top % line_height),
624 // );
625 // let centering_offset = vec2f(
626 // (layout.gutter_padding + layout.gutter_margin - indicator.size().x()) / 2.,
627 // (line_height - indicator.size().y()) / 2.,
628 // );
629
630 // let indicator_origin = bounds.origin() + position + centering_offset;
631
632 // indicator.paint(indicator_origin, visible_bounds, editor, cx);
633 // }
634 // }
635
636 // if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
637 // let mut x = 0.;
638 // let mut y = *row as f32 * line_height - scroll_top;
639 // x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
640 // y += (line_height - indicator.size().y()) / 2.;
641 // indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, editor, cx);
642 // }
643 // }
644
645 // fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &mut LayoutState, cx: &mut ViewContext<Editor>) {
646 // let diff_style = &theme::current(cx).editor.diff.clone();
647 // let line_height = layout.position_map.line_height;
648
649 // let scroll_position = layout.position_map.snapshot.scroll_position();
650 // let scroll_top = scroll_position.y() * line_height;
651
652 // for hunk in &layout.display_hunks {
653 // let (display_row_range, status) = match hunk {
654 // //TODO: This rendering is entirely a horrible hack
655 // &DisplayDiffHunk::Folded { display_row: row } => {
656 // let start_y = row as f32 * line_height - scroll_top;
657 // let end_y = start_y + line_height;
658
659 // let width = diff_style.removed_width_em * line_height;
660 // let highlight_origin = bounds.origin() + vec2f(-width, start_y);
661 // let highlight_size = vec2f(width * 2., end_y - start_y);
662 // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
663
664 // cx.scene().push_quad(Quad {
665 // bounds: highlight_bounds,
666 // background: Some(diff_style.modified),
667 // border: Border::new(0., Color::transparent_black()).into(),
668 // corner_radii: (1. * line_height).into(),
669 // });
670
671 // continue;
672 // }
673
674 // DisplayDiffHunk::Unfolded {
675 // display_row_range,
676 // status,
677 // } => (display_row_range, status),
678 // };
679
680 // let color = match status {
681 // DiffHunkStatus::Added => diff_style.inserted,
682 // DiffHunkStatus::Modified => diff_style.modified,
683
684 // //TODO: This rendering is entirely a horrible hack
685 // DiffHunkStatus::Removed => {
686 // let row = display_row_range.start;
687
688 // let offset = line_height / 2.;
689 // let start_y = row as f32 * line_height - offset - scroll_top;
690 // let end_y = start_y + line_height;
691
692 // let width = diff_style.removed_width_em * line_height;
693 // let highlight_origin = bounds.origin() + vec2f(-width, start_y);
694 // let highlight_size = vec2f(width * 2., end_y - start_y);
695 // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
696
697 // cx.scene().push_quad(Quad {
698 // bounds: highlight_bounds,
699 // background: Some(diff_style.deleted),
700 // border: Border::new(0., Color::transparent_black()).into(),
701 // corner_radii: (1. * line_height).into(),
702 // });
703
704 // continue;
705 // }
706 // };
707
708 // let start_row = display_row_range.start;
709 // let end_row = display_row_range.end;
710
711 // let start_y = start_row as f32 * line_height - scroll_top;
712 // let end_y = end_row as f32 * line_height - scroll_top;
713
714 // let width = diff_style.width_em * line_height;
715 // let highlight_origin = bounds.origin() + vec2f(-width, start_y);
716 // let highlight_size = vec2f(width * 2., end_y - start_y);
717 // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
718
719 // cx.scene().push_quad(Quad {
720 // bounds: highlight_bounds,
721 // background: Some(color),
722 // border: Border::new(0., Color::transparent_black()).into(),
723 // corner_radii: (diff_style.corner_radius * line_height).into(),
724 // });
725 // }
726 // }
727
728 // fn paint_text(
729 // &mut self,
730 // bounds: Bounds<Pixels>,
731 // visible_bounds: Bounds<Pixels>,
732 // layout: &mut LayoutState,
733 // editor: &mut Editor,
734 // cx: &mut ViewContext<Editor>,
735 // ) {
736 // let style = &self.style;
737 // let scroll_position = layout.position_map.snapshot.scroll_position();
738 // let start_row = layout.visible_display_row_range.start;
739 // let scroll_top = scroll_position.y() * layout.position_map.line_height;
740 // let max_glyph_width = layout.position_map.em_width;
741 // let scroll_left = scroll_position.x() * max_glyph_width;
742 // let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
743 // let line_end_overshoot = 0.15 * layout.position_map.line_height;
744 // let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
745
746 // cx.scene().push_layer(Some(bounds));
747
748 // cx.scene().push_cursor_region(CursorRegion {
749 // bounds,
750 // style: if !editor.link_go_to_definition_state.definitions.is_empty() {
751 // CursorStyle::PointingHand
752 // } else {
753 // CursorStyle::IBeam
754 // },
755 // });
756
757 // let fold_corner_radius =
758 // self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
759 // for (id, range, color) in layout.fold_ranges.iter() {
760 // self.paint_highlighted_range(
761 // range.clone(),
762 // *color,
763 // fold_corner_radius,
764 // fold_corner_radius * 2.,
765 // layout,
766 // content_origin,
767 // scroll_top,
768 // scroll_left,
769 // bounds,
770 // cx,
771 // );
772
773 // for bound in range_to_bounds(
774 // &range,
775 // content_origin,
776 // scroll_left,
777 // scroll_top,
778 // &layout.visible_display_row_range,
779 // line_end_overshoot,
780 // &layout.position_map,
781 // ) {
782 // cx.scene().push_cursor_region(CursorRegion {
783 // bounds: bound,
784 // style: CursorStyle::PointingHand,
785 // });
786
787 // let display_row = range.start.row();
788
789 // let buffer_row = DisplayPoint::new(display_row, 0)
790 // .to_point(&layout.position_map.snapshot.display_snapshot)
791 // .row;
792
793 // let view_id = cx.view_id();
794 // cx.scene().push_mouse_region(
795 // MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
796 // .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
797 // editor.unfold_at(&UnfoldAt { buffer_row }, cx)
798 // })
799 // .with_notify_on_hover(true)
800 // .with_notify_on_click(true),
801 // )
802 // }
803 // }
804
805 // for (range, color) in &layout.highlighted_ranges {
806 // self.paint_highlighted_range(
807 // range.clone(),
808 // *color,
809 // 0.,
810 // line_end_overshoot,
811 // layout,
812 // content_origin,
813 // scroll_top,
814 // scroll_left,
815 // bounds,
816 // cx,
817 // );
818 // }
819
820 // let mut cursors = SmallVec::<[Cursor; 32]>::new();
821 // let corner_radius = 0.15 * layout.position_map.line_height;
822 // let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
823
824 // for (selection_style, selections) in &layout.selections {
825 // for selection in selections {
826 // self.paint_highlighted_range(
827 // selection.range.clone(),
828 // selection_style.selection,
829 // corner_radius,
830 // corner_radius * 2.,
831 // layout,
832 // content_origin,
833 // scroll_top,
834 // scroll_left,
835 // bounds,
836 // cx,
837 // );
838
839 // if selection.is_local && !selection.range.is_empty() {
840 // invisible_display_ranges.push(selection.range.clone());
841 // }
842 // if !selection.is_local || editor.show_local_cursors(cx) {
843 // let cursor_position = selection.head;
844 // if layout
845 // .visible_display_row_range
846 // .contains(&cursor_position.row())
847 // {
848 // let cursor_row_layout = &layout.position_map.line_layouts
849 // [(cursor_position.row() - start_row) as usize]
850 // .line;
851 // let cursor_column = cursor_position.column() as usize;
852
853 // let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
854 // let mut block_width =
855 // cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
856 // if block_width == 0.0 {
857 // block_width = layout.position_map.em_width;
858 // }
859 // let block_text = if let CursorShape::Block = selection.cursor_shape {
860 // layout
861 // .position_map
862 // .snapshot
863 // .chars_at(cursor_position)
864 // .next()
865 // .and_then(|(character, _)| {
866 // let font_id =
867 // cursor_row_layout.font_for_index(cursor_column)?;
868 // let text = character.to_string();
869
870 // Some(cx.text_layout_cache().layout_str(
871 // &text,
872 // cursor_row_layout.font_size(),
873 // &[(
874 // text.chars().count(),
875 // RunStyle {
876 // font_id,
877 // color: style.background,
878 // underline: Default::default(),
879 // },
880 // )],
881 // ))
882 // })
883 // } else {
884 // None
885 // };
886
887 // let x = cursor_character_x - scroll_left;
888 // let y = cursor_position.row() as f32 * layout.position_map.line_height
889 // - scroll_top;
890 // if selection.is_newest {
891 // editor.pixel_position_of_newest_cursor = Some(vec2f(
892 // bounds.origin_x() + x + block_width / 2.,
893 // bounds.origin_y() + y + layout.position_map.line_height / 2.,
894 // ));
895 // }
896 // cursors.push(Cursor {
897 // color: selection_style.cursor,
898 // block_width,
899 // origin: vec2f(x, y),
900 // line_height: layout.position_map.line_height,
901 // shape: selection.cursor_shape,
902 // block_text,
903 // });
904 // }
905 // }
906 // }
907 // }
908
909 // if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
910 // for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
911 // let row = start_row + ix as u32;
912 // line_with_invisibles.draw(
913 // layout,
914 // row,
915 // scroll_top,
916 // content_origin,
917 // scroll_left,
918 // visible_text_bounds,
919 // whitespace_setting,
920 // &invisible_display_ranges,
921 // visible_bounds,
922 // cx,
923 // )
924 // }
925 // }
926
927 // cx.scene().push_layer(Some(bounds));
928 // for cursor in cursors {
929 // cursor.paint(content_origin, cx);
930 // }
931 // cx.scene().pop_layer();
932
933 // if let Some((position, context_menu)) = layout.context_menu.as_mut() {
934 // cx.scene().push_stacking_context(None, None);
935 // let cursor_row_layout =
936 // &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
937 // let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
938 // let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
939 // let mut list_origin = content_origin + vec2f(x, y);
940 // let list_width = context_menu.size().x();
941 // let list_height = context_menu.size().y();
942
943 // // Snap the right edge of the list to the right edge of the window if
944 // // its horizontal bounds overflow.
945 // if list_origin.x() + list_width > cx.window_size().x() {
946 // list_origin.set_x((cx.window_size().x() - list_width).max(0.));
947 // }
948
949 // if list_origin.y() + list_height > bounds.max_y() {
950 // list_origin.set_y(list_origin.y() - layout.position_map.line_height - list_height);
951 // }
952
953 // context_menu.paint(
954 // list_origin,
955 // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
956 // editor,
957 // cx,
958 // );
959
960 // cx.scene().pop_stacking_context();
961 // }
962
963 // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
964 // cx.scene().push_stacking_context(None, None);
965
966 // // This is safe because we check on layout whether the required row is available
967 // let hovered_row_layout =
968 // &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
969
970 // // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
971 // // height. This is the size we will use to decide whether to render popovers above or below
972 // // the hovered line.
973 // let first_size = hover_popovers[0].size();
974 // let height_to_reserve = first_size.y()
975 // + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
976
977 // // Compute Hovered Point
978 // let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
979 // let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
980 // let hovered_point = content_origin + vec2f(x, y);
981
982 // if hovered_point.y() - height_to_reserve > 0.0 {
983 // // There is enough space above. Render popovers above the hovered point
984 // let mut current_y = hovered_point.y();
985 // for hover_popover in hover_popovers {
986 // let size = hover_popover.size();
987 // let mut popover_origin = vec2f(hovered_point.x(), current_y - size.y());
988
989 // let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
990 // if x_out_of_bounds < 0.0 {
991 // popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
992 // }
993
994 // hover_popover.paint(
995 // popover_origin,
996 // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
997 // editor,
998 // cx,
999 // );
1000
1001 // current_y = popover_origin.y() - HOVER_POPOVER_GAP;
1002 // }
1003 // } else {
1004 // // There is not enough space above. Render popovers below the hovered point
1005 // let mut current_y = hovered_point.y() + layout.position_map.line_height;
1006 // for hover_popover in hover_popovers {
1007 // let size = hover_popover.size();
1008 // let mut popover_origin = vec2f(hovered_point.x(), current_y);
1009
1010 // let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
1011 // if x_out_of_bounds < 0.0 {
1012 // popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
1013 // }
1014
1015 // hover_popover.paint(
1016 // popover_origin,
1017 // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
1018 // editor,
1019 // cx,
1020 // );
1021
1022 // current_y = popover_origin.y() + size.y() + HOVER_POPOVER_GAP;
1023 // }
1024 // }
1025
1026 // cx.scene().pop_stacking_context();
1027 // }
1028
1029 // cx.scene().pop_layer();
1030 // }
1031
1032 // fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> f32 {
1033 // bounds.max_x() - self.style.theme.scrollbar.width
1034 // }
1035
1036 // fn paint_scrollbar(
1037 // &mut self,
1038 // bounds: Bounds<Pixels>,
1039 // layout: &mut LayoutState,
1040 // editor: &Editor,
1041 // cx: &mut ViewContext<Editor>,
1042 // ) {
1043 // enum ScrollbarMouseHandlers {}
1044 // if layout.mode != EditorMode::Full {
1045 // return;
1046 // }
1047
1048 // let style = &self.style.theme.scrollbar;
1049
1050 // let top = bounds.min_y();
1051 // let bottom = bounds.max_y();
1052 // let right = bounds.max_x();
1053 // let left = self.scrollbar_left(&bounds);
1054 // let row_range = &layout.scrollbar_row_range;
1055 // let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
1056
1057 // let mut height = bounds.height();
1058 // let mut first_row_y_offset = 0.0;
1059
1060 // // Impose a minimum height on the scrollbar thumb
1061 // let row_height = height / max_row;
1062 // let min_thumb_height =
1063 // style.min_height_factor * cx.font_cache.line_height(self.style.text.font_size);
1064 // let thumb_height = (row_range.end - row_range.start) * row_height;
1065 // if thumb_height < min_thumb_height {
1066 // first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
1067 // height -= min_thumb_height - thumb_height;
1068 // }
1069
1070 // let y_for_row = |row: f32| -> f32 { top + first_row_y_offset + row * row_height };
1071
1072 // let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
1073 // let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
1074 // let track_bounds = Bounds<Pixels>::from_points(vec2f(left, top), vec2f(right, bottom));
1075 // let thumb_bounds = Bounds<Pixels>::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom));
1076
1077 // if layout.show_scrollbars {
1078 // cx.scene().push_quad(Quad {
1079 // bounds: track_bounds,
1080 // border: style.track.border.into(),
1081 // background: style.track.background_color,
1082 // ..Default::default()
1083 // });
1084 // let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
1085 // let theme = theme::current(cx);
1086 // let scrollbar_theme = &theme.editor.scrollbar;
1087 // if layout.is_singleton && scrollbar_settings.selections {
1088 // let start_anchor = Anchor::min();
1089 // let end_anchor = Anchor::max();
1090 // let color = scrollbar_theme.selections;
1091 // let border = Border {
1092 // width: 1.,
1093 // color: style.thumb.border.color,
1094 // overlay: false,
1095 // top: false,
1096 // right: true,
1097 // bottom: false,
1098 // left: true,
1099 // };
1100 // let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
1101 // let start_y = y_for_row(start.row() as f32);
1102 // let mut end_y = y_for_row(end.row() as f32);
1103 // if end_y - start_y < 1. {
1104 // end_y = start_y + 1.;
1105 // }
1106 // let bounds = Bounds<Pixels>::from_points(vec2f(left, start_y), vec2f(right, end_y));
1107
1108 // cx.scene().push_quad(Quad {
1109 // bounds,
1110 // background: Some(color),
1111 // border: border.into(),
1112 // corner_radii: style.thumb.corner_radii.into(),
1113 // })
1114 // };
1115 // let background_ranges = editor
1116 // .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
1117 // start_anchor..end_anchor,
1118 // &layout.position_map.snapshot,
1119 // 50000,
1120 // );
1121 // for row in background_ranges {
1122 // let start = row.start();
1123 // let end = row.end();
1124 // push_region(*start, *end);
1125 // }
1126 // }
1127
1128 // if layout.is_singleton && scrollbar_settings.git_diff {
1129 // let diff_style = scrollbar_theme.git.clone();
1130 // for hunk in layout
1131 // .position_map
1132 // .snapshot
1133 // .buffer_snapshot
1134 // .git_diff_hunks_in_range(0..(max_row.floor() as u32))
1135 // {
1136 // let start_display = Point::new(hunk.buffer_range.start, 0)
1137 // .to_display_point(&layout.position_map.snapshot.display_snapshot);
1138 // let end_display = Point::new(hunk.buffer_range.end, 0)
1139 // .to_display_point(&layout.position_map.snapshot.display_snapshot);
1140 // let start_y = y_for_row(start_display.row() as f32);
1141 // let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
1142 // y_for_row((end_display.row() + 1) as f32)
1143 // } else {
1144 // y_for_row((end_display.row()) as f32)
1145 // };
1146
1147 // if end_y - start_y < 1. {
1148 // end_y = start_y + 1.;
1149 // }
1150 // let bounds = Bounds<Pixels>::from_points(vec2f(left, start_y), vec2f(right, end_y));
1151
1152 // let color = match hunk.status() {
1153 // DiffHunkStatus::Added => diff_style.inserted,
1154 // DiffHunkStatus::Modified => diff_style.modified,
1155 // DiffHunkStatus::Removed => diff_style.deleted,
1156 // };
1157
1158 // let border = Border {
1159 // width: 1.,
1160 // color: style.thumb.border.color,
1161 // overlay: false,
1162 // top: false,
1163 // right: true,
1164 // bottom: false,
1165 // left: true,
1166 // };
1167
1168 // cx.scene().push_quad(Quad {
1169 // bounds,
1170 // background: Some(color),
1171 // border: border.into(),
1172 // corner_radii: style.thumb.corner_radii.into(),
1173 // })
1174 // }
1175 // }
1176
1177 // cx.scene().push_quad(Quad {
1178 // bounds: thumb_bounds,
1179 // border: style.thumb.border.into(),
1180 // background: style.thumb.background_color,
1181 // corner_radii: style.thumb.corner_radii.into(),
1182 // });
1183 // }
1184
1185 // cx.scene().push_cursor_region(CursorRegion {
1186 // bounds: track_bounds,
1187 // style: CursorStyle::Arrow,
1188 // });
1189 // let region_id = cx.view_id();
1190 // cx.scene().push_mouse_region(
1191 // MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
1192 // .on_move(move |event, editor: &mut Editor, cx| {
1193 // if event.pressed_button.is_none() {
1194 // editor.scroll_manager.show_scrollbar(cx);
1195 // }
1196 // })
1197 // .on_down(MouseButton::Left, {
1198 // let row_range = row_range.clone();
1199 // move |event, editor: &mut Editor, cx| {
1200 // let y = event.position.y();
1201 // if y < thumb_top || thumb_bottom < y {
1202 // let center_row = ((y - top) * max_row as f32 / height).round() as u32;
1203 // let top_row = center_row
1204 // .saturating_sub((row_range.end - row_range.start) as u32 / 2);
1205 // let mut position = editor.scroll_position(cx);
1206 // position.set_y(top_row as f32);
1207 // editor.set_scroll_position(position, cx);
1208 // } else {
1209 // editor.scroll_manager.show_scrollbar(cx);
1210 // }
1211 // }
1212 // })
1213 // .on_drag(MouseButton::Left, {
1214 // move |event, editor: &mut Editor, cx| {
1215 // if event.end {
1216 // return;
1217 // }
1218
1219 // let y = event.prev_mouse_position.y();
1220 // let new_y = event.position.y();
1221 // if thumb_top < y && y < thumb_bottom {
1222 // let mut position = editor.scroll_position(cx);
1223 // position.set_y(position.y() + (new_y - y) * (max_row as f32) / height);
1224 // if position.y() < 0.0 {
1225 // position.set_y(0.);
1226 // }
1227 // editor.set_scroll_position(position, cx);
1228 // }
1229 // }
1230 // }),
1231 // );
1232 // }
1233
1234 // #[allow(clippy::too_many_arguments)]
1235 // fn paint_highlighted_range(
1236 // &self,
1237 // range: Range<DisplayPoint>,
1238 // color: Color,
1239 // corner_radius: f32,
1240 // line_end_overshoot: f32,
1241 // layout: &LayoutState,
1242 // content_origin: gpui::Point<Pixels>,
1243 // scroll_top: f32,
1244 // scroll_left: f32,
1245 // bounds: Bounds<Pixels>,
1246 // cx: &mut ViewContext<Editor>,
1247 // ) {
1248 // let start_row = layout.visible_display_row_range.start;
1249 // let end_row = layout.visible_display_row_range.end;
1250 // if range.start != range.end {
1251 // let row_range = if range.end.column() == 0 {
1252 // cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
1253 // } else {
1254 // cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
1255 // };
1256
1257 // let highlighted_range = HighlightedRange {
1258 // color,
1259 // line_height: layout.position_map.line_height,
1260 // corner_radius,
1261 // start_y: content_origin.y()
1262 // + row_range.start as f32 * layout.position_map.line_height
1263 // - scroll_top,
1264 // lines: row_range
1265 // .into_iter()
1266 // .map(|row| {
1267 // let line_layout =
1268 // &layout.position_map.line_layouts[(row - start_row) as usize].line;
1269 // HighlightedRangeLine {
1270 // start_x: if row == range.start.row() {
1271 // content_origin.x()
1272 // + line_layout.x_for_index(range.start.column() as usize)
1273 // - scroll_left
1274 // } else {
1275 // content_origin.x() - scroll_left
1276 // },
1277 // end_x: if row == range.end.row() {
1278 // content_origin.x()
1279 // + line_layout.x_for_index(range.end.column() as usize)
1280 // - scroll_left
1281 // } else {
1282 // content_origin.x() + line_layout.width() + line_end_overshoot
1283 // - scroll_left
1284 // },
1285 // }
1286 // })
1287 // .collect(),
1288 // };
1289
1290 // highlighted_range.paint(bounds, cx);
1291 // }
1292 // }
1293
1294 // fn paint_blocks(
1295 // &mut self,
1296 // bounds: Bounds<Pixels>,
1297 // visible_bounds: Bounds<Pixels>,
1298 // layout: &mut LayoutState,
1299 // editor: &mut Editor,
1300 // cx: &mut ViewContext<Editor>,
1301 // ) {
1302 // let scroll_position = layout.position_map.snapshot.scroll_position();
1303 // let scroll_left = scroll_position.x() * layout.position_map.em_width;
1304 // let scroll_top = scroll_position.y() * layout.position_map.line_height;
1305
1306 // for block in &mut layout.blocks {
1307 // let mut origin = bounds.origin()
1308 // + vec2f(
1309 // 0.,
1310 // block.row as f32 * layout.position_map.line_height - scroll_top,
1311 // );
1312 // if !matches!(block.style, BlockStyle::Sticky) {
1313 // origin += vec2f(-scroll_left, 0.);
1314 // }
1315 // block.element.paint(origin, visible_bounds, editor, cx);
1316 // }
1317 // }
1318
1319 // fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> f32 {
1320 // let style = &self.style;
1321
1322 // cx.text_layout_cache()
1323 // .layout_str(
1324 // " ".repeat(column).as_str(),
1325 // style.text.font_size,
1326 // &[(
1327 // column,
1328 // RunStyle {
1329 // font_id: style.text.font_id,
1330 // color: Color::black(),
1331 // underline: Default::default(),
1332 // },
1333 // )],
1334 // )
1335 // .width()
1336 // }
1337
1338 // fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> f32 {
1339 // let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
1340 // self.column_pixels(digit_count, cx)
1341 // }
1342
1343 //Folds contained in a hunk are ignored apart from shrinking visual size
1344 //If a fold contains any hunks then that fold line is marked as modified
1345 // fn layout_git_gutters(
1346 // &self,
1347 // display_rows: Range<u32>,
1348 // snapshot: &EditorSnapshot,
1349 // ) -> Vec<DisplayDiffHunk> {
1350 // let buffer_snapshot = &snapshot.buffer_snapshot;
1351
1352 // let buffer_start_row = DisplayPoint::new(display_rows.start, 0)
1353 // .to_point(snapshot)
1354 // .row;
1355 // let buffer_end_row = DisplayPoint::new(display_rows.end, 0)
1356 // .to_point(snapshot)
1357 // .row;
1358
1359 // buffer_snapshot
1360 // .git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
1361 // .map(|hunk| diff_hunk_to_display(hunk, snapshot))
1362 // .dedup()
1363 // .collect()
1364 // }
1365
1366 // fn calculate_relative_line_numbers(
1367 // &self,
1368 // snapshot: &EditorSnapshot,
1369 // rows: &Range<u32>,
1370 // relative_to: Option<u32>,
1371 // ) -> HashMap<u32, u32> {
1372 // let mut relative_rows: HashMap<u32, u32> = Default::default();
1373 // let Some(relative_to) = relative_to else {
1374 // return relative_rows;
1375 // };
1376
1377 // let start = rows.start.min(relative_to);
1378 // let end = rows.end.max(relative_to);
1379
1380 // let buffer_rows = snapshot
1381 // .buffer_rows(start)
1382 // .take(1 + (end - start) as usize)
1383 // .collect::<Vec<_>>();
1384
1385 // let head_idx = relative_to - start;
1386 // let mut delta = 1;
1387 // let mut i = head_idx + 1;
1388 // while i < buffer_rows.len() as u32 {
1389 // if buffer_rows[i as usize].is_some() {
1390 // if rows.contains(&(i + start)) {
1391 // relative_rows.insert(i + start, delta);
1392 // }
1393 // delta += 1;
1394 // }
1395 // i += 1;
1396 // }
1397 // delta = 1;
1398 // i = head_idx.min(buffer_rows.len() as u32 - 1);
1399 // while i > 0 && buffer_rows[i as usize].is_none() {
1400 // i -= 1;
1401 // }
1402
1403 // while i > 0 {
1404 // i -= 1;
1405 // if buffer_rows[i as usize].is_some() {
1406 // if rows.contains(&(i + start)) {
1407 // relative_rows.insert(i + start, delta);
1408 // }
1409 // delta += 1;
1410 // }
1411 // }
1412
1413 // relative_rows
1414 // }
1415
1416 // fn layout_line_numbers(
1417 // &self,
1418 // rows: Range<u32>,
1419 // active_rows: &BTreeMap<u32, bool>,
1420 // newest_selection_head: DisplayPoint,
1421 // is_singleton: bool,
1422 // snapshot: &EditorSnapshot,
1423 // cx: &ViewContext<Editor>,
1424 // ) -> (
1425 // Vec<Option<text_layout::Line>>,
1426 // Vec<Option<(FoldStatus, BufferRow, bool)>>,
1427 // ) {
1428 // let style = &self.style;
1429 // let include_line_numbers = snapshot.mode == EditorMode::Full;
1430 // let mut line_number_layouts = Vec::with_capacity(rows.len());
1431 // let mut fold_statuses = Vec::with_capacity(rows.len());
1432 // let mut line_number = String::new();
1433 // let is_relative = settings::get::<EditorSettings>(cx).relative_line_numbers;
1434 // let relative_to = if is_relative {
1435 // Some(newest_selection_head.row())
1436 // } else {
1437 // None
1438 // };
1439
1440 // let relative_rows = self.calculate_relative_line_numbers(&snapshot, &rows, relative_to);
1441
1442 // for (ix, row) in snapshot
1443 // .buffer_rows(rows.start)
1444 // .take((rows.end - rows.start) as usize)
1445 // .enumerate()
1446 // {
1447 // let display_row = rows.start + ix as u32;
1448 // let (active, color) = if active_rows.contains_key(&display_row) {
1449 // (true, style.line_number_active)
1450 // } else {
1451 // (false, style.line_number)
1452 // };
1453 // if let Some(buffer_row) = row {
1454 // if include_line_numbers {
1455 // line_number.clear();
1456 // let default_number = buffer_row + 1;
1457 // let number = relative_rows
1458 // .get(&(ix as u32 + rows.start))
1459 // .unwrap_or(&default_number);
1460 // write!(&mut line_number, "{}", number).unwrap();
1461 // line_number_layouts.push(Some(cx.text_layout_cache().layout_str(
1462 // &line_number,
1463 // style.text.font_size,
1464 // &[(
1465 // line_number.len(),
1466 // RunStyle {
1467 // font_id: style.text.font_id,
1468 // color,
1469 // underline: Default::default(),
1470 // },
1471 // )],
1472 // )));
1473 // fold_statuses.push(
1474 // is_singleton
1475 // .then(|| {
1476 // snapshot
1477 // .fold_for_line(buffer_row)
1478 // .map(|fold_status| (fold_status, buffer_row, active))
1479 // })
1480 // .flatten(),
1481 // )
1482 // }
1483 // } else {
1484 // fold_statuses.push(None);
1485 // line_number_layouts.push(None);
1486 // }
1487 // }
1488
1489 // (line_number_layouts, fold_statuses)
1490 // }
1491
1492 // fn layout_lines(
1493 // &mut self,
1494 // rows: Range<u32>,
1495 // line_number_layouts: &[Option<Line>],
1496 // snapshot: &EditorSnapshot,
1497 // cx: &ViewContext<Editor>,
1498 // ) -> Vec<LineWithInvisibles> {
1499 // if rows.start >= rows.end {
1500 // return Vec::new();
1501 // }
1502
1503 // // When the editor is empty and unfocused, then show the placeholder.
1504 // if snapshot.is_empty() {
1505 // let placeholder_style = self
1506 // .style
1507 // .placeholder_text
1508 // .as_ref()
1509 // .unwrap_or(&self.style.text);
1510 // let placeholder_text = snapshot.placeholder_text();
1511 // let placeholder_lines = placeholder_text
1512 // .as_ref()
1513 // .map_or("", AsRef::as_ref)
1514 // .split('\n')
1515 // .skip(rows.start as usize)
1516 // .chain(iter::repeat(""))
1517 // .take(rows.len());
1518 // placeholder_lines
1519 // .map(|line| {
1520 // cx.text_layout_cache().layout_str(
1521 // line,
1522 // placeholder_style.font_size,
1523 // &[(
1524 // line.len(),
1525 // RunStyle {
1526 // font_id: placeholder_style.font_id,
1527 // color: placeholder_style.color,
1528 // underline: Default::default(),
1529 // },
1530 // )],
1531 // )
1532 // })
1533 // .map(|line| LineWithInvisibles {
1534 // line,
1535 // invisibles: Vec::new(),
1536 // })
1537 // .collect()
1538 // } else {
1539 // let style = &self.style;
1540 // let chunks = snapshot.highlighted_chunks(rows.clone(), true, style);
1541
1542 // LineWithInvisibles::from_chunks(
1543 // chunks,
1544 // &style.text,
1545 // cx.text_layout_cache(),
1546 // cx.font_cache(),
1547 // MAX_LINE_LEN,
1548 // rows.len() as usize,
1549 // line_number_layouts,
1550 // snapshot.mode,
1551 // )
1552 // }
1553 // }
1554
1555 // #[allow(clippy::too_many_arguments)]
1556 // fn layout_blocks(
1557 // &mut self,
1558 // rows: Range<u32>,
1559 // snapshot: &EditorSnapshot,
1560 // editor_width: f32,
1561 // scroll_width: f32,
1562 // gutter_padding: f32,
1563 // gutter_width: f32,
1564 // em_width: f32,
1565 // text_x: f32,
1566 // line_height: f32,
1567 // style: &EditorStyle,
1568 // line_layouts: &[LineWithInvisibles],
1569 // editor: &mut Editor,
1570 // cx: &mut ViewContext<Editor>,
1571 // ) -> (f32, Vec<BlockLayout>) {
1572 // let mut block_id = 0;
1573 // let scroll_x = snapshot.scroll_anchor.offset.x();
1574 // let (fixed_blocks, non_fixed_blocks) = snapshot
1575 // .blocks_in_range(rows.clone())
1576 // .partition::<Vec<_>, _>(|(_, block)| match block {
1577 // TransformBlock::ExcerptHeader { .. } => false,
1578 // TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed,
1579 // });
1580 // let mut render_block = |block: &TransformBlock, width: f32, block_id: usize| {
1581 // let mut element = match block {
1582 // TransformBlock::Custom(block) => {
1583 // let align_to = block
1584 // .position()
1585 // .to_point(&snapshot.buffer_snapshot)
1586 // .to_display_point(snapshot);
1587 // let anchor_x = text_x
1588 // + if rows.contains(&align_to.row()) {
1589 // line_layouts[(align_to.row() - rows.start) as usize]
1590 // .line
1591 // .x_for_index(align_to.column() as usize)
1592 // } else {
1593 // layout_line(align_to.row(), snapshot, style, cx.text_layout_cache())
1594 // .x_for_index(align_to.column() as usize)
1595 // };
1596
1597 // block.render(&mut BlockContext {
1598 // view_context: cx,
1599 // anchor_x,
1600 // gutter_padding,
1601 // line_height,
1602 // scroll_x,
1603 // gutter_width,
1604 // em_width,
1605 // block_id,
1606 // })
1607 // }
1608 // TransformBlock::ExcerptHeader {
1609 // id,
1610 // buffer,
1611 // range,
1612 // starts_new_buffer,
1613 // ..
1614 // } => {
1615 // let tooltip_style = theme::current(cx).tooltip.clone();
1616 // let include_root = editor
1617 // .project
1618 // .as_ref()
1619 // .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
1620 // .unwrap_or_default();
1621 // let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
1622 // let jump_path = ProjectPath {
1623 // worktree_id: file.worktree_id(cx),
1624 // path: file.path.clone(),
1625 // };
1626 // let jump_anchor = range
1627 // .primary
1628 // .as_ref()
1629 // .map_or(range.context.start, |primary| primary.start);
1630 // let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
1631
1632 // enum JumpIcon {}
1633 // MouseEventHandler::new::<JumpIcon, _>((*id).into(), cx, |state, _| {
1634 // let style = style.jump_icon.style_for(state);
1635 // Svg::new("icons/arrow_up_right.svg")
1636 // .with_color(style.color)
1637 // .constrained()
1638 // .with_width(style.icon_width)
1639 // .aligned()
1640 // .contained()
1641 // .with_style(style.container)
1642 // .constrained()
1643 // .with_width(style.button_width)
1644 // .with_height(style.button_width)
1645 // })
1646 // .with_cursor_style(CursorStyle::PointingHand)
1647 // .on_click(MouseButton::Left, move |_, editor, cx| {
1648 // if let Some(workspace) = editor
1649 // .workspace
1650 // .as_ref()
1651 // .and_then(|(workspace, _)| workspace.upgrade(cx))
1652 // {
1653 // workspace.update(cx, |workspace, cx| {
1654 // Editor::jump(
1655 // workspace,
1656 // jump_path.clone(),
1657 // jump_position,
1658 // jump_anchor,
1659 // cx,
1660 // );
1661 // });
1662 // }
1663 // })
1664 // .with_tooltip::<JumpIcon>(
1665 // (*id).into(),
1666 // "Jump to Buffer".to_string(),
1667 // Some(Box::new(crate::OpenExcerpts)),
1668 // tooltip_style.clone(),
1669 // cx,
1670 // )
1671 // .aligned()
1672 // .flex_float()
1673 // });
1674
1675 // if *starts_new_buffer {
1676 // let editor_font_size = style.text.font_size;
1677 // let style = &style.diagnostic_path_header;
1678 // let font_size = (style.text_scale_factor * editor_font_size).round();
1679
1680 // let path = buffer.resolve_file_path(cx, include_root);
1681 // let mut filename = None;
1682 // let mut parent_path = None;
1683 // // Can't use .and_then() because `.file_name()` and `.parent()` return references :(
1684 // if let Some(path) = path {
1685 // filename = path.file_name().map(|f| f.to_string_lossy().to_string());
1686 // parent_path =
1687 // path.parent().map(|p| p.to_string_lossy().to_string() + "/");
1688 // }
1689
1690 // Flex::row()
1691 // .with_child(
1692 // Label::new(
1693 // filename.unwrap_or_else(|| "untitled".to_string()),
1694 // style.filename.text.clone().with_font_size(font_size),
1695 // )
1696 // .contained()
1697 // .with_style(style.filename.container)
1698 // .aligned(),
1699 // )
1700 // .with_children(parent_path.map(|path| {
1701 // Label::new(path, style.path.text.clone().with_font_size(font_size))
1702 // .contained()
1703 // .with_style(style.path.container)
1704 // .aligned()
1705 // }))
1706 // .with_children(jump_icon)
1707 // .contained()
1708 // .with_style(style.container)
1709 // .with_padding_left(gutter_padding)
1710 // .with_padding_right(gutter_padding)
1711 // .expanded()
1712 // .into_any_named("path header block")
1713 // } else {
1714 // let text_style = style.text.clone();
1715 // Flex::row()
1716 // .with_child(Label::new("⋯", text_style))
1717 // .with_children(jump_icon)
1718 // .contained()
1719 // .with_padding_left(gutter_padding)
1720 // .with_padding_right(gutter_padding)
1721 // .expanded()
1722 // .into_any_named("collapsed context")
1723 // }
1724 // }
1725 // };
1726
1727 // element.layout(
1728 // SizeConstraint {
1729 // min: gpui::Point<Pixels>::zero(),
1730 // max: vec2f(width, block.height() as f32 * line_height),
1731 // },
1732 // editor,
1733 // cx,
1734 // );
1735 // element
1736 // };
1737
1738 // let mut fixed_block_max_width = 0f32;
1739 // let mut blocks = Vec::new();
1740 // for (row, block) in fixed_blocks {
1741 // let element = render_block(block, f32::INFINITY, block_id);
1742 // block_id += 1;
1743 // fixed_block_max_width = fixed_block_max_width.max(element.size().x() + em_width);
1744 // blocks.push(BlockLayout {
1745 // row,
1746 // element,
1747 // style: BlockStyle::Fixed,
1748 // });
1749 // }
1750 // for (row, block) in non_fixed_blocks {
1751 // let style = match block {
1752 // TransformBlock::Custom(block) => block.style(),
1753 // TransformBlock::ExcerptHeader { .. } => BlockStyle::Sticky,
1754 // };
1755 // let width = match style {
1756 // BlockStyle::Sticky => editor_width,
1757 // BlockStyle::Flex => editor_width
1758 // .max(fixed_block_max_width)
1759 // .max(gutter_width + scroll_width),
1760 // BlockStyle::Fixed => unreachable!(),
1761 // };
1762 // let element = render_block(block, width, block_id);
1763 // block_id += 1;
1764 // blocks.push(BlockLayout {
1765 // row,
1766 // element,
1767 // style,
1768 // });
1769 // }
1770 // (
1771 // scroll_width.max(fixed_block_max_width - gutter_width),
1772 // blocks,
1773 // )
1774 // }
1775}
1776
1777#[derive(Debug)]
1778pub struct LineWithInvisibles {
1779 pub line: Line,
1780 invisibles: Vec<Invisible>,
1781}
1782
1783// impl LineWithInvisibles {
1784// fn from_chunks<'a>(
1785// chunks: impl Iterator<Item = HighlightedChunk<'a>>,
1786// text_style: &TextStyle,
1787// text_layout_cache: &TextLayoutCache,
1788// font_cache: &Arc<FontCache>,
1789// max_line_len: usize,
1790// max_line_count: usize,
1791// line_number_layouts: &[Option<Line>],
1792// editor_mode: EditorMode,
1793// ) -> Vec<Self> {
1794// let mut layouts = Vec::with_capacity(max_line_count);
1795// let mut line = String::new();
1796// let mut invisibles = Vec::new();
1797// let mut styles = Vec::new();
1798// let mut non_whitespace_added = false;
1799// let mut row = 0;
1800// let mut line_exceeded_max_len = false;
1801// for highlighted_chunk in chunks.chain([HighlightedChunk {
1802// chunk: "\n",
1803// style: None,
1804// is_tab: false,
1805// }]) {
1806// for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
1807// if ix > 0 {
1808// layouts.push(Self {
1809// line: text_layout_cache.layout_str(&line, text_style.font_size, &styles),
1810// invisibles: invisibles.drain(..).collect(),
1811// });
1812
1813// line.clear();
1814// styles.clear();
1815// row += 1;
1816// line_exceeded_max_len = false;
1817// non_whitespace_added = false;
1818// if row == max_line_count {
1819// return layouts;
1820// }
1821// }
1822
1823// if !line_chunk.is_empty() && !line_exceeded_max_len {
1824// let text_style = if let Some(style) = highlighted_chunk.style {
1825// text_style
1826// .clone()
1827// .highlight(style, font_cache)
1828// .map(Cow::Owned)
1829// .unwrap_or_else(|_| Cow::Borrowed(text_style))
1830// } else {
1831// Cow::Borrowed(text_style)
1832// };
1833
1834// if line.len() + line_chunk.len() > max_line_len {
1835// let mut chunk_len = max_line_len - line.len();
1836// while !line_chunk.is_char_boundary(chunk_len) {
1837// chunk_len -= 1;
1838// }
1839// line_chunk = &line_chunk[..chunk_len];
1840// line_exceeded_max_len = true;
1841// }
1842
1843// styles.push((
1844// line_chunk.len(),
1845// RunStyle {
1846// font_id: text_style.font_id,
1847// color: text_style.color,
1848// underline: text_style.underline,
1849// },
1850// ));
1851
1852// if editor_mode == EditorMode::Full {
1853// // Line wrap pads its contents with fake whitespaces,
1854// // avoid printing them
1855// let inside_wrapped_string = line_number_layouts
1856// .get(row)
1857// .and_then(|layout| layout.as_ref())
1858// .is_none();
1859// if highlighted_chunk.is_tab {
1860// if non_whitespace_added || !inside_wrapped_string {
1861// invisibles.push(Invisible::Tab {
1862// line_start_offset: line.len(),
1863// });
1864// }
1865// } else {
1866// invisibles.extend(
1867// line_chunk
1868// .chars()
1869// .enumerate()
1870// .filter(|(_, line_char)| {
1871// let is_whitespace = line_char.is_whitespace();
1872// non_whitespace_added |= !is_whitespace;
1873// is_whitespace
1874// && (non_whitespace_added || !inside_wrapped_string)
1875// })
1876// .map(|(whitespace_index, _)| Invisible::Whitespace {
1877// line_offset: line.len() + whitespace_index,
1878// }),
1879// )
1880// }
1881// }
1882
1883// line.push_str(line_chunk);
1884// }
1885// }
1886// }
1887
1888// layouts
1889// }
1890
1891// fn draw(
1892// &self,
1893// layout: &LayoutState,
1894// row: u32,
1895// scroll_top: f32,
1896// content_origin: gpui::Point<Pixels>,
1897// scroll_left: f32,
1898// visible_text_bounds: Bounds<Pixels>,
1899// whitespace_setting: ShowWhitespaceSetting,
1900// selection_ranges: &[Range<DisplayPoint>],
1901// visible_bounds: Bounds<Pixels>,
1902// cx: &mut ViewContext<Editor>,
1903// ) {
1904// let line_height = layout.position_map.line_height;
1905// let line_y = row as f32 * line_height - scroll_top;
1906
1907// self.line.paint(
1908// content_origin + vec2f(-scroll_left, line_y),
1909// visible_text_bounds,
1910// line_height,
1911// cx,
1912// );
1913
1914// self.draw_invisibles(
1915// &selection_ranges,
1916// layout,
1917// content_origin,
1918// scroll_left,
1919// line_y,
1920// row,
1921// visible_bounds,
1922// line_height,
1923// whitespace_setting,
1924// cx,
1925// );
1926// }
1927
1928// fn draw_invisibles(
1929// &self,
1930// selection_ranges: &[Range<DisplayPoint>],
1931// layout: &LayoutState,
1932// content_origin: gpui::Point<Pixels>,
1933// scroll_left: f32,
1934// line_y: f32,
1935// row: u32,
1936// visible_bounds: Bounds<Pixels>,
1937// line_height: f32,
1938// whitespace_setting: ShowWhitespaceSetting,
1939// cx: &mut ViewContext<Editor>,
1940// ) {
1941// let allowed_invisibles_regions = match whitespace_setting {
1942// ShowWhitespaceSetting::None => return,
1943// ShowWhitespaceSetting::Selection => Some(selection_ranges),
1944// ShowWhitespaceSetting::All => None,
1945// };
1946
1947// for invisible in &self.invisibles {
1948// let (&token_offset, invisible_symbol) = match invisible {
1949// Invisible::Tab { line_start_offset } => (line_start_offset, &layout.tab_invisible),
1950// Invisible::Whitespace { line_offset } => (line_offset, &layout.space_invisible),
1951// };
1952
1953// let x_offset = self.line.x_for_index(token_offset);
1954// let invisible_offset =
1955// (layout.position_map.em_width - invisible_symbol.width()).max(0.0) / 2.0;
1956// let origin = content_origin + vec2f(-scroll_left + x_offset + invisible_offset, line_y);
1957
1958// if let Some(allowed_regions) = allowed_invisibles_regions {
1959// let invisible_point = DisplayPoint::new(row, token_offset as u32);
1960// if !allowed_regions
1961// .iter()
1962// .any(|region| region.start <= invisible_point && invisible_point < region.end)
1963// {
1964// continue;
1965// }
1966// }
1967// invisible_symbol.paint(origin, visible_bounds, line_height, cx);
1968// }
1969// }
1970// }
1971
1972#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1973enum Invisible {
1974 Tab { line_start_offset: usize },
1975 Whitespace { line_offset: usize },
1976}
1977
1978impl Element<Editor> for EditorElement {
1979 type ElementState = ();
1980
1981 fn id(&self) -> Option<gpui::ElementId> {
1982 None
1983 }
1984
1985 fn initialize(
1986 &mut self,
1987 view_state: &mut Editor,
1988 element_state: Option<Self::ElementState>,
1989 cx: &mut gpui::ViewContext<Editor>,
1990 ) -> Self::ElementState {
1991 ()
1992 }
1993
1994 fn layout(
1995 &mut self,
1996 view_state: &mut Editor,
1997 element_state: &mut Self::ElementState,
1998 cx: &mut gpui::ViewContext<Editor>,
1999 ) -> gpui::LayoutId {
2000 cx.request_layout(Style::default().size_full(), None)
2001 }
2002
2003 fn paint(
2004 &mut self,
2005 bounds: Bounds<gpui::Pixels>,
2006 view_state: &mut Editor,
2007 element_state: &mut Self::ElementState,
2008 cx: &mut gpui::ViewContext<Editor>,
2009 ) {
2010 let text_style = cx.text_style();
2011
2012 let layout_text = cx.text_system().layout_text(
2013 "hello world",
2014 text_style.font_size,
2015 &[TextRun {
2016 len: "hello world".len(),
2017 font: text_style.font,
2018 color: text_style.color,
2019 underline: text_style.underline,
2020 }],
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(0.0).min(self.size.y());
2702 let x = position.x() + (scroll_position.x() * self.em_width);
2703 let row = (y / self.line_height + scroll_position.y()) as u32;
2704 let (column, x_overshoot_after_line_end) = if let Some(line) = self
2705 .line_layouts
2706 .get(row as usize - scroll_position.y() as usize)
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, 0f32.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// }