Skip to content

Commit

Permalink
auto select current file in picker
Browse files Browse the repository at this point in the history
  • Loading branch information
mangas committed Dec 10, 2022
1 parent 0e8ea13 commit af6c68f
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 10 deletions.
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>,
) -> 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

0 comments on commit af6c68f

Please sign in to comment.