[UPD] tui qemu: pick the VM by number for its state

Changing state meant retyping the name, on a single comma-separated line.
Names are long and alike -- two of them sometimes differ by a suffix
only -- and a typo here decided whether a machine started or shut down.

The screen now reuses the numbered list from the delete screen, "all"
included, and its parser, which already accepts names: nothing is lost
for those who typed them. The warning on an unknown entry is kept, that
parser otherwise dropping it without a word.

--- FR ---

Changer l'état demandait de retaper le nom, sur une seule ligne séparée
par des virgules. Les noms sont longs et se ressemblent — deux d'entre
eux ne diffèrent parfois que par un suffixe — et une faute de frappe
portait ici sur le démarrage ou l'extinction d'une machine.

L'écran reprend donc la liste numérotée de la suppression, « all »
compris, et son analyseur, qui accepte déjà les noms : rien n'est perdu
pour qui les tapait. L'avertissement sur une entrée inconnue est
conservé, cet analyseur l'écartant autrement sans un mot.

Assisted-by: Claude Opus 5
This commit is contained in:
Mathieu Benoit 2026-08-11 09:24:59 -04:00
parent c7b9d2396d
commit 891d412aa2

View file

@ -2137,20 +2137,34 @@ class TODO:
if not names:
print(f"\n{t('No VM found.')}")
return
print(f"\n{t('Available VMs:')} {', '.join(names)}")
raw = input(t("VMs to change (comma-separated): ")).strip()
targets = [n.strip() for n in raw.split(",") if n.strip()]
if not targets:
# Liste NUMÉROTÉE, comme l'écran de suppression : les noms de VM sont
# longs et se ressemblent, les retaper invite à la faute de frappe sur
# une commande qui change l'état d'une machine.
print(f"\n{t('Available VMs:')}")
for i, n in enumerate(names, 1):
print(f" [{i}] {n}")
print(f" [all] {t('select all')}")
raw = input(t("Selection (numbers, or 'all'): ")).strip()
if not raw:
print(t("Nothing selected."))
return
# Résoudre les ID -> noms et valider l'existence.
resolved, unknown = [], []
known = set(names)
for tgt in targets:
real = self._qemu_domname(tgt)
(resolved if real in known else unknown).append(real)
if unknown:
print(f"{t('Unknown VM(s):')} {', '.join(unknown)}")
if raw.lower() in ("all", "*"):
resolved = list(names)
else:
resolved = self._parse_index_selection(raw.lower(), names)
# Le parseur ignore en silence ce qu'il ne reconnaît pas. Sur une
# sélection qui va démarrer ou éteindre des VM, un numéro hors
# liste doit être dit, pas escamoté.
unknown = [
tok
for tok in re.split(r"[\s,]+", raw.strip())
if tok and tok not in names and not self._is_index(tok, names)
]
if unknown:
print(f"{t('Unknown VM(s):')} {', '.join(unknown)}")
return
if not resolved:
print(t("Nothing selected."))
return
# Choix de l'état cible : ouvrir (démarrer) ou fermer (éteindre).
print(f"\n{t('Target state:')}")
@ -3812,6 +3826,14 @@ class TODO:
pass
return 0
@staticmethod
def _is_index(token, options):
"""Vrai si le jeton est un numéro valide dans la liste (1-based)."""
try:
return 1 <= int(token) <= len(options)
except ValueError:
return False
@staticmethod
def _parse_index_selection(raw, options):
"""« 1 3 » ou « 1,3 » -> sous-liste d'options (indices 1-based)."""