diff --git a/CHANGELOG.md b/CHANGELOG.md index a94c3a4d..ca1e5f37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Customizable keybindings for search - History for search mode, bound to ^P/^N/Up/Down by default - Default binding to cancel search on Ctrl+C +- History position indicator for search and vi mode ### Changed diff --git a/alacritty.yml b/alacritty.yml index cb16bf7c..4a23f5c9 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -211,16 +211,6 @@ # text: CellBackground # cursor: CellForeground - # Selection colors - # - # Colors which should be used to draw the selection area. - # - # Allowed values are CellForeground and CellBackground, which reference the - # affected cell, or hexadecimal colors like #ff00ff. - #selection: - # text: CellBackground - # background: CellForeground - # Search colors # # Colors used for the search bar and match highlighting. @@ -238,6 +228,26 @@ # background: '#c5c8c6' # foreground: '#1d1f21' + # Line indicator + # + # Color used for the indicator displaying the position in history during + # search and vi mode. + # + # By default, these will use the opposing primary color. + #line_indicator: + # foreground: None + # background: None + + # Selection colors + # + # Colors which should be used to draw the selection area. + # + # Allowed values are CellForeground and CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + #selection: + # text: CellBackground + # background: CellForeground + # Normal colors #normal: # black: '#1d1f21' diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs index 4084d639..b5c2bfa9 100644 --- a/alacritty/src/display.rs +++ b/alacritty/src/display.rs @@ -23,10 +23,10 @@ use wayland_client::{Display as WaylandDisplay, EventQueue}; use crossfont::{self, Rasterize, Rasterizer}; use alacritty_terminal::event::{EventListener, OnResize}; -use alacritty_terminal::index::{Column, Direction, Point}; +use alacritty_terminal::grid::Dimensions as _; +use alacritty_terminal::index::{Column, Direction, Line, Point}; use alacritty_terminal::selection::Selection; -use alacritty_terminal::term::{SizeInfo, Term, TermMode}; -use alacritty_terminal::term::{MIN_COLS, MIN_SCREEN_LINES}; +use alacritty_terminal::term::{SizeInfo, Term, TermMode, MIN_COLS, MIN_SCREEN_LINES}; use crate::config::font::Font; use crate::config::window::Dimensions; @@ -460,21 +460,19 @@ impl Display { let cursor = content.cursor(); let visual_bell_intensity = terminal.visual_bell.intensity(); + let display_offset = terminal.grid().display_offset(); let background_color = terminal.background_color(); let cursor_point = terminal.grid().cursor.point; + let total_lines = terminal.grid().total_lines(); let metrics = self.glyph_cache.font_metrics(); - let glyph_cache = &mut self.glyph_cache; let size_info = self.size_info; let selection = !terminal.selection.as_ref().map(Selection::is_empty).unwrap_or(true); let mouse_mode = terminal.mode().intersects(TermMode::MOUSE_MODE) && !terminal.mode().contains(TermMode::VI); - let vi_mode_cursor = if terminal.mode().contains(TermMode::VI) { - Some(terminal.vi_mode_cursor) - } else { - None - }; + let vi_mode = terminal.mode().contains(TermMode::VI); + let vi_mode_cursor = if vi_mode { Some(terminal.vi_mode_cursor) } else { None }; // Drop terminal as early as possible to free lock. drop(terminal); @@ -490,6 +488,7 @@ impl Display { { let _sampler = self.meter.sampler(); + let glyph_cache = &mut self.glyph_cache; self.renderer.with_api(&config.ui_config, &size_info, |mut api| { // Iterate over all non-empty cells in the grid. for mut cell in grid_cells { @@ -539,11 +538,19 @@ impl Display { } } - // Highlight URLs at the vi mode cursor position. if let Some(vi_mode_cursor) = vi_mode_cursor { - if let Some(url) = self.urls.find_at(vi_mode_cursor.point) { + // Highlight URLs at the vi mode cursor position. + let vi_mode_point = vi_mode_cursor.point; + if let Some(url) = self.urls.find_at(vi_mode_point) { rects.append(&mut url.rects(&metrics, &size_info)); } + + // Indicate vi mode by showing the cursor's position in the top right corner. + let line = size_info.screen_lines() + display_offset - vi_mode_point.line - 1; + self.draw_line_indicator(config, &size_info, total_lines, Some(vi_mode_point), line.0); + } else if search_active { + // Show current display offset in vi-less search to indicate match position. + self.draw_line_indicator(config, &size_info, total_lines, None, display_offset); } // Push the cursor rects for rendering. @@ -574,13 +581,13 @@ impl Display { let start_line = size_info.screen_lines() + search_offset; let y = size_info.cell_height().mul_add(start_line.0 as f32, size_info.padding_y()); - let color = match message.ty() { + let bg = match message.ty() { MessageType::Error => config.colors.normal.red, MessageType::Warning => config.colors.normal.yellow, }; let message_bar_rect = - RenderRect::new(0., y, size_info.width(), size_info.height() - y, color, 1.); + RenderRect::new(0., y, size_info.width(), size_info.height() - y, bg, 1.); // Push message_bar in the end, so it'll be above all other content. rects.push(message_bar_rect); @@ -589,10 +596,12 @@ impl Display { self.renderer.draw_rects(&size_info, rects); // Relay messages to the user. + let glyph_cache = &mut self.glyph_cache; let fg = config.colors.primary.background; for (i, message_text) in text.iter().enumerate() { + let point = Point::new(start_line + i, Column(0)); self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, start_line + i, &message_text, fg, None); + api.render_string(glyph_cache, point, fg, bg, &message_text); }); } } else { @@ -681,10 +690,12 @@ impl Display { // Assure text length is at least num_cols. let text = format!("{:<1$}", text, num_cols); + let point = Point::new(size_info.screen_lines(), Column(0)); let fg = config.colors.search_bar_foreground(); let bg = config.colors.search_bar_background(); + self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, size_info.screen_lines(), &text, fg, Some(bg)); + api.render_string(glyph_cache, point, fg, bg, &text); }); } @@ -693,17 +704,43 @@ impl Display { if !config.ui_config.debug.render_timer { return; } + let glyph_cache = &mut self.glyph_cache; let timing = format!("{:.3} usec", self.meter.average()); + let point = Point::new(size_info.screen_lines() - 2, Column(0)); let fg = config.colors.primary.background; let bg = config.colors.normal.red; self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, size_info.screen_lines() - 2, &timing[..], fg, Some(bg)); + api.render_string(glyph_cache, point, fg, bg, &timing); }); } + /// Draw an indicator for the position of a line in history. + fn draw_line_indicator( + &mut self, + config: &Config, + size_info: &SizeInfo, + total_lines: usize, + vi_mode_point: Option, + line: usize, + ) { + let text = format!("[{}/{}]", line, total_lines - 1); + let column = Column(size_info.cols().0.saturating_sub(text.len())); + let colors = &config.colors; + let fg = colors.line_indicator.foreground.unwrap_or(colors.primary.background); + let bg = colors.line_indicator.background.unwrap_or(colors.primary.foreground); + + // Do not render anything if it would obscure the vi mode cursor. + if vi_mode_point.map_or(true, |point| point.line.0 != 0 || point.col < column) { + let glyph_cache = &mut self.glyph_cache; + self.renderer.with_api(&config.ui_config, &size_info, |mut api| { + api.render_string(glyph_cache, Point::new(Line(0), column), fg, bg, &text); + }); + } + } + /// Requst a new frame for a window on Wayland. #[inline] #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index 5edcbb4a..39e53b82 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -14,7 +14,7 @@ use fnv::FnvHasher; use log::{error, info}; use unicode_width::UnicodeWidthChar; -use alacritty_terminal::index::{Column, Line}; +use alacritty_terminal::index::Point; use alacritty_terminal::term::cell::Flags; use alacritty_terminal::term::color::Rgb; use alacritty_terminal::term::render::RenderableCell; @@ -820,25 +820,23 @@ impl<'a> RenderApi<'a> { pub fn render_string( &mut self, glyph_cache: &mut GlyphCache, - line: Line, - string: &str, + point: Point, fg: Rgb, - bg: Option, + bg: Rgb, + string: &str, ) { - let bg_alpha = bg.map(|_| 1.0).unwrap_or(0.0); - let cells = string .chars() .enumerate() .map(|(i, character)| RenderableCell { - line, - column: Column(i), + line: point.line, + column: point.col + i, character, zerowidth: None, flags: Flags::empty(), - bg_alpha, + bg_alpha: 1.0, fg, - bg: bg.unwrap_or(Rgb { r: 0, g: 0, b: 0 }), + bg, is_match: false, }) .collect::>(); diff --git a/alacritty_terminal/src/config/colors.rs b/alacritty_terminal/src/config/colors.rs index f295da1c..88ca5057 100644 --- a/alacritty_terminal/src/config/colors.rs +++ b/alacritty_terminal/src/config/colors.rs @@ -16,6 +16,7 @@ pub struct Colors { pub dim: Option, pub indexed_colors: Vec, pub search: SearchColors, + pub line_indicator: LineIndicatorColors, } impl Colors { @@ -28,6 +29,12 @@ impl Colors { } } +#[derive(ConfigDeserialize, Copy, Clone, Default, Debug, PartialEq, Eq)] +pub struct LineIndicatorColors { + pub foreground: Option, + pub background: Option, +} + #[derive(Deserialize, Copy, Clone, Default, Debug, PartialEq, Eq)] pub struct IndexedColor { pub color: Rgb,