@@ -2383,49 +2383,16 @@ def _determine_completion_context(self, line):
23832383 # Recursively determine the context of the expression
23842384 return self ._determine_completion_context (expr )
23852385
2386- # Match tuples followed by a dot (e.g., (a, b).index)
2387- tuple_attr_match = re .search (
2388- r"\(\s*[a-zA-Z_][a-zA-Z0-9_]*\s*(,\s*[a-zA-Z_][a-zA-Z0-9_]*\s*)+\)\.$" , line
2389- )
2390- if tuple_attr_match :
2391- return self ._CompletionContextType .ATTRIBUTE
2392-
2393- # Match for number literals should come first
23942386 # Handle plain number literals - should be global context
2395- if re .search (r"^[-+]?\d+\.(\d+)?$" , line ):
2387+ # Ex: 3. -42.14 but not 3.1.
2388+ if re .search (r"(?<!\w)(?<!\d\.)([-+]?\d+\.(\d+)?)(?!\w)$" , line ):
23962389 return self ._CompletionContextType .GLOBAL
23972390
2398- # Match numeric literals in parentheses followed by dot
2399- # Handles cases like (3).to_
2400- numeric_paren_attr_match = re .search (
2401- r"\([-+]?\d+(\.\d*)?\)(\.([a-zA-Z_][a-zA-Z0-9_]*)?)?$" , line
2402- )
2403- if numeric_paren_attr_match :
2404- return self ._CompletionContextType .ATTRIBUTE
2405-
2406- # Match float literals followed by dot and optional attribute
2407- # Handles cases like 3.1.as_, -3.1.r_
2408- float_attr_match = re .search (r"[-+]?\d+\.\d+\.([a-zA-Z_][a-zA-Z0-9_]*)?$" , line )
2409- if float_attr_match :
2410- return self ._CompletionContextType .ATTRIBUTE
2411-
2412- # Handle indexed access followed by dot - like d[0].k
2413- indexed_attr_match = re .search (
2414- r"[a-zA-Z_][a-zA-Z0-9_]*\[[^\]]+\]\.([a-zA-Z_][a-zA-Z0-9_]*)?$" , line
2415- )
2416- if indexed_attr_match :
2417- return self ._CompletionContextType .ATTRIBUTE
2418-
2419- # Match 'word-dot-word' at end for attribute context.
2420- # Ex: 'obj.', 'np.random.ran'.
2421- chain_match = re .search (
2422- r"([a-zA-Z_][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)?$" , line
2423- )
2391+ # Handle all other attribute matches np.ran, d[0].k, (a,b).count
2392+ chain_match = re .search (r".*(.+\.(?:[a-zA-Z]\w*)?)$" , line )
24242393 if chain_match :
24252394 return self ._CompletionContextType .ATTRIBUTE
24262395
2427- # No attribute pattern → GLOBAL.
2428- # Ex: 'var', '', '3.', '-42.5.'
24292396 return self ._CompletionContextType .GLOBAL
24302397
24312398 def _is_in_string_or_comment (self , text ):
@@ -2488,28 +2455,31 @@ def _is_in_string_or_comment(self, text):
24882455 i += 2
24892456 continue
24902457
2491- # Handle expressions in f-strings or t-strings
2492- if (
2493- in_template_string
2494- and text [i ] == "{"
2495- and not (in_expression and expression_depth > 0 and text [i - 1 ] != "{" )
2496- ):
2497- in_expression = True
2498- expression_depth += 1
2499- i += 1
2500- continue
2501- elif in_template_string and text [i ] == "}" and in_expression :
2502- expression_depth -= 1
2503- if expression_depth == 0 :
2504- in_expression = False
2505- i += 1
2506- continue
2458+ # Handle nested braces within f-strings
2459+ if in_template_string :
2460+ # Special handling for consecutive opening braces
2461+ if i + 1 < len (text ) and text [i : i + 2 ] == "{{" :
2462+ i += 2
2463+ continue
25072464
2508- # Handle nested braces within expressions
2509- if in_expression and text [i ] == "{" :
2510- expression_depth += 1
2511- elif in_expression and text [i ] == "}" and expression_depth > 0 :
2512- expression_depth -= 1
2465+ # Detect start of an expression
2466+ if text [i ] == "{" :
2467+ # Only increment depth and mark as expression if not already in an expression
2468+ # or if we're at a top-level nested brace
2469+ if not in_expression or (in_expression and expression_depth == 0 ):
2470+ in_expression = True
2471+ expression_depth += 1
2472+ i += 1
2473+ continue
2474+
2475+ # Detect end of an expression
2476+ if text [i ] == "}" :
2477+ expression_depth -= 1
2478+ if expression_depth <= 0 :
2479+ in_expression = False
2480+ expression_depth = 0
2481+ i += 1
2482+ continue
25132483
25142484 # Handle quotes - also reset template string when closing quotes are encountered
25152485 if (
@@ -2555,7 +2525,6 @@ def _is_in_string_or_comment(self, text):
25552525 )
25562526
25572527 # Return tuple (is_string, is_in_expression)
2558- # For nested f-strings, we're in a string but not necessarily in an expression
25592528 return (
25602529 is_string or (in_template_string and not in_expression ),
25612530 in_expression and expression_depth > 0 ,
0 commit comments