Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Upcoming (TBD)
Features
--------
* Sort completion candidates by frecency from history.
* Add help snippets in special /command completions.


Internal
Expand Down
8 changes: 8 additions & 0 deletions mycli/client_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ def register_special_commands(self) -> None:
"/use <database>",
"Change to a new database.",
aliases=[SpecialCommandAlias("\\u", case_sensitive=False)],
completion_snippet='change databases',
)
special.register_special_command(
self.manual_reconnect,
Expand All @@ -245,6 +246,7 @@ def register_special_commands(self) -> None:
"Reconnect to the server, optionally switching databases.",
case_sensitive=True,
aliases=[SpecialCommandAlias("\\r", case_sensitive=True)],
completion_snippet='reconnect to server',
)
special.register_special_command(
self.rehash,
Expand All @@ -253,6 +255,7 @@ def register_special_commands(self) -> None:
"Refresh auto-completions.",
arg_type=ArgType.NO_ARGUMENT,
aliases=[SpecialCommandAlias("\\#", case_sensitive=False)],
completion_snippet='refresh completions',
)
special.register_special_command(
self.change_table_format,
Expand All @@ -261,6 +264,7 @@ def register_special_commands(self) -> None:
"Change the table format used to output interactive results.",
case_sensitive=True,
aliases=[SpecialCommandAlias("\\T", case_sensitive=True)],
completion_snippet='change interactive output format',
)
special.register_special_command(
self.change_redirect_format,
Expand All @@ -269,13 +273,15 @@ def register_special_commands(self) -> None:
"Change the table format used to output redirected results.",
case_sensitive=True,
aliases=[SpecialCommandAlias("\\Tr", case_sensitive=True)],
completion_snippet='change redirected output format',
)
special.register_special_command(
self.execute_from_file,
"source",
"/source [--special|--show|--page] <file>",
"Execute queries from a file.",
aliases=[SpecialCommandAlias("\\.", case_sensitive=False)],
completion_snippet='execute queries from file',
)
special.register_special_command(
self.change_prompt_format,
Expand All @@ -284,12 +290,14 @@ def register_special_commands(self) -> None:
"Show or change prompt format.",
case_sensitive=True,
aliases=[SpecialCommandAlias("\\R", case_sensitive=True)],
completion_snippet='show or change prompt format',
)
special.register_special_command(
self.config_command,
r'\config',
'/config <help|get|search|edit> [key]',
'Inspect settings from config files.',
completion_snippet='inspect config file settings',
)

def manual_reconnect(self, arg: str = "", **_) -> Generator[SQLResult, None, None]:
Expand Down
2 changes: 1 addition & 1 deletion mycli/completion_refresher.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def refresh_collations(completer: SQLCompleter, executor: SQLExecute) -> None:

@refresher("special_commands")
def refresh_special(completer: SQLCompleter, executor: SQLExecute) -> None:
completer.extend_special_commands(list(COMMANDS.keys()))
completer.extend_special_commands({command: details.completion_snippet or details.description for command, details in COMMANDS.items()})


@refresher("show_commands")
Expand Down
3 changes: 3 additions & 0 deletions mycli/packages/special/dbcommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"List or describe tables.",
arg_type=ArgType.PARSED_QUERY,
case_sensitive=True,
completion_snippet='list or describe tables',
)
def list_tables(
cur: Cursor,
Expand Down Expand Up @@ -65,6 +66,7 @@ def list_tables(
"List databases.",
arg_type=ArgType.RAW_QUERY,
case_sensitive=True,
completion_snippet='list databases',
)
def list_databases(cur: Cursor, **_) -> list[SQLResult]:
query = "SHOW DATABASES"
Expand All @@ -85,6 +87,7 @@ def list_databases(cur: Cursor, **_) -> list[SQLResult]:
arg_type=ArgType.RAW_QUERY,
case_sensitive=True,
aliases=[SpecialCommandAlias("\\s", case_sensitive=True)],
completion_snippet='get status from server',
)
def status(cur: Cursor, **_) -> list[SQLResult]:
query = "SHOW GLOBAL STATUS;"
Expand Down
17 changes: 17 additions & 0 deletions mycli/packages/special/iocommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def is_show_warnings_enabled() -> bool:
arg_type=ArgType.NO_ARGUMENT,
case_sensitive=True,
aliases=[SpecialCommandAlias('\\W', case_sensitive=True)],
completion_snippet='enable warnings display',
)
def enable_show_warnings() -> Generator[SQLResult, None, None]:
global SHOW_WARNINGS_ENABLED
Expand All @@ -129,6 +130,7 @@ def enable_show_warnings() -> Generator[SQLResult, None, None]:
arg_type=ArgType.NO_ARGUMENT,
case_sensitive=True,
aliases=[SpecialCommandAlias('\\w', case_sensitive=True)],
completion_snippet='disable warnings display',
)
def disable_show_warnings() -> Generator[SQLResult, None, None]:
global SHOW_WARNINGS_ENABLED
Expand All @@ -144,6 +146,7 @@ def disable_show_warnings() -> Generator[SQLResult, None, None]:
arg_type=ArgType.PARSED_QUERY,
case_sensitive=True,
aliases=[SpecialCommandAlias("\\P", case_sensitive=True)],
completion_snippet='set pager',
)
def set_pager(arg: str, **_) -> list[SQLResult]:
if arg:
Expand All @@ -168,6 +171,7 @@ def set_pager(arg: str, **_) -> list[SQLResult]:
arg_type=ArgType.NO_ARGUMENT,
case_sensitive=True,
aliases=[SpecialCommandAlias("\\n", case_sensitive=True)],
completion_snippet='disable pager',
)
def disable_pager() -> list[SQLResult]:
set_pager_enabled(False)
Expand All @@ -181,6 +185,7 @@ def disable_pager() -> list[SQLResult]:
arg_type=ArgType.NO_ARGUMENT,
case_sensitive=True,
aliases=[SpecialCommandAlias("\\t", case_sensitive=True)],
completion_snippet='toggle query timing',
)
def toggle_timing() -> list[SQLResult]:
global TIMING_ENABLED
Expand Down Expand Up @@ -356,6 +361,7 @@ def set_redirect(command_part: str | None, file_operator_part: str | None, file_
'Alternative favorite query interface. See /favorite help.',
arg_type=ArgType.PARSED_QUERY,
case_sensitive=False,
completion_snippet='manage favorite queries',
)
def favorite(arg: str, cur: Cursor | None = None, **_) -> Iterable[SQLResult]:
args = arg.strip().split(maxsplit=1)
Expand Down Expand Up @@ -411,6 +417,7 @@ def favorite(arg: str, cur: Cursor | None = None, **_) -> Iterable[SQLResult]:
"List or execute favorite queries.",
arg_type=ArgType.PARSED_QUERY,
case_sensitive=True,
completion_snippet='list or run favorite queries',
)
def execute_favorite_query(cur: Cursor, arg: str, **_) -> Generator[SQLResult, None, None]:
if arg == "":
Expand Down Expand Up @@ -582,6 +589,7 @@ def subst_favorite_query_args(query: str, args: list[str]) -> list[str | None]:
"\\fs",
"/fs <name> <query>",
"Save a favorite query.",
completion_snippet='save favorite queries',
)
def save_favorite_query(arg: str, **_) -> list[SQLResult]:
"""Save a new favorite query."""
Expand Down Expand Up @@ -636,6 +644,7 @@ def is_favorite_save_command(statement: str) -> bool:
"\\fd",
"/fd <name>",
"Delete a favorite query.",
completion_snippet='delete favorite queries',
)
def delete_favorite_query(arg: str, **_) -> list[SQLResult]:
"""Delete an existing favorite query."""
Expand All @@ -658,6 +667,7 @@ def _delete_favorite_query(arg: str, usage: str) -> list[SQLResult]:
'Manage saved DSNs. See /dsn help.',
arg_type=ArgType.PARSED_QUERY,
case_sensitive=False,
completion_snippet='manage saved DSNs',
)
def dsn(
cur: Cursor,
Expand Down Expand Up @@ -734,6 +744,7 @@ def _edit_dsn_alias(alias: str) -> list[SQLResult]:
"system",
"/system [-r] <command>",
"Execute a system shell command (raw mode with -r).",
completion_snippet='execute system command',
)
def execute_system_command(arg: str, **_) -> list[SQLResult]:
"""Execute a system shell command."""
Expand Down Expand Up @@ -815,6 +826,7 @@ def parseargfile(arg: str) -> tuple[str, str]:
"tee",
"/tee [-o] <file>",
"Append all results to an output file (overwrite using -o).",
completion_snippet='append all results to file',
)
def set_tee(arg: str, **_) -> list[SQLResult]:
global tee_file
Expand All @@ -838,6 +850,7 @@ def close_tee() -> None:
"notee",
"/notee",
"Stop writing results to an output file.",
completion_snippet='stop writing to tee file',
)
def no_tee(arg: str, **_) -> list[SQLResult]:
close_tee()
Expand All @@ -859,6 +872,7 @@ def write_tee(output: str | ANSI | FormattedText, nl: bool = True) -> None:
"/once [-o] <file>",
"Append next result to an output file (overwrite using -o).",
aliases=[SpecialCommandAlias("\\o", case_sensitive=False)],
completion_snippet='append one result to file',
)
def set_once(arg: str, **_) -> list[SQLResult]:
global once_file, written_to_once_file
Expand Down Expand Up @@ -922,6 +936,7 @@ def _run_post_redirect_hook(post_redirect_command: str, filename: str) -> None:
"/pipe_once <command>",
"Send next result to a subprocess.",
aliases=[SpecialCommandAlias("\\|", case_sensitive=False)],
completion_snippet='send one result to subprocess',
)
def set_pipe_once(arg: str, **_) -> list[SQLResult]:
if not arg:
Expand Down Expand Up @@ -985,6 +1000,7 @@ def flush_pipe_once_if_written(post_redirect_command: str) -> None:
"watch",
"/watch [seconds] [-c] <query>",
"Execute query every [seconds] seconds (5 by default).",
completion_snippet='run query every N seconds',
)
def watch_query(arg: str, **kwargs) -> Generator[SQLResult, None, None]:
usage = """Syntax: watch [seconds] [-c] query.
Expand Down Expand Up @@ -1056,6 +1072,7 @@ def watch_query(arg: str, **kwargs) -> Generator[SQLResult, None, None]:
"delimiter",
"/delimiter <string>",
"Change end-of-statement delimiter.",
completion_snippet='change end-of-statement delimiter',
)
def set_delimiter(arg: str, **_) -> list[SQLResult]:
return delimiter_command.set(arg)
Expand Down
22 changes: 21 additions & 1 deletion mycli/packages/special/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class SpecialCommand:
case_sensitive: bool | None
aliases: list[SpecialCommandAlias] | None
backslash_only: bool
completion_snippet: str | None = None


class CommandNotFound(Exception):
Expand Down Expand Up @@ -86,6 +87,7 @@ def special_command(
case_sensitive: bool = False,
aliases: list[SpecialCommandAlias] | None = None,
backslash_only: bool = False,
completion_snippet: str | None = None,
) -> Callable:
def wrapper(wrapped):
register_special_command(
Expand All @@ -98,6 +100,7 @@ def wrapper(wrapped):
case_sensitive=case_sensitive,
aliases=aliases,
backslash_only=backslash_only,
completion_snippet=completion_snippet,
)
return wrapped

Expand All @@ -114,6 +117,7 @@ def register_special_command(
case_sensitive: bool = False,
aliases: list[SpecialCommandAlias] | None = None,
backslash_only: bool = False,
completion_snippet: str | None = None,
) -> None:
if command.startswith('\\'):
forwardslash_command = '/' + command.removeprefix('\\')
Expand All @@ -131,6 +135,7 @@ def register_special_command(
case_sensitive=case_sensitive,
aliases=aliases,
backslash_only=backslash_only,
completion_snippet=completion_snippet,
)
if not backslash_only:
COMMANDS[fcmd] = SpecialCommand(
Expand All @@ -143,6 +148,7 @@ def register_special_command(
case_sensitive=case_sensitive,
aliases=aliases,
backslash_only=backslash_only,
completion_snippet=completion_snippet,
)
if case_sensitive:
CASE_SENSITIVE_COMMANDS.add(command)
Expand Down Expand Up @@ -174,6 +180,7 @@ def register_special_command(
hidden=True,
aliases=None,
backslash_only=backslash_only,
completion_snippet=completion_snippet,
)
if not backslash_only:
COMMANDS[fcmd] = SpecialCommand(
Expand All @@ -186,6 +193,7 @@ def register_special_command(
hidden=True,
aliases=None,
backslash_only=backslash_only,
completion_snippet=completion_snippet,
)


Expand Down Expand Up @@ -226,6 +234,7 @@ def execute(cur: Cursor, sql: str) -> list[SQLResult]:
"Show this table, or search for help on a term.",
arg_type=ArgType.NO_ARGUMENT,
aliases=[SpecialCommandAlias("\\?", case_sensitive=False), SpecialCommandAlias("?", case_sensitive=False)],
completion_snippet='show help or search',
)
def show_help(*_args) -> list[SQLResult]:
header = ["Command", "Shortcut", "Usage", "Description"]
Expand Down Expand Up @@ -288,7 +297,13 @@ def show_keyword_help(cur: Cursor, arg: str) -> list[SQLResult]:
return _show_mysql_help(cur, keyword)


@special_command('\\bug', '/bug', 'File a bug on GitHub.', arg_type=ArgType.NO_ARGUMENT)
@special_command(
'\\bug',
'/bug',
'File a bug on GitHub.',
arg_type=ArgType.NO_ARGUMENT,
completion_snippet='file a bug on GitHub',
)
def file_bug(*_args) -> list[SQLResult]:
webbrowser.open_new_tab(ISSUES_URL)
return [SQLResult(status=f'{ISSUES_URL} — press "New Issue"')]
Expand All @@ -300,13 +315,15 @@ def file_bug(*_args) -> list[SQLResult]:
"Exit.",
arg_type=ArgType.NO_ARGUMENT,
aliases=[SpecialCommandAlias("\\q", case_sensitive=False)],
completion_snippet='exit',
)
@special_command(
"quit",
"/quit",
"Quit.",
arg_type=ArgType.NO_ARGUMENT,
aliases=[SpecialCommandAlias("\\q", case_sensitive=False)],
completion_snippet='exit',
)
def quit_(*_args):
raise EOFError
Expand All @@ -319,13 +336,15 @@ def quit_(*_args):
arg_type=ArgType.NO_ARGUMENT,
case_sensitive=True,
aliases=[SpecialCommandAlias("\\e", case_sensitive=True)],
completion_snippet='edit query with editor',
)
@special_command(
"\\clip",
"/clip | <query>\\clip",
"Copy query to the system clipboard.",
arg_type=ArgType.NO_ARGUMENT,
case_sensitive=True,
completion_snippet='copy query to clipboard',
)
@special_command(
"\\G",
Expand Down Expand Up @@ -364,6 +383,7 @@ def stub():
arg_type=ArgType.RAW_QUERY,
case_sensitive=True,
aliases=[SpecialCommandAlias("\\ai", case_sensitive=True)],
completion_snippet='interrogate an LLM',
)
def llm_stub():
raise NotImplementedError
Loading
Loading