Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-term/src/commands.rs')
-rw-r--r--helix-term/src/commands.rs100
1 files changed, 97 insertions, 3 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index d927d3f4..d0b9047c 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -3,10 +3,14 @@ pub(crate) mod lsp;
pub(crate) mod typed;
pub use dap::*;
+use helix_event::status;
use helix_stdx::rope::{self, RopeSliceExt};
-use helix_vcs::Hunk;
+use helix_vcs::{FileChange, Hunk};
pub use lsp::*;
-use tui::widgets::Row;
+use tui::{
+ text::Span,
+ widgets::{Cell, Row},
+};
pub use typed::*;
use helix_core::{
@@ -39,6 +43,7 @@ use helix_view::{
info::Info,
input::KeyEvent,
keyboard::KeyCode,
+ theme::Style,
tree,
view::View,
Document, DocumentId, Editor, ViewId,
@@ -54,7 +59,7 @@ use crate::{
filter_picker_entry,
job::Callback,
keymap::ReverseKeymap,
- ui::{self, overlay::overlaid, Picker, Popup, Prompt, PromptEvent},
+ ui::{self, menu::Item, overlay::overlaid, Picker, Popup, Prompt, PromptEvent},
};
use crate::job::{self, Jobs};
@@ -324,6 +329,7 @@ impl MappableCommand {
buffer_picker, "Open buffer picker",
jumplist_picker, "Open jumplist picker",
symbol_picker, "Open symbol picker",
+ changed_file_picker, "Open changed file picker",
select_references_to_symbol_under_cursor, "Select symbol references",
workspace_symbol_picker, "Open workspace symbol picker",
diagnostics_picker, "Open diagnostic picker",
@@ -2996,6 +3002,94 @@ fn jumplist_picker(cx: &mut Context) {
cx.push_layer(Box::new(overlaid(picker)));
}
+fn changed_file_picker(cx: &mut Context) {
+ pub struct FileChangeData {
+ cwd: PathBuf,
+ style_untracked: Style,
+ style_modified: Style,
+ style_conflict: Style,
+ style_deleted: Style,
+ style_renamed: Style,
+ }
+
+ impl Item for FileChange {
+ type Data = FileChangeData;
+
+ fn format(&self, data: &Self::Data) -> Row {
+ let process_path = |path: &PathBuf| {
+ path.strip_prefix(&data.cwd)
+ .unwrap_or(path)
+ .display()
+ .to_string()
+ };
+
+ let (sign, style, content) = match self {
+ Self::Untracked { path } => ("[+]", data.style_untracked, process_path(path)),
+ Self::Modified { path } => ("[~]", data.style_modified, process_path(path)),
+ Self::Conflict { path } => ("[x]", data.style_conflict, process_path(path)),
+ Self::Deleted { path } => ("[-]", data.style_deleted, process_path(path)),
+ Self::Renamed { from_path, to_path } => (
+ "[>]",
+ data.style_renamed,
+ format!("{} -> {}", process_path(from_path), process_path(to_path)),
+ ),
+ };
+
+ Row::new([Cell::from(Span::styled(sign, style)), Cell::from(content)])
+ }
+ }
+
+ let cwd = helix_stdx::env::current_working_dir();
+ if !cwd.exists() {
+ cx.editor
+ .set_error("Current working directory does not exist");
+ return;
+ }
+
+ let added = cx.editor.theme.get("diff.plus");
+ let modified = cx.editor.theme.get("diff.delta");
+ let conflict = cx.editor.theme.get("diff.delta.conflict");
+ let deleted = cx.editor.theme.get("diff.minus");
+ let renamed = cx.editor.theme.get("diff.delta.moved");
+
+ let picker = Picker::new(
+ Vec::new(),
+ FileChangeData {
+ cwd: cwd.clone(),
+ style_untracked: added,
+ style_modified: modified,
+ style_conflict: conflict,
+ style_deleted: deleted,
+ style_renamed: renamed,
+ },
+ |cx, meta: &FileChange, action| {
+ let path_to_open = meta.path();
+ if let Err(e) = cx.editor.open(path_to_open, action) {
+ let err = if let Some(err) = e.source() {
+ format!("{}", err)
+ } else {
+ format!("unable to open \"{}\"", path_to_open.display())
+ };
+ cx.editor.set_error(err);
+ }
+ },
+ )
+ .with_preview(|_editor, meta| Some((meta.path().to_path_buf().into(), None)));
+ let injector = picker.injector();
+
+ cx.editor
+ .diff_providers
+ .clone()
+ .for_each_changed_file(cwd, move |change| match change {
+ Ok(change) => injector.push(change).is_ok(),
+ Err(err) => {
+ status::report_blocking(err);
+ true
+ }
+ });
+ cx.push_layer(Box::new(overlaid(picker)));
+}
+
impl ui::menu::Item for MappableCommand {
type Data = ReverseKeymap;