terminal_element.rs

  1pub mod terminal_layout_context;
  2
  3use alacritty_terminal::{
  4    ansi::{Color::Named, NamedColor},
  5    event::WindowSize,
  6    grid::{Dimensions, GridIterator, Indexed, Scroll},
  7    index::{Column as GridCol, Line as GridLine, Point, Side},
  8    selection::SelectionRange,
  9    term::cell::{Cell, Flags},
 10};
 11use editor::{Cursor, CursorShape, HighlightedRange, HighlightedRangeLine};
 12use gpui::{
 13    color::Color,
 14    elements::*,
 15    fonts::{TextStyle, Underline},
 16    geometry::{
 17        rect::RectF,
 18        vector::{vec2f, Vector2F},
 19    },
 20    json::json,
 21    text_layout::{Line, RunStyle},
 22    Event, FontCache, KeyDownEvent, MouseButton, MouseButtonEvent, MouseMovedEvent, MouseRegion,
 23    PaintContext, Quad, ScrollWheelEvent, SizeConstraint, TextLayoutCache, WeakModelHandle,
 24    WeakViewHandle,
 25};
 26use itertools::Itertools;
 27use ordered_float::OrderedFloat;
 28use settings::Settings;
 29use theme::TerminalStyle;
 30use util::ResultExt;
 31
 32use std::{cmp::min, ops::Range};
 33use std::{fmt::Debug, ops::Sub};
 34
 35use crate::{color_translation::convert_color, connection::Terminal, TerminalView};
 36
 37use self::terminal_layout_context::TerminalLayoutData;
 38
 39///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
 40///Scroll multiplier that is set to 3 by default. This will be removed when I
 41///Implement scroll bars.
 42const ALACRITTY_SCROLL_MULTIPLIER: f32 = 3.;
 43
 44///The GPUI element that paints the terminal.
 45///We need to keep a reference to the view for mouse events, do we need it for any other terminal stuff, or can we move that to connection?
 46pub struct TerminalEl {
 47    connection: WeakModelHandle<Terminal>,
 48    view: WeakViewHandle<TerminalView>,
 49    modal: bool,
 50}
 51
 52#[derive(Clone, Copy, Debug)]
 53pub struct TerminalDimensions {
 54    pub cell_width: f32,
 55    pub line_height: f32,
 56    pub height: f32,
 57    pub width: f32,
 58}
 59
 60impl TerminalDimensions {
 61    pub fn new(line_height: f32, cell_width: f32, size: Vector2F) -> Self {
 62        TerminalDimensions {
 63            cell_width,
 64            line_height,
 65            width: size.x(),
 66            height: size.y(),
 67        }
 68    }
 69
 70    pub fn num_lines(&self) -> usize {
 71        (self.height / self.line_height).floor() as usize
 72    }
 73
 74    pub fn num_columns(&self) -> usize {
 75        (self.width / self.cell_width).floor() as usize
 76    }
 77
 78    pub fn height(&self) -> f32 {
 79        self.height
 80    }
 81
 82    pub fn width(&self) -> f32 {
 83        self.width
 84    }
 85
 86    pub fn cell_width(&self) -> f32 {
 87        self.cell_width
 88    }
 89
 90    pub fn line_height(&self) -> f32 {
 91        self.line_height
 92    }
 93}
 94
 95//TODO look at what TermSize is
 96impl Into<WindowSize> for TerminalDimensions {
 97    fn into(self) -> WindowSize {
 98        WindowSize {
 99            num_lines: self.num_lines() as u16,
100            num_cols: self.num_columns() as u16,
101            cell_width: self.cell_width() as u16,
102            cell_height: self.line_height() as u16,
103        }
104    }
105}
106
107impl Dimensions for TerminalDimensions {
108    fn total_lines(&self) -> usize {
109        self.num_lines() //TODO: Check that this is fine. This is supposed to be for the back buffer...
110    }
111
112    fn screen_lines(&self) -> usize {
113        self.num_lines()
114    }
115
116    fn columns(&self) -> usize {
117        self.num_columns()
118    }
119}
120
121#[derive(Clone, Debug, Default)]
122struct LayoutCell {
123    point: Point<i32, i32>,
124    text: Line,
125}
126
127impl LayoutCell {
128    fn new(point: Point<i32, i32>, text: Line) -> LayoutCell {
129        LayoutCell { point, text }
130    }
131
132    fn paint(
133        &self,
134        origin: Vector2F,
135        layout: &LayoutState,
136        visible_bounds: RectF,
137        cx: &mut PaintContext,
138    ) {
139        let pos = point_to_absolute(origin, self.point, layout);
140        self.text
141            .paint(pos, visible_bounds, layout.size.line_height, cx);
142    }
143}
144
145#[derive(Clone, Debug, Default)]
146struct LayoutRect {
147    point: Point<i32, i32>,
148    num_of_cells: usize,
149    color: Color,
150}
151
152impl LayoutRect {
153    fn new(point: Point<i32, i32>, num_of_cells: usize, color: Color) -> LayoutRect {
154        LayoutRect {
155            point,
156            num_of_cells,
157            color,
158        }
159    }
160
161    fn extend(&self) -> Self {
162        LayoutRect {
163            point: self.point,
164            num_of_cells: self.num_of_cells + 1,
165            color: self.color,
166        }
167    }
168
169    fn paint(&self, origin: Vector2F, layout: &LayoutState, cx: &mut PaintContext) {
170        let position = point_to_absolute(origin, self.point, layout);
171
172        let size = vec2f(
173            (layout.size.cell_width.ceil() * self.num_of_cells as f32).ceil(),
174            layout.size.line_height,
175        );
176
177        cx.scene.push_quad(Quad {
178            bounds: RectF::new(position, size),
179            background: Some(self.color),
180            border: Default::default(),
181            corner_radius: 0.,
182        })
183    }
184}
185
186fn point_to_absolute(origin: Vector2F, point: Point<i32, i32>, layout: &LayoutState) -> Vector2F {
187    vec2f(
188        (origin.x() + point.column as f32 * layout.size.cell_width).floor(),
189        origin.y() + point.line as f32 * layout.size.line_height,
190    )
191}
192
193#[derive(Clone, Debug, Default)]
194struct RelativeHighlightedRange {
195    line_index: usize,
196    range: Range<usize>,
197}
198
199impl RelativeHighlightedRange {
200    fn new(line_index: usize, range: Range<usize>) -> Self {
201        RelativeHighlightedRange { line_index, range }
202    }
203
204    fn to_highlighted_range_line(
205        &self,
206        origin: Vector2F,
207        layout: &LayoutState,
208    ) -> HighlightedRangeLine {
209        let start_x = origin.x() + self.range.start as f32 * layout.size.cell_width;
210        let end_x =
211            origin.x() + self.range.end as f32 * layout.size.cell_width + layout.size.cell_width;
212
213        return HighlightedRangeLine { start_x, end_x };
214    }
215}
216
217///The information generated during layout that is nescessary for painting
218pub struct LayoutState {
219    cells: Vec<LayoutCell>,
220    rects: Vec<LayoutRect>,
221    highlights: Vec<RelativeHighlightedRange>,
222    cursor: Option<Cursor>,
223    background_color: Color,
224    selection_color: Color,
225    size: TerminalDimensions,
226}
227
228impl TerminalEl {
229    pub fn new(
230        view: WeakViewHandle<TerminalView>,
231        connection: WeakModelHandle<Terminal>,
232        modal: bool,
233    ) -> TerminalEl {
234        TerminalEl {
235            view,
236            connection,
237            modal,
238        }
239    }
240
241    fn attach_mouse_handlers(
242        &self,
243        origin: Vector2F,
244        view_id: usize,
245        visible_bounds: RectF,
246        cur_size: TerminalDimensions,
247        cx: &mut PaintContext,
248    ) {
249        let mouse_down_connection = self.connection.clone();
250        let click_connection = self.connection.clone();
251        let drag_connection = self.connection.clone();
252        cx.scene.push_mouse_region(
253            MouseRegion::new(view_id, None, visible_bounds)
254                .on_down(
255                    MouseButton::Left,
256                    move |MouseButtonEvent { position, .. }, cx| {
257                        if let Some(conn_handle) = mouse_down_connection.upgrade(cx.app) {
258                            conn_handle.update(cx.app, |terminal, cx| {
259                                let (point, side) = mouse_to_cell_data(
260                                    position,
261                                    origin,
262                                    cur_size,
263                                    terminal.get_display_offset(),
264                                );
265
266                                terminal.mouse_down(point, side);
267
268                                cx.notify();
269                            })
270                        }
271                    },
272                )
273                .on_click(
274                    MouseButton::Left,
275                    move |MouseButtonEvent {
276                              position,
277                              click_count,
278                              ..
279                          },
280                          cx| {
281                        cx.focus_parent_view();
282                        if let Some(conn_handle) = click_connection.upgrade(cx.app) {
283                            conn_handle.update(cx.app, |terminal, cx| {
284                                let (point, side) = mouse_to_cell_data(
285                                    position,
286                                    origin,
287                                    cur_size,
288                                    terminal.get_display_offset(),
289                                );
290
291                                terminal.click(point, side, click_count);
292
293                                cx.notify();
294                            });
295                        }
296                    },
297                )
298                .on_drag(
299                    MouseButton::Left,
300                    move |_, MouseMovedEvent { position, .. }, cx| {
301                        if let Some(conn_handle) = drag_connection.upgrade(cx.app) {
302                            conn_handle.update(cx.app, |terminal, cx| {
303                                let (point, side) = mouse_to_cell_data(
304                                    position,
305                                    origin,
306                                    cur_size,
307                                    terminal.get_display_offset(),
308                                );
309
310                                terminal.drag(point, side);
311
312                                cx.notify()
313                            });
314                        }
315                    },
316                ),
317        );
318    }
319}
320
321impl Element for TerminalEl {
322    type LayoutState = LayoutState;
323    type PaintState = ();
324
325    fn layout(
326        &mut self,
327        constraint: gpui::SizeConstraint,
328        cx: &mut gpui::LayoutContext,
329    ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
330        let layout =
331            TerminalLayoutData::new(cx.global::<Settings>(), &cx.font_cache(), constraint.max);
332
333        let terminal = self.connection.upgrade(cx).unwrap().read(cx);
334
335        let (cursor, cells, rects, highlights) =
336            terminal.render_lock(Some(layout.size.clone()), |content| {
337                let (cells, rects, highlights) = layout_grid(
338                    content.display_iter,
339                    &layout.text_style,
340                    layout.terminal_theme,
341                    cx.text_layout_cache,
342                    self.modal,
343                    content.selection,
344                );
345
346                //Layout cursor
347                let cursor = layout_cursor(
348                    // grid,
349                    cx.text_layout_cache,
350                    &layout,
351                    content.cursor.point,
352                    content.display_offset,
353                    constraint,
354                );
355
356                (cursor, cells, rects, highlights)
357            });
358
359        //Select background color
360        let background_color = if self.modal {
361            layout.terminal_theme.colors.modal_background
362        } else {
363            layout.terminal_theme.colors.background
364        };
365
366        //Done!
367        (
368            constraint.max,
369            LayoutState {
370                cells,
371                cursor,
372                background_color,
373                selection_color: layout.selection_color,
374                size: layout.size,
375                rects,
376                highlights,
377            },
378        )
379    }
380
381    fn paint(
382        &mut self,
383        bounds: gpui::geometry::rect::RectF,
384        visible_bounds: gpui::geometry::rect::RectF,
385        layout: &mut Self::LayoutState,
386        cx: &mut gpui::PaintContext,
387    ) -> Self::PaintState {
388        /*
389         * For paint, I want to change how mouse events are handled:
390         * - Refactor the mouse handlers to push the grid cell actions into the connection
391         *   - But keep the conversion from GPUI coordinates to grid cells in the Terminal element
392         * - Switch from directly painting things, to calling 'paint' on items produced by layout
393         */
394
395        //Setup element stuff
396        let clip_bounds = Some(visible_bounds);
397
398        cx.paint_layer(clip_bounds, |cx| {
399            let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
400
401            //Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
402            self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, layout.size, cx);
403
404            cx.paint_layer(clip_bounds, |cx| {
405                //Start with a background color
406                cx.scene.push_quad(Quad {
407                    bounds: RectF::new(bounds.origin(), bounds.size()),
408                    background: Some(layout.background_color),
409                    border: Default::default(),
410                    corner_radius: 0.,
411                });
412
413                for rect in &layout.rects {
414                    rect.paint(origin, &layout, cx)
415                }
416            });
417
418            //Draw Selection
419            cx.paint_layer(clip_bounds, |cx| {
420                let start_y = layout.highlights.get(0).map(|highlight| {
421                    origin.y() + highlight.line_index as f32 * layout.size.line_height
422                });
423
424                if let Some(y) = start_y {
425                    let range_lines = layout
426                        .highlights
427                        .iter()
428                        .map(|relative_highlight| {
429                            relative_highlight.to_highlighted_range_line(origin, layout)
430                        })
431                        .collect::<Vec<HighlightedRangeLine>>();
432
433                    let hr = HighlightedRange {
434                        start_y: y, //Need to change this
435                        line_height: layout.size.line_height,
436                        lines: range_lines,
437                        color: layout.selection_color,
438                        //Copied from editor. TODO: move to theme or something
439                        corner_radius: 0.15 * layout.size.line_height,
440                    };
441                    hr.paint(bounds, cx.scene);
442                }
443            });
444
445            //Draw the text cells
446            cx.paint_layer(clip_bounds, |cx| {
447                for cell in &layout.cells {
448                    cell.paint(origin, layout, visible_bounds, cx);
449                }
450            });
451
452            //Draw cursor
453            if let Some(cursor) = &layout.cursor {
454                cx.paint_layer(clip_bounds, |cx| {
455                    cursor.paint(origin, cx);
456                })
457            }
458        });
459    }
460
461    fn dispatch_event(
462        &mut self,
463        event: &gpui::Event,
464        _bounds: gpui::geometry::rect::RectF,
465        visible_bounds: gpui::geometry::rect::RectF,
466        layout: &mut Self::LayoutState,
467        _paint: &mut Self::PaintState,
468        cx: &mut gpui::EventContext,
469    ) -> bool {
470        match event {
471            Event::ScrollWheel(ScrollWheelEvent {
472                delta, position, ..
473            }) => visible_bounds
474                .contains_point(*position)
475                .then(|| {
476                    let vertical_scroll =
477                        (delta.y() / layout.size.line_height) * ALACRITTY_SCROLL_MULTIPLIER;
478
479                    self.connection.upgrade(cx.app).map(|terminal| {
480                        terminal
481                            .read(cx.app)
482                            .scroll(Scroll::Delta(vertical_scroll.round() as i32));
483                    });
484                })
485                .is_some(),
486            Event::KeyDown(KeyDownEvent { keystroke, .. }) => {
487                if !cx.is_parent_view_focused() {
488                    return false;
489                }
490
491                //TODO Talk to keith about how to catch events emitted from an element.
492                if let Some(view) = self.view.upgrade(cx.app) {
493                    view.update(cx.app, |view, cx| view.clear_bel(cx))
494                }
495
496                self.connection
497                    .upgrade(cx.app)
498                    .map(|model_handle| model_handle.read(cx.app))
499                    .map(|term| term.try_keystroke(keystroke))
500                    .unwrap_or(false)
501            }
502            _ => false,
503        }
504    }
505
506    fn metadata(&self) -> Option<&dyn std::any::Any> {
507        None
508    }
509
510    fn debug(
511        &self,
512        _bounds: gpui::geometry::rect::RectF,
513        _layout: &Self::LayoutState,
514        _paint: &Self::PaintState,
515        _cx: &gpui::DebugContext,
516    ) -> gpui::serde_json::Value {
517        json!({
518            "type": "TerminalElement",
519        })
520    }
521}
522
523///TODO: Fix cursor rendering with alacritty fork
524fn layout_cursor(
525    // grid: &Grid<Cell>,
526    text_layout_cache: &TextLayoutCache,
527    tcx: &TerminalLayoutData,
528    cursor_point: Point,
529    display_offset: usize,
530    constraint: SizeConstraint,
531) -> Option<Cursor> {
532    let cursor_text = layout_cursor_text(/*grid,*/ cursor_point, text_layout_cache, tcx);
533    get_cursor_shape(
534        cursor_point.line.0 as usize,
535        cursor_point.column.0 as usize,
536        display_offset,
537        tcx.size.line_height,
538        tcx.size.cell_width,
539        (constraint.max.y() / tcx.size.line_height) as usize, //TODO
540        &cursor_text,
541    )
542    .map(move |(cursor_position, block_width)| {
543        let block_width = if block_width != 0.0 {
544            block_width
545        } else {
546            tcx.size.cell_width
547        };
548
549        Cursor::new(
550            cursor_position,
551            block_width,
552            tcx.size.line_height,
553            tcx.terminal_theme.colors.cursor,
554            CursorShape::Block,
555            Some(cursor_text.clone()),
556        )
557    })
558}
559
560fn layout_cursor_text(
561    // grid: &Grid<Cell>,
562    _cursor_point: Point,
563    text_layout_cache: &TextLayoutCache,
564    tcx: &TerminalLayoutData,
565) -> Line {
566    let cursor_text = " "; //grid[cursor_point.line][cursor_point.column].c.to_string();
567
568    text_layout_cache.layout_str(
569        &cursor_text,
570        tcx.text_style.font_size,
571        &[(
572            cursor_text.len(),
573            RunStyle {
574                font_id: tcx.text_style.font_id,
575                color: tcx.terminal_theme.colors.background,
576                underline: Default::default(),
577            },
578        )],
579    )
580}
581
582pub fn mouse_to_cell_data(
583    pos: Vector2F,
584    origin: Vector2F,
585    cur_size: TerminalDimensions,
586    display_offset: usize,
587) -> (Point, alacritty_terminal::index::Direction) {
588    let pos = pos.sub(origin);
589    let point = {
590        let col = pos.x() / cur_size.cell_width; //TODO: underflow...
591        let col = min(GridCol(col as usize), cur_size.last_column());
592
593        let line = pos.y() / cur_size.line_height;
594        let line = min(line as i32, cur_size.bottommost_line().0);
595
596        Point::new(GridLine(line - display_offset as i32), col)
597    };
598
599    //Copied (with modifications) from alacritty/src/input.rs > Processor::cell_side()
600    let side = {
601        let x = pos.0.x() as usize;
602        let cell_x = x.saturating_sub(cur_size.cell_width as usize) % cur_size.cell_width as usize;
603        let half_cell_width = (cur_size.cell_width / 2.0) as usize;
604
605        let additional_padding =
606            (cur_size.width() - cur_size.cell_width * 2.) % cur_size.cell_width;
607        let end_of_grid = cur_size.width() - cur_size.cell_width - additional_padding;
608        //Width: Pixels or columns?
609        if cell_x > half_cell_width
610                // Edge case when mouse leaves the window.
611                || x as f32 >= end_of_grid
612        {
613            Side::Right
614        } else {
615            Side::Left
616        }
617    };
618
619    (point, side)
620}
621
622fn layout_grid(
623    grid: GridIterator<Cell>,
624    text_style: &TextStyle,
625    terminal_theme: &TerminalStyle,
626    text_layout_cache: &TextLayoutCache,
627    modal: bool,
628    selection_range: Option<SelectionRange>,
629) -> (
630    Vec<LayoutCell>,
631    Vec<LayoutRect>,
632    Vec<RelativeHighlightedRange>,
633) {
634    let mut cells = vec![];
635    let mut rects = vec![];
636    let mut highlight_ranges = vec![];
637
638    let mut cur_rect: Option<LayoutRect> = None;
639    let mut cur_alac_color = None;
640    let mut highlighted_range = None;
641
642    let linegroups = grid.group_by(|i| i.point.line);
643    for (line_index, (_, line)) in linegroups.into_iter().enumerate() {
644        for (x_index, cell) in line.enumerate() {
645            //Increase selection range
646            {
647                if selection_range
648                    .map(|range| range.contains(cell.point))
649                    .unwrap_or(false)
650                {
651                    let mut range = highlighted_range.take().unwrap_or(x_index..x_index);
652                    range.end = range.end.max(x_index);
653                    highlighted_range = Some(range);
654                }
655            }
656
657            //Expand background rect range
658            {
659                if matches!(cell.bg, Named(NamedColor::Background)) {
660                    //Continue to next cell, resetting variables if nescessary
661                    cur_alac_color = None;
662                    if let Some(rect) = cur_rect {
663                        rects.push(rect);
664                        cur_rect = None
665                    }
666                } else {
667                    match cur_alac_color {
668                        Some(cur_color) => {
669                            if cell.bg == cur_color {
670                                cur_rect = cur_rect.take().map(|rect| rect.extend());
671                            } else {
672                                cur_alac_color = Some(cell.bg);
673                                if let Some(_) = cur_rect {
674                                    rects.push(cur_rect.take().unwrap());
675                                }
676                                cur_rect = Some(LayoutRect::new(
677                                    Point::new(line_index as i32, cell.point.column.0 as i32),
678                                    1,
679                                    convert_color(&cell.bg, &terminal_theme.colors, modal),
680                                ));
681                            }
682                        }
683                        None => {
684                            cur_alac_color = Some(cell.bg);
685                            cur_rect = Some(LayoutRect::new(
686                                Point::new(line_index as i32, cell.point.column.0 as i32),
687                                1,
688                                convert_color(&cell.bg, &terminal_theme.colors, modal),
689                            ));
690                        }
691                    }
692                }
693            }
694
695            //Layout current cell text
696            {
697                let cell_text = &cell.c.to_string();
698                if cell_text != " " {
699                    let cell_style = cell_style(&cell, terminal_theme, text_style, modal);
700
701                    let layout_cell = text_layout_cache.layout_str(
702                        cell_text,
703                        text_style.font_size,
704                        &[(cell_text.len(), cell_style)],
705                    );
706
707                    cells.push(LayoutCell::new(
708                        Point::new(line_index as i32, cell.point.column.0 as i32),
709                        layout_cell,
710                    ))
711                }
712            };
713        }
714
715        if highlighted_range.is_some() {
716            highlight_ranges.push(RelativeHighlightedRange::new(
717                line_index,
718                highlighted_range.take().unwrap(),
719            ))
720        }
721
722        if cur_rect.is_some() {
723            rects.push(cur_rect.take().unwrap());
724        }
725    }
726
727    (cells, rects, highlight_ranges)
728}
729
730// Compute the cursor position and expected block width, may return a zero width if x_for_index returns
731// the same position for sequential indexes. Use em_width instead
732//TODO: This function is messy, too many arguments and too many ifs. Simplify.
733fn get_cursor_shape(
734    line: usize,
735    line_index: usize,
736    display_offset: usize,
737    line_height: f32,
738    cell_width: f32,
739    total_lines: usize,
740    text_fragment: &Line,
741) -> Option<(Vector2F, f32)> {
742    let cursor_line = line + display_offset;
743    if cursor_line <= total_lines {
744        let cursor_width = if text_fragment.width() == 0. {
745            cell_width
746        } else {
747            text_fragment.width()
748        };
749
750        Some((
751            vec2f(
752                line_index as f32 * cell_width,
753                cursor_line as f32 * line_height,
754            ),
755            cursor_width,
756        ))
757    } else {
758        None
759    }
760}
761
762///Convert the Alacritty cell styles to GPUI text styles and background color
763fn cell_style(
764    indexed: &Indexed<&Cell>,
765    style: &TerminalStyle,
766    text_style: &TextStyle,
767    modal: bool,
768) -> RunStyle {
769    let flags = indexed.cell.flags;
770    let fg = convert_color(&indexed.cell.fg, &style.colors, modal);
771
772    let underline = flags
773        .contains(Flags::UNDERLINE)
774        .then(|| Underline {
775            color: Some(fg),
776            squiggly: false,
777            thickness: OrderedFloat(1.),
778        })
779        .unwrap_or_default();
780
781    RunStyle {
782        color: fg,
783        font_id: text_style.font_id,
784        underline,
785    }
786}
787
788mod test {
789
790    #[test]
791    fn test_mouse_to_selection() {
792        let term_width = 100.;
793        let term_height = 200.;
794        let cell_width = 10.;
795        let line_height = 20.;
796        let mouse_pos_x = 100.; //Window relative
797        let mouse_pos_y = 100.; //Window relative
798        let origin_x = 10.;
799        let origin_y = 20.;
800
801        let cur_size = crate::terminal_element::TerminalDimensions::new(
802            line_height,
803            cell_width,
804            gpui::geometry::vector::vec2f(term_width, term_height),
805        );
806
807        let mouse_pos = gpui::geometry::vector::vec2f(mouse_pos_x, mouse_pos_y);
808        let origin = gpui::geometry::vector::vec2f(origin_x, origin_y); //Position of terminal window, 1 'cell' in
809        let (point, _) =
810            crate::terminal_element::mouse_to_cell_data(mouse_pos, origin, cur_size, 0);
811        assert_eq!(
812            point,
813            alacritty_terminal::index::Point::new(
814                alacritty_terminal::index::Line(((mouse_pos_y - origin_y) / line_height) as i32),
815                alacritty_terminal::index::Column(((mouse_pos_x - origin_x) / cell_width) as usize),
816            )
817        );
818    }
819}