@@ -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" ,
@@ -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+
30023096impl ui:: menu:: Item for MappableCommand {
30033097 type Data = ReverseKeymap ;
30043098
0 commit comments