WebBase HTML CSS Javascript

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

WebBase HTML CSS Javascript

Message par falsam »

WebBase est un recueil de fonctionnalités HTML/CSS/Javascript en cours de développement.

➡️ Objectif :
Avoir les éléments nécessaires pour la production d'une application d'édition de code HTML/CSS/Javascript.

➡️ Fonctionnalités :

Version 0.00 😁
Mise en place du gadget Scintilla
Propriété du gadget Scintilla
Scintilla callback pour gérer les évènements Scintilla

Version 0.01 Ajout :
Indentation.
viewtopic.php?p=220087#p220087

Version 0.02 Ajout :
Auto-complétions.
viewtopic.php?p=220088#p220088

Version 0.05 Ajout :
Coloration des mots clés HTML
Coloration des commentaires
viewtopic.php?p=220095#p220095

Version 1.10 Ajout :
Folding (Pliage et dépliage du code)
Coloration des mots clés Javascript
viewtopic.php?p=220099#p220099

Version 1.20 Ajout :
Auto fermeture des tag <tag> -> </tag> automatique
viewtopic.php?p=220101#p220101

Version 1.30 Ajout :
Coloration CSS.
viewtopic.php?p=220113#p220113

Version 1.40 Ajout :
Coloration des nombres
Coloration des strings entre guillemets
Coloration des brackets
Coloration des parenthèses
viewtopic.php?p=220116#p220116

➡️ Code de mise en place du gadget Scintilla associé à un callback évènementiel. Les commentaires sont dans le code.

Code : Tout sélectionner

; WebBase - Trame d'un éditeur HTML/JavaScript
; Version 0.00

; PureBasic 6.30 (x64)
; Mise à jour du 29 Janvier 2026
; Pas d'API & Scintilla natif

; Fonctionnalités
; ===============
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla

EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
EndEnumeration

Define version.s = "0.00"

; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50

; Couleurs
Global scFrontColor = RGB(105,105, 105) 
Global scBackColor  = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)

; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12

;- Sommaire des procédures

; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)

; Callback évenementielle du gadget scintilla 
Declare ScintillaCallBack(gadget, *scn.scNotification)

;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version , #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)

AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)  
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)

; Editeur Scintilla gadget associé à un callback 
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())

;- Parametres Scintilla (Couleur, font, numerotation, style,  etc ...)
ScintillaProperties(#editor)

; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)

;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow

;-
;- Liste des procédures

; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
  ;- 1 Style par défaut
  ; Couleur et police de caractéres
  ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
  ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
  
  ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont) 
  ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
  
  ;- 2 Propager vers tous les styles
  ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
  
  ;- 3 Définir des styles spécifiques
  ; Activation et couleur de la ligne en cours d'édition
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
  
  ; Les tabulations sont remplacées par des espaces 
  ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
  
  ; Nombre d'espaces pour une tabulation
  ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
  
  ; Création de la colonne de numérotation des lignes
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER) 
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
  
  ; Création de la colonne de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)
  
EndProcedure

;-

; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)

  ; Analyser les evenement scintilla
  Select *scn\nmhdr\code
    Case #SCN_CHARADDED 
      Debug "#SCN_CHARADDED - Indentation et autocomplétion"
      
    Case #SCN_UPDATEUI  
      Debug "#SCN_UPDATEUI - Coloration et systeme de folding"
      
    Case #SCN_MARGINCLICK
      ; Clique sur la deuxiéme colonne (folding)
      If *scn\margin = 2
        Debug "#SCN_MARGINCLICK - pliage/dépliage du code"
      EndIf
      
  EndSelect     
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Version 0.01 - Je vous propose maintenant de nous occuper de l'indentation.

➡️ Objectif :
Vous pressez la touche tab une ou plusieurs fois.
Vous pressez la touche entrée pour aller à la ligne suivante.
Le curseur de saisie se placera au même niveau que la position du curseur de la ligne précédente.

L'indentation est gérée dans le callback dans l'évènement #SCN_CHARADDED

➡️ Code incluant la mise en place de l'indentation. Commentaires dans le code.

Code : Tout sélectionner

; WebBase - Trame d'un éditeur HTML/JavaScript
; Version 0.01

; PureBasic 6.30 (x64)
; Mise à jour du 29 Janvier 2026
; Pas d'API & Scintilla natif

; Fonctionnalités
; ===============
; V0.00
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla

; V0.01
; Indentation 

EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
EndEnumeration

Define version.s = "0.01"

; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50

; Couleurs
Global scFrontColor = RGB(105,105, 105) 
Global scBackColor  = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)

; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12

; Indentation
Global scIndent, scLine, scPos, scCol


;- Sommaire des procédures

; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)

; Callback évenementielle du gadget scintilla 
Declare ScintillaCallBack(gadget, *scn.scNotification)

;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version , #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)

AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)  
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)

; Editeur Scintilla gadget associé à un callback 
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())

;- Parametres Scintilla (Couleur, font, numerotation, style,  etc ...)
ScintillaProperties(#editor)

; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)

;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow

;-
;- Liste des procédures

; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
  ;- 1 Style par défaut
  ; Couleur et police de caractéres
  ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
  ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
  
  ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont) 
  ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
  
  ;- 2 Propager vers tous les styles
  ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
  
  ;- 3 Définir des styles spécifiques
  ; Activation et couleur de la ligne en cours d'édition
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
  
  ; Les tabulations sont remplacées par des espaces 
  ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
  
  ; Nombre d'espaces pour une tabulation
  ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
  
  ; Création de la colonne de numérotation des lignes
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER) 
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
  
  ; Création de la colonne de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)
  
EndProcedure

;-

; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)
  Protected textLength
  Protected SciCurrentPos, SciWordStartPos
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(#editor, #SCI_GETLENGTH)
  
  ; Analyser les evenement scintilla
  Select *scn\nmhdr\code
    Case #SCN_CHARADDED 
      Debug "#SCN_CHARADDED - Indentation et autocomplétion"
      
      ; Un caractére est saisie      
      Select *scn\ch
        Case 13
          ;- Indentation
          ; Vous avez pressé la touche entrée
          
          ; Quel est la position du décalages du texte au niveau de la marge.
          scIndent = ScintillaSendMessage(Gadget, #SCI_GETLINEINDENTATION, scLine)
          
          ; Passer à la ligne suivante 
          ; et positionner le curseur 
          ScintillaSendMessage(Gadget, #SCI_SETLINEINDENTATION, scLine+1, scIndent)
          
          ; Touche entrée préssée : Le curseur ne passera pas à  la ligne suivante.
          ; Forcer le passage à la ligne en insérant la longueur de #CRLF$
          If scIndent=0 
            scPos = scPos + Len(#CRLF$)
          EndIf
          
          ; Positionner le curseur de saisie 
          ScintillaSendMessage(Gadget, #SCI_GOTOPOS, scPos + scIndent)
      EndSelect 
      
    Case #SCN_UPDATEUI  
      Debug "#SCN_UPDATEUI - Coloration et systeme de folding"
      
    Case #SCN_MARGINCLICK
      ; Clique sur la deuxiéme colonne (folding)
      If *scn\margin = 2
        Debug "#SCN_MARGINCLICK - pliage/dépliage du code"
      EndIf
      
  EndSelect 
  
  ; Important pour le fonctionnement de l'indentation
  
  ; Trouver la position du curseur de saisie  
  scPos = ScintillaSendMessage(Gadget, #SCI_GETANCHOR)
  
  ; Trouver la ligne ou se touve le curseur
  scLine = ScintillaSendMessage(Gadget, #SCI_LINEFROMPOSITION, scPos)
  
  ; Trouver la colonne en cours
  scCol = ScintillaSendMessage(Gadget, #SCI_GETCOLUMN, scPos)
  
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Version 0.02 - Je vous propose maintenant de mettre en place l'auto-complétions des mots clés.

➡️ Objectif :
Proposer des mots à l'utilisateur à partir des premiers caractères saisis.

L'auto-complétions est gérée dans le callback avec l'évènement #SCN_CHARADDED

⚠️ Dans la procédure ScintillaProperties(), j'ai ajouté le paramétrage de la mise en œuvre de l'auto-complétions.

Code : Tout sélectionner

  ; Autocomplétion : Parametres de la liste des mots clés 
ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXHEIGHT, 40)
ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXWIDTH, 150)
ScintillaSendMessage(gadget, #SCI_AUTOCSETAUTOHIDE, #True)
ScintillaSendMessage(gadget, #SCI_AUTOCSETCHOOSESINGLE, #True)
ScintillaSendMessage(gadget, #SCI_AUTOCSETIGNORECASE, #True)
  
; Autocomplétion : Caractére séparant chaque mot de la liste des mots clés
ScintillaSendMessage(gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
  
; Autocomplétion : Caractére sélectionnant le mot de la liste d'autocomplétion
ScintillaSendMessage(gadget, #SCI_AUTOCSETFILLUPS, 0, @" ")
  
; Autocomplétion : Tri de la liste 
ScintillaSendMessage(gadget, #SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT)
 

➡️ Code incluant la mise en place de l'auto-complétions. Commentaires dans le code.

Code : Tout sélectionner

; WebBase - Trame d'un editeur HTML/JavaScript
; Version 0.02

; PureBasic 6.30 (x64)
; Mise à jour du 29 Janvier 2026
; Pas d'API & Scintilla natif

; Fonctionnalités
; ===============
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla
; Indentation 

; V0.02
; Autocomplétion 


EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
EndEnumeration

Define version.s = "0.02"

; Liste des mots clés (C'est un jeu de test)
Global htmlKeyWords.s = "html,head,body,title,script,style,div,canvas,meta,h1,h2,h3,h4,h5,h6,button"

; Séparateur des mots clés
Global KeyWordSep.s = ","

; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50

; Couleurs
Global scFrontColor = RGB(105,105, 105) 
Global scBackColor  = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)

; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12

; Indentation
Global scIndent, scLine, scPos, scCol


;- Sommaire des procédures

; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)

; Callback évenementielle du gadget scintilla 
Declare ScintillaCallBack(gadget, *scn.scNotification)

; Texte au format UTF8
Declare MakeUTF8Text(text.s)

;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version , #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)

AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)  
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)

; Editeur Scintilla gadget associé à un callback 
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())

;- Parametres Scintilla (Couleur, font, numerotation, style,  etc ...)
ScintillaProperties(#editor)

; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)

;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow

;-
;- Liste des procédures

; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
  ;- 1 Style par défaut
  ; Couleur et police de caractéres
  ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
  ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
  
  ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont) 
  ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
  
  ;- 2 Propager vers tous les styles
  ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
  
  ;- 3 Définir des styles spécifiques
  ; Activation et couleur de la ligne en cours d'édition
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
  
  ; Les tabulations sont remplacées par des espaces 
  ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
  
  ; Nombre d'espaces pour une tabulation
  ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
  
  ; Création de la colonne de numérotation des lignes
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER) 
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
  
  ; Autocomplétion : Parametres de la liste des mots clés 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXHEIGHT, 40)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXWIDTH, 150)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETAUTOHIDE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETCHOOSESINGLE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETIGNORECASE, #True)
  
  ; Autocomplétion : Caractére séparant chaque mot de la liste des mots clés
  ScintillaSendMessage(gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
  
  ; Autocomplétion : Caractére sélectionnant le mot de la liste d'autocomplétion
  ScintillaSendMessage(gadget, #SCI_AUTOCSETFILLUPS, 0, @" ")
  
  ; Autocomplétion : Tri de la liste 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT) 

  
  ; Création de la colonne de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)
  
EndProcedure

;-

; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)
  Protected textLength
  Protected SciCurrentPos, SciWordStartPos
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(#editor, #SCI_GETLENGTH)
  
  ; Analyser les evenement scintilla
  Select *scn\nmhdr\code
    Case #SCN_CHARADDED 
      Debug "#SCN_CHARADDED - Indentation et autocomplétion"
      
      ; Un caractére est saisie      
      Select *scn\ch
        Case 13
          ;- Indentation
          ; Vous avez pressé la touche entrée
          
          ; Quel est la position du décalages du texte au niveau de la marge.
          scIndent = ScintillaSendMessage(gadget, #SCI_GETLINEINDENTATION, scLine)
          
          ; Passer à la ligne suivante 
          ; et positionner le curseur 
          ScintillaSendMessage(gadget, #SCI_SETLINEINDENTATION, scLine+1, scIndent)
          
          ; Touche entrée préssée : Le curseur ne passera pas à  la ligne suivante.
          ; Forcer le passage à la ligne en insérant la longueur de #CRLF$
          If scIndent=0 
            scPos = scPos + Len(#CRLF$)
          EndIf
          
          ; Positionner le curseur de saisie 
          ScintillaSendMessage(gadget, #SCI_GOTOPOS, scPos + scIndent)
          
        Case 'a' To 'z', 'A' To 'Z'
          ; Autocomplétion (Affichage d'une liste contenant les mots clés HTML
          ; Affichage du mot selectionné si autocomplétion
          SciCurrentPos = ScintillaSendMessage(Gadget, #SCI_GETCURRENTPOS)
          SciWordStartPos = ScintillaSendMessage(Gadget, #SCI_WORDSTARTPOSITION, SciCurrentPos, 1)
          ScintillaSendMessage(0, #SCI_AUTOCSHOW, SciCurrentPos - SciWordStartPos, MakeUTF8Text(htmlKeyWords))
          
      EndSelect 
      
    Case #SCN_UPDATEUI  
      Debug "#SCN_UPDATEUI - Coloration et systeme de folding"
      
    Case #SCN_MARGINCLICK
      ; Clique sur la deuxiéme colonne (folding)
      If *scn\margin = 2
        Debug "#SCN_MARGINCLICK - pliage/dépliage du code"
      EndIf
      
  EndSelect 
  
  ; Important pour le fonctionnement de l'indentation
  
  ; Trouver la position du curseur de saisie  
  scPos = ScintillaSendMessage(Gadget, #SCI_GETANCHOR)
  
  ; Trouver la ligne ou se touve le curseur
  scLine = ScintillaSendMessage(Gadget, #SCI_LINEFROMPOSITION, scPos)
  
  ; Trouver la colonne en cours
  scCol = ScintillaSendMessage(Gadget, #SCI_GETCOLUMN, scPos)
  
EndProcedure

;-
;- Utilitaire(s)

; Obtenir un UTF8 d'un string
Procedure MakeUTF8Text(text.s)
  Static buffer.s
  
  buffer = Space(StringByteLength(text, #PB_UTF8) + 1)
  PokeS(@buffer, text, -1, #PB_UTF8)
  ProcedureReturn @buffer
EndProcedure

🔜 Prochain sujet. On rentre dans le vif. Coloration des balises HTML 🌞
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Mindphazer
Messages : 729
Inscription : mer. 24/août/2005 10:42

Re: WebBase HTML CSS Javascript

Message par Mindphazer »

Y'en a un qui va être content ! N'est-ce pas KCC ? :mrgreen:
Bureau : Win11 64bits
Maison : Macbook Pro M4 16" SSD 512 Go / Ram 24 Go - iPad Air 128 Go (pour madame) - iPhone 17 Pro Max 256 Go
Avatar de l’utilisateur
Mindphazer
Messages : 729
Inscription : mer. 24/août/2005 10:42

Re: WebBase HTML CSS Javascript

Message par Mindphazer »

falsam a écrit : ven. 30/janv./2026 0:14

Code : Tout sélectionner

; Mise à jour du 29 Janvier 2025
2025 ? Vraiment ? :mrgreen:
Bureau : Win11 64bits
Maison : Macbook Pro M4 16" SSD 512 Go / Ram 24 Go - iPad Air 128 Go (pour madame) - iPhone 17 Pro Max 256 Go
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

C'est corrigé. Merci Mindphazer et plein de bonnes choses à toi et ton entourage pour cette nouvelle Année 2026 🎉 🎊 🎁
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Mindphazer
Messages : 729
Inscription : mer. 24/août/2005 10:42

Re: WebBase HTML CSS Javascript

Message par Mindphazer »

falsam a écrit : ven. 30/janv./2026 11:18 Merci Mindphazer et plein de bonnes choses à toi et ton entourage pour cette nouvelle Année 2026 🎉 🎊 🎁
On est encore dans les temps alors très bonne nouvelle année à toi aussi et à tes proches :D
Bureau : Win11 64bits
Maison : Macbook Pro M4 16" SSD 512 Go / Ram 24 Go - iPad Air 128 Go (pour madame) - iPhone 17 Pro Max 256 Go
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Version 0.05 - Coloration des mots clés HTML et des commentaires.

➡️ Objectif :
Colorer les mots clés HTML en rouges et les commentaires en verts.

La coloration des mots clés HTML et commentaire est gérée dans le callback avec l'évènement #SCN_CHARADDED

➡️ Le code forcément se complique avec l'ajout de trois procédures.
- getScintillaWord(gadget, startPos, endPos) pour obtenir un string entre deux positions.
- isKeyword(word.s, keyWords.s) pour tester si le mot est un mot clé. (KeyWords.s contient la liste des mots).
- ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s) pour colorer les mots clés HTML & commentaires.

⚠️ Ajout dans la procédures ScintillaProperties() de la définition des styles :
- #Style_HTML_Keyword coloration des mots clés.
- #Style_Comment coloration des commentaires.

Les couleurs sont définis dans deux variables globales :
scStyleHTMLKeyWordColor = RGB(255, 0, 0)
scStyleHTMLCommentColot = RGB(154, 205, 50)

➡️ Voici le code.

Code : Tout sélectionner

; WebBase - Trame d'un editeur HTML/JavaScript
; Version 0.05

; PureBasic 6.30 (x64)
; Mise à jour du 30 Janvier 2026
; Pas d'API & Scintilla natif

; Fonctionnalités
; ===============
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla
; Indentation 
; Autocomplétion

; Add
; Coloration des mots clés HTML
; Coloration des commentaires


EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
  #Style_Comment
  #Style_HTML_Keyword
EndEnumeration

Define version.s = "0.05"

; Liste des mots clés (C'est un jeu de test)
Global htmlKeyWords.s = "html,head,body,title,script,style,div,canvas,meta,h1,h2,h3,h4,h5,h6,button"

; Séparateur des mots clés
Global KeyWordSep.s = ","

; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50

; Couleurs
Global scFrontColor = RGB(105,105, 105) 
Global scBackColor  = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)

; Couleur des styles par defaut
Global scStyleHTMLKeyWordColor = RGB(255, 0, 0)
Global scStyleHTMLCommentColot = RGB(154, 205, 50)

; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12

; Indentation
Global scIndent, scLine, scPos, scCol

; Pour la recherche des blocs commentaires "<!--" et "-->"
; Ces deux chaines doivent être stockées dans un buffer UTF8
Global commentStartPattern = AllocateMemory(5)
Global commentEndPattern   = AllocateMemory(4)


;- Sommaire des procédures

; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)

; Callback évenementielle du gadget scintilla 
Declare ScintillaCallBack(gadget, *scn.scNotification)

; Obtenir le mot se trouvant entre deux position
Declare.s getScintillaWord(gadget, startPos, endPos)

; Tester si un mot est un mot clé
Declare.b isKeyword(word.s, keyWords.s)

; Coloration des mots clés HTML
Declare ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)


; Texte au format UTF8
Declare MakeUTF8Text(text.s)

;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version , #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)

AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)  
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)

; Editeur Scintilla gadget associé à un callback 
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())

;- Parametres Scintilla (Couleur, font, numerotation, style,  etc ...)
ScintillaProperties(#editor)

; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)

; "<!--" et "-->" convertis au format UTF8
PokeS(commentStartPattern, "<!--", -1, #PB_UTF8)
PokeS(commentEndPattern,   "-->",  -1, #PB_UTF8)

;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow

;-
;- Liste des procédures

; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
  ;- 1 Style par défaut
  ; Couleur et police de caractéres
  ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
  ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
  
  ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont) 
  ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
  
  ;- 2 Propager vers tous les styles
  ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
  
  ;- 3 Définir des styles spécifiques
  ; Activation et couleur de la ligne en cours d'édition
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
  
  ; Les tabulations sont remplacées par des espaces 
  ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
  
  ; Nombre d'espaces pour une tabulation
  ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
  
  ; Création de la colonne de numérotation des lignes
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER) 
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
  
  ; Autocomplétion : Parametres de la liste des mots clés 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXHEIGHT, 40)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXWIDTH, 150)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETAUTOHIDE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETCHOOSESINGLE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETIGNORECASE, #True)
  
  ; Autocomplétion : Caractére séparant chaque mot de la liste des mots clés
  ScintillaSendMessage(gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
  
  ; Autocomplétion : Caractére sélectionnant le mot de la liste d'autocomplétion
  ScintillaSendMessage(gadget, #SCI_AUTOCSETFILLUPS, 0, @" ")
  
  ; Autocomplétion : Tri de la liste 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT) 

  ; Création de la colonne de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)
  
  ; Styles : Coloration des mots clés HTML 
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_HTML_Keyword, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_HTML_Keyword, scStyleHTMLKeyWordColor)
  
  ; Style commentaires HTML
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_Comment, scStyleHTMLCommentColot)
  
  
EndProcedure

;-

; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)
  Protected textLength
  Protected SciCurrentPos, SciWordStartPos
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(#editor, #SCI_GETLENGTH)
  
  ; Analyser les evenement scintilla
  Select *scn\nmhdr\code
    Case #SCN_CHARADDED 
      
      ; Un caractére est saisie      
      Select *scn\ch
        Case 13
          ;- Indentation
          ; Vous avez pressé la touche entrée
          
          ; Quel est la position du décalages du texte au niveau de la marge.
          scIndent = ScintillaSendMessage(gadget, #SCI_GETLINEINDENTATION, scLine)
          
          ; Passer à la ligne suivante 
          ; et positionner le curseur 
          ScintillaSendMessage(gadget, #SCI_SETLINEINDENTATION, scLine+1, scIndent)
          
          ; Touche entrée préssée : Le curseur ne passera pas à  la ligne suivante.
          ; Forcer le passage à la ligne en insérant la longueur de #CRLF$
          If scIndent=0 
            scPos = scPos + Len(#CRLF$)
          EndIf
          
          ; Positionner le curseur de saisie 
          ScintillaSendMessage(gadget, #SCI_GOTOPOS, scPos + scIndent)
          
        Case 'a' To 'z', 'A' To 'Z'
          ; Autocomplétion (Affichage d'une liste contenant les mots clés HTML
          ; Affichage du mot selectionné si autocomplétion
          SciCurrentPos = ScintillaSendMessage(Gadget, #SCI_GETCURRENTPOS)
          SciWordStartPos = ScintillaSendMessage(Gadget, #SCI_WORDSTARTPOSITION, SciCurrentPos, 1)
          ScintillaSendMessage(0, #SCI_AUTOCSHOW, SciCurrentPos - SciWordStartPos, MakeUTF8Text(htmlKeyWords))
          
      EndSelect 
      
    Case #SCN_UPDATEUI  
      Debug "#SCN_UPDATEUI - Coloration et systeme de folding"
      ; Style UNIQUEMENT si le contenu change
      If *scn\updated & #SC_UPDATE_CONTENT
        ColorizeHTMLTags(gadget, 0, textLength, htmlKeyWords)
      EndIf
      
    Case #SCN_MARGINCLICK
      ; Clique sur la deuxiéme colonne (folding)
      If *scn\margin = 2
        Debug "#SCN_MARGINCLICK - pliage/dépliage du code"
      EndIf
      
  EndSelect 
  
  ; Important pour le fonctionnement de l'indentation
  
  ; Trouver la position du curseur de saisie  
  scPos = ScintillaSendMessage(Gadget, #SCI_GETANCHOR)
  
  ; Trouver la ligne ou se touve le curseur
  scLine = ScintillaSendMessage(Gadget, #SCI_LINEFROMPOSITION, scPos)
  
  ; Trouver la colonne en cours
  scCol = ScintillaSendMessage(Gadget, #SCI_GETCOLUMN, scPos)
  
EndProcedure

; Obtenir le mot (ou texte) se trouvant entre deux positions
Procedure.s getScintillaWord(gadget, startPos, endPos)
  Protected tr.scTextRange, *buffer, length, result.s
  
  length = endPos - startPos
  
  If length > 0
    *buffer = AllocateMemory(length + 1)
    
    tr\chrg\cpMin = startPos
    tr\chrg\cpMax = endPos
    tr\lpstrText  = *buffer
    
    ScintillaSendMessage(gadget, #SCI_GETTEXTRANGE, 0, @tr)
    
    ; Lecture UTF-8 correcte
    result = PeekS(*buffer, -1, #PB_UTF8)
    FreeMemory(*buffer)
  EndIf 
  
  ProcedureReturn result
EndProcedure

; Tester si un mot est un mot clé
Procedure.b isKeyword(word.s, keyWords.s)
  Protected countWords = CountString(keyWords, KeyWordSep), n
  Protected result.b  
  
  For n = 1 To countWords + 1
    If LCase(StringField(keyWords, n, KeyWordSep)) = LCase(word)
      result = #True
    EndIf
  Next
  ProcedureReturn result
EndProcedure


;-
; Coloration des mots clés
Procedure ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)
  Protected pos                       ; Position actuelle de l'indice de parcours du string
  Protected lowerTag                  ; Position du prochain "<"
  Protected upperTag                  ; Position du prochain ">"
  Protected tagStart                  ; Premier caractère après "<"
  Protected tagEnd                    ; Fin du nom de la balise sans ">"
  Protected originalTagStart          ; Début logique de la balise (après "<")
  Protected tagName.s                 ; Tag sans balise d'ouverture/fermeture "<tag> -> "tag"
  Protected nameStart                 ; Premier caractère après "<" 
  Protected isClosing                 ; Indicateur de balise fermée
  Protected space                     ; Position d'un espace à l'intérieur de "<" et ">"
  Protected commentStart, commentEnd  ;Position de début et fin d'un commentaire
  
  ; La coloration se fera en plusieurs passage 
  ; - 1 Commentaires
  ; - 2 Tags HTML <tag> </tag>
  
  ; Reset des indicateurs de styles
  ScintillaSendMessage(Gadget, #SCI_SETINDICATORCURRENT, #Style_Comment, 0)
  ScintillaSendMessage(Gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)

  ScintillaSendMessage(Gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
  ScintillaSendMessage(Gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
    
  ;- ■ 1 Pass commentaires <!-- Commentaire -->
  pos = startPos
  
  While pos < endPos
    
    ; Définir le target de recherche
    ScintillaSendMessage(Gadget, #SCI_SETTARGETSTART, pos)
    ScintillaSendMessage(Gadget, #SCI_SETTARGETEND, endPos)
    
    ; Rechercher la chaine de début de commentaire "<!--" (Longueur 4)
    commentStart = ScintillaSendMessage(Gadget, #SCI_SEARCHINTARGET, 4, commentStartPattern)
    
    ; Il y en a pas, on s'arrete !
    If commentStart = -1 : Break : EndIf
    
    ; Nouveau target de recherche qui commencera aprés "<!--"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, commentStart + 4)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Rechercher la chaine de fin de commentaire "-->" (Longueur 3)
    commentEnd = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 3, commentEndPattern)
    
    If commentEnd <> -1
      commentEnd + 3
    Else
      commentEnd = endPos
    EndIf

    ; colorer le commentaire
    ScintillaSendMessage(Gadget, #SCI_SETINDICATORCURRENT, #Style_Comment)
    ScintillaSendMessage(Gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)

    pos = commentEnd
  Wend

  ;- ■ 2 Pass tag HTML "<html>" 
  pos = startPos
  
  While pos < endPos
    
    ; Définir le target de recherche
    ScintillaSendMessage(Gadget, #SCI_SETTARGETSTART, pos)
    ScintillaSendMessage(Gadget, #SCI_SETTARGETEND, endPos)
    
    ; Chercher le caractére '<' dans la zone de scan 
    lowerTag = ScintillaSendMessage(Gadget, #SCI_SEARCHINTARGET, 1, @"<")
    
    ; Il y en a pas. On sort de la boucle
    If lowerTag = -1 : Break : EndIf
    
    ; "<" est trouvé
    ; Nouveau target de recherche qui commencera aprés "<"
    ScintillaSendMessage(Gadget, #SCI_SETTARGETSTART, lowerTag + 1) 
    ScintillaSendMessage(Gadget, #SCI_SETTARGETEND, endPos)
    
    ; Chercher le prochain '>'
    upperTag = ScintillaSendMessage(Gadget, #SCI_SEARCHINTARGET, 1, @">")
    
    If upperTag = -1
      ;ScintillaSendMessage(Gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
      ;ScintillaSendMessage(Gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
      Break
    EndIf
    
    ; Bonne nouvelle nous avons maintenant localisé "<" et ">"
    originalTagStart = lowerTag + 1
    tagStart         = originalTagStart
    
    ; Nouveau target de recherche qui commencera aprés "<" et se termine à ">"
    ScintillaSendMessage(Gadget, #SCI_SETTARGETSTART, tagStart)
    ScintillaSendMessage(Gadget, #SCI_SETTARGETEND, upperTag)
    
    ; Recherche du caractéres espace dans las chaine située entre "<" et ">" 
    space = ScintillaSendMessage(Gadget, #SCI_SEARCHINTARGET, 1, @" ")
    
    If space = -1
      tagEnd = upperTag
    Else
      tagEnd = space
    EndIf
    
    ; Rechercher le mot situé entre "<" et ">" 
    If tagEnd > tagStart
      tagName = GetScintillaWord(gadget, tagStart, tagEnd)
      isClosing = #False
      nameStart = tagStart
      
      ; Détecter </tag>
      If Left(tagName, 1) = "/"
        isClosing = #True
        tagName  = Mid(tagName, 2)
        nameStart = tagStart + 1
      EndIf
      
      ; Indiquer le début de la coloration  style #Style_HTML_Keyword 
      ; Indiquer la position de débug et fin de la coloration
      ScintillaSendMessage(Gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword)
      ScintillaSendMessage(Gadget, #SCI_INDICATORCLEARRANGE, originalTagStart, upperTag - originalTagStart)
      
      ; Coloration de la balise "<" - position de début sur une longueur de 1
      ScintillaSendMessage(Gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
      
      ; Coloration de "/" si balise fermante - position de début sur une longueur de 1
      If isClosing
        ScintillaSendMessage(Gadget, #SCI_INDICATORFILLRANGE, tagStart, 1)
      EndIf
      
      ; Coloration du nom de balise (ouvrante OU fermante) - Exemple html
      If IsKeyword(tagName, keyWords)
        ScintillaSendMessage(Gadget, #SCI_INDICATORFILLRANGE, nameStart, tagEnd - nameStart)
      EndIf
            
      ; Coloration de ">" - position de fin sur une longueur de 1
      ScintillaSendMessage(Gadget, #SCI_INDICATORFILLRANGE, upperTag, 1)
    EndIf
    
    ; AU suivant ...
    pos = upperTag + 1
  Wend
EndProcedure

;-
;- Utilitaire(s)

; Obtenir un UTF8 d'un string
Procedure MakeUTF8Text(text.s)
  Static buffer.s
  
  buffer = Space(StringByteLength(text, #PB_UTF8) + 1)
  PokeS(@buffer, text, -1, #PB_UTF8)
  ProcedureReturn @buffer
EndProcedure


🔜 Prochain sujet. Pliage et dépliage avant de passer à la coloration JavaScript 🌞
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
venom
Messages : 3177
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: WebBase HTML CSS Javascript

Message par venom »

Sa boss sa boss chez falsam :roll:
Bon courage et merci du partage






@++
Windows 10 x64, PureBasic 6.30 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Merci pour tes encouragements Venom 🌞
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Je suis trop content de vous présenter cette nouvelle version 🎁

Version 1.10 - Pliage et dépliage de code & coloration des mots clés JavaScript.

➡️ Objectif : Mise en place du folding. Vous cliquez devant une balise. Le code se trouvant entre la balise d'ouverture et la balise de fermeture va disparaitre. Vous cliquez à nouveau devant la même balise et le code va de nouveau apparaitre devant vos yeux émerveillés 🤪

La coloration en bleu des mots clés Javascript est fonctionnelle.

➡️ Le code continue de grossir :
- Ajout des paramètres du folding (Pliage/dépliage de code) dans la procédure ScintillaProperties()
- Ajout de quelques mots Javascripts dans la variable jsKeywords.s.
- Ajout de la procédure IsInsideScriptBlock(Gadget, pos). Sommes nous dans un context Javascript.
- Ajout de la procédure ColorizeJSKeywords(Gadget, startPos, endPos, keywordsList.s). Coloration des mots clés Javascript.

⚠️ Ajout dans la procédures ScintillaProperties() de la définition du style #Style_JS_KeyWord

La couleurs de coloration JavasScript est défini dans la variable globale scStyleJSKeywordColor = RGB(0, 0, 205).

➡️ Voici le code.

Code : Tout sélectionner

; Web Framework - Trame d'un editeur HTML/JavaScript
; Version 1.10

; PureBasic 6.30 (x64)
; Mise à jour du 31 Janvier 2026
; Pas d'API & Scintilla natif

; Fonctionnalités
; ===============
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla
; Indentation 
; Autocomplétion
; Coloration des mots clés HTML
; Coloration des commentaires

; Add :
; Folding (Pliage et dépliage du code)
; Coloration des mots clés Javascript

EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
  #Style_Comment
  #Style_HTML_Keyword
  #Style_JS_Comment
  #Style_JS_KeyWord
EndEnumeration

Define version.s = "1.10"

; Liste des mots clés (C'est un jeu de test)
Global htmlKeyWords.s = "html,head,body,title,script,style,div,canvas,meta,h1,h2,h3,h4,h5,h6,button,p"

; Liste des mots clés Javascript
Global jsKeywords.s = "break,case,catch,class,const,continue,debugger,default,delete,do," +
                      "else,export,extends,finally,for,function,if,import,in,instanceof," +
                      "let,new,return,super,switch,this,throw,try,typeof,var,void,while," +
                      "with,yield,await,enum,implements,interface,package,private," +
                      "protected,public,static,null,true,false,undefined"

; Liste des mots clés déclencheur de pliage/dépliage de code
Global KeywordsFolding.s = "html,head,body,div,section,article,nav,ul,ol,table"

; Séparateur des mots clés
Global KeyWordSep.s = ","

; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50

; Couleurs
Global scFrontColor = RGB(105,105, 105) 
Global scBackColor  = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)
Global scMasterFolder = RGB(255, 0, 0)

; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12

; Couleur des styles par defaut
Global scStyleHTMLKeyWordColor = RGB(255, 0, 0)
Global scStyleHTMLCommentColor = RGB(0, 255, 0)

Global scStyleJSCommentColor = RGB(0, 255, 0)
Global scStyleJSKeywordColor = RGB(0, 0, 205)

; Indentation
Global scIndent, scLine, scPos, scCol

; Pour la recherche des blocs commentaires "<!--" et "-->"
; Ces deux chaines doivent être stockées dans un buffer UTF8
Global commentStartPattern = AllocateMemory(5)
Global commentEndPattern   = AllocateMemory(4)

;- Sommaire des procédures

; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)

; Callback évenementielle du gadget scintilla 
Declare ScintillaCallBack(gadget, *scn.scNotification)

; Obtenir le texte de la ligne en cours de saisie 
Declare.s GetScintillaLineText(gadget, line)

; Obtenir le mot se trouvant entre deux position
Declare.s getScintillaWord(gadget, startPos, endPos)

; Tester si un mot est un mot clé
Declare.b isKeyword(word.s, keyWords.s)

; Tester si un mot est une clé de pliage
Declare.b isFoldingKeyWord(word.s, keyWordfoldingDown.s)

; Vérifier que la coloration du code JavaScript se trouve entre les balise <script> </script>
Declare.b IsInsideScriptBlock(gadget, pos)

; Coloration des mots clés HTML
Declare ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)

; Ignorer les lignes de commentaires JavaScript "//"
Declare SkipJSLineComment(gadget, pos)

; Ignorer les blocs de commentaires JavaScript "/* .. */"
Declare SkipJSBlockComment(gadget, pos)

; Coloration des mots clés JavaScript
Declare ColorizeJSKeywords(gadget, startPos, endPos)

; Coloration des commentaires Javascript
Declare ColorizeJSComments(gadget, startPos, endPos)

; Mettre à jour le pliage/dépliage
Declare UpdateHTMLFolding(gadget, KeywordsFolding.s) 

; Texte au format UTF8
Declare MakeUTF8Text(text.s)

;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)

AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)  
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)

; Editeur Scintilla gadget associé à un callback 
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())

;- Parametres Scintilla (Couleur, font, numerotation, style,  etc ...)
ScintillaProperties(#editor)

; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)

; "<!--" et "-->" convertis au format UTF8
PokeS(commentStartPattern, "<!--", -1, #PB_UTF8)
PokeS(commentEndPattern,   "-->",  -1, #PB_UTF8)

;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow

;-
;- Liste des procédures

; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
  ;- 1 Style par défaut
  ; Couleur et police de caractéres
  ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
  ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
  
  ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont) 
  ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
  
  ;- 2 Propager vers tous les styles
  ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
  
  ;- 3 Définir des styles spécifiques
  ; Activation et couleur de la ligne en cours d'édition
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
  
  ; Les tabulations sont remplacées par des espaces 
  ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
  
  ; Nombre d'espaces pour une tabulation
  ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
  
  ; Création de la colonne de numérotation des lignes
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER) 
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
    
  ; Autocomplétion : Parametres de la liste des mots clés 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXHEIGHT, 40)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXWIDTH, 150)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETAUTOHIDE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETCHOOSESINGLE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETIGNORECASE, #True)
  
  ; Autocomplétion : Caractére séparant chaque mot de la liste des mots clés
  ScintillaSendMessage(gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
  
  ; Autocomplétion : Caractére sélectionnant le mot de la liste d'autocomplétion
  ScintillaSendMessage(gadget, #SCI_AUTOCSETFILLUPS, 0, @" ")
  
  ; Autocomplétion : Tri de la liste 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT) 
  
  ; Folding : Création de la colonne de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)

  ; Folding : Choix des icones de pliages du code 5
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEROPEN, #SC_MARK_CIRCLEMINUS) 
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDER, #SC_MARK_CIRCLEPLUS)
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERSUB, #SC_MARK_VLINE) ;Ligne verticale
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERTAIL, #SC_MARK_LCORNERCURVE) ;fin arborescence
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEREND, #SC_MARK_CIRCLEPLUSCONNECTED) ;Dépliage
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEROPENMID, #SC_MARK_CIRCLEMINUSCONNECTED) ;Pliage
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERMIDTAIL, #SC_MARK_TCORNERCURVE)
  
  ; Folding : Couleur des icones de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_MARKERSETFORE, #SC_MARKNUM_FOLDER, scMasterFolder)
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDER, RGB(0, 0, 0))
  
  ScintillaSendMessage(gadget, #SCI_MARKERSETFORE, #SC_MARKNUM_FOLDEROPEN, scMasterFolder)
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDEROPEN, RGB(0, 0, 0))
  
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDEROPENMID, RGB(0, 0, 0))
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERSUB, RGB(0, 0, 0))
  
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERTAIL, RGB(0, 0, 0))
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERMIDTAIL, RGB(0, 0, 0))
  
  ;- Folding : Activation du folding
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 2, #SC_MARGIN_SYMBOL)
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, 1)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  
  ;ScintillaSendMessage(gadget, #SCI_SETPROPERTY, @"fold", @"2")  
  
  ;- Définit les styles
  
  ; Styles : Coloration des mots clés HTML 
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_HTML_Keyword, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_HTML_Keyword, scStyleHTMLKeyWordColor)
  
  ; Style commentaires HTML
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_Comment, scStyleHTMLCommentColor)
  
  ; Styles : Coloration des commentaire JavaScript
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_Comment, scStyleJSCommentColor)
  
  ; Styles : Coloration des mots clés JavaScript
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_KeyWord, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_KeyWord, scStyleJSKeywordColor)
  
EndProcedure

;-

; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)
  Protected textLength
  Protected SciCurrentPos, SciWordStartPos
  Protected curPos, curPos2
  Protected *buf, *buf2
  Protected tag.s   ;Rechercher le tag entre "<" et ">" pour auto-fermeture du tag 
  Protected close.s ;Création du tag de fermeture "</tag>
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(#editor, #SCI_GETLENGTH)
  
  ; Analyser les evenement scintilla
  Select *scn\nmhdr\code
    Case #SCN_CHARADDED 
      ; Un caractére est saisie
      
      Select *scn\ch
        Case 13
          ; Indentation
          ; Vous avez pressé la touche entrée
          
          ; Quel est la position du décalages du texte au niveau de la marge.
          scIndent = ScintillaSendMessage(gadget, #SCI_GETLINEINDENTATION, scLine)
          
          ; Passer à la ligne suivante 
          ; et positionner le curseur 
          ScintillaSendMessage(gadget, #SCI_SETLINEINDENTATION, scLine+1, scIndent)
          
          ; Touche entrée préssée : Le curseur ne passera pas à  la ligne suivante.
          ; Forcer le passage à la ligne en insérant la longueur de #CRLF$
          If scIndent=0 
            scPos = scPos + Len(#CRLF$)
          EndIf
          
          ; Positionner le curseur de saisie 
          ScintillaSendMessage(gadget, #SCI_GOTOPOS, scPos + scIndent)
          
        Case 'a' To 'z', 'A' To 'Z'
          ; Autocomplétion (Affichage d'une liste contenant les mots clés HTML
          ; Affichage du mot selectionné si autocomplétion
          SciCurrentPos = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS)
          SciWordStartPos = ScintillaSendMessage(gadget, #SCI_WORDSTARTPOSITION, SciCurrentPos, 1)
          ScintillaSendMessage(0, #SCI_AUTOCSHOW, SciCurrentPos - SciWordStartPos, MakeUTF8Text(htmlKeyWords))
      
      EndSelect

    Case #SCN_UPDATEUI  
      ; Une mise à jour du gadget Scintilla est effectué 
      
      ; Style & folding UNIQUEMENT si le contenu change
      If *scn\updated & #SC_UPDATE_CONTENT
        ColorizeHTMLTags(gadget, 0, textLength, htmlKeyWords)
        UpdateHTMLFolding(gadget, KeywordsFolding)
      EndIf
      
    Case #SCN_MARGINCLICK
      ; Mise en oeuvre du pliage dépliage (folding)
      ; Clique sur la deuxiéme colonne
      If *scn\margin = 2
       
        ; Ligne réelle à partir de la position du clic
        Protected line = ScintillaSendMessage(gadget, #SCI_LINEFROMPOSITION, *scn\position, 0)
        Protected level = ScintillaSendMessage(gadget, #SCI_GETFOLDLEVEL, line, 0)
        
        ; Autoriser uniquement sur les lignes HEADER
        If level & #SC_FOLDLEVELHEADERFLAG
          ScintillaSendMessage(gadget, #SCI_TOGGLEFOLD, line)
        EndIf
      EndIf      
  EndSelect   
  
  ; Important pour le fonctionnement de l'indentation
  
  ; Trouver la position du curseur de saisie  
  scPos = ScintillaSendMessage(gadget, #SCI_GETANCHOR)
  
  ; Trouver la ligne ou se touve le curseur
  scLine = ScintillaSendMessage(gadget, #SCI_LINEFROMPOSITION, scPos)
  
  ; Trouver la colonne en cours
  scCol = ScintillaSendMessage(gadget, #SCI_GETCOLUMN, scPos)
  
EndProcedure

;-

; Obtenir le texte de la ligne en cours de saisie 
Procedure.s getScintillaLineText(gadget, line)
  Protected lineLength, *buffer, result.s
  
  ; Longueur de la ligne
  lineLength = ScintillaSendMessage(gadget, #SCI_LINELENGTH, line)
  
  ; Initialisation du buffer UTF8
  *buffer = AllocateMemory(lineLength + 1)
   
  If *buffer > 0
    ; Obtenir et renvoyer le contenu de la ligne
    ScintillaSendMessage(gadget, #SCI_GETLINE, line, *buffer)
    result.s = PeekS(*buffer, -1, #PB_UTF8)
    FreeMemory(*buffer)
  EndIf   
  ProcedureReturn result
EndProcedure

; Obtenir le mot (ou texte) se trouvant entre deux positions
Procedure.s getScintillaWord(gadget, startPos, endPos)
  Protected tr.scTextRange, *buffer, length, result.s
  
  length = endPos - startPos
  
  If length > 0
    *buffer = AllocateMemory(length + 1)
    
    tr\chrg\cpMin = startPos
    tr\chrg\cpMax = endPos
    tr\lpstrText  = *buffer
    
    ScintillaSendMessage(gadget, #SCI_GETTEXTRANGE, 0, @tr)
    
    ; Lecture UTF-8 correcte
    result = PeekS(*buffer, -1, #PB_UTF8)
    FreeMemory(*buffer)
  EndIf 
  
  ProcedureReturn result
EndProcedure

; Tester si un mot est un mot clé
Procedure.b isKeyword(word.s, keyWords.s)
  Protected countWords = CountString(keyWords, KeyWordSep), n
  Protected result.b  
  
  For n = 1 To countWords + 1
    If LCase(StringField(keyWords, n, KeyWordSep)) = LCase(word)
      result = #True
    EndIf
  Next
  ProcedureReturn result
EndProcedure

; Tester si un mot trouvé dans un string déclenche le folding
Procedure.b isFoldingKeyWord(text.s, keyWordsfolding.s)
  Protected countWords, n
  Protected result.b  
  
  ; Compter le nombre de mots clés folding contenu dans la variable KeyWordsFolding 
  countWords = CountString(keyWordsfolding, KeyWordSep)
  
  ; Pour chaque mots clé folding
  For n = 1 To countWords + 1
    ; Vérifier que le mot clé se trouve dans dans la chaine reçu
    ; Il doit se trouver au début (Position 1) de la chaine testé (text.s)
    If FindString(LCase(text), LCase(StringField(keyWordsfolding, n, KeyWordSep))) = 1   
      result = #True
    EndIf
  Next
  
  ProcedureReturn result
EndProcedure

; Vérifier que la coloration du code JavaScript se trouve entre les balise <script> </script>
Procedure.b IsInsideScriptBlock(gadget, pos)
  Protected textStart = 0
  Protected textEnd   = pos
  
  Protected text.s = GetScintillaWord(gadget, textStart, textEnd)
  
  Protected openCount = CountString(LCase(text), "<script")
  Protected closeCount = CountString(LCase(text), "</script>")
  
  If openCount > closeCount
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure


;-

; Coloration des mots clés
Procedure ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)
  Protected pos                       ; Position actuelle de l'indice de parcours du string
  Protected lowerTag                  ; Position du prochain "<"
  Protected upperTag                  ; Position du prochain ">"
  Protected tagStart                  ; Premier caractère après "<"
  Protected tagEnd                    ; Fin du nom de la balise sans ">"
  Protected originalTagStart          ; Début logique de la balise (après "<")
  Protected tagName.s                 ; Tag sans balise d'ouverture/fermeture "<tag> -> "tag"
  Protected nameStart                 ; Premier caractère après "<" 
  Protected isClosing                 ; Indicateur de balise fermée
  Protected space                     ; Position d'un espace à l'intérieur de "<" et ">"
  Protected commentStart, commentEnd  ;Position de début et fin d'un commentaire
  
  ; La coloration se fera en plusieurs passage 
  ; - 1 Commentaires
  ; - 2 Tags HTML <tag> </tag>
  
  ; Reset des indicateurs de styles
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_Comment, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)

  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
    
  ;- ■ 1 Pass commentaires <!-- Commentaire -->
  pos = startPos
  
  While pos < endPos
    
    ; Définir le target de recherche
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Rechercher la chaine de début de commentaire "<!--" (Longueur 4)
    commentStart = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 4, commentStartPattern)
    
    ; Il y en a pas, on s'arrete !
    If commentStart = -1 : Break : EndIf
    
    ; Nouveau target de recherche qui commencera aprés "<!--"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, commentStart + 4)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Rechercher la chaine de fin de commentaire "-->" (Longueur 3)
    commentEnd = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 3, commentEndPattern)
    
    If commentEnd <> -1
      commentEnd + 3
    Else
      commentEnd = endPos
    EndIf

    ; colorer le commentaire
    ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_Comment)
    ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)

    pos = commentEnd
  Wend

  ;- ■ 2 Pass tag HTML "<html>" 
  pos = startPos
  
  While pos < endPos
    
    ; Définir le target de recherche
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Chercher le caractére '<' dans la zone de scan 
    lowerTag = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @"<")
    
    ; Il y en a pas. On sort de la boucle
    If lowerTag = -1 : Break : EndIf
    
    ; "<" est trouvé
    ; Nouveau target de recherche qui commencera aprés "<"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, lowerTag + 1) 
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Chercher le prochain '>'
    upperTag = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @">")
    
    If upperTag = -1
      ;ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
      ;ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
      Break
    EndIf
    
    ; Bonne nouvelle nous avons maintenant localisé "<" et ">"
    originalTagStart = lowerTag + 1
    tagStart         = originalTagStart
    
    ; Nouveau target de recherche qui commencera aprés "<" et se termine à ">"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, tagStart)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, upperTag)
    
    ; Recherche du caractéres espace dans las chaine située entre "<" et ">" 
    space = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @" ")
    
    If space = -1
      tagEnd = upperTag
    Else
      tagEnd = space
    EndIf
    
    ; Rechercher le mot situé entre "<" et ">" 
    If tagEnd > tagStart
      tagName = GetScintillaWord(gadget, tagStart, tagEnd)
      isClosing = #False
      nameStart = tagStart
      
      ; Détecter </tag>
      If Left(tagName, 1) = "/"
        isClosing = #True
        tagName  = Mid(tagName, 2)
        nameStart = tagStart + 1
      EndIf
      
      ; Indiquer le début de la coloration  style #Style_HTML_Keyword 
      ; Indiquer la position de débug et fin de la coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword)
      ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, originalTagStart, upperTag - originalTagStart)
      
      ; Coloration de la balise "<" - position de début sur une longueur de 1
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
      
      ; Coloration de "/" si balise fermante - position de début sur une longueur de 1
      If isClosing
        ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, tagStart, 1)
      EndIf
      
      ; Coloration du nom de balise (ouvrante OU fermante) - Exemple html
      If IsKeyword(tagName, keyWords)
        ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, nameStart, tagEnd - nameStart)
      EndIf
            
      ; Coloration de ">" - position de fin sur une longueur de 1
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, upperTag, 1)
    EndIf
    
    ;-■ 3 Coloration JavaScript 
    If IsInsideScriptBlock(gadget, pos)     
      ColorizeJSComments(gadget, startPos, endPos)
      ColorizeJSKeywords(gadget, startPos, endPos)
    EndIf
    
    ; Au suivant ...
    pos = upperTag + 1
  Wend
EndProcedure

; Chercher la fin d'un commentaire 
Procedure SkipJSLineComment(gadget, pos)
  Protected ch
  
  While pos < ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0)
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    If ch = 10 Or ch = 13
      Break
    EndIf
    pos + 1
  Wend
  ProcedureReturn pos
EndProcedure

; Ignorer les blocks de commentaires JavaScript "/* ... */"
Procedure SkipJSBlockComment(gadget, pos)
  pos + 2
  While pos < ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0) - 1
    If ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) = '*' And
       ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '/'
      pos + 2
      Break
    EndIf
    pos + 1
  Wend
  ProcedureReturn pos
EndProcedure

; Colorer les mots clés JavaScript 
Procedure ColorizeJSKeywords(gadget, startPos, endPos)
  Protected pos = startPos
  Protected wordStart, wordEnd, word.s
  Protected ch
  
  ; Reset de la coloration des mots clés JavaScript
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_KeyWord, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
    
  While pos < endPos
    
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        
    ; Ignorer les lignes de commentaires JavaScript "//"
    If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '/'
        pos = SkipJSLineComment(gadget, pos)
      Continue
    EndIf 
    
    ; Ignorer les lignes de bloc de commentaires JavaScript "/* ... */"
    If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '*'
      pos = SkipJSBlockComment(gadget, pos)
      Continue
    EndIf
    
    ; Sauter non-lettres    
    If (ch < 'A' Or ch > 'Z') And (ch < 'a' Or ch > 'z') And ch <> '_'
      pos + 1
      Continue
    EndIf
        
    ; Lire mot
    wordStart = pos
    
    While pos < endPos
      ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
      If (ch >= 'A' And ch <= 'Z') Or (ch >= 'a' And ch <= 'z') Or 
         (ch >= '0' And ch <= '9') Or ch = '_'
        pos + 1
      Else
        Break
      EndIf
    Wend
    
    wordEnd = pos
    word = GetScintillaWord(gadget, wordStart, wordEnd)
    
    If IsKeyword(word, jsKeywords)
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_KeyWord, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, wordStart, wordEnd - wordStart)
    EndIf

  Wend
EndProcedure

; Coloration des commentaires JavaScript
Procedure ColorizeJSComments(gadget, startPos, endPos)
  Protected pos = startPos
  Protected ch, nextCh
  Protected commentStart, commentEnd
  
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)

  
  While pos < endPos - 1
    
    ch     = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
    
    ; // commentaire ligne
    If ch = '/' And nextCh = '/'
      
      commentStart = pos
      
      ; aller jusqu'à fin de ligne ou fin zone
      pos + 2
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        If ch = 10 Or ch = 13   ; LF ou CR
          Break
        EndIf
        pos + 1
      Wend
      
      commentEnd = pos
      
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
      
      Continue
    EndIf
    
    ; /* commentaire bloc */
    If ch = '/' And nextCh = '*'
      
      commentStart = pos
      
      pos + 2
      While pos < endPos - 1
        ch     = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
        If ch = '*' And nextCh = '/'
          pos + 2
          Break
        EndIf
        pos + 1
      Wend
      
      commentEnd = pos
      
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
      
      Continue
    EndIf
    
    pos + 1
  Wend
EndProcedure

;-

; Mettre à jour le folding (Pliage/Dépliage)
Procedure UpdateHTMLFolding(gadget, KeywordsFolding.s)  
  Protected lineCount, i    
  Protected level = 0
  Protected text.s 
  Protected buffer.s
    
  ; Traitement du pliage/depliage 
  ; Ligne par ligne depuis la premiére ligne
  
  ; Obtenir le nombre de lignes
  lineCount = ScintillaSendMessage(gadget, #SCI_GETLINECOUNT, 0, 0)
  
  ; Parcourir les lignes 
  For i = 0 To lineCount - 1
    
    ; Obtenir le texte de la ligne 
    text = GetScintillaLineText(gadget, i)
    
    ; Important : Supprimer #CRLF$
    text = Trim(RemoveString(text, #CRLF$))
    
    ; Supprimer les chaines entourant le déclencheur de folding
    ; Exemples "<html>" -> html ou "</html>" -> html 
    buffer = RemoveString(text, "<")
    buffer = RemoveString(buffer, ">")
    buffer = RemoveString(buffer, "/")
    
    ; Supprimer les espaces encadrant le texte
    buffer = Trim(buffer)
    
    ; Traitement balise de fermeture, on décremente aprés 
    If Bool(Left(text, 2) = "</" And isFoldingKeyWord(buffer, KeywordsFolding)) 
      ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level)
      level - 1
      If level < 0 : level = 0 : EndIf
      Continue
    EndIf
    
    ; Niveau normal
    ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level)
    
    ; Traitement balise ouvrante
    If Bool(Left(text, 1) = "<" And Mid(text, 2, 1) <> "/" And Right(text, 1)=">" And isFoldingKeyWord(buffer, KeywordsFolding))     
      ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level | #SC_FOLDLEVELHEADERFLAG)
      level + 1      
    EndIf
  Next
EndProcedure

;-
;- Utilitaire(s)

; Obtenir un UTF8 d'un string
Procedure MakeUTF8Text(text.s)
  Static buffer.s
  
  buffer = Space(StringByteLength(text, #PB_UTF8) + 1)
  PokeS(@buffer, text, -1, #PB_UTF8)
  ProcedureReturn @buffer
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Amélioration de la version précédente.
La coloration JavaScript doit être exécutée uniquement si on se trouve dans un contexte JavaScript. Ce qui veut dire que le code Javascript doit se trouver entre les balises <script> .... </script>

Le code de la version 1.10 est corrigé.
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Version 1.20 - Auto fermeture des tag.

➡️ Objectif : Vous tapez un tag. Par exemple <html>. Le code va générer automatiquement le tag de fermeture </tag>. Whaouuu c'est génial 🤪

➡️ Le code continue de grossir :
- Ajout de la procédure GetOpeningTagBeforeCaret(Gadget) pour rechercher le tag précédent le curseur de de saisie.

⚠️ l'évènement est géré dans la procédure scintillaCallback()

➡️ Voici le code.

Code : Tout sélectionner

; Web Framework - Trame d'un editeur HTML/JavaScript
; Version 1.20

; PureBasic 6.30 (x64)
; Mise à jour du 1 Février 2026
; Pas d'API & Scintilla natif

; Fonctionnalités
; ===============
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla
; Indentation 
; Autocomplétion
; Coloration des mots clés HTML
; Coloration des commentaires
; Folding (Pliage et dépliage du code)
; Coloration des mots clés Javascript

; Ajout 
; Auto-fermeture des tag <tag> -> </tag> automatique

EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
  #Style_Comment
  #Style_HTML_Keyword
  #Style_JS_Comment
  #Style_JS_KeyWord
EndEnumeration

Define version.s = "1.20"

; Liste des mots clés (C'est un jeu de test)
Global htmlKeyWords.s = "html,head,body,title,script,style,div,canvas,meta,h1,h2,h3,h4,h5,h6,button,p"

; Liste des mots clés Javascript
Global jsKeywords.s = "break,case,catch,class,const,continue,debugger,default,delete,do," +
                      "else,export,extends,finally,for,function,if,import,in,instanceof," +
                      "let,new,return,super,switch,this,throw,try,typeof,var,void,while," +
                      "with,yield,await,enum,implements,interface,package,private," +
                      "protected,public,static,null,true,false,undefined"

; Liste des mots clés déclencheur de pliage/dépliage de code
Global KeywordsFolding.s = "html,head,body,div,section,article,nav,ul,ol,table"

; Séparateur des mots clés
Global KeyWordSep.s = ","

; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50

; Couleurs
Global scFrontColor = RGB(105,105, 105) 
Global scBackColor  = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)
Global scMasterFolder = RGB(255, 0, 0)

; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12

; Couleur des styles par defaut
Global scStyleHTMLKeyWordColor = RGB(255, 0, 0)
Global scStyleHTMLCommentColor = RGB(0, 255, 0)

Global scStyleJSCommentColor = RGB(0, 255, 0)
Global scStyleJSKeywordColor = RGB(0, 0, 205)

; Indentation
Global scIndent, scLine, scPos, scCol

; Pour la recherche des blocs commentaires "<!--" et "-->"
; Ces deux chaines doivent être stockées dans un buffer UTF8
Global commentStartPattern = AllocateMemory(5)
Global commentEndPattern   = AllocateMemory(4)

;- Sommaire des procédures

; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)

; Callback évenementielle du gadget scintilla 
Declare ScintillaCallBack(gadget, *scn.scNotification)

; Obtenir le texte de la ligne en cours de saisie 
Declare.s GetScintillaLineText(gadget, line)

; Obtenir le mot se trouvant entre deux position
Declare.s getScintillaWord(gadget, startPos, endPos)

; Tester si un mot est un mot clé
Declare.b isKeyword(word.s, keyWords.s)

; 
Declare.s GetOpeningTagBeforeCaret(gadget)

; Tester si un mot est une clé de pliage
Declare.b isFoldingKeyWord(word.s, keyWordfoldingDown.s)

; Vérifier que la coloration du code JavaScript se trouve entre les balise <script> </script>
Declare.b IsInsideScriptBlock(gadget, pos)

; Coloration des mots clés HTML
Declare ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)

; Ignorer les lignes de commentaires JavaScript "//"
Declare SkipJSLineComment(gadget, pos)

; Ignorer les blocs de commentaires JavaScript "/* .. */"
Declare SkipJSBlockComment(gadget, pos)

; Coloration des commentaires JavaScripts
Declare ColorizeJSComments(gadget, startPos, endPos)

; Coloration des mots clés JavaScript
Declare ColorizeJSKeywords(gadget, startPos, endPos)

; Mettre à jour le pliage/dépliage
Declare UpdateHTMLFolding(gadget, KeywordsFolding.s) 

; Texte au format UTF8
Declare MakeUTF8Text(text.s)

;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)

AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)  
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)

; Editeur Scintilla gadget associé à un callback 
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())

;- Parametres Scintilla (Couleur, font, numerotation, style,  etc ...)
ScintillaProperties(#editor)

; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)

; "<!--" et "-->" convertis au format UTF8
PokeS(commentStartPattern, "<!--", -1, #PB_UTF8)
PokeS(commentEndPattern,   "-->",  -1, #PB_UTF8)

;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow

;-
;- Liste des procédures

; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
  ;- 1 Style par défaut
  ; Couleur et police de caractéres
  ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
  ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
  
  ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont) 
  ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
  
  ;- 2 Propager vers tous les styles
  ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
  
  ;- 3 Définir des styles spécifiques
  ; Activation et couleur de la ligne en cours d'édition
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
  ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
  
  ; Les tabulations sont remplacées par des espaces 
  ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
  
  ; Nombre d'espaces pour une tabulation
  ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
  
  ; Création de la colonne de numérotation des lignes
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER) 
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
  
  ; Autocomplétion : Parametres de la liste des mots clés 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXHEIGHT, 40)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXWIDTH, 150)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETAUTOHIDE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETCHOOSESINGLE, #True)
  ScintillaSendMessage(gadget, #SCI_AUTOCSETIGNORECASE, #True)
  
  ; Autocomplétion : Caractére séparant chaque mot de la liste des mots clés
  ScintillaSendMessage(gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
  
  ; Autocomplétion : Caractére sélectionnant le mot de la liste d'autocomplétion
  ScintillaSendMessage(gadget, #SCI_AUTOCSETFILLUPS, 0, @" ")
  
  ; Autocomplétion : Tri de la liste 
  ScintillaSendMessage(gadget, #SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT) 
  
  ; Folding : Création de la colonne de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)
  
  ; Folding : Choix des icones de pliages du code 5
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEROPEN, #SC_MARK_CIRCLEMINUS) 
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDER, #SC_MARK_CIRCLEPLUS)
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERSUB, #SC_MARK_VLINE) ;Ligne verticale
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERTAIL, #SC_MARK_LCORNERCURVE) ;fin arborescence
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEREND, #SC_MARK_CIRCLEPLUSCONNECTED) ;Dépliage
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEROPENMID, #SC_MARK_CIRCLEMINUSCONNECTED) ;Pliage
  ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERMIDTAIL, #SC_MARK_TCORNERCURVE)
  
  ; Folding : Couleur des icones de pliages/dépliage
  ScintillaSendMessage(gadget, #SCI_MARKERSETFORE, #SC_MARKNUM_FOLDER, scMasterFolder)
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDER, RGB(0, 0, 0))
  
  ScintillaSendMessage(gadget, #SCI_MARKERSETFORE, #SC_MARKNUM_FOLDEROPEN, scMasterFolder)
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDEROPEN, RGB(0, 0, 0))
  
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDEROPENMID, RGB(0, 0, 0))
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERSUB, RGB(0, 0, 0))
  
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERTAIL, RGB(0, 0, 0))
  ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERMIDTAIL, RGB(0, 0, 0))
  
  ;- Folding : Activation du folding
  ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 2, #SC_MARGIN_SYMBOL)
  ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
  ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, 1)
  ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
  
  ;ScintillaSendMessage(gadget, #SCI_SETPROPERTY, @"fold", @"2")  
  
  ;- Définit les styles
  
  ; Styles : Coloration des mots clés HTML 
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_HTML_Keyword, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_HTML_Keyword, scStyleHTMLKeyWordColor)
  
  ; Style commentaires HTML
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_Comment, scStyleHTMLCommentColor)
  
  ; Styles : Coloration des commentaire JavaScript
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_Comment, scStyleJSCommentColor)

  ; Syles : Coloration des mots clés JavaScript
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_KeyWord, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_KeyWord, scStyleJSKeywordColor)
  
EndProcedure

;-

; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)
  Protected textLength
  Protected SciCurrentPos, SciWordStartPos
  Protected curPos, curPos2
  Protected *buf, *buf2
  Protected tag.s   ;Rechercher le tag entre "<" et ">" pour auto-fermeture du tag 
  Protected close.s ;Création du tag de fermeture "</tag>
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(#editor, #SCI_GETLENGTH)
  
  ; Analyser les evenement scintilla
  Select *scn\nmhdr\code
    Case #SCN_CHARADDED 
      ; Un caractére est saisie
      
      Select *scn\ch
        Case 13
          ;- Indentation
          ; Vous avez pressé la touche entrée
          
          ; Quel est la position du décalages du texte au niveau de la marge.
          scIndent = ScintillaSendMessage(gadget, #SCI_GETLINEINDENTATION, scLine)
          
          ; Passer à la ligne suivante 
          ; et positionner le curseur 
          ScintillaSendMessage(gadget, #SCI_SETLINEINDENTATION, scLine+1, scIndent)
          
          ; Touche entrée préssée : Le curseur ne passera pas à  la ligne suivante.
          ; Forcer le passage à la ligne en insérant la longueur de #CRLF$
          If scIndent=0 
            scPos = scPos + Len(#CRLF$)
          EndIf
          
          ; Positionner le curseur de saisie 
          ScintillaSendMessage(gadget, #SCI_GOTOPOS, scPos + scIndent)
          
        Case 'a' To 'z', 'A' To 'Z'
          ;- Autocomplétion (Affichage d'une liste contenant les mots clés HTML
          ; Affichage du mot selectionné si autocomplétion
          SciCurrentPos = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS)
          SciWordStartPos = ScintillaSendMessage(gadget, #SCI_WORDSTARTPOSITION, SciCurrentPos, 1)
          ScintillaSendMessage(0, #SCI_AUTOCSHOW, SciCurrentPos - SciWordStartPos, MakeUTF8Text(htmlKeyWords))
          
        Case  '>'
          ;- Auto fermeture de tag <tag>|</tag>
          
          ; Obtenir le tag de fermeture
          tag = GetOpeningTagBeforeCaret(gadget)
          
          If tag <> ""
            
            curPos2 = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS, 0, 0)
            close = "</" + tag + ">"
            
            *buf2 = AllocateMemory(StringByteLength(close, #PB_UTF8) + 1)
            PokeS(*buf2, close, -1, #PB_UTF8)
            
            ScintillaSendMessage(gadget, #SCI_INSERTTEXT, curPos2, *buf2)
            FreeMemory(*buf2)
            
            ; On ne modidie pas la position du curseur.
            ; Il est positionné entre le tag d'ouverture et le tag de fermeture
          EndIf      
      EndSelect
      
    Case #SCN_UPDATEUI  
      ; Une mise à jour du gadget Scintilla est effectué 
      
      ; Style & folding UNIQUEMENT si le contenu change
      If *scn\updated & #SC_UPDATE_CONTENT
        ColorizeHTMLTags(gadget, 0, textLength, htmlKeyWords)
        UpdateHTMLFolding(gadget, KeywordsFolding)
      EndIf
      
    Case #SCN_MARGINCLICK
      ; Mise en oeuvre du pliage dépliage (folding)
      ; Clique sur la deuxiéme colonne
      If *scn\margin = 2
        
        ; Ligne réelle à partir de la position du clic
        Protected line = ScintillaSendMessage(gadget, #SCI_LINEFROMPOSITION, *scn\position, 0)
        Protected level = ScintillaSendMessage(gadget, #SCI_GETFOLDLEVEL, line, 0)
        
        ; Autoriser uniquement sur les lignes HEADER
        If level & #SC_FOLDLEVELHEADERFLAG
          ScintillaSendMessage(gadget, #SCI_TOGGLEFOLD, line)
        EndIf
      EndIf      
  EndSelect   
  
  ; Important pour le fonctionnement de l'indentation
  
  ; Trouver la position du curseur de saisie  
  scPos = ScintillaSendMessage(gadget, #SCI_GETANCHOR)
  
  ; Trouver la ligne ou se touve le curseur
  scLine = ScintillaSendMessage(gadget, #SCI_LINEFROMPOSITION, scPos)
  
  ; Trouver la colonne en cours
  scCol = ScintillaSendMessage(gadget, #SCI_GETCOLUMN, scPos)
  
EndProcedure

;-

; Obtenir le texte de la ligne en cours de saisie 
Procedure.s getScintillaLineText(gadget, line)
  Protected lineLength, *buffer, result.s
  
  ; Longueur de la ligne
  lineLength = ScintillaSendMessage(gadget, #SCI_LINELENGTH, line)
  
  ; Initialisation du buffer UTF8
  *buffer = AllocateMemory(lineLength + 1)
  
  If *buffer > 0
    ; Obtenir et renvoyer le contenu de la ligne
    ScintillaSendMessage(gadget, #SCI_GETLINE, line, *buffer)
    result.s = PeekS(*buffer, -1, #PB_UTF8)
    FreeMemory(*buffer)
  EndIf   
  ProcedureReturn result
EndProcedure

; Obtenir le mot (ou texte) se trouvant entre deux positions
Procedure.s getScintillaWord(gadget, startPos, endPos)
  Protected tr.scTextRange, *buffer, length, result.s
  
  length = endPos - startPos
  
  If length > 0
    *buffer = AllocateMemory(length + 1)
    
    tr\chrg\cpMin = startPos
    tr\chrg\cpMax = endPos
    tr\lpstrText  = *buffer
    
    ScintillaSendMessage(gadget, #SCI_GETTEXTRANGE, 0, @tr)
    
    ; Lecture UTF-8 correcte
    result = PeekS(*buffer, -1, #PB_UTF8)
    FreeMemory(*buffer)
  EndIf 
  
  ProcedureReturn result
EndProcedure

; Tester si un mot est un mot clé
Procedure.b isKeyword(word.s, keyWords.s)
  Protected countWords = CountString(keyWords, KeyWordSep), n
  Protected result.b  
  
  For n = 1 To countWords + 1
    If LCase(StringField(keyWords, n, KeyWordSep)) = LCase(word)
      result = #True
    EndIf
  Next
  ProcedureReturn result
EndProcedure

; Rechercher le tag précédent le curseur de saisie
Procedure.s GetOpeningTagBeforeCaret(gadget)
  Protected curPos, startPos, endPos, text.s, name.s, i, ch
  
  ; Déterminer la position du curseur
  curPos = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS, 0, 0)
  startPos = curPos - 2   ; juste avant '>'
  
  If startPos < 0 : ProcedureReturn "" : EndIf
  
  ; Remonter jusqu'à '<'
  For i = startPos To 0 Step -1
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, i, 0)
    If ch = '<'
      startPos = i
      Break
    EndIf
  Next
  
  If ch <> '<' : ProcedureReturn "" : EndIf
  
  ; lire le contenu <...>
  endPos = curPos - 1
  text = GetScintillaWord(gadget, startPos, endPos)
  text = Trim(text)
  
  ; Rejeter </tag> et <br/>
  If Left(text, 2) = "</" : ProcedureReturn "" : EndIf
  If Right(text, 2) = "/>" : ProcedureReturn "" : EndIf
  
  ; Extraire nom après '<'
  For i = 2 To Len(text)
    ch = Asc(Mid(text, i, 1))
    If (ch >= 'a' And ch <= 'z') Or (ch >= 'A' And ch <= 'Z') Or
       (ch >= '0' And ch <= '9') Or ch = '-' Or ch = '_'
      name + Chr(ch)
    Else
      Break
    EndIf
  Next
  
  ProcedureReturn name
EndProcedure


; Tester si un mot trouvé dans un string déclenche le folding
Procedure.b isFoldingKeyWord(text.s, keyWordsfolding.s)
  Protected countWords, n
  Protected result.b  
  
  ; Compter le nombre de mots clés folding contenu dans la variable KeyWordsFolding 
  countWords = CountString(keyWordsfolding, KeyWordSep)
  
  ; Pour chaque mots clé folding
  For n = 1 To countWords + 1
    ; Vérifier que le mot clé se trouve dans dans la chaine reçu
    ; Il doit se trouver au début (Position 1) de la chaine testé (text.s)
    If FindString(LCase(text), LCase(StringField(keyWordsfolding, n, KeyWordSep))) = 1   
      result = #True
    EndIf
  Next
  
  ProcedureReturn result
EndProcedure

Procedure.b IsInsideScriptBlock(gadget, pos)
  Protected textStart = 0
  Protected textEnd   = pos
  
  Protected text.s = GetScintillaWord(gadget, textStart, textEnd)
  
  Protected openCount = CountString(LCase(text), "<script")
  Protected closeCount = CountString(LCase(text), "</script>")
  
  If openCount > closeCount
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure


;-

; Coloration des mots clés
Procedure ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)
  Protected pos                       ; Position actuelle de l'indice de parcours du string
  Protected lowerTag                  ; Position du prochain "<"
  Protected upperTag                  ; Position du prochain ">"
  Protected tagStart                  ; Premier caractère après "<"
  Protected tagEnd                    ; Fin du nom de la balise sans ">"
  Protected originalTagStart          ; Début logique de la balise (après "<")
  Protected tagName.s                 ; Tag sans balise d'ouverture/fermeture "<tag> -> "tag"
  Protected nameStart                 ; Premier caractère après "<" 
  Protected isClosing                 ; Indicateur de balise fermée
  Protected space                     ; Position d'un espace à l'intérieur de "<" et ">"
  Protected commentStart, commentEnd  ;Position de début et fin d'un commentaire
  
  ; La coloration se fera en plusieurs passage 
  ; - 1 Commentaires
  ; - 2 Tags HTML <tag> </tag>
  
  ; Reset des indicateurs de styles
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_Comment, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
  
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
  
  ;- ■ 1 Pass commentaires <!-- Commentaire -->
  pos = startPos
  
  While pos < endPos
    
    ; Définir le target de recherche
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Rechercher la chaine de début de commentaire "<!--" (Longueur 4)
    commentStart = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 4, commentStartPattern)
    
    ; Il y en a pas, on s'arrete !
    If commentStart = -1 : Break : EndIf
    
    ; Nouveau target de recherche qui commencera aprés "<!--"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, commentStart + 4)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Rechercher la chaine de fin de commentaire "-->" (Longueur 3)
    commentEnd = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 3, commentEndPattern)
    
    If commentEnd <> -1
      commentEnd + 3
    Else
      commentEnd = endPos
    EndIf
    
    ; colorer le commentaire
    ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_Comment)
    ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
    
    pos = commentEnd
  Wend
  
  ;- ■ 2 Pass tag HTML "<html>" 
  pos = startPos
  
  While pos < endPos
    
    ; Définir le target de recherche
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Chercher le caractére '<' dans la zone de scan 
    lowerTag = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @"<")
    
    ; Il y en a pas. On sort de la boucle
    If lowerTag = -1 : Break : EndIf
    
    ; "<" est trouvé
    ; Nouveau target de recherche qui commencera aprés "<"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, lowerTag + 1) 
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
    
    ; Chercher le prochain '>'
    upperTag = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @">")
    
    If upperTag = -1
      ;ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
      ;ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
      Break
    EndIf
    
    ; Bonne nouvelle nous avons maintenant localisé "<" et ">"
    originalTagStart = lowerTag + 1
    tagStart         = originalTagStart
    
    ; Nouveau target de recherche qui commencera aprés "<" et se termine à ">"
    ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, tagStart)
    ScintillaSendMessage(gadget, #SCI_SETTARGETEND, upperTag)
    
    ; Recherche du caractéres espace dans las chaine située entre "<" et ">" 
    space = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @" ")
    
    If space = -1
      tagEnd = upperTag
    Else
      tagEnd = space
    EndIf
    
    ; Rechercher le mot situé entre "<" et ">" 
    If tagEnd > tagStart
      tagName = GetScintillaWord(gadget, tagStart, tagEnd)
      isClosing = #False
      nameStart = tagStart
      
      ; Détecter </tag>
      If Left(tagName, 1) = "/"
        isClosing = #True
        tagName  = Mid(tagName, 2)
        nameStart = tagStart + 1
      EndIf
      
      ; Indiquer le début de la coloration  style #Style_HTML_Keyword 
      ; Indiquer la position de débug et fin de la coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword)
      ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, originalTagStart, upperTag - originalTagStart)
      
      ; Coloration de la balise "<" - position de début sur une longueur de 1
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
      
      ; Coloration de "/" si balise fermante - position de début sur une longueur de 1
      If isClosing
        ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, tagStart, 1)
      EndIf
      
      ; Coloration du nom de balise (ouvrante OU fermante) - Exemple html
      If IsKeyword(tagName, keyWords)
        ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, nameStart, tagEnd - nameStart)
      EndIf
      
      ; Coloration de ">" - position de fin sur une longueur de 1
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, upperTag, 1)
    EndIf
    
    ;-■ 3 Coloration JavaScript
    
    If IsInsideScriptBlock(gadget, pos)
      ColorizeJSComments(gadget, startPos, endPos)      
      ColorizeJSKeywords(gadget, startPos, endPos)
    EndIf
    
    ; AU suivant ...
    pos = upperTag + 1
  Wend
EndProcedure


; Chercher la fin d'un commentaire 
Procedure SkipJSLineComment(gadget, pos)
  Protected ch
  
  While pos < ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0)
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    If ch = 10 Or ch = 13
      Break
    EndIf
    pos + 1
  Wend
  ProcedureReturn pos
EndProcedure

; Ignorer les blocks de commentaires JavaScript "/* ... */"
Procedure SkipJSBlockComment(gadget, pos)
  pos + 2
  While pos < ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0) - 1
    If ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) = '*' And
       ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '/'
      pos + 2
      Break
    EndIf
    pos + 1
  Wend
  ProcedureReturn pos
EndProcedure

; Colorer les mots clés JavaScript 
Procedure ColorizeJSKeywords(gadget, startPos, endPos)
  Protected pos = startPos
  Protected wordStart, wordEnd, word.s
  Protected ch
  
  ; Reset de la coloration des mots clés JavaScript
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_KeyWord, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
    
  While pos < endPos
    
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        
    ; Ignorer les lignes de commentaires JavaScript "//"
    If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '/'
        pos = SkipJSLineComment(gadget, pos)
      Continue
    EndIf 
    
    ; Ignorer les lignes de bloc de commentaires JavaScript "/* ... */"
    If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '*'
      pos = SkipJSBlockComment(gadget, pos)
      Continue
    EndIf
    
    ; Sauter non-lettres    
    If (ch < 'A' Or ch > 'Z') And (ch < 'a' Or ch > 'z') And ch <> '_'
      pos + 1
      Continue
    EndIf
        
    ; Lire mot
    wordStart = pos
    
    While pos < endPos
      ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
      If (ch >= 'A' And ch <= 'Z') Or (ch >= 'a' And ch <= 'z') Or 
         (ch >= '0' And ch <= '9') Or ch = '_'
        pos + 1
      Else
        Break
      EndIf
    Wend
    
    wordEnd = pos
    word = GetScintillaWord(gadget, wordStart, wordEnd)
    
    If IsKeyword(word, jsKeywords)
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_KeyWord, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, wordStart, wordEnd - wordStart)
    EndIf

  Wend
EndProcedure

; Coloration des commentaires JavaScript
Procedure ColorizeJSComments(gadget, startPos, endPos)
  Protected pos = startPos
  Protected ch, nextCh
  Protected commentStart, commentEnd
  
  ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
  ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)

  
  While pos < endPos - 1
    
    ch     = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
    
    ; // commentaire ligne
    If ch = '/' And nextCh = '/'
      
      commentStart = pos
      
      ; aller jusqu'à fin de ligne ou fin zone
      pos + 2
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        If ch = 10 Or ch = 13   ; LF ou CR
          Break
        EndIf
        pos + 1
      Wend
      
      commentEnd = pos
      
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
      
      Continue
    EndIf
    
    ; /* commentaire bloc */
    If ch = '/' And nextCh = '*'
      
      commentStart = pos
      
      pos + 2
      While pos < endPos - 1
        ch     = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
        If ch = '*' And nextCh = '/'
          pos + 2
          Break
        EndIf
        pos + 1
      Wend
      
      commentEnd = pos
      
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
      
      Continue
    EndIf
    
    pos + 1
  Wend
EndProcedure

;-

; Mettre à jour le folding (Pliage/Dépliage)
Procedure UpdateHTMLFolding(gadget, KeywordsFolding.s)  
  Protected lineCount, i    
  Protected level = 0
  Protected text.s 
  Protected buffer.s
  
  ; Traitement du pliage/depliage 
  ; Ligne par ligne depuis la premiére ligne
  
  ; Obtenir le nombre de lignes
  lineCount = ScintillaSendMessage(gadget, #SCI_GETLINECOUNT, 0, 0)
  
  ; Parcourir les lignes 
  For i = 0 To lineCount - 1
    
    ; Obtenir le texte de la ligne 
    text = GetScintillaLineText(gadget, i)
    
    ; Important : Supprimer #CRLF$
    text = Trim(RemoveString(text, #CRLF$))
    
    ; Supprimer les chaines entourant le déclencheur de folding
    ; Exemples "<html>" -> html ou "</html>" -> html 
    buffer = RemoveString(text, "<")
    buffer = RemoveString(buffer, ">")
    buffer = RemoveString(buffer, "/")
    
    ; Supprimer les espaces encadrant le texte
    buffer = Trim(buffer)
    
    ; Traitement balise de fermeture, on décremente aprés 
    If Bool(Left(text, 2) = "</" And isFoldingKeyWord(buffer, KeywordsFolding)) 
      ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level)
      level - 1
      If level < 0 : level = 0 : EndIf
      Continue
    EndIf
    
    ; Niveau normal
    ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level)
    
    ; Traitement balise ouvrante
    If Bool(Left(text, 1) = "<" And Mid(text, 2, 1) <> "/" And Right(text, 1)=">" And isFoldingKeyWord(buffer, KeywordsFolding))     
      ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level | #SC_FOLDLEVELHEADERFLAG)
      level + 1      
    EndIf
  Next
EndProcedure

;-
;- Utilitaire(s)

; Obtenir un UTF8 d'un string
Procedure MakeUTF8Text(text.s)
  Static buffer.s
  
  buffer = Space(StringByteLength(text, #PB_UTF8) + 1)
  PokeS(@buffer, text, -1, #PB_UTF8)
  ProcedureReturn @buffer
EndProcedure



Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Mindphazer
Messages : 729
Inscription : mer. 24/août/2005 10:42

Re: WebBase HTML CSS Javascript

Message par Mindphazer »

Salut falsam
ça commence à prendre une belle tournure, bravo !
Et, juste pour info, ça tourne très bien sur MacOS :mrgreen:
Bureau : Win11 64bits
Maison : Macbook Pro M4 16" SSD 512 Go / Ram 24 Go - iPad Air 128 Go (pour madame) - iPhone 17 Pro Max 256 Go
Avatar de l’utilisateur
falsam
Messages : 7382
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: WebBase HTML CSS Javascript

Message par falsam »

Mindphazer a écrit : dim. 01/févr./2026 12:28 Salut falsam
ça commence à prendre une belle tournure, bravo !
Et, juste pour info, ça tourne très bien sur MacOS :mrgreen:
Merci pour ce retour. Je pense que ça doit aussi fonctionner sous Linux. Pas d'API, pas de bibliothèque externe et que du natif PureBasic.

Est ce que tu codes en Javascript ?
Configuration : Windows 11 Famille 64-bit - PB 6.23 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Répondre