Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select current file in file picker #4905

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ impl Application {
if first.is_dir() {
std::env::set_current_dir(first).context("set current dir")?;
editor.new_file(Action::VerticalSplit);
let picker = ui::file_picker(".".into(), &config.load().editor);
let picker = ui::file_picker(".".into(), None, &config.load().editor);
compositor.push(Box::new(overlayed(picker)));
} else {
let nr_of_files = args.files.len();
Expand Down
15 changes: 12 additions & 3 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1839,7 +1839,7 @@ fn make_search_word_bounded(cx: &mut Context) {
}

fn global_search(cx: &mut Context) {
#[derive(Debug)]
#[derive(Debug, PartialEq)]
struct FileResult {
path: PathBuf,
/// 0 indexed lines
Expand Down Expand Up @@ -2007,6 +2007,7 @@ fn global_search(cx: &mut Context) {
|_editor, FileResult { path, line_num }| {
Some((path.clone().into(), Some((*line_num, *line_num))))
},
None,
);
compositor.push(Box::new(overlayed(picker)));
},
Expand Down Expand Up @@ -2286,19 +2287,24 @@ fn file_picker(cx: &mut Context) {
// We don't specify language markers, root will be the root of the current
// git repo or the current dir if we're not in a repo
let root = find_root(None, &[]);
let picker = ui::file_picker(root, &cx.editor.config());

let doc = doc!(cx.editor);
let picker = ui::file_picker(root, doc.path().cloned(), &cx.editor.config());
cx.push_layer(Box::new(overlayed(picker)));
}

fn file_picker_in_current_directory(cx: &mut Context) {
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("./"));
let picker = ui::file_picker(cwd, &cx.editor.config());

let doc = doc!(cx.editor);
let picker = ui::file_picker(cwd, doc.path().cloned(), &cx.editor.config());
cx.push_layer(Box::new(overlayed(picker)));
}

fn buffer_picker(cx: &mut Context) {
let current = view!(cx.editor).doc;

#[derive(PartialEq)]
struct BufferMeta {
id: DocumentId,
path: Option<PathBuf>,
Expand Down Expand Up @@ -2362,11 +2368,13 @@ fn buffer_picker(cx: &mut Context) {
.cursor_line(doc.text().slice(..));
Some((meta.id.into(), Some((line, line))))
},
None,
);
cx.push_layer(Box::new(overlayed(picker)));
}

fn jumplist_picker(cx: &mut Context) {
#[derive(PartialEq)]
struct JumpMeta {
id: DocumentId,
path: Option<PathBuf>,
Expand Down Expand Up @@ -2444,6 +2452,7 @@ fn jumplist_picker(cx: &mut Context) {
let line = meta.selection.primary().cursor_line(doc.text().slice(..));
Some((meta.path.clone()?.into(), Some((line, line))))
},
None,
);
cx.push_layer(Box::new(overlayed(picker)));
}
Expand Down
2 changes: 2 additions & 0 deletions helix-term/src/commands/dap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ fn thread_picker(
));
Some((path.into(), pos))
},
None,
);
compositor.push(Box::new(picker));
},
Expand Down Expand Up @@ -714,6 +715,7 @@ pub fn dap_switch_stack_frame(cx: &mut Context) {
)
})
},
None,
);
cx.push_layer(Box::new(picker))
}
4 changes: 4 additions & 0 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct DiagnosticStyles {
error: Style,
}

#[derive(PartialEq)]
struct PickerDiagnostic {
url: lsp::Url,
diag: lsp::Diagnostic,
Expand Down Expand Up @@ -241,6 +242,7 @@ fn sym_picker(
}
},
move |_editor, symbol| Some(location_to_file_location(&symbol.location)),
None,
)
.truncate_start(false)
}
Expand Down Expand Up @@ -304,6 +306,7 @@ fn diag_picker(
let location = lsp::Location::new(url.clone(), diag.range);
Some(location_to_file_location(&location))
},
None,
)
.truncate_start(false)
}
Expand Down Expand Up @@ -854,6 +857,7 @@ fn goto_impl(
jump_to_location(cx.editor, location, offset_encoding, action)
},
move |_editor, location| Some(location_to_file_location(location)),
None,
);
compositor.push(Box::new(overlayed(picker)));
}
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use fuzzy_matcher::FuzzyMatcher;
use helix_view::{graphics::Rect, Editor};
use tui::layout::Constraint;

pub trait Item {
pub trait Item: PartialEq {
/// Additional editor state that is used for label calculation.
type Data;

Expand Down
13 changes: 12 additions & 1 deletion helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ pub fn regex_prompt(
cx.push_layer(Box::new(prompt));
}

pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker<PathBuf> {
pub fn file_picker(
root: PathBuf,
default_path: Option<PathBuf>,
config: &helix_view::editor::Config,
) -> FilePicker<PathBuf> {
use ignore::{types::TypesBuilder, WalkBuilder};
use std::time::Instant;

Expand Down Expand Up @@ -215,6 +219,12 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
files.take(MAX).collect()
};

// Enforce the correct behavior based on the configuration.
let default_path = match default_path {
Some(path) if config.file_picker.highlight_current => Some(path),
_ => None,
};

log::debug!("file_picker init {:?}", Instant::now().duration_since(now));

FilePicker::new(
Expand All @@ -231,6 +241,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
}
},
|_editor, path| Some((path.clone().into(), None)),
default_path,
)
}

Expand Down
32 changes: 28 additions & 4 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ impl<T: Item> FilePicker<T> {
editor_data: T::Data,
callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static,
initial_cursor: Option<T>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called initial_item instead?

) -> Self {
let truncate_start = true;
let mut picker = Picker::new(options, editor_data, callback_fn);
let mut picker =
Picker::new(options, editor_data, callback_fn).with_default_item(initial_cursor);
picker.truncate_start = truncate_start;

Self {
Expand Down Expand Up @@ -365,6 +367,7 @@ impl Ord for PickerMatch {

pub struct Picker<T: Item> {
options: Vec<T>,
default_item: Option<T>,
editor_data: T::Data,
// filter: String,
matcher: Box<Matcher>,
Expand Down Expand Up @@ -410,7 +413,9 @@ impl<T: Item> Picker<T> {
show_preview: true,
callback_fn: Box::new(callback_fn),
completion_height: 0,
default_item: None,
};
picker.cursor = picker.find_default_item_index().unwrap_or(0);

// scoring on empty input:
// TODO: just reuse score()
Expand All @@ -428,6 +433,11 @@ impl<T: Item> Picker<T> {
picker
}

pub fn with_default_item(mut self, default_item: Option<T>) -> Self {
self.default_item = default_item;
self
}

pub fn score(&mut self) {
let now = Instant::now();

Expand All @@ -437,7 +447,7 @@ impl<T: Item> Picker<T> {
return;
}

if pattern.is_empty() {
let cursor = if pattern.is_empty() {
// Fast path for no pattern.
self.matches.clear();
self.matches
Expand All @@ -449,6 +459,8 @@ impl<T: Item> Picker<T> {
len: text.chars().count(),
}
}));

self.find_default_item_index().unwrap_or(0)
} else if pattern.starts_with(&self.previous_pattern) {
let query = FuzzyQuery::new(pattern);
// optimization: if the pattern is a more specific version of the previous one
Expand All @@ -468,6 +480,7 @@ impl<T: Item> Picker<T> {
});

self.matches.sort_unstable();
0
} else {
let query = FuzzyQuery::new(pattern);
self.matches.clear();
Expand All @@ -488,15 +501,26 @@ impl<T: Item> Picker<T> {
}),
);
self.matches.sort_unstable();
}
0
};

log::debug!("picker score {:?}", Instant::now().duration_since(now));

// reset cursor position
self.cursor = 0;
self.cursor = cursor;
self.previous_pattern.clone_from(pattern);
}

fn find_default_item_index(&self) -> Option<usize> {
self.default_item
.as_ref()
.and_then(|default_item| self.find_item_index(default_item))
}

fn find_item_index(&self, item: &T) -> Option<usize> {
self.options.iter().position(|option| item.eq(option))
}

/// Move the cursor by a number of lines, either down (`Forward`) or up (`Backward`)
pub fn move_by(&mut self, amount: usize, direction: Direction) {
let len = self.matches.len();
Expand Down
4 changes: 4 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ pub struct FilePickerConfig {
/// WalkBuilder options
/// Maximum Depth to recurse directories in file picker and global search. Defaults to `None`.
pub max_depth: Option<usize>,
/// FilePicker option
/// If set the FilePicker selects the current doc's path by default from the list, if possible.
pub highlight_current: bool,
}

impl Default for FilePickerConfig {
Expand All @@ -111,6 +114,7 @@ impl Default for FilePickerConfig {
git_global: true,
git_exclude: true,
max_depth: None,
highlight_current: true,
}
}
}
Expand Down