main
  1diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
  2index 05cf7769..4f5081bf 100644
  3--- a/helix-term/src/ui/editor.rs
  4+++ b/helix-term/src/ui/editor.rs
  5@@ -43,6 +43,7 @@ pub struct EditorView {
  6     pub(crate) last_insert: (commands::MappableCommand, Vec<InsertEvent>),
  7     pub(crate) completion: Option<Completion>,
  8     spinners: ProgressSpinners,
  9+    bufferline_info: BufferLineInfo,
 10     /// Tracks if the terminal window is focused by reaction to terminal focus events
 11     terminal_focused: bool,
 12 }
 13@@ -67,6 +68,7 @@ pub fn new(keymaps: Keymaps) -> Self {
 14             last_insert: (commands::MappableCommand::normal_mode, Vec::new()),
 15             completion: None,
 16             spinners: ProgressSpinners::default(),
 17+            bufferline_info: BufferLineInfo::default(),
 18             terminal_focused: true,
 19         }
 20     }
 21@@ -683,7 +685,7 @@ pub fn tabstop_highlights(doc: &Document, theme: &Theme) -> Option<OverlayHighli
 22     }
 23 
 24     /// Render bufferline at the top
 25-    pub fn render_bufferline(editor: &Editor, viewport: Rect, surface: &mut Surface) {
 26+    pub fn render_bufferline(&mut self, editor: &Editor, viewport: Rect, surface: &mut Surface) {
 27         let scratch = PathBuf::from(SCRATCH_BUFFER_NAME); // default filename to use for scratch buffer
 28         surface.clear_with(
 29             viewport,
 30@@ -706,6 +708,8 @@ pub fn render_bufferline(editor: &Editor, viewport: Rect, surface: &mut Surface)
 31         let mut x = viewport.x;
 32         let current_doc = view!(editor).doc;
 33 
 34+        self.bufferline_info.clear();
 35+
 36         for doc in editor.documents() {
 37             let fname = doc
 38                 .path()
 39@@ -725,9 +729,14 @@ pub fn render_bufferline(editor: &Editor, viewport: Rect, surface: &mut Surface)
 40             let used_width = viewport.x.saturating_sub(x);
 41             let rem_width = surface.area.width.saturating_sub(used_width);
 42 
 43+            let start_x = x;
 44             x = surface
 45                 .set_stringn(x, viewport.y, &text, rem_width as usize, style)
 46                 .0;
 47+            let end_x = x.min(surface.area.right());
 48+
 49+            self.bufferline_info
 50+                .add_buffer_info(doc.id(), start_x..end_x);
 51 
 52             if x >= surface.area.right() {
 53                 break;
 54@@ -1396,6 +1405,14 @@ fn handle_mouse_event(
 55             MouseEventKind::Down(MouseButton::Left) => {
 56                 let editor = &mut cxt.editor;
 57 
 58+                if is_bufferline_visible(editor) && row == 0 {
 59+                    if let Some(buffer_info) = self.bufferline_info.get_clicked_buffer(column) {
 60+                        editor.switch(buffer_info.document_id, helix_view::editor::Action::Replace);
 61+                    }
 62+
 63+                    return EventResult::Consumed(None);
 64+                }
 65+
 66                 if let Some((pos, view_id)) = pos_and_view(editor, row, column, true) {
 67                     editor.focus(view_id);
 68 
 69@@ -1778,12 +1795,7 @@ fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
 70         surface.set_style(area, cx.editor.theme.get("ui.background"));
 71         let config = cx.editor.config();
 72 
 73-        // check if bufferline should be rendered
 74-        let use_bufferline = match config.bufferline {
 75-            BufferLine::Always => true,
 76-            BufferLine::Multiple if cx.editor.documents.len() > 1 => true,
 77-            _ => false,
 78-        };
 79+        let use_bufferline = is_bufferline_visible(cx.editor);
 80 
 81         let mut area = area;
 82 
 83@@ -1811,7 +1823,7 @@ fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
 84         cx.editor.resize(editor_area);
 85 
 86         if use_bufferline {
 87-            Self::render_bufferline(cx.editor, area.with_height(1), surface);
 88+            self.render_bufferline(cx.editor, area.with_height(1), surface);
 89         }
 90 
 91         let views: Vec<(ViewId, bool)> = {
 92@@ -1936,6 +1948,47 @@ fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind)
 93     }
 94 }
 95 
 96+#[derive(Debug, Default)]
 97+struct BufferLineInfo {
 98+    visible_buffers: Vec<BufferInfo>,
 99+}
100+
101+impl BufferLineInfo {
102+    fn clear(&mut self) {
103+        self.visible_buffers.clear();
104+    }
105+
106+    fn add_buffer_info(&mut self, document_id: DocumentId, columns: std::ops::Range<u16>) {
107+        self.visible_buffers.push(BufferInfo {
108+            document_id,
109+            columns,
110+        });
111+    }
112+
113+    fn get_clicked_buffer(&self, column: u16) -> Option<&BufferInfo> {
114+        self.visible_buffers
115+            .iter()
116+            .find(|cell| cell.columns.contains(&column))
117+    }
118+}
119+
120+#[derive(Debug)]
121+struct BufferInfo {
122+    document_id: DocumentId,
123+    // The bufferline column span used to show the document name
124+    columns: std::ops::Range<u16>,
125+}
126+
127+fn is_bufferline_visible(editor: &Editor) -> bool {
128+    let config = editor.config();
129+
130+    match config.bufferline {
131+        BufferLine::Always => true,
132+        BufferLine::Multiple => editor.documents.len() > 1,
133+        BufferLine::Never => false,
134+    }
135+}
136+
137 fn canonicalize_key(key: &mut KeyEvent) {
138     if let KeyEvent {
139         code: KeyCode::Char(_),