diff options
author | Amjith Ramanujam <amjith.r@gmail.com> | 2015-01-29 10:24:53 -0800 |
---|---|---|
committer | Amjith Ramanujam <amjith.r@gmail.com> | 2015-01-29 10:24:53 -0800 |
commit | 3ed89e01e495c122283053c3a91d752d0d70abce (patch) | |
tree | 9769b0a22303da5b6439265f7bcc126119bf8741 | |
parent | 27a363ee06d8c3e2faadeebf3031a3f1c71b46ad (diff) | |
parent | 13f84bf83e0aa35c9fb9ca9fa3214fd470353327 (diff) |
Merge pull request #142 from darikg/master
Fix #106 - autocompletion in multiple statements
-rw-r--r-- | pgcli/packages/sqlcompletion.py | 28 | ||||
-rw-r--r-- | tests/test_sqlcompletion.py | 43 |
2 files changed, 67 insertions, 4 deletions
diff --git a/pgcli/packages/sqlcompletion.py b/pgcli/packages/sqlcompletion.py index 45e38fed..75d9f98d 100644 --- a/pgcli/packages/sqlcompletion.py +++ b/pgcli/packages/sqlcompletion.py @@ -38,10 +38,30 @@ def suggest_type(full_text, text_before_cursor): else: parsed = sqlparse.parse(text_before_cursor) - # Need to check if `p` is not empty, since an empty string will result in - # an empty tuple. - p = parsed[0] if parsed else None - last_token = p and p.token_prev(len(p.tokens)) or '' + if len(parsed) > 1: + # Multiple statements being edited -- isolate the current one by + # cumulatively summing statement lengths to find the one that bounds the + # current position + current_pos = len(text_before_cursor) + stmt_start, stmt_end = 0, 0 + + for statement in parsed: + stmt_len = len(statement.to_unicode()) + stmt_start, stmt_end = stmt_end, stmt_end + stmt_len + + if stmt_end >= current_pos: + text_before_cursor = full_text[stmt_start:current_pos] + full_text = full_text[stmt_start:] + break + + elif parsed: + # A single statement + statement = parsed[0] + else: + # The empty string + statement = None + + last_token = statement and statement.token_prev(len(statement.tokens)) or '' return suggest_based_on_last_token(last_token, text_before_cursor, full_text) diff --git a/tests/test_sqlcompletion.py b/tests/test_sqlcompletion.py index 22e8c11b..760e4dba 100644 --- a/tests/test_sqlcompletion.py +++ b/tests/test_sqlcompletion.py @@ -183,3 +183,46 @@ def test_on_suggests_tables_right_side(): 'select abc.x, bcd.y from abc join bcd on ', 'select abc.x, bcd.y from abc join bcd on ') assert suggestions == [{'type': 'alias', 'aliases': ['abc', 'bcd']}] + +def test_2_statements_2nd_current(): + suggestions = suggest_type('select * from a; select * from ', + 'select * from a; select * from ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'table', 'schema': []}, {'type': 'schema'}]) + + suggestions = suggest_type('select * from a; select from b', + 'select * from a; select ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'column', 'tables': [(None, 'b', None)]}, + {'type': 'function'}]) + + # Should work even if first statement is invalid + suggestions = suggest_type('select * from; select * from ', + 'select * from; select * from ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'table', 'schema': []}, {'type': 'schema'}]) + +def test_2_statements_1st_current(): + suggestions = suggest_type('select * from ; select * from b', + 'select * from ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'table', 'schema': []}, {'type': 'schema'}]) + + suggestions = suggest_type('select from a; select * from b', + 'select ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'column', 'tables': [(None, 'a', None)]}, + {'type': 'function'}]) + +def test_3_statements_2nd_current(): + suggestions = suggest_type('select * from a; select * from ; select * from c', + 'select * from a; select * from ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'table', 'schema': []}, {'type': 'schema'}]) + + suggestions = suggest_type('select * from a; select from b; select * from c', + 'select * from a; select ') + assert sorted_dicts(suggestions) == sorted_dicts([ + {'type': 'column', 'tables': [(None, 'b', None)]}, + {'type': 'function'}]) + |