Skip to content

Commit

Permalink
Show path in file picker and explorer
Browse files Browse the repository at this point in the history
The file picker and explorer can each be opened in several ways, each
causing it to have a different root path. What's more, the file explorer
can change its path while you have it open.

This can make it very difficult to keep track of the root directory for
these pickers, so we add it as a header.

If desired, we could alternatively make this a configuration option, but
I see little downside to always including it.
  • Loading branch information
paholg committed Feb 16, 2025
1 parent c36ed6a commit 381e2e5
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
24 changes: 22 additions & 2 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use text::Text;
use helix_view::Editor;
use tui::text::Span;

use std::borrow::Cow;
use std::path::Path;
use std::{error::Error, path::PathBuf};

Expand Down Expand Up @@ -185,6 +186,23 @@ pub fn raw_regex_prompt(
cx.push_layer(Box::new(prompt));
}

/// Get the relative directory as a string.
///
/// NOTE: Assumes the given path is a directory, and will always output wiht a
/// trailing slash.
fn get_relative_dir(path: &Path) -> Cow<'static, str> {
let path = helix_stdx::path::get_relative_path(path);
if path.components().next().is_none() {
"./".into()
} else {
let mut str = path.to_string_lossy().into_owned();
if !str.ends_with('/') {
str.push('/');
}
str.into()
}
}

type FilePicker = Picker<PathBuf, PathBuf>;

pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker {
Expand Down Expand Up @@ -235,7 +253,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
log::debug!("file_picker init {:?}", Instant::now().duration_since(now));

let columns = [PickerColumn::new(
"path",
get_relative_dir(&root),
|item: &PathBuf, root: &PathBuf| {
item.strip_prefix(root)
.unwrap_or(item)
Expand All @@ -253,6 +271,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
cx.editor.set_error(err);
}
})
.always_show_headers()
.with_preview(|_editor, path| Some((path.as_path().into(), None)));
let injector = picker.injector();
let timeout = std::time::Instant::now() + std::time::Duration::from_millis(30);
Expand Down Expand Up @@ -286,7 +305,7 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result<FileExplorer, std
let directory_content = directory_content(&root)?;

let columns = [PickerColumn::new(
"path",
get_relative_dir(&root),
|(path, is_dir): &(PathBuf, bool), (root, directory_style): &(PathBuf, Style)| {
let name = path.strip_prefix(root).unwrap_or(path).to_string_lossy();
if *is_dir {
Expand Down Expand Up @@ -324,6 +343,7 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result<FileExplorer, std
}
},
)
.always_show_headers()
.with_preview(|_editor, (path, _is_dir)| Some((path.as_path().into(), None)));

Ok(picker)
Expand Down
9 changes: 8 additions & 1 deletion helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ type DynQueryCallback<T, D> =
pub struct Picker<T: 'static + Send + Sync, D: 'static> {
columns: Arc<[Column<T, D>]>,
primary_column: usize,
always_show_headers: bool,
editor_data: Arc<D>,
version: Arc<AtomicUsize>,
matcher: Nucleo<T>,
Expand Down Expand Up @@ -373,6 +374,7 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
Self {
columns,
primary_column: default_column,
always_show_headers: false,
matcher,
editor_data,
version,
Expand Down Expand Up @@ -424,6 +426,11 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
self
}

pub fn always_show_headers(mut self) -> Self {
self.always_show_headers = true;
self
}

pub fn with_dynamic_query(
mut self,
callback: DynQueryCallback<T, D>,
Expand Down Expand Up @@ -818,7 +825,7 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
.widths(&self.widths);

// -- Header
if self.columns.len() > 1 {
if self.always_show_headers || self.columns.len() > 1 {
let active_column = self.query.active_column(self.prompt.position());
let header_style = cx.editor.theme.get("ui.picker.header");
let header_column_style = cx.editor.theme.get("ui.picker.header.column");
Expand Down

0 comments on commit 381e2e5

Please sign in to comment.