diff --git a/PBIDE-GitTool.pb b/PBIDE-GitTool.pb index f5cbdca..423f76e 100644 --- a/PBIDE-GitTool.pb +++ b/PBIDE-GitTool.pb @@ -22,7 +22,6 @@ CompilerElse CompilerEndIf ; ====== IDs UI (placer ce bloc AVANT toutes les procédures) ====== - ; Fenêtre principale #GWindow = 1 #GLabelRepo = 10 @@ -71,6 +70,17 @@ CompilerEndIf #GInstallCancel = 120 #GInstallNote = 121 +; --- Nouveaux gadgets --- +#GDiff = 32 +#GMakeIgnore = 33 +#GConfig = 34 +#GGuide = 35 + +; --- Fenêtre Diff --- +#WDiff = 300 +#GDiffText = 301 +#GDiffClose = 302 + ; ====== Structures ====== Structure GitCall @@ -112,6 +122,12 @@ Declare.i SwitchToBranch(repoDir$, branch$) Declare.i RestoreFromBranch(repoDir$, branch$) Declare.i InstallPBGitInIDE(ideExe$, toolsPrefs$, themeZip$) Declare.i OpenInstallWizard() +Declare.s PorcelainToLabel(code$) +Declare.i OpenDiffWindow(repoDir$, List rows.FileRow()) +Declare.i ConfigIdentityWizard(repoDir$) +Declare.i MakeDefaultGitignore(repoDir$) +Declare.i UpdateGuide(repoDir$, List rows.FileRow(), branch$, remote$) +Declare.s GetLocalConfig(repoDir$, key$) ; ====== Utils ====== Procedure.s TrimNewlines(text$) @@ -391,8 +407,10 @@ EndProcedure Procedure.i FillStatusList(List rows.FileRow()) ClearGadgetItems(#GListStatus) Protected idx.i = 0 + Protected label$ ForEach rows() - AddGadgetItem(#GListStatus, -1, rows()\stat + #LF$ + rows()\file) + label$ = PorcelainToLabel(rows()\stat) + AddGadgetItem(#GListStatus, -1, label$ + #LF$ + rows()\file) If rows()\include SetGadgetItemState(#GListStatus, idx, #PB_ListIcon_Checked) Else @@ -403,6 +421,7 @@ Procedure.i FillStatusList(List rows.FileRow()) ProcedureReturn CountGadgetItems(#GListStatus) EndProcedure + Procedure.i ToggleIncludeAt(index.i, List rows.FileRow()) If index < 0 : ProcedureReturn 0 : EndIf Protected c.i = CountGadgetItems(#GListStatus) @@ -551,6 +570,206 @@ Procedure.i RestoreFromBranch(repoDir$, branch$) ProcedureReturn 0 EndProcedure +Procedure.s PorcelainToLabel(code$) + Protected x$ = Left(code$, 1) + Protected y$ = Right(code$, 1) + + If code$ = "??" + ProcedureReturn "Nouveau (non suivi)" + EndIf + If code$ = "!!" + ProcedureReturn "Ignoré" + EndIf + + ; Colonne X = indexé (staged) + If x$ = "M" : ProcedureReturn "Modifié (indexé)" : EndIf + If x$ = "A" : ProcedureReturn "Ajouté (indexé)" : EndIf + If x$ = "D" : ProcedureReturn "Supprimé (indexé)" : EndIf + If x$ = "R" : ProcedureReturn "Renommé (indexé)" : EndIf + If x$ = "C" : ProcedureReturn "Copié (indexé)" : EndIf + + ; Colonne Y = non indexé (worktree) + If y$ = "M" : ProcedureReturn "Modifié (non indexé)" : EndIf + If y$ = "A" : ProcedureReturn "Ajouté (non indexé)" : EndIf + If y$ = "D" : ProcedureReturn "Supprimé (non indexé)" : EndIf + + 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 + gc\workdir = repoDir$ + gc\args = "config --get " + key$ + If RunGit(@gc) = 0 + ProcedureReturn TrimNewlines(gc\output) + EndIf + ProcedureReturn "" +EndProcedure + +Procedure.i ConfigIdentityWizard(repoDir$) + Protected curName$ = GetLocalConfig(repoDir$, "user.name") + Protected curMail$ = GetLocalConfig(repoDir$, "user.email") + Protected name$ = InputRequester("Identité Git", "Nom d’auteur (user.name)", curName$) + If name$ = "" : ProcedureReturn 0 : EndIf + Protected mail$ = InputRequester("Identité Git", "Email (user.email)", curMail$) + If mail$ = "" Or FindString(mail$, "@", 1) = 0 + MessageRequester("Identité Git", "Email invalide.", #PB_MessageRequester_Warning) + ProcedureReturn 0 + EndIf + + Protected gc.GitCall + gc\workdir = repoDir$ + gc\args = "config user.name " + Chr(34) + name$ + Chr(34) + If RunGit(@gc) <> 0 + MessageRequester("Git config", "Échec user.name: " + #LF$ + TrimNewlines(gc\errors), #PB_MessageRequester_Error) + ProcedureReturn 0 + EndIf + + gc\args = "config user.email " + Chr(34) + mail$ + Chr(34) + If RunGit(@gc) <> 0 + MessageRequester("Git config", "Échec user.email: " + #LF$ + TrimNewlines(gc\errors), #PB_MessageRequester_Error) + ProcedureReturn 0 + EndIf + + MessageRequester("Identité Git", "Identité locale configurée.", #PB_MessageRequester_Info) + ProcedureReturn 1 +EndProcedure + +Procedure.i MakeDefaultGitignore(repoDir$) + Protected base$ = repoDir$ + If Right(base$, 1) <> #PathSep$ : base$ + #PathSep$ : EndIf + Protected path$ = base$ + ".gitignore" + + If FileSize(path$) > 0 + If MessageRequester(".gitignore", "Un .gitignore existe déjà. Le remplacer ?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_No + ProcedureReturn 0 + EndIf + EndIf + + Protected txt$ = "" + txt$ + "# PureBasic / build artefacts" + #LF$ + txt$ + "*.exe" + #LF$ + txt$ + "*.dll" + #LF$ + txt$ + "*.so" + #LF$ + txt$ + "*.dylib" + #LF$ + txt$ + "*.o" + #LF$ + txt$ + "*.obj" + #LF$ + txt$ + "*.pdb" + #LF$ + txt$ + "*.res" + #LF$ + txt$ + "*.a" + #LF$ + txt$ + "*.lib" + #LF$ + txt$ + "*.d" + #LF$ + txt$ + "*.map" + #LF$ + txt$ + "*.dbg" + #LF$ + txt$ + "*.log" + #LF$ + txt$ + "*.temp" + #LF$ + txt$ + "*.bak" + #LF$ + txt$ + "*.cache" + #LF$ + txt$ + #LF$ + txt$ + "# IDE / OS" + #LF$ + txt$ + ".DS_Store" + #LF$ + txt$ + "Thumbs.db" + #LF$ + txt$ + ".idea" + #LF$ + txt$ + ".vscode" + #LF$ + + Protected ok.i + If CreateFile(0, path$) + WriteString(0, txt$) : CloseFile(0) : ok = 1 + EndIf + + If ok + MessageRequester(".gitignore", "Fichier .gitignore créé.", #PB_MessageRequester_Info) + ProcedureReturn 1 + EndIf + + MessageRequester(".gitignore", "Échec de création.", #PB_MessageRequester_Error) + ProcedureReturn 0 +EndProcedure + +Procedure.i UpdateGuide(repoDir$, List rows.FileRow(), branch$, remote$) + Protected tips$ = "" + Protected hasChanges.i = 0 + ForEach rows() + hasChanges = 1 + Break + Next + + Protected name$ = GetLocalConfig(repoDir$, "user.name") + Protected mail$ = GetLocalConfig(repoDir$, "user.email") + + tips$ + "Bienvenue !" + #LF$ + tips$ + "- Si vous débutez, suivez ces étapes :" + #LF$ + #LF$ + tips$ + "1) " + Chr(149) + " Vérifiez que l'identité Git est configurée (bouton 'Configurer identité…')." + #LF$ + If name$ = "" Or mail$ = "" + tips$ + " → Identité actuelle : INCOMPLÈTE." + #LF$ + Else + tips$ + " → Identité : " + name$ + " <" + mail$ + ">" + #LF$ + EndIf + + tips$ + "2) " + Chr(149) + " Optionnel : créez un '.gitignore' (bouton dédié) pour ignorer les fichiers de compilation." + #LF$ + tips$ + "3) " + Chr(149) + " Cochez dans la liste les fichiers à inclure au commit." + #LF$ + If hasChanges + tips$ + " → Des modifications sont détectées ci-dessus." + #LF$ + Else + tips$ + " → Aucune modification à committer pour l’instant." + #LF$ + EndIf + + tips$ + "4) " + Chr(149) + " Saisissez un message puis cliquez sur 'Add + Commit' (coche 'Pousser après' si besoin)." + #LF$ + tips$ + "5) " + Chr(149) + " Pour changer/recuperer une branche : bouton 'Avancé…'." + #LF$ + #LF$ + + tips$ + "Infos :" + #LF$ + tips$ + "• Remote : " + remote$ + " • Branche : " + branch$ + #LF$ + tips$ + "• Cliquez sur 'Diff…' pour voir le détail d’un fichier sélectionné." + #LF$ + + SetGadgetText(#GGuide, tips$) + ProcedureReturn 1 +EndProcedure + ; ====== UI principale ====== ; Gadgets IDs (inclut les NOUVEAUX boutons) #GWindow = 1 @@ -582,68 +801,65 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) Protected remote$ = "", branch$ = "" LoadPrefs(prefsPath$, remote$, branch$) - If OpenWindow(#GWindow, 0, 0, 740, 560, "PBIDE-GitTool — Git simplifié pour PureBasic", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) + If OpenWindow(#GWindow, 0, 0, 820, 640, "PBIDE-GitTool — Git (mode simplifié)", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) TextGadget(#GLabelRepo, 10, 12, 60, 22, "Dépôt :") - StringGadget(#GStringRepo, 80, 10, 540, 24, repoDir$) - ButtonGadget(#GButtonBrowse, 630, 10, 100, 24, "Parcourir…") + StringGadget(#GStringRepo, 80, 10, 620, 24, repoDir$) + ButtonGadget(#GButtonBrowse, 710, 10, 100, 24, "Parcourir…") ; Liste avec cases à cocher - ListIconGadget(#GListStatus, 10, 46, 720, 280, "Statut", 100, #PB_ListIcon_CheckBoxes | #PB_ListIcon_FullRowSelect) + ListIconGadget(#GListStatus, 10, 46, 800, 300, "Statut", 180, #PB_ListIcon_CheckBoxes | #PB_ListIcon_FullRowSelect) AddGadgetColumn(#GListStatus, 1, "Fichier", 600) - ButtonGadget(#GRefresh, 10, 332, 90, 26, "Rafraîchir") - ButtonGadget(#GInit, 110, 332, 90, 26, "Init repo") - ButtonGadget(#GInclude, 210, 332, 90, 26, "Inclure") - ButtonGadget(#GExclude, 310, 332, 90, 26, "Exclure") - ButtonGadget(#GIncludeAll, 410, 332, 110, 26, "Tout inclure") - ButtonGadget(#GExcludeAll, 530, 332, 110, 26, "Tout exclure") - ButtonGadget(#GAdvanced, 650, 332, 80, 26, "Avancé…") + ; 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, 70, 26, "Diff…") + ButtonGadget(#GAdvanced, 730, 352, 80, 26, "Avancé…") - TextGadget(#GLabelMsg, 10, 372, 100, 22, "Message :") - StringGadget(#GStringMsg, 110, 370, 620, 24, "") - CheckBoxGadget(#GCheckPush, 10, 402, 120, 22, "Pousser après") + ; 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") SetGadgetState(#GCheckPush, #True) - TextGadget(#GLabelRemote, 150, 402, 60, 22, "Remote :") - StringGadget(#GStringRemote, 210, 400, 120, 24, remote$) - TextGadget(#GLabelBranch, 340, 402, 60, 22, "Branche :") - ComboBoxGadget(#GComboBranch, 400, 400, 170, 24) - ButtonGadget(#GSavePrefs, 580, 400, 150, 24, "Sauver défauts") + 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(#GCommit, 10, 440, 120, 30, "Add + Commit") - ButtonGadget(#GPush, 140, 440, 120, 30, "Push") - ButtonGadget(#GPull, 270, 440, 120, 30, "Pull") + 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é)") + + ; Panneau Guide + EditorGadget(#GGuide, 10, 490, 800, 140) + DisableGadget(#GGuide, 1) ; Infobulles - GadgetToolTip(#GStringRepo, "Dossier du dépôt Git. Utilisez 'Parcourir…' pour le sélectionner.") - GadgetToolTip(#GButtonBrowse, "Choisir le répertoire du dépôt.") - GadgetToolTip(#GListStatus, "Cochez pour inclure un fichier dans le prochain commit. Colonnes : Statut / Fichier.") - GadgetToolTip(#GRefresh, "Rafraîchir l’état du dépôt (git status --porcelain).") - GadgetToolTip(#GInit, "Initialiser un dépôt Git ici (git init).") - GadgetToolTip(#GInclude, "Inclure l’élément sélectionné.") - GadgetToolTip(#GExclude, "Exclure l’élément sélectionné.") - GadgetToolTip(#GIncludeAll, "Inclure tous les éléments de la liste.") - GadgetToolTip(#GExcludeAll, "Exclure tous les éléments de la liste.") - GadgetToolTip(#GAdvanced, "Ouvrir les actions avancées (branches, restauration…).") - GadgetToolTip(#GStringMsg, "Message de commit.") - GadgetToolTip(#GCheckPush, "Activer pour pousser après le commit (git push).") - GadgetToolTip(#GStringRemote, "Nom du remote (ex: origin).") - GadgetToolTip(#GComboBranch, "Branche cible (ex: main).") - GadgetToolTip(#GSavePrefs, "Sauver remote/branche comme valeurs par défaut.") - GadgetToolTip(#GCommit, ~"git add (fichiers cochés ou -A si aucun coché) puis git commit -m \"message\" (et push si coché).") - GadgetToolTip(#GPush, "Pousser la branche (git push).") - GadgetToolTip(#GPull, "Récupérer les changements distants (git pull).") + GadgetToolTip(#GListStatus, "Cochez pour inclure un fichier dans le prochain commit. Double-cliquez pour sélectionner, bouton 'Diff…' pour le détail.") + GadgetToolTip(#GDiff, "Afficher les différences du fichier sélectionné.") + GadgetToolTip(#GConfig, "Configurer user.name et user.email localement pour ce dépôt.") + GadgetToolTip(#GMakeIgnore, "Créer un .gitignore avec des règles recommandées pour PureBasic.") - ; Branches et status + ; Branches NewList branchItems.s() ListBranches(repoDir$, branchItems()) ClearGadgetItems(#GComboBranch) ForEach branchItems() : AddGadgetItem(#GComboBranch, -1, branchItems()) : Next If branch$ <> "" : SetGadgetText(#GComboBranch, branch$) : EndIf + ; Status NewList rows.FileRow() LoadStatusRows(repoDir$, rows()) FillStatusList(rows()) + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) ; Boucle Repeat @@ -651,7 +867,6 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) Select ev Case #PB_Event_Gadget Select EventGadget() - Case #GButtonBrowse Protected newDir$ = PathRequester("Choisir le répertoire du dépôt", repoDir$) If newDir$ <> "" @@ -664,6 +879,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) ClearList(rows()) LoadStatusRows(repoDir$, rows()) FillStatusList(rows()) + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) EndIf Case #GRefresh @@ -671,6 +887,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) ClearList(rows()) LoadStatusRows(repoDir$, rows()) FillStatusList(rows()) + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) Case #GInit repoDir$ = GetGadgetText(#GStringRepo) @@ -678,6 +895,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) ClearList(rows()) LoadStatusRows(repoDir$, rows()) FillStatusList(rows()) + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) Case #GInclude Protected idx.i = GetGadgetState(#GListStatus) @@ -685,6 +903,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) SetGadgetItemState(#GListStatus, idx, #PB_ListIcon_Checked) ToggleIncludeAt(idx, rows()) EndIf + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) Case #GExclude idx = GetGadgetState(#GListStatus) @@ -692,16 +911,23 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) SetGadgetItemState(#GListStatus, idx, 0) ToggleIncludeAt(idx, rows()) EndIf + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) Case #GIncludeAll Protected c.i = CountGadgetItems(#GListStatus) For idx = 0 To c - 1 : SetGadgetItemState(#GListStatus, idx, #PB_ListIcon_Checked) : Next ForEach rows() : rows()\include = 1 : Next + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) Case #GExcludeAll c = CountGadgetItems(#GListStatus) For idx = 0 To c - 1 : SetGadgetItemState(#GListStatus, idx, 0) : Next ForEach rows() : rows()\include = 0 : Next + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) + + Case #GDiff + repoDir$ = GetGadgetText(#GStringRepo) + OpenDiffWindow(repoDir$, rows()) Case #GAdvanced repoDir$ = GetGadgetText(#GStringRepo) @@ -709,6 +935,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) ClearList(rows()) LoadStatusRows(repoDir$, rows()) FillStatusList(rows()) + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) Case #GSavePrefs remote$ = GetGadgetText(#GStringRemote) @@ -718,6 +945,22 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) Else MessageRequester("Préférences", "Échec d'enregistrement.", #PB_MessageRequester_Error) EndIf + 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$) + ; optionnel : refresh + ClearList(rows()) + LoadStatusRows(repoDir$, rows()) + FillStatusList(rows()) + EndIf Case #GCommit repoDir$ = GetGadgetText(#GStringRepo) @@ -737,6 +980,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) ClearList(rows()) LoadStatusRows(repoDir$, rows()) FillStatusList(rows()) + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) EndIf Case #GPush @@ -754,6 +998,7 @@ Procedure.i OpenGUI(initialDir$, prefsPath$) Case #GListStatus idx = GetGadgetState(#GListStatus) If idx >= 0 : ToggleIncludeAt(idx, rows()) : EndIf + UpdateGuide(repoDir$, rows(), GetGadgetText(#GComboBranch), GetGadgetText(#GStringRemote)) EndSelect EndSelect @@ -963,9 +1208,9 @@ Else EndIf ; IDE Options = PureBasic 6.21 (Windows - x64) -; CursorPosition = 632 -; FirstLine = 628 -; Folding = ----- +; CursorPosition = 1010 +; FirstLine = 969 +; Folding = ------ ; EnableXP ; DPIAware ; Executable = ..\PBIDE-GitTool.exe diff --git a/PureBasic_Compilation1.exe b/PureBasic_Compilation1.exe new file mode 100644 index 0000000..bfe5a97 Binary files /dev/null and b/PureBasic_Compilation1.exe differ diff --git a/git_icons_pack/git_icons_pack/test.txt b/git_icons_pack/git_icons_pack/test.txt new file mode 100644 index 0000000..e69de29