Skip to content

Commit 853aba5

Browse files
authored
[REPL] Handle empty completion, keywords better (#59045)
When the context is empty, (like "<TAB><TAB>"), return only names local to the module (fixes #58931). If the cursor is on something that "looks like" an identifier, like a boolean or one of the keywords, treat it as if it was one for completion purposes. Typing a keyword and hitting tab no longer returns the completions for the empty input (fixes #58309, #58832).
1 parent 55b1f3c commit 853aba5

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

stdlib/REPL/src/REPLCompletions.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ function complete_symbol!(suggestions::Vector{Completion},
186186
complete_modules_only::Bool=false,
187187
shift::Bool=false)
188188
local mod, t, val
189-
complete_internal_only = false
189+
complete_internal_only = isempty(name)
190190
if prefix !== nothing
191191
res = repl_eval_ex(prefix, context_module)
192192
res === nothing && return Completion[]
@@ -1095,26 +1095,27 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif
10951095

10961096
# Symbol completion
10971097
# TODO: Should completions replace the identifier at the cursor?
1098+
looks_like_ident = Base.isidentifier(@view string[intersect(char_range(cur), 1:pos)])
10981099
if cur.parent !== nothing && kind(cur.parent) == K"var"
10991100
# Replace the entire var"foo", but search using only "foo".
11001101
r = intersect(char_range(cur.parent), 1:pos)
11011102
r2 = char_range(children_nt(cur.parent)[1])
11021103
s = string[intersect(r2, 1:pos)]
1103-
elseif kind(cur) in KSet"Identifier @"
1104-
r = intersect(char_range(cur), 1:pos)
1105-
s = string[r]
11061104
elseif kind(cur) == K"MacroName"
11071105
# Include the `@`
11081106
r = intersect(prevind(string, cur.position):char_last(cur), 1:pos)
11091107
s = string[r]
1108+
elseif looks_like_ident || kind(cur) in KSet"Bool Identifier @"
1109+
r = intersect(char_range(cur), 1:pos)
1110+
s = string[r]
11101111
else
11111112
r = nextind(string, pos):pos
11121113
s = ""
11131114
end
11141115

11151116
complete_modules_only = false
11161117
prefix = node_prefix(cur, context_module)
1117-
comp_keywords = prefix === nothing
1118+
comp_keywords = prefix === nothing && !isempty(s)
11181119

11191120
# Complete loadable module names:
11201121
# import Mod TAB

stdlib/REPL/test/replcompletions.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,3 +2720,25 @@ let s = "foo58296(findfi"
27202720
@test "findfirst" in c
27212721
@test r == 10:15
27222722
end
2723+
2724+
# #58931 - only show local names when completing the empty string
2725+
let s = ""
2726+
c, r = test_complete_foo(s)
2727+
@test "test" in c
2728+
@test !("rand" in c)
2729+
end
2730+
2731+
# #58309, #58832 - don't show every name when completing after a full keyword
2732+
let s = "true" # bool is a little different (Base.isidentifier special case)
2733+
c, r = test_complete(s)
2734+
@test "trues" in c
2735+
@test "true" in c
2736+
@test !("rand" in c)
2737+
end
2738+
2739+
let s = "for"
2740+
c, r = test_complete(s)
2741+
@test "for" in c
2742+
@test "foreach" in c
2743+
@test !("rand" in c)
2744+
end

0 commit comments

Comments
 (0)