Skip to content

Commit 7873942

Browse files
committed
REPL completion: make import mode more forgiving
Don't require a using/import to be on its own line to enter import mode; instead look for partial import expressions and require the cursor be in the range where modules/imported names would go. Fixes JuliaLang#56389 (including the fix for JuliaLang#55842)
1 parent b5dc5ae commit 7873942

File tree

2 files changed

+27
-31
lines changed

2 files changed

+27
-31
lines changed

stdlib/REPL/src/REPLCompletions.jl

+13-31
Original file line numberDiff line numberDiff line change
@@ -937,40 +937,22 @@ const superscript_regex = Regex("^\\\\\\^[" * join(isdigit(k) || isletter(k) ? "
937937

938938
# Aux function to detect whether we're right after a using or import keyword
939939
function get_import_mode(s::String, pos::Int)
940-
# allow all of these to start with leading whitespace and macros like @eval and @eval(
941-
# ^\s*(?:@\w+\s*(?:\(\s*)?)?
942-
943-
# Do not enter import mode unless cursor beyond import keyword
944-
beyond_kw(m) = pos >= m.offsets[1] + sizeof(m[1])
945-
946-
# match simple cases like `using |` and `import |`
947-
mod_import_match_simple = match(r"^\s*(?:@\w+\s*(?:\(\s*)?)?\b(using|import)\s*$", s)
948-
if mod_import_match_simple !== nothing && beyond_kw(mod_import_match_simple)
949-
if mod_import_match_simple[1] == "using"
950-
return :using_module
951-
else
952-
return :import_module
953-
end
954-
end
955-
# match module import statements like `using Foo|`, `import Foo, Bar|` and `using Foo.Bar, Baz, |`
956-
mod_import_match = match(r"^\s*(?:@\w+\s*(?:\(\s*)?)?\b(using|import)\s+([\w\.]+(?:\s*,\s*[\w\.]+)*),?\s*$", s)
957-
if mod_import_match !== nothing && beyond_kw(mod_import_match)
958-
if mod_import_match.captures[1] == "using"
959-
return :using_module
960-
else
961-
return :import_module
940+
# Capture group 1 will be returned, group 2 is where the cursor should be.
941+
function match_pos(re)
942+
for m in eachmatch(re, s, overlap=true)
943+
m !== nothing || continue
944+
pos in range(m.offsets[2], length=sizeof(m[2])) || continue
945+
return m[1]
962946
end
963947
end
948+
949+
# match module import statements like `using |`, `import |`, `using Foo|`, `import Foo, Bar|` and `using Foo.Bar, Baz, |`
950+
m = match_pos(r"\b(using|import)(\s+(?:[\w\.]+(?:\s*,\s*[\w\.]+)*(:?\s*,)?\s*)?)")
951+
m !== nothing && return m == "using" ? :using_module : :import_module
952+
964953
# now match explicit name import statements like `using Foo: |` and `import Foo: bar, baz|`
965-
name_import_match = match(r"^\s*(?:@\w+\s*(?:\(\s*)?)?\b(using|import)\s+([\w\.]+)\s*:\s*([\w@!\s,]+)$", s)
966-
if name_import_match !== nothing && beyond_kw(name_import_match)
967-
if name_import_match[1] == "using"
968-
return :using_name
969-
else
970-
return :import_name
971-
end
972-
end
973-
return nothing
954+
m = match_pos(r"\b(using|import)\s+(?:[\w\.]+(?:\s*,\s*[\w\.]+)*)\s*(:\s*(?:[\w@!\s,]+)*)")
955+
m !== nothing && return m == "using" ? :using_name : :import_name
974956
end
975957

976958
function close_path_completion(dir, path, str, pos)

stdlib/REPL/test/replcompletions.jl

+14
Original file line numberDiff line numberDiff line change
@@ -2492,3 +2492,17 @@ let (c, r) = test_complete_pos("@tim| using Date")
24922492
@test "@time" in c
24932493
@test r == 1:4
24942494
end
2495+
2496+
# #56389
2497+
let s = "begin\n using Linear"
2498+
c, r = test_complete(s)
2499+
@test "LinearAlgebra" in c
2500+
@test r == 15:20
2501+
@test s[r] == "Linear"
2502+
end
2503+
let s = "using .CompletionFoo: bar, type_"
2504+
c, r = test_complete(s)
2505+
@test "type_test" in c
2506+
@test r == 28:32
2507+
@test s[r] == "type_"
2508+
end

0 commit comments

Comments
 (0)