aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-10-23 15:37:06 -0700
committerJoe Wilm <joe@jwilm.com>2016-10-23 15:37:06 -0700
commit5876b4bf7a88a59482aefcc85e04a9ef6ecfed74 (patch)
tree8e55fbf061383569fca610418e02368b05a29fc2 /src
parentea07f03ac901c366ed31da540711b84ca9e75602 (diff)
downloadalacritty-5876b4bf7a88a59482aefcc85e04a9ef6ecfed74.tar.gz
alacritty-5876b4bf7a88a59482aefcc85e04a9ef6ecfed74.zip
Proof of concept live reloading for colors
The architecture here is really poor. Need to move file watching into a dedicated location and probably have an spmc broadcast queue. other modules besides rendering will care about config reloading in the future.
Diffstat (limited to 'src')
-rw-r--r--src/ansi.rs12
-rw-r--r--src/config.rs6
-rw-r--r--src/main.rs17
-rw-r--r--src/renderer/mod.rs139
-rw-r--r--src/term.rs84
5 files changed, 157 insertions, 101 deletions
diff --git a/src/ansi.rs b/src/ansi.rs
index 45cc66f9..c419d7e5 100644
--- a/src/ansi.rs
+++ b/src/ansi.rs
@@ -337,6 +337,10 @@ pub enum Color {
BrightCyan,
/// Bright white
BrightWhite,
+ /// The foreground color
+ Foreground,
+ /// The background color
+ Background,
}
/// Terminal character attributes
@@ -384,10 +388,6 @@ pub enum Attr {
Background(Color),
/// Set specific background color
BackgroundSpec(Rgb),
- /// Set default foreground
- DefaultForeground,
- /// Set default background
- DefaultBackground,
}
impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
@@ -584,7 +584,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
break;
}
},
- 39 => Attr::DefaultForeground,
+ 39 => Attr::Foreground(Color::Foreground),
40 => Attr::Background(Color::Black),
41 => Attr::Background(Color::Red),
42 => Attr::Background(Color::Green),
@@ -600,7 +600,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
break;
}
},
- 49 => Attr::DefaultBackground,
+ 49 => Attr::Background(Color::Background),
90 => Attr::Foreground(Color::BrightBlack),
91 => Attr::Foreground(Color::BrightRed),
92 => Attr::Foreground(Color::BrightGreen),
diff --git a/src/config.rs b/src/config.rs
index 56f96e80..27fcf3ca 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -259,7 +259,7 @@ impl Config {
///
/// The ordering returned here is expected by the terminal. Colors are simply indexed in this
/// array for performance.
- pub fn color_list(&self) -> [Rgb; 16] {
+ pub fn color_list(&self) -> [Rgb; 18] {
let colors = &self.colors;
[
@@ -282,6 +282,10 @@ impl Config {
colors.bright.magenta,
colors.bright.cyan,
colors.bright.white,
+
+ // Foreground and background
+ colors.primary.foreground,
+ colors.primary.background,
]
}
diff --git a/src/main.rs b/src/main.rs
index 9639fd29..9042494d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -112,6 +112,7 @@ pub struct Rgb {
}
mod gl {
+ #![allow(non_upper_case_globals)]
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}
@@ -155,7 +156,7 @@ fn main() {
let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);
// Create renderer
- let mut renderer = QuadRenderer::new(width, height);
+ let mut renderer = QuadRenderer::new(&config, width, height);
// Initialize glyph cache
let glyph_cache = {
@@ -180,7 +181,6 @@ fn main() {
println!("Cell Size: ({} x {})", cell_width, cell_height);
let terminal = Term::new(
- &config,
width as f32,
height as f32,
cell_width as f32,
@@ -295,11 +295,6 @@ impl Display {
// events into one.
let mut new_size = None;
- // TODO should be built into renderer
- unsafe {
- gl::ClearColor(self.clear_red, self.clear_blue, self.clear_green, 1.0);
- gl::Clear(gl::COLOR_BUFFER_BIT);
- }
// Check for any out-of-band resize events (mac only)
while let Ok(sz) = self.rx.try_recv() {
@@ -322,18 +317,16 @@ impl Display {
let size_info = terminal.size_info().clone();
self.renderer.with_api(&size_info, |mut api| {
// Draw the grid
- let bg = terminal.bg;
- api.render_grid(&bg, &terminal.render_grid(), glyph_cache);
+ api.render_grid(&terminal.render_grid(), glyph_cache);
});
}
// Draw render timer
if self.render_timer {
let timing = format!("{:.3} usec", self.meter.average());
- let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
+ let color = ::term::cell::Color::Rgb(Rgb { r: 0xd5, g: 0x4e, b: 0x53 });
self.renderer.with_api(terminal.size_info(), |mut api| {
- let bg = terminal.bg;
- api.render_string(&bg, &timing[..], glyph_cache, &color);
+ api.render_string(&timing[..], glyph_cache, &color);
});
}
}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 7ddf1d01..959b3d4f 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -20,6 +20,7 @@ use std::path::{PathBuf};
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};
+use std::sync::mpsc;
use cgmath;
use font::{self, Rasterizer, RasterizedGlyph, FontDesc, GlyphKey, FontKey};
@@ -42,6 +43,38 @@ pub trait LoadGlyph {
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph;
}
+enum Msg {
+ ConfigReload(Config),
+ ShaderReload,
+}
+
+/// Colors!
+///
+/// FIXME this is obviously bad; need static for reload logic for now. Hacking something in with
+/// minimal effort and will improve later.
+///
+/// Only renderer is allowed to access this to prevent race conditions
+static mut COLORS: [Rgb; 18] = [
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+ Rgb { r: 0, g: 0, b: 0 },
+];
+
/// Text drawing program
///
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
@@ -222,7 +255,6 @@ struct InstanceData {
#[derive(Debug)]
pub struct QuadRenderer {
program: ShaderProgram,
- should_reload: Arc<AtomicBool>,
vao: GLuint,
vbo: GLuint,
ebo: GLuint,
@@ -230,6 +262,7 @@ pub struct QuadRenderer {
atlas: Vec<Atlas>,
active_tex: GLuint,
batch: Batch,
+ rx: mpsc::Receiver<Msg>,
}
#[derive(Debug)]
@@ -272,6 +305,18 @@ impl Batch {
self.tex = glyph.tex_id;
}
+ // TODO move colors list to uniform buffer and do this indexing in vertex shader
+ let fg = match cell.fg {
+ ::term::cell::Color::Rgb(rgb) => rgb,
+ ::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] },
+ };
+
+ // TODO move colors list to uniform buffer and do this indexing in vertex shader
+ let bg = match cell.bg {
+ ::term::cell::Color::Rgb(rgb) => rgb,
+ ::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] },
+ };
+
let mut instance = InstanceData {
col: col,
row: row,
@@ -286,23 +331,23 @@ impl Batch {
uv_width: glyph.uv_width,
uv_height: glyph.uv_height,
- r: cell.fg.r as f32,
- g: cell.fg.g as f32,
- b: cell.fg.b as f32,
+ r: fg.r as f32,
+ g: fg.g as f32,
+ b: fg.b as f32,
- bg_r: cell.bg.r as f32,
- bg_g: cell.bg.g as f32,
- bg_b: cell.bg.b as f32,
+ bg_r: bg.r as f32,
+ bg_g: bg.g as f32,
+ bg_b: bg.b as f32,
};
if cell.flags.contains(cell::INVERSE) {
- instance.r = cell.bg.r as f32;
- instance.g = cell.bg.g as f32;
- instance.b = cell.bg.b as f32;
+ instance.r = bg.r as f32;
+ instance.g = bg.g as f32;
+ instance.b = bg.b as f32;
- instance.bg_r = cell.fg.r as f32;
- instance.bg_g = cell.fg.g as f32;
- instance.bg_b = cell.fg.b as f32;
+ instance.bg_r = fg.r as f32;
+ instance.bg_g = fg.g as f32;
+ instance.bg_b = fg.b as f32;
}
self.instances.push(instance);
@@ -345,7 +390,7 @@ const ATLAS_SIZE: i32 = 1024;
impl QuadRenderer {
// TODO should probably hand this a transform instead of width/height
- pub fn new(width: u32, height: u32) -> QuadRenderer {
+ pub fn new(config: &Config, width: u32, height: u32) -> QuadRenderer {
let program = ShaderProgram::new(width, height).unwrap();
let mut vao: GLuint = 0;
@@ -448,11 +493,14 @@ impl QuadRenderer {
let should_reload = Arc::new(AtomicBool::new(false));
let should_reload2 = should_reload.clone();
+ let (msg_tx, msg_rx) = mpsc::channel();
+
::std::thread::spawn(move || {
- let (tx, rx) = ::std::sync::mpsc::channel();
+ let (tx, rx) = mpsc::channel();
let mut watcher = Watcher::new(tx).unwrap();
watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader");
watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader");
+ watcher.watch("/home/jwilm/.alacritty.yml").expect("watch alacritty yml");
loop {
let event = rx.recv().expect("watcher event");
@@ -468,10 +516,17 @@ impl QuadRenderer {
if let Err(err) = watcher.watch(path) {
println!("failed to establish watch on {:?}: {:?}", path, err);
}
- }
- // This is last event we see after saving in vim
- should_reload2.store(true, Ordering::Relaxed);
+ if path == ::std::path::Path::new("/home/jwilm/.alacritty.yml") {
+ if let Ok(config) = Config::load() {
+ msg_tx.send(Msg::ConfigReload(config))
+ .expect("msg send ok");
+ };
+ } else {
+ msg_tx.send(Msg::ShaderReload)
+ .expect("msg send ok");
+ }
+ }
}
}
}
@@ -479,7 +534,6 @@ impl QuadRenderer {
let mut renderer = QuadRenderer {
program: program,
- should_reload: should_reload,
vao: vao,
vbo: vbo,
ebo: ebo,
@@ -487,8 +541,13 @@ impl QuadRenderer {
atlas: Vec::new(),
active_tex: 0,
batch: Batch::new(),
+ rx: msg_rx,
};
+ unsafe {
+ COLORS = config.color_list();
+ }
+
let atlas = Atlas::new(ATLAS_SIZE);
renderer.atlas.push(atlas);
@@ -498,8 +557,17 @@ impl QuadRenderer {
pub fn with_api<F, T>(&mut self, props: &term::SizeInfo, func: F) -> T
where F: FnOnce(RenderApi) -> T
{
- if self.should_reload.load(Ordering::Relaxed) {
- self.reload_shaders(props.width as u32, props.height as u32);
+ while let Ok(msg) = self.rx.try_recv() {
+ match msg {
+ Msg::ConfigReload(config) => {
+ unsafe {
+ COLORS = config.color_list();
+ }
+ },
+ Msg::ShaderReload => {
+ self.reload_shaders(props.width as u32, props.height as u32);
+ }
+ }
}
unsafe {
@@ -544,7 +612,6 @@ impl QuadRenderer {
}
pub fn reload_shaders(&mut self, width: u32, height: u32) {
- self.should_reload.store(false, Ordering::Relaxed);
let program = match ShaderProgram::new(width, height) {
Ok(program) => program,
Err(err) => {
@@ -612,10 +679,9 @@ impl<'a> RenderApi<'a> {
/// optimization.
pub fn render_string(
&mut self,
- bg: &Rgb,
s: &str,
glyph_cache: &mut GlyphCache,
- color: &Rgb,
+ color: &::term::cell::Color,
) {
let row = 40.0;
let mut col = 100.0;
@@ -630,8 +696,8 @@ impl<'a> RenderApi<'a> {
if let Some(glyph) = glyph_cache.get(&glyph_key, self) {
let cell = Cell {
c: c,
- fg: *color,
- bg: *bg,
+ fg: color.clone(),
+ bg: cell::Color::Rgb(Rgb { r: 0, g: 0, b: 0}),
flags: cell::INVERSE,
};
self.add_render_item(row, col, &cell, glyph);
@@ -658,12 +724,27 @@ impl<'a> RenderApi<'a> {
}
}
- pub fn render_grid(&mut self, bg: &Rgb, grid: &Grid<Cell>, glyph_cache: &mut GlyphCache) {
+ pub fn render_grid(
+ &mut self,
+ grid: &Grid<Cell>,
+ glyph_cache: &mut GlyphCache
+ ) {
+ // TODO should be built into renderer
+ let color = unsafe { COLORS[::ansi::Color::Background as usize] };
+ unsafe {
+ gl::ClearColor(
+ color.r as f32 / 255.0,
+ color.g as f32 / 255.0,
+ color.b as f32 / 255.0,
+ 1.0
+ );
+ gl::Clear(gl::COLOR_BUFFER_BIT);
+ }
+
for (i, line) in grid.lines().enumerate() {
for (j, cell) in line.cells().enumerate() {
// Skip empty cells
- if cell.c == ' ' &&
- cell.bg == *bg &&
+ if cell.c == ' ' && cell.bg == cell::Color::Ansi(::ansi::Color::Background) &&
!cell.flags.contains(cell::INVERSE)
{
continue;
diff --git a/src/term.rs b/src/term.rs
index 898251d7..a2b6aa3c 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -21,9 +21,7 @@ use ansi::{self, Attr, Handler};
use grid::{Grid, ClearRegion};
use index::{Cursor, Column, Line};
use tty;
-use config::Config;
-
-use ::Rgb;
+use ansi::Color;
/// RAII type which manages grid state for render
///
@@ -90,20 +88,26 @@ pub mod cell {
}
}
- #[derive(Clone, Debug, Copy)]
+ #[derive(Debug, Clone, PartialEq, Eq)]
+ pub enum Color {
+ Rgb(Rgb),
+ Ansi(::ansi::Color),
+ }
+
+ #[derive(Clone, Debug)]
pub struct Cell {
pub c: char,
- pub fg: Rgb,
- pub bg: Rgb,
+ pub fg: Color,
+ pub bg: Color,
pub flags: Flags,
}
impl Cell {
- pub fn new(c: char) -> Cell {
+ pub fn new(c: char, fg: Color, bg: Color) -> Cell {
Cell {
c: c.into(),
- bg: Default::default(),
- fg: Default::default(),
+ bg: bg,
+ fg: fg,
flags: Flags::empty(),
}
}
@@ -111,13 +115,7 @@ pub mod cell {
#[inline]
pub fn reset(&mut self, template: &Cell) {
// memcpy template to self
- unsafe {
- ::std::ptr::copy_nonoverlapping(
- template as *const Cell,
- self as *mut Cell,
- 1
- );
- }
+ *self = template.clone();
}
}
}
@@ -165,12 +163,6 @@ pub struct Term {
/// Alt cursor
alt_cursor: Cursor,
- /// Active foreground color
- pub fg: Rgb,
-
- /// Active background color
- pub bg: Rgb,
-
/// Tabstops
tabs: Vec<bool>,
@@ -189,9 +181,6 @@ pub struct Term {
/// Empty cell
empty_cell: Cell,
- /// Text colors
- colors: [Rgb; 16],
-
pub dirty: bool,
}
@@ -225,7 +214,6 @@ impl SizeInfo {
impl Term {
pub fn new(
- config: &Config,
width: f32,
height: f32,
cell_width: f32,
@@ -238,20 +226,18 @@ impl Term {
cell_height: cell_height as f32,
};
- let mut template = Cell::new(' ');
- template.flags = cell::Flags::empty();
- template.bg = config.bg_color();
- template.fg = config.fg_color();
+ let template = Cell::new(
+ ' ',
+ cell::Color::Ansi(Color::Foreground),
+ cell::Color::Ansi(Color::Background)
+ );
let num_cols = size.cols();
let num_lines = size.lines();
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
- println!("bg: {:?}, fg: {:?}", template.bg, template.fg);
- println!("colors: {:?}", config.color_list());
-
- let grid = Grid::new(num_lines, num_cols, &Cell::new(' '));
+ let grid = Grid::new(num_lines, num_cols, &template);
let tty = tty::new(*num_lines as u8, *num_cols as u8);
tty.resize(*num_lines as usize, *num_cols as usize, size.width as usize, size.height as usize);
@@ -272,16 +258,13 @@ impl Term {
alt: false,
cursor: Cursor::default(),
alt_cursor: Cursor::default(),
- fg: config.fg_color(),
- bg: config.bg_color(),
tty: tty,
tabs: tabs,
mode: Default::default(),
scroll_region: scroll_region,
size_info: size,
- template_cell: template,
+ template_cell: template.clone(),
empty_cell: template,
- colors: config.color_list(),
}
}
@@ -323,8 +306,9 @@ impl Term {
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
// Resize grids to new size
- self.grid.resize(num_lines, num_cols, &Cell::new(' '));
- self.alt_grid.resize(num_lines, num_cols, &Cell::new(' '));
+ let template = self.template_cell.clone();
+ self.grid.resize(num_lines, num_cols, &template);
+ self.alt_grid.resize(num_lines, num_cols, &template);
// Ensure cursor is in-bounds
self.cursor.line = limit(self.cursor.line, Line(0), num_lines);
@@ -462,7 +446,7 @@ impl ansi::Handler for Term {
}
let cell = &mut self.grid[&self.cursor];
- *cell = self.template_cell;
+ *cell = self.template_cell.clone();
cell.c = c;
self.cursor.col += 1;
}
@@ -779,27 +763,21 @@ impl ansi::Handler for Term {
fn terminal_attribute(&mut self, attr: Attr) {
debug_println!("Set Attribute: {:?}", attr);
match attr {
- Attr::DefaultForeground => {
- self.template_cell.fg = self.fg;
- },
- Attr::DefaultBackground => {
- self.template_cell.bg = self.bg;
- },
Attr::Foreground(named_color) => {
- self.template_cell.fg = self.colors[named_color as usize];
+ self.template_cell.fg = cell::Color::Ansi(named_color);
},
Attr::Background(named_color) => {
- self.template_cell.bg = self.colors[named_color as usize];
+ self.template_cell.bg = cell::Color::Ansi(named_color);
},
Attr::ForegroundSpec(rgb) => {
- self.template_cell.fg = rgb;
+ self.template_cell.fg = cell::Color::Rgb(rgb);
},
Attr::BackgroundSpec(rgb) => {
- self.template_cell.bg = rgb;
+ self.template_cell.bg = cell::Color::Rgb(rgb);
},
Attr::Reset => {
- self.template_cell.fg = self.fg;
- self.template_cell.bg = self.bg;
+ self.template_cell.fg = cell::Color::Ansi(Color::Foreground);
+ self.template_cell.bg = cell::Color::Ansi(Color::Background);
self.template_cell.flags = cell::Flags::empty();
},
Attr::Reverse => self.template_cell.flags.insert(cell::INVERSE),