@@ -22,7 +22,8 @@ pub use typed::*;
2222use helix_core:: {
2323 char_idx_at_visual_offset,
2424 chars:: char_is_word,
25- command_line, comment,
25+ command_line:: { self , Args } ,
26+ comment,
2627 doc_formatter:: TextFormat ,
2728 encoding, find_workspace,
2829 graphemes:: { self , next_grapheme_boundary} ,
@@ -46,6 +47,7 @@ use helix_core::{
4647use helix_view:: {
4748 document:: { FormatterError , Mode , SCRATCH_BUFFER_NAME } ,
4849 editor:: Action ,
50+ expansion,
4951 info:: Info ,
5052 input:: KeyEvent ,
5153 keyboard:: KeyCode ,
@@ -6256,64 +6258,52 @@ enum ShellBehavior {
62566258}
62576259
62586260fn shell_pipe ( cx : & mut Context ) {
6259- shell_prompt ( cx, "pipe:" . into ( ) , ShellBehavior :: Replace ) ;
6261+ shell_prompt_for_behavior ( cx, "pipe:" . into ( ) , ShellBehavior :: Replace ) ;
62606262}
62616263
62626264fn shell_pipe_to ( cx : & mut Context ) {
6263- shell_prompt ( cx, "pipe-to:" . into ( ) , ShellBehavior :: Ignore ) ;
6265+ shell_prompt_for_behavior ( cx, "pipe-to:" . into ( ) , ShellBehavior :: Ignore ) ;
62646266}
62656267
62666268fn shell_insert_output ( cx : & mut Context ) {
6267- shell_prompt ( cx, "insert-output:" . into ( ) , ShellBehavior :: Insert ) ;
6269+ shell_prompt_for_behavior ( cx, "insert-output:" . into ( ) , ShellBehavior :: Insert ) ;
62686270}
62696271
62706272fn shell_append_output ( cx : & mut Context ) {
6271- shell_prompt ( cx, "append-output:" . into ( ) , ShellBehavior :: Append ) ;
6273+ shell_prompt_for_behavior ( cx, "append-output:" . into ( ) , ShellBehavior :: Append ) ;
62726274}
62736275
62746276fn shell_keep_pipe ( cx : & mut Context ) {
6275- ui:: prompt (
6276- cx,
6277- "keep-pipe:" . into ( ) ,
6278- Some ( '|' ) ,
6279- ui:: completers:: none,
6280- move |cx, input : & str , event : PromptEvent | {
6281- let shell = & cx. editor . config ( ) . shell ;
6282- if event != PromptEvent :: Validate {
6283- return ;
6284- }
6285- if input. is_empty ( ) {
6286- return ;
6287- }
6288- let ( view, doc) = current ! ( cx. editor) ;
6289- let selection = doc. selection ( view. id ) ;
6277+ shell_prompt ( cx, "keep-pipe:" . into ( ) , |cx, args| {
6278+ let shell = & cx. editor . config ( ) . shell ;
6279+ let ( view, doc) = current ! ( cx. editor) ;
6280+ let selection = doc. selection ( view. id ) ;
62906281
6291- let mut ranges = SmallVec :: with_capacity ( selection. len ( ) ) ;
6292- let old_index = selection. primary_index ( ) ;
6293- let mut index: Option < usize > = None ;
6294- let text = doc. text ( ) . slice ( ..) ;
6282+ let mut ranges = SmallVec :: with_capacity ( selection. len ( ) ) ;
6283+ let old_index = selection. primary_index ( ) ;
6284+ let mut index: Option < usize > = None ;
6285+ let text = doc. text ( ) . slice ( ..) ;
62956286
6296- for ( i, range) in selection. ranges ( ) . iter ( ) . enumerate ( ) {
6297- let fragment = range. slice ( text) ;
6298- if let Err ( err) = shell_impl ( shell, input, Some ( fragment. into ( ) ) ) {
6299- log:: debug!( "Shell command failed: {}" , err) ;
6300- } else {
6301- ranges. push ( * range) ;
6302- if i >= old_index && index. is_none ( ) {
6303- index = Some ( ranges. len ( ) - 1 ) ;
6304- }
6287+ for ( i, range) in selection. ranges ( ) . iter ( ) . enumerate ( ) {
6288+ let fragment = range. slice ( text) ;
6289+ if let Err ( err) = shell_impl ( shell, args. join ( " " ) . as_str ( ) , Some ( fragment. into ( ) ) ) {
6290+ log:: debug!( "Shell command failed: {}" , err) ;
6291+ } else {
6292+ ranges. push ( * range) ;
6293+ if i >= old_index && index. is_none ( ) {
6294+ index = Some ( ranges. len ( ) - 1 ) ;
63056295 }
63066296 }
6297+ }
63076298
6308- if ranges. is_empty ( ) {
6309- cx. editor . set_error ( "No selections remaining" ) ;
6310- return ;
6311- }
6299+ if ranges. is_empty ( ) {
6300+ cx. editor . set_error ( "No selections remaining" ) ;
6301+ return ;
6302+ }
63126303
6313- let index = index. unwrap_or_else ( || ranges. len ( ) - 1 ) ;
6314- doc. set_selection ( view. id , Selection :: new ( ranges, index) ) ;
6315- } ,
6316- ) ;
6304+ let index = index. unwrap_or_else ( || ranges. len ( ) - 1 ) ;
6305+ doc. set_selection ( view. id , Selection :: new ( ranges, index) ) ;
6306+ } ) ;
63176307}
63186308
63196309fn shell_impl ( shell : & [ String ] , cmd : & str , input : Option < Rope > ) -> anyhow:: Result < Tendril > {
@@ -6468,25 +6458,35 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
64686458 view. ensure_cursor_in_view ( doc, config. scrolloff ) ;
64696459}
64706460
6471- fn shell_prompt ( cx : & mut Context , prompt : Cow < ' static , str > , behavior : ShellBehavior ) {
6461+ fn shell_prompt < F > ( cx : & mut Context , prompt : Cow < ' static , str > , mut callback_fn : F )
6462+ where
6463+ F : FnMut ( & mut compositor:: Context , Args ) + ' static ,
6464+ {
64726465 ui:: prompt (
64736466 cx,
64746467 prompt,
64756468 Some ( '|' ) ,
6476- ui :: completers :: shell ,
6477- move |cx, input : & str , event : PromptEvent | {
6478- if event != PromptEvent :: Validate {
6469+ |editor , input| complete_command_args ( editor , SHELL_SIGNATURE , & SHELL_COMPLETER , input , 0 ) ,
6470+ move |cx, input, event| {
6471+ if event != PromptEvent :: Validate || input . is_empty ( ) {
64796472 return ;
64806473 }
6481- if input. is_empty ( ) {
6482- return ;
6474+ match Args :: parse ( input, SHELL_SIGNATURE , true , |token| {
6475+ expansion:: expand ( cx. editor , token) . map_err ( |err| err. into ( ) )
6476+ } ) {
6477+ Ok ( args) => callback_fn ( cx, args) ,
6478+ Err ( err) => cx. editor . set_error ( err. to_string ( ) ) ,
64836479 }
6484-
6485- shell ( cx, input, & behavior) ;
64866480 } ,
64876481 ) ;
64886482}
64896483
6484+ fn shell_prompt_for_behavior ( cx : & mut Context , prompt : Cow < ' static , str > , behavior : ShellBehavior ) {
6485+ shell_prompt ( cx, prompt, move |cx, args| {
6486+ shell ( cx, args. join ( " " ) . as_str ( ) , & behavior)
6487+ } )
6488+ }
6489+
64906490fn suspend ( _cx : & mut Context ) {
64916491 #[ cfg( not( windows) ) ]
64926492 {
0 commit comments