usecli 0.1.70__tar.gz → 0.1.72__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {usecli-0.1.70 → usecli-0.1.72}/PKG-INFO +1 -1
- {usecli-0.1.70 → usecli-0.1.72}/pyproject.toml +1 -1
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/make/make_command.py +12 -3
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/base_command.py +4 -1
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/ui/list.py +44 -9
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/ui/title.py +2 -1
- {usecli-0.1.70 → usecli-0.1.72}/LICENSE +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/README.md +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/README.md +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/custom/README.md +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/custom/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/init_command.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/config/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/config/colors.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/error/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/error/handler.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/error/utils.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/exceptions/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/exceptions/base.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/exceptions/config.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/exceptions/usage.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/exceptions/validation.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/ui/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/ui/title.txt +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/validators/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/validators/network.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/validators/numeric.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/validators/path.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/core/validators/string.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/services/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/services/command_service.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/templates/command.py.j2 +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/templates/theme.toml.j2 +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/ayu_dark.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/default.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/dracula.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/nord.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/themes/tokyo_night.toml +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/utils/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/utils/interactive/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/menu.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/params.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/shared/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/shared/config/__init__.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/shared/config/globals.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/shared/config/manager.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/ui.py +0 -0
- {usecli-0.1.70 → usecli-0.1.72}/src/usecli/usecli.config.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usecli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.72"
|
|
4
4
|
description = "A powerful Python CLI framework for building beautiful, developer-friendly command-line tools."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Edward Boswell", email = "thememium@gmail.com" }]
|
|
@@ -43,9 +43,18 @@ class MakeCommand(BaseCommand):
|
|
|
43
43
|
name: The name of the command to create.
|
|
44
44
|
"""
|
|
45
45
|
clean_name = name.replace("Command", "").replace("command", "")
|
|
46
|
-
class_name =
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
class_name = (
|
|
47
|
+
pascalcase(clean_name.replace(":", "_").replace(" ", "_")) + "Command"
|
|
48
|
+
)
|
|
49
|
+
if ":" in clean_name:
|
|
50
|
+
command_name = clean_name
|
|
51
|
+
elif " " in clean_name:
|
|
52
|
+
command_name = clean_name
|
|
53
|
+
else:
|
|
54
|
+
command_name = snakecase(clean_name)
|
|
55
|
+
file_name = (
|
|
56
|
+
f"{snakecase(clean_name.replace(':', '_').replace(' ', '_'))}_command.py"
|
|
57
|
+
)
|
|
49
58
|
|
|
50
59
|
config = get_config()
|
|
51
60
|
current_root = find_project_root(Path.cwd()) or Path.cwd().resolve()
|
|
@@ -42,6 +42,7 @@ class NestedCommandRegistry:
|
|
|
42
42
|
_instance: ClassVar[NestedCommandRegistry | None] = None
|
|
43
43
|
_groups: dict[str, typer.Typer]
|
|
44
44
|
_group_commands: dict[str, list[dict[str, Any]]]
|
|
45
|
+
_main_app: typer.Typer | None
|
|
45
46
|
|
|
46
47
|
def __new__(cls) -> NestedCommandRegistry:
|
|
47
48
|
"""Ensure singleton pattern for the registry."""
|
|
@@ -49,6 +50,7 @@ class NestedCommandRegistry:
|
|
|
49
50
|
cls._instance = super().__new__(cls)
|
|
50
51
|
cls._instance._groups = {}
|
|
51
52
|
cls._instance._group_commands = {}
|
|
53
|
+
cls._instance._main_app = None
|
|
52
54
|
return cls._instance
|
|
53
55
|
|
|
54
56
|
def get_or_create_group(
|
|
@@ -73,6 +75,7 @@ class NestedCommandRegistry:
|
|
|
73
75
|
)
|
|
74
76
|
self._groups[group_name] = group_app
|
|
75
77
|
self._group_commands[group_name] = []
|
|
78
|
+
self._main_app = main_app
|
|
76
79
|
|
|
77
80
|
# Add the group app to main app
|
|
78
81
|
main_app.add_typer(group_app, name=group_name)
|
|
@@ -142,7 +145,7 @@ class NestedCommandRegistry:
|
|
|
142
145
|
|
|
143
146
|
group_app = self._groups.get(group_name)
|
|
144
147
|
if group_app:
|
|
145
|
-
list_group_commands(group_app, group_name)
|
|
148
|
+
list_group_commands(group_app, group_name, self._main_app)
|
|
146
149
|
|
|
147
150
|
def register_command(
|
|
148
151
|
self,
|
|
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, TypedDict
|
|
|
7
7
|
import click
|
|
8
8
|
import typer
|
|
9
9
|
from rich.console import Console
|
|
10
|
+
from rich.markup import escape
|
|
10
11
|
|
|
11
12
|
from usecli.cli.config.colors import COLOR
|
|
12
13
|
from usecli.cli.core.ui.title import (
|
|
@@ -178,14 +179,14 @@ def list_commands(app: typer.Typer, prefix_filter: str | None = None) -> None:
|
|
|
178
179
|
for cmd in commands
|
|
179
180
|
)
|
|
180
181
|
if has_colon_commands:
|
|
181
|
-
# Colon-separated: use make:COMMAND [OPTIONS]
|
|
182
|
+
# Colon-separated: use make:[COMMAND] [OPTIONS]
|
|
182
183
|
console.print(
|
|
183
|
-
f" [not bold {COLOR.PRIMARY}]{command_name} {prefix_filter}:COMMAND [OPTIONS][/]"
|
|
184
|
+
f" [not bold {COLOR.PRIMARY}]{command_name} {prefix_filter}:{escape('[COMMAND]')} {escape('[OPTIONS]')}[/]"
|
|
184
185
|
)
|
|
185
186
|
else:
|
|
186
187
|
# Space-separated nested groups: use make [COMMAND] [OPTIONS]
|
|
187
188
|
console.print(
|
|
188
|
-
f" [not bold {COLOR.PRIMARY}]{command_name} {prefix_filter} [COMMAND] [OPTIONS][/]"
|
|
189
|
+
f" [not bold {COLOR.PRIMARY}]{command_name} {prefix_filter} {escape('[COMMAND]')} {escape('[OPTIONS]')}[/]"
|
|
189
190
|
)
|
|
190
191
|
console.print()
|
|
191
192
|
console.print(f"[bold {COLOR.SECONDARY}]Options:")
|
|
@@ -203,7 +204,7 @@ def list_commands(app: typer.Typer, prefix_filter: str | None = None) -> None:
|
|
|
203
204
|
else:
|
|
204
205
|
console.print(f"[bold {COLOR.SECONDARY}]Usage:[/bold {COLOR.SECONDARY}]")
|
|
205
206
|
console.print(
|
|
206
|
-
f" [not bold {COLOR.PRIMARY}]{command_name} [OPTIONS] [ARGUMENTS][/]"
|
|
207
|
+
f" [not bold {COLOR.PRIMARY}]{command_name} {escape('[COMMAND]')} {escape('[OPTIONS]')} {escape('[ARGUMENTS]')}[/]"
|
|
207
208
|
)
|
|
208
209
|
console.print()
|
|
209
210
|
|
|
@@ -266,7 +267,9 @@ def list_commands(app: typer.Typer, prefix_filter: str | None = None) -> None:
|
|
|
266
267
|
console.print()
|
|
267
268
|
|
|
268
269
|
|
|
269
|
-
def list_group_commands(
|
|
270
|
+
def list_group_commands(
|
|
271
|
+
group_app: typer.Typer, group_name: str, main_app: typer.Typer | None = None
|
|
272
|
+
) -> None:
|
|
270
273
|
"""List all commands within a specific command group.
|
|
271
274
|
|
|
272
275
|
Displays commands in a formatted list for a nested command group,
|
|
@@ -275,16 +278,31 @@ def list_group_commands(group_app: typer.Typer, group_name: str) -> None:
|
|
|
275
278
|
Args:
|
|
276
279
|
group_app: The Typer sub-app for the command group.
|
|
277
280
|
group_name: The name of the command group.
|
|
281
|
+
main_app: Optional main app to include colon-separated commands.
|
|
278
282
|
"""
|
|
279
283
|
alias_registry = _get_alias_registry(group_app)
|
|
280
284
|
alias_to_primary = _build_alias_to_primary(alias_registry)
|
|
281
285
|
|
|
282
286
|
command_name = get_script_command_name(default="usecli")
|
|
283
287
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
# Check if group has both colon-separated and space-separated commands
|
|
289
|
+
has_colon_commands = main_app is not None and any(
|
|
290
|
+
cmd.name and cmd.name.startswith(f"{group_name}:")
|
|
291
|
+
for cmd in (main_app.registered_commands or [])
|
|
287
292
|
)
|
|
293
|
+
has_nested_commands = len(group_app.registered_commands) > 0
|
|
294
|
+
|
|
295
|
+
console.print(f"[bold {COLOR.SECONDARY}]Usage:[/bold {COLOR.SECONDARY}]")
|
|
296
|
+
if has_colon_commands and has_nested_commands:
|
|
297
|
+
# Both formats exist: usecli [COMMAND] [OPTIONS] [ARGUMENTS]
|
|
298
|
+
console.print(
|
|
299
|
+
f" [not bold {COLOR.PRIMARY}]{command_name} {escape('[COMMAND]')} {escape('[OPTIONS]')} {escape('[ARGUMENTS]')}[/]"
|
|
300
|
+
)
|
|
301
|
+
else:
|
|
302
|
+
# Only space-separated: usecli make [COMMAND] [OPTIONS]
|
|
303
|
+
console.print(
|
|
304
|
+
f" [not bold {COLOR.PRIMARY}]{command_name} {group_name} {escape('[COMMAND]')} {escape('[OPTIONS]')}[/]"
|
|
305
|
+
)
|
|
288
306
|
console.print()
|
|
289
307
|
commands_by_name: dict[str, CommandMeta] = {}
|
|
290
308
|
for command in group_app.registered_commands:
|
|
@@ -303,6 +321,23 @@ def list_group_commands(group_app: typer.Typer, group_name: str) -> None:
|
|
|
303
321
|
"aliases": alias_registry.get(name, list[str]()),
|
|
304
322
|
}
|
|
305
323
|
|
|
324
|
+
# Include colon-separated commands from main app with matching prefix
|
|
325
|
+
if main_app is not None:
|
|
326
|
+
prefix = f"{group_name}:"
|
|
327
|
+
main_alias_registry = _get_alias_registry(main_app)
|
|
328
|
+
for command in main_app.registered_commands:
|
|
329
|
+
cmd_name = command.name or ""
|
|
330
|
+
if not cmd_name.startswith(prefix):
|
|
331
|
+
continue
|
|
332
|
+
if cmd_name in commands_by_name:
|
|
333
|
+
continue
|
|
334
|
+
help_text = command.help or ""
|
|
335
|
+
aliases = main_alias_registry.get(cmd_name, [])
|
|
336
|
+
commands_by_name[cmd_name] = {
|
|
337
|
+
"help": help_text,
|
|
338
|
+
"aliases": aliases,
|
|
339
|
+
}
|
|
340
|
+
|
|
306
341
|
commands: list[CommandEntry] = []
|
|
307
342
|
for name in commands_by_name:
|
|
308
343
|
aliases = commands_by_name[name]["aliases"]
|
|
@@ -355,7 +390,7 @@ def list_group_commands(group_app: typer.Typer, group_name: str) -> None:
|
|
|
355
390
|
display_name = cmd["display_name"]
|
|
356
391
|
padding = " " * (longest_label_length - len(display_name) + SPACER_LENGTH)
|
|
357
392
|
console.print(
|
|
358
|
-
f" [{COLOR.COMMAND}]{display_name}[/{COLOR.COMMAND}]{padding}{cmd['help']}"
|
|
393
|
+
f" [{COLOR.COMMAND} not bold]{display_name}[/{COLOR.COMMAND} not bold]{padding}{cmd['help']}"
|
|
359
394
|
)
|
|
360
395
|
|
|
361
396
|
console.print()
|
|
@@ -131,12 +131,13 @@ def print_title(title: str | None = None) -> None:
|
|
|
131
131
|
|
|
132
132
|
title_font = config.get("title_font", "big") or "big"
|
|
133
133
|
try:
|
|
134
|
-
raw_title = pyfiglet.figlet_format(text=title, font=title_font)
|
|
134
|
+
raw_title = pyfiglet.figlet_format(text=title, font=title_font).rstrip()
|
|
135
135
|
title_text = "\n".join(" " + line for line in raw_title.split("\n"))
|
|
136
136
|
except pyfiglet.FontNotFound:
|
|
137
137
|
title_text = title
|
|
138
138
|
console.print()
|
|
139
139
|
console.print(f"[{COLOR.PRIMARY}]{title_text}")
|
|
140
|
+
console.print()
|
|
140
141
|
except (ImportError, ModuleNotFoundError):
|
|
141
142
|
if title is None or title.lower() == "usecli":
|
|
142
143
|
console.print(f"[{COLOR.PRIMARY}]{default_title_text}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{usecli-0.1.70 → usecli-0.1.72}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|