diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 746cec7535aca..27a3c57152f6c 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -1047,7 +1047,7 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif # "~/example.txt TAB => "/home/user/example.txt" r, closed = find_str(cur) if r !== nothing - s = do_string_unescape(string[r]) + s = do_string_unescape(string[intersect(r, 1:pos)]) ret, success = complete_path_string(s, hint; string_escape=true, dirsep=Sys.iswindows() ? '\\' : '/') if length(ret) == 1 && !closed && close_path_completion(ret[1].path) diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index d8429f39b41b0..a0366a4fd0547 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1458,6 +1458,45 @@ let (c, r) = test_complete("cd(\"folder_do_not_exist_77/file") @test length(c) == 0 end +# Test path completion in the middle of a line (issue #60050) +mktempdir() do path + # Create test directory structure + foo_dir = joinpath(path, "foo_dir") + mkpath(foo_dir) + touch(joinpath(path, "foo_file.txt")) + + # On Windows, use backslashes; on Unix, use forward slashes + sep = Sys.iswindows() ? "\\\\" : "/" + # On Windows, completion results have escaped backslashes + path_expected = Sys.iswindows() ? replace(path, "\\" => "\\\\") : path + + # Completion at end of line should work + let (c, r, res) = test_complete("\"$(path)$(sep)foo") + @test res + @test length(c) == 2 + @test "$(path_expected)$(sep)foo_dir$(sep)" in c + @test "$(path_expected)$(sep)foo_file.txt" in c + end + + # Completion in middle of line should also work (regression in 1.12) + let (c, r, res) = test_complete_pos("\"$(path)$(sep)foo|$(sep)bar.toml\"") + @test res + @test length(c) == 2 + @test "$(path_expected)$(sep)foo_dir$(sep)" in c + @test "$(path_expected)$(sep)foo_file.txt" in c + # Check that the range covers only the part before the cursor + @test findfirst("$(sep)bar", "\"$(path)$(sep)foo$(sep)bar.toml\"")[1] - 1 in r + end + + # Completion in middle of function call with trailing arguments + let (c, r, res) = test_complete_pos("run_something(\"$(path)$(sep)foo|$(sep)bar.toml\"; kwarg=true)") + @test res + @test length(c) == 2 + @test "$(path_expected)$(sep)foo_dir$(sep)" in c + @test "$(path_expected)$(sep)foo_file.txt" in c + end +end + if Sys.iswindows() tmp = tempname() touch(tmp)