From 3db0987b4008ff14cacd1ecd9ee3fbfb1e727f17 Mon Sep 17 00:00:00 2001 From: Jacob Anderson Date: Thu, 26 Jun 2025 12:04:10 +0800 Subject: [PATCH 1/2] Add 256 color support for apple terminal --- src/bin/edit/main.rs | 18 +++++++++++++++++ src/framebuffer.rs | 47 +++++++++++++++++++++++++++++++++++++++++++- src/tui.rs | 7 ++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/bin/edit/main.rs b/src/bin/edit/main.rs index dabef35847a5..9edce76e6e46 100644 --- a/src/bin/edit/main.rs +++ b/src/bin/edit/main.rs @@ -629,6 +629,24 @@ fn setup_terminal(tui: &mut Tui, state: &mut State, vt_parser: &mut vt::Parser) tui.setup_indexed_colors(indexed_colors); } + // Detects if edit is running on an "old" version of terminal.app on Mac OS. If it detects + // the terminal.app is older than version 460, which added truecolor support, + // is_old_macos_terminal gets set to true, and sets ColorMode to Color256. + let is_old_macos_terminal = { + if env::var("TERM_PROGRAM").as_deref() == Ok("Apple_Terminal") { + env::var("TERM_PROGRAM_VERSION") + .ok() + .and_then(|s| s.split('.').next()?.parse::().ok()) + .map_or(false, |v| v < 460) + } else { + false + } + }; + + if is_old_macos_terminal { + tui.setup_color_mode(framebuffer::ColorMode::Color256); + } + RestoreModes } diff --git a/src/framebuffer.rs b/src/framebuffer.rs index b86d4808148d..8a6917c5e68d 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -53,6 +53,14 @@ pub enum IndexedColor { Foreground, } +/// Color modes used in format_color function +#[derive(Clone, Copy, Default)] +pub enum ColorMode { + #[default] + TrueColor, + Color256, +} + /// Number of indices used by [`IndexedColor`]. pub const INDEXED_COLORS_COUNT: usize = 18; @@ -105,6 +113,8 @@ pub struct Framebuffer { contrast_colors: [Cell<(u32, u32)>; CACHE_TABLE_SIZE], background_fill: u32, foreground_fill: u32, + // The color mode, either truecolor(default) or color256 + color_mode: ColorMode, } impl Framebuffer { @@ -121,6 +131,7 @@ impl Framebuffer { contrast_colors: [const { Cell::new((0, 0)) }; CACHE_TABLE_SIZE], background_fill: DEFAULT_THEME[IndexedColor::Background as usize], foreground_fill: DEFAULT_THEME[IndexedColor::Foreground as usize], + color_mode: ColorMode::default(), } } @@ -537,6 +548,12 @@ impl Framebuffer { result } + // Sets the color rendering mode, either truecolor(default) or color256, determined by the + // setup_terminal function in main.rs + pub fn set_color_mode(&mut self, mode: ColorMode) { + self.color_mode = mode; + } + fn format_color(&self, dst: &mut ArenaString, fg: bool, mut color: u32) { let typ = if fg { '3' } else { '4' }; @@ -567,7 +584,35 @@ impl Framebuffer { let r = color & 0xff; let g = (color >> 8) & 0xff; let b = (color >> 16) & 0xff; - _ = write!(dst, "\x1b[{typ}8;2;{r};{g};{b}m"); + + // If the terminal doesn't support truecolor, the rgb channel needs to be + // downsampled to display properly. + match self.color_mode { + ColorMode::TrueColor => { + _ = write!(dst, "\x1b[{typ}8;2;{r};{g};{b}m"); + } + ColorMode::Color256 => { + let index: u8 = if r == g && g == b { + // grayscale path + if r < 8 { + 16 + } else if r > 248 { + 231 + } else { + let gray_index = ((r - 8 + 5) / 10).min(23); + 232 + gray_index + } + } else { + // Color path + let r_idx = (r * 6 / 256) as u32; + let g_idx = (g * 6 / 256) as u32; + let b_idx = (b * 6 / 256) as u32; + (16 + 36 * r_idx + 6 * g_idx + b_idx) as u32 + } as u8; + + _ = write!(dst, "\x1b[{typ}8;5;{index}m"); + } + } } } diff --git a/src/tui.rs b/src/tui.rs index 48cc094ea44c..6044c713ab42 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -154,7 +154,7 @@ use crate::buffer::{CursorMovement, MoveLineDirection, RcTextBuffer, TextBuffer, use crate::cell::*; use crate::clipboard::Clipboard; use crate::document::WriteableDocument; -use crate::framebuffer::{Attributes, Framebuffer, INDEXED_COLORS_COUNT, IndexedColor}; +use crate::framebuffer::{Attributes, Framebuffer, INDEXED_COLORS_COUNT, IndexedColor, ColorMode}; use crate::hash::*; use crate::helpers::*; use crate::input::{InputKeyMod, kbmod, vk}; @@ -429,6 +429,11 @@ impl Tui { self.framebuffer.set_indexed_colors(colors); } + /// Sets the color rendering mode based on terminal capabilities. + pub fn setup_color_mode(&mut self, mode: ColorMode) { + self.framebuffer.set_color_mode(mode); + } + /// Set up translations for Ctrl/Alt/Shift modifiers. pub fn setup_modifier_translations(&mut self, translations: ModifierTranslations) { self.modifier_translations = translations; From e48c9cdf37bc857bd9e50c8358a18553751aa1f2 Mon Sep 17 00:00:00 2001 From: Jacob Anderson Date: Thu, 26 Jun 2025 14:05:30 +0800 Subject: [PATCH 2/2] forgot to run rustfmt --- src/tui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tui.rs b/src/tui.rs index 6044c713ab42..ba03ed058e27 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -154,7 +154,7 @@ use crate::buffer::{CursorMovement, MoveLineDirection, RcTextBuffer, TextBuffer, use crate::cell::*; use crate::clipboard::Clipboard; use crate::document::WriteableDocument; -use crate::framebuffer::{Attributes, Framebuffer, INDEXED_COLORS_COUNT, IndexedColor, ColorMode}; +use crate::framebuffer::{Attributes, ColorMode, Framebuffer, INDEXED_COLORS_COUNT, IndexedColor}; use crate::hash::*; use crate::helpers::*; use crate::input::{InputKeyMod, kbmod, vk};