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.
This commit is contained in:
parent
ea07f03ac9
commit
5876b4bf7a
12
src/ansi.rs
12
src/ansi.rs
|
@ -337,6 +337,10 @@ pub enum Color {
|
||||||
BrightCyan,
|
BrightCyan,
|
||||||
/// Bright white
|
/// Bright white
|
||||||
BrightWhite,
|
BrightWhite,
|
||||||
|
/// The foreground color
|
||||||
|
Foreground,
|
||||||
|
/// The background color
|
||||||
|
Background,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Terminal character attributes
|
/// Terminal character attributes
|
||||||
|
@ -384,10 +388,6 @@ pub enum Attr {
|
||||||
Background(Color),
|
Background(Color),
|
||||||
/// Set specific background color
|
/// Set specific background color
|
||||||
BackgroundSpec(Rgb),
|
BackgroundSpec(Rgb),
|
||||||
/// Set default foreground
|
|
||||||
DefaultForeground,
|
|
||||||
/// Set default background
|
|
||||||
DefaultBackground,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
39 => Attr::DefaultForeground,
|
39 => Attr::Foreground(Color::Foreground),
|
||||||
40 => Attr::Background(Color::Black),
|
40 => Attr::Background(Color::Black),
|
||||||
41 => Attr::Background(Color::Red),
|
41 => Attr::Background(Color::Red),
|
||||||
42 => Attr::Background(Color::Green),
|
42 => Attr::Background(Color::Green),
|
||||||
|
@ -600,7 +600,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
49 => Attr::DefaultBackground,
|
49 => Attr::Background(Color::Background),
|
||||||
90 => Attr::Foreground(Color::BrightBlack),
|
90 => Attr::Foreground(Color::BrightBlack),
|
||||||
91 => Attr::Foreground(Color::BrightRed),
|
91 => Attr::Foreground(Color::BrightRed),
|
||||||
92 => Attr::Foreground(Color::BrightGreen),
|
92 => Attr::Foreground(Color::BrightGreen),
|
||||||
|
|
|
@ -259,7 +259,7 @@ impl Config {
|
||||||
///
|
///
|
||||||
/// The ordering returned here is expected by the terminal. Colors are simply indexed in this
|
/// The ordering returned here is expected by the terminal. Colors are simply indexed in this
|
||||||
/// array for performance.
|
/// array for performance.
|
||||||
pub fn color_list(&self) -> [Rgb; 16] {
|
pub fn color_list(&self) -> [Rgb; 18] {
|
||||||
let colors = &self.colors;
|
let colors = &self.colors;
|
||||||
|
|
||||||
[
|
[
|
||||||
|
@ -282,6 +282,10 @@ impl Config {
|
||||||
colors.bright.magenta,
|
colors.bright.magenta,
|
||||||
colors.bright.cyan,
|
colors.bright.cyan,
|
||||||
colors.bright.white,
|
colors.bright.white,
|
||||||
|
|
||||||
|
// Foreground and background
|
||||||
|
colors.primary.foreground,
|
||||||
|
colors.primary.background,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -112,6 +112,7 @@ pub struct Rgb {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod gl {
|
mod gl {
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
|
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +156,7 @@ fn main() {
|
||||||
let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);
|
let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);
|
||||||
|
|
||||||
// Create renderer
|
// Create renderer
|
||||||
let mut renderer = QuadRenderer::new(width, height);
|
let mut renderer = QuadRenderer::new(&config, width, height);
|
||||||
|
|
||||||
// Initialize glyph cache
|
// Initialize glyph cache
|
||||||
let glyph_cache = {
|
let glyph_cache = {
|
||||||
|
@ -180,7 +181,6 @@ fn main() {
|
||||||
println!("Cell Size: ({} x {})", cell_width, cell_height);
|
println!("Cell Size: ({} x {})", cell_width, cell_height);
|
||||||
|
|
||||||
let terminal = Term::new(
|
let terminal = Term::new(
|
||||||
&config,
|
|
||||||
width as f32,
|
width as f32,
|
||||||
height as f32,
|
height as f32,
|
||||||
cell_width as f32,
|
cell_width as f32,
|
||||||
|
@ -295,11 +295,6 @@ impl Display {
|
||||||
// events into one.
|
// events into one.
|
||||||
let mut new_size = None;
|
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)
|
// Check for any out-of-band resize events (mac only)
|
||||||
while let Ok(sz) = self.rx.try_recv() {
|
while let Ok(sz) = self.rx.try_recv() {
|
||||||
|
@ -322,18 +317,16 @@ impl Display {
|
||||||
let size_info = terminal.size_info().clone();
|
let size_info = terminal.size_info().clone();
|
||||||
self.renderer.with_api(&size_info, |mut api| {
|
self.renderer.with_api(&size_info, |mut api| {
|
||||||
// Draw the grid
|
// Draw the grid
|
||||||
let bg = terminal.bg;
|
api.render_grid(&terminal.render_grid(), glyph_cache);
|
||||||
api.render_grid(&bg, &terminal.render_grid(), glyph_cache);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw render timer
|
// Draw render timer
|
||||||
if self.render_timer {
|
if self.render_timer {
|
||||||
let timing = format!("{:.3} usec", self.meter.average());
|
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| {
|
self.renderer.with_api(terminal.size_info(), |mut api| {
|
||||||
let bg = terminal.bg;
|
api.render_string(&timing[..], glyph_cache, &color);
|
||||||
api.render_string(&bg, &timing[..], glyph_cache, &color);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use std::path::{PathBuf};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{Ordering, AtomicBool};
|
use std::sync::atomic::{Ordering, AtomicBool};
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
use cgmath;
|
use cgmath;
|
||||||
use font::{self, Rasterizer, RasterizedGlyph, FontDesc, GlyphKey, FontKey};
|
use font::{self, Rasterizer, RasterizedGlyph, FontDesc, GlyphKey, FontKey};
|
||||||
|
@ -42,6 +43,38 @@ pub trait LoadGlyph {
|
||||||
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph;
|
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
|
/// Text drawing program
|
||||||
///
|
///
|
||||||
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
|
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
|
||||||
|
@ -222,7 +255,6 @@ struct InstanceData {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct QuadRenderer {
|
pub struct QuadRenderer {
|
||||||
program: ShaderProgram,
|
program: ShaderProgram,
|
||||||
should_reload: Arc<AtomicBool>,
|
|
||||||
vao: GLuint,
|
vao: GLuint,
|
||||||
vbo: GLuint,
|
vbo: GLuint,
|
||||||
ebo: GLuint,
|
ebo: GLuint,
|
||||||
|
@ -230,6 +262,7 @@ pub struct QuadRenderer {
|
||||||
atlas: Vec<Atlas>,
|
atlas: Vec<Atlas>,
|
||||||
active_tex: GLuint,
|
active_tex: GLuint,
|
||||||
batch: Batch,
|
batch: Batch,
|
||||||
|
rx: mpsc::Receiver<Msg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -272,6 +305,18 @@ impl Batch {
|
||||||
self.tex = glyph.tex_id;
|
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 {
|
let mut instance = InstanceData {
|
||||||
col: col,
|
col: col,
|
||||||
row: row,
|
row: row,
|
||||||
|
@ -286,23 +331,23 @@ impl Batch {
|
||||||
uv_width: glyph.uv_width,
|
uv_width: glyph.uv_width,
|
||||||
uv_height: glyph.uv_height,
|
uv_height: glyph.uv_height,
|
||||||
|
|
||||||
r: cell.fg.r as f32,
|
r: fg.r as f32,
|
||||||
g: cell.fg.g as f32,
|
g: fg.g as f32,
|
||||||
b: cell.fg.b as f32,
|
b: fg.b as f32,
|
||||||
|
|
||||||
bg_r: cell.bg.r as f32,
|
bg_r: bg.r as f32,
|
||||||
bg_g: cell.bg.g as f32,
|
bg_g: bg.g as f32,
|
||||||
bg_b: cell.bg.b as f32,
|
bg_b: bg.b as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
if cell.flags.contains(cell::INVERSE) {
|
if cell.flags.contains(cell::INVERSE) {
|
||||||
instance.r = cell.bg.r as f32;
|
instance.r = bg.r as f32;
|
||||||
instance.g = cell.bg.g as f32;
|
instance.g = bg.g as f32;
|
||||||
instance.b = cell.bg.b as f32;
|
instance.b = bg.b as f32;
|
||||||
|
|
||||||
instance.bg_r = cell.fg.r as f32;
|
instance.bg_r = fg.r as f32;
|
||||||
instance.bg_g = cell.fg.g as f32;
|
instance.bg_g = fg.g as f32;
|
||||||
instance.bg_b = cell.fg.b as f32;
|
instance.bg_b = fg.b as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.instances.push(instance);
|
self.instances.push(instance);
|
||||||
|
@ -345,7 +390,7 @@ const ATLAS_SIZE: i32 = 1024;
|
||||||
|
|
||||||
impl QuadRenderer {
|
impl QuadRenderer {
|
||||||
// TODO should probably hand this a transform instead of width/height
|
// 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 program = ShaderProgram::new(width, height).unwrap();
|
||||||
|
|
||||||
let mut vao: GLuint = 0;
|
let mut vao: GLuint = 0;
|
||||||
|
@ -448,11 +493,14 @@ impl QuadRenderer {
|
||||||
let should_reload = Arc::new(AtomicBool::new(false));
|
let should_reload = Arc::new(AtomicBool::new(false));
|
||||||
let should_reload2 = should_reload.clone();
|
let should_reload2 = should_reload.clone();
|
||||||
|
|
||||||
|
let (msg_tx, msg_rx) = mpsc::channel();
|
||||||
|
|
||||||
::std::thread::spawn(move || {
|
::std::thread::spawn(move || {
|
||||||
let (tx, rx) = ::std::sync::mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let mut watcher = Watcher::new(tx).unwrap();
|
let mut watcher = Watcher::new(tx).unwrap();
|
||||||
watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader");
|
watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader");
|
||||||
watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader");
|
watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader");
|
||||||
|
watcher.watch("/home/jwilm/.alacritty.yml").expect("watch alacritty yml");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let event = rx.recv().expect("watcher event");
|
let event = rx.recv().expect("watcher event");
|
||||||
|
@ -468,10 +516,17 @@ impl QuadRenderer {
|
||||||
if let Err(err) = watcher.watch(path) {
|
if let Err(err) = watcher.watch(path) {
|
||||||
println!("failed to establish watch on {:?}: {:?}", path, err);
|
println!("failed to establish watch on {:?}: {:?}", path, err);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This is last event we see after saving in vim
|
if path == ::std::path::Path::new("/home/jwilm/.alacritty.yml") {
|
||||||
should_reload2.store(true, Ordering::Relaxed);
|
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 {
|
let mut renderer = QuadRenderer {
|
||||||
program: program,
|
program: program,
|
||||||
should_reload: should_reload,
|
|
||||||
vao: vao,
|
vao: vao,
|
||||||
vbo: vbo,
|
vbo: vbo,
|
||||||
ebo: ebo,
|
ebo: ebo,
|
||||||
|
@ -487,8 +541,13 @@ impl QuadRenderer {
|
||||||
atlas: Vec::new(),
|
atlas: Vec::new(),
|
||||||
active_tex: 0,
|
active_tex: 0,
|
||||||
batch: Batch::new(),
|
batch: Batch::new(),
|
||||||
|
rx: msg_rx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
COLORS = config.color_list();
|
||||||
|
}
|
||||||
|
|
||||||
let atlas = Atlas::new(ATLAS_SIZE);
|
let atlas = Atlas::new(ATLAS_SIZE);
|
||||||
renderer.atlas.push(atlas);
|
renderer.atlas.push(atlas);
|
||||||
|
|
||||||
|
@ -498,8 +557,17 @@ impl QuadRenderer {
|
||||||
pub fn with_api<F, T>(&mut self, props: &term::SizeInfo, func: F) -> T
|
pub fn with_api<F, T>(&mut self, props: &term::SizeInfo, func: F) -> T
|
||||||
where F: FnOnce(RenderApi) -> T
|
where F: FnOnce(RenderApi) -> T
|
||||||
{
|
{
|
||||||
if self.should_reload.load(Ordering::Relaxed) {
|
while let Ok(msg) = self.rx.try_recv() {
|
||||||
self.reload_shaders(props.width as u32, props.height as u32);
|
match msg {
|
||||||
|
Msg::ConfigReload(config) => {
|
||||||
|
unsafe {
|
||||||
|
COLORS = config.color_list();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Msg::ShaderReload => {
|
||||||
|
self.reload_shaders(props.width as u32, props.height as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -544,7 +612,6 @@ impl QuadRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload_shaders(&mut self, width: u32, height: u32) {
|
pub fn reload_shaders(&mut self, width: u32, height: u32) {
|
||||||
self.should_reload.store(false, Ordering::Relaxed);
|
|
||||||
let program = match ShaderProgram::new(width, height) {
|
let program = match ShaderProgram::new(width, height) {
|
||||||
Ok(program) => program,
|
Ok(program) => program,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -612,10 +679,9 @@ impl<'a> RenderApi<'a> {
|
||||||
/// optimization.
|
/// optimization.
|
||||||
pub fn render_string(
|
pub fn render_string(
|
||||||
&mut self,
|
&mut self,
|
||||||
bg: &Rgb,
|
|
||||||
s: &str,
|
s: &str,
|
||||||
glyph_cache: &mut GlyphCache,
|
glyph_cache: &mut GlyphCache,
|
||||||
color: &Rgb,
|
color: &::term::cell::Color,
|
||||||
) {
|
) {
|
||||||
let row = 40.0;
|
let row = 40.0;
|
||||||
let mut col = 100.0;
|
let mut col = 100.0;
|
||||||
|
@ -630,8 +696,8 @@ impl<'a> RenderApi<'a> {
|
||||||
if let Some(glyph) = glyph_cache.get(&glyph_key, self) {
|
if let Some(glyph) = glyph_cache.get(&glyph_key, self) {
|
||||||
let cell = Cell {
|
let cell = Cell {
|
||||||
c: c,
|
c: c,
|
||||||
fg: *color,
|
fg: color.clone(),
|
||||||
bg: *bg,
|
bg: cell::Color::Rgb(Rgb { r: 0, g: 0, b: 0}),
|
||||||
flags: cell::INVERSE,
|
flags: cell::INVERSE,
|
||||||
};
|
};
|
||||||
self.add_render_item(row, col, &cell, glyph);
|
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 (i, line) in grid.lines().enumerate() {
|
||||||
for (j, cell) in line.cells().enumerate() {
|
for (j, cell) in line.cells().enumerate() {
|
||||||
// Skip empty cells
|
// Skip empty cells
|
||||||
if cell.c == ' ' &&
|
if cell.c == ' ' && cell.bg == cell::Color::Ansi(::ansi::Color::Background) &&
|
||||||
cell.bg == *bg &&
|
|
||||||
!cell.flags.contains(cell::INVERSE)
|
!cell.flags.contains(cell::INVERSE)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
84
src/term.rs
84
src/term.rs
|
@ -21,9 +21,7 @@ use ansi::{self, Attr, Handler};
|
||||||
use grid::{Grid, ClearRegion};
|
use grid::{Grid, ClearRegion};
|
||||||
use index::{Cursor, Column, Line};
|
use index::{Cursor, Column, Line};
|
||||||
use tty;
|
use tty;
|
||||||
use config::Config;
|
use ansi::Color;
|
||||||
|
|
||||||
use ::Rgb;
|
|
||||||
|
|
||||||
/// RAII type which manages grid state for render
|
/// 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 struct Cell {
|
||||||
pub c: char,
|
pub c: char,
|
||||||
pub fg: Rgb,
|
pub fg: Color,
|
||||||
pub bg: Rgb,
|
pub bg: Color,
|
||||||
pub flags: Flags,
|
pub flags: Flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cell {
|
impl Cell {
|
||||||
pub fn new(c: char) -> Cell {
|
pub fn new(c: char, fg: Color, bg: Color) -> Cell {
|
||||||
Cell {
|
Cell {
|
||||||
c: c.into(),
|
c: c.into(),
|
||||||
bg: Default::default(),
|
bg: bg,
|
||||||
fg: Default::default(),
|
fg: fg,
|
||||||
flags: Flags::empty(),
|
flags: Flags::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,13 +115,7 @@ pub mod cell {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset(&mut self, template: &Cell) {
|
pub fn reset(&mut self, template: &Cell) {
|
||||||
// memcpy template to self
|
// memcpy template to self
|
||||||
unsafe {
|
*self = template.clone();
|
||||||
::std::ptr::copy_nonoverlapping(
|
|
||||||
template as *const Cell,
|
|
||||||
self as *mut Cell,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,12 +163,6 @@ pub struct Term {
|
||||||
/// Alt cursor
|
/// Alt cursor
|
||||||
alt_cursor: Cursor,
|
alt_cursor: Cursor,
|
||||||
|
|
||||||
/// Active foreground color
|
|
||||||
pub fg: Rgb,
|
|
||||||
|
|
||||||
/// Active background color
|
|
||||||
pub bg: Rgb,
|
|
||||||
|
|
||||||
/// Tabstops
|
/// Tabstops
|
||||||
tabs: Vec<bool>,
|
tabs: Vec<bool>,
|
||||||
|
|
||||||
|
@ -189,9 +181,6 @@ pub struct Term {
|
||||||
/// Empty cell
|
/// Empty cell
|
||||||
empty_cell: Cell,
|
empty_cell: Cell,
|
||||||
|
|
||||||
/// Text colors
|
|
||||||
colors: [Rgb; 16],
|
|
||||||
|
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +214,6 @@ impl SizeInfo {
|
||||||
|
|
||||||
impl Term {
|
impl Term {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: &Config,
|
|
||||||
width: f32,
|
width: f32,
|
||||||
height: f32,
|
height: f32,
|
||||||
cell_width: f32,
|
cell_width: f32,
|
||||||
|
@ -238,20 +226,18 @@ impl Term {
|
||||||
cell_height: cell_height as f32,
|
cell_height: cell_height as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut template = Cell::new(' ');
|
let template = Cell::new(
|
||||||
template.flags = cell::Flags::empty();
|
' ',
|
||||||
template.bg = config.bg_color();
|
cell::Color::Ansi(Color::Foreground),
|
||||||
template.fg = config.fg_color();
|
cell::Color::Ansi(Color::Background)
|
||||||
|
);
|
||||||
|
|
||||||
let num_cols = size.cols();
|
let num_cols = size.cols();
|
||||||
let num_lines = size.lines();
|
let num_lines = size.lines();
|
||||||
|
|
||||||
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
|
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
|
||||||
|
|
||||||
println!("bg: {:?}, fg: {:?}", template.bg, template.fg);
|
let grid = Grid::new(num_lines, num_cols, &template);
|
||||||
println!("colors: {:?}", config.color_list());
|
|
||||||
|
|
||||||
let grid = Grid::new(num_lines, num_cols, &Cell::new(' '));
|
|
||||||
|
|
||||||
let tty = tty::new(*num_lines as u8, *num_cols as u8);
|
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);
|
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,
|
alt: false,
|
||||||
cursor: Cursor::default(),
|
cursor: Cursor::default(),
|
||||||
alt_cursor: Cursor::default(),
|
alt_cursor: Cursor::default(),
|
||||||
fg: config.fg_color(),
|
|
||||||
bg: config.bg_color(),
|
|
||||||
tty: tty,
|
tty: tty,
|
||||||
tabs: tabs,
|
tabs: tabs,
|
||||||
mode: Default::default(),
|
mode: Default::default(),
|
||||||
scroll_region: scroll_region,
|
scroll_region: scroll_region,
|
||||||
size_info: size,
|
size_info: size,
|
||||||
template_cell: template,
|
template_cell: template.clone(),
|
||||||
empty_cell: template,
|
empty_cell: template,
|
||||||
colors: config.color_list(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,8 +306,9 @@ impl Term {
|
||||||
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
|
println!("num_cols, num_lines = {}, {}", num_cols, num_lines);
|
||||||
|
|
||||||
// Resize grids to new size
|
// Resize grids to new size
|
||||||
self.grid.resize(num_lines, num_cols, &Cell::new(' '));
|
let template = self.template_cell.clone();
|
||||||
self.alt_grid.resize(num_lines, num_cols, &Cell::new(' '));
|
self.grid.resize(num_lines, num_cols, &template);
|
||||||
|
self.alt_grid.resize(num_lines, num_cols, &template);
|
||||||
|
|
||||||
// Ensure cursor is in-bounds
|
// Ensure cursor is in-bounds
|
||||||
self.cursor.line = limit(self.cursor.line, Line(0), num_lines);
|
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];
|
let cell = &mut self.grid[&self.cursor];
|
||||||
*cell = self.template_cell;
|
*cell = self.template_cell.clone();
|
||||||
cell.c = c;
|
cell.c = c;
|
||||||
self.cursor.col += 1;
|
self.cursor.col += 1;
|
||||||
}
|
}
|
||||||
|
@ -779,27 +763,21 @@ impl ansi::Handler for Term {
|
||||||
fn terminal_attribute(&mut self, attr: Attr) {
|
fn terminal_attribute(&mut self, attr: Attr) {
|
||||||
debug_println!("Set Attribute: {:?}", attr);
|
debug_println!("Set Attribute: {:?}", attr);
|
||||||
match attr {
|
match attr {
|
||||||
Attr::DefaultForeground => {
|
|
||||||
self.template_cell.fg = self.fg;
|
|
||||||
},
|
|
||||||
Attr::DefaultBackground => {
|
|
||||||
self.template_cell.bg = self.bg;
|
|
||||||
},
|
|
||||||
Attr::Foreground(named_color) => {
|
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) => {
|
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) => {
|
Attr::ForegroundSpec(rgb) => {
|
||||||
self.template_cell.fg = rgb;
|
self.template_cell.fg = cell::Color::Rgb(rgb);
|
||||||
},
|
},
|
||||||
Attr::BackgroundSpec(rgb) => {
|
Attr::BackgroundSpec(rgb) => {
|
||||||
self.template_cell.bg = rgb;
|
self.template_cell.bg = cell::Color::Rgb(rgb);
|
||||||
},
|
},
|
||||||
Attr::Reset => {
|
Attr::Reset => {
|
||||||
self.template_cell.fg = self.fg;
|
self.template_cell.fg = cell::Color::Ansi(Color::Foreground);
|
||||||
self.template_cell.bg = self.bg;
|
self.template_cell.bg = cell::Color::Ansi(Color::Background);
|
||||||
self.template_cell.flags = cell::Flags::empty();
|
self.template_cell.flags = cell::Flags::empty();
|
||||||
},
|
},
|
||||||
Attr::Reverse => self.template_cell.flags.insert(cell::INVERSE),
|
Attr::Reverse => self.template_cell.flags.insert(cell::INVERSE),
|
||||||
|
|
Loading…
Reference in New Issue