packages
This commit is contained in:
@@ -19,44 +19,44 @@
|
|||||||
"cachyos": {
|
"cachyos": {
|
||||||
"variables": {
|
"variables": {
|
||||||
"base": "10.0",
|
"base": "10.0",
|
||||||
"release": "20251222"
|
"release": "20260102"
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
"proton": {
|
"proton": {
|
||||||
"hash": "sha256-W7cC4pi8WED4rOEXYVXIio1tiUNvArzqsTl6xKwy/mY="
|
"hash": "sha256-e2A9jrAGUHlD8KUuGjkLUhknclBxVZVYKJFElUEs0Us="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cachyos-v2": {
|
"cachyos-v2": {
|
||||||
"variables": {
|
"variables": {
|
||||||
"base": "10.0",
|
"base": "10.0",
|
||||||
"release": "20251222"
|
"release": "20260102"
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
"proton": {
|
"proton": {
|
||||||
"hash": "sha256-S5i8RBbrPAlsYYavzzhTFanLU3uyLT3OQRpX9S6pPE0="
|
"hash": "sha256-e2A9jrAGUHlD8KUuGjkLUhknclBxVZVYKJFElUEs0Us="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cachyos-v3": {
|
"cachyos-v3": {
|
||||||
"variables": {
|
"variables": {
|
||||||
"base": "10.0",
|
"base": "10.0",
|
||||||
"release": "20251222"
|
"release": "20260102"
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
"proton": {
|
"proton": {
|
||||||
"hash": "sha256-tw1/uX4qZX3cQKyzsss8l+wHKLoJF2/8B+6RUIQt4oQ="
|
"hash": "sha256-e2A9jrAGUHlD8KUuGjkLUhknclBxVZVYKJFElUEs0Us="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cachyos-v4": {
|
"cachyos-v4": {
|
||||||
"variables": {
|
"variables": {
|
||||||
"base": "10.0",
|
"base": "10.0",
|
||||||
"release": "20251222"
|
"release": "20260102"
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
"proton": {
|
"proton": {
|
||||||
"hash": "sha256-1+6nCUc93vVZg3j4oSwuM7DYOZ2bNbLIjbH+8OUOSAQ="
|
"hash": "sha256-e2A9jrAGUHlD8KUuGjkLUhknclBxVZVYKJFElUEs0Us="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
290
scripts/version_tui.py
Normal file → Executable file
290
scripts/version_tui.py
Normal file → Executable file
@@ -184,6 +184,16 @@ def http_get_json(url: str, token: Optional[str] = None) -> Any:
|
|||||||
with urllib.request.urlopen(req) as resp:
|
with urllib.request.urlopen(req) as resp:
|
||||||
return json.loads(resp.read().decode("utf-8"))
|
return json.loads(resp.read().decode("utf-8"))
|
||||||
|
|
||||||
|
def http_get_text(url: str) -> Optional[str]:
|
||||||
|
try:
|
||||||
|
# Provide a basic User-Agent to avoid some hosts rejecting the request
|
||||||
|
req = urllib.request.Request(url, headers={"User-Agent": "version-tui/1.0"})
|
||||||
|
with urllib.request.urlopen(req) as resp:
|
||||||
|
return resp.read().decode("utf-8")
|
||||||
|
except Exception as e:
|
||||||
|
eprintln(f"http_get_text failed for {url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def gh_latest_release(owner: str, repo: str, token: Optional[str]) -> Optional[str]:
|
def gh_latest_release(owner: str, repo: str, token: Optional[str]) -> Optional[str]:
|
||||||
try:
|
try:
|
||||||
data = http_get_json(f"https://api.github.com/repos/{owner}/{repo}/releases/latest", token)
|
data = http_get_json(f"https://api.github.com/repos/{owner}/{repo}/releases/latest", token)
|
||||||
@@ -201,6 +211,14 @@ def gh_latest_tag(owner: str, repo: str, token: Optional[str]) -> Optional[str]:
|
|||||||
eprintln(f"latest_tag failed for {owner}/{repo}: {e}")
|
eprintln(f"latest_tag failed for {owner}/{repo}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def gh_list_tags(owner: str, repo: str, token: Optional[str]) -> List[str]:
|
||||||
|
try:
|
||||||
|
data = http_get_json(f"https://api.github.com/repos/{owner}/{repo}/tags?per_page=100", token)
|
||||||
|
return [t.get("name") for t in data if isinstance(t, dict) and "name" in t]
|
||||||
|
except Exception as e:
|
||||||
|
eprintln(f"list_tags failed for {owner}/{repo}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
def gh_head_commit(owner: str, repo: str) -> Optional[str]:
|
def gh_head_commit(owner: str, repo: str) -> Optional[str]:
|
||||||
out = run_get_stdout(["git", "ls-remote", f"https://github.com/{owner}/{repo}.git", "HEAD"])
|
out = run_get_stdout(["git", "ls-remote", f"https://github.com/{owner}/{repo}.git", "HEAD"])
|
||||||
if not out:
|
if not out:
|
||||||
@@ -358,11 +376,46 @@ class PackageDetailScreen(ScreenBase):
|
|||||||
repo = comp.get("repo")
|
repo = comp.get("repo")
|
||||||
if owner and repo:
|
if owner and repo:
|
||||||
r = gh_latest_release(owner, repo, self.gh_token)
|
r = gh_latest_release(owner, repo, self.gh_token)
|
||||||
if r: c["release"] = r
|
if r:
|
||||||
|
c["release"] = r
|
||||||
t = gh_latest_tag(owner, repo, self.gh_token)
|
t = gh_latest_tag(owner, repo, self.gh_token)
|
||||||
if t: c["tag"] = t
|
if t:
|
||||||
|
c["tag"] = t
|
||||||
m = gh_head_commit(owner, repo)
|
m = gh_head_commit(owner, repo)
|
||||||
if m: c["commit"] = m
|
if m:
|
||||||
|
c["commit"] = m
|
||||||
|
|
||||||
|
# Special-case raspberrypi/linux: prefer latest stable_* tag or series-specific tags
|
||||||
|
try:
|
||||||
|
if owner == "raspberrypi" and repo == "linux":
|
||||||
|
tags_all = gh_list_tags(owner, repo, self.gh_token)
|
||||||
|
rendered = render_templates(comp, self.merged_vars)
|
||||||
|
cur_tag = str(rendered.get("tag") or "")
|
||||||
|
# If current tag uses stable_YYYYMMDD scheme, pick latest stable_* tag
|
||||||
|
if cur_tag.startswith("stable_"):
|
||||||
|
stable_tags = sorted(
|
||||||
|
[x for x in tags_all if re.match(r"^stable_\d{8}$", x)],
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
if stable_tags:
|
||||||
|
c["tag"] = stable_tags[0]
|
||||||
|
else:
|
||||||
|
# Try to pick a tag matching the current major.minor series if available
|
||||||
|
mm = str(self.merged_vars.get("modDirVersion") or "")
|
||||||
|
m2 = re.match(r"^(\d+)\.(\d+)", mm)
|
||||||
|
if m2:
|
||||||
|
base = f"rpi-{m2.group(1)}.{m2.group(2)}"
|
||||||
|
series_tags = [x for x in tags_all if (
|
||||||
|
x == f"{base}.y"
|
||||||
|
or x.startswith(f"{base}.y")
|
||||||
|
or x.startswith(f"{base}.")
|
||||||
|
)]
|
||||||
|
series_tags.sort(reverse=True)
|
||||||
|
if series_tags:
|
||||||
|
c["tag"] = series_tags[0]
|
||||||
|
except Exception as _e:
|
||||||
|
# Fallback to previously computed values
|
||||||
|
pass
|
||||||
elif fetcher == "git":
|
elif fetcher == "git":
|
||||||
url = comp.get("url")
|
url = comp.get("url")
|
||||||
if url:
|
if url:
|
||||||
@@ -414,6 +467,126 @@ class PackageDetailScreen(ScreenBase):
|
|||||||
return nix_prefetch_url(url)
|
return nix_prefetch_url(url)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def cachyos_suffix(self) -> str:
|
||||||
|
if self.vidx == 0:
|
||||||
|
return ""
|
||||||
|
v = self.variants[self.vidx]
|
||||||
|
mapping = {"rc": "-rc", "hardened": "-hardened", "lts": "-lts"}
|
||||||
|
return mapping.get(v, "")
|
||||||
|
|
||||||
|
def fetch_cachyos_linux_latest(self, suffix: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Try to determine latest linux version from upstream:
|
||||||
|
- Prefer .SRCINFO (preprocessed)
|
||||||
|
- Fallback to PKGBUILD (parse pkgver= line)
|
||||||
|
Tries both 'CachyOS' and 'cachyos' org casing just in case.
|
||||||
|
"""
|
||||||
|
bases = [
|
||||||
|
"https://raw.githubusercontent.com/CachyOS/linux-cachyos/master",
|
||||||
|
"https://raw.githubusercontent.com/cachyos/linux-cachyos/master",
|
||||||
|
]
|
||||||
|
paths = [
|
||||||
|
f"linux-cachyos{suffix}/.SRCINFO",
|
||||||
|
f"linux-cachyos{suffix}/PKGBUILD",
|
||||||
|
]
|
||||||
|
|
||||||
|
def parse_srcinfo(text: str) -> Optional[str]:
|
||||||
|
m = re.search(r"^\s*pkgver\s*=\s*([^\s#]+)\s*$", text, re.MULTILINE)
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
v = m.group(1).strip()
|
||||||
|
return v
|
||||||
|
|
||||||
|
def parse_pkgbuild(text: str) -> Optional[str]:
|
||||||
|
# Parse assignments and expand variables in pkgver
|
||||||
|
# Build a simple env map from VAR=value lines
|
||||||
|
env: Dict[str, str] = {}
|
||||||
|
for line in text.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
m_assign = re.match(r'^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$', line)
|
||||||
|
if m_assign:
|
||||||
|
key = m_assign.group(1)
|
||||||
|
val = m_assign.group(2).strip()
|
||||||
|
# Remove trailing comments
|
||||||
|
val = re.sub(r'\s+#.*$', '', val).strip()
|
||||||
|
# Strip surrounding quotes
|
||||||
|
if (val.startswith('"') and val.endswith('"')) or (val.startswith("'") and val.endswith("'")):
|
||||||
|
val = val[1:-1]
|
||||||
|
env[key] = val
|
||||||
|
|
||||||
|
m = re.search(r"^\s*pkgver\s*=\s*(.+)$", text, re.MULTILINE)
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
raw = m.group(1).strip()
|
||||||
|
# Strip quotes
|
||||||
|
if (raw.startswith('"') and raw.endswith('"')) or (raw.startswith("'") and raw.endswith("'")):
|
||||||
|
raw = raw[1:-1]
|
||||||
|
|
||||||
|
def expand_vars(s: str) -> str:
|
||||||
|
def repl_braced(mb):
|
||||||
|
key = mb.group(1)
|
||||||
|
return env.get(key, mb.group(0))
|
||||||
|
def repl_unbraced(mu):
|
||||||
|
key = mu.group(1)
|
||||||
|
return env.get(key, mu.group(0))
|
||||||
|
# Expand ${var} then $var
|
||||||
|
s = re.sub(r"\$\{([^}]+)\}", repl_braced, s)
|
||||||
|
s = re.sub(r"\$([A-Za-z_][A-Za-z0-9_]*)", repl_unbraced, s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
v = expand_vars(raw).strip()
|
||||||
|
# normalize rc form like 6.19.rc6 -> 6.19-rc6
|
||||||
|
v = v.replace(".rc", "-rc")
|
||||||
|
return v
|
||||||
|
|
||||||
|
# Try .SRCINFO first, then PKGBUILD
|
||||||
|
for base in bases:
|
||||||
|
# .SRCINFO
|
||||||
|
url = f"{base}/{paths[0]}"
|
||||||
|
text = http_get_text(url)
|
||||||
|
if text:
|
||||||
|
ver = parse_srcinfo(text)
|
||||||
|
if ver:
|
||||||
|
return ver.replace(".rc", "-rc")
|
||||||
|
# PKGBUILD fallback
|
||||||
|
url = f"{base}/{paths[1]}"
|
||||||
|
text = http_get_text(url)
|
||||||
|
if text:
|
||||||
|
ver = parse_pkgbuild(text)
|
||||||
|
if ver:
|
||||||
|
return ver.replace(".rc", "-rc")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def linux_tarball_url_for_version(self, version: str) -> str:
|
||||||
|
# Use torvalds snapshot for -rc, stable releases from CDN
|
||||||
|
if "-rc" in version:
|
||||||
|
return f"https://git.kernel.org/torvalds/t/linux-{version}.tar.gz"
|
||||||
|
parts = version.split(".")
|
||||||
|
major = parts[0] if parts else "6"
|
||||||
|
major_minor = ".".join(parts[:2]) if len(parts) >= 2 else version
|
||||||
|
ver_for_tar = major_minor if version.endswith(".0") else version
|
||||||
|
return f"https://cdn.kernel.org/pub/linux/kernel/v{major}.x/linux-{ver_for_tar}.tar.xz"
|
||||||
|
|
||||||
|
def update_linux_from_pkgbuild(self, name: str):
|
||||||
|
suffix = self.cachyos_suffix()
|
||||||
|
latest = self.fetch_cachyos_linux_latest(suffix)
|
||||||
|
if not latest:
|
||||||
|
self.set_status("linux: failed to get version from PKGBUILD")
|
||||||
|
return
|
||||||
|
url = self.linux_tarball_url_for_version(latest)
|
||||||
|
sri = nix_prefetch_url(url)
|
||||||
|
if not sri:
|
||||||
|
self.set_status("linux: prefetch failed")
|
||||||
|
return
|
||||||
|
ts = self.target_dict.setdefault("sources", {})
|
||||||
|
compw = ts.setdefault(name, {})
|
||||||
|
compw["version"] = latest
|
||||||
|
compw["hash"] = sri
|
||||||
|
self.set_status(f"{name}: updated version to {latest} and refreshed hash")
|
||||||
|
|
||||||
def set_ref(self, name: str, kind: str, value: str):
|
def set_ref(self, name: str, kind: str, value: str):
|
||||||
# Write to selected target dict (base or variant override)
|
# Write to selected target dict (base or variant override)
|
||||||
ts = self.target_dict.setdefault("sources", {})
|
ts = self.target_dict.setdefault("sources", {})
|
||||||
@@ -511,15 +684,32 @@ class PackageDetailScreen(ScreenBase):
|
|||||||
elif ch in (ord('r'),):
|
elif ch in (ord('r'),):
|
||||||
if self.snames:
|
if self.snames:
|
||||||
name = self.snames[self.sidx]
|
name = self.snames[self.sidx]
|
||||||
self.fetch_candidates_for(name)
|
comp = self.merged_srcs[name]
|
||||||
cand = self.candidates.get(name, {})
|
fetcher = comp.get("fetcher", "none")
|
||||||
lines = [
|
if self.pkg_name == "linux-cachyos" and name == "linux":
|
||||||
f"Candidates for {name}:",
|
# Show available linux version from upstream PKGBUILD (.SRCINFO)
|
||||||
f" latest release: {cand.get('release') or '-'}",
|
suffix = self.cachyos_suffix()
|
||||||
f" latest tag : {cand.get('tag') or '-'}",
|
latest = self.fetch_cachyos_linux_latest(suffix)
|
||||||
f" latest commit : {cand.get('commit') or '-'}",
|
rendered = render_templates(comp, self.merged_vars)
|
||||||
]
|
cur_version = str(rendered.get("version") or "")
|
||||||
show_popup(self.stdscr, lines)
|
url_hint = self.linux_tarball_url_for_version(latest) if latest else "-"
|
||||||
|
lines = [
|
||||||
|
f"linux-cachyos ({'base' if self.vidx == 0 else self.variants[self.vidx]}):",
|
||||||
|
f" current : {cur_version or '-'}",
|
||||||
|
f" available: {latest or '-'}",
|
||||||
|
f" tarball : {url_hint}",
|
||||||
|
]
|
||||||
|
show_popup(self.stdscr, lines)
|
||||||
|
else:
|
||||||
|
self.fetch_candidates_for(name)
|
||||||
|
cand = self.candidates.get(name, {})
|
||||||
|
lines = [
|
||||||
|
f"Candidates for {name}:",
|
||||||
|
f" latest release: {cand.get('release') or '-'}",
|
||||||
|
f" latest tag : {cand.get('tag') or '-'}",
|
||||||
|
f" latest commit : {cand.get('commit') or '-'}",
|
||||||
|
]
|
||||||
|
show_popup(self.stdscr, lines)
|
||||||
elif ch in (ord('i'),):
|
elif ch in (ord('i'),):
|
||||||
# Show full rendered URL for URL-based sources
|
# Show full rendered URL for URL-based sources
|
||||||
if self.snames:
|
if self.snames:
|
||||||
@@ -586,7 +776,24 @@ class PackageDetailScreen(ScreenBase):
|
|||||||
("Recompute hash", ("hash", None)),
|
("Recompute hash", ("hash", None)),
|
||||||
("Cancel", ("cancel", None)),
|
("Cancel", ("cancel", None)),
|
||||||
]
|
]
|
||||||
choice = select_menu(self.stdscr, f"Actions for {name}", [label for label, _ in items])
|
# Build header with current and available refs
|
||||||
|
rendered = render_templates(comp, self.merged_vars)
|
||||||
|
cur_tag = rendered.get("tag") or ""
|
||||||
|
cur_rev = rendered.get("rev") or ""
|
||||||
|
cur_version = rendered.get("version") or ""
|
||||||
|
if cur_tag:
|
||||||
|
current_str = f"current: tag={cur_tag}"
|
||||||
|
elif cur_rev:
|
||||||
|
current_str = f"current: rev={cur_rev[:12]}"
|
||||||
|
elif cur_version:
|
||||||
|
current_str = f"current: version={cur_version}"
|
||||||
|
else:
|
||||||
|
current_str = "current: -"
|
||||||
|
header_lines = [
|
||||||
|
current_str,
|
||||||
|
f"available: release={cand.get('release') or '-'} tag={cand.get('tag') or '-'} commit={(cand.get('commit') or '')[:12] or '-'}",
|
||||||
|
]
|
||||||
|
choice = select_menu(self.stdscr, f"Actions for {name}", [label for label, _ in items], header=header_lines)
|
||||||
if choice is not None:
|
if choice is not None:
|
||||||
kind, val = items[choice][1]
|
kind, val = items[choice][1]
|
||||||
if kind in ("release", "tag", "commit"):
|
if kind in ("release", "tag", "commit"):
|
||||||
@@ -621,7 +828,23 @@ class PackageDetailScreen(ScreenBase):
|
|||||||
menu_items.append(("Recompute hash (prefetch)", ("hash", None)))
|
menu_items.append(("Recompute hash (prefetch)", ("hash", None)))
|
||||||
menu_items.append(("Cancel", ("cancel", None)))
|
menu_items.append(("Cancel", ("cancel", None)))
|
||||||
|
|
||||||
choice = select_menu(self.stdscr, f"Actions for {name}", [label for label, _ in menu_items])
|
# Build header with current and available release info
|
||||||
|
base = str(self.merged_vars.get("base") or "")
|
||||||
|
rel = str(self.merged_vars.get("release") or "")
|
||||||
|
rp = str(self.merged_vars.get("releasePrefix") or "")
|
||||||
|
rs = str(self.merged_vars.get("releaseSuffix") or "")
|
||||||
|
current_tag = f"{rp}{base}-{rel}{rs}" if (base and rel) else ""
|
||||||
|
if current_tag:
|
||||||
|
current_str = f"current: {current_tag}"
|
||||||
|
elif base or rel:
|
||||||
|
current_str = f"current: base={base or '-'} release={rel or '-'}"
|
||||||
|
else:
|
||||||
|
current_str = "current: -"
|
||||||
|
header_lines = [
|
||||||
|
current_str,
|
||||||
|
f"available: tag={(cand.get('tag') or '-') if cand else '-'} base={(cand.get('base') or '-') if cand else '-'} release={(cand.get('release') or '-') if cand else '-'}",
|
||||||
|
]
|
||||||
|
choice = select_menu(self.stdscr, f"Actions for {name}", [label for label, _ in menu_items], header=header_lines)
|
||||||
if choice is not None:
|
if choice is not None:
|
||||||
kind, payload = menu_items[choice][1]
|
kind, payload = menu_items[choice][1]
|
||||||
if kind == "update_vars" and isinstance(payload, dict):
|
if kind == "update_vars" and isinstance(payload, dict):
|
||||||
@@ -652,19 +875,50 @@ class PackageDetailScreen(ScreenBase):
|
|||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
show_popup(self.stdscr, [f"{name}: fetcher={fetcher}", "Use 'e' to edit fields manually."])
|
if self.pkg_name == "linux-cachyos" and name == "linux":
|
||||||
|
# Offer update of linux version from upstream PKGBUILD (.SRCINFO)
|
||||||
|
suffix = self.cachyos_suffix()
|
||||||
|
latest = self.fetch_cachyos_linux_latest(suffix)
|
||||||
|
rendered = render_templates(comp, self.merged_vars)
|
||||||
|
cur_version = str(rendered.get("version") or "")
|
||||||
|
header_lines = [
|
||||||
|
f"current: version={cur_version or '-'}",
|
||||||
|
f"available: version={latest or '-'}",
|
||||||
|
]
|
||||||
|
opts = []
|
||||||
|
if latest:
|
||||||
|
opts.append(f"Update linux version to {latest} from PKGBUILD (.SRCINFO)")
|
||||||
|
else:
|
||||||
|
opts.append("Update linux version from PKGBUILD (.SRCINFO)")
|
||||||
|
opts.append("Cancel")
|
||||||
|
choice = select_menu(self.stdscr, f"Actions for {name}", opts, header=header_lines)
|
||||||
|
if choice == 0 and latest:
|
||||||
|
self.update_linux_from_pkgbuild(name)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
show_popup(self.stdscr, [f"{name}: fetcher={fetcher}", "Use 'e' to edit fields manually."])
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def select_menu(stdscr, title: str, options: List[str]) -> Optional[int]:
|
def select_menu(stdscr, title: str, options: List[str], header: Optional[List[str]] = None) -> Optional[int]:
|
||||||
idx = 0
|
idx = 0
|
||||||
while True:
|
while True:
|
||||||
stdscr.clear()
|
stdscr.clear()
|
||||||
h, w = stdscr.getmaxyx()
|
h, w = stdscr.getmaxyx()
|
||||||
stdscr.addstr(0, 0, title[:w-1])
|
stdscr.addstr(0, 0, title[:w-1])
|
||||||
for i, opt in enumerate(options[:h-3], start=0):
|
y = 1
|
||||||
|
if header:
|
||||||
|
for line in header:
|
||||||
|
if y >= h-2:
|
||||||
|
break
|
||||||
|
stdscr.addstr(y, 0, str(line)[:w-1])
|
||||||
|
y += 1
|
||||||
|
start_y = y + 1
|
||||||
|
max_opts = max(0, h - start_y - 1)
|
||||||
|
for i, opt in enumerate(options[:max_opts], start=0):
|
||||||
sel = ">" if i == idx else " "
|
sel = ">" if i == idx else " "
|
||||||
stdscr.addstr(2+i, 0, f"{sel} {opt}"[:w-1])
|
stdscr.addstr(start_y + i, 0, f"{sel} {opt}"[:w-1])
|
||||||
stdscr.addstr(h-1, 0, "Enter: select | Backspace: cancel")
|
stdscr.addstr(h-1, 0, "Enter: select | Backspace: cancel")
|
||||||
stdscr.refresh()
|
stdscr.refresh()
|
||||||
ch = stdscr.getch()
|
ch = stdscr.getch()
|
||||||
|
|||||||
Reference in New Issue
Block a user