Look for the signature of the function before the cursor position without use of Jedi. This uses a similar approach as the `DictionaryCompleter` of running `eval()` over the detected function name.
(
document: Document, locals: dict[str, Any], globals: dict[str, Any]
)
| 196 | |
| 197 | |
| 198 | def get_signatures_using_eval( |
| 199 | document: Document, locals: dict[str, Any], globals: dict[str, Any] |
| 200 | ) -> list[Signature]: |
| 201 | """ |
| 202 | Look for the signature of the function before the cursor position without |
| 203 | use of Jedi. This uses a similar approach as the `DictionaryCompleter` of |
| 204 | running `eval()` over the detected function name. |
| 205 | """ |
| 206 | # Look for open parenthesis, before cursor position. |
| 207 | pos = document.cursor_position - 1 |
| 208 | |
| 209 | paren_mapping = {")": "(", "}": "{", "]": "["} |
| 210 | paren_stack = [ |
| 211 | ")" |
| 212 | ] # Start stack with closing ')'. We are going to look for the matching open ')'. |
| 213 | comma_count = 0 # Number of comma's between start of function call and cursor pos. |
| 214 | found_start = False # Found something. |
| 215 | |
| 216 | while pos >= 0: |
| 217 | char = document.text[pos] |
| 218 | if char in ")]}": |
| 219 | paren_stack.append(char) |
| 220 | elif char in "([{": |
| 221 | if not paren_stack: |
| 222 | # Open paren, while no closing paren was found. Mouse cursor is |
| 223 | # positioned in nested parentheses. Not at the "top-level" of a |
| 224 | # function call. |
| 225 | break |
| 226 | if paren_mapping[paren_stack[-1]] != char: |
| 227 | # Unmatching parentheses: syntax error? |
| 228 | break |
| 229 | |
| 230 | paren_stack.pop() |
| 231 | |
| 232 | if len(paren_stack) == 0: |
| 233 | found_start = True |
| 234 | break |
| 235 | |
| 236 | elif char == "," and len(paren_stack) == 1: |
| 237 | comma_count += 1 |
| 238 | |
| 239 | pos -= 1 |
| 240 | |
| 241 | if not found_start: |
| 242 | return [] |
| 243 | |
| 244 | # We found the start of the function call. Now look for the object before |
| 245 | # this position on which we can do an 'eval' to retrieve the function |
| 246 | # object. |
| 247 | obj = DictionaryCompleter(lambda: globals, lambda: locals).eval_expression( |
| 248 | Document(document.text, cursor_position=pos), locals |
| 249 | ) |
| 250 | if obj is None: |
| 251 | return [] |
| 252 | |
| 253 | try: |
| 254 | name = obj.__name__ # type:ignore |
| 255 | except Exception: |
no test coverage detected