SXXXXXXX_PyUCC/doc/DIFF_VIEWER.md

239 lines
8.8 KiB
Markdown

# 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('<Double-Button-1>',
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