aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/commands.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/commands.rs')
-rw-r--r--helix-term/src/commands.rs149
1 files changed, 92 insertions, 57 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 59ca2e3b..df4867fc 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -45,6 +45,7 @@ use movement::Movement;
use crate::{
args,
compositor::{self, Component, Compositor},
+ keymap::ReverseKeymap,
ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent},
};
@@ -1744,8 +1745,42 @@ fn search_selection(cx: &mut Context) {
}
fn global_search(cx: &mut Context) {
- let (all_matches_sx, all_matches_rx) =
- tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
+ #[derive(Debug)]
+ struct FileResult {
+ path: PathBuf,
+ /// 0 indexed lines
+ line_num: usize,
+ }
+
+ impl FileResult {
+ fn new(path: &Path, line_num: usize) -> Self {
+ Self {
+ path: path.to_path_buf(),
+ line_num,
+ }
+ }
+ }
+
+ impl ui::menu::Item for FileResult {
+ type Data = Option<PathBuf>;
+
+ fn label(&self, current_path: &Self::Data) -> Spans {
+ let relative_path = helix_core::path::get_relative_path(&self.path)
+ .to_string_lossy()
+ .into_owned();
+ if current_path
+ .as_ref()
+ .map(|p| p == &self.path)
+ .unwrap_or(false)
+ {
+ format!("{} (*)", relative_path).into()
+ } else {
+ relative_path.into()
+ }
+ }
+ }
+
+ let (all_matches_sx, all_matches_rx) = tokio::sync::mpsc::unbounded_channel::<FileResult>();
let config = cx.editor.config();
let smart_case = config.search.smart_case;
let file_picker_config = config.file_picker.clone();
@@ -1809,7 +1844,7 @@ fn global_search(cx: &mut Context) {
entry.path(),
sinks::UTF8(|line_num, _| {
all_matches_sx
- .send((line_num as usize - 1, entry.path().to_path_buf()))
+ .send(FileResult::new(entry.path(), line_num as usize - 1))
.unwrap();
Ok(true)
@@ -1836,7 +1871,7 @@ fn global_search(cx: &mut Context) {
let current_path = doc_mut!(cx.editor).path().cloned();
let show_picker = async move {
- let all_matches: Vec<(usize, PathBuf)> =
+ let all_matches: Vec<FileResult> =
UnboundedReceiverStream::new(all_matches_rx).collect().await;
let call: job::Callback =
Box::new(move |editor: &mut Editor, compositor: &mut Compositor| {
@@ -1847,17 +1882,8 @@ fn global_search(cx: &mut Context) {
let picker = FilePicker::new(
all_matches,
- move |(_line_num, path)| {
- let relative_path = helix_core::path::get_relative_path(path)
- .to_string_lossy()
- .into_owned();
- if current_path.as_ref().map(|p| p == path).unwrap_or(false) {
- format!("{} (*)", relative_path).into()
- } else {
- relative_path.into()
- }
- },
- move |cx, (line_num, path), action| {
+ current_path,
+ move |cx, FileResult { path, line_num }, action| {
match cx.editor.open(path, action) {
Ok(_) => {}
Err(e) => {
@@ -1879,7 +1905,9 @@ fn global_search(cx: &mut Context) {
doc.set_selection(view.id, Selection::single(start, end));
align_view(doc, view, Align::Center);
},
- |_editor, (line_num, path)| Some((path.clone(), Some((*line_num, *line_num)))),
+ |_editor, FileResult { path, line_num }| {
+ Some((path.clone(), Some((*line_num, *line_num))))
+ },
);
compositor.push(Box::new(overlayed(picker)));
});
@@ -2172,8 +2200,10 @@ fn buffer_picker(cx: &mut Context) {
is_current: bool,
}
- impl BufferMeta {
- fn format(&self) -> Spans {
+ impl ui::menu::Item for BufferMeta {
+ type Data = ();
+
+ fn label(&self, _data: &Self::Data) -> Spans {
let path = self
.path
.as_deref()
@@ -2213,7 +2243,7 @@ fn buffer_picker(cx: &mut Context) {
.iter()
.map(|(_, doc)| new_meta(doc))
.collect(),
- BufferMeta::format,
+ (),
|cx, meta, action| {
cx.editor.switch(meta.id, action);
},
@@ -2230,6 +2260,38 @@ fn buffer_picker(cx: &mut Context) {
cx.push_layer(Box::new(overlayed(picker)));
}
+impl ui::menu::Item for MappableCommand {
+ type Data = ReverseKeymap;
+
+ fn label(&self, keymap: &Self::Data) -> Spans {
+ // formats key bindings, multiple bindings are comma separated,
+ // individual key presses are joined with `+`
+ let fmt_binding = |bindings: &Vec<Vec<KeyEvent>>| -> String {
+ bindings
+ .iter()
+ .map(|bind| {
+ bind.iter()
+ .map(|key| key.to_string())
+ .collect::<Vec<String>>()
+ .join("+")
+ })
+ .collect::<Vec<String>>()
+ .join(", ")
+ };
+
+ match self {
+ MappableCommand::Typable { doc, name, .. } => match keymap.get(name as &String) {
+ Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(),
+ None => doc.as_str().into(),
+ },
+ MappableCommand::Static { doc, name, .. } => match keymap.get(*name) {
+ Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(),
+ None => (*doc).into(),
+ },
+ }
+ }
+}
+
pub fn command_palette(cx: &mut Context) {
cx.callback = Some(Box::new(
move |compositor: &mut Compositor, cx: &mut compositor::Context| {
@@ -2246,44 +2308,17 @@ pub fn command_palette(cx: &mut Context) {
}
}));
- // formats key bindings, multiple bindings are comma separated,
- // individual key presses are joined with `+`
- let fmt_binding = |bindings: &Vec<Vec<KeyEvent>>| -> String {
- bindings
- .iter()
- .map(|bind| {
- bind.iter()
- .map(|key| key.key_sequence_format())
- .collect::<String>()
- })
- .collect::<Vec<String>>()
- .join(", ")
- };
-
- let picker = Picker::new(
- commands,
- move |command| match command {
- MappableCommand::Typable { doc, name, .. } => match keymap.get(name) {
- Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(),
- None => doc.as_str().into(),
- },
- MappableCommand::Static { doc, name, .. } => match keymap.get(*name) {
- Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(),
- None => (*doc).into(),
- },
- },
- move |cx, command, _action| {
- let mut ctx = Context {
- register: None,
- count: std::num::NonZeroUsize::new(1),
- editor: cx.editor,
- callback: None,
- on_next_key_callback: None,
- jobs: cx.jobs,
- };
- command.execute(&mut ctx);
- },
- );
+ let picker = Picker::new(commands, keymap, move |cx, command, _action| {
+ let mut ctx = Context {
+ register: None,
+ count: std::num::NonZeroUsize::new(1),
+ editor: cx.editor,
+ callback: None,
+ on_next_key_callback: None,
+ jobs: cx.jobs,
+ };
+ command.execute(&mut ctx);
+ });
compositor.push(Box::new(overlayed(picker)));
},
));