skit-cli 0.0.1__py3-none-any.whl
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.
- skit/__init__.py +3 -0
- skit/analyzer.py +410 -0
- skit/argspec.py +528 -0
- skit/argstate.py +166 -0
- skit/atomic.py +101 -0
- skit/cli.py +1621 -0
- skit/config.py +255 -0
- skit/editor.py +77 -0
- skit/flows.py +596 -0
- skit/i18n.py +324 -0
- skit/inlineform.py +61 -0
- skit/launcher.py +326 -0
- skit/locales/zh_CN/LC_MESSAGES/skit.mo +0 -0
- skit/locales/zh_TW/LC_MESSAGES/skit.mo +0 -0
- skit/metawriter.py +267 -0
- skit/models.py +154 -0
- skit/paths.py +44 -0
- skit/pep723.py +292 -0
- skit/promptform.py +67 -0
- skit/reconcile.py +321 -0
- skit/shim.py +386 -0
- skit/store.py +566 -0
- skit/theme.py +123 -0
- skit/tokens.py +112 -0
- skit/tui.py +774 -0
- skit/tui_add.py +361 -0
- skit/tui_footer.py +38 -0
- skit/tui_form.py +586 -0
- skit/tui_health.py +150 -0
- skit/tui_prefs.py +175 -0
- skit/tui_settings.py +374 -0
- skit/uvman.py +288 -0
- skit_cli-0.0.1.dist-info/METADATA +199 -0
- skit_cli-0.0.1.dist-info/RECORD +37 -0
- skit_cli-0.0.1.dist-info/WHEEL +4 -0
- skit_cli-0.0.1.dist-info/entry_points.txt +3 -0
- skit_cli-0.0.1.dist-info/licenses/LICENSE +21 -0
skit/tokens.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Value tokens: run-time placeholders usable inside any form value.
|
|
2
|
+
|
|
3
|
+
`{cwd}` (invoke-time working directory), `{today}` (YYYY-MM-DD), `{now}` (HH-MM-SS),
|
|
4
|
+
`{env:NAME}` (environment variable), and a leading `~` (home). Values store the token
|
|
5
|
+
TEXT (intent), never the expanded result — argstate/presets persist `out_{today}.png`,
|
|
6
|
+
and every run expands fresh (the same rule that keeps `shots/*.png` a living glob).
|
|
7
|
+
|
|
8
|
+
Expansion contract:
|
|
9
|
+
- Only the known token names above are expanded. Any other `{...}` passes through
|
|
10
|
+
untouched — a value may legitimately contain braces destined for the script itself.
|
|
11
|
+
- `{{` and `}}` escape to literal `{` / `}` (the way to pass a literal `{cwd}` through).
|
|
12
|
+
- A missing environment variable is an error, never a silent empty string — a command
|
|
13
|
+
quietly assembled around "" is exactly the kind of breakage the non-interactive
|
|
14
|
+
contract forbids.
|
|
15
|
+
|
|
16
|
+
This module is headless and stdlib-only; `cwd`/`env`/`now` are injectable for tests.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import re
|
|
23
|
+
from collections.abc import Mapping
|
|
24
|
+
from datetime import datetime
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
from .i18n import gettext
|
|
28
|
+
|
|
29
|
+
# {cwd} / {today} / {now} / {env:NAME}; NAME follows the usual environment-variable shape.
|
|
30
|
+
_TOKEN_RE = re.compile(r"\{(cwd|today|now|env:(?P<env>[A-Za-z_][A-Za-z0-9_]*))\}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TokenError(ValueError):
|
|
34
|
+
"""A token cannot be expanded (currently: the named environment variable is unset)."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def expand(
|
|
38
|
+
text: str,
|
|
39
|
+
*,
|
|
40
|
+
cwd: Path | str,
|
|
41
|
+
env: Mapping[str, str] | None = None,
|
|
42
|
+
now: datetime | None = None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Expand tokens in text and return the final value. Raises TokenError."""
|
|
45
|
+
if env is None:
|
|
46
|
+
env = os.environ
|
|
47
|
+
if now is None:
|
|
48
|
+
now = datetime.now()
|
|
49
|
+
if text.startswith("~"):
|
|
50
|
+
text = os.path.expanduser(text)
|
|
51
|
+
out: list[str] = []
|
|
52
|
+
i = 0
|
|
53
|
+
n = len(text)
|
|
54
|
+
while i < n:
|
|
55
|
+
ch = text[i]
|
|
56
|
+
two = text[i : i + 2]
|
|
57
|
+
if two == "{{":
|
|
58
|
+
out.append("{")
|
|
59
|
+
i += 2
|
|
60
|
+
continue
|
|
61
|
+
if two == "}}":
|
|
62
|
+
out.append("}")
|
|
63
|
+
i += 2
|
|
64
|
+
continue
|
|
65
|
+
if ch == "{":
|
|
66
|
+
m = _TOKEN_RE.match(text, i)
|
|
67
|
+
if m is not None:
|
|
68
|
+
out.append(_resolve(m, cwd=cwd, env=env, now=now))
|
|
69
|
+
i = m.end()
|
|
70
|
+
continue
|
|
71
|
+
out.append(ch)
|
|
72
|
+
i += 1
|
|
73
|
+
return "".join(out)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _resolve(m: re.Match[str], *, cwd: Path | str, env: Mapping[str, str], now: datetime) -> str:
|
|
77
|
+
name = m.group(1)
|
|
78
|
+
if name == "cwd":
|
|
79
|
+
return str(cwd)
|
|
80
|
+
if name == "today":
|
|
81
|
+
return now.strftime("%Y-%m-%d")
|
|
82
|
+
if name == "now":
|
|
83
|
+
return now.strftime("%H-%M-%S")
|
|
84
|
+
env_name = m.group("env")
|
|
85
|
+
if env_name not in env:
|
|
86
|
+
raise TokenError(
|
|
87
|
+
gettext("The environment variable %(name)s isn't set (needed by %(token)s).")
|
|
88
|
+
% {"name": env_name, "token": m.group(0)}
|
|
89
|
+
)
|
|
90
|
+
return env[env_name]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def preview(
|
|
94
|
+
text: str,
|
|
95
|
+
*,
|
|
96
|
+
cwd: Path | str,
|
|
97
|
+
env: Mapping[str, str] | None = None,
|
|
98
|
+
now: datetime | None = None,
|
|
99
|
+
) -> tuple[str, str | None]:
|
|
100
|
+
"""Non-raising expand for live form previews: (expanded, None) on success,
|
|
101
|
+
(original text, error message) when a token can't be expanded."""
|
|
102
|
+
try:
|
|
103
|
+
return expand(text, cwd=cwd, env=env, now=now), None
|
|
104
|
+
except TokenError as exc:
|
|
105
|
+
return text, str(exc)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def has_tokens(text: str) -> bool:
|
|
109
|
+
"""Whether expand() would change text (used to decide if a preview line is worth showing)."""
|
|
110
|
+
return (
|
|
111
|
+
text.startswith("~") or "{{" in text or "}}" in text or _TOKEN_RE.search(text) is not None
|
|
112
|
+
)
|