Compare commits

..

5 Commits

Author SHA1 Message Date
03bdf767b5 Add First Push 2025-08-30 08:05:05 +02:00
339f4f5f40 Fils List Corrected and sorted 2025-08-29 22:11:55 +02:00
1464995bc8 Add Switch Branch in Commit 2025-08-29 17:46:58 +02:00
86512b2d5a Add Commit 2025-08-29 17:44:10 +02:00
d66e2a88a6 Add Local and Remote Branch 2025-08-29 17:08:18 +02:00
2 changed files with 477 additions and 16 deletions

View File

@@ -761,7 +761,7 @@ Procedure.i GetRemoteStatusInfo()
; Vérifier que Git est dispo et repo initialisé ; Vérifier que Git est dispo et repo initialisé
If Not main\info\isGit Or Not main\info\isInit If Not main\info\isGit Or Not main\info\isInit
main\remoteStatus\status = "Repo non initialisé" main\remoteStatus\status = "Repo non initialisé"
ProcedureReturn 0 ProcedureReturn #False
EndIf EndIf
; Récupérer la branche courante ; Récupérer la branche courante
@@ -2778,8 +2778,8 @@ OpenGUI()
; IDE Options = PureBasic 6.21 (Windows - x64) ; IDE Options = PureBasic 6.21 (Windows - x64)
; CursorPosition = 2467 ; CursorPosition = 537
; FirstLine = 2371 ; FirstLine = 537
; Folding = ----------- ; Folding = -----------
; Optimizer ; Optimizer
; EnableThread ; EnableThread

487
main2.pb
View File

@@ -593,7 +593,7 @@ EndProcedure
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; Tooltips & i18n ; Tooltips & i18n
; FR: Appeler après la création des gadgets, puis après tout changement de langue. ; FR: Appeler après la création des gadgets, puis après tout changement de langue
; EN: Call after creating gadgets, then after any language change. ; EN: Call after creating gadgets, then after any language change.
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
@@ -902,6 +902,185 @@ Procedure.i DoGitFetch(remote.s="origin",branch.s="main")
ProcedureReturn #False ProcedureReturn #False
EndProcedure EndProcedure
Procedure.i DoCommit()
Protected code.i,nb.l=0,i.l
Protected args.s = "add"
For i = 0 To CountGadgetItems(#GID_ListStatus) - 1
If GetGadgetItemState(#GID_ListStatus, i) & #PB_ListIcon_Checked
nb+1
args+" "+Chr(34)+StringField(GetGadgetItemText(#GID_ListStatus, i),1,Chr(10))+Chr(34)
EndIf
Next i
If nb=0
MessageRequester("Git add", "Échec: Vous devez selectionnez des fichiers à ajouter au commit", #PB_MessageRequester_Error)
ProcedureReturn #False
EndIf
If Trim(GetGadgetText(#GID_EdMessage))=""
MessageRequester("Git add", "Échec: Vous devez mettre un message", #PB_MessageRequester_Error)
ProcedureReturn #False
EndIf
If GetGadgetText(#GID_CbLocalBranch)<>"" And Git("switch "+GetGadgetText(#GID_CbLocalBranch))<>0
MessageRequester("Git switch", "Échec: " + #LF$ + main\GitCall\errors, #PB_MessageRequester_Error)
EndIf
If Git(args)<>0
MessageRequester("Git add", "Échec: " + #LF$ + main\GitCall\errors, #PB_MessageRequester_Error)
ProcedureReturn #False
EndIf
; Commit with message / Valider avec un message
args = "commit -m " + Chr(34) + GetGadgetText(#GID_EdMessage) + Chr(34)
If Git(args)<>0
MessageRequester("Git commit", "Échec ou rien à valider: " + #LF$ + main\GitCall\errors + #LF$ + main\GitCall\output, #PB_MessageRequester_Warning)
ProcedureReturn 0
Else
MessageRequester("Git commit", "OK:" + #LF$ + main\GitCall\output, #PB_MessageRequester_Info)
EndIf
ProcedureReturn #True
EndProcedure
Procedure AddRemoteRepo(Url.s,name.s="origin")
Url=SupTrim(Url)
name=SupTrim(name)
Protected add.b=#False
;Check if this remote already exists
If git("remote get-url "+name) = 0
;if yes we remove it
If Url<>SupTrim(main\Gitcall\output)
git("remote remove "+name)
add=#True
EndIf
Else
add=#True
EndIf
; We add a new remote
If add=#True
If git("remote add "+name+" "+Url) = 0
;MessageRequester("Git Remote", "OK:" + #LF$ + main\Gitcall\output, #PB_MessageRequester_Info)
ProcedureReturn #True
Else
MessageRequester("Git config", "Échec: " + #LF$ + main\Gitcall\errors, #PB_MessageRequester_Error)
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndIf
EndProcedure
Procedure DoPush()
If Trim(GetGadgetText(#GID_EdRemote))=""
MessageRequester("Git Push", "Échec: " + #LF$ + "You Must tu have a remote", #PB_MessageRequester_Error)
EndIf
If AddRemoteRepo(Trim(GetGadgetText(#GID_EdRemote)))
If Git("push -u origin "+GetGadgetText(#GID_CbRemoteBranch))
MessageRequester("Git Push", "OK:" + #LF$ + main\Gitcall\output, #PB_MessageRequester_Info)
ProcedureReturn #True
Else
MessageRequester("Git Push", "Échec: " + #LF$ + main\Gitcall\errors, #PB_MessageRequester_Error)
ProcedureReturn #False
EndIf
Else
Debug"ZOOOOOOOOOOOOOOM"
ProcedureReturn #False
EndIf
EndProcedure
Procedure.i GetRemoteStatusInfo()
; Récupère les informations de status du remote
Protected localBranch.s = GetGadgetText(#GID_CbLocalBranch)
Protected remoteBranch.s = GetGadgetText(#GID_CbRemoteBranch)
; Variables initialisées
Protected ahead.l = 0
Protected behind.l = 0
Protected isUpToDate.b = #False
Protected status.s = "--"
Protected needsAction.s = "--"
Protected color.i = RGB(60, 60, 60) ; Gris par défaut
; Vérifier que les branches sont définies
If Len(Trim(localBranch)) = 0 Or Len(Trim(remoteBranch)) = 0
status = "Branches non sélectionnées"
needsAction = "Sélectionner les branches"
ProcedureReturn #False
EndIf
; Comparer local vs remote
If Git("rev-list --left-right --count " + localBranch + "..." + remoteBranch) = 0
Protected counts.s = Trim(main\GitCall\output)
; Vérifier que la sortie contient bien des données
If Len(counts) > 0
; Parser les résultats (séparés par des espaces ou tabs)
Protected parts.s = ReplaceString(counts, #TAB$, " ") ; Normaliser les séparateurs
parts = ReplaceString(parts, " ", " ") ; Supprimer les espaces multiples
ahead = Val(StringField(parts, 1, " "))
behind = Val(StringField(parts, 2, " "))
; Construire le status et les actions
If ahead = 0 And behind = 0
isUpToDate = #True
status = "À jour"
needsAction = ""
color = RGB(0, 128, 0) ; Vert pour "à jour"
ElseIf ahead > 0 And behind = 0
status = Str(ahead) + " commit(s) en avance"
needsAction = "Push recommandé"
color = RGB(0, 100, 200) ; Bleu pour "en avance"
ElseIf ahead = 0 And behind > 0
status = Str(behind) + " commit(s) en retard"
needsAction = "Pull nécessaire"
color = RGB(255, 140, 0) ; Orange pour "en retard"
Else
status = Str(ahead) + " en avance, " + Str(behind) + " en retard"
needsAction = "Branches divergentes - Merge/Rebase requis"
color = RGB(255, 69, 0) ; Rouge-orange pour divergence
EndIf
Else
status = "Réponse vide de Git"
needsAction = "Vérifier la configuration Git"
EndIf
Else
; Erreur dans la commande Git
status = "Erreur comparaison"
needsAction = "Vérifier les noms de branches"
color = RGB(255, 0, 0) ; Rouge pour erreur
; Debug pour diagnostiquer l'erreur
Debug "Erreur Git: " + main\GitCall\output
Debug "Commande: rev-list --left-right --count " + localBranch + "..." + remoteBranch
EndIf
; Mettre à jour l'interface
SetGadgetText(#GID_TxtRemoteStatus, status)
; Définir la couleur si le gadget le supporte
; (Décommentez si votre version de PureBasic/OS le supporte)
; SetGadgetColor(#GID_LblRemoteStatus, #PB_Gadget_FrontColor, color)
; Action recommandée
If needsAction <> ""
SetGadgetText(#GID_TxtAction, needsAction)
Else
SetGadgetText(#GID_TxtAction, "Aucune action nécessaire")
EndIf
ProcedureReturn #True
EndProcedure
Procedure.s GetStatusDescription(status.s) Procedure.s GetStatusDescription(status.s)
Select status Select status
Case " " Case " "
@@ -953,8 +1132,50 @@ Procedure.s GetStatusDescription(status.s)
EndSelect EndSelect
EndProcedure EndProcedure
Procedure.i GetStatusImportance(status.s)
Protected x.s = Left(status, 1)
Protected y.s = Mid(status, 2, 1)
Protected score.i = 0
; Conflits d'abord
Select status
Case "DD","AU","UD","UA","DU","AA","UU"
ProcedureReturn 1000
EndSelect
If x = "U" Or y = "U" : ProcedureReturn 1000 : EndIf
; Cas simples
If status = "??" : ProcedureReturn 300 : EndIf ; Non suivis
If status = "!!" : ProcedureReturn 50 : EndIf ; Ignorés
If status = " " : ProcedureReturn 0 : EndIf ; Propres
; Index > Worktree
If x <> " " : score + 700 : EndIf
If y <> " " And y <> "?" And y <> "!" : score + 600 : EndIf
; Raffinement (X puis Y)
Select x
Case "D" : score + 80
Case "R" : score + 70
Case "A" : score + 60
Case "M" : score + 50
Case "C" : score + 40
Case "T" : score + 30
EndSelect
Select y
Case "D" : score + 40
Case "R" : score + 35
Case "A" : score + 30
Case "M" : score + 25
Case "C" : score + 20
Case "T" : score + 15
EndSelect
ProcedureReturn score
EndProcedure
Procedure GetGitStatusPocelaine() Procedure GetGitStatusPocelaine()
If Git("status --porcelain -z --ignored") = 0 If Git("status --porcelain --ignored") = 0
ProcedureReturn #True ProcedureReturn #True
EndIf EndIf
ProcedureReturn #False ProcedureReturn #False
@@ -962,22 +1183,22 @@ EndProcedure
; Parse la sortie de: git status --porcelain -z ; Parse la sortie de: git status --porcelain -z
Procedure ParseStatusPorcelaine(output$) Procedure ParseStatusPorcelaine(output$)
Protected delim$ = Chr(0) Protected delim$ = Chr(10)
Protected total.l = CountString(output$, delim$) + 1 Protected total.l = CountString(output$, delim$) + 1
Protected i.l = 1, tok$, sp.l Protected i.l = 1, tok$, sp.l
Protected xy$, path1$, path2$, name$, found.b Protected xy$, path1$, path2$, name$, found.b
; Ne PAS vider main\Files(): on met à jour si existe déjà ; Ne PAS vider main\Files(): on met à jour si existe déjà
For i=1 To total For i=1 To total
tok$ = StringField(output$, i, delim$) : i + 1 tok$ = StringField(output$, i, delim$)
If tok$ = "" : Continue : EndIf If tok$ = "" : Continue : EndIf
; tok$ ressemble à: "XY[...score...]␠<path1>" ; tok$ ressemble à: "XY[...score...]␠<path1>"
sp = FindString(tok$, " ", 3) If Mid(tok$,3,1)<>" "
Debug "sp="+Str(sp) Continue
If sp = 0 Or Len(tok$) < 3 : Continue : EndIf EndIf
xy$ = Left(tok$, 2) ; ex: " M", "R ", " C", "??", "UU", etc. xy$ = Left(tok$, 2) ; ex: " M", "R ", " C", "??", "UU", etc.
path1$ = Mid(tok$, sp+1,Len(tok$)-(sp+1)) ; 1er chemin path1$ = Mid(tok$, 4,Len(tok$)-(3)) ; 1er chemin
;TODO check this ;TODO check this
; Renomme/copie ? (si X ou Y est R/C, le prochain champ NUL = nouveau chemin) ; Renomme/copie ? (si X ou Y est R/C, le prochain champ NUL = nouveau chemin)
@@ -1017,6 +1238,130 @@ Procedure ParseStatusPorcelaine(output$)
ProcedureReturn #True ProcedureReturn #True
EndProcedure EndProcedure
; Parse la sortie de: git status --porcelain -z
Procedure ParseStatusPorcelaine_new(output$)
Protected delim$ = Chr(0)
Protected pos.l = 1, nextPos.l
Protected xy$, path1$, path2$, name$, found.b
Protected line$, spacePos.l
Debug "Début parsing status -z, taille output: " + Str(Len(output$))
; Ne PAS vider main\Files(): on met à jour si existe déjà
While pos <= Len(output$)
; Trouver la prochaine entrée (délimitée par Chr(0))
nextPos = FindString(output$, delim$, pos)
If nextPos = 0
nextPos = Len(output$) + 1 ; Dernière entrée
EndIf
line$ = Mid(output$, pos, nextPos - pos)
; Passer à la prochaine entrée
pos = nextPos + 1
; Ignorer les lignes vides
If Len(line$) < 3
Continue
EndIf
Debug "Ligne analysée: [" + ReplaceString(line$, Chr(9), "<TAB>") + "]"
; Format: XY<espace><chemin> où XY = 2 caractères de status
xy$ = Left(line$, 2)
; Le 3ème caractère doit être un espace
If Mid(line$, 3, 1) <> " "
Debug "Format invalide - pas d'espace en position 3: " + line$
Continue
EndIf
; Extraire le chemin (à partir du 4ème caractère)
path1$ = Mid(line$, 4)
; Initialiser path2$ pour les cas rename/copy
path2$ = ""
; Vérifier si c'est un rename ou copy (R ou C dans le status)
; Format pour rename: "R100 ancien_nom<NUL>nouveau_nom<NUL>"
If Left(xy$, 1) = "R" Or Left(xy$, 1) = "C" Or Right(xy$, 1) = "R" Or Right(xy$, 1) = "C"
; Pour les renames/copies, il peut y avoir un score (ex: R100)
; Le chemin source se termine par NUL, suivi du chemin destination
Protected nullPos.l = FindString(path1$, delim$, 1)
If nullPos > 0
; Séparer les deux chemins
Protected tempPath$ = path1$
path1$ = Left(tempPath$, nullPos - 1)
; Le chemin de destination est après le NUL
If pos <= Len(output$)
nextPos = FindString(output$, delim$, pos)
If nextPos = 0
nextPos = Len(output$) + 1
EndIf
path2$ = Mid(output$, pos, nextPos - pos)
pos = nextPos + 1
EndIf
Debug "Rename/Copy détecté: " + path1$ + " -> " + path2$
EndIf
; Pour les renames, utiliser le nouveau nom
If path2$ <> ""
name$ = path2$
Else
name$ = path1$
EndIf
Else
name$ = path1$
EndIf
; Nettoyer le nom (enlever les guillemets si présents)
If Left(name$, 1) = Chr(34) And Right(name$, 1) = Chr(34) ; guillemets doubles
name$ = Mid(name$, 2, Len(name$) - 2)
EndIf
; Normaliser les séparateurs
name$ = ReplaceString(name$, "\", "/")
; Décoder les caractères échappés (\n, \t, \\, etc.)
name$ = ReplaceString(name$, "\\", "\")
name$ = ReplaceString(name$, "\n", Chr(10))
name$ = ReplaceString(name$, "\t", Chr(9))
Debug "Fichier traité: [" + name$ + "] Status: [" + xy$ + "]"
; Vérifier que le nom n'est pas vide
If Len(Trim(name$)) = 0
Debug "Nom de fichier vide, ignoré"
Continue
EndIf
; MAJ si déjà présent, sinon ajout
found = #False
ForEach main\Files()
If main\Files()\name = name$
found = #True
main\Files()\status = xy$
main\Files()\statusDescription = GetStatusDescription(xy$)
Debug "Fichier mis à jour: " + name$
Break
EndIf
Next
If Not found
AddElement(main\Files())
main\Files()\name = name$
main\Files()\status = xy$
main\Files()\statusDescription = GetStatusDescription(xy$)
Debug "Nouveau fichier ajouté: " + name$
EndIf
Wend
Debug "Récupération des status Git (-z) réussie. " + Str(ListSize(main\Files())) + " fichiers (maj/ajout)."
ProcedureReturn #True
EndProcedure
Procedure IsGitRepository() Procedure IsGitRepository()
If Git("status") <> 0 If Git("status") <> 0
ProcedureReturn #False ProcedureReturn #False
@@ -1033,6 +1378,102 @@ Procedure GetGitRemoteUrl(name.s="origin")
EndIf EndIf
EndProcedure EndProcedure
Procedure GetGitLocalBranch()
If Git("branch")=0
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure.s RefreshLocalBranchesList(Gdt.i)
ClearGadgetItems(Gdt)
; Parser ligne par ligne
Protected n.l = CountString(main\Gitcall\output, #LF$) + 1
Protected i.l, line.s
For i = 1 To n
line = StringField(main\Gitcall\output, i, #LF$)
line = Trim(line)
If Len(line) = 0
Continue ; Ignorer les lignes vides
EndIf
Protected selectbranch.b=#False
If Left(line,1)="*"
selectbranch=#True
line=Trim(StringField(line,2," "))
EndIf
AddGadgetItem(Gdt,i-1,line)
If selectbranch=#True
SetGadgetState(Gdt,i-1)
EndIf
Next
EndProcedure
Procedure GetGitRemoteBranch()
If Git("branch -r")=0
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure.s RefreshRemoteBranchesList(Gdt.i)
ClearGadgetItems(Gdt)
; Parser ligne par ligne
Protected n.l = CountString(main\Gitcall\output, #LF$) + 1
Protected i.l, line.s, cleanBranchName.s, defaultBranch.s
Protected itemIndex.l
; Trouver d'abord la branche par défaut
For i = 1 To n
line = StringField(main\Gitcall\output, i, #LF$)
line = Trim(line)
If FindString(line, "->", 1)
; Extraire la branche par défaut depuis "origin/HEAD -> origin/main"
defaultBranch = Trim(StringField(line, 2, "->"))
If Left(defaultBranch, 8) = "remotes/"
defaultBranch = Right(defaultBranch, Len(defaultBranch) - 8)
EndIf
Break
EndIf
Next
; Ajouter les branches
For i = 1 To n
line = StringField(main\Gitcall\output, i, #LF$)
line = Trim(line)
If Len(line) = 0
Continue ; Ignorer les lignes vides
EndIf
; Ignorer la ligne origin/HEAD -> origin/main
If FindString(line, "->", 1)
Continue
EndIf
; Nettoyer le nom de la branche (enlever "remotes/" si présent)
cleanBranchName = line
If Left(cleanBranchName, 8) = "remotes/"
cleanBranchName = Right(cleanBranchName, Len(cleanBranchName) - 8)
EndIf
itemIndex = CountGadgetItems(Gdt)
AddGadgetItem(Gdt, itemIndex, cleanBranchName)
; Sélectionner la branche par défaut
If cleanBranchName = defaultBranch
SetGadgetState(Gdt, itemIndex)
EndIf
Next
EndProcedure
; --- Helper interne : scanne un dossier et alimente la liste ; --- Helper interne : scanne un dossier et alimente la liste
Procedure _ScanFiles(path$, root$="") Procedure _ScanFiles(path$, root$="")
If root$="":root$=path$:EndIf If root$="":root$=path$:EndIf
@@ -1085,16 +1526,33 @@ Procedure RefreshFiles()
ClearList(main\Files()) ClearList(main\Files())
readDirectory() readDirectory()
If main\IsRepository And GetGitVersion() If main\IsRepository And GetGitVersion()
GetGitLocalBranch()
RefreshLocalBranchesList(#GID_CbLocalBranch)
GetGitStatusPocelaine() GetGitStatusPocelaine()
ParseStatusPorcelaine(main\gitCall\output) ParseStatusPorcelaine(main\gitCall\output)
If GetGitRemoteUrl() If GetGitRemoteUrl()
SetGadgetText(#GID_EdRemote,SupTrim(main\gitCall\output)) SetGadgetText(#GID_EdRemote,SupTrim(main\gitCall\output))
main\hasRemoteUrl=#True main\hasRemoteUrl=#True
GetGitRemoteBranch()
RefreshRemoteBranchesList(#GID_CbRemoteBranch)
Debug "###################################"
GetRemoteStatusInfo()
Else Else
SetGadgetText(#GID_EdRemote,"") SetGadgetText(#GID_EdRemote,"")
main\hasRemoteUrl=#False main\hasRemoteUrl=#False
ClearGadgetItems(#GID_CbRemoteBranch)
EndIf EndIf
EndIf EndIf
;Get Status
ForEach main\Files()
main\Files()\importance = GetStatusImportance(main\Files()\status)
Next
;Sort by Importance
SortStructuredList(main\Files(), #PB_Sort_Descending, OffsetOf(FilesStruct\importance), #PB_Integer)
;Display list
Protected n.l=n-1 Protected n.l=n-1
ForEach main\Files() ForEach main\Files()
n=n+1 n=n+1
@@ -1225,7 +1683,10 @@ Procedure Main()
; TODO: ignore ; TODO: ignore
Case #GID_BtnCommit Case #GID_BtnCommit
; TODO: commit with GetGadgetText(#GID_EdMessage) If DoCommit()=#True
SetGadgetText(#GID_EdMessage,"")
RefreshFiles()
EndIf
Case #GID_BtnSaveGitIgnore Case #GID_BtnSaveGitIgnore
; TODO: save .gitignore ; TODO: save .gitignore
@@ -1243,8 +1704,8 @@ EndProcedure
Main() Main()
; IDE Options = PureBasic 6.21 (Windows - x64) ; IDE Options = PureBasic 6.21 (Windows - x64)
; CursorPosition = 591 ; CursorPosition = 952
; FirstLine = 521 ; FirstLine = 948
; Folding = ------ ; Folding = ----f--
; EnableXP ; EnableXP
; DPIAware ; DPIAware