Skip to content

Commit db0c8e3

Browse files
committed
modify-logic
1 parent 1951fc2 commit db0c8e3

2 files changed

Lines changed: 45 additions & 28 deletions

File tree

IPython/core/completer.py

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,45 +2368,42 @@ def _determine_completion_context(self, line):
23682368
"""
23692369
Determine whether the cursor is in an attribute or global completion context.
23702370
"""
2371+
# Cursor in string/comment → GLOBAL.
23712372
if self._is_in_string_or_comment(line):
23722373
return self._CompletionContextType.GLOBAL
2373-
if line.endswith("."):
2374-
return self._CompletionContextType.ATTRIBUTE
2375-
2376-
last_token_match = re.search(r"([\w]+)$", line)
2377-
if not last_token_match:
2378-
return self._CompletionContextType.GLOBAL
23792374

2380-
prefix = line[: last_token_match.start()]
2381-
chain_match = re.search(r"(.*)\.(\w*)$", prefix.rstrip())
2375+
# Match 'anything-dot-word' at end for attribute context.
2376+
# Ex: 'obj.', 'np.random.ran'.
2377+
chain_match = re.search(r"(.+)\.(\w*)$", line)
23822378
if chain_match:
2379+
prefix = chain_match.group(1)
2380+
# If prefix is a number → GLOBAL (no attributes).
2381+
# Ex: '3.', '-42.5.'.
2382+
if re.fullmatch(r"[-+]?\d*\.?\d+", prefix):
2383+
return self._CompletionContextType.GLOBAL
23832384
return self._CompletionContextType.ATTRIBUTE
23842385

2386+
# No attribute pattern → GLOBAL.
2387+
# Ex: 'var', ''.
23852388
return self._CompletionContextType.GLOBAL
23862389

23872390
def _is_in_string_or_comment(self, text):
2388-
# Check for comments
2389-
if "#" in text:
2390-
parts = text.split("#")
2391-
if len(parts) > 1:
2392-
return True
2393-
23942391
in_single_quote = False
23952392
in_double_quote = False
23962393
in_triple_single = False
23972394
in_triple_double = False
2398-
in_fstring = False
2399-
in_fstring_expression = False
2395+
in_template_string = False # Covers both f-strings and t-strings
2396+
in_expression = False # For expressions in f/t-strings
24002397
i = 0
24012398

24022399
while i < len(text):
2403-
# Check for f-string start
2400+
# Check for f-string or t-string start
24042401
if (
24052402
i + 1 < len(text)
2406-
and text[i] == "f"
2403+
and text[i] in ("f", "t")
24072404
and (text[i + 1] == '"' or text[i + 1] == "'")
24082405
):
2409-
in_fstring = True
2406+
in_template_string = True
24102407
i += 1
24112408

24122409
# Handle triple quotes
@@ -2433,11 +2430,11 @@ def _is_in_string_or_comment(self, text):
24332430
i += 2
24342431
continue
24352432

2436-
# Handle f-string expressions
2437-
if in_fstring and text[i] == "{":
2438-
in_fstring_expression = True
2439-
elif in_fstring and text[i] == "}":
2440-
in_fstring_expression = False
2433+
# Handle expressions in f-strings or t-strings
2434+
if in_template_string and text[i] == "{":
2435+
in_expression = True
2436+
elif in_template_string and text[i] == "}":
2437+
in_expression = False
24412438

24422439
# Handle quotes
24432440
if (
@@ -2455,10 +2452,22 @@ def _is_in_string_or_comment(self, text):
24552452
):
24562453
in_single_quote = not in_single_quote
24572454

2455+
# Check for comment
2456+
if text[i] == "#" and (
2457+
not (
2458+
in_single_quote
2459+
or in_double_quote
2460+
or in_triple_single
2461+
or in_triple_double
2462+
)
2463+
or in_expression
2464+
):
2465+
return True
2466+
24582467
i += 1
24592468

2460-
# If we're in an f-string expression, return False
2461-
if in_fstring_expression:
2469+
# If we're in an expression (f-string or t-string), return False
2470+
if in_expression:
24622471
return False
24632472

24642473
# Otherwise, return True if we're in any type of string

tests/test_completer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,18 +1801,26 @@ def _(expected):
18011801
# Dots in string literals
18021802
('some_var = "this is a string with a dot.', "global"),
18031803
("text = 'another string with a dot.", "global"),
1804+
('f"greeting {user.na', "attribute"), # Cursor in f-string expression
1805+
('t"welcome {guest.na', "attribute"), # Cursor in t-string expression
1806+
('f"hello {name} worl', "global"), # Cursor in f-string outside expression
18041807
# Backslash escapes in strings
18051808
('var = "string with \\"escaped quote and a dot.', "global"),
18061809
("escaped = 'single \\'quote\\' with a dot.", "global"),
18071810
# Multi-line strings
18081811
('multi = """This is line one\nwith a dot.', "global"),
18091812
("multi_single = '''Another\nmulti-line\nwith a dot.", "global"),
1810-
# Inline comments with dots
1811-
("x = 5 # This is a comment with a dot.", "global"),
1813+
# Inline comments
1814+
("x = 5 # This is a comment", "global"),
18121815
("y = obj.method() # Comment after dot.method", "global"),
1816+
# Hash symbol within string literals should not be treated as comments
1817+
("d['#'] = np.", "attribute"),
18131818
# Nested parentheses with dots
18141819
("complex_expr = (func((obj.method(param.attr", "attribute"),
18151820
("multiple_nesting = {key: [value.attr", "attribute"),
1821+
# Numbers
1822+
("3.", "global"),
1823+
("-42.14", "global"),
18161824
# Additional cases
18171825
('str_with_code = "x.attr', "global"),
18181826
('f"formatted {obj.attr', "attribute"),

0 commit comments

Comments
 (0)