diff --git a/Cargo.lock b/Cargo.lock index 7c2d413..5cefe3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "nvim-gtk" -version = "0.1.2" +version = "0.2.0" dependencies = [ "cairo-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 0008642..bef06e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nvim-gtk" -version = "0.1.2" +version = "0.2.0" authors = ["daa84 "] build = "build.rs" diff --git a/src/render/mod.rs b/src/render/mod.rs index bd15973..44ddc99 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -4,7 +4,7 @@ mod model_clip_iterator; pub use self::context::Context; pub use self::context::CellMetrics; -use self::model_clip_iterator::ModelClipIteratorFactory; +use self::model_clip_iterator::{RowView, ModelClipIteratorFactory}; use mode; use color; @@ -31,62 +31,34 @@ pub fn render( ctx.paint(); let cell_metrics = font_ctx.cell_metrics(); - let &CellMetrics { - line_height, - char_width, - underline_position, - underline_thickness, - .. - } = cell_metrics; + let &CellMetrics { char_width, .. } = cell_metrics; let (cursor_row, cursor_col) = ui_model.get_cursor(); - for (row, line) in ui_model.get_clip_iterator(ctx, cell_metrics) { - let line_y = row as f64 * line_height; + for cell_view in ui_model.get_clip_iterator(ctx, cell_metrics) { let mut line_x = 0.0; + let RowView { line, row, line_y, .. } = cell_view; for col in 0..line.line.len() { let cell = &line.line[col]; - draw_cell( - ctx, - cell_metrics, - color_model, - line, - cell, - col, - line_x, - line_y, - ); + draw_cell(&cell_view, color_model, cell, col, line_x); - if cell.attrs.underline || cell.attrs.undercurl { - if cell.attrs.undercurl { - let sp = color_model.actual_cell_sp(cell); - ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7); + draw_underline(&cell_view, color_model, cell, line_x); - let max_undercurl_height = (line_height - underline_position) * 2.0; - let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height); - let undercurl_y = line_y + underline_position - undercurl_height / 2.0; - - ctx.show_error_underline(line_x, undercurl_y, char_width, undercurl_height); - } else if cell.attrs.underline { - let fg = color_model.actual_cell_fg(cell); - ctx.set_source_rgb(fg.0, fg.1, fg.2); - ctx.set_line_width(underline_thickness); - ctx.move_to(line_x, line_y + underline_position); - ctx.line_to(line_x + char_width, line_y + underline_position); - ctx.stroke(); - } - } if row == cursor_row && col == cursor_col { + let double_width = line.line.get(col + 1).map_or( + false, + |c| c.attrs.double_width, + ); ctx.move_to(line_x, line_y); cursor.draw( ctx, font_ctx, mode, line_y, - false, //TODO: double_width, + double_width, color_model.actual_cell_bg(cell), ); } @@ -96,23 +68,68 @@ pub fn render( } } -fn draw_cell( - ctx: &cairo::Context, - cell_metrics: &CellMetrics, +fn draw_underline( + cell_view: &RowView, + color_model: &color::ColorModel, + cell: &ui_model::Cell, + line_x: f64, +) { + + if cell.attrs.underline || cell.attrs.undercurl { + + let &RowView { + ctx, + line_y, + cell_metrics: &CellMetrics { + line_height, + char_width, + underline_position, + underline_thickness, + .. + }, + .. + } = cell_view; + + if cell.attrs.undercurl { + let sp = color_model.actual_cell_sp(cell); + ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7); + + let max_undercurl_height = (line_height - underline_position) * 2.0; + let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height); + let undercurl_y = line_y + underline_position - undercurl_height / 2.0; + + ctx.show_error_underline(line_x, undercurl_y, char_width, undercurl_height); + } else if cell.attrs.underline { + let fg = color_model.actual_cell_fg(cell); + ctx.set_source_rgb(fg.0, fg.1, fg.2); + ctx.set_line_width(underline_thickness); + ctx.move_to(line_x, line_y + underline_position); + ctx.line_to(line_x + char_width, line_y + underline_position); + ctx.stroke(); + } + } +} + +fn draw_cell( + cell_view: &RowView, color_model: &color::ColorModel, - line: &ui_model::Line, cell: &ui_model::Cell, col: usize, line_x: f64, - line_y: f64, ) { - let &CellMetrics { - char_width, - line_height, - ascent, + let &RowView { + ctx, + line, + line_y, + cell_metrics: &CellMetrics { + char_width, + line_height, + ascent, + .. + }, .. - } = cell_metrics; + } = cell_view; let (bg, fg) = color_model.cell_colors(cell); diff --git a/src/render/model_clip_iterator.rs b/src/render/model_clip_iterator.rs index 997da2c..b849333 100644 --- a/src/render/model_clip_iterator.rs +++ b/src/render/model_clip_iterator.rs @@ -4,25 +4,57 @@ use cairo; use super::context::CellMetrics; use ui_model; +pub struct RowView<'a> { + pub row: usize, + pub line: &'a ui_model::Line, + pub cell_metrics: &'a CellMetrics, + pub line_y: f64, + pub ctx: &'a cairo::Context, +} + +impl<'a> RowView<'a> { + pub fn new( + row: usize, + ctx: &'a cairo::Context, + cell_metrics: &'a CellMetrics, + line: &'a ui_model::Line, + ) -> Self { + RowView { + line, + line_y: row as f64 * cell_metrics.line_height, + row, + cell_metrics, + ctx, + } + } +} + pub struct ModelClipIterator<'a> { model_idx: usize, model_iter: Iter<'a, ui_model::Line>, + cell_metrics: &'a CellMetrics, + ctx: &'a cairo::Context, } pub trait ModelClipIteratorFactory { - fn get_clip_iterator( - &self, - ctx: &cairo::Context, - cell_metrics: &CellMetrics, + fn get_clip_iterator<'a>( + &'a self, + ctx: &'a cairo::Context, + cell_metrics: &'a CellMetrics, ) -> ModelClipIterator; } impl<'a> Iterator for ModelClipIterator<'a> { - type Item = (usize, &'a ui_model::Line); + type Item = RowView<'a>; - fn next(&mut self) -> Option<(usize, &'a ui_model::Line)> { + fn next(&mut self) -> Option> { let next = if let Some(line) = self.model_iter.next() { - Some((self.model_idx, line)) + Some(RowView::new( + self.model_idx, + self.ctx, + self.cell_metrics, + line, + )) } else { None }; @@ -36,11 +68,11 @@ impl<'a> Iterator for ModelClipIterator<'a> { /// this is because in some cases(like 'g' character) drawing character does not fit to calculated bounds /// and if one line must be repainted - also previous and next line must be repainted to impl ModelClipIteratorFactory for ui_model::UiModel { - fn get_clip_iterator( - &self, - ctx: &cairo::Context, - cell_metrics: &CellMetrics, - ) -> ModelClipIterator { + fn get_clip_iterator<'a>( + &'a self, + ctx: &'a cairo::Context, + cell_metrics: &'a CellMetrics, + ) -> ModelClipIterator<'a> { let model = self.model(); let (x1, y1, x2, y2) = ctx.clip_extents(); @@ -59,6 +91,8 @@ impl ModelClipIteratorFactory for ui_model::UiModel { ModelClipIterator { model_idx: model_clip_top, model_iter: model[model_clip_top..model_clip_bot + 1].iter(), + ctx, + cell_metrics, } } } diff --git a/src/ui_model/model_rect.rs b/src/ui_model/model_rect.rs index 9ce5ac5..3287cbe 100644 --- a/src/ui_model/model_rect.rs +++ b/src/ui_model/model_rect.rs @@ -108,6 +108,24 @@ impl ModelRect { if right < self.right + len_since_right { right = self.right + len_since_right; } + + // extend also double_width chars + let cell = &line.line[self.left]; + if self.left > 0 && cell.attrs.double_width { + let dw_char_idx = self.left - 1; + if dw_char_idx < left { + left = dw_char_idx; + } + } + + let dw_char_idx = self.right + 1; + if let Some(cell) = line.line.get(dw_char_idx) { + if cell.attrs.double_width { + if right < dw_char_idx { + right = dw_char_idx; + } + } + } } self.left = left;