1// #![allow(unused)] // todo!()
2
3// use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
4// use gpui::{
5// point, transparent_black, AnyElement, AppContext, Bounds, Component, CursorStyle, Element,
6// ElementId, FontStyle, FontWeight, HighlightStyle, Hsla, IntoElement, IsZero, LayoutId,
7// ModelContext, Overlay, Pixels, Point, Quad, TextRun, TextStyle, TextSystem, Underline,
8// ViewContext, WeakModel, WindowContext,
9// };
10// use itertools::Itertools;
11// use language::CursorShape;
12// use ordered_float::OrderedFloat;
13// use settings::Settings;
14// use terminal::{
15// alacritty_terminal::{
16// ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor},
17// grid::Dimensions,
18// index::Point as AlacPoint,
19// term::{cell::Flags, TermMode},
20// },
21// terminal_settings::TerminalSettings,
22// IndexedCell, Terminal, TerminalContent, TerminalSize,
23// };
24// use theme::ThemeSettings;
25
26// use std::mem;
27// use std::{fmt::Debug, ops::RangeInclusive};
28
29// use crate::TerminalView;
30
31// ///The information generated during layout that is necessary for painting
32// pub struct LayoutState {
33// cells: Vec<LayoutCell>,
34// rects: Vec<LayoutRect>,
35// relative_highlighted_ranges: Vec<(RangeInclusive<AlacPoint>, Hsla)>,
36// cursor: Option<Cursor>,
37// background_color: Hsla,
38// size: TerminalSize,
39// mode: TermMode,
40// display_offset: usize,
41// hyperlink_tooltip: Option<AnyElement>,
42// gutter: f32,
43// }
44
45// ///Helper struct for converting data between alacritty's cursor points, and displayed cursor points
46// struct DisplayCursor {
47// line: i32,
48// col: usize,
49// }
50
51// impl DisplayCursor {
52// fn from(cursor_point: AlacPoint, display_offset: usize) -> Self {
53// Self {
54// line: cursor_point.line.0 + display_offset as i32,
55// col: cursor_point.column.0,
56// }
57// }
58
59// pub fn line(&self) -> i32 {
60// self.line
61// }
62
63// pub fn col(&self) -> usize {
64// self.col
65// }
66// }
67
68// #[derive(Clone, Debug, Default)]
69// struct LayoutCell {
70// point: AlacPoint<i32, i32>,
71// text: Line,
72// }
73
74// impl LayoutCell {
75// fn new(point: AlacPoint<i32, i32>, text: Line) -> LayoutCell {
76// LayoutCell { point, text }
77// }
78
79// fn paint(
80// &self,
81// origin: Point<Pixels>,
82// layout: &LayoutState,
83// _visible_bounds: Bounds<Pixels>,
84// _view: &mut TerminalView,
85// cx: &mut WindowContext,
86// ) {
87// let pos = {
88// let point = self.point;
89
90// Point::new(
91// (origin.x + point.column as f32 * layout.size.cell_width).floor(),
92// origin.y + point.line as f32 * layout.size.line_height,
93// )
94// };
95
96// self.text.paint(pos, layout.size.line_height, cx);
97// }
98// }
99
100// #[derive(Clone, Debug, Default)]
101// struct LayoutRect {
102// point: AlacPoint<i32, i32>,
103// num_of_cells: usize,
104// color: Hsla,
105// }
106
107// impl LayoutRect {
108// fn new(point: AlacPoint<i32, i32>, num_of_cells: usize, color: Hsla) -> LayoutRect {
109// LayoutRect {
110// point,
111// num_of_cells,
112// color,
113// }
114// }
115
116// fn extend(&self) -> Self {
117// LayoutRect {
118// point: self.point,
119// num_of_cells: self.num_of_cells + 1,
120// color: self.color,
121// }
122// }
123
124// fn paint(
125// &self,
126// origin: Point<Pixels>,
127// layout: &LayoutState,
128// _view: &mut TerminalView,
129// cx: &mut ViewContext<TerminalView>,
130// ) {
131// let position = {
132// let alac_point = self.point;
133// point(
134// (origin.x + alac_point.column as f32 * layout.size.cell_width).floor(),
135// origin.y + alac_point.line as f32 * layout.size.line_height,
136// )
137// };
138// let size = point(
139// (layout.size.cell_width * self.num_of_cells as f32).ceil(),
140// layout.size.line_height,
141// )
142// .into();
143
144// cx.paint_quad(
145// Bounds::new(position, size),
146// Default::default(),
147// self.color,
148// Default::default(),
149// transparent_black(),
150// );
151// }
152// }
153
154// ///The GPUI element that paints the terminal.
155// ///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?
156// pub struct TerminalElement {
157// terminal: WeakModel<Terminal>,
158// focused: bool,
159// cursor_visible: bool,
160// can_navigate_to_selected_word: bool,
161// }
162
163// impl TerminalElement {
164// pub fn new(
165// terminal: WeakModel<Terminal>,
166// focused: bool,
167// cursor_visible: bool,
168// can_navigate_to_selected_word: bool,
169// ) -> TerminalElement {
170// TerminalElement {
171// terminal,
172// focused,
173// cursor_visible,
174// can_navigate_to_selected_word,
175// }
176// }
177
178// //Vec<Range<AlacPoint>> -> Clip out the parts of the ranges
179
180// fn layout_grid(
181// grid: &Vec<IndexedCell>,
182// text_style: &TextStyle,
183// terminal_theme: &TerminalStyle,
184// text_system: &TextSystem,
185// hyperlink: Option<(HighlightStyle, &RangeInclusive<AlacPoint>)>,
186// cx: &mut WindowContext<'_>,
187// ) -> (Vec<LayoutCell>, Vec<LayoutRect>) {
188// let mut cells = vec![];
189// let mut rects = vec![];
190
191// let mut cur_rect: Option<LayoutRect> = None;
192// let mut cur_alac_color = None;
193
194// let linegroups = grid.into_iter().group_by(|i| i.point.line);
195// for (line_index, (_, line)) in linegroups.into_iter().enumerate() {
196// for cell in line {
197// let mut fg = cell.fg;
198// let mut bg = cell.bg;
199// if cell.flags.contains(Flags::INVERSE) {
200// mem::swap(&mut fg, &mut bg);
201// }
202
203// //Expand background rect range
204// {
205// if matches!(bg, Named(NamedColor::Background)) {
206// //Continue to next cell, resetting variables if necessary
207// cur_alac_color = None;
208// if let Some(rect) = cur_rect {
209// rects.push(rect);
210// cur_rect = None
211// }
212// } else {
213// match cur_alac_color {
214// Some(cur_color) => {
215// if bg == cur_color {
216// cur_rect = cur_rect.take().map(|rect| rect.extend());
217// } else {
218// cur_alac_color = Some(bg);
219// if cur_rect.is_some() {
220// rects.push(cur_rect.take().unwrap());
221// }
222// cur_rect = Some(LayoutRect::new(
223// AlacPoint::new(
224// line_index as i32,
225// cell.point.column.0 as i32,
226// ),
227// 1,
228// convert_color(&bg, &terminal_theme),
229// ));
230// }
231// }
232// None => {
233// cur_alac_color = Some(bg);
234// cur_rect = Some(LayoutRect::new(
235// AlacPoint::new(line_index as i32, cell.point.column.0 as i32),
236// 1,
237// convert_color(&bg, &terminal_theme),
238// ));
239// }
240// }
241// }
242// }
243
244// //Layout current cell text
245// {
246// let cell_text = &cell.c.to_string();
247// if !is_blank(&cell) {
248// let cell_style = TerminalElement::cell_style(
249// &cell,
250// fg,
251// terminal_theme,
252// text_style,
253// text_system,
254// hyperlink,
255// );
256
257// let layout_cell = text_system.layout_line(
258// cell_text,
259// text_style.font_size.to_pixels(cx.rem_size()),
260// &[(cell_text.len(), cell_style)],
261// )?;
262
263// cells.push(LayoutCell::new(
264// AlacPoint::new(line_index as i32, cell.point.column.0 as i32),
265// layout_cell,
266// ))
267// };
268// }
269// }
270
271// if cur_rect.is_some() {
272// rects.push(cur_rect.take().unwrap());
273// }
274// }
275// (cells, rects)
276// }
277
278// // Compute the cursor position and expected block width, may return a zero width if x_for_index returns
279// // the same position for sequential indexes. Use em_width instead
280// fn shape_cursor(
281// cursor_point: DisplayCursor,
282// size: TerminalSize,
283// text_fragment: &Line,
284// ) -> Option<(Point<Pixels>, Pixels)> {
285// if cursor_point.line() < size.total_lines() as i32 {
286// let cursor_width = if text_fragment.width == Pixels::ZERO {
287// size.cell_width()
288// } else {
289// text_fragment.width
290// };
291
292// //Cursor should always surround as much of the text as possible,
293// //hence when on pixel boundaries round the origin down and the width up
294// Some((
295// point(
296// (cursor_point.col() as f32 * size.cell_width()).floor(),
297// (cursor_point.line() as f32 * size.line_height()).floor(),
298// ),
299// cursor_width.ceil(),
300// ))
301// } else {
302// None
303// }
304// }
305
306// ///Convert the Alacritty cell styles to GPUI text styles and background color
307// fn cell_style(
308// indexed: &IndexedCell,
309// fg: terminal::alacritty_terminal::ansi::Color,
310// style: &TerminalStyle,
311// text_style: &TextStyle,
312// text_system: &TextSystem,
313// hyperlink: Option<(HighlightStyle, &RangeInclusive<AlacPoint>)>,
314// ) -> TextRun {
315// let flags = indexed.cell.flags;
316// let fg = convert_color(&fg, &style);
317
318// let mut underline = flags
319// .intersects(Flags::ALL_UNDERLINES)
320// .then(|| Underline {
321// color: fg,
322// thickness: Pixels::from(1.0).scale(1.0),
323// order: todo!(),
324// bounds: todo!(),
325// content_mask: todo!(),
326// wavy: flags.contains(Flags::UNDERCURL),
327// })
328// .unwrap_or_default();
329
330// if indexed.cell.hyperlink().is_some() {
331// if underline.thickness.is_zero() {
332// underline.thickness = Pixels::from(1.0).scale(1.0);
333// }
334// }
335
336// let mut properties = Properties::new();
337// if indexed.flags.intersects(Flags::BOLD | Flags::DIM_BOLD) {
338// properties = *properties.weight(FontWeight::BOLD);
339// }
340// if indexed.flags.intersects(Flags::ITALIC) {
341// properties = *properties.style(FontStyle::Italic);
342// }
343
344// let font_id = text_system
345// .select_font(text_style.font_family, &properties)
346// .unwrap_or(text_style.font_id);
347
348// let mut result = TextRun {
349// color: fg,
350// font_id,
351// underline,
352// };
353
354// if let Some((style, range)) = hyperlink {
355// if range.contains(&indexed.point) {
356// if let Some(underline) = style.underline {
357// result.underline = Some(underline);
358// }
359
360// if let Some(color) = style.color {
361// result.color = color;
362// }
363// }
364// }
365
366// result
367// }
368
369// // todo!()
370// // fn generic_button_handler<E>(
371// // connection: WeakModel<Terminal>,
372// // origin: Point<Pixels>,
373// // f: impl Fn(&mut Terminal, Point<Pixels>, E, &mut ModelContext<Terminal>),
374// // ) -> impl Fn(E, &mut TerminalView, &mut EventContext<TerminalView>) {
375// // move |event, _: &mut TerminalView, cx| {
376// // cx.focus_parent();
377// // if let Some(conn_handle) = connection.upgrade() {
378// // conn_handle.update(cx, |terminal, cx| {
379// // f(terminal, origin, event, cx);
380
381// // cx.notify();
382// // })
383// // }
384// // }
385// // }
386
387// fn attach_mouse_handlers(
388// &self,
389// origin: Point<Pixels>,
390// visible_bounds: Bounds<Pixels>,
391// mode: TermMode,
392// cx: &mut ViewContext<TerminalView>,
393// ) {
394// // todo!()
395// // let connection = self.terminal;
396
397// // let mut region = MouseRegion::new::<Self>(cx.view_id(), 0, visible_bounds);
398
399// // // Terminal Emulator controlled behavior:
400// // region = region
401// // // Start selections
402// // .on_down(MouseButton::Left, move |event, v: &mut TerminalView, cx| {
403// // let terminal_view = cx.handle();
404// // cx.focus(&terminal_view);
405// // v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
406// // if let Some(conn_handle) = connection.upgrade() {
407// // conn_handle.update(cx, |terminal, cx| {
408// // terminal.mouse_down(&event, origin);
409
410// // cx.notify();
411// // })
412// // }
413// // })
414// // // Update drag selections
415// // .on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| {
416// // if event.end {
417// // return;
418// // }
419
420// // if cx.is_self_focused() {
421// // if let Some(conn_handle) = connection.upgrade() {
422// // conn_handle.update(cx, |terminal, cx| {
423// // terminal.mouse_drag(event, origin);
424// // cx.notify();
425// // })
426// // }
427// // }
428// // })
429// // // Copy on up behavior
430// // .on_up(
431// // MouseButton::Left,
432// // TerminalElement::generic_button_handler(
433// // connection,
434// // origin,
435// // move |terminal, origin, e, cx| {
436// // terminal.mouse_up(&e, origin, cx);
437// // },
438// // ),
439// // )
440// // // Context menu
441// // .on_click(
442// // MouseButton::Right,
443// // move |event, view: &mut TerminalView, cx| {
444// // let mouse_mode = if let Some(conn_handle) = connection.upgrade() {
445// // conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(event.shift))
446// // } else {
447// // // If we can't get the model handle, probably can't deploy the context menu
448// // true
449// // };
450// // if !mouse_mode {
451// // view.deploy_context_menu(event.position, cx);
452// // }
453// // },
454// // )
455// // .on_move(move |event, _: &mut TerminalView, cx| {
456// // if cx.is_self_focused() {
457// // if let Some(conn_handle) = connection.upgrade() {
458// // conn_handle.update(cx, |terminal, cx| {
459// // terminal.mouse_move(&event, origin);
460// // cx.notify();
461// // })
462// // }
463// // }
464// // })
465// // .on_scroll(move |event, _: &mut TerminalView, cx| {
466// // if let Some(conn_handle) = connection.upgrade() {
467// // conn_handle.update(cx, |terminal, cx| {
468// // terminal.scroll_wheel(event, origin);
469// // cx.notify();
470// // })
471// // }
472// // });
473
474// // // Mouse mode handlers:
475// // // All mouse modes need the extra click handlers
476// // if mode.intersects(TermMode::MOUSE_MODE) {
477// // region = region
478// // .on_down(
479// // MouseButton::Right,
480// // TerminalElement::generic_button_handler(
481// // connection,
482// // origin,
483// // move |terminal, origin, e, _cx| {
484// // terminal.mouse_down(&e, origin);
485// // },
486// // ),
487// // )
488// // .on_down(
489// // MouseButton::Middle,
490// // TerminalElement::generic_button_handler(
491// // connection,
492// // origin,
493// // move |terminal, origin, e, _cx| {
494// // terminal.mouse_down(&e, origin);
495// // },
496// // ),
497// // )
498// // .on_up(
499// // MouseButton::Right,
500// // TerminalElement::generic_button_handler(
501// // connection,
502// // origin,
503// // move |terminal, origin, e, cx| {
504// // terminal.mouse_up(&e, origin, cx);
505// // },
506// // ),
507// // )
508// // .on_up(
509// // MouseButton::Middle,
510// // TerminalElement::generic_button_handler(
511// // connection,
512// // origin,
513// // move |terminal, origin, e, cx| {
514// // terminal.mouse_up(&e, origin, cx);
515// // },
516// // ),
517// // )
518// // }
519
520// // cx.scene().push_mouse_region(region);
521// }
522// }
523
524// impl Element for TerminalElement {
525// type State = LayoutState;
526
527// fn layout(
528// &mut self,
529// element_state: Option<Self::State>,
530// cx: &mut WindowContext<'_>,
531// ) -> (LayoutId, Self::State) {
532// let settings = ThemeSettings::get_global(cx);
533// let terminal_settings = TerminalSettings::get_global(cx);
534
535// //Setup layout information
536// let terminal_theme = settings.theme.terminal.clone(); //TODO: Try to minimize this clone.
537// let link_style = settings.theme.editor.link_definition;
538// let tooltip_style = settings.theme.tooltip.clone();
539
540// let text_system = cx.text_system();
541// let font_size = font_size(&terminal_settings, cx).unwrap_or(settings.buffer_font_size(cx));
542// let font_family_name = terminal_settings
543// .font_family
544// .as_ref()
545// .unwrap_or(&settings.buffer_font_family_name);
546// let font_features = terminal_settings
547// .font_features
548// .as_ref()
549// .unwrap_or(&settings.buffer_font_features);
550// let family_id = text_system
551// .load_family(&[font_family_name], &font_features)
552// .log_err()
553// .unwrap_or(settings.buffer_font_family);
554// let font_id = text_system
555// .select_font(family_id, &Default::default())
556// .unwrap();
557
558// let text_style = TextStyle {
559// color: settings.theme.editor.text_color,
560// font_family_id: family_id,
561// font_family_name: text_system.family_name(family_id).unwrap(),
562// font_id,
563// font_size,
564// font_properties: Default::default(),
565// underline: Default::default(),
566// soft_wrap: false,
567// font_family: todo!(),
568// font_features: todo!(),
569// line_height: todo!(),
570// font_weight: todo!(),
571// font_style: todo!(),
572// background_color: todo!(),
573// white_space: todo!(),
574// };
575// let selection_color = settings.theme.editor.selection.selection;
576// let match_color = settings.theme.search.match_background;
577// let gutter;
578// let dimensions = {
579// let line_height = text_style.font_size * terminal_settings.line_height.value();
580// let cell_width = text_system.em_advance(text_style.font_id, text_style.font_size);
581// gutter = cell_width;
582
583// let size = constraint.max - point(gutter, 0.);
584// TerminalSize::new(line_height, cell_width, size)
585// };
586
587// let search_matches = if let Some(terminal_model) = self.terminal.upgrade() {
588// terminal_model.read(cx).matches.clone()
589// } else {
590// Default::default()
591// };
592
593// let background_color = terminal_theme.background;
594// let terminal_handle = self.terminal.upgrade().unwrap();
595
596// let last_hovered_word = terminal_handle.update(cx, |terminal, cx| {
597// terminal.set_size(dimensions);
598// terminal.try_sync(cx);
599// if self.can_navigate_to_selected_word && terminal.can_navigate_to_selected_word() {
600// terminal.last_content.last_hovered_word.clone()
601// } else {
602// None
603// }
604// });
605
606// let hyperlink_tooltip = last_hovered_word.clone().map(|hovered_word| {
607// let mut tooltip = Overlay::new(
608// Empty::new()
609// .contained()
610// .constrained()
611// .with_width(dimensions.width())
612// .with_height(dimensions.height())
613// .with_tooltip::<TerminalElement>(
614// hovered_word.id,
615// hovered_word.word,
616// None,
617// tooltip_style,
618// cx,
619// ),
620// )
621// .with_position_mode(gpui::OverlayPositionMode::Local)
622// .into_any();
623
624// tooltip.layout(
625// SizeConstraint::new(Point::zero(), cx.window_size()),
626// view_state,
627// cx,
628// );
629// tooltip
630// });
631
632// let TerminalContent {
633// cells,
634// mode,
635// display_offset,
636// cursor_char,
637// selection,
638// cursor,
639// ..
640// } = { &terminal_handle.read(cx).last_content };
641
642// // searches, highlights to a single range representations
643// let mut relative_highlighted_ranges = Vec::new();
644// for search_match in search_matches {
645// relative_highlighted_ranges.push((search_match, match_color))
646// }
647// if let Some(selection) = selection {
648// relative_highlighted_ranges.push((selection.start..=selection.end, selection_color));
649// }
650
651// // then have that representation be converted to the appropriate highlight data structure
652
653// let (cells, rects) = TerminalElement::layout_grid(
654// cells,
655// &text_style,
656// &terminal_theme,
657// &cx.text_system(),
658// last_hovered_word
659// .as_ref()
660// .map(|last_hovered_word| (link_style, &last_hovered_word.word_match)),
661// cx,
662// );
663
664// //Layout cursor. Rectangle is used for IME, so we should lay it out even
665// //if we don't end up showing it.
666// let cursor = if let AlacCursorShape::Hidden = cursor.shape {
667// None
668// } else {
669// let cursor_point = DisplayCursor::from(cursor.point, *display_offset);
670// let cursor_text = {
671// let str_trxt = cursor_char.to_string();
672
673// let color = if self.focused {
674// terminal_theme.background
675// } else {
676// terminal_theme.foreground
677// };
678
679// cx.text_system().layout_line(
680// &str_trxt,
681// text_style.font_size,
682// &[(
683// str_trxt.len(),
684// TextRun {
685// font_id: text_style.font_id,
686// color,
687// underline: Default::default(),
688// },
689// )],
690// )?
691// };
692
693// let focused = self.focused;
694// TerminalElement::shape_cursor(cursor_point, dimensions, &cursor_text).map(
695// move |(cursor_position, block_width)| {
696// let (shape, text) = match cursor.shape {
697// AlacCursorShape::Block if !focused => (CursorShape::Hollow, None),
698// AlacCursorShape::Block => (CursorShape::Block, Some(cursor_text)),
699// AlacCursorShape::Underline => (CursorShape::Underscore, None),
700// AlacCursorShape::Beam => (CursorShape::Bar, None),
701// AlacCursorShape::HollowBlock => (CursorShape::Hollow, None),
702// //This case is handled in the if wrapping the whole cursor layout
703// AlacCursorShape::Hidden => unreachable!(),
704// };
705
706// Cursor::new(
707// cursor_position,
708// block_width,
709// dimensions.line_height,
710// terminal_theme.cursor,
711// shape,
712// text,
713// )
714// },
715// )
716// };
717
718// //Done!
719// (
720// constraint.max,
721// Self::State {
722// cells,
723// cursor,
724// background_color,
725// size: dimensions,
726// rects,
727// relative_highlighted_ranges,
728// mode: *mode,
729// display_offset: *display_offset,
730// hyperlink_tooltip,
731// gutter,
732// },
733// )
734// }
735
736// fn paint(
737// self,
738// bounds: Bounds<Pixels>,
739// element_state: &mut Self::State,
740// cx: &mut WindowContext<'_>,
741// ) {
742// // todo!()
743// // let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
744
745// // //Setup element stuff
746// // let clip_bounds = Some(visible_bounds);
747
748// // cx.paint_layer(clip_bounds, |cx| {
749// // let origin = bounds.origin + point(element_state.gutter, 0.);
750
751// // // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
752// // self.attach_mouse_handlers(origin, visible_bounds, element_state.mode, cx);
753
754// // cx.scene().push_cursor_region(gpui::CursorRegion {
755// // bounds,
756// // style: if element_state.hyperlink_tooltip.is_some() {
757// // CursorStyle::AlacPointingHand
758// // } else {
759// // CursorStyle::IBeam
760// // },
761// // });
762
763// // cx.paint_layer(clip_bounds, |cx| {
764// // //Start with a background color
765// // cx.scene().push_quad(Quad {
766// // bounds,
767// // background: Some(element_state.background_color),
768// // border: Default::default(),
769// // corner_radii: Default::default(),
770// // });
771
772// // for rect in &element_state.rects {
773// // rect.paint(origin, element_state, view_state, cx);
774// // }
775// // });
776
777// // //Draw Highlighted Backgrounds
778// // cx.paint_layer(clip_bounds, |cx| {
779// // for (relative_highlighted_range, color) in
780// // element_state.relative_highlighted_ranges.iter()
781// // {
782// // if let Some((start_y, highlighted_range_lines)) = to_highlighted_range_lines(
783// // relative_highlighted_range,
784// // element_state,
785// // origin,
786// // ) {
787// // let hr = HighlightedRange {
788// // start_y, //Need to change this
789// // line_height: element_state.size.line_height,
790// // lines: highlighted_range_lines,
791// // color: color.clone(),
792// // //Copied from editor. TODO: move to theme or something
793// // corner_radius: 0.15 * element_state.size.line_height,
794// // };
795// // hr.paint(bounds, cx);
796// // }
797// // }
798// // });
799
800// // //Draw the text cells
801// // cx.paint_layer(clip_bounds, |cx| {
802// // for cell in &element_state.cells {
803// // cell.paint(origin, element_state, visible_bounds, view_state, cx);
804// // }
805// // });
806
807// // //Draw cursor
808// // if self.cursor_visible {
809// // if let Some(cursor) = &element_state.cursor {
810// // cx.paint_layer(clip_bounds, |cx| {
811// // cursor.paint(origin, cx);
812// // })
813// // }
814// // }
815
816// // if let Some(element) = &mut element_state.hyperlink_tooltip {
817// // element.paint(origin, visible_bounds, view_state, cx)
818// // }
819// // });
820// }
821
822// // todo!() remove?
823// // fn metadata(&self) -> Option<&dyn std::any::Any> {
824// // None
825// // }
826
827// // fn debug(
828// // &self,
829// // _: Bounds<Pixels>,
830// // _: &Self::State,
831// // _: &Self::PaintState,
832// // _: &TerminalView,
833// // _: &gpui::ViewContext<TerminalView>,
834// // ) -> gpui::serde_json::Value {
835// // json!({
836// // "type": "TerminalElement",
837// // })
838// // }
839
840// // fn rect_for_text_range(
841// // &self,
842// // _: Range<usize>,
843// // bounds: Bounds<Pixels>,
844// // _: Bounds<Pixels>,
845// // layout: &Self::State,
846// // _: &Self::PaintState,
847// // _: &TerminalView,
848// // _: &gpui::ViewContext<TerminalView>,
849// // ) -> Option<Bounds<Pixels>> {
850// // // Use the same origin that's passed to `Cursor::paint` in the paint
851// // // method bove.
852// // let mut origin = bounds.origin() + point(layout.size.cell_width, 0.);
853
854// // // TODO - Why is it necessary to move downward one line to get correct
855// // // positioning? I would think that we'd want the same rect that is
856// // // painted for the cursor.
857// // origin += point(0., layout.size.line_height);
858
859// // Some(layout.cursor.as_ref()?.bounding_rect(origin))
860// // }
861// }
862
863// impl IntoElement for TerminalElement {
864// type Element = Self;
865
866// fn element_id(&self) -> Option<ElementId> {
867// todo!()
868// }
869
870// fn into_element(self) -> Self::Element {
871// self
872// }
873// }
874
875// fn is_blank(cell: &IndexedCell) -> bool {
876// if cell.c != ' ' {
877// return false;
878// }
879
880// if cell.bg != AnsiColor::Named(NamedColor::Background) {
881// return false;
882// }
883
884// if cell.hyperlink().is_some() {
885// return false;
886// }
887
888// if cell
889// .flags
890// .intersects(Flags::ALL_UNDERLINES | Flags::INVERSE | Flags::STRIKEOUT)
891// {
892// return false;
893// }
894
895// return true;
896// }
897
898// fn to_highlighted_range_lines(
899// range: &RangeInclusive<AlacPoint>,
900// layout: &LayoutState,
901// origin: Point<Pixels>,
902// ) -> Option<(Pixels, Vec<HighlightedRangeLine>)> {
903// // Step 1. Normalize the points to be viewport relative.
904// // When display_offset = 1, here's how the grid is arranged:
905// //-2,0 -2,1...
906// //--- Viewport top
907// //-1,0 -1,1...
908// //--------- Terminal Top
909// // 0,0 0,1...
910// // 1,0 1,1...
911// //--- Viewport Bottom
912// // 2,0 2,1...
913// //--------- Terminal Bottom
914
915// // Normalize to viewport relative, from terminal relative.
916// // lines are i32s, which are negative above the top left corner of the terminal
917// // If the user has scrolled, we use the display_offset to tell us which offset
918// // of the grid data we should be looking at. But for the rendering step, we don't
919// // want negatives. We want things relative to the 'viewport' (the area of the grid
920// // which is currently shown according to the display offset)
921// let unclamped_start = AlacPoint::new(
922// range.start().line + layout.display_offset,
923// range.start().column,
924// );
925// let unclamped_end =
926// AlacPoint::new(range.end().line + layout.display_offset, range.end().column);
927
928// // Step 2. Clamp range to viewport, and return None if it doesn't overlap
929// if unclamped_end.line.0 < 0 || unclamped_start.line.0 > layout.size.num_lines() as i32 {
930// return None;
931// }
932
933// let clamped_start_line = unclamped_start.line.0.max(0) as usize;
934// let clamped_end_line = unclamped_end.line.0.min(layout.size.num_lines() as i32) as usize;
935// //Convert the start of the range to pixels
936// let start_y = origin.y + clamped_start_line as f32 * layout.size.line_height;
937
938// // Step 3. Expand ranges that cross lines into a collection of single-line ranges.
939// // (also convert to pixels)
940// let mut highlighted_range_lines = Vec::new();
941// for line in clamped_start_line..=clamped_end_line {
942// let mut line_start = 0;
943// let mut line_end = layout.size.columns();
944
945// if line == clamped_start_line {
946// line_start = unclamped_start.column.0 as usize;
947// }
948// if line == clamped_end_line {
949// line_end = unclamped_end.column.0 as usize + 1; //+1 for inclusive
950// }
951
952// highlighted_range_lines.push(HighlightedRangeLine {
953// start_x: origin.x + line_start as f32 * layout.size.cell_width,
954// end_x: origin.x + line_end as f32 * layout.size.cell_width,
955// });
956// }
957
958// Some((start_y, highlighted_range_lines))
959// }
960
961// fn font_size(terminal_settings: &TerminalSettings, cx: &mut AppContext) -> Option<Pixels> {
962// terminal_settings
963// .font_size
964// .map(|size| theme::adjusted_font_size(size, cx))
965// }
966
967// // mappings::colors::convert_color
968// fn convert_color(fg: &terminal::alacritty_terminal::ansi::Color, style: &TerminalStyle) -> Hsla {
969// todo!()
970// }