@@ -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,21 @@ 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 ( target : & RedirectionTarget , pos : usize ) -> Option < & Expression > {
87+ let expr = target. expr ( ) ;
88+ expr. and_then ( |expression| {
89+ if let Expr :: String ( _) = expression. expr
90+ && expression. span . contains ( pos)
91+ {
92+ expr
93+ } else {
94+ None
95+ }
96+ } )
97+ }
98+
8199/// Before completion, an additional character `a` is added to the source as a placeholder for correct parsing results.
82100/// This function helps to strip it
83101fn strip_placeholder_if_any < ' a > (
@@ -218,9 +236,26 @@ impl NuCompleter {
218236 if !extra_placeholder {
219237 pos_to_search = pos_to_search. saturating_sub ( 1 ) ;
220238 }
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 {
239+ let Some ( element_expression) = block
240+ . find_map ( working_set, & |expr : & Expression | {
241+ find_pipeline_element_by_position ( expr, working_set, pos_to_search)
242+ } )
243+ . or_else ( || {
244+ block. pipelines . iter ( ) . find_map ( |pipeline| {
245+ pipeline. elements . iter ( ) . find_map ( |element| {
246+ element. redirection . as_ref ( ) . and_then ( |redir| match redir {
247+ PipelineRedirection :: Single { target, .. } => {
248+ redirection_target_expression ( target, pos_to_search)
249+ }
250+ PipelineRedirection :: Separate { out, err } => {
251+ redirection_target_expression ( out, pos_to_search)
252+ . or_else ( || redirection_target_expression ( err, pos_to_search) )
253+ }
254+ } )
255+ } )
256+ } )
257+ } )
258+ else {
224259 return vec ! [ ] ;
225260 } ;
226261
@@ -259,6 +294,16 @@ impl NuCompleter {
259294 let mut suggestions: Vec < SemanticSuggestion > = vec ! [ ] ;
260295
261296 match & element_expression. expr {
297+ // WARN: Expr::String should only match redirection targets.
298+ // We choose to handle it explicitly here because of a legacy issue: fallback file
299+ // completion doesn't work well with filepath with spaces
300+ // https://github.com/nushell/nushell/issues/16712
301+ Expr :: String ( _) => {
302+ let span = element_expression. span ;
303+ let ( new_span, prefix) = strip_placeholder_if_any ( working_set, & span, strip) ;
304+ let ctx = Context :: new ( working_set, new_span, prefix, offset) ;
305+ return self . process_completion ( & mut FileCompletion , & ctx) ;
306+ }
262307 Expr :: Var ( _) => {
263308 return self . variable_names_completion_helper (
264309 working_set,
0 commit comments