From 2773bb0fa721b86f54cb7e81427f5e0d3663fda4 Mon Sep 17 00:00:00 2001 From: Erasin Date: Sat, 31 May 2025 19:03:50 +0800 Subject: [PATCH 1/2] feat: statusline element style --- helix-term/src/ui/statusline.rs | 25 +++++++++++++++++++------ helix-view/src/editor.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index ea3d27bd6..9f7099329 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -68,6 +68,7 @@ pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface for element_id in &config.statusline.left { let render = get_render_function(*element_id); (render)(context, |context, span| { + let base_style = statusline_style(context, &element_id.to_string()); append(&mut context.parts.left, span, base_style) }); } @@ -84,6 +85,7 @@ pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface for element_id in &config.statusline.right { let render = get_render_function(*element_id); (render)(context, |context, span| { + let base_style = statusline_style(context, &element_id.to_string()); append(&mut context.parts.right, span, base_style) }) } @@ -103,6 +105,7 @@ pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface for element_id in &config.statusline.center { let render = get_render_function(*element_id); (render)(context, |context, span| { + let base_style = statusline_style(context, &element_id.to_string()); append(&mut context.parts.center, span, base_style) }) } @@ -161,6 +164,18 @@ where } } +fn statusline_style(context: &RenderContext, scope: &str) -> Style { + let scope = format!("ui.statusline.{scope}"); + let visible = context.focused; + let config = context.editor.config(); + + if visible && config.color_modes { + context.editor.theme.get(&scope) + } else { + Style::default() + } +} + fn render_mode<'a, F>(context: &mut RenderContext<'a>, write: F) where F: Fn(&mut RenderContext<'a>, Span<'a>) + Copy, @@ -522,10 +537,9 @@ fn render_separator<'a, F>(context: &mut RenderContext<'a>, write: F) where F: Fn(&mut RenderContext<'a>, Span<'a>) + Copy, { - let sep = &context.editor.config().statusline.separator; - let style = context.editor.theme.get("ui.statusline.separator"); + let sep = context.editor.config().statusline.separator.clone(); - write(context, Span::styled(sep.to_string(), style)); + write(context, sep.into()); } fn render_spacer<'a, F>(context: &mut RenderContext<'a>, write: F) @@ -561,11 +575,10 @@ fn render_file_indent_style<'a, F>(context: &mut RenderContext<'a>, write: F) where F: Fn(&mut RenderContext<'a>, Span<'a>) + Copy, { - let style = context.doc.indent_style; - + let indent_style = context.doc.indent_style; write( context, - match style { + match indent_style { IndentStyle::Tabs => " tabs ".into(), IndentStyle::Spaces(indent) => { format!(" {} space{} ", indent, if indent == 1 { "" } else { "s" }).into() diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index bc811b88b..59358a2e3 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -27,6 +27,7 @@ use std::{ borrow::Cow, cell::Cell, collections::{BTreeMap, HashMap, HashSet}, + fmt::Display, fs, io::{self, stdin}, num::NonZeroUsize, @@ -620,6 +621,37 @@ pub enum StatusLineElement { Register, } +impl Display for StatusLineElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use StatusLineElement::*; + let element = match self { + Mode => "mode", + Spinner => "spinner", + FileBaseName => "file-base-name", + FileName => "file-name", + FileAbsolutePath => "file-absolute-path", + FileModificationIndicator => "file-modification-indicator", + ReadOnlyIndicator => "read-only-indicator", + FileEncoding => "file-encoding", + FileLineEnding => "file-line-ending", + FileIndentStyle => "file-indent-style", + FileType => "file-type", + Diagnostics => "diagnostics", + WorkspaceDiagnostics => "workspace-diagnostics", + Selections => "selections", + PrimarySelectionLength => "primary-selection-length", + Position => "position", + Separator => "separator", + PositionPercentage => "position-percentage", + TotalLineNumbers => "total-line-numbers", + Spacer => "spacer", + VersionControl => "version-control", + Register => "register", + }; + write!(f, "{element}") + } +} + // Cursor shape is read and used on every rendered frame and so needs // to be fast. Therefore we avoid a hashmap and use an enum indexed array. #[derive(Debug, Clone, PartialEq, Eq)] From 738bdb429dc4c9b88de0350f431c97d9cadc451c Mon Sep 17 00:00:00 2001 From: Erasin Date: Sun, 1 Jun 2025 22:33:20 +0800 Subject: [PATCH 2/2] feat: statusline elements theme support --- book/src/themes.md | 2 +- helix-term/src/ui/statusline.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index dc377db17..31ac36a59 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -285,7 +285,7 @@ These scopes are used for theming the editor interface: | `ui.gutter.selected` | Gutter for the line the cursor is on | | `ui.linenr` | Line numbers | | `ui.linenr.selected` | Line number for the line the cursor is on | -| `ui.statusline` | Statusline | +| `ui.statusline` | Statusline (support element style e.g. `ui.statusline.file-name`) | | `ui.statusline.inactive` | Statusline (unfocused document) | | `ui.statusline.normal` | Statusline mode during normal mode ([only if `editor.color-modes` is enabled][editor-section]) | | `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) | diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 9f7099329..f08179ab6 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -165,11 +165,15 @@ where } fn statusline_style(context: &RenderContext, scope: &str) -> Style { - let scope = format!("ui.statusline.{scope}"); - let visible = context.focused; + let scope = if context.focused { + format!("ui.statusline.{scope}") + } else { + format!("ui.statusline.inactive.{scope}") + }; + let config = context.editor.config(); - if visible && config.color_modes { + if config.color_modes { context.editor.theme.get(&scope) } else { Style::default() @@ -411,7 +415,7 @@ where let maxrows = context.doc.text().len_lines(); write( context, - format!("{}%", (position.row + 1) * 100 / maxrows).into(), + format!(" {}% ", (position.row + 1) * 100 / maxrows).into(), ); } @@ -496,11 +500,7 @@ fn render_file_modification_indicator<'a, F>(context: &mut RenderContext<'a>, wr where F: Fn(&mut RenderContext<'a>, Span<'a>) + Copy, { - let title = if context.doc.is_modified() { - "[+]" - } else { - " " - }; + let title = if context.doc.is_modified() { "[+]" } else { "" }; write(context, title.into()); }