Programme d'indentation -> Nouvelle version

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
ZapMan
Messages : 460
Inscription : ven. 13/févr./2004 23:14
Localisation : France
Contact :

Programme d'indentation -> Nouvelle version

Message par ZapMan »

J'ai modifié le programme absolument génial de Brossden pour corriger tout ce qui clochait chez moi. Quelques rappels et explications :
- C'est un programme d'indentation automatique qui permet de remettre les espaces en début de ligne pour bien aligner le code
- On peut l'installer dans l'éditeur de PureBasic ou dans JapPB pour l'avoir sous la main et le déclancher n'importe quand
- Si on fait une sélection de code avant de le lancer, l'indentation ne se fait que sur la sélection, sinon elle se fait sur la totalité du code

Petites notes pour ceux qui ont essayé la version précédente :
- Il fonctionne désormais sur un code trés long (jusqu'à un million de caractères)
- Le presse-papier est conservé (dans la précédente version, son contenu était perdu)
- Il gère désormais parfaitement TOUS les codes comportant plusieurs instructions par ligne comme :

Code : Tout sélectionner

For i=1 to 10 : blabla () : Next
(dans la version précédente, seuls : Until et : EndIf était gérés)

Voilà :

Code : Tout sélectionner


;*********************************************************************************************
;* Il est Possible de passer en Paramètre le nombre de Blanc correspondant à l'indentation ! *
;*            La valeur par défaut (#Tab) est de "2" mais ne demande qu'à être modifiée      *
;* Si #IndentComment = 1, les commentaires sont indentés, sinon ils restent alignés à gauche *
;* Programme écrit par Brossden - Complété par Zapman avec les astuces de tout le monde      *
;*********************************************************************************************

Global ProgText.s,mc.s
#Tab=2
#IndentComment=1
#RC1 = Chr(13)+Chr(10)
#RC2 = ":"
#MaxSize=1000000
Blanc=0
Dejacom = 0
While getkeystate_(#VK_LMENU)<0 ; si on appelé ce programme à l'aide d'une touche
  Delay(10)                      ; de fonction, on attend que l'utilisateur relache
Wend                            ; la touche

;************************************************************
;* Le truc de Fred pour augmenter la taille du buffer texte *
;*   et éviter les plantage quand on manipule des grandes   *
;*    chaines de caractères.                                *
;************************************************************

Procedure SetStringManipulationBufferSize(Bytes)
  PBStringBase.l = 0
  PBMemoryBase.l = 0
  !MOV eax, dword [PB_StringBase]
  !MOV [esp+4],eax
  !MOV eax, dword [PB_MemoryBase]
  !MOV [esp+8],eax
  HeapReAlloc_(PBMemoryBase, #GMEM_ZEROINIT, PBStringBase, Bytes)
  !MOV dword [_PB_StringBase],eax
EndProcedure

; Set the buffer size for all strings to 1 MB.

SetStringManipulationBufferSize(#MaxSize)

;************************************************************
;* La procédure qui permet de savoir si le caractère que    *
;*   l'on vient de trouver ne se trouve pas inclus dans une *
;*    chaines entre guillemets                              *
;************************************************************

Procedure PasEntreGuillemets (Pos,Jusqu_a)
  cr.s=Mid(ProgText,Pos,1) ; cr est le caractere recherché (situé à la position "Pos")
  If pos<Jusqu_a And pos: cont=1 : Else : cont=0 : EndIf    ; on regarde si on n'a pas ":" avant le retour chariot
  While cont                                                  ; Il y a ":", mais il est peut-être entre guillemets !
    DansGuillemets=0
    test=pos - 1
    While test >0
      mc.s=Mid(ProgText,test,1)
      If Mid(ProgText,test,1)=Chr(34) ; Chr(34) est le code ascii du guillemet
        DansGuillemets=DansGuillemets+1
      EndIf
      If Mid(ProgText,test,1)=Chr(13) Or Mid(ProgText,test,1)=Chr(10)
        test = 0
      Else
        test - 1
      EndIf
    Wend
    If (Int(DansGuillemets/2)*2)<>DansGuillemets         ; Si le nombre de guillements est impair...
      pos=FindString(ProgText,cr,(pos + 1))              ; on ne tient pas compte du signe et on recherche le suivant
      If pos<Jusqu_a And pos:cont=1:Else:cont=0:EndIf  ; (En tout cas si c'est encore la peine)
    Else
      cont=0
    EndIf
  Wend
  If pos>Jusqu_a
    pos=0
  EndIf
  ProcedureReturn pos
EndProcedure

;*********************************************************
;* Recherche de la Fenêtre contenant le texte à Indenter *
;*********************************************************

Hwnd = FindWindow_( 0, 0 )
While Hwnd <> 0
  Txt.s = Space(256)
  GetWindowText_(Hwnd, Txt, 256)
  Hwnd = GetWindow_(Hwnd, #GW_HWNDNEXT)
  If FindString(UCase(Txt),"PUREBASIC - ",1) = 1 And FindString(UCase(Txt),"DEBUG",1) =0
    Handle=Hwnd
    Hwnd=0
  EndIf
Wend

;*****************************************************
;* Activation de la Fenêtre de Programme à Indenter  *
;* Copie du Texte du Programme dans le presse-papier *
;* puis du contenu du presse-papier dans ProgText    *
;*****************************************************

SetFocus_(Handle)
ProgText.s=""
If OpenClipboard_(WindowID())

  ;*****************************************************
  ;* On sauvegarde le contenu du presse-papier         *
  ;*****************************************************

  *hmem = GetClipboardData_(#CF_TEXT)
  *D=GlobalLock_(*hmem)
  If *D
    SauvPP.s = PeekS(*D,#MaxSize)
    GlobalUnlock_(*hmem)
  EndIf

  ;*****************************************************
  ;* On vide le presse-papier                          *
  ;*****************************************************

  EmptyClipboard_()
  CloseClipboard_()

  ;*****************************************************
  ;* On commence par un simple "Copier" pour voir si   *
  ;* l'utilisateur a fait une sélection                *
  ;*****************************************************

  Res = Keybd_Event_(#VK_CONTROL,0,0,0)+ Keybd_Event_(#VK_C,0,0,0)+Keybd_Event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0)
  Delay(200) ; Il faut laisser assez de temps pour les textes longs

  ; ProgText=GetClipboardText() Plante quand le texte
  ; dépasse Maxsize. On va donc utiliser une méthode
  ; plus complexe mais qui permet de limiter la taille
  ; de ce qu'on manipule.
  ; (Sait-on jamais, le texte fera peut-être plus de 1000000 caractères vu les heures que je passe à programmer !)

  OpenClipboard_(WindowID())
  *hmem = GetClipboardData_(#CF_TEXT)
  *D=GlobalLock_(*hmem)
  If *D
    ProgText = PeekS(*D,#MaxSize)
    GlobalUnlock_(*hmem)
  EndIf
  CloseClipboard_()
  If ProgText=""

    ;*****************************************************
    ;* Si on a rien récupéré, on fait "Tout sélectionner"*
    ;* puis à nouveau "Copier"                           *
    ;*****************************************************

    Res = Keybd_Event_(#VK_CONTROL,0,0,0)+ Keybd_Event_(#VK_A,0,0,0)+ Keybd_Event_(#VK_C,0,0,0)+Keybd_Event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0)
    Delay(200) ; Il faut laisser assez de temps pour les textes longs
    OpenClipboard_(WindowID())
    *hmem = GetClipboardData_(#CF_TEXT)
    *D=GlobalLock_(*hmem)
    If *D
      ProgText = PeekS(*D,#MaxSize)
      GlobalUnlock_(*hmem)
    EndIf
    CloseClipboard_()
  EndIf
  If Len(ProgText)=#MaxSize
    ProgText=""
    hw=OpenWindow(30, 0, 0, 20, 20,  #PB_Window_ScreenCentered | #PB_Window_TitleBar , "AutoIndent")
    SetForegroundWIndow_(hw)
    MessageRequester("Gasp !", "Désolé, ce texte est trop long. Procédez par morceau.", 0)
    CloseWindow(30)
  EndIf
  If ProgText<>""
    ProgText=ProgText+#RC1+#RC1

    ;**************************
    ;* Sauvegarde de sécurité *
    ;**************************
    ;  If CreateFile(#1,"c:\sauvegarde.bak")
    ;    WriteString(Progtext)
    ;    CloseFile(#1)
    ;  EndIf
    ;
    ;Maintenant que ça marche bien, inutile poluer le disque avec une sauvegarde
    ;
    ;
    ;*****************************************
    ;* Mise en Forme du texte et Indentation *
    ;*****************************************

    Prog.s=""
    Deb = 1
    voir=0
    mSep.s=""
    Fin  = FindString(ProgText,#RC1,Deb) ; on cherche le prochain retour chariot
    Sep.s= #RC1

    ; On va ensuite chercher le prochain signe ":"
    ; S'il n'est pas entre guillemets, et s'il n'est pas situé
    ; aprés un ";" alors on va le prendre comme fin de ligne
    ; à la place du retour chariot

    Fin2 = PasEntreGuillemets (FindString(ProgText,#RC2,Deb),Fin)
    If Fin2
      Fin3 = PasEntreGuillemets (FindString(ProgText,";",Deb),Fin)
      If Fin3>Fin2 Or Fin3=0 ; Si le";" n'est pas avant le ":"
        Fin=Fin2
        Sep=#RC2
      EndIf
    EndIf
    While fin + 2 < Len(ProgText)
      LineAvecEspaces.s = Mid(ProgText,deb,fin-deb)
      LineIndent.s = Trim(LineAvecEspaces)
      If LineIndent > ""
        Pos.l = FindString(LineIndent," ",1)
        If Pos = 0
          Cde.s = LineIndent
        Else
          Cde=Left(LineIndent,Pos-1)
        EndIf
        Pos.l = FindString(LineIndent,".",1)
        If Pos
          Cde=Left(Cde,Pos-1)
        EndIf
        Cde=UCase(Cde)
        ChaineRech$="*ENDIF*END*ENDSELECT*ELSE*CASE*WEND*NEXT*UNTIL*DEFAULT*ELSEIF*ENDPROCEDURE*ENDSTRUCTURE*ENDDATASECTION*"
        Cde2$="*"+Cde+"*"
        If FindString(ChaineRech$,Cde2$,1)
          Blanc - #Tab
        EndIf
        If Blanc < 0: blanc=0 : EndIf
        If Left(Cde,1) =";" And DejaCom = 0: DejaCom = 1 : Prog + #RC1 : EndIf ; On met une ligne blanche avant les commentaires
        If Left(Cde,1)<>";" And DejaCom: DejaCom = 0 : Prog + #RC1 : EndIf ; On met une ligne blanche aprés les commentaires

        ; Quand le séparateur trouvé n'est pas un retour chariot, on évite de faire Trim
        ; afin de garder les espaces avant et aprés le ":"

        If mSep=#RC1
          While Left(LineAvecEspaces,1)=" "
            LineAvecEspaces=Right(LineAvecEspaces,(Len(LineAvecEspaces)-1))
          Wend
        EndIf
        If Sep=#RC1
          While Right(LineAvecEspaces,1)=" "
            LineAvecEspaces=Left(LineAvecEspaces,(Len(LineAvecEspaces)-1))
          Wend
        EndIf

        ; Il nous reste à gérer la constante #IndentComment

        If (#IndentComment = 0 And Left(Cde,1) =";") Or mSep<>#RC1
          Prog + LineAvecEspaces + Sep
        Else
          Prog + Space(Blanc) + LineIndent + Sep
        EndIf
        ChaineRech$="*IF*FOREACH*REPEAT*WHILE*FOR*SELECT*ELSE*CASE*DEFAULT*ELSEIF*PROCEDURE*STRUCTURE*DATASECTION*"
        If FindString(ChaineRech$,"*"+Cde+"*",1)>0
          Blanc + #Tab
        EndIf
      EndIf
      deb = fin+Len(Sep)
      mSep=Sep
      Fin  = FindString(ProgText,#RC1,Deb) ; Voir commentaires en début de boucle
      Sep  = #RC1
      Fin2 = PasEntreGuillemets (FindString(ProgText,#RC2,Deb),Fin)
      If Fin2
        Fin3 = PasEntreGuillemets (FindString(ProgText,";",Deb),Fin)
        If Fin3>Fin2 Or Fin3=0 ; Si le";" n'est pas avant le ":"
          Fin=Fin2
          Sep=#RC2
        EndIf
      EndIf
    Wend
    Prog=Left(Prog,(Len(Prog)-2)) ; on enlève le dernier retour chariot inutile

    ;*********************************************************
    ;* Remplacement du programme Actuel par le texte indenté *
    ;*********************************************************

    OpenClipboard_(WindowID()) ; Je suis happy avec les API
    EmptyClipboard_()
    SetClipboardData_(#CF_TEXT,@Prog)
    CloseClipboard_()
    SetFocus_(Handle)
    Res = Keybd_Event_(#VK_CONTROL,0,0,0)+Keybd_Event_(#VK_V,0,0,0)
    Delay(200)
    Res = Keybd_Event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0)
    Delay(200)

    ;*********************************************************
    ;* Restauration du contenu du presse-papier              *
    ;*********************************************************

    OpenClipboard_(WindowID())
    EmptyClipboard_()
    SetClipboardData_(#CF_TEXT,@SauvPP)
    CloseClipboard_()
  EndIf
Else
  hw=OpenWindow(30, 0, 0, 20, 20,  #PB_Window_ScreenCentered | #PB_Window_TitleBar , "AutoIndent")
  SetForegroundWIndow_(hw)
  MessageRequester("Gasp !", "Impossible d'ouvrir le presse-papier !!", 0)
  CloseWindow(30)
EndIf
Tout obstacle est un point d'appui potentiel.

Bibliothèques PureBasic et autres codes à télécharger :https://www.editions-humanis.com/downlo ... ads_FR.htm
Avatar de l’utilisateur
ZapMan
Messages : 460
Inscription : ven. 13/févr./2004 23:14
Localisation : France
Contact :

Message par ZapMan »

Les gars, ça serait sympa de me dire çe que vous en pensez, si ça marche chez vous, si vous avez des critiques et tout et tout.
J'ai posté mon truc et personne ne réagit.
Je sens mauvais sous les bras, ou quoi ?
Tout obstacle est un point d'appui potentiel.

Bibliothèques PureBasic et autres codes à télécharger :https://www.editions-humanis.com/downlo ... ads_FR.htm
brossden
Messages : 833
Inscription : lun. 26/janv./2004 14:37

Message par brossden »

ZapMan a écrit : Je sens mauvais sous les bras, ou quoi ?
Ca il n'y a que toi qui puisse le savoir, car heureusement le Net ne transmet pas encore les odeurs !!! :)
Pour en revenir à ton programme, issu en partie mien n'a plus trés grand interet quand on a essayé l'éditeur de JaPBe...

Il faut reconnaitre que celui qui ne laisse pas l'éditeur de PB pour ce dernier c'est qu'il ne l'a pas essayé !

Au moment ou j'ai écris ce programme j'ignorais l'existance de ce JaPBe si tu ne l'as pas encore fait je te conseil vivement de le tester c'est TIP TOP ! #hello

Aller sans rancune !!! :lol:
Denis

Bonne Jounée à tous
Répondre