feat: ajouter les Snippets de commandes

Bibliotheque de commandes organisee par categories (Linux/Docker/Proxmox
fournis en exemples au premier lancement, librement modifiables), avec
recherche.

- app/snippets.py : Snippet/SnippetStore, meme pattern que les autres stores
  (JSON atomique, schema_version).
- SnippetManagerDialog : creer/modifier/supprimer/rechercher, regroupe par
  categorie.
- Integration terminal : le dernier commit du depot a delibrement fait du
  clic droit un raccourci de collage (style terminal Unix), sans menu
  contextuel. Plutot que d'ecraser ce choix recent, les snippets passent par
  un bouton dedie "📋 Snippets" dans la barre de l'onglet (SessionTabWidget et
  LocalTerminalTabWidget), avec un menu Categorie -> Snippet -> Action
  (Inserer dans le terminal / Executer / Executer avec Multi-Send).
  "Inserer" n'envoie jamais Entree (le texte est ecrit, a l'utilisateur de
  valider) ; seul "Executer" l'ajoute.
- BroadcastManager.broadcast_now() : diffusion explicite et ponctuelle vers
  tous les terminaux, independante de l'etat du bouton Multi (utilisee par
  "Executer avec Multi-Send", qui est une action volontaire et pas une frappe
  clavier a relayer).
- La construction du menu (_build_snippets_menu) est separee de son
  affichage (_show_snippets_menu) : testable sans declencher l'appel
  bloquant menu.exec().

tests/test_snippets.py : stockage (CRUD, recherche, categories, persistance)
et integration terminal (inserer/executer/multi-send, construction et
declenchement du menu), avec LocalTerminalConnection.start() neutralisee.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Florian
2026-09-05 02:55:10 +02:00
parent a3c72ade0b
commit 0a07ddcb62
8 changed files with 545 additions and 10 deletions

View File

@@ -35,11 +35,20 @@ class BroadcastManager(QObject):
def _broadcast(self, data: bytes, source) -> None:
if not self.enabled:
return
self._send_to_all(data, exclude=source)
def broadcast_now(self, data: bytes) -> None:
"""Diffuse immediatement vers tous les terminaux, independamment de l'etat
du bouton Multi : declenchement explicite et ponctuel (ex : un snippet
execute avec « Executer avec Multi-Send »), pas une frappe clavier."""
self._send_to_all(data, exclude=None)
def _send_to_all(self, data: bytes, exclude) -> None:
# import tardif : evite un cycle (app.ui.tabs importe des dialogues, pas ce module)
from app.ui.tabs import BaseTerminalTab
for tab in self._tabs_provider():
if tab is source or not isinstance(tab, BaseTerminalTab):
if tab is exclude or not isinstance(tab, BaseTerminalTab):
continue
if tab.connection:
# on ecrit directement dans la connexion : passer par le terminal