@@ -3,10 +3,14 @@ pub(crate) mod lsp;
33pub ( crate ) mod typed;
44
55pub use dap:: * ;
6+ use helix_event:: status;
67use helix_stdx:: rope:: { self , RopeSliceExt } ;
7- use helix_vcs:: Hunk ;
8+ use helix_vcs:: { FileChange , Hunk } ;
89pub use lsp:: * ;
9- use tui:: widgets:: Row ;
10+ use tui:: {
11+ text:: Span ,
12+ widgets:: { Cell , Row } ,
13+ } ;
1014pub use typed:: * ;
1115
1216use 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
6065use 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" ,
@@ -2996,6 +3002,94 @@ fn jumplist_picker(cx: &mut Context) {
29963002 cx. push_layer ( Box :: new ( overlaid ( picker) ) ) ;
29973003}
29983004
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+
29993093impl ui:: menu:: Item for MappableCommand {
30003094 type Data = ReverseKeymap ;
30013095
0 commit comments