From 8a763c928ebf5c92151f2a32afbcb891dbe6c5e4 Mon Sep 17 00:00:00 2001 From: daa84 Date: Thu, 31 Mar 2016 19:19:08 +0300 Subject: [PATCH] background / foreground highlight --- src/nvim.rs | 21 +++++++++++++++++- src/ui.rs | 57 +++++++++++++++++++++++++++++++++++++++++++------ src/ui_model.rs | 46 +++++++++++++++++++++++++++++++-------- 3 files changed, 108 insertions(+), 16 deletions(-) diff --git a/src/nvim.rs b/src/nvim.rs index add19aa..ebe5e98 100644 --- a/src/nvim.rs +++ b/src/nvim.rs @@ -1,6 +1,7 @@ use neovim_lib::{Neovim, NeovimApi, Session}; use std::io::{Result, Error, ErrorKind}; use std::result; +use std::collections::HashMap; use ui_model::UiModel; use rmp::Value; use rmp::value::Integer; @@ -18,6 +19,8 @@ pub trait RedrawEvents { fn on_resize(&mut self, columns: u64, rows: u64); fn on_redraw(&self); + + fn on_highlight_set(&mut self, attrs: &HashMap); } macro_rules! try_str { @@ -110,7 +113,23 @@ fn call(method: &str, args: Vec) { Ok(()) }); } - _ => println!("Event {}", method), + "highlight_set" => { + safe_call(move |ui| { + if let Value::Map(ref attrs) = args[0] { + let attrs_map: HashMap = attrs.iter().map(|v| { + match v { + &(Value::String(ref key), ref value) => (key.clone(), value.clone()), + _ => panic!("attribute key must be string"), + } + }).collect(); + ui.on_highlight_set(&attrs_map); + } else { + panic!("Supports only map value as argument"); + } + Ok(()) + }); + } + _ => println!("Event {}({:?})", method, args), }; } diff --git a/src/ui.rs b/src/ui.rs index eb71e98..bf3b66d 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,5 +1,10 @@ use std::cell::RefCell; use std::thread; +use std::collections::HashMap; +use std::mem; + +use rmp::Value; +use rmp::value::Integer; use cairo; use gtk; @@ -9,7 +14,7 @@ use gdk; use gdk::EventKey; use neovim_lib::{Neovim, NeovimApi}; -use ui_model::UiModel; +use ui_model::{UiModel, Attrs, Color}; use nvim::RedrawEvents; thread_local!(pub static UI: RefCell = { @@ -25,6 +30,7 @@ pub struct Ui { pub model: UiModel, nvim: Option, drawing_area: DrawingArea, + cur_attrs: Option, } impl Ui { @@ -33,6 +39,7 @@ impl Ui { model: UiModel::empty(), drawing_area: DrawingArea::new(), nvim: None, + cur_attrs: None, } } @@ -104,6 +111,10 @@ fn gtk_draw(drawing_area: &DrawingArea, ctx: &cairo::Context) -> Inhibit { let width = drawing_area.get_allocated_width() as f64; let height = drawing_area.get_allocated_height() as f64; + ctx.set_source_rgb(0.0, 0.0, 0.0); + ctx.paint(); + ctx.set_source_rgb(1.0, 1.0, 1.0); + let font_face = cairo::FontFace::toy_create("", cairo::enums::FontSlant::Normal, cairo::enums::FontWeight::Normal); @@ -113,11 +124,23 @@ fn gtk_draw(drawing_area: &DrawingArea, ctx: &cairo::Context) -> Inhibit { UI.with(|ui_cell| { let ui = ui_cell.borrow(); - ctx.set_source_rgb(0.0, 0.0, 0.0); let mut line_y = font_extents.height; - for line in ui.model.lines() { - ctx.move_to(0.0, line_y); - ctx.show_text(&line); + for line in ui.model.model() { + ctx.move_to(0.0, line_y - font_extents.descent); + for cell in line { + let bg = &cell.attrs.background; + ctx.set_source_rgb(bg.0, bg.1, bg.2); + //ctx.set_source_rgb(1.0, 0.0 , 0.0); + let text_extents = ctx.text_extents(&cell.ch.to_string()); + let current_point = ctx.get_current_point(); + ctx.rectangle(current_point.0, line_y - font_extents.height, text_extents.width, font_extents.height); + ctx.fill(); + + ctx.move_to(current_point.0, current_point.1); + let fg = &cell.attrs.foreground; + ctx.set_source_rgb(fg.0, fg.1, fg.2); + ctx.show_text(&cell.ch.to_string()); + } line_y += font_extents.height; } }); @@ -131,7 +154,7 @@ impl RedrawEvents for Ui { } fn on_put(&mut self, text: &str) { - self.model.put(text); + self.model.put(text, &self.cur_attrs); } fn on_clear(&mut self) { @@ -145,4 +168,26 @@ impl RedrawEvents for Ui { fn on_redraw(&self) { self.drawing_area.queue_draw(); } + + // highlight_set([Map([(String("bold"), Boolean(true)), (String("foreground"), Integer(U64(255)))])]) + fn on_highlight_set(&mut self, attrs: &HashMap) { + let mut model_attrs = Attrs::new(); + if let Some(&Value::Integer(Integer::U64(fg))) = attrs.get("foreground") { + model_attrs.foreground = split_color(fg); + } + if let Some(&Value::Integer(Integer::U64(fg))) = attrs.get("background") { + model_attrs.background = split_color(fg); + } + if attrs.contains_key("reverse") { + mem::swap(&mut model_attrs.foreground, &mut model_attrs.background); + } + self.cur_attrs = Some(model_attrs); + } +} + +fn split_color(indexed_color: u64) -> Color { + let r = ((indexed_color >> 16) & 0xff) as f64; + let g = ((indexed_color >> 8) & 0xff) as f64; + let b = (indexed_color & 0xff) as f64; + Color(255.0 / r, 255.0 / g, 255.0 / b) } diff --git a/src/ui_model.rs b/src/ui_model.rs index 89cd272..3d9276e 100644 --- a/src/ui_model.rs +++ b/src/ui_model.rs @@ -1,14 +1,40 @@ + +#[derive(Clone)] +pub struct Color(pub f64, pub f64, pub f64); + +const COLOR_BLACK: Color = Color(0.0, 0.0, 0.0); +const COLOR_WHITE: Color = Color(1.0, 1.0, 1.0); + +#[derive(Clone)] +pub struct Attrs { + pub foreground: Color, + pub background: Color, +} + +impl Attrs { + pub fn new() -> Attrs { + Attrs { + foreground: COLOR_WHITE, + background: COLOR_BLACK, + } + } +} + pub struct Cell { - ch: char, + pub ch: char, + pub attrs: Attrs, } impl Cell { pub fn new(ch: char) -> Cell { - Cell { ch: ch } + Cell { + ch: ch, + attrs: Attrs::new(), + } } fn clear(&mut self) { - self.ch = ' '; + self.ch = ' '; } } @@ -29,12 +55,12 @@ impl UiModel { let mut model = Vec::with_capacity(rows as usize); for i in 0..rows as usize { model.push(Vec::with_capacity(columns as usize)); - for _ in 0..columns as usize{ + for _ in 0..columns as usize { model[i].push(Cell::new(' ')); } } - UiModel { + UiModel { columns: columns as usize, rows: rows as usize, cur_row: 0, @@ -43,8 +69,8 @@ impl UiModel { } } - pub fn lines(&self) -> Vec { - self.model.iter().map(|r| r.iter().map(|c| c.ch).collect::()).collect() + pub fn model(&self) -> &Vec> { + &self.model } pub fn set_cursor(&mut self, row: u64, col: u64) { @@ -52,8 +78,10 @@ impl UiModel { self.cur_row = row as usize; } - pub fn put(&mut self, text: &str) { - self.model[self.cur_row][self.cur_col].ch = text.chars().last().unwrap(); + pub fn put(&mut self, text: &str, attrs: &Option) { + let mut cell = &mut self.model[self.cur_row][self.cur_col]; + cell.ch = text.chars().last().unwrap(); + cell.attrs = attrs.as_ref().map(|o| o.clone()).unwrap_or_else(|| Attrs::new()); self.cur_col += 1; }