Page 1 of 1

[IDE Tool] Procedure and macro scanner

Posted: Mon May 27, 2024 8:53 am
by boddhi
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.

Image

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. :wink:

Install:
Image

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
;}

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.. :mrgreen: :wink:

[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

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 6:53 am
by Piero
Seems to me you can replace:
_*[a-z]\w*
with:
\w+

also (for "real tabs", just in case…) you can replace:
" *" (space*)
with:
\s*

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 7:08 am
by AZJIO
Piero wrote: Fri May 31, 2024 6:53 am Seems to me you can replace:
_*[a-z]\w*
with:
\w+

also (for "real tabs", just in case…) you can replace:
" *" (space*)
with:
\s*
\w+ contains a number, and the first character of the variable and procedure name must not be a number
[_a-z]\w* here is the first character other than a number, and then any character is possible and allows 1 character as a name.
\s* contains vertical characters, and between parts of a line, between a procedure and a bracket, there cannot be vertical characters, but only horizontal spaces and tabs, which means \h+, but in some cases \h*, for example, between the name of a procedure and a bracket.

Example for procedure name capture test

Code: Select all

Global x
Procedure	 Pr1(i)
	ProcedureReturn 1
EndProcedure

Procedure Pr2(i)
	ProcedureReturn 2
EndProcedure

Procedure Pr3 (i)
	ProcedureReturn 3
EndProcedure

Procedure Pr4	 (i)
	ProcedureReturn 4
EndProcedure

Procedure Pr5	(i)
	ProcedureReturn 5
EndProcedure

Global x
Debug Pr1(0)
Debug Pr2(0)
Debug Pr3(0)
Debug Pr4(0)
Debug Pr5(0)
(?i) используется если регулярное выражение вводит пользователь в поле ввода для последующего использования программой, а в коде лучше использовать константу #PB_RegularExpression_NoCase

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 7:19 am
by Piero
AZJIO wrote: Fri May 31, 2024 7:08 am \w+ contains a number, and the first character of the variable and procedure name must not be a number
[_a-z]\w* here is the first character other than a number, and then any character is possible and allows 1 character as a name.
\s* contains vertical characters, and between parts of a line, between a procedure and a bracket, there cannot be vertical characters, but only horizontal spaces and tabs, which means \h+, but in some cases \h*, for example, between the name of a procedure and a bracket.
You are right: I now remember I saw that when testing a regex for PB "words"!
Anyway it seems so strange to me that you can do stuff like:
Procedure a[tab].[tab]b(c)

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 7:22 am
by AZJIO
more

Code: Select all

Procedure	.i Pr6(i)
	ProcedureReturn 6
EndProcedure

Procedure _(i)
	ProcedureReturn 7
EndProcedure

Debug Pr6(0)
Debug _(0)
Piero wrote: Fri May 31, 2024 7:19 am Anyway it seems so strange to me that you can do stuff like:
the syntax allows this. In any case, the brevity of the recording remains the same, but the quality increases.

Code: Select all

 *( *
manipulation with two spaces, they can be combined into one \h*(

Code: Select all

(?!return)
Why is there a negation of "return" here? Logically, after “Procedure” you can have what’s in brackets (dll|cdll|c)? or a space, or a dot \., “return” is initially impossible for you.

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 7:39 am
by Piero
AZJIO wrote: Fri May 31, 2024 7:22 am the quality increases.
Being that you worked a lot with (PB) syntax, regexps etc. (THANKS!)……

Don't you think that in some cases it would be useful/faster to consider the code "syntax-errors-free" and use "less strict" regexps?
Did you ever do that for some IDE tool?

(Hope you understood my question: I prefer Spaghetti to English)

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 7:40 am
by AZJIO
more

Code: Select all

Procedure$ Pr8(i)
	ProcedureReturn "8"
EndProcedure

Debug Pr8(0)
Piero wrote: Fri May 31, 2024 7:39 am Don't you think that in some cases it would be useful/faster to consider the code "syntax-errors-free" and use "less strict" regexps?
I allowed Procedure[CDL$] although this is incorrect. I thought that the recording would look simpler.
Piero wrote: Fri May 31, 2024 7:39 am Did you ever do that for some IDE tool?
I used character-by-character search instead of regular expression, or use SyntaxHighlighting.
The only tool where I had to modify the regular expression is "FindAllReferences".
This is the second time I say the same thing

And I understood why the first character cannot be a number: to easily distinguish the multiplication sign from the pointer, for example *5

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 8:25 am
by Piero
AZJIO wrote: Fri May 31, 2024 7:40 am I thought that the recording would look simpler.
Recording? (I'm kidding; I understand you!)

I made a fuzzy autocomplete for Mac (you know how much I suffer because you don't seem to have a Mac!) and I didn't waste too much time with regexps (search/filter speed is very good, so I don't need to "check for perfect syntax" to extract procedures in theory, and I'm also waiting for the IDE to work better to eventually improve it)… anyway I think that's a good case where you can "relax" the regexps… we will see
(for now I just posted examples to show how you can customize your fuzzy search results)

Pizznoffskaya! :)

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 1:02 pm
by boddhi
AZJIO wrote: \w+ contains a number, and the first character of the variable and procedure name must not be a number
[_a-z]\w* here is the first character other than a number [...]
[_a-z] isn't correct too because we can have names with several underscores before, such as : Procedure __X().
It's why I wrote _* before [a-z] :wink:

Re: [IDE Tool] Procedure and macro scanner

Posted: Fri May 31, 2024 1:14 pm
by AZJIO
boddhi wrote: Fri May 31, 2024 1:02 pm [_a-z] isn't correct too because we can have names with several underscores before, such as : Procedure __X().
It's why I wrote _* before [a-z] :wink:
\w = [_a-zA-Z\d] (screenshot)
[_a-z]\w* - supports double underlining, and even tenfold underlining __
_*a*b*c*d*e*etc - don’t do that
_*a*b*c*d*e*etc = \w* = [_a-zA-Z0-9]*

Regular expression reference

[IDE Tool] Procedure and macro scanner

Posted: Sat Jul 27, 2024 11:48 pm
by boddhi
Two small new features:
  • Left double-click on ListIcons places the cursor on the corresponding line if PB is open.
  • Sticky mode on/off

Re: [IDE Tool] Procedure and macro scanner

Posted: Sun Jul 28, 2024 11:41 am
by Sergey
Useful tool, thanks for sharing, boddhi
I only added one line and if it does not sticky the tool window closes after clicking any ListIcon

Code: Select all

			Case #PB_EventType_LeftDoubleClick
				Select NoGadget
				Case #GAD_FP_LS_PROCEDURES,#GAD_FP_LS_DETAIL:Pc_DeplacementDestination(NoGadget)
				EndSelect
				
				If GetGadgetData(#GAD_FP_BT_EPINGLER) = 0: End: EndIf; <<< this line
			EndSelect
		Case #PB_Event_CloseWindow
			End

Re: [IDE Tool] Procedure and macro scanner

Posted: Mon Jul 29, 2024 1:53 am
by boddhi
Sergey wrote: I only added one line and if it does not sticky the tool window closes after clicking any ListIcon
Why not... It's not a bad idea :) :wink:

Re: [IDE Tool] Procedure and macro scanner

Posted: Tue Jul 30, 2024 5:35 pm
by Sergey
Hi, boddhi
Some new tests with tool

First test:

Code: Select all

Procedure a()
EndProcedure
a()
No Procedure Or Macro found!

Code: Select all

; first line, maybe empty
Procedure a()
EndProcedure
a()
OK

Second test:

Code: Select all

; first line, maybe empty
Procedure b()	
EndProcedure

Procedure a()
	b(); <<< don't show this procedure's call
EndProcedure
a()
And request to replace word "procedure" and "macro" with squared image "P" and "M" ;-)