Files
gpui-native-kit/crates/editor/src/utils.rs
T
2026-11-10 15:06:16 +07:00

137 lines
4.2 KiB
Rust

//! 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<Language> {
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<E>(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<usize>, 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)
}