on master help sign in
Add cursorcolumn (#4084)

* Implement cursorcolumn * Add documentation * Separate column style from line with fallback * Fallback to cursorcolumn first * Switch to non-fallback try_get_exact Add new function `try_get_exact`, which doesn't perform fallback, and use that instead because the fallback behaviour is being handled manually.

commitc15f1ea274d300feb23208324aa5b27d7274bebd authorA-Walrus <58790821+A-Walrus@users.noreply.github.com> dateSat 8 Oct 2022, 21:28 (4 years ago) parent18cfe86
5 files changed+109−46
book/src/configuration.md+1 book/src/themes.md+47−45 helix-term/src/ui/editor.rs+51−1 helix-view/src/editor.rs+3 helix-view/src/theme.rs+7
book/src/configuration.md+1
@@ -45,6 +45,7 @@ on unix operating systems.
4545| `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`<br/>Windows: `["cmd", "/C"]` |
4646| `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers. | `absolute` |
4747| `cursorline` | Highlight all lines with a cursor. | `false` |
48+| `cursorcolumn` | Highlight all columns with a cursor. | `false` |
4849| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "line-numbers"]` |
4950| `auto-completion` | Enable automatic pop up of auto-completion. | `true` |
5051| `auto-format` | Enable automatic formatting on save. | `true` |
book/src/themes.md+47−45
@@ -225,51 +225,53 @@ These scopes are used for theming the editor interface.
225225 - `hover` - for hover popup ui
226226
227227
228−| Key | Notes |
229−| --- | --- |
230−| `ui.background` | |
231−| `ui.background.separator` | Picker separator below input line |
232−| `ui.cursor` | |
233−| `ui.cursor.insert` | |
234−| `ui.cursor.select` | |
235−| `ui.cursor.match` | Matching bracket etc. |
236−| `ui.cursor.primary` | Cursor with primary selection |
237−| `ui.gutter` | Gutter |
238−| `ui.gutter.selected` | Gutter for the line the cursor is on |
239−| `ui.linenr` | Line numbers |
240−| `ui.linenr.selected` | Line number for the line the cursor is on |
241−| `ui.statusline` | Statusline |
242−| `ui.statusline.inactive` | Statusline (unfocused document) |
243−| `ui.statusline.normal` | Statusline mode during normal mode ([only if `editor.color-modes` is enabled][editor-section]) |
244−| `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) |
245−| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
246−| `ui.statusline.separator` | Separator character in statusline |
247−| `ui.popup` | Documentation popups (e.g space-k) |
248−| `ui.popup.info` | Prompt for multiple key options |
249−| `ui.window` | Border lines separating splits |
250−| `ui.help` | Description box for commands |
251−| `ui.text` | Command prompts, popup text, etc. |
252−| `ui.text.focus` | |
253−| `ui.text.info` | The key: command text in `ui.popup.info` boxes |
254−| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section])|
255−| `ui.virtual.whitespace` | Visible white-space characters |
256−| `ui.virtual.indent-guide` | Vertical indent width guides |
257−| `ui.menu` | Code and command completion menus |
258−| `ui.menu.selected` | Selected autocomplete item |
259−| `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar |
260−| `ui.selection` | For selections in the editing area |
261−| `ui.selection.primary` | |
262−| `ui.cursorline.primary` | The line of the primary cursor |
263−| `ui.cursorline.secondary` | The lines of any other cursors |
264−| `warning` | Diagnostics warning (gutter) |
265−| `error` | Diagnostics error (gutter) |
266−| `info` | Diagnostics info (gutter) |
267−| `hint` | Diagnostics hint (gutter) |
268−| `diagnostic` | Diagnostics fallback style (editing area) |
269−| `diagnostic.hint` | Diagnostics hint (editing area) |
270−| `diagnostic.info` | Diagnostics info (editing area) |
271−| `diagnostic.warning` | Diagnostics warning (editing area) |
272−| `diagnostic.error` | Diagnostics error (editing area) |
228+| Key | Notes |
229+| --- | --- |
230+| `ui.background` | |
231+| `ui.background.separator` | Picker separator below input line |
232+| `ui.cursor` | |
233+| `ui.cursor.insert` | |
234+| `ui.cursor.select` | |
235+| `ui.cursor.match` | Matching bracket etc. |
236+| `ui.cursor.primary` | Cursor with primary selection |
237+| `ui.gutter` | Gutter |
238+| `ui.gutter.selected` | Gutter for the line the cursor is on |
239+| `ui.linenr` | Line numbers |
240+| `ui.linenr.selected` | Line number for the line the cursor is on |
241+| `ui.statusline` | Statusline |
242+| `ui.statusline.inactive` | Statusline (unfocused document) |
243+| `ui.statusline.normal` | Statusline mode during normal mode ([only if `editor.color-modes` is enabled][editor-section]) |
244+| `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) |
245+| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
246+| `ui.statusline.separator` | Separator character in statusline |
247+| `ui.popup` | Documentation popups (e.g space-k) |
248+| `ui.popup.info` | Prompt for multiple key options |
249+| `ui.window` | Border lines separating splits |
250+| `ui.help` | Description box for commands |
251+| `ui.text` | Command prompts, popup text, etc. |
252+| `ui.text.focus` | |
253+| `ui.text.info` | The key: command text in `ui.popup.info` boxes |
254+| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section]) |
255+| `ui.virtual.whitespace` | Visible white-space characters |
256+| `ui.virtual.indent-guide` | Vertical indent width guides |
257+| `ui.menu` | Code and command completion menus |
258+| `ui.menu.selected` | Selected autocomplete item |
259+| `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar |
260+| `ui.selection` | For selections in the editing area |
261+| `ui.selection.primary` | |
262+| `ui.cursorline.primary` | The line of the primary cursor ([if cursorline is enabled][editor-section]) |
263+| `ui.cursorline.secondary` | The lines of any other cursors ([if cursorline is enabled][editor-section]) |
264+| `ui.cursorcolumn.primary` | The column of the primary cursor ([if cursorcolumn is enabled][editor-section]) |
265+| `ui.cursorcolumn.secondary` | The columns of any other cursors ([if cursorcolumn is enabled][editor-section]) |
266+| `warning` | Diagnostics warning (gutter) |
267+| `error` | Diagnostics error (gutter) |
268+| `info` | Diagnostics info (gutter) |
269+| `hint` | Diagnostics hint (gutter) |
270+| `diagnostic` | Diagnostics fallback style (editing area) |
271+| `diagnostic.hint` | Diagnostics hint (editing area) |
272+| `diagnostic.info` | Diagnostics info (editing area) |
273+| `diagnostic.warning` | Diagnostics warning (editing area) |
274+| `diagnostic.error` | Diagnostics error (editing area) |
273275
274276You can check compliance to spec with
275277
helix-term/src/ui/editor.rs+51−1
@@ -13,7 +13,7 @@ use helix_core::{
1313 movement::Direction,
1414 syntax::{self, HighlightEvent},
1515 unicode::width::UnicodeWidthStr,
16− LineEnding, Position, Range, Selection, Transaction,
16+ visual_coords_at_pos, LineEnding, Position, Range, Selection, Transaction,
1717};
1818use helix_view::{
1919 document::{Mode, SCRATCH_BUFFER_NAME},
@@ -118,6 +118,9 @@ impl EditorView {
118118 if is_focused && editor.config().cursorline {
119119 Self::highlight_cursorline(doc, view, surface, theme);
120120 }
121+ if is_focused && editor.config().cursorcolumn {
122+ Self::highlight_cursorcolumn(doc, view, surface, theme);
123+ }
121124
122125 let highlights = Self::doc_syntax_highlights(doc, view.offset, inner.height, theme);
123126 let highlights = syntax::merge(highlights, Self::doc_diagnostics_highlights(doc, theme));
@@ -830,6 +833,53 @@ impl EditorView {
830833 }
831834 }
832835
836+ /// Apply the highlighting on the columns where a cursor is active
837+ pub fn highlight_cursorcolumn(
838+ doc: &Document,
839+ view: &View,
840+ surface: &mut Surface,
841+ theme: &Theme,
842+ ) {
843+ let text = doc.text().slice(..);
844+
845+ // Manual fallback behaviour:
846+ // ui.cursorcolumn.{p/s} -> ui.cursorcolumn -> ui.cursorline.{p/s}
847+ let primary_style = theme
848+ .try_get_exact("ui.cursorcolumn.primary")
849+ .or_else(|| theme.try_get_exact("ui.cursorcolumn"))
850+ .unwrap_or_else(|| theme.get("ui.cursorline.primary"));
851+ let secondary_style = theme
852+ .try_get_exact("ui.cursorcolumn.secondary")
853+ .or_else(|| theme.try_get_exact("ui.cursorcolumn"))
854+ .unwrap_or_else(|| theme.get("ui.cursorline.secondary"));
855+
856+ let inner_area = view.inner_area();
857+ let offset = view.offset.col;
858+
859+ let selection = doc.selection(view.id);
860+ let primary = selection.primary();
861+ for range in selection.iter() {
862+ let is_primary = primary == *range;
863+
864+ let Position { row: _, col } =
865+ visual_coords_at_pos(text, range.cursor(text), doc.tab_width());
866+ // if the cursor is horizontally in the view
867+ if col >= offset && inner_area.width > (col - offset) as u16 {
868+ let area = Rect::new(
869+ inner_area.x + (col - offset) as u16,
870+ view.area.y,
871+ 1,
872+ view.area.height,
873+ );
874+ if is_primary {
875+ surface.set_style(area, primary_style)
876+ } else {
877+ surface.set_style(area, secondary_style)
878+ }
879+ }
880+ }
881+ }
882+
833883 /// Handle events by looking them up in `self.keymaps`. Returns None
834884 /// if event was handled (a command was executed or a subkeymap was
835885 /// activated). Only KeymapResult::{NotFound, Cancelled} is returned
helix-view/src/editor.rs+3
@@ -124,6 +124,8 @@ pub struct Config {
124124 pub line_number: LineNumber,
125125 /// Highlight the lines cursors are currently on. Defaults to false.
126126 pub cursorline: bool,
127+ /// Highlight the columns cursors are currently on. Defaults to false.
128+ pub cursorcolumn: bool,
127129 /// Gutters. Default ["diagnostics", "line-numbers"]
128130 pub gutters: Vec<GutterType>,
129131 /// Middle click paste support. Defaults to true.
@@ -582,6 +584,7 @@ impl Default for Config {
582584 },
583585 line_number: LineNumber::Absolute,
584586 cursorline: false,
587+ cursorcolumn: false,
585588 gutters: vec![GutterType::Diagnostics, GutterType::LineNumbers],
586589 middle_click_paste: true,
587590 auto_pairs: AutoPairConfig::default(),
helix-view/src/theme.rs+7
@@ -277,6 +277,13 @@ impl Theme {
277277 .find_map(|s| self.styles.get(s).copied())
278278 }
279279
280+ /// Get the style of a scope, without falling back to dot separated broader
281+ /// scopes. For example if `ui.text.focus` is not defined in the theme, it
282+ /// will return `None`, even if `ui.text` is.
283+ pub fn try_get_exact(&self, scope: &str) -> Option<Style> {
284+ self.styles.get(scope).copied()
285+ }
286+
280287 #[inline]
281288 pub fn scopes(&self) -> &[String] {
282289 &self.scopes