Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
@@ -0,0 +1,94 @@
//! This module defines CellGlyphCache, a struct which manages the caching of glyph values for cells
//! when rendering Grids within Warp.
use warpui::elements::DEFAULT_LINE_HEIGHT_RATIO;
use warpui::fonts::{Cache as FontCache, FamilyId, FontId, GlyphId, Properties};
use warpui::platform::LineStyle;
use warpui::text_layout::{StyleAndFont, DEFAULT_TOP_BOTTOM_RATIO};
use warpui::PaintContext;
use std::collections::HashMap;
/// Stores cached glyph values for characters/strings. Note that we normally only need to look up
/// characters - we only look up strings in the case of zerowidth characters (which act as modifiers
/// to the first character e.g. emoji variant selectors). We have 2 separate caches internally for
/// performance reasons (avoid allocating strings when we don't need to!).
#[derive(Default)]
pub struct CellGlyphCache {
glyph_cache: HashMap<(char, FontId), Option<(GlyphId, FontId)>>,
string_cache: HashMap<(String, FontId), Option<(GlyphId, FontId)>>,
}
impl CellGlyphCache {
pub(super) fn glyph_for_char(
&mut self,
char: char,
font_id: FontId,
font_cache: &FontCache,
) -> Option<(GlyphId, FontId)> {
*self
.glyph_cache
.entry((char, font_id))
.or_insert_with(|| font_cache.glyph_for_char(font_id, char, true))
}
#[allow(clippy::too_many_arguments)]
pub(super) fn glyph_for_string(
&mut self,
string: &str,
font_id: FontId,
font_cache: &FontCache,
font_family: FamilyId,
font_size: f32,
properties: Properties,
ctx: &mut PaintContext,
) -> Option<(GlyphId, FontId)> {
let glyph = *self
.string_cache
.entry((string.to_owned(), font_id))
.or_insert_with(|| {
// Calculate the length of total characters in the string.
let run_length_chars = string.chars().count();
let line = ctx.text_layout_cache.layout_line(
string,
LineStyle {
font_size,
// Note that we DO NOT paint the `Line` in this particular instance. As such,
// the line height ratio and baseline ratio are both NOT used. Hence, we arbitrarily
// set them to the default values.
line_height_ratio: DEFAULT_LINE_HEIGHT_RATIO,
baseline_ratio: DEFAULT_TOP_BOTTOM_RATIO,
fixed_width_tab_size: None,
},
&[(
(0..run_length_chars),
StyleAndFont {
font_family,
properties,
style: Default::default(),
},
)],
f32::MAX,
Default::default(),
&font_cache.text_layout_system(),
);
let run = line.runs.first()?;
if run.glyphs.len() > 1 {
// If we have more than one glyph, something has gone wrong.
return None;
}
run.glyphs.first().map(|glyph| (glyph.id, run.font_id))
});
glyph.or_else(|| {
#[cfg(debug_assertions)]
log::warn!("Falling back to glyph for first character of string, could not get glyph for entire string: {string:?}");
let first_char = string.chars().next()?;
let glyph = self.glyph_for_char(first_char, font_id, font_cache);
// Make sure we update the cache with the fallback, so we don't
// recompute it again.
self.string_cache.insert((string.to_owned(), font_id), glyph);
glyph
})
}
}
+216
View File
@@ -0,0 +1,216 @@
use pathfinder_color::ColorU;
use crate::{
terminal::{
color,
model::{
ansi::{color_index, Color, NamedColor},
cell::{Cell, Flags},
ObfuscateSecrets,
},
},
util::color::OPAQUE,
};
use super::{BLOCK_FILTER_MATCH_COLOR, FOCUSED_MATCH_COLOR, MATCH_COLOR, URL_COLOR};
#[derive(PartialEq)]
pub(super) struct Secret {
pub(super) hovered: bool,
pub(super) is_obfuscated: bool,
}
/// Determines whether a match is focused.
#[derive(PartialEq, Clone, Copy)]
pub(super) enum IsFocused {
Yes,
No,
}
#[derive(Default, PartialEq)]
pub(super) struct CellType {
pub(super) is_find_match: Option<IsFocused>,
pub(super) is_url: bool,
pub(super) secret: Option<Secret>,
pub(super) is_filter_match: bool,
pub(super) is_marked_text_char: bool,
}
impl CellType {
pub(super) fn marked_text_char() -> Self {
Self {
is_marked_text_char: true,
..Default::default()
}
}
pub(super) fn is_find_match(&self) -> bool {
self.is_find_match.is_some()
}
pub(super) fn is_focused_find_match(&self) -> bool {
self.is_find_match
.map_or_else(|| false, |is_focused| matches!(is_focused, IsFocused::Yes))
}
pub(super) fn is_unfocused_find_match(&self) -> bool {
self.is_find_match
.map_or_else(|| false, |is_focused| matches!(is_focused, IsFocused::No))
}
pub(super) fn is_filter_match(&self) -> bool {
self.is_filter_match
}
pub(super) fn is_url(&self) -> bool {
self.is_url
}
pub(super) fn is_secret(&self) -> bool {
self.secret.is_some()
}
pub(super) fn is_hovered_secret(&self) -> bool {
self.secret
.as_ref()
.map_or_else(|| false, |secret| secret.hovered)
}
pub(super) fn is_unhovered_secret(&self) -> bool {
self.secret
.as_ref()
.map_or_else(|| false, |secret| !secret.hovered)
}
/// Used to check if a CellType is equivalent to the default (i.e. no matches, urls, secrets, etc).
pub(super) fn is_default(&self) -> bool {
&Self::default() == self
}
pub(super) fn is_marked_text_char(&self) -> bool {
self.is_marked_text_char
}
/// Calculate the foreground color for a cell. Does not set alpha value.
pub(super) fn foreground_color(
&self,
cell: &Cell,
colors: &color::List,
override_colors: &color::OverrideList,
obfuscate_mode: ObfuscateSecrets,
) -> ColorU {
let is_unhovered_secret = self.is_unhovered_secret();
if self.is_filter_match() {
*BLOCK_FILTER_MATCH_COLOR
} else if self.is_url() || self.is_hovered_secret() {
*URL_COLOR
} else if matches!(obfuscate_mode, ObfuscateSecrets::Strikethrough) && is_unhovered_secret {
warpui::color::ColorU::new(128, 128, 128, 255)
} else if self.is_default()
|| self.is_marked_text_char()
|| is_unhovered_secret
|| matches!(obfuscate_mode, ObfuscateSecrets::AlwaysShow)
{
compute_fg_rgb(colors, override_colors, cell.fg, cell.flags)
} else {
ColorU::black()
}
}
/// Calculate the background color (including the alpha) for a cell.
pub(super) fn background_color(
&self,
cell: &Cell,
colors: &color::List,
override_colors: &color::OverrideList,
) -> ColorU {
let mut bg_color =
if self.is_unfocused_find_match() && !self.is_hovered_secret() && !self.is_url() {
*MATCH_COLOR
} else if self.is_focused_find_match() && !self.is_hovered_secret() && !self.is_url() {
*FOCUSED_MATCH_COLOR
} else {
compute_bg_rgb(colors, override_colors, cell.bg)
};
let bg_alpha = if cell.flags.contains(Flags::INVERSE) {
OPAQUE
} else if self.is_default()
|| self.is_url()
|| (self.is_filter_match() && !self.is_find_match())
|| (self.is_secret() && !self.is_find_match())
|| self.is_hovered_secret()
{
if cell.bg == Color::Named(NamedColor::Background) {
// If the background of the cell is the same as the terminal background, treat it as
// an alpha value of 0.
0
} else {
OPAQUE
}
} else {
OPAQUE
};
bg_color.a = bg_alpha;
bg_color
}
}
/// Get the RGB color from a cell's foreground color.
fn compute_fg_rgb(
colors: &color::List,
override_colors: &color::OverrideList,
fg: Color,
flags: Flags,
) -> ColorU {
match fg {
Color::Spec(rgb) => match flags & Flags::DIM {
Flags::DIM => crate::terminal::color::dim(rgb),
_ => rgb,
},
Color::Named(ansi) => {
match flags & Flags::DIM_BOLD {
// If no bright foreground is set, treat it like the BOLD flag doesn't exist.
Flags::DIM_BOLD if ansi == NamedColor::Foreground => {
get_override_color(colors, override_colors, color_index::DIM_FOREGROUND)
}
// Cell is marked as dim and not bold.
Flags::DIM => {
get_override_color(colors, override_colors, ansi.to_dim().into_color_index())
}
// None of the above, keep original color..
_ => get_override_color(colors, override_colors, ansi.into_color_index()),
}
}
Color::Indexed(idx) => {
let idx = match (flags & Flags::DIM_BOLD, idx) {
(Flags::DIM, 8..=15) => idx as usize - 8,
(Flags::DIM, 0..=7) => color_index::DIM_BLACK + idx as usize,
_ => idx as usize,
};
get_override_color(colors, override_colors, idx)
}
}
}
/// Get the RGB color from a cell's background color.
fn compute_bg_rgb(
colors: &color::List,
override_colors: &color::OverrideList,
bg: Color,
) -> ColorU {
match bg {
Color::Spec(rgb) => rgb,
Color::Named(ansi) => get_override_color(colors, override_colors, ansi.into_color_index()),
Color::Indexed(idx) => get_override_color(colors, override_colors, idx as usize),
}
}
pub fn get_override_color(
colors: &color::List,
override_colors: &color::OverrideList,
index: usize,
) -> ColorU {
override_colors[index].unwrap_or(colors[index])
}