@@ -8,7 +8,10 @@ use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
88use nu_parser:: { parse, parse_module_file_or_dir} ;
99use nu_protocol:: {
1010 CommandWideCompleter , Completion , Span , Type , Value ,
11- ast:: { Argument , Block , Expr , Expression , FindMapResult , ListItem , Traverse } ,
11+ ast:: {
12+ Argument , Block , Expr , Expression , FindMapResult , ListItem , PipelineRedirection ,
13+ RedirectionTarget , Traverse ,
14+ } ,
1215 engine:: { EngineState , Stack , StateWorkingSet } ,
1316} ;
1417use reedline:: { Completer as ReedlineCompleter , Suggestion } ;
@@ -78,6 +81,24 @@ fn find_pipeline_element_by_position<'a>(
7881 }
7982}
8083
84+ /// For redirection target completion
85+ /// https://github.com/nushell/nushell/issues/16827
86+ fn redirection_target_expression < ' a > (
87+ target : & ' a RedirectionTarget ,
88+ pos : usize ,
89+ ) -> Option < & ' a Expression > {
90+ let expr = target. expr ( ) ;
91+ expr. and_then ( |expression| {
92+ if let Expr :: String ( _) = expression. expr
93+ && expression. span . contains ( pos)
94+ {
95+ expr
96+ } else {
97+ None
98+ }
99+ } )
100+ }
101+
81102/// Before completion, an additional character `a` is added to the source as a placeholder for correct parsing results.
82103/// This function helps to strip it
83104fn strip_placeholder_if_any < ' a > (
@@ -218,9 +239,26 @@ impl NuCompleter {
218239 if !extra_placeholder {
219240 pos_to_search = pos_to_search. saturating_sub ( 1 ) ;
220241 }
221- let Some ( element_expression) = block. find_map ( working_set, & |expr : & Expression | {
222- find_pipeline_element_by_position ( expr, working_set, pos_to_search)
223- } ) else {
242+ let Some ( element_expression) = block
243+ . find_map ( working_set, & |expr : & Expression | {
244+ find_pipeline_element_by_position ( expr, working_set, pos_to_search)
245+ } )
246+ . or_else ( || {
247+ block. pipelines . iter ( ) . find_map ( |pipeline| {
248+ pipeline. elements . iter ( ) . find_map ( |element| {
249+ element. redirection . as_ref ( ) . and_then ( |redir| match redir {
250+ PipelineRedirection :: Single { target, .. } => {
251+ redirection_target_expression ( target, pos_to_search)
252+ }
253+ PipelineRedirection :: Separate { out, err } => {
254+ redirection_target_expression ( out, pos_to_search)
255+ . or_else ( || redirection_target_expression ( err, pos_to_search) )
256+ }
257+ } )
258+ } )
259+ } )
260+ } )
261+ else {
224262 return vec ! [ ] ;
225263 } ;
226264
@@ -259,6 +297,16 @@ impl NuCompleter {
259297 let mut suggestions: Vec < SemanticSuggestion > = vec ! [ ] ;
260298
261299 match & element_expression. expr {
300+ // WARN: Expr::String should only match redirection targets.
301+ // We choose to handle it explicitly here because of a legacy issue: fallback file
302+ // completion doesn't work well with filepath with spaces
303+ // https://github.com/nushell/nushell/issues/16712
304+ Expr :: String ( _) => {
305+ let span = element_expression. span ;
306+ let ( new_span, prefix) = strip_placeholder_if_any ( working_set, & span, strip) ;
307+ let ctx = Context :: new ( working_set, new_span, prefix, offset) ;
308+ return self . process_completion ( & mut FileCompletion , & ctx) ;
309+ }
262310 Expr :: Var ( _) => {
263311 return self . variable_names_completion_helper (
264312 working_set,
0 commit comments