Skip to content

Commit 8d483ff

Browse files
xJonathanLEIwongjiahauthe-mikedavispascalkuthe
authored andcommitted
Changed file picker (helix-editor#5645)
Co-authored-by: WJH <[email protected]> Co-authored-by: Michael Davis <[email protected]> Co-authored-by: Pascal Kuthe <[email protected]>
1 parent b5bf69f commit 8d483ff

File tree

9 files changed

+380
-24
lines changed

9 files changed

+380
-24
lines changed

Cargo.lock

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

book/src/themes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ We use a similar set of scopes as
251251
- `gutter` - gutter indicator
252252
- `delta` - modifications
253253
- `moved` - renamed or moved files/changes
254+
- `conflict` - merge conflicts
254255
- `gutter` - gutter indicator
255256

256257
#### Interface

helix-term/src/commands.rs

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ pub(crate) mod lsp;
33
pub(crate) mod typed;
44

55
pub use dap::*;
6+
use helix_event::status;
67
use helix_stdx::rope::{self, RopeSliceExt};
7-
use helix_vcs::Hunk;
8+
use helix_vcs::{FileChange, Hunk};
89
pub use lsp::*;
9-
use tui::widgets::Row;
10+
use tui::{
11+
text::Span,
12+
widgets::{Cell, Row},
13+
};
1014
pub use typed::*;
1115

1216
use helix_core::{
@@ -39,6 +43,7 @@ use helix_view::{
3943
info::Info,
4044
input::KeyEvent,
4145
keyboard::KeyCode,
46+
theme::Style,
4247
tree,
4348
view::View,
4449
Document, DocumentId, Editor, ViewId,
@@ -54,7 +59,7 @@ use crate::{
5459
filter_picker_entry,
5560
job::Callback,
5661
keymap::ReverseKeymap,
57-
ui::{self, overlay::overlaid, Picker, Popup, Prompt, PromptEvent},
62+
ui::{self, menu::Item, overlay::overlaid, Picker, Popup, Prompt, PromptEvent},
5863
};
5964

6065
use crate::job::{self, Jobs};
@@ -324,6 +329,7 @@ impl MappableCommand {
324329
buffer_picker, "Open buffer picker",
325330
jumplist_picker, "Open jumplist picker",
326331
symbol_picker, "Open symbol picker",
332+
changed_file_picker, "Open changed file picker",
327333
select_references_to_symbol_under_cursor, "Select symbol references",
328334
workspace_symbol_picker, "Open workspace symbol picker",
329335
diagnostics_picker, "Open diagnostic picker",
@@ -2999,6 +3005,94 @@ fn jumplist_picker(cx: &mut Context) {
29993005
cx.push_layer(Box::new(overlaid(picker)));
30003006
}
30013007

3008+
fn changed_file_picker(cx: &mut Context) {
3009+
pub struct FileChangeData {
3010+
cwd: PathBuf,
3011+
style_untracked: Style,
3012+
style_modified: Style,
3013+
style_conflict: Style,
3014+
style_deleted: Style,
3015+
style_renamed: Style,
3016+
}
3017+
3018+
impl Item for FileChange {
3019+
type Data = FileChangeData;
3020+
3021+
fn format(&self, data: &Self::Data) -> Row {
3022+
let process_path = |path: &PathBuf| {
3023+
path.strip_prefix(&data.cwd)
3024+
.unwrap_or(path)
3025+
.display()
3026+
.to_string()
3027+
};
3028+
3029+
let (sign, style, content) = match self {
3030+
Self::Untracked { path } => ("[+]", data.style_untracked, process_path(path)),
3031+
Self::Modified { path } => ("[~]", data.style_modified, process_path(path)),
3032+
Self::Conflict { path } => ("[x]", data.style_conflict, process_path(path)),
3033+
Self::Deleted { path } => ("[-]", data.style_deleted, process_path(path)),
3034+
Self::Renamed { from_path, to_path } => (
3035+
"[>]",
3036+
data.style_renamed,
3037+
format!("{} -> {}", process_path(from_path), process_path(to_path)),
3038+
),
3039+
};
3040+
3041+
Row::new([Cell::from(Span::styled(sign, style)), Cell::from(content)])
3042+
}
3043+
}
3044+
3045+
let cwd = helix_stdx::env::current_working_dir();
3046+
if !cwd.exists() {
3047+
cx.editor
3048+
.set_error("Current working directory does not exist");
3049+
return;
3050+
}
3051+
3052+
let added = cx.editor.theme.get("diff.plus");
3053+
let modified = cx.editor.theme.get("diff.delta");
3054+
let conflict = cx.editor.theme.get("diff.delta.conflict");
3055+
let deleted = cx.editor.theme.get("diff.minus");
3056+
let renamed = cx.editor.theme.get("diff.delta.moved");
3057+
3058+
let picker = Picker::new(
3059+
Vec::new(),
3060+
FileChangeData {
3061+
cwd: cwd.clone(),
3062+
style_untracked: added,
3063+
style_modified: modified,
3064+
style_conflict: conflict,
3065+
style_deleted: deleted,
3066+
style_renamed: renamed,
3067+
},
3068+
|cx, meta: &FileChange, action| {
3069+
let path_to_open = meta.path();
3070+
if let Err(e) = cx.editor.open(path_to_open, action) {
3071+
let err = if let Some(err) = e.source() {
3072+
format!("{}", err)
3073+
} else {
3074+
format!("unable to open \"{}\"", path_to_open.display())
3075+
};
3076+
cx.editor.set_error(err);
3077+
}
3078+
},
3079+
)
3080+
.with_preview(|_editor, meta| Some((meta.path().to_path_buf().into(), None)));
3081+
let injector = picker.injector();
3082+
3083+
cx.editor
3084+
.diff_providers
3085+
.clone()
3086+
.for_each_changed_file(cwd, move |change| match change {
3087+
Ok(change) => injector.push(change).is_ok(),
3088+
Err(err) => {
3089+
status::report_blocking(err);
3090+
true
3091+
}
3092+
});
3093+
cx.push_layer(Box::new(overlaid(picker)));
3094+
}
3095+
30023096
impl ui::menu::Item for MappableCommand {
30033097
type Data = ReverseKeymap;
30043098

helix-term/src/keymap/default.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,10 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
225225
"S" => workspace_symbol_picker,
226226
"d" => diagnostics_picker,
227227
"D" => workspace_diagnostics_picker,
228+
"g" => changed_file_picker,
228229
"a" => code_action,
229230
"'" => last_picker,
230-
"g" => { "Debug (experimental)" sticky=true
231+
"G" => { "Debug (experimental)" sticky=true
231232
"l" => dap_launch,
232233
"r" => dap_restart,
233234
"b" => dap_toggle_breakpoint,

helix-vcs/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
1919
parking_lot = "0.12"
2020
arc-swap = { version = "1.7.1" }
2121

22-
gix = { version = "0.61.0", features = ["attributes"], default-features = false, optional = true }
22+
gix = { version = "0.61.0", features = ["attributes", "status"], default-features = false, optional = true }
2323
imara-diff = "0.1.5"
2424
anyhow = "1"
2525

0 commit comments

Comments
 (0)