diff --git a/book/src/configuration.md b/book/src/configuration.md index affd497c..fdabe768 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -49,6 +49,7 @@ You may also specify a file to use for configuration with the `-c` or | `auto-info` | Whether to display infoboxes | `true` | | `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` | | `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` | +| `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | ### `[editor.statusline]` Section diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index fa437a7e..d0def9ba 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -16,14 +16,14 @@ use helix_core::{ LineEnding, Position, Range, Selection, Transaction, }; use helix_view::{ - document::Mode, + document::{Mode, SCRATCH_BUFFER_NAME}, editor::{CompleteAction, CursorShapeConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::borrow::Cow; +use std::{borrow::Cow, path::PathBuf}; use tui::buffer::Buffer as Surface; @@ -619,6 +619,59 @@ impl EditorView { } } + /// Render bufferline at the top + pub fn render_bufferline(editor: &Editor, viewport: Rect, surface: &mut Surface) { + let scratch = PathBuf::from(SCRATCH_BUFFER_NAME); // default filename to use for scratch buffer + surface.clear_with( + viewport, + editor + .theme + .try_get("ui.bufferline.background") + .unwrap_or_else(|| editor.theme.get("ui.statusline")), + ); + + let bufferline_active = editor + .theme + .try_get("ui.bufferline.active") + .unwrap_or_else(|| editor.theme.get("ui.statusline.active")); + + let bufferline_inactive = editor + .theme + .try_get("ui.bufferline") + .unwrap_or_else(|| editor.theme.get("ui.statusline.inactive")); + + let mut x = viewport.x; + let current_doc = view!(editor).doc; + + for doc in editor.documents() { + let fname = doc + .path() + .unwrap_or(&scratch) + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default(); + + let style = if current_doc == doc.id() { + bufferline_active + } else { + bufferline_inactive + }; + + let text = format!(" {}{} ", fname, if doc.is_modified() { "[+]" } else { "" }); + let used_width = viewport.x.saturating_sub(x); + let rem_width = surface.area.width.saturating_sub(used_width); + + x = surface + .set_stringn(x, viewport.y, text, rem_width as usize, style) + .0; + + if x >= surface.area.right() { + break; + } + } + } + pub fn render_gutter( editor: &Editor, doc: &Document, @@ -1291,8 +1344,27 @@ impl Component for EditorView { // clear with background color surface.set_style(area, cx.editor.theme.get("ui.background")); let config = cx.editor.config(); + + // check if bufferline should be rendered + use helix_view::editor::BufferLine; + let use_bufferline = match config.bufferline { + BufferLine::Always => true, + BufferLine::Multiple if cx.editor.documents.len() > 1 => true, + _ => false, + }; + + // -1 for commandline and -1 for bufferline + let mut editor_area = area.clip_bottom(1); + if use_bufferline { + editor_area = editor_area.clip_top(1); + } + // if the terminal size suddenly changed, we need to trigger a resize - cx.editor.resize(area.clip_bottom(1)); // -1 from bottom for commandline + cx.editor.resize(editor_area); + + if use_bufferline { + Self::render_bufferline(cx.editor, area.with_height(1), surface); + } for (view, is_focused) in cx.editor.tree.views() { let doc = cx.editor.document(view.doc).unwrap(); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ed1813b3..65e64b16 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -162,6 +162,8 @@ pub struct Config { pub rulers: Vec, #[serde(default)] pub whitespace: WhitespaceConfig, + /// Persistently display open buffers along the top + pub bufferline: BufferLine, /// Vertical indent width guides. pub indent_guides: IndentGuidesConfig, /// Whether to color modes with different colors. Defaults to `false`. @@ -367,6 +369,24 @@ impl Default for CursorShapeConfig { } } +/// bufferline render modes +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum BufferLine { + /// Don't render bufferline + Never, + /// Always render + Always, + /// Only if multiple buffers are open + Multiple, +} + +impl Default for BufferLine { + fn default() -> Self { + BufferLine::Never + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum LineNumber { @@ -554,6 +574,7 @@ impl Default for Config { terminal: get_terminal_provider(), rulers: Vec::new(), whitespace: WhitespaceConfig::default(), + bufferline: BufferLine::default(), indent_guides: IndentGuidesConfig::default(), color_modes: false, }