aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/ui/editor.rs
diff options
context:
space:
mode:
authorMr. E2022-07-18 00:57:01 +0000
committerGitHub2022-07-18 00:57:01 +0000
commitdbf68e0370981dc4ad0fa74596b57347f7048fab (patch)
treef0b04c445708158827b611ce602235bb5ff72142 /helix-term/src/ui/editor.rs
parent43761d426cb0c508bfcea93c4bf1d08949e6c7c1 (diff)
Customizable/configurable status line (#2434)
* feat(statusline): add the file type (language id) to the status line * refactor(statusline): move the statusline implementation into an own struct * refactor(statusline): split the statusline implementation into different functions * refactor(statusline): Append elements using a consistent API This is a preparation for the configurability which is about to be implemented. * refactor(statusline): implement render_diagnostics() This avoid cluttering the render() function and will simplify configurability. * feat(statusline): make the status line configurable * refactor(statusline): make clippy happy * refactor(statusline): avoid intermediate StatusLineObject Use a more functional approach to obtain render functions and write to the buffers, and avoid an intermediate StatusLineElement object. * fix(statusline): avoid rendering the left elements twice * refactor(statusline): make clippy happy again * refactor(statusline): rename `buffer` into `parts` * refactor(statusline): ensure the match is exhaustive * fix(statusline): avoid an overflow when calculating the maximal center width * chore(statusline): Describe the statusline configurability in the book * chore(statusline): Correct and add documentation * refactor(statusline): refactor some code following the code review Avoid very small helper functions for the diagnositcs and inline them instead. Rename the config field `status_line` to `statusline` to remain consistent with `bufferline`. * chore(statusline): adjust documentation following the config field refactoring * revert(statusline): revert regression introduced by c0a1870 * chore(statusline): slight adjustment in the configuration documentation * feat(statusline): integrate changes from #2676 after rebasing * refactor(statusline): remove the StatusLine struct Because none of the functions need `Self` and all of them are in an own file, there is no explicit need for the struct. * fix(statusline): restore the configurability of color modes The configuration was ignored after reintegrating the changes of #2676 in 8d28f95. * fix(statusline): remove the spinner padding * refactor(statusline): remove unnecessary format!()
Diffstat (limited to 'helix-term/src/ui/editor.rs')
-rw-r--r--helix-term/src/ui/editor.rs163
1 files changed, 8 insertions, 155 deletions
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index a7c67a21..9b8bf8eb 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -7,7 +7,6 @@ use crate::{
};
use helix_core::{
- coords_at_pos, encoding,
graphemes::{
ensure_grapheme_boundary_next_byte, next_grapheme_boundary, prev_grapheme_boundary,
},
@@ -17,7 +16,7 @@ use helix_core::{
LineEnding, Position, Range, Selection, Transaction,
};
use helix_view::{
- document::{Mode, SCRATCH_BUFFER_NAME},
+ document::Mode,
editor::{CompleteAction, CursorShapeConfig},
graphics::{Color, CursorKind, Modifier, Rect, Style},
input::KeyEvent,
@@ -29,6 +28,8 @@ use std::borrow::Cow;
use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind};
use tui::buffer::Buffer as Surface;
+use super::statusline;
+
pub struct EditorView {
pub keymaps: Keymaps,
on_next_key: Option<Box<dyn FnOnce(&mut commands::Context, KeyEvent)>>,
@@ -161,7 +162,11 @@ impl EditorView {
.area
.clip_top(view.area.height.saturating_sub(1))
.clip_bottom(1); // -1 from bottom to remove commandline
- self.render_statusline(editor, doc, view, statusline_area, surface, is_focused);
+
+ let mut context =
+ statusline::RenderContext::new(editor, doc, view, is_focused, &self.spinners);
+
+ statusline::render(&mut context, statusline_area, surface);
}
pub fn render_rulers(
@@ -730,158 +735,6 @@ impl EditorView {
}
}
- pub fn render_statusline(
- &self,
- editor: &Editor,
- doc: &Document,
- view: &View,
- viewport: Rect,
- surface: &mut Surface,
- is_focused: bool,
- ) {
- use tui::text::{Span, Spans};
-
- //-------------------------------
- // Left side of the status line.
- //-------------------------------
-
- let theme = &editor.theme;
- let (mode, mode_style) = match doc.mode() {
- Mode::Insert => (" INS ", theme.get("ui.statusline.insert")),
- Mode::Select => (" SEL ", theme.get("ui.statusline.select")),
- Mode::Normal => (" NOR ", theme.get("ui.statusline.normal")),
- };
- let progress = doc
- .language_server()
- .and_then(|srv| {
- self.spinners
- .get(srv.id())
- .and_then(|spinner| spinner.frame())
- })
- .unwrap_or("");
-
- let base_style = if is_focused {
- theme.get("ui.statusline")
- } else {
- theme.get("ui.statusline.inactive")
- };
- // statusline
- surface.set_style(viewport.with_height(1), base_style);
- if is_focused {
- let color_modes = editor.config().color_modes;
- surface.set_string(
- viewport.x,
- viewport.y,
- mode,
- if color_modes { mode_style } else { base_style },
- );
- }
- surface.set_string(viewport.x + 5, viewport.y, progress, base_style);
-
- //-------------------------------
- // Right side of the status line.
- //-------------------------------
-
- let mut right_side_text = Spans::default();
-
- // Compute the individual info strings and add them to `right_side_text`.
-
- // Diagnostics
- let diags = doc.diagnostics().iter().fold((0, 0), |mut counts, diag| {
- use helix_core::diagnostic::Severity;
- match diag.severity {
- Some(Severity::Warning) => counts.0 += 1,
- Some(Severity::Error) | None => counts.1 += 1,
- _ => {}
- }
- counts
- });
- let (warnings, errors) = diags;
- let warning_style = theme.get("warning");
- let error_style = theme.get("error");
- for i in 0..2 {
- let (count, style) = match i {
- 0 => (warnings, warning_style),
- 1 => (errors, error_style),
- _ => unreachable!(),
- };
- if count == 0 {
- continue;
- }
- let style = base_style.patch(style);
- right_side_text.0.push(Span::styled("●", style));
- right_side_text
- .0
- .push(Span::styled(format!(" {} ", count), base_style));
- }
-
- // Selections
- let sels_count = doc.selection(view.id).len();
- right_side_text.0.push(Span::styled(
- format!(
- " {} sel{} ",
- sels_count,
- if sels_count == 1 { "" } else { "s" }
- ),
- base_style,
- ));
-
- // Position
- let pos = coords_at_pos(
- doc.text().slice(..),
- doc.selection(view.id)
- .primary()
- .cursor(doc.text().slice(..)),
- );
- right_side_text.0.push(Span::styled(
- format!(" {}:{} ", pos.row + 1, pos.col + 1), // Convert to 1-indexing.
- base_style,
- ));
-
- let enc = doc.encoding();
- if enc != encoding::UTF_8 {
- right_side_text
- .0
- .push(Span::styled(format!(" {} ", enc.name()), base_style));
- }
-
- // Render to the statusline.
- surface.set_spans(
- viewport.x
- + viewport
- .width
- .saturating_sub(right_side_text.width() as u16),
- viewport.y,
- &right_side_text,
- right_side_text.width() as u16,
- );
-
- //-------------------------------
- // Middle / File path / Title
- //-------------------------------
- let title = {
- let rel_path = doc.relative_path();
- let path = rel_path
- .as_ref()
- .map(|p| p.to_string_lossy())
- .unwrap_or_else(|| SCRATCH_BUFFER_NAME.into());
- format!("{}{}", path, if doc.is_modified() { "[+]" } else { "" })
- };
-
- surface.set_string_truncated(
- viewport.x + 8, // 8: 1 space + 3 char mode string + 1 space + 1 spinner + 1 space
- viewport.y,
- &title,
- viewport
- .width
- .saturating_sub(6)
- .saturating_sub(right_side_text.width() as u16 + 1) as usize, // "+ 1": a space between the title and the selection info
- |_| base_style,
- true,
- true,
- );
- }
-
/// Handle events by looking them up in `self.keymaps`. Returns None
/// if event was handled (a command was executed or a subkeymap was
/// activated). Only KeymapResult::{NotFound, Cancelled} is returned