[IDE Tool] Procedure and macro scanner
Posted: Mon May 27, 2024 8:53 am
A small IDE tool that lists the procedures and macros in the current source code.
It displays their position in the code, the number of times they are called up and the lines where they appear in the code.
Those that are not will appear in red in the list on the left.

Combining the use of RegEx and string manipulation, I hope I've covered most cases.
The only limitation is that (X)include files are not taken into consideration.
Sorry if the variables and procedure names are in French, the language in which it was originally written, but it is localized and some comments have been added.
The code is cross-platform, but some aesthetic improvements may be needed on MacOs and Linux (See all CompilerIf #PB_Compiler_OS).
If you make your own corrections, feel free to share.
Install:
PS: Please don't comment on how I refer to objects created with Dialog lib, I know it's not the most orthodox way but I find it less complicated than with DialogGadget(), etc..

[EDIT] : RegEx optimzations after AZJIO's guidance (no change in results from original code)
[EDIT 07/28/24] : Sticky mode & cursor moves on corresponding lines
It displays their position in the code, the number of times they are called up and the lines where they appear in the code.
Those that are not will appear in red in the list on the left.

Combining the use of RegEx and string manipulation, I hope I've covered most cases.
The only limitation is that (X)include files are not taken into consideration.
Sorry if the variables and procedure names are in French, the language in which it was originally written, but it is localized and some comments have been added.
The code is cross-platform, but some aesthetic improvements may be needed on MacOs and Linux (See all CompilerIf #PB_Compiler_OS).
If you make your own corrections, feel free to share.

Install:

Code: Select all
EnableExplicit
;#LANGUE=0 ; Français
#LANGUE=1 ; English
; ╔═══════════════════════════════════════════════════════════════════════════════════════╗
; ║ PLUGINS - STRUCTURES - ENUMERATIONS - CONSTANTES - MACROS - MAPS - VARIABLES GLOBALES ║
; ╚═══════════════════════════════════════════════════════════════════════════════════════╝
;{ ════ PLUGINS ════
;- ════ PLUGINS ════
UsePNGImageDecoder()
;}
;{ ════ STRUCTURES ════
;- ════ STRUCTURES ════
Structure APPEL ;{
NoLigne.l ; Line number in code
IndexListe.l ; List index of LignesCode()
EndStructure ;}
Structure NOMPOSITION ;{
Nom.s ; Name
NoLigne.l ; Line number in code
Type.a ; Type (1=Procedure or 2=macro)
EndStructure ;}
Structure DETAIL Extends NOMPOSITION ;{
NomTri.s ; Order name
List NoLignes.APPEL() ; Line numbers in code
EndStructure ;}
;}
;{ ════ ENUMERATIONS ════
;- ════ ENUMERATIONS ════
Runtime Enumeration Fenetres ;{ Window numbers
#FEN_PRINCIPALE
EndEnumeration ;}
Runtime Enumeration Gadgets ;{ Gadget numbers
#GAD_FP_SEP_SEPARATEUR
#GAD_FP_LS_PROCEDURES
#GAD_FP_CP_NOMPROCEDURE
#GAD_FP_BT_EPINGLER
#GAD_FP_LIB_POSITION
#GAD_FP_CP_POSITION
#GAD_FP_LIB_NBOCCURENCES
#GAD_FP_CP_NBOCCURENCES
#GAD_FP_LS_DETAIL
EndEnumeration ;}
Runtime Enumeration MenusRaccourcis 50 ;{ Menus & Hotkeys
#RACCOURCI_QUITTER ; Exit (End)
#RACCOURCI_RAFFRAICHIER ; Refresh
EndEnumeration ;}
Enumeration XML ;{ XML tree
#ARBRE_XML
EndEnumeration ;}
Enumeration DialoguesXML ;{ XML dialogs
#XML_FENPRINCIPALE
EndEnumeration ;}
Enumeration Images ;{ Gadget images
#IMG_BTEPINGLER
#IMG_BTEPINGLERAPPUI
EndEnumeration ;}
Enumeration RegEx 1 ;{ RegEx numbers
#EXPREG_PROCEDURE
#EXPREG_MACRO
#EXPREG_NOMPROCEDURE
EndEnumeration ;}
;}
;{ ════ CONSTANTES ════
;- ════ CONSTANTES ════
#REGEX_PROCEDURE="(?i)procedure(?!return)(dll|cdll|c)? *( *\. *[abcdfilqsuw])? *_*[a-z]\w* *\(.*\)"
#REGEX_MACRO="(?i)macro *_*[a-z]{1}\w* *\(.*\)"
#REGEX_NOMPROCEDURE="(?i)( |[:@=&!~<>\+\-\*\/\|\(]) *%s *\("
;}
;{ ════ MAPS ════
;- ════ MAPS ════
Global NewMap Textes.s()
CompilerSelect #LANGUE
CompilerCase 0 ; Français
Textes("TITRE")="Liste Procedures & Macros"
Textes("GAD-NOM")="Nom"
Textes("GAD-NBOCCURENCES")="Nb occurences : "
Textes("GAD-LIGNE")="Ligne : "
Textes("COL-LIGNE")="Ligne"
Textes("COL-CODE")="Code"
Textes("MSG-RAFFRAICHIR")="(F5 pour raffraîchir)"
Textes("MSG-ERREURFICHIER")="Aucun nom de fichier passé en paramètre !"
Textes("MSG-ERREURACCESFICHIER")="Échec lors de l'accès au fichier !"
Textes("MSG-ERREURREGEX")="Échec création Regex!"
Textes("MSG-AUCUNEPROCEDURE")="Aucune procédure ni macro trouvées !"
CompilerCase 1 ; English
Textes("TITRE")="Procedure & Macro list"
Textes("GAD-NOM")="Name"
Textes("GAD-NBOCCURENCES")="N# occurences: "
Textes("GAD-LIGNE")="Line: "
Textes("COL-LIGNE")="Line"
Textes("COL-CODE")="Code"
Textes("MSG-RAFFRAICHIR")="(F5 to refresh)"
Textes("MSG-ERREURFICHIER")="No file name passed as parameter!"
Textes("MSG-ERREURACCESFICHIER")="Failed to access file!"
Textes("MSG-ERREURREGEX")="Regex creation failed!"
Textes("MSG-AUCUNEPROCEDURE")="No Procedure Or Macro found!"
CompilerDefault
CompilerError "La constante #LANGUE n'est pas valide (The #LANGUE constant is Not valid!)"
CompilerEndSelect
;}
;{ ════ LISTES ════
;- ════ LISTES ════
Global NewList ProceduresMacros.DETAIL() ; Procedure and macro list
Global NewList LignesCode.NOMPOSITION() ; Code lines
;}
;{ ════ VARIABLES GLOBALES ════
;- ════ VARIABLES GLOBALES ════
Global.i IDPB,IDScintilla
Global.s FichierSource ; Source file
;}
; ╔═════════════════════════════════════════╗
; ║ DECLARATIONS - FICHIERS INCLUS - IMAGES ║
; ╚═════════════════════════════════════════╝
;{ ════ DECLARATIONS ════
;- ════ DECLARATIONS ════
;}
;{ ════ FICHIERS INCLUS ════
;- ════ FICHIERS INCLUS ════
;}
;{ ════ IMAGES ════
;- ════ IMAGES ════
;}
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
; ╔════════════╗
; ║ PROCEDURES ║
; ╚════════════╝
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Procedure Pc_Demarrage() ; Start procedure
If CountProgramParameters()<>1 ; MT
MessageRequester(Textes("TITRE"),Textes("MSG-ERREURFICHIER"),#PB_MessageRequester_Error)
End
EndIf
FichierSource=ProgramParameter()
If Not CreateRegularExpression(#EXPREG_PROCEDURE,#REGEX_PROCEDURE) Or Not CreateRegularExpression(#EXPREG_MACRO,#REGEX_MACRO)
MessageRequester(Textes("TITRE"),Textes("MSG-ERREURREGEX"),#PB_MessageRequester_Error)
End
EndIf
IDPB=Val(GetEnvironmentVariable("PB_TOOL_MainWindow"))
IDScintilla=Val(GetEnvironmentVariable("PB_TOOL_Scintilla"))
EndProcedure
Procedure Pc_RechercheProceduresMacros() ; Procedure and macro search
Protected.l NoLigne ; Line number
Protected.l Position ; String position or boolean result
Protected.s ChaineSource ; Source string
Protected.s ChaineRecherchee ; Search string
If ReadFile(0,FichierSource,#PB_File_SharedRead|#PB_UTF8)=0
Debug GetLastError_()
MessageRequester(Textes("TITRE"),Textes("MSG-ERREURACCESFICHIER"),#PB_MessageRequester_Error)
End
EndIf
While Not Eof(0)
ChaineSource=Trim(ReadString(0,#PB_UTF8)):NoLigne+1
If ChaineSource<>""
If Left(ChaineSource,1)<>";"
AddElement(LignesCode())
With LignesCode()
\Nom=ChaineSource
\NoLigne=NoLigne
EndWith
; Recherche procédures
If ExamineRegularExpression(#EXPREG_PROCEDURE,ChaineSource)
While NextRegularExpressionMatch(#EXPREG_PROCEDURE)
Position=RegularExpressionMatchPosition(#EXPREG_PROCEDURE)
If Position=1
AddElement(ProceduresMacros())
With ProceduresMacros()
\Type=1
\Nom=RegularExpressionMatchString(#EXPREG_PROCEDURE)
\NoLigne=NoLigne
EndWith
EndIf
Wend
EndIf
; Recherche macros
If ExamineRegularExpression(#EXPREG_MACRO,ChaineSource)
While NextRegularExpressionMatch(#EXPREG_MACRO)
Position=RegularExpressionMatchPosition(#EXPREG_MACRO)
If Position=1
AddElement(ProceduresMacros())
With ProceduresMacros()
\Type=2
\Nom=RegularExpressionMatchString(#EXPREG_MACRO)
\NoLigne=NoLigne
EndWith
EndIf
Wend
EndIf
EndIf
EndIf
Wend
CloseFile(0)
If ListSize(ProceduresMacros())
ForEach ProceduresMacros()
With ProceduresMacros()
ChaineSource=Trim(StringField(\Nom,1,"("))
ChaineSource=Trim(StringField(ChaineSource,CountString(ChaineSource," ")+1," "))
\NomTri=ChaineSource
If IsRegularExpression(#EXPREG_NOMPROCEDURE):FreeRegularExpression(#EXPREG_NOMPROCEDURE):EndIf
If CreateRegularExpression(#EXPREG_NOMPROCEDURE,ReplaceString(#REGEX_NOMPROCEDURE,"%s",ChaineSource))
ForEach LignesCode()
If LignesCode()\NoLigne<>\NoLigne
Position=FindString(" "+LignesCode()\Nom,ChaineSource)
If Position
Position=Bool(MatchRegularExpression(#EXPREG_NOMPROCEDURE," "+LignesCode()\Nom)<>0)
If Position
AddElement(\NoLignes())
\NoLignes()\NoLigne=LignesCode()\NoLigne
\NoLignes()\IndexListe=ListIndex(LignesCode())
EndIf
EndIf
EndIf
Next
EndIf
EndWith
Next
SortStructuredList(ProceduresMacros(),#PB_Sort_Ascending|#PB_Sort_NoCase,OffsetOf(DETAIL\NomTri),TypeOf(DETAIL\NomTri))
SortStructuredList(ProceduresMacros(),#PB_Sort_Ascending|#PB_Sort_NoCase,OffsetOf(DETAIL\Type),TypeOf(DETAIL\Type))
Else
MessageRequester(Textes("TITRE"),Textes("MSG-AUCUNEPROCEDURE"),#PB_MessageRequester_Error)
End
EndIf
EndProcedure
Procedure Pc_AffichageProcedures() ; Procedure list filling
Protected.l NoItem
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SendMessage_(GadgetID(#GAD_FP_LS_PROCEDURES),#WM_SETREDRAW,#False,0)
CompilerEndIf
ClearGadgetItems(#GAD_FP_LS_PROCEDURES)
ForEach ProceduresMacros()
AddGadgetItem(#GAD_FP_LS_PROCEDURES,-1,ProceduresMacros()\Nom)
If ListSize(ProceduresMacros()\NoLignes())=0
SetGadgetItemColor(#GAD_FP_LS_PROCEDURES,NoItem,#PB_Gadget_FrontColor,#Red)
EndIf
NoItem+1
Next
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SendMessage_(GadgetID(#GAD_FP_LS_PROCEDURES),#LVM_SETCOLUMNWIDTH,0,#LVSCW_AUTOSIZE)
SendMessage_(GadgetID(#GAD_FP_LS_PROCEDURES),#WM_SETREDRAW,#True,0)
CompilerEndIf
EndProcedure
Procedure Pc_AffichageDetail() ; Data list filling
Protected.l NoItem=GetGadgetState(#GAD_FP_LS_PROCEDURES) ; Procedure list item number
Protected.s NoLigne ; Line number in code
Protected.s NbOccurrences ; Number of calls in code
Protected.s Nom ; Procedure/Macro name
CompilerIf #PB_Compiler_Version<610
Protected.LVCOLUMN LVC
CompilerEndIf
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#WM_SETREDRAW,#False,0)
CompilerEndIf
RemoveGadgetColumn(#GAD_FP_LS_DETAIL,#PB_All)
If NoItem>=0
SelectElement(ProceduresMacros(),NoItem)
With ProceduresMacros()
Nom=\Nom
NoLigne=FormatNumber(\NoLigne,0,""," ")
NbOccurrences=FormatNumber(ListSize(\NoLignes()),0,""," ")
If ListSize(\NoLignes())
AddGadgetColumn(#GAD_FP_LS_DETAIL,0,Textes("COL-LIGNE"),80)
AddGadgetColumn(#GAD_FP_LS_DETAIL,1,Textes("COL-CODE"),200)
CompilerIf #PB_Compiler_Version<610
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
LVC\mask=#LVCF_FMT
LVC\fmt=#LVCFMT_RIGHT
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#LVM_SETCOLUMN,0,@LVC)
CompilerEndIf
CompilerElse
SetGadgetItemAttribute(#GAD_FP_LS_DETAIL,#PB_ListIcon_Right,#PB_ListIcon_ColumnAlignment,0)
CompilerEndIf
EndIf
ForEach \NoLignes()
SelectElement(LignesCode(),\NoLignes()\IndexListe)
AddGadgetItem(#GAD_FP_LS_DETAIL,-1,FormatNumber(\NoLignes()\NoLigne,0,""," ")+Chr(10)+LignesCode()\Nom)
Next
EndWith
EndIf
SetGadgetText(#GAD_FP_CP_NOMPROCEDURE,Nom)
SetGadgetText(#GAD_FP_CP_POSITION,NoLigne)
SetGadgetText(#GAD_FP_CP_NBOCCURENCES,NbOccurrences)
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#LVM_SETCOLUMNWIDTH,0,#LVSCW_AUTOSIZE)
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#LVM_SETCOLUMNWIDTH,1,#LVSCW_AUTOSIZE)
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#WM_SETREDRAW,#True,0)
CompilerEndIf
EndProcedure
Procedure Pc_DeplacementDestination(ArgNoGadget.u) ; Cursor positionning on procedure or call procedure
Protected.l NoItem=GetGadgetState(ArgNoGadget) ; Item of used ListIcon
Protected.l NoLigne ; Line number in code
If NoItem>=0 And IDPB And IDScintilla
Select ArgNoGadget
Case #GAD_FP_LS_PROCEDURES:SelectElement(ProceduresMacros(),NoItem):NoLigne=ProceduresMacros()\NoLigne
Case #GAD_FP_LS_DETAIL:NoLigne=Val(ReplaceString(GetGadgetItemText(ArgNoGadget,NoItem,0)," ",""))
EndSelect
SendMessage_(IDScintilla,#SCI_GOTOLINE,NoLigne-1,0)
SendMessage_(IDScintilla,#SCI_ENSUREVISIBLE,NoLigne-1,0)
SetForegroundWindow_(IDPB)
SetActiveWindow_(IDPB)
EndIf
EndProcedure
Procedure Pc_RaffraichissementListe() ; Procedure list refresh
ClearList(ProceduresMacros())
ClearList(LignesCode())
SetGadgetText(#GAD_FP_CP_NOMPROCEDURE,"")
SetGadgetText(#GAD_FP_CP_POSITION,"")
SetGadgetText(#GAD_FP_CP_NBOCCURENCES,"")
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#WM_SETREDRAW,#False,0)
CompilerEndIf
RemoveGadgetColumn(#GAD_FP_LS_DETAIL,#PB_All)
Pc_RechercheProceduresMacros()
Pc_AffichageProcedures()
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SendMessage_(GadgetID(#GAD_FP_LS_DETAIL),#WM_SETREDRAW,#True,0)
CompilerEndIf
EndProcedure
; ╔══════════════╗
; ║ FENETRES XML ║
; ╚══════════════╝
Procedure.a Fc_Fenetres_OuvertureDialogueXML(ArgArbreXML.u,ArgDialogueXML.u,ArgChaineXML.s,ArgNomFenetre.s,ArgIdFenetreParente.i=0) ; XML handling
Protected.i NoDialogue
Protected.a TypeErreur
Protected.s TitreMSG=Textes("TITRE"),MsgErreur
If ArgChaineXML
If ParseXML(ArgArbreXML,ArgChaineXML)
If XMLStatus(ArgArbreXML)=#PB_XML_Success
If CreateDialog(ArgDialogueXML)
If ArgIdFenetreParente<>0
NoDialogue=OpenXMLDialog(ArgDialogueXML,ArgArbreXML,ArgNomFenetre,0,0,0,0,ArgIdFenetreParente)
Else
NoDialogue=OpenXMLDialog(ArgDialogueXML,ArgArbreXML,ArgNomFenetre,0,0,0,0)
EndIf
If NoDialogue
FreeXML(ArgArbreXML)
ProcedureReturn #True
Else
TypeErreur=3
EndIf
FreeDialog(ArgDialogueXML)
Else
TypeErreur=2
EndIf
FreeXML(ArgArbreXML)
Else
TypeErreur=1
MsgErreur="Erreur durant l'interprétation du dialogue XML !"
EndIf
Else
TypeErreur=1
MsgErreur="Erreur durant la lecture des données du dialogue XML !"
EndIf
EndIf
Select TypeErreur
Case 1:MsgErreur+"\n\n No erreur : "+XMLStatus(ArgArbreXML)+" - "+XMLError(ArgArbreXML)+"\n Ligne : "+Str(XMLErrorLine(ArgArbreXML))+" - Colonne : "+Str(XMLErrorPosition(ArgArbreXML))
Case 2:MsgErreur="Erreur durant la création de la fenêtre de dialogue !"
Case 3:MsgErreur="Erreur durant l'ouverture de la fenêtre de dialogue !\n\nErreur : "+DialogError(ArgDialogueXML)
EndSelect
MessageRequester(TitreMSG,UnescapeString(MsgErreur),#PB_MessageRequester_Error)
EndProcedure
; ╔════════════════════╗
; ║ FENETRE PRINCIPALE ║
; ╚════════════════════╝
Procedure Pc_Epinglage_Fenetre() ; Sticky mode On/off
Protected.a Mode=GetGadgetData(#GAD_FP_BT_EPINGLER)!1
SetGadgetAttribute(#GAD_FP_BT_EPINGLER,#PB_Button_Image,ImageID(#IMG_BTEPINGLER+Mode))
StickyWindow(#FEN_PRINCIPALE,Mode)
SetGadgetData(#GAD_FP_BT_EPINGLER,Mode)
EndProcedure
Procedure Pc_FenPrincipale_GestionEvenements() ; Event handling
Debug #PB_Compiler_Procedure,5
Define.l Evenmt,EvenmtMenu,TypeEvenmt,NoGadget
Repeat
Evenmt=WaitWindowEvent()
TypeEvenmt=EventType()
Select Evenmt
Case #PB_Event_Gadget
NoGadget=EventGadget()
Select TypeEvenmt
Case #PB_EventType_Change
Select NoGadget
Case #GAD_FP_LS_PROCEDURES:Pc_AffichageDetail()
EndSelect
Case #PB_EventType_LeftClick
Select NoGadget
Case #GAD_FP_BT_EPINGLER:Pc_Epinglage_Fenetre()
EndSelect
Case #PB_EventType_LeftDoubleClick
Select NoGadget
Case #GAD_FP_LS_PROCEDURES,#GAD_FP_LS_DETAIL:Pc_DeplacementDestination(NoGadget)
EndSelect
EndSelect
Case #PB_Event_CloseWindow
End
Case #PB_Event_Menu
EvenmtMenu=EventMenu()
Select EvenmtMenu
Case #RACCOURCI_RAFFRAICHIER:Pc_RaffraichissementListe()
Case #RACCOURCI_QUITTER:End
EndSelect
EndSelect
ForEver
EndProcedure
Procedure Pc_FenPrincipale_Affichage() ; Display window
Protected.a ValeurRetour
Protected.s ChaineXML
If ListSize(ProceduresMacros())=0:End:EndIf
ChaineXML.s="<?xml version='1.0' encoding='UTF-16'?>"+Chr(10)+ ;{
"<dialogs>"+Chr(10)+
" <window id='#FEN_PRINCIPALE' name='FEN_PRINCIPALE' text='"+EscapeString(Textes("TITRE"),#PB_String_EscapeXML)+" "+Textes("MSG-RAFFRAICHIR")+"' xpos='0' ypos='0' minwidth='662' minheight='140' width='600' height='400' margin='12' flags='#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_Invisible|#PB_Window_ScreenCentered'>"+Chr(10)+
" <vbox>"+Chr(10)+
" <splitter id='#GAD_FP_SEP_SEPARATEUR' name='GAD_FP_SEP_SEPARATEUR' flags='#PB_Splitter_Vertical|#PB_Splitter_Separator|#PB_Splitter_FirstFixed' secondmin='400' firstmin='320'>"+Chr(10)+
" <listicon id='#GAD_FP_LS_PROCEDURES' name='GAD_FP_LS_PROCEDURES' text='"+Textes("GAD-NOM")+"' flags='#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection'/>"+Chr(10)+
" <hbox expand='item:2' spacing='8'>"+Chr(10)+
" <empty width='4'/>"+Chr(10)+
" <vbox expand='item:3' spacing='8'>"+Chr(10)+
" <hbox expand='item:1' align='' spacing='4'>"+Chr(10)+
" <string id='#GAD_FP_CP_NOMPROCEDURE' name='GAD_FP_CP_NOMPROCEDURE' flags='#PB_String_ReadOnly'/>"+Chr(10)+
" <buttonimage id='#GAD_FP_BT_EPINGLER' name='GAD_FP_BT_EPINGLER' height='24'/>"+Chr(10)+
" </hbox>"+Chr(10)+
" <hbox expand='no' align='' spacing='4'>"+Chr(10)+
" <vbox expand='no' align='center'>"+Chr(10)+
" <text id='#GAD_FP_LIB_POSITION' name='GAD_FP_LIB_POSITION' text='"+Textes("GAD-LIGNE")+"'/> "+Chr(10)+
" </vbox>"+Chr(10)+
" <string id='#GAD_FP_CP_POSITION' name='GAD_FP_CP_POSITION' width='72' flags='#PB_String_ReadOnly'/>"+Chr(10)+
" <empty width='24'/>"+Chr(10)+
" <vbox expand='no' align='center'>"+Chr(10)+
" <text id='#GAD_FP_LIB_NBOCCURENCES' name='GAD_FP_LIB_NBOCCURENCES' text='"+Textes("GAD-NBOCCURENCES")+"'/> "+Chr(10)+
" </vbox>"+Chr(10)+
" <string id='#GAD_FP_CP_NBOCCURENCES' name='GAD_FP_CP_NBOCCURENCES' width='72' flags='#PB_String_ReadOnly'/> "+Chr(10)+
" </hbox>"+Chr(10)+
" <listicon id='#GAD_FP_LS_DETAIL' name='GAD_FP_LS_DETAIL' flags='#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection'/> "+Chr(10)+
" </vbox>"+Chr(10)+
" </hbox> "+Chr(10)+
" </splitter> "+Chr(10)+
" </vbox> "+Chr(10)+
" </window> "+Chr(10)+
"</dialogs>" ;}
ValeurRetour=Fc_Fenetres_OuvertureDialogueXML(#ARBRE_XML,#XML_FENPRINCIPALE,ChaineXML,"FEN_PRINCIPALE")
If ValeurRetour
CatchImage(#IMG_BTEPINGLER,?ImageBtEpingler_Debut,?ImageBtEpingler_Fin-?ImageBtEpingler_Debut)
CatchImage(#IMG_BTEPINGLERAPPUI,?ImageBtEpinglerAppui_Debut,?ImageBtEpinglerAppui_Fin-?ImageBtEpinglerAppui_Debut)
SetGadgetAttribute(#GAD_FP_BT_EPINGLER,#PB_Button_Image,ImageID(#IMG_BTEPINGLER))
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
SetWindowLongPtr_(GadgetID(#GAD_FP_CP_POSITION),#GWL_STYLE,GetWindowLongPtr_(GadgetID(#GAD_FP_CP_POSITION),#GWL_STYLE)|#SS_RIGHT)
SetWindowLongPtr_(GadgetID(#GAD_FP_CP_NBOCCURENCES),#GWL_STYLE,GetWindowLongPtr_(GadgetID(#GAD_FP_CP_NBOCCURENCES),#GWL_STYLE)|#SS_RIGHT)
CompilerEndIf
RemoveGadgetColumn(#GAD_FP_LS_DETAIL,0)
Pc_AffichageProcedures()
HideWindow(#FEN_PRINCIPALE,#False)
AddKeyboardShortcut(#FEN_PRINCIPALE,#PB_Shortcut_Escape,#RACCOURCI_QUITTER)
AddKeyboardShortcut(#FEN_PRINCIPALE,#PB_Shortcut_F5,#RACCOURCI_RAFFRAICHIER)
Pc_FenPrincipale_GestionEvenements()
EndIf
EndProcedure
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
; ╔══════════════════╗
; ║ MODULE PRINCIPAL ║
; ╚══════════════════╝
Pc_Demarrage()
Pc_RechercheProceduresMacros()
Pc_FenPrincipale_Affichage()
End
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
; ╔═════════════════╗
; ║ SECTION DONNEES ║
; ╚═════════════════╝
DataSection ;{ Images
ImageBtEpingler_Debut: ;{ Fichier : D:\FICHIERS\Fichiers PureBasic\GestionAlbumsAudio\Ressources\Images\Divers\Noticeboardpin-Inverse-SansOmbre.png
Data.q $0A1A0A0D474E5089,$524448490D000000,$140000000D000000,$B732560000000608,$474B62060000002F,$A0FF00FF00FF0044,$700900000093A7BD,$00D70D0000735948
Data.q $789B284201D70D00,$544144490B020000,$60D36BCF9295CB38,$B523FB7DE49FC718,$0745B63319525A59,$42287983275D3193,$6303FE08BD115329,$DB0E4865EB060C20
Data.q $8084AADE24F0E869,$97A8769D8583D2B7,$10C1C1DB9D5AED82,$28CD1CDD3B3A36ED,$D2C5483C4D37926D,$EFBE1CFBE9CFDB5A,$BCC00014BCFBE5F3,$A69887A10A617FDF
Data.q $D52A593175D1BF2F,$725C1F060A580BA1,$60426571451B6438,$9ABB3700932734C2,$AFB934C555B66D06,$0C9A618318B03AF5,$5545F3D750FA07FC,$0818655C070E8335
Data.q $099BBE041444DDB9,$F228D1A19F9D3A0D,$D3473E1E31781B36,$B5D9649E9E308717,$F14D513276A94575,$59AD72E53FB8103C,$89E699A01A34A000,$D99ABDA691EAA113
Data.q $455829A9B2D27FDF,$C59618CCF1E232F9,$A29397211B810871,$70E618D7238C5E3C,$E29A229FE3ECECFD,$458E28A761302046,$0423D80C3539DFBF,$A40019601501084E
Data.q $068458774210D336,$D1F50AAA4F82CB74,$FABB7B601A69A051,$A61846F18ED99093,$D06AD7DE8FEDD826,$C7780ACAC8831B18,$772F7BCDCD8D8DC7,$E5AB14DE54B6DF77
Data.q $000E9EEAD57787F2,$C58B15BEB676763F,$6D231716B7C79E01,$ACE98C32D87BFA77,$74BD707076795EAA,$FCF3CA7210977C7C,$492457A1E78A28BC,$5C9932560A142D9A
Data.q $93267252A5487E82,$3AF18E9E62C58A39,$1EFB4D3417A74E91,$F917FBDADAE7870E,$BF7E1B42850B5E7C,$E5CB9D7BE7CFA9FF,$44B9F1E3C6639ED4,$2C82F5EFE5B8F122
Data.q $8FDD12ECD9B22FCB,$1B70820B2CA952A9,$7302FF0E8D1A25FA,$00A85F65D4EAC18A,$AE444E4549000000
Data.b $42,$60,$82
ImageBtEpingler_Fin: ;}
ImageBtEpinglerAppui_Debut: ;{ Fichier : D:\FICHIERS\Fichiers PureBasic\GestionAlbumsAudio\Ressources\Images\Divers\Noticeboardpin-Vert-Inverse-SansOmbre.png
Data.q $0A1A0A0D474E5089,$524448490D000000,$140000000D000000,$B732560000000608,$474B62060000002F,$A0FF00FF00FF0044,$700900000093A7BD,$00D70D0000735948
Data.q $789B284201D70D00,$5441444902020000,$6112884D9295CB38,$DDC74751F9DF8600,$60DA4B68FF114651,$A59160927B1160F7,$829631D4142CBA88,$D5B6F761E16F2885
Data.q $E2044422120F60B5,$3314D23176CF6121,$BA92CEDA15B258E8,$4949D33A3F3A38B6,$BE1E1DFBD39F4CD6,$72DC700008FBF797,$E0CE1403730F1878,$D0098BB55CD5A21D
Data.q $4024C5C675EE07EE,$174ACE90BA8E9381,$7A6EC99289A5C391,$060B61F7EE6474AA,$C81FF19B27A900C6,$8E35D429A16EAFEE,$53B4E3878A7EC1B7,$D1944927E39F5B9D
Data.q $B1CCDF7514517C47,$999F28628074ADA0,$D4A75EF48BD1AF37,$75DD704188938F69,$BF40E83DD917675D,$B440C275EAAE87D3,$C7B567B517BD477B,$562B1018820D3723
Data.q $29628E09D0877AD6,$B28DA48D21690C90,$28FC4D5305A6AB52,$9F739B820C438796,$8000485A47148CA7,$16D88638DC7056D2,$8870F88036FA2BA1,$5E721690AFA76DA1
Data.q $F927C268FE6869EB,$4D6DFA3E84BF34B0,$0ED81763D6C636D4,$CF2C05DF09EF2369,$2B3C562EE6F7632F,$FA9BFAB5D2FBD2BD,$41F5E0E107C991DB,$E51935937C2AF849
Data.q $7277D95AA553F95A,$7789EACEF6E77A4E,$C67C35E55720FBFA,$71B3F1A17A95F539,$A3F7F3CF26D55555,$37C78F12D313A8D1,$30B6A54A9EA2C58A,$8566CD913A74E90B
Data.q $991C6F5B1B622448,$50A187CB2CA1E64C,$2850A2FF7AC4F368,$7FEFDF83F060C1C8,$6979F3E65E3870E2,$4C99336C58B19AEA,$244890D37BF91A3E,$A916722DB972E79E
Data.q $98CBDEBD7B6D6AD5,$0ACB03F81C387095,$000043C8BF0DC0C0,$42AE444E45490000
Data.b $60,$82
ImageBtEpinglerAppui_Fin: ;}
EndDataSection
;}


[EDIT] : RegEx optimzations after AZJIO's guidance (no change in results from original code)
[EDIT 07/28/24] : Sticky mode & cursor moves on corresponding lines