Get the token at a given cursor Used for introspection. Function calls are prioritized, so the token for the callable will be returned if the cursor is anywhere inside the call. Parameters ---------- cell : unicode A block of Python code cursor
(cell, cursor_pos=0)
| 57 | return (line, offset) |
| 58 | |
| 59 | def token_at_cursor(cell, cursor_pos=0): |
| 60 | """Get the token at a given cursor |
| 61 | |
| 62 | Used for introspection. |
| 63 | |
| 64 | Function calls are prioritized, so the token for the callable will be returned |
| 65 | if the cursor is anywhere inside the call. |
| 66 | |
| 67 | Parameters |
| 68 | ---------- |
| 69 | |
| 70 | cell : unicode |
| 71 | A block of Python code |
| 72 | cursor_pos : int |
| 73 | The location of the cursor in the block where the token should be found |
| 74 | """ |
| 75 | names = [] |
| 76 | tokens = [] |
| 77 | call_names = [] |
| 78 | |
| 79 | offsets = {1: 0} # lines start at 1 |
| 80 | for tup in generate_tokens(StringIO(cell).readline): |
| 81 | |
| 82 | tok = Token(*tup) |
| 83 | |
| 84 | # token, text, start, end, line = tup |
| 85 | start_line, start_col = tok.start |
| 86 | end_line, end_col = tok.end |
| 87 | if end_line + 1 not in offsets: |
| 88 | # keep track of offsets for each line |
| 89 | lines = tok.line.splitlines(True) |
| 90 | for lineno, line in enumerate(lines, start_line + 1): |
| 91 | if lineno not in offsets: |
| 92 | offsets[lineno] = offsets[lineno-1] + len(line) |
| 93 | |
| 94 | offset = offsets[start_line] |
| 95 | # allow '|foo' to find 'foo' at the beginning of a line |
| 96 | boundary = cursor_pos + 1 if start_col == 0 else cursor_pos |
| 97 | if offset + start_col >= boundary: |
| 98 | # current token starts after the cursor, |
| 99 | # don't consume it |
| 100 | break |
| 101 | |
| 102 | if tok.token == tokenize.NAME and not iskeyword(tok.text): |
| 103 | if names and tokens and tokens[-1].token == tokenize.OP and tokens[-1].text == '.': |
| 104 | names[-1] = "%s.%s" % (names[-1], tok.text) |
| 105 | else: |
| 106 | names.append(tok.text) |
| 107 | elif tok.token == tokenize.OP: |
| 108 | if tok.text == '=' and names: |
| 109 | # don't inspect the lhs of an assignment |
| 110 | names.pop(-1) |
| 111 | if tok.text == '(' and names: |
| 112 | # if we are inside a function call, inspect the function |
| 113 | call_names.append(names[-1]) |
| 114 | elif tok.text == ')' and call_names: |
| 115 | call_names.pop(-1) |
| 116 |