mirror of https://github.com/helix-editor/helix
Show path in file picker and explorer
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.pull/12806/head
parent
0815b52e09
commit
9dc6fb8216
|
@ -32,6 +32,7 @@ pub use text::Text;
|
||||||
use helix_view::Editor;
|
use helix_view::Editor;
|
||||||
use tui::text::{Span, Spans};
|
use tui::text::{Span, Spans};
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{error::Error, path::PathBuf};
|
use std::{error::Error, path::PathBuf};
|
||||||
|
|
||||||
|
@ -185,6 +186,23 @@ pub fn raw_regex_prompt(
|
||||||
cx.push_layer(Box::new(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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FilePickerData {
|
pub struct FilePickerData {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
|
@ -246,7 +264,7 @@ pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker {
|
||||||
log::debug!("file_picker init {:?}", Instant::now().duration_since(now));
|
log::debug!("file_picker init {:?}", Instant::now().duration_since(now));
|
||||||
|
|
||||||
let columns = [PickerColumn::new(
|
let columns = [PickerColumn::new(
|
||||||
"path",
|
get_relative_dir(&root),
|
||||||
|item: &PathBuf, data: &FilePickerData| {
|
|item: &PathBuf, data: &FilePickerData| {
|
||||||
let path = item.strip_prefix(&data.root).unwrap_or(item);
|
let path = item.strip_prefix(&data.root).unwrap_or(item);
|
||||||
let mut spans = Vec::with_capacity(3);
|
let mut spans = Vec::with_capacity(3);
|
||||||
|
@ -274,6 +292,7 @@ pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker {
|
||||||
cx.editor.set_error(err);
|
cx.editor.set_error(err);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.always_show_headers()
|
||||||
.with_preview(|_editor, path| Some((path.as_path().into(), None)));
|
.with_preview(|_editor, path| Some((path.as_path().into(), None)));
|
||||||
let injector = picker.injector();
|
let injector = picker.injector();
|
||||||
let timeout = std::time::Instant::now() + std::time::Duration::from_millis(30);
|
let timeout = std::time::Instant::now() + std::time::Duration::from_millis(30);
|
||||||
|
@ -307,7 +326,7 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result<FileExplorer, std
|
||||||
let directory_content = directory_content(&root)?;
|
let directory_content = directory_content(&root)?;
|
||||||
|
|
||||||
let columns = [PickerColumn::new(
|
let columns = [PickerColumn::new(
|
||||||
"path",
|
get_relative_dir(&root),
|
||||||
|(path, is_dir): &(PathBuf, bool), (root, directory_style): &(PathBuf, Style)| {
|
|(path, is_dir): &(PathBuf, bool), (root, directory_style): &(PathBuf, Style)| {
|
||||||
let name = path.strip_prefix(root).unwrap_or(path).to_string_lossy();
|
let name = path.strip_prefix(root).unwrap_or(path).to_string_lossy();
|
||||||
if *is_dir {
|
if *is_dir {
|
||||||
|
@ -345,6 +364,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)));
|
.with_preview(|_editor, (path, _is_dir)| Some((path.as_path().into(), None)));
|
||||||
|
|
||||||
Ok(picker)
|
Ok(picker)
|
||||||
|
|
|
@ -241,6 +241,7 @@ type DynQueryCallback<T, D> =
|
||||||
pub struct Picker<T: 'static + Send + Sync, D: 'static> {
|
pub struct Picker<T: 'static + Send + Sync, D: 'static> {
|
||||||
columns: Arc<[Column<T, D>]>,
|
columns: Arc<[Column<T, D>]>,
|
||||||
primary_column: usize,
|
primary_column: usize,
|
||||||
|
always_show_headers: bool,
|
||||||
editor_data: Arc<D>,
|
editor_data: Arc<D>,
|
||||||
version: Arc<AtomicUsize>,
|
version: Arc<AtomicUsize>,
|
||||||
matcher: Nucleo<T>,
|
matcher: Nucleo<T>,
|
||||||
|
@ -373,6 +374,7 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
|
||||||
Self {
|
Self {
|
||||||
columns,
|
columns,
|
||||||
primary_column: default_column,
|
primary_column: default_column,
|
||||||
|
always_show_headers: false,
|
||||||
matcher,
|
matcher,
|
||||||
editor_data,
|
editor_data,
|
||||||
version,
|
version,
|
||||||
|
@ -424,6 +426,11 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn always_show_headers(mut self) -> Self {
|
||||||
|
self.always_show_headers = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_dynamic_query(
|
pub fn with_dynamic_query(
|
||||||
mut self,
|
mut self,
|
||||||
callback: DynQueryCallback<T, D>,
|
callback: DynQueryCallback<T, D>,
|
||||||
|
@ -818,7 +825,7 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
|
||||||
.widths(&self.widths);
|
.widths(&self.widths);
|
||||||
|
|
||||||
// -- Header
|
// -- 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 active_column = self.query.active_column(self.prompt.position());
|
||||||
let header_style = cx.editor.theme.get("ui.picker.header");
|
let header_style = cx.editor.theme.get("ui.picker.header");
|
||||||
let header_column_style = cx.editor.theme.get("ui.picker.header.column");
|
let header_column_style = cx.editor.theme.get("ui.picker.header.column");
|
||||||
|
|
Loading…
Reference in New Issue