//! Shared helpers for the editor's views: gutter cells, role colors and run //! styles, code line text, language mapping and change washes. #[cfg(feature = "markdown_view")] use std::ops::Range; #[cfg(feature = "markdown_view")] use crate::highlight::{Language, Line}; #[cfg(feature = "markdown_view")] use gpui::StyledText; #[cfg(feature = "code_view")] use gpui::{App, HighlightStyle, Hsla, IntoElement, ParentElement as _, Styled as _, div}; #[cfg(feature = "code_view")] use gpui_native_theme::{ActiveTheme as _, ColorTokens, Ramps}; #[cfg(feature = "diff_view")] use gpui_native_theme::{WASH_ALPHA, WASH_ALPHA_GUTTER, WASH_ALPHA_STRONG}; #[cfg(feature = "code_view")] use crate::highlight::Role; #[cfg(feature = "code_view")] impl Role { /// Maps the role to the theme's semantic palette. pub(crate) fn color(self, colors: ColorTokens, ramps: Ramps) -> Hsla { match self { Role::Text => colors.foreground, Role::Keyword => ramps.primary.base, Role::String | Role::Escape => ramps.success.base, Role::Comment | Role::Punctuation => colors.muted_foreground, Role::Function | Role::Property => ramps.info.base, Role::Type => ramps.warning.base, Role::Number | Role::Constant => ramps.secondary.base, Role::Operator => colors.foreground, Role::Tag => ramps.destructive.base, } } /// Builds the highlight style for one run of a code view row. pub(crate) fn run_style( self, selected: bool, colors: ColorTokens, ramps: Ramps, ) -> HighlightStyle { HighlightStyle { color: Some(self.color(colors, ramps)), background_color: selected.then_some(colors.selection), ..Default::default() } } } #[cfg(feature = "markdown_view")] impl Language { /// Maps a fence info string to a bundled grammar. pub(crate) fn from_fence_info(info: &str) -> Option { match info.to_ascii_lowercase().as_str() { "rust" | "rs" => Some(Language::Rust), "typescript" | "ts" => Some(Language::TypeScript), "javascript" | "js" => Some(Language::JavaScript), "python" | "py" => Some(Language::Python), _ => None, } } } /// A gutter cell sized to the whole row. #[cfg(feature = "code_view")] pub(crate) fn gutter_cell(cx: &App, color: Hsla, content: E) -> gpui::Div where E: IntoElement, { let theme = cx.theme(); div() .size_10() .flex() .items_center() .justify_center() .flex_none() .font_family(theme.mono_font) .text_size(theme.sizes.small.text_size) .line_height(gpui::relative(1.0)) .text_color(color) .child(content) } /// A change wash: the ramp color at the alpha rows tint with. #[cfg(feature = "diff_view")] pub(crate) fn wash(color: Hsla) -> Hsla { Hsla { a: color.a * WASH_ALPHA, ..color } } /// The stronger wash under number gutters and intra-line word changes. #[cfg(feature = "diff_view")] pub(crate) fn wash_strong(color: Hsla) -> Hsla { Hsla { a: color.a * WASH_ALPHA_STRONG, ..color } } /// The subtle wash that sets the number gutter off from the code. #[cfg(feature = "diff_view")] pub(crate) fn wash_gutter(colors: &ColorTokens) -> Hsla { Hsla { a: colors.muted.a * WASH_ALPHA_GUTTER, ..colors.muted } } /// One highlighted code line as styled text, roles resolved from the theme. #[cfg(feature = "markdown_view")] pub(crate) fn code_line(line: &Line, colors: ColorTokens, ramps: Ramps) -> StyledText { let mut highlights: Vec<(Range, HighlightStyle)> = Vec::new(); let mut offset = 0usize; for span in &line.spans { let end = offset + span.text.len(); if span.role != Role::Text { highlights.push(( offset..end, HighlightStyle { color: Some(span.role.color(colors, ramps)), ..Default::default() }, )); } offset = end; } StyledText::new(line.text()).with_highlights(highlights) }