diff --git a/src/graphics.rs b/src/graphics.rs index 14acecf..331b257 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -131,7 +131,7 @@ impl Canvas { } } -#[derive(Clone, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct GlyphInfo { c: char, fg: u32, @@ -141,24 +141,22 @@ pub struct GlyphInfo { pub struct GlyphCache { renderer: BitmapGlyphRenderer, - colors: Colors, glyphs: HashMap>, } impl GlyphCache { - pub fn new(colors: Colors, font_config: &FontConfig) -> Self { + pub fn new(font_config: &FontConfig) -> Self { Self { renderer: BitmapGlyphRenderer::new(font_config), - colors, glyphs: Default::default(), } } - pub fn cell_info(&self, cell: &Cell) -> GlyphInfo { + pub fn cell_info(&self, graphics: &Graphics, cell: &Cell) -> GlyphInfo { GlyphInfo { c: cell.c, - fg: self.color_to_u32(&cell.fg), - bg: self.color_to_u32(&cell.bg), + fg: graphics.color_to_u32(&cell.fg), + bg: graphics.color_to_u32(&cell.bg), flags: cell.flags, } } @@ -168,21 +166,6 @@ impl GlyphCache { .entry(glyph.clone()) .or_insert_with(|| self.renderer.draw(glyph).into_boxed_slice()) } - - // TODO deduplicate - pub fn color_to_u32(&self, color: &Color) -> u32 { - let rgb = match color { - Color::Named(name) => self.colors[*name].unwrap(), - Color::Spec(rgb) => *rgb, - Color::Indexed(index) => self.colors[*index as usize].unwrap_or(Rgb { - r: 255, - g: 0, - b: 255, - }), - }; - - ((rgb.r as u32) << 16) | ((rgb.g as u32) << 8) | (rgb.b as u32) - } } pub struct BitmapGlyphRenderer { @@ -213,6 +196,8 @@ impl BitmapGlyphRenderer { } pub fn draw(&self, glyph: &GlyphInfo) -> Vec { + // eprintln!("rendering glyph: {:?}", glyph); + let mut buf = Vec::with_capacity(self.cell_width * self.cell_height); let font = if glyph.flags.contains(CellFlags::BOLD) { @@ -246,6 +231,7 @@ impl BitmapGlyphRenderer { } } } else { + eprintln!("character bitmap miss: {:?}", glyph.c); buf.resize(buf.capacity(), 0x00ff00ff); } @@ -275,7 +261,7 @@ impl Graphics { let bg = ((bg.r as u32) << 16) | ((bg.g as u32) << 8) | (bg.b as u32); let canvas = Canvas::new(bg, 2000, 2000); - let glyph_cache = GlyphCache::new(colors.clone(), &config.fonts); + let glyph_cache = GlyphCache::new(&config.fonts); let cell_cache = Default::default(); Self { @@ -295,14 +281,16 @@ impl Graphics { pub fn load_colors(config: &ColorConfig, colors: &mut Colors) { use NamedColor::*; - let mut set = |color: NamedColor, value: hex_color::HexColor| { - let rgb = Rgb { + let rgb = |value: hex_color::HexColor| { + Some(Rgb { r: value.r, g: value.g, b: value.b, - }; + }) + }; - colors[color] = Some(rgb); + let mut set = |color: NamedColor, value: hex_color::HexColor| { + colors[color] = rgb(value); }; set(Background, config.background); @@ -323,19 +311,69 @@ impl Graphics { set(BrightMagenta, config.bright_magenta); set(BrightCyan, config.bright_cyan); set(BrightWhite, config.bright_white); + + colors[256] = rgb(config.foreground); + colors[257] = rgb(config.background); + } + + pub fn get_color_idx(&self, index: usize) -> Rgb { + if let Some(color) = self.colors[index] { + color + } else if index > 255 { + eprintln!("color miss and out-of-bounds at {index}"); + + Rgb { + r: 0xff, + g: 0x00, + b: 0xff, + } + } else if let Some(gray) = index.checked_sub(232) { + let value = gray as u8 * 10 + 8; + Rgb { + r: value, + g: value, + b: value, + } + } else if let Some(cube_idx) = index.checked_sub(16) { + let cube_idx = cube_idx as u8; + let r = cube_idx / 36; + let g = (cube_idx / 6) % 6; + let b = cube_idx % 6; + + let c = |c| { + if c == 0 { + 0 + } else { + c * 40 + 55 + } + }; + + Rgb { + r: c(r), + g: c(g), + b: c(b), + } + } else { + eprintln!("color index miss at {index}"); + + Rgb { + r: 0xff, + g: 0x00, + b: 0xff, + } + } + } + + pub fn get_color(&self, color: &Color) -> Rgb { + match color { + Color::Named(name) => self.colors[*name].unwrap(), + Color::Spec(rgb) => *rgb, + Color::Indexed(index) => self.get_color_idx(*index as usize), + } } pub fn color_to_u32(&self, color: &Color) -> u32 { - let rgb = match color { - Color::Named(name) => self.colors[*name].unwrap(), - Color::Spec(rgb) => *rgb, - Color::Indexed(index) => self.colors[*index as usize].unwrap_or(Rgb { - r: 255, - g: 0, - b: 255, - }), - }; - + let rgb = self.get_color(color); ((rgb.r as u32) << 16) | ((rgb.g as u32) << 8) | (rgb.b as u32) } @@ -380,7 +418,7 @@ impl Graphics { continue; } - let glyph_info = self.glyph_cache.cell_info(&cell); + let glyph_info = self.glyph_cache.cell_info(self, &cell); if self.cell_cache.get(&term_coords) == Some(&glyph_info) { continue; diff --git a/src/main.rs b/src/main.rs index 0573e8e..d49e892 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ // Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later +use alacritty_terminal::ansi::Color; use alacritty_terminal::config::PtyConfig; use alacritty_terminal::event::{Event as TermEvent, EventListener}; use alacritty_terminal::event_loop::{ @@ -47,10 +48,11 @@ fn get_login_shell(config: Config) -> String { config.system.shell } else { match std::env::consts::OS { - "linux" | "openbsd" | "netbsd" | "dragonfly" | "solaris" | "macos" => - std::env::var("SHELL").unwrap_or("/bin/sh".to_string()), + "linux" | "openbsd" | "netbsd" | "dragonfly" | "solaris" | "macos" => { + std::env::var("SHELL").unwrap_or("/bin/sh".to_string()) + } "windows" => r#"C:\Windows\System32\cmd.exe"#.to_string(), - _ => unimplemented!("Unrecognized operating system; cannot get user's shell") + _ => unimplemented!("Unrecognized operating system; cannot get user's shell"), } } } @@ -83,7 +85,9 @@ impl App { let term_config = alacritty_terminal::config::Config { pty_config: PtyConfig { - shell: Some(alacritty_terminal::config::Program::Just(get_login_shell(config))), + shell: Some(alacritty_terminal::config::Program::Just(get_login_shell( + config, + ))), working_directory: None, hold: false, }, @@ -123,22 +127,17 @@ impl App { while let Ok(event) = self.term_events.try_recv() { match event { TermEvent::ColorRequest(index, format) => { - let color = self.graphics.colors[index].unwrap_or(Rgb { - r: 255, - g: 0, - b: 255, - }); - - self.send_input(&format(color)); + let rgb = self.graphics.get_color_idx(index); + self.send_input(&format(rgb)); } TermEvent::PtyWrite(text) => self.send_input(&text), TermEvent::Wakeup => self.request_redraw(), TermEvent::Exit => self.should_quit = true, - _ => {} + event => eprintln!("unhandled event: {:#?}", event), } } } - + pub fn request_redraw(&self) { self.graphics_context.window().request_redraw(); }