prêt pour la BETa

This commit is contained in:
2025-08-15 11:26:13 +02:00
parent df5f970aa0
commit 6940055618

View File

@@ -46,6 +46,10 @@ CompilerEndIf
#GIncludeAll = 29
#GExcludeAll = 30
#GAdvanced = 31
; Options daffichage
#GShowClean = 39 ; Afficher les fichiers suivis à jour (propres)
#GShowIgnored = 40 ; Afficher aussi les fichiers ignorés (.gitignore)
; Fenêtre avancée (branches)
#WAdv = 200
@@ -148,8 +152,73 @@ Declare.i IsGitRepo(dir$)
Declare.i UpdateGuide(repoDir$, List rows.FileRow(), branch$, remote$)
Declare.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
Declare.i RestoreFileFromCommit(repoDir$, file$, commit$)
Declare.i BuildFullFileList(repoDir$, showClean.i, showIgnored.i, List rows.FileRow())
Declare.s FileFromRowsByIndex(index.i, List rows.FileRow())
Declare.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
Declare.s NormalizeGitFilePath(repoDir$, raw$)
Declare.i RepoFileExists(repoDir$, rel$)
Declare.i BuildFullFileList(repoDir$, showClean.i, showIgnored.i, List rows.FileRow())
Declare.s PorcelainToLabel(code$) ; (remplacer par la version complète ci-dessous)
; ====== Utils ======
; Convertit le chemin pour Git (Windows ok) :
; - remplace "\" par "/"
; - retire un éventuel préfixe "./"
Procedure.s GitPath(file$)
Protected p$ = file$
p$ = ReplaceString(p$, "\", "/")
If Left(p$, 2) = "./"
p$ = Mid(p$, 3)
EndIf
ProcedureReturn p$
EndProcedure
; Normalise un chemin renvoyé par Git :
; - enlève espaces/quotes superflus
; - garde la destination en cas de renommage "old -> new"
; - remplace les "/" par le séparateur OS
; - retire un éventuel "./" de tête
Procedure.s NormalizeGitFilePath(repoDir$, raw$)
Protected p$ = Trim(raw$)
; retirer quotes simples/doubles éventuelles autour
If Left(p$, 1) = Chr(34) And Right(p$, 1) = Chr(34)
p$ = Mid(p$, 2, Len(p$)-2)
EndIf
If Left(p$, 1) = "'" And Right(p$, 1) = "'"
p$ = Mid(p$, 2, Len(p$)-2)
EndIf
; cas "old -> new" : on garde "new"
Protected pos.i = FindString(p$, "->", 1)
If pos > 0
p$ = Trim(Mid(p$, pos + 2))
EndIf
; retirer "./"
If Left(p$, 2) = "./"
p$ = Mid(p$, 3)
EndIf
; slashes vers séparateur OS
p$ = ReplaceString(p$, "/", #PathSep$)
ProcedureReturn p$
EndProcedure
; Vérifie lexistence dun fichier RELATIF au repo (fichier ou dossier)
; renvoie 1 si présent, 0 sinon
Procedure.i RepoFileExists(repoDir$, rel$)
Protected base$ = repoDir$
If Right(base$, 1) <> #PathSep$ : base$ + #PathSep$ : EndIf
Protected abs$ = base$ + rel$
Protected s.q = FileSize(abs$)
If s >= 0 Or s = -2
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
Procedure.s TrimNewlines(text$)
Protected s$ = text$
While Right(s$, 1) = #LF$ Or Right(s$, 1) = #CR$
@@ -506,6 +575,65 @@ Procedure.i DoPull(repoDir$, remote$, branch$)
ProcedureReturn 0
EndProcedure
; ------------------------------------------------------------------
; Ouvre une fenêtre affichant le diff du fichier sélectionné
; ------------------------------------------------------------------
Procedure.i OpenDiffWindow(repoDir$, List rows.FileRow())
Protected idx.i = GetGadgetState(#GListStatus)
If idx < 0
MessageRequester("Diff", "Sélectionnez un fichier dans la liste.", #PB_MessageRequester_Info)
ProcedureReturn 0
EndIf
; Retrouver le chemin du fichier depuis la liste rows()
Protected j.i = 0, target$
ForEach rows()
If j = idx
target$ = rows()\file
Break
EndIf
j + 1
Next
If target$ = ""
MessageRequester("Diff", "Aucun fichier sélectionné.", #PB_MessageRequester_Info)
ProcedureReturn 0
EndIf
; Exécuter 'git diff -- "<fichier>"'
Protected gc.GitCall
gc\workdir = repoDir$
gc\args = "diff -- " + Chr(34) + target$ + Chr(34)
If RunGit(@gc) <> 0
MessageRequester("Diff", "Échec: " + #LF$ + TrimNewlines(gc\errors), #PB_MessageRequester_Error)
ProcedureReturn 0
EndIf
Protected diff$ = gc\output
If Trim(diff$) = ""
diff$ = "Aucune différence détectée pour ce fichier."
EndIf
; Fenêtre daffichage
Protected title$ = "Diff — " + target$
If OpenWindow(#WDiff, 0, 0, 800, 500, title$, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
EditorGadget(#GDiffText, 10, 10, 780, 440)
ButtonGadget(#GDiffClose, 690, 460, 100, 28, "Fermer")
SetGadgetText(#GDiffText, diff$)
Repeat
Protected ev.i = WaitWindowEvent()
If ev = #PB_Event_Gadget And EventGadget() = #GDiffClose
CloseWindow(#WDiff)
Break
EndIf
Until ev = #PB_Event_CloseWindow
EndIf
ProcedureReturn 1
EndProcedure
Procedure.i ListBranches(repoDir$, List branchesList.s())
ClearList(branchesList())
Protected gc.GitCall
@@ -531,8 +659,13 @@ Procedure.i ListBranches(repoDir$, List branchesList.s())
EndProcedure
; ====== Status → lignes et gestion des coches ======
; Charge le status dans une liste de lignes (stat, file, include=0)
; Parsing robuste : on prend tout ce qui suit le premier séparateur (espace/tab)
; après les 2 lettres de statut ; gère aussi "old -> new" (renommage).
Procedure.i LoadStatusRows(repoDir$, List rows.FileRow())
Protected gc.GitCall, text$, line$, n.i, i.i
Protected gc.GitCall, text$, line$, code$, file$
Protected i.i, n.i, start.i, ch$, pos.i
gc\args = "status --porcelain"
gc\workdir = repoDir$
If RunGit(@gc) <> 0
@@ -542,36 +675,83 @@ Procedure.i LoadStatusRows(repoDir$, List rows.FileRow())
text$ = gc\output
n = CountString(text$, #LF$) + 1
ClearList(rows())
For i = 1 To n
line$ = Trim(StringField(text$, i, #LF$))
If line$ <> ""
AddElement(rows())
rows()\stat = Left(line$, 2)
rows()\file = Trim(Mid(line$, 4))
rows()\include = 0
line$ = StringField(text$, i, #LF$)
line$ = Trim(line$)
If line$ = "" : Continue : EndIf
; 2 premières colonnes = statut (XY)
code$ = Left(line$, 2)
; Cherche le début du chemin : après les espaces/tabs suivant la colonne 3
start = 3
While start <= Len(line$)
ch$ = Mid(line$, start, 1)
If ch$ <> " " And ch$ <> #TAB$
Break
EndIf
start + 1
Wend
file$ = Mid(line$, start)
; Renommage "old -> new" : garder la destination
pos = FindString(file$, "->", 1)
If pos > 0
file$ = Trim(Mid(file$, pos + 2))
EndIf
; (Optionnel) normalisation simple
If Left(file$, 2) = "./" : file$ = Mid(file$, 3) : EndIf
file$ = ReplaceString(file$, "/", #PathSep$)
AddElement(rows())
rows()\stat = code$
rows()\file = file$
rows()\include = 0
Next i
ProcedureReturn ListSize(rows())
EndProcedure
; Remplit #GListStatus sans #LF$ (évite la perte du 1er caractère en col. 2)
Procedure.i FillStatusList(List rows.FileRow())
ClearGadgetItems(#GListStatus)
Protected idx.i = 0
Protected label$
Protected label$, file$
ForEach rows()
; 1) Texte de la 1re colonne (état lisible)
label$ = PorcelainToLabel(rows()\stat)
AddGadgetItem(#GListStatus, -1, label$ + #LF$ + rows()\file)
AddGadgetItem(#GListStatus, -1, label$)
; 2) Texte de la 2e colonne (chemin)
file$ = rows()\file
SetGadgetItemText(#GListStatus, idx, file$, 1)
; 3) Case à cocher selon include
If rows()\include
SetGadgetItemState(#GListStatus, idx, #PB_ListIcon_Checked)
Else
SetGadgetItemState(#GListStatus, idx, 0)
EndIf
; 4) Debug (utile pour vérifier ce qui est réellement affiché)
If #EnableDebug
Debug "[Fill] idx=" + Str(idx) + " file='" + file$ + "' readback='" + GetGadgetItemText(#GListStatus, idx, 1) + "'"
EndIf
idx + 1
Next
ProcedureReturn CountGadgetItems(#GListStatus)
EndProcedure
Procedure.i ToggleIncludeAt(index.i, List rows.FileRow())
If index < 0 : ProcedureReturn 0 : EndIf
Protected c.i = CountGadgetItems(#GListStatus)
@@ -724,11 +904,16 @@ Procedure.s PorcelainToLabel(code$)
Protected x$ = Left(code$, 1)
Protected y$ = Right(code$, 1)
If code$ = "OK"
ProcedureReturn "À jour (suivi)"
EndIf
If code$ = "??"
ProcedureReturn "Nouveau (non suivi)"
EndIf
If code$ = "!!"
ProcedureReturn "Ignoré"
ProcedureReturn "Ignoré (.gitignore)"
EndIf
; Colonne X = indexé (staged)
@@ -746,50 +931,6 @@ Procedure.s PorcelainToLabel(code$)
ProcedureReturn "Changement"
EndProcedure
Procedure.i OpenDiffWindow(repoDir$, List rows.FileRow())
Protected idx.i = GetGadgetState(#GListStatus)
If idx < 0
MessageRequester("Diff", "Sélectionnez un fichier dans la liste.", #PB_MessageRequester_Info)
ProcedureReturn 0
EndIf
Protected j.i = 0, target$
ForEach rows()
If j = idx
target$ = rows()\file
Break
EndIf
j + 1
Next
If target$ = ""
MessageRequester("Diff", "Aucun fichier sélectionné.", #PB_MessageRequester_Info)
ProcedureReturn 0
EndIf
Protected gc.GitCall
gc\workdir = repoDir$
gc\args = "diff -- " + Chr(34) + target$ + Chr(34)
If RunGit(@gc) <> 0
MessageRequester("Diff", "Échec: " + #LF$ + TrimNewlines(gc\errors), #PB_MessageRequester_Error)
ProcedureReturn 0
EndIf
If OpenWindow(#WDiff, 0, 0, 800, 500, "Diff — " + target$, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
EditorGadget(#GDiffText, 10, 10, 780, 440)
ButtonGadget(#GDiffClose, 690, 460, 100, 28, "Fermer")
SetGadgetText(#GDiffText, gc\output)
Repeat
Protected ev.i = WaitWindowEvent()
If ev = #PB_Event_Gadget And EventGadget() = #GDiffClose
CloseWindow(#WDiff)
Break
EndIf
Until ev = #PB_Event_CloseWindow
EndIf
ProcedureReturn 1
EndProcedure
Procedure.s GetLocalConfig(repoDir$, key$)
Protected gc.GitCall
@@ -917,22 +1058,28 @@ EndProcedure
; Restaure un fichier à létat dun commit précis
; - Essaye 'git restore --source <commit> -- <file>'
; - Fallback 'git checkout <commit> -- <file>' (pour Git anciens)
; Restaure un fichier à létat dun commit précis
; - utilise GitPath() pour la robustesse
; - dabord 'git restore', fallback 'git checkout'
Procedure.i RestoreFileFromCommit(repoDir$, file$, commit$)
Protected gc.GitCall
gc\workdir = repoDir$
gc\args = "restore --source " + Chr(34) + commit$ + Chr(34) + " -- " + Chr(34) + file$ + Chr(34)
Protected gc.GitCall, q$ = Chr(34)
Protected path$ = GitPath(file$)
gc\workdir = repoDir$
gc\args = "restore --source " + q$ + commit$ + q$ + " -- " + q$ + path$ + q$
If #EnableDebug
Debug "[RestoreFile] " + gc\args + " (wd=" + repoDir$ + ")"
EndIf
If RunGit(@gc) = 0
MessageRequester("Restaurer", "Le fichier a été restauré depuis le commit " + commit$ + ".", #PB_MessageRequester_Info)
ProcedureReturn 1
EndIf
; Fallback pour compatibilité
gc\args = "checkout " + Chr(34) + commit$ + Chr(34) + " -- " + Chr(34) + file$ + Chr(34)
; Fallback (compat versions Git)
gc\args = "checkout " + q$ + commit$ + q$ + " -- " + q$ + path$ + q$
If #EnableDebug
Debug "[RestoreFile fallback] " + gc\args
EndIf
If RunGit(@gc) = 0
MessageRequester("Restaurer", "Le fichier a été restauré (fallback checkout) depuis " + commit$ + ".", #PB_MessageRequester_Info)
ProcedureReturn 1
@@ -944,6 +1091,17 @@ EndProcedure
; Ouvre une fenêtre listant les commits du fichier sélectionné,
; puis restaure le fichier vers le commit choisi.
; Ouvre une fenêtre listant les commits du fichier sélectionné,
; puis restaure le fichier vers le commit choisi.
; Améliorations :
; - lit le chemin depuis la 2e colonne du gadget (source de vérité)
; - normalise le chemin pour Git via GitPath()
; - utilise --follow et fallback --all pour couvrir les renommages / autres branches
; Fenêtre de sélection de commit puis restauration dun fichier
; Robuste :
; - lit le nom depuis le gadget ET depuis rows()
; - corrige le cas où la 1re lettre saute (ex: "PBIDE..." → "BIDE...")
; - normalise le chemin (GitPath), suit les renommages (--follow) + fallback --all
Procedure.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
Protected idx.i = GetGadgetState(#GListStatus)
If idx < 0
@@ -951,41 +1109,67 @@ Procedure.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
ProcedureReturn 0
EndIf
; Récupère le chemin du fichier choisi dans rows()
Protected j.i = 0, target$
ForEach rows()
If j = idx
target$ = rows()\file
Break
; 1) Deux sources : gadget (colonne 2) et liste interne rows()
Protected fromGadget$ = GetGadgetItemText(#GListStatus, idx, 1)
Protected fromRows$ = FileFromRowsByIndex(idx, rows())
; 2) Choisir la version la plus fiable
Protected target$ = fromGadget$
If fromRows$ <> ""
; Si la version rows() est plus longue OU si fromRows$ commence par un caractère
; qui, en retirant le 1er, donne exactement fromGadget$, on privilégie rows().
If Len(fromRows$) > Len(fromGadget$)
target$ = fromRows$
ElseIf Len(fromRows$) > 1 And Mid(fromRows$, 2) = fromGadget$
target$ = fromRows$
EndIf
j + 1
Next
EndIf
; Dernier filet de sécurité
If target$ = "" : target$ = fromRows$ : EndIf
If target$ = "" : target$ = fromGadget$ : EndIf
If #EnableDebug
Debug "[Restore select] gadget='" + fromGadget$ + "' rows='" + fromRows$ + "' chosen='" + target$ + "'"
EndIf
If target$ = ""
MessageRequester("Restaurer", "Aucun fichier sélectionné.", #PB_MessageRequester_Info)
ProcedureReturn 0
EndIf
; Récupère lhistorique des commits de ce fichier (50 derniers)
Protected gc.GitCall, out$, line$, n.i, i.i
gc\workdir = repoDir$
gc\args = "log --date=short --pretty=format:%h%x09%ad%x09%s -n 50 -- " + Chr(34) + target$ + Chr(34)
; Normaliser le chemin pour Git (slashs, ./)
Protected fileArg$ = GitPath(target$)
Protected gc.GitCall, out$, line$, n.i, i.i, q$ = Chr(34)
; 3) Historique avec suivi des renommages
gc\workdir = repoDir$
gc\args = "log --follow --date=short --pretty=format:%h%x09%ad%x09%s -n 200 -- " + q$ + fileArg$ + q$
If #EnableDebug : Debug "[Restore log] " + gc\args : EndIf
If RunGit(@gc) <> 0
MessageRequester("Restaurer", "Échec du log : " + #LF$ + TrimNewlines(gc\errors), #PB_MessageRequester_Error)
ProcedureReturn 0
EndIf
out$ = gc\output
; 4) Fallback : toutes les refs (utile si lhistorique du fichier est sur une autre branche)
If Trim(out$) = ""
MessageRequester("Restaurer", "Aucun commit trouvé pour ce fichier.", #PB_MessageRequester_Info)
gc\args = "log --all --follow --date=short --pretty=format:%h%x09%ad%x09%s -n 200 -- " + q$ + fileArg$ + q$
If #EnableDebug : Debug "[Restore log fallback --all] " + gc\args : EndIf
If RunGit(@gc) = 0
out$ = gc\output
EndIf
EndIf
If Trim(out$) = ""
MessageRequester("Restaurer", "Aucun commit trouvé pour ce fichier." + #LF$ +
"Vérifiez que le fichier est (ou a été) suivi par Git et quil a déjà été committé.",
#PB_MessageRequester_Info)
ProcedureReturn 0
EndIf
; Prépare une liste parallèle des hash pour retrouver le commit sélectionné
; Liste des commits → UI
NewList hashes.s()
; Fenêtre de sélection
If OpenWindow(#WRestore, 0, 0, 760, 420, "Restaurer : " + target$, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(#GRestInfo, 10, 10, 740, 22, "Choisissez le commit vers lequel restaurer le fichier.")
ListIconGadget(#GRestList, 10, 40, 740, 330, "Commit", 100, #PB_ListIcon_FullRowSelect)
@@ -994,12 +1178,10 @@ Procedure.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
ButtonGadget(#GRestOK, 540, 380, 100, 28, "Restaurer")
ButtonGadget(#GRestCancel, 650, 380, 100, 28, "Annuler")
; Remplit la liste
n = CountString(out$, #LF$) + 1
For i = 1 To n
line$ = StringField(out$, i, #LF$)
If Trim(line$) <> ""
; Format: %h<TAB>%ad<TAB>%s
Protected h$ = StringField(line$, 1, #TAB$)
Protected d$ = StringField(line$, 2, #TAB$)
Protected s$ = StringField(line$, 3, #TAB$)
@@ -1008,7 +1190,6 @@ Procedure.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
EndIf
Next
; Boucle fenêtre
Repeat
Protected ev.i = WaitWindowEvent()
If ev = #PB_Event_Gadget
@@ -1018,15 +1199,13 @@ Procedure.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
If idx < 0
MessageRequester("Restaurer", "Sélectionnez un commit.", #PB_MessageRequester_Warning)
Else
; Récupère le hash à lindex idx
j = 0
Protected chosen$
Protected k.i = 0, chosen$
ForEach hashes()
If j = idx : chosen$ = hashes() : Break : EndIf
j + 1
If k = idx : chosen$ = hashes() : Break : EndIf
k + 1
Next
If chosen$ <> ""
If RestoreFileFromCommit(repoDir$, target$, chosen$)
If RestoreFileFromCommit(repoDir$, fileArg$, chosen$)
CloseWindow(#WRestore)
ProcedureReturn 1
EndIf
@@ -1046,8 +1225,6 @@ Procedure.i OpenRestoreFileWindow(repoDir$, List rows.FileRow())
ProcedureReturn 0
EndProcedure
; Met à jour le panneau "Guide" avec un pas-à-pas adapté
; - Inclut létape “Init repo” si le dossier nest pas encore un dépôt
; - Rappelle la différence Commit / Push pour débutants
@@ -1118,85 +1295,198 @@ EndProcedure
; Affiche stdout + stderr dans une fenêtre (évite le texte tronqué)
; Construit la liste rows() avec tous les fichiers (selon options), SANS correction de nom
; - showClean=1 → inclut les fichiers suivis "propres" (OK)
; - showIgnored=1 → inclut aussi les fichiers ignorés (!!)
; - Vérifie lexistence côté disque ; si absent et pas un delete, marque "NF" (Introuvable)
; - rows()\include = 1 pour les éléments potentiellement à committer (≠ OK/!!)
Procedure.i BuildFullFileList(repoDir$, showClean.i, showIgnored.i, List rows.FileRow())
Protected gc.GitCall
Protected text$, line$, code$, file$
Protected i.i, n.i, start.i, ch$, pos.i, exists.i, isDelete.i
ClearList(rows())
; ====== UI principale ======
; Gadgets IDs (inclut les NOUVEAUX boutons)
#GWindow = 1
#GLabelRepo = 10
#GStringRepo = 11
#GButtonBrowse = 12
#GListStatus = 13
#GRefresh = 14
#GLabelMsg = 15
#GStringMsg = 16
#GCheckPush = 17
#GLabelRemote = 18
#GStringRemote = 19
#GLabelBranch = 20
#GComboBranch = 21
#GSavePrefs = 22
#GInit = 23
#GCommit = 24
#GPull = 25
#GPush = 26
#GInclude = 27
#GExclude = 28
#GIncludeAll = 29
#GExcludeAll = 30
#GAdvanced = 31
; --- 1) status --porcelain --ignored → map fichier -> code (??, !!, " M", etc.)
NewMap statusMap.s()
gc\workdir = repoDir$
gc\args = "status --porcelain --ignored"
If RunGit(@gc) <> 0
MessageRequester("Git status", "Échec: " + #LF$ + TrimNewlines(gc\errors), #PB_MessageRequester_Error)
ProcedureReturn 0
EndIf
text$ = gc\output
n = CountString(text$, #LF$) + 1
For i = 1 To n
line$ = Trim(StringField(text$, i, #LF$))
If line$ = "" : Continue : EndIf
code$ = Left(line$, 2)
; --- parsing robuste du chemin (tout ce qui suit les espaces/tabs après col.2) ---
start = 3
While start <= Len(line$)
ch$ = Mid(line$, start, 1)
If ch$ <> " " And ch$ <> #TAB$
Break
EndIf
start + 1
Wend
file$ = Mid(line$, start)
; renommage "old -> new" : garder la destination
pos = FindString(file$, "->", 1)
If pos > 0 : file$ = Trim(Mid(file$, pos + 2)) : EndIf
; normalisation simple
If Left(file$, 2) = "./" : file$ = Mid(file$, 3) : EndIf
file$ = ReplaceString(file$, "/", #PathSep$)
; -------------------------------------------------------------------------------
AddMapElement(statusMap(), file$)
statusMap() = code$
Next
; --- 2) ls-files → tous les suivis
NewMap trackedMap.i()
gc\args = "ls-files"
If RunGit(@gc) = 0
text$ = gc\output
n = CountString(text$, #LF$) + 1
For i = 1 To n
file$ = Trim(StringField(text$, i, #LF$))
If file$ = "" : Continue : EndIf
If Left(file$, 2) = "./" : file$ = Mid(file$, 3) : EndIf
file$ = ReplaceString(file$, "/", #PathSep$)
AddMapElement(trackedMap(), file$) : trackedMap() = 1
Next
EndIf
; --- 3) Ajouter les suivis (propres/modifiés)
ForEach trackedMap()
file$ = MapKey(trackedMap())
If FindMapElement(statusMap(), file$)
code$ = statusMap()
Else
code$ = "OK"
EndIf
If code$ = "OK" And showClean = 0 : Continue : EndIf
If code$ = "!!" And showIgnored = 0 : Continue : EndIf
exists = RepoFileExists(repoDir$, file$)
isDelete = 0
If Left(code$, 1) = "D" Or Right(code$, 1) = "D" : isDelete = 1 : EndIf
AddElement(rows())
rows()\file = file$
If exists = 0 And isDelete = 0
rows()\stat = "NF" ; Introuvable (FS)
rows()\include = 0
Else
rows()\stat = code$
rows()\include = Bool(code$ <> "OK" And code$ <> "!!")
EndIf
Next
; --- 4) Ajouter non suivis (!!/??) qui ne sont pas dans trackedMap
ForEach statusMap()
file$ = MapKey(statusMap())
code$ = statusMap()
If FindMapElement(trackedMap(), file$) = 0
If code$ = "!!" And showIgnored = 0 : Continue : EndIf
exists = RepoFileExists(repoDir$, file$)
AddElement(rows())
rows()\file = file$
If exists = 0 And Left(code$, 1) <> "D" And Right(code$, 1) <> "D"
rows()\stat = "NF"
rows()\include = 0
Else
rows()\stat = code$
rows()\include = 1
EndIf
EndIf
Next
ProcedureReturn ListSize(rows())
EndProcedure
; Récupère le nom de fichier de la ligne 'index' depuis la liste interne
Procedure.s FileFromRowsByIndex(index.i, List rows.FileRow())
Protected j.i = 0
ForEach rows()
If j = index
ProcedureReturn rows()\file
EndIf
j + 1
Next
ProcedureReturn ""
EndProcedure
; Fenêtre de sélection de commit puis restauration dun fichier
; Robuste :
; - lit le nom depuis le gadget ET depuis rows()
; - corrige le cas où la 1re lettre saute (ex: "PBIDE..." → "BIDE...")
; - normalise le chemin (GitPath), suit les renommages (--follow) + fallback --all
Procedure.i OpenGUI(initialDir$, prefsPath$)
Protected repoDir$ = DetectRepoRoot(initialDir$)
Protected remote$ = "", branch$ = ""
LoadPrefs(prefsPath$, remote$, branch$)
; On élargit légèrement pour caser le nouveau bouton
If OpenWindow(#GWindow, 0, 0, 900, 640, "PBIDE-GitTool — Git (mode simplifié)", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If OpenWindow(#GWindow, 0, 0, 900, 660, "PBIDE-GitTool — Git (mode simplifié)", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(#GLabelRepo, 10, 12, 60, 22, "Dépôt :")
StringGadget(#GStringRepo, 80, 10, 720, 24, repoDir$)
ButtonGadget(#GButtonBrowse, 810, 10, 80, 24, "Parcourir…")
; Options daffichage
CheckBoxGadget(#GShowClean, 10, 40, 180, 20, "Afficher suivis à jour")
SetGadgetState(#GShowClean, #True) ; par défaut : on veut tout voir
CheckBoxGadget(#GShowIgnored, 200, 40, 200, 20, "Inclure ignorés (.gitignore)")
SetGadgetState(#GShowIgnored, #False)
; Liste avec cases à cocher
ListIconGadget(#GListStatus, 10, 46, 880, 300, "Statut", 180, #PB_ListIcon_CheckBoxes | #PB_ListIcon_FullRowSelect)
ListIconGadget(#GListStatus, 10, 66, 880, 300, "État", 180, #PB_ListIcon_CheckBoxes | #PB_ListIcon_FullRowSelect)
AddGadgetColumn(#GListStatus, 1, "Fichier", 680)
; Ligne actions liste
ButtonGadget(#GRefresh, 10, 352, 90, 26, "Rafraîchir")
ButtonGadget(#GInit, 110, 352, 90, 26, "Init repo")
ButtonGadget(#GInclude, 210, 352, 90, 26, "Inclure")
ButtonGadget(#GExclude, 310, 352, 90, 26, "Exclure")
ButtonGadget(#GIncludeAll, 410, 352, 110, 26, "Tout inclure")
ButtonGadget(#GExcludeAll, 530, 352, 110, 26, "Tout exclure")
ButtonGadget(#GDiff, 650, 352, 80, 26, "Diff…")
ButtonGadget(#GRestoreFile,740, 352, 150, 26, "Restaurer fichier…")
ButtonGadget(#GRefresh, 10, 372, 90, 26, "Rafraîchir")
ButtonGadget(#GInit, 110, 372, 90, 26, "Init repo")
ButtonGadget(#GInclude, 210, 372, 90, 26, "Inclure")
ButtonGadget(#GExclude, 310, 372, 90, 26, "Exclure")
ButtonGadget(#GIncludeAll, 410, 372, 110, 26, "Tout inclure")
ButtonGadget(#GExcludeAll, 530, 372, 110, 26, "Tout exclure")
ButtonGadget(#GDiff, 650, 372, 80, 26, "Diff…")
ButtonGadget(#GRestoreFile,740, 372, 150, 26, "Restaurer fichier…")
; Zone commit / push
TextGadget(#GLabelMsg, 10, 388, 100, 22, "Message :")
StringGadget(#GStringMsg, 110, 386, 620, 24, "")
CheckBoxGadget(#GCheckPush, 10, 418, 140, 22, "Pousser après")
TextGadget(#GLabelMsg, 10, 408, 100, 22, "Message :")
StringGadget(#GStringMsg, 110, 406, 620, 24, "")
CheckBoxGadget(#GCheckPush, 10, 438, 140, 22, "Pousser après")
SetGadgetState(#GCheckPush, #True)
TextGadget(#GLabelRemote, 160, 418, 60, 22, "Remote :")
StringGadget(#GStringRemote, 220, 416, 120, 24, remote$)
TextGadget(#GLabelBranch, 350, 418, 60, 22, "Branche :")
ComboBoxGadget(#GComboBranch, 410, 416, 170, 24)
ButtonGadget(#GSavePrefs, 590, 416, 220, 24, "Sauver défauts")
ButtonGadget(#GAdvanced, 820, 416, 70, 24, "Avancé…")
TextGadget(#GLabelRemote, 160, 438, 60, 22, "Remote :")
StringGadget(#GStringRemote, 220, 436, 120, 24, remote$)
TextGadget(#GLabelBranch, 350, 438, 60, 22, "Branche :")
ComboBoxGadget(#GComboBranch, 410, 436, 170, 24)
ButtonGadget(#GSavePrefs, 590, 436, 220, 24, "Sauver défauts")
ButtonGadget(#GAdvanced, 820, 436, 70, 24, "Avancé…")
ButtonGadget(#GCommit, 10, 450, 120, 30, "Add + Commit")
ButtonGadget(#GPush, 140, 450, 120, 30, "Push")
ButtonGadget(#GPull, 270, 450, 120, 30, "Pull")
ButtonGadget(#GConfig, 400, 450, 170, 30, "Configurer identité…")
ButtonGadget(#GMakeIgnore, 580, 450, 230, 30, "Créer .gitignore (recommandé)")
ButtonGadget(#GCommit, 10, 470, 120, 30, "Add + Commit")
ButtonGadget(#GPush, 140, 470, 120, 30, "Push")
ButtonGadget(#GPull, 270, 470, 120, 30, "Pull")
ButtonGadget(#GConfig, 400, 470, 170, 30, "Configurer identité…")
ButtonGadget(#GMakeIgnore, 580, 470, 230, 30, "Créer .gitignore (recommandé)")
; Panneau Guide
EditorGadget(#GGuide, 10, 490, 880, 140)
EditorGadget(#GGuide, 10, 510, 880, 140)
DisableGadget(#GGuide, 1)
; Infobulles utiles
GadgetToolTip(#GRestoreFile, "Restaurer le fichier sélectionné à un commit précis (historique).")
GadgetToolTip(#GDiff, "Afficher les différences du fichier sélectionné.")
; Infobulles clés
GadgetToolTip(#GShowClean, "Afficher aussi les fichiers déjà suivis et sans changement (pratique pour restaurer).")
GadgetToolTip(#GShowIgnored, "Inclure les fichiers ignorés par .gitignore (lecture seule pour info).")
GadgetToolTip(#GListStatus, "Cochez pour inclure un fichier au commit. 'Diff…' pour voir le détail. 'Restaurer fichier…' pour revenir à un commit.")
; Branches
NewList branchItems.s()
@@ -1205,9 +1495,9 @@ Procedure.i OpenGUI(initialDir$, prefsPath$)
ForEach branchItems() : AddGadgetItem(#GComboBranch, -1, branchItems()) : Next
If branch$ <> "" : SetGadgetText(#GComboBranch, branch$) : EndIf
; Status
; Fichiers (liste complète)
NewList rows.FileRow()
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
@@ -1228,23 +1518,28 @@ Procedure.i OpenGUI(initialDir$, prefsPath$)
ClearGadgetItems(#GComboBranch)
ForEach branchItems() : AddGadgetItem(#GComboBranch, -1, branchItems()) : Next
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
EndIf
Case #GRefresh
repoDir$ = GetGadgetText(#GStringRepo)
Case #GShowClean, #GShowIgnored
; Refiltrer laffichage à la volée
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
Case #GRefresh
ClearList(rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
Case #GInit
repoDir$ = GetGadgetText(#GStringRepo)
DoInitRepo(repoDir$)
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
@@ -1277,24 +1572,20 @@ Procedure.i OpenGUI(initialDir$, prefsPath$)
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
Case #GDiff
repoDir$ = GetGadgetText(#GStringRepo)
OpenDiffWindow(repoDir$, rows())
Case #GRestoreFile
repoDir$ = GetGadgetText(#GStringRepo)
If OpenRestoreFileWindow(repoDir$, rows())
; Après restauration : rafraîchir létat
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
EndIf
Case #GAdvanced
repoDir$ = GetGadgetText(#GStringRepo)
OpenAdvancedWindow(repoDir$)
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
@@ -1309,21 +1600,18 @@ Procedure.i OpenGUI(initialDir$, prefsPath$)
UpdateGuide(repoDir$, rows(), branch$, remote$)
Case #GConfig
repoDir$ = GetGadgetText(#GStringRepo)
If ConfigIdentityWizard(repoDir$)
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
EndIf
Case #GMakeIgnore
repoDir$ = GetGadgetText(#GStringRepo)
If MakeDefaultGitignore(repoDir$)
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
EndIf
Case #GCommit
repoDir$ = GetGadgetText(#GStringRepo)
remote$ = GetGadgetText(#GStringRemote)
branch$ = GetGadgetText(#GComboBranch)
Protected msg$ = GetGadgetText(#GStringMsg)
@@ -1338,19 +1626,17 @@ Procedure.i OpenGUI(initialDir$, prefsPath$)
DoCommit(repoDir$, msg$, GetGadgetState(#GCheckPush), remote$, branch$)
EndIf
ClearList(rows())
LoadStatusRows(repoDir$, rows())
BuildFullFileList(repoDir$, GetGadgetState(#GShowClean), GetGadgetState(#GShowIgnored), rows())
FillStatusList(rows())
UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote))
EndIf
Case #GPush
repoDir$ = GetGadgetText(#GStringRepo)
remote$ = GetGadgetText(#GStringRemote)
branch$ = GetGadgetText(#GComboBranch)
DoPush(repoDir$, remote$, branch$)
Case #GPull
repoDir$ = GetGadgetText(#GStringRepo)
remote$ = GetGadgetText(#GStringRemote)
branch$ = GetGadgetText(#GComboBranch)
DoPull(repoDir$, remote$, branch$)
@@ -1369,6 +1655,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$)
ProcedureReturn 0
EndProcedure
; ====== Installation IDE ======
; Fenêtre assistant
#WInstall = 100
@@ -1568,9 +1855,9 @@ Else
EndIf
; IDE Options = PureBasic 6.21 (Windows - x64)
; CursorPosition = 1370
; FirstLine = 1329
; Folding = -------
; CursorPosition = 1413
; FirstLine = 1375
; Folding = --------
; EnableXP
; DPIAware
; Executable = ..\PBIDE-GitTool.exe