diff --git a/toot/cli/__init__.py b/toot/cli/__init__.py index f36d70a..0c71cb3 100644 --- a/toot/cli/__init__.py +++ b/toot/cli/__init__.py @@ -4,11 +4,14 @@ import os import sys import typing as t +from click.shell_completion import CompletionItem from click.testing import Result +from click.types import StringParamType from functools import wraps + from toot import App, User, config, __version__ -from toot.settings import get_settings from toot.output import print_warning +from toot.settings import get_settings if t.TYPE_CHECKING: import typing_extensions as te @@ -89,10 +92,24 @@ class TootObj(t.NamedTuple): """Data to add to Click context""" color: bool = True debug: bool = False + as_user: t.Optional[str] = None # Pass a context for testing purposes test_ctx: t.Optional[Context] = None +class AccountParamType(StringParamType): + """Custom type to add shell completion for account names""" + name = "account" + + def shell_complete(self, ctx, param, incomplete: str): + users = config.load_config()["users"].keys() + return [ + CompletionItem(u) + for u in users + if u.lower().startswith(incomplete.lower()) + ] + + def pass_context(f: "t.Callable[te.Concatenate[Context, P], R]") -> "t.Callable[P, R]": """Pass the toot Context as first argument.""" @wraps(f) @@ -110,9 +127,14 @@ def get_context() -> Context: if obj.test_ctx: return obj.test_ctx - user, app = config.get_active_user_app() - if not user or not app: - raise click.ClickException("This command requires you to be logged in.") + if obj.as_user: + user, app = config.get_user_app(obj.as_user) + if not user or not app: + raise click.ClickException(f"Account '{obj.as_user}' not found. Run `toot auth` to see available accounts.") + else: + user, app = config.get_active_user_app() + if not user or not app: + raise click.ClickException("This command requires you to be logged in.") return Context(app, user, obj.color, obj.debug) @@ -129,11 +151,12 @@ json_option = click.option( @click.option("-w", "--max-width", type=int, default=80, help="Maximum width for content rendered by toot") @click.option("--debug/--no-debug", default=False, help="Log debug info to stderr") @click.option("--color/--no-color", default=sys.stdout.isatty(), help="Use ANSI color in output") +@click.option("--as", "as_user", type=AccountParamType(), help="The account to use, overrides the active account.") @click.version_option(__version__, message="%(prog)s v%(version)s") @click.pass_context -def cli(ctx: click.Context, max_width: int, color: bool, debug: bool): +def cli(ctx: click.Context, max_width: int, color: bool, debug: bool, as_user: str): """Toot is a Mastodon CLI""" - ctx.obj = TootObj(color, debug) + ctx.obj = TootObj(color, debug, as_user) ctx.color = color ctx.max_content_width = max_width diff --git a/toot/cli/auth.py b/toot/cli/auth.py index c72f0c4..b7d32e6 100644 --- a/toot/cli/auth.py +++ b/toot/cli/auth.py @@ -2,13 +2,10 @@ import click import platform import sys import webbrowser -from click.shell_completion import CompletionItem - -from click.types import StringParamType from toot import api, config, __version__ from toot.auth import get_or_create_app, login_auth_code, login_username_password -from toot.cli import cli +from toot.cli import AccountParamType, cli from toot.cli.validators import validate_instance @@ -22,18 +19,6 @@ instance_option = click.option( ) -class AccountParamType(StringParamType): - """Custom type to add shell completion for account names""" - - def shell_complete(self, ctx, param, incomplete: str): - accounts = config.load_config()["users"].keys() - return [ - CompletionItem(a) - for a in accounts - if a.lower().startswith(incomplete.lower()) - ] - - @cli.command() def auth(): """Show logged in accounts and instances"""