@@ -3,10 +3,14 @@ pub(crate) mod lsp;
3
3
pub ( crate ) mod typed;
4
4
5
5
pub use dap:: * ;
6
+ use helix_event:: status;
6
7
use helix_stdx:: rope:: { self , RopeSliceExt } ;
7
- use helix_vcs:: Hunk ;
8
+ use helix_vcs:: { FileChange , Hunk } ;
8
9
pub use lsp:: * ;
9
- use tui:: widgets:: Row ;
10
+ use tui:: {
11
+ text:: Span ,
12
+ widgets:: { Cell , Row } ,
13
+ } ;
10
14
pub use typed:: * ;
11
15
12
16
use helix_core:: {
@@ -39,6 +43,7 @@ use helix_view::{
39
43
info:: Info ,
40
44
input:: KeyEvent ,
41
45
keyboard:: KeyCode ,
46
+ theme:: Style ,
42
47
tree,
43
48
view:: View ,
44
49
Document , DocumentId , Editor , ViewId ,
@@ -54,7 +59,7 @@ use crate::{
54
59
filter_picker_entry,
55
60
job:: Callback ,
56
61
keymap:: ReverseKeymap ,
57
- ui:: { self , overlay:: overlaid, Picker , Popup , Prompt , PromptEvent } ,
62
+ ui:: { self , menu :: Item , overlay:: overlaid, Picker , Popup , Prompt , PromptEvent } ,
58
63
} ;
59
64
60
65
use crate :: job:: { self , Jobs } ;
@@ -324,6 +329,7 @@ impl MappableCommand {
324
329
buffer_picker, "Open buffer picker" ,
325
330
jumplist_picker, "Open jumplist picker" ,
326
331
symbol_picker, "Open symbol picker" ,
332
+ changed_file_picker, "Open changed file picker" ,
327
333
select_references_to_symbol_under_cursor, "Select symbol references" ,
328
334
workspace_symbol_picker, "Open workspace symbol picker" ,
329
335
diagnostics_picker, "Open diagnostic picker" ,
@@ -2996,6 +3002,94 @@ fn jumplist_picker(cx: &mut Context) {
2996
3002
cx. push_layer ( Box :: new ( overlaid ( picker) ) ) ;
2997
3003
}
2998
3004
3005
+ fn changed_file_picker ( cx : & mut Context ) {
3006
+ pub struct FileChangeData {
3007
+ cwd : PathBuf ,
3008
+ style_untracked : Style ,
3009
+ style_modified : Style ,
3010
+ style_conflict : Style ,
3011
+ style_deleted : Style ,
3012
+ style_renamed : Style ,
3013
+ }
3014
+
3015
+ impl Item for FileChange {
3016
+ type Data = FileChangeData ;
3017
+
3018
+ fn format ( & self , data : & Self :: Data ) -> Row {
3019
+ let process_path = |path : & PathBuf | {
3020
+ path. strip_prefix ( & data. cwd )
3021
+ . unwrap_or ( path)
3022
+ . display ( )
3023
+ . to_string ( )
3024
+ } ;
3025
+
3026
+ let ( sign, style, content) = match self {
3027
+ Self :: Untracked { path } => ( "[+]" , data. style_untracked , process_path ( path) ) ,
3028
+ Self :: Modified { path } => ( "[~]" , data. style_modified , process_path ( path) ) ,
3029
+ Self :: Conflict { path } => ( "[x]" , data. style_conflict , process_path ( path) ) ,
3030
+ Self :: Deleted { path } => ( "[-]" , data. style_deleted , process_path ( path) ) ,
3031
+ Self :: Renamed { from_path, to_path } => (
3032
+ "[>]" ,
3033
+ data. style_renamed ,
3034
+ format ! ( "{} -> {}" , process_path( from_path) , process_path( to_path) ) ,
3035
+ ) ,
3036
+ } ;
3037
+
3038
+ Row :: new ( [ Cell :: from ( Span :: styled ( sign, style) ) , Cell :: from ( content) ] )
3039
+ }
3040
+ }
3041
+
3042
+ let cwd = helix_stdx:: env:: current_working_dir ( ) ;
3043
+ if !cwd. exists ( ) {
3044
+ cx. editor
3045
+ . set_error ( "Current working directory does not exist" ) ;
3046
+ return ;
3047
+ }
3048
+
3049
+ let added = cx. editor . theme . get ( "diff.plus" ) ;
3050
+ let modified = cx. editor . theme . get ( "diff.delta" ) ;
3051
+ let conflict = cx. editor . theme . get ( "diff.delta.conflict" ) ;
3052
+ let deleted = cx. editor . theme . get ( "diff.minus" ) ;
3053
+ let renamed = cx. editor . theme . get ( "diff.delta.moved" ) ;
3054
+
3055
+ let picker = Picker :: new (
3056
+ Vec :: new ( ) ,
3057
+ FileChangeData {
3058
+ cwd : cwd. clone ( ) ,
3059
+ style_untracked : added,
3060
+ style_modified : modified,
3061
+ style_conflict : conflict,
3062
+ style_deleted : deleted,
3063
+ style_renamed : renamed,
3064
+ } ,
3065
+ |cx, meta : & FileChange , action| {
3066
+ let path_to_open = meta. path ( ) ;
3067
+ if let Err ( e) = cx. editor . open ( path_to_open, action) {
3068
+ let err = if let Some ( err) = e. source ( ) {
3069
+ format ! ( "{}" , err)
3070
+ } else {
3071
+ format ! ( "unable to open \" {}\" " , path_to_open. display( ) )
3072
+ } ;
3073
+ cx. editor . set_error ( err) ;
3074
+ }
3075
+ } ,
3076
+ )
3077
+ . with_preview ( |_editor, meta| Some ( ( meta. path ( ) . to_path_buf ( ) . into ( ) , None ) ) ) ;
3078
+ let injector = picker. injector ( ) ;
3079
+
3080
+ cx. editor
3081
+ . diff_providers
3082
+ . clone ( )
3083
+ . for_each_changed_file ( cwd, move |change| match change {
3084
+ Ok ( change) => injector. push ( change) . is_ok ( ) ,
3085
+ Err ( err) => {
3086
+ status:: report_blocking ( err) ;
3087
+ true
3088
+ }
3089
+ } ) ;
3090
+ cx. push_layer ( Box :: new ( overlaid ( picker) ) ) ;
3091
+ }
3092
+
2999
3093
impl ui:: menu:: Item for MappableCommand {
3000
3094
type Data = ReverseKeymap ;
3001
3095
0 commit comments