aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/sqlite3
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/sqlite3')
-rw-r--r--Lib/sqlite3/__main__.py23
-rw-r--r--Lib/sqlite3/_completer.py42
2 files changed, 55 insertions, 10 deletions
diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py
index c2fa23c46cf..35344ecceff 100644
--- a/Lib/sqlite3/__main__.py
+++ b/Lib/sqlite3/__main__.py
@@ -12,6 +12,8 @@ from code import InteractiveConsole
from textwrap import dedent
from _colorize import get_theme, theme_no_color
+from ._completer import completer
+
def execute(c, sql, suppress_errors=True, theme=theme_no_color):
"""Helper that wraps execution of SQL code.
@@ -61,17 +63,21 @@ class SqliteInteractiveConsole(InteractiveConsole):
if source[0] == ".":
match source[1:].strip():
case "version":
- print(f"{sqlite3.sqlite_version}")
+ print(sqlite3.sqlite_version)
case "help":
- print("Enter SQL code and press enter.")
+ t = theme.syntax
+ print(f"Enter SQL code or one of the below commands, and press enter.\n\n"
+ f"{t.builtin}.version{t.reset} Print underlying SQLite library version\n"
+ f"{t.builtin}.help{t.reset} Print this help message\n"
+ f"{t.builtin}.quit{t.reset} Exit the CLI, equivalent to CTRL-D\n")
case "quit":
sys.exit(0)
case "":
pass
case _ as unknown:
t = theme.traceback
- self.write(f'{t.type}Error{t.reset}:{t.message} unknown'
- f'command or invalid arguments: "{unknown}".\n{t.reset}')
+ self.write(f'{t.type}Error{t.reset}: {t.message}unknown '
+ f'command: "{unknown}"{t.reset}\n')
else:
if not sqlite3.complete_statement(source):
return True
@@ -136,12 +142,9 @@ def main(*args):
execute(con, args.sql, suppress_errors=False, theme=theme)
else:
# No SQL provided; start the REPL.
- console = SqliteInteractiveConsole(con, use_color=True)
- try:
- import readline # noqa: F401
- except ImportError:
- pass
- console.interact(banner, exitmsg="")
+ with completer():
+ console = SqliteInteractiveConsole(con, use_color=True)
+ console.interact(banner, exitmsg="")
finally:
con.close()
diff --git a/Lib/sqlite3/_completer.py b/Lib/sqlite3/_completer.py
new file mode 100644
index 00000000000..f21ef69cad6
--- /dev/null
+++ b/Lib/sqlite3/_completer.py
@@ -0,0 +1,42 @@
+from contextlib import contextmanager
+
+try:
+ from _sqlite3 import SQLITE_KEYWORDS
+except ImportError:
+ SQLITE_KEYWORDS = ()
+
+_completion_matches = []
+
+
+def _complete(text, state):
+ global _completion_matches
+
+ if state == 0:
+ text_upper = text.upper()
+ _completion_matches = [c for c in SQLITE_KEYWORDS if c.startswith(text_upper)]
+ try:
+ return _completion_matches[state] + " "
+ except IndexError:
+ return None
+
+
+@contextmanager
+def completer():
+ try:
+ import readline
+ except ImportError:
+ yield
+ return
+
+ old_completer = readline.get_completer()
+ try:
+ readline.set_completer(_complete)
+ if readline.backend == "editline":
+ # libedit uses "^I" instead of "tab"
+ command_string = "bind ^I rl_complete"
+ else:
+ command_string = "tab: complete"
+ readline.parse_and_bind(command_string)
+ yield
+ finally:
+ readline.set_completer(old_completer)