Add support for clicking on the bufferline to select a buffer
Co-authored-by: Kyle Smith <kyle.smith@salsify.com>
This commit is contained in:
parent
5ba97ba41e
commit
3af529d868
1 changed files with 63 additions and 9 deletions
|
@ -29,7 +29,7 @@ use helix_view::{
|
||||||
graphics::{Color, CursorKind, Modifier, Rect, Style},
|
graphics::{Color, CursorKind, Modifier, Rect, Style},
|
||||||
input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind},
|
input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind},
|
||||||
keyboard::{KeyCode, KeyModifiers},
|
keyboard::{KeyCode, KeyModifiers},
|
||||||
Document, Editor, Theme, View,
|
Document, DocumentId, Editor, Theme, View,
|
||||||
};
|
};
|
||||||
use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, sync::Arc};
|
use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ pub struct EditorView {
|
||||||
pub(crate) last_insert: (commands::MappableCommand, Vec<InsertEvent>),
|
pub(crate) last_insert: (commands::MappableCommand, Vec<InsertEvent>),
|
||||||
pub(crate) completion: Option<Completion>,
|
pub(crate) completion: Option<Completion>,
|
||||||
spinners: ProgressSpinners,
|
spinners: ProgressSpinners,
|
||||||
|
bufferline_info: BufferLineInfo,
|
||||||
/// Tracks if the terminal window is focused by reaction to terminal focus events
|
/// Tracks if the terminal window is focused by reaction to terminal focus events
|
||||||
terminal_focused: bool,
|
terminal_focused: bool,
|
||||||
}
|
}
|
||||||
|
@ -72,6 +73,7 @@ impl EditorView {
|
||||||
last_insert: (commands::MappableCommand::normal_mode, Vec::new()),
|
last_insert: (commands::MappableCommand::normal_mode, Vec::new()),
|
||||||
completion: None,
|
completion: None,
|
||||||
spinners: ProgressSpinners::default(),
|
spinners: ProgressSpinners::default(),
|
||||||
|
bufferline_info: BufferLineInfo::default(),
|
||||||
terminal_focused: true,
|
terminal_focused: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,7 +595,7 @@ impl EditorView {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render bufferline at the top
|
/// Render bufferline at the top
|
||||||
pub fn render_bufferline(editor: &Editor, viewport: Rect, surface: &mut Surface) {
|
pub fn render_bufferline(&mut self, editor: &Editor, viewport: Rect, surface: &mut Surface) {
|
||||||
let scratch = PathBuf::from(SCRATCH_BUFFER_NAME); // default filename to use for scratch buffer
|
let scratch = PathBuf::from(SCRATCH_BUFFER_NAME); // default filename to use for scratch buffer
|
||||||
surface.clear_with(
|
surface.clear_with(
|
||||||
viewport,
|
viewport,
|
||||||
|
@ -616,6 +618,8 @@ impl EditorView {
|
||||||
let mut x = viewport.x;
|
let mut x = viewport.x;
|
||||||
let current_doc = view!(editor).doc;
|
let current_doc = view!(editor).doc;
|
||||||
|
|
||||||
|
self.bufferline_info.clear();
|
||||||
|
|
||||||
for doc in editor.documents() {
|
for doc in editor.documents() {
|
||||||
let fname = doc
|
let fname = doc
|
||||||
.path()
|
.path()
|
||||||
|
@ -635,9 +639,14 @@ impl EditorView {
|
||||||
let used_width = viewport.x.saturating_sub(x);
|
let used_width = viewport.x.saturating_sub(x);
|
||||||
let rem_width = surface.area.width.saturating_sub(used_width);
|
let rem_width = surface.area.width.saturating_sub(used_width);
|
||||||
|
|
||||||
|
let start_x = x;
|
||||||
x = surface
|
x = surface
|
||||||
.set_stringn(x, viewport.y, text, rem_width as usize, style)
|
.set_stringn(x, viewport.y, text, rem_width as usize, style)
|
||||||
.0;
|
.0;
|
||||||
|
let end_x = x.min(surface.area.right());
|
||||||
|
|
||||||
|
self.bufferline_info
|
||||||
|
.add_buffer_info(doc.id(), start_x..end_x);
|
||||||
|
|
||||||
if x >= surface.area.right() {
|
if x >= surface.area.right() {
|
||||||
break;
|
break;
|
||||||
|
@ -1139,6 +1148,14 @@ impl EditorView {
|
||||||
MouseEventKind::Down(MouseButton::Left) => {
|
MouseEventKind::Down(MouseButton::Left) => {
|
||||||
let editor = &mut cxt.editor;
|
let editor = &mut cxt.editor;
|
||||||
|
|
||||||
|
if is_bufferline_visible(editor) && row == 0 {
|
||||||
|
if let Some(buffer_info) = self.bufferline_info.get_clicked_buffer(column) {
|
||||||
|
editor.switch(buffer_info.document_id, helix_view::editor::Action::Replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EventResult::Consumed(None);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((pos, view_id)) = pos_and_view(editor, row, column, true) {
|
if let Some((pos, view_id)) = pos_and_view(editor, row, column, true) {
|
||||||
let prev_view_id = view!(editor).id;
|
let prev_view_id = view!(editor).id;
|
||||||
let doc = doc_mut!(editor, &view!(editor, view_id).doc);
|
let doc = doc_mut!(editor, &view!(editor, view_id).doc);
|
||||||
|
@ -1480,12 +1497,7 @@ impl Component for EditorView {
|
||||||
let config = cx.editor.config();
|
let config = cx.editor.config();
|
||||||
|
|
||||||
// check if bufferline should be rendered
|
// check if bufferline should be rendered
|
||||||
use helix_view::editor::BufferLine;
|
let use_bufferline = is_bufferline_visible(cx.editor);
|
||||||
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
|
// -1 for commandline and -1 for bufferline
|
||||||
let mut editor_area = area.clip_bottom(1);
|
let mut editor_area = area.clip_bottom(1);
|
||||||
|
@ -1497,7 +1509,7 @@ impl Component for EditorView {
|
||||||
cx.editor.resize(editor_area);
|
cx.editor.resize(editor_area);
|
||||||
|
|
||||||
if use_bufferline {
|
if use_bufferline {
|
||||||
Self::render_bufferline(cx.editor, area.with_height(1), surface);
|
self.render_bufferline(cx.editor, area.with_height(1), surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (view, is_focused) in cx.editor.tree.views() {
|
for (view, is_focused) in cx.editor.tree.views() {
|
||||||
|
@ -1592,6 +1604,48 @@ impl Component for EditorView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct BufferLineInfo {
|
||||||
|
visible_buffers: Vec<BufferInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufferLineInfo {
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.visible_buffers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_buffer_info(&mut self, document_id: DocumentId, columns: std::ops::Range<u16>) {
|
||||||
|
self.visible_buffers.push(BufferInfo {
|
||||||
|
document_id,
|
||||||
|
columns,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_clicked_buffer(&self, column: u16) -> Option<&BufferInfo> {
|
||||||
|
self.visible_buffers
|
||||||
|
.iter()
|
||||||
|
.find(|cell| cell.columns.contains(&column))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BufferInfo {
|
||||||
|
document_id: DocumentId,
|
||||||
|
// The bufferline column span used to show the document name
|
||||||
|
columns: std::ops::Range<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_bufferline_visible(editor: &Editor) -> bool {
|
||||||
|
use helix_view::editor::BufferLine;
|
||||||
|
let config = editor.config();
|
||||||
|
|
||||||
|
match config.bufferline {
|
||||||
|
BufferLine::Always => true,
|
||||||
|
BufferLine::Multiple if editor.documents.len() > 1 => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn canonicalize_key(key: &mut KeyEvent) {
|
fn canonicalize_key(key: &mut KeyEvent) {
|
||||||
if let KeyEvent {
|
if let KeyEvent {
|
||||||
code: KeyCode::Char(_),
|
code: KeyCode::Char(_),
|
||||||
|
|
Loading…
Reference in a new issue