# Diff Viewer - Visualizzazione Side-by-Side delle Differenze ## Descrizione Il Diff Viewer Γ¨ una nuova funzionalitΓ  che permette di visualizzare le differenze tra due versioni di un file in modo affiancato, con evidenziazione delle modifiche e una minimappa per navigare rapidamente tra le differenze. ## Come Utilizzare ### Accesso dalla GUI 1. Esegui un'operazione di **Differing** dalla GUI principale 2. Nella tabella dei risultati, **doppio-click** su qualsiasi riga per aprire il Diff Viewer 3. La finestra mostrerΓ  il file della baseline (a sinistra) e il file corrente (a destra) affiancati ### FunzionalitΓ  #### Visualizzazione Affiancata - **Colonna Sinistra**: File dalla baseline (versione precedente) - **Colonna Centrale**: Minimappa con rappresentazione visiva delle differenze - **Colonna Destra**: File corrente (versione attuale) #### Evidenziazione delle Differenze - πŸ”΄ **Rosso**: Linee **cancellate** (presenti solo nella baseline) - 🟒 **Verde**: Linee **aggiunte** (presenti solo nella versione corrente) - 🟑 **Giallo**: Linee **modificate** (diverse tra baseline e corrente) - βšͺ **Bianco**: Linee **uguali** (nessuna modifica) #### Numeri di Riga - Ogni riga mostra il numero di linea originale - Simboli speciali: - `#### | ` = Linea uguale - `#### - ` = Linea cancellata - `#### + ` = Linea aggiunta - `#### ~ ` = Linea modificata - ` ~ ` = Linea vuota (per allineamento) #### Minimappa - Visualizzazione compatta di tutte le differenze - I colori corrispondono al tipo di modifica - **Click sulla minimappa** per navigare rapidamente a una sezione specifica - Il rettangolo blu indica la porzione attualmente visibile #### Navigazione - **Scroll sincronizzato**: entrambi i file scorrono insieme - **Mouse wheel**: scorri verticalmente - **Frecce su/giΓΉ**: navigazione linea per linea - **Scrollbar condivisa**: controllo centralizzato dello scroll verticale - **Scrollbar orizzontali**: separate per ogni file #### Informazioni - **Barra info** in basso: - Numero di linee: baseline β†’ corrente - Conteggio linee: aggiunte, cancellate, modificate ### Casi d'Uso #### File Modificato ``` Baseline (test.py) Current (test.py) ------------------ ----------------- 1 | def hello(): 1 | def hello(): 2 | ~ print("Hi") 2 + ~ # nuovo 3 | ~ return 42 3 + ~ print("Hi") 4 | ~ return 42 ``` #### File Cancellato - Baseline: mostra il contenuto del file - Current: mostra "N/A" (file non esiste piΓΉ) #### File Aggiunto - Baseline: mostra "N/A" (file non esisteva) - Current: mostra il contenuto del nuovo file ## Architettura Tecnica ### File: `pyucc/gui/diff_viewer.py` #### Classe `DiffViewer(tk.Toplevel)` Finestra modale per la visualizzazione delle differenze. **Parametri del costruttore:** - `parent`: Widget parent (finestra principale) - `file_a_path`: Path del file baseline (puΓ² essere None) - `file_b_path`: Path del file corrente (puΓ² essere None) - `title_a`: Titolo per il pannello sinistro (default: "Baseline") - `title_b`: Titolo per il pannello destro (default: "Current") **Metodi principali:** - `_load_file(filepath)`: Carica il contenuto di un file - `_compute_diff_blocks()`: Calcola i blocchi di differenze usando `difflib.SequenceMatcher` - `_build_ui()`: Costruisce l'interfaccia utente - `_populate_content()`: Popola i text widget con evidenziazione - `_draw_minimap()`: Disegna la minimappa delle differenze - `_setup_scroll_sync()`: Configura la sincronizzazione dello scroll #### Funzione Helper `show_diff_viewer()` Funzione di convenienza per aprire il diff viewer. ```python from pyucc.gui.diff_viewer import show_diff_viewer show_diff_viewer(parent, file_a_path, file_b_path, title_a="Baseline", title_b="Current") ``` ### Integrazione con GUI Principale #### File: `pyucc/gui/gui.py` **Modifiche apportate:** 1. **Tracking della modalitΓ  corrente** (`_current_mode`): - `'scan'`: ModalitΓ  scanning - `'countings'`: ModalitΓ  conteggi - `'metrics'`: ModalitΓ  metriche - `'differ'`: ModalitΓ  differ (abilita double-click) 2. **Memorizzazione dei path root**: - `_differ_baseline_root`: Path root della baseline - `_differ_current_root`: Path root del progetto corrente 3. **Event handler per double-click**: ```python def _on_results_double_click(self, event): # Verifica modalitΓ  differ # Ottiene file dalla riga selezionata # Costruisce path completi # Apre DiffViewer ``` 4. **Binding**: ```python self.results_tree.bind('', self._on_results_double_click) ``` ## Algoritmo di Diff Il diff viewer utilizza `difflib.SequenceMatcher` di Python per calcolare le differenze: 1. **Caricamento file**: Legge entrambi i file in liste di linee 2. **Calcolo differenze**: `SequenceMatcher.get_opcodes()` restituisce blocchi: - `'equal'`: Blocco di linee uguali - `'delete'`: Linee presenti solo in A (baseline) - `'insert'`: Linee presenti solo in B (corrente) - `'replace'`: Linee diverse tra A e B 3. **Rendering**: Ogni blocco viene colorato appropriatamente 4. **Allineamento**: Linee vuote (`~`) mantengono l'allineamento visivo ## Limitazioni e Note ### Limitazioni Attuali - ⚠️ La finestra Γ¨ modale (blocca interazione con finestra principale) - ⚠️ Non supporta diff a livello di carattere (solo linee intere) - ⚠️ File molto grandi (>10k linee) potrebbero rallentare l'interfaccia - ⚠️ Encoding: assume UTF-8 con fallback a ignore errors ### Gestione Errori - Se un file non esiste, viene mostrato come vuoto - Se entrambi i file non esistono, viene mostrato un warning - Errori di lettura file vengono gestiti silenziosamente ### Performance - Ottimizzato per file fino a ~5000 linee - La minimappa usa rendering canvas nativo (veloce) - Scroll sincronizzato con evento batching ## Estensioni Future Possibili 1. **Diff inline**: Evidenziare caratteri specifici modificati dentro una linea 2. **Navigazione tra differenze**: Bottoni "Previous/Next Difference" 3. **Merge tool**: Permettere di selezionare quale versione tenere 4. **Export diff**: Salvare il diff in formato unified o patch 5. **Fold equal blocks**: Nascondere blocchi di linee uguali lunghi 6. **Syntax highlighting**: Colorazione sintassi del linguaggio 7. **Line numbers toggle**: Nascondere/mostrare numeri di riga 8. **Search**: Cercare testo all'interno del diff ## Test Per testare manualmente il diff viewer: ```bash python tests/test_diff_viewer_manual.py ``` Questo script crea due file temporanei con differenze e apre il diff viewer. ## Esempio di Utilizzo Programmatico ```python import tkinter as tk from pyucc.gui.diff_viewer import show_diff_viewer # Crea finestra principale root = tk.Tk() root.withdraw() # Apri diff viewer show_diff_viewer( root, file_a_path="/path/to/baseline/file.py", file_b_path="/path/to/current/file.py", title_a="Version 1.0", title_b="Version 2.0" ) root.mainloop() ``` ## Screenshot delle FunzionalitΓ  ### Layout Principale ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Baseline: file.py Diff Map Current: file.py β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”‚ β”‚ 1 | def hello(): β”‚ β–ˆβ–ˆβ–ˆβ–ˆ β”‚ 1 | def hello(): β”‚ β”‚ 2 | ~ print("Hi") β”‚ β–ˆβ–ˆβ–ˆβ–ˆ β”‚ 2 + ~ # comment β”‚ β”‚ 3 | ~ return 42 β”‚ β–ˆβ–ˆβ–ˆβ–ˆ β”‚ 3 + ~ print("Hi") β”‚ β”‚ β”‚ β–ˆβ–ˆβ–ˆβ–ˆ β”‚ 4 | ~ return 42 β”‚ β”‚ 4 | def goodbye(): β”‚ ──── β”‚ 5 | def goodbye(): β”‚ β”‚ 5 | ~ print("Bye") β”‚ ──── β”‚ 6 | ~ print("Bye") β”‚ β”‚ β”‚ β–ˆβ–ˆβ–ˆβ–ˆ β”‚ 7 + def new(): β”‚ β”‚ β”‚ β–ˆβ–ˆβ–ˆβ–ˆ β”‚ 8 + ~ pass β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Lines: 5 β†’ 8 | Added: 3 Deleted: 0 Modified: 2 [Close]β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` Legenda colori: - `β–ˆβ–ˆβ–ˆβ–ˆ` Rosso = Linee cancellate - `β–ˆβ–ˆβ–ˆβ–ˆ` Verde = Linee aggiunte - `β–ˆβ–ˆβ–ˆβ–ˆ` Giallo = Linee modificate - `────` Grigio = Linee uguali