Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1026,8 +1026,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif
if obj !== nothing
# Skip leading whitespace inside brackets.
i = @something findnext(!isspace, string, first(key)) nextind(string, last(key))
key = i:last(key)
s = string[intersect(key, 1:pos)]
key = intersect(i:last(key), 1:pos)
s = string[key]
matches = find_dict_matches(obj, s)
length(matches) == 1 && !closed && (matches[1] *= ']')
if length(matches) > 0
Expand All @@ -1052,7 +1052,8 @@ 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[intersect(r, 1:pos)])
r = intersect(r, 1:pos)
s = do_string_unescape(string[r])
ret, success = complete_path_string(s, hint; string_escape=true,
dirsep=Sys.iswindows() ? '\\' : '/')
if length(ret) == 1 && !closed && close_path_completion(ret[1].path)
Expand Down Expand Up @@ -1095,8 +1096,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif
# Keyword argument completion:
# foo(ar TAB => keyword arguments like `arg1=`
elseif kind(cur) == K"Identifier"
r = char_range(cur)
s = string[intersect(r, 1:pos)]
r = intersect(char_range(cur), 1:pos)
s = string[r]
# Return without adding more suggestions if kwargs only
complete_keyword_argument!(suggestions, e, s, context_module, arg_pos; shift) &&
return sort_suggestions(), r, true
Expand Down
32 changes: 32 additions & 0 deletions stdlib/REPL/test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,23 @@ mktempdir() do path
@test "$(path_expected)$(sep)foo_dir$(sep)" in c
@test "$(path_expected)$(sep)foo_file.txt" in c
end

# Issue #60444: path completion should not delete text after the string (e.g. indexing)
let (c, r, res) = test_complete_pos("f(\"$(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
let (c, r, res) = test_complete_pos("f(\"$(path)$(sep)foo|\")[1]")
@test res
@test length(c) == 2
@test "$(path_expected)$(sep)foo_dir$(sep)" in c
@test "$(path_expected)$(sep)foo_file.txt" in c
# Range should end at cursor position, not overwrite ")[1]"
pos = findfirst('|', "f(\"$(path)$(sep)foo|\")[1]") - 1
@test last(r) == pos
end
end

if Sys.iswindows()
Expand Down Expand Up @@ -1648,6 +1665,14 @@ test_dict_completion("test_repl_comp_customdict")
let s = "test_dict_no_length["
@test REPLCompletions.completions(s, sizeof(s), Main.CompletionFoo) isa Tuple
end

# Issue #60444: completing dict keys should not overwrite input after cursor
let s = "test_dict[\"ab|c\"]"
c, r = test_complete_context_pos(s, Main.CompletionFoo)
@test "\"abc\"" in c
@test "\"abcd\"" in c
@test r == 11:13 # range ends at cursor, not at end of key
end
end

@testset "completion of string/cmd macros (#22577)" begin
Expand Down Expand Up @@ -1794,6 +1819,13 @@ end
@test hasnokwsuggestions("CompletionFoo.kwtest5('a', 3, 5, unknownsplat...; xy")
@test hasnokwsuggestions("CompletionFoo.kwtest5(3; somek")
=#

# Issue #60444: completing keyword arguments should not overwrite input after cursor
let s = "CompletionFoo.kwtest3(a; foob|true)"
c, r = test_complete_pos(s)
@test c == ["foobar="]
@test r == 26:29
end
end

# Test completion in context
Expand Down