summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pgcli/packages/sqlcompletion.py58
-rw-r--r--tests/test_pgspecial.py10
2 files changed, 53 insertions, 15 deletions
diff --git a/pgcli/packages/sqlcompletion.py b/pgcli/packages/sqlcompletion.py
index 885cbd63..5185c8be 100644
--- a/pgcli/packages/sqlcompletion.py
+++ b/pgcli/packages/sqlcompletion.py
@@ -3,6 +3,7 @@ import sys
import sqlparse
from sqlparse.sql import Comparison
from .parseutils import last_word, extract_tables, find_prev_keyword
+from .pgspecial import parse_special_command
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
@@ -30,7 +31,8 @@ def suggest_type(full_text, text_before_cursor):
# partially typed string which renders the smart completion useless because
# it will always return the list of keywords as completion.
if word_before_cursor:
- if word_before_cursor[-1] in ('(', '.'):
+ if (word_before_cursor[-1] in ('(', '.')
+ or word_before_cursor[0] == '\\'):
parsed = sqlparse.parse(text_before_cursor)
else:
parsed = sqlparse.parse(
@@ -61,10 +63,50 @@ def suggest_type(full_text, text_before_cursor):
# The empty string
statement = None
+ # Check for special commands and handle those separately
+ if statement:
+ # Be careful here because trivial whitespace is parsed as a statement,
+ # but the statement won't have a first token
+ tok1 = statement.token_first()
+ if tok1 and tok1.value == '\\':
+ return suggest_special(text_before_cursor)
+
last_token = statement and statement.token_prev(len(statement.tokens)) or ''
return suggest_based_on_last_token(last_token, text_before_cursor, full_text)
+
+def suggest_special(text):
+ cmd, _, arg = parse_special_command(text)
+
+ if cmd == text:
+ # Trying to complete the special command itself
+ return [{'type': 'special'}]
+
+ if cmd == '\\c':
+ return [{'type': 'database'}]
+
+ if arg:
+ # Try to distinguish "\d name" from "\d schema.name"
+ # Note that this will fail to obtain a schema name if wildcards are
+ # used, e.g. "\d schema???.name"
+ parsed = sqlparse.parse(arg)[0].tokens[0]
+ try:
+ schema = parsed.get_parent_name()
+ except AttributeError:
+ schema = None
+ else:
+ schema = None
+
+ if cmd[1:] in ('d', 'dt', 'dv'):
+ if schema:
+ return [{'type': 'table', 'schema': schema}]
+ else:
+ return [{'type': 'schema'}, {'type': 'table', 'schema': []}]
+
+ return [{'type': 'keyword'}, {'type': 'special'}]
+
+
def suggest_based_on_last_token(token, text_before_cursor, full_text):
if isinstance(token, string_types):
token_v = token
@@ -111,20 +153,6 @@ def suggest_based_on_last_token(token, text_before_cursor, full_text):
return [{'type': 'alias', 'aliases': alias}]
- elif token_v in ('d',): # \d
- # Apparently "\d <other>" is parsed by sqlparse as
- # Identifer('d', Whitespace, '<other>')
- if len(token.tokens) > 2:
- other = token.tokens[-1].value
- identifiers = other.split('.')
- if len(identifiers) == 1:
- # "\d table" or "\d schema"
- return [{'type': 'schema'}, {'type': 'table', 'schema': []}]
- elif len(identifiers) == 2:
- # \d schema.table
- return [{'type': 'table', 'schema': identifiers[0]}]
- else:
- return [{'type': 'schema'}, {'type': 'table', 'schema': []}]
elif token_v.lower() in ('c', 'use', 'database', 'template'):
# "\c <db", "use <db>", "DROP DATABASE <db>",
# "CREATE DATABASE <newdb> WITH TEMPLATE <db>"
diff --git a/tests/test_pgspecial.py b/tests/test_pgspecial.py
index f02efac9..9d2834bc 100644
--- a/tests/test_pgspecial.py
+++ b/tests/test_pgspecial.py
@@ -1,6 +1,16 @@
from pgcli.packages.sqlcompletion import suggest_type
from test_sqlcompletion import sorted_dicts
+def test_slash_suggests_special():
+ suggestions = suggest_type('\\', '\\')
+ assert sorted_dicts(suggestions) == sorted_dicts(
+ [{'type': 'special'}])
+
+def test_slash_d_suggests_special():
+ suggestions = suggest_type('\\d', '\\d')
+ assert sorted_dicts(suggestions) == sorted_dicts(
+ [{'type': 'special'}])
+
def test_d_suggests_tables_and_schemas():
suggestions = suggest_type('\d ', '\d ')
assert sorted_dicts(suggestions) == sorted_dicts([