WebBase HTML CSS Javascript

Partagez votre expérience de PureBasic avec les autres utilisateurs.
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 : dim. 01/févr./2026 14:14 Est ce que tu codes en Javascript ?
Pas trop non
Je bidouille 2-3 trucs en Spiderbasic (sans licence, juste la version démo), y'a quelques infos intéressantes sur le forum Spider, notamment des intégrations de code JS dans SpiderBasic, mais ça va pas plus loin pour le moment

Mais toi oui, il me semble ?
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 : Mais toi oui, il me semble ?
Oui je code aussi avec JavaScript. Ayant un casque de réalité virtuelle ma codification du moment est de tester la réalité virtuelle avec le framework Babylon.js.
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
Kwai chang caine
Messages : 7005
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: WebBase HTML CSS Javascript

Message par Kwai chang caine »

Ayai !!! comme promis à l'allumage de mon PC, la première chose que j'ai fait c'est essayer ton super code 8)
Je voulais dors et déjà te dire que rien que tes beaux POSTS bien rangés avec des jolis flèches bleus (pas un poil qui dépasse 8O) donnent envie de voir le reste :wink:
Quand on regarde ton code, on est pas déçu, c'est du même acabit....ça doit être drôlement bien rangé chez toi :mrgreen:

Je vois que tu as fait le choix de ne pas traiter les 4 langages en même temps, j'ai pas vu le PHP et le CSS
Parce que l'imbrication c'est quelque chose, je me mords les .....avec cette daube, y'a pas idée d'être dans du JS qui est lui même dans du PHP, qui à son tour est dans du HTML qui peut contenir du CSS en ligne(J'l'aime bien celui là, c'est ce vieux format que j'utilise dans mes sites) :twisted:

On sent vraiment que le langage WEB, c'est des gluttes de langages qui ont été ajoutées les un après les autres, au fur et à mesure des innovations, pour faire maintenant un gros fatras de codes entremêlés et illisibles :twisted:
Ils auraient mieux fait de créer un nouveau HTML qui comprends tout dedans, coté front et backend, ce serait beaucoup plus lisible et moins buggy :cry: Quand tu pense que le JS est aussi désormais et depuis un certain temps dans le backend 8O je m'en tripote d'avance :lol:
Je pense que celui qui arrive au bout de ce genre de code, n'a plus peur de rien avec Scintilla, d'ailleurs même l'AI m'a dit qu'aucun éditeur WEB professionnel ne pouvait reconnaitre tous les cas tordus possibles que certains cerveaux malades peuvent imposer aux navigateurs en codant comme leurs pieds :? (Enfin c'est pas tout à fait les mots qu'il a donné :mrgreen: )

En tout cas...bravo, j'attends la suite avec impatience, et je vais quand même essayer de continuer le miens bien que je n'ai pas beaucoup d'espoir :oops:
Dernière modification par Kwai chang caine le dim. 01/févr./2026 17:15, modifié 7 fois.
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel
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.30 - C'est au tour du code CSS d'être colorer.

➡️ Objectif :
Colorer les sélecteurs CSS,
Colorer les propriétés CSS,
Colorer les valeurs CSS,
Colorer les nombres CSS,
Colorer les string CSS,
Colorer les commentaire CSS,
Colorer la ponctuation CSS,

Vous allez peut être me dire que j'en fais un peu trop ? OUiiiiiiiii vous avez raison 🤪

➡️ Pour réaliser cet objectif j'ai ajouter deux procédures :
- Ajout de quelques mots CSS dans les variables cssProperties.s et cssValues.s
- Ajout des propriétés de style CSS dans la procédure ScintillaProperties()
- GetCSSRange(gadget, *start.Integer, *end.Integer) pour connaitre le début et la fin de la section <style> </style>.
- Procedure ColorizeCSS(gadget, startPos, endPos) pour la coloration des mots clés CSS


La coloration CSS est exécutée dans la procédure scintillaCallBack() lors de la détection de l'évènement #SCN_UPDATEUI.

➡️ Code incluant la coloration CSS.

Code : Tout sélectionner

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

; 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
; Auto-fermeture des tag <tag> -> </tag> automatique

; Ajout
; Coloration CSS

EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
  #Style_Comment
  #Style_HTML_Keyword
  
  #Style_JS_Comment
  #Style_JS_KeyWord
  
  #Style_CSS_Selector
  #Style_CSS_Property
  #Style_CSS_Value
  #Style_CSS_Number
  #Style_CSS_String
  #Style_CSS_Comment
  #Style_CSS_Punct
EndEnumeration

Define version.s = "1.30"

; 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 (C'est un jeu de test)
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 (C'est un jeu de test)
Global KeywordsFolding.s = "html,head,body,div,section,article,nav,ul,ol,table"

; Liste des mots clés CSS propriétés (C'est un jeu de test)
Global cssProperties.s = "color,background,background-color,margin,padding,width,height,display," + 
                         "position,top,left,right,bottom,font-size,font-family,border,border-radius," + 
                         "box-shadow,opacity,z-index|overflow,text-align,line-height"

; Liste des mots clé CSS valeur (C'est un jeu de test)
Global cssValues.s = "auto,inherit,initial,unset,none,block,inline,flex,grid,absolute,relative,fixed," + 
                     "sticky,solid,dashed,center,cover,contain,Repeat,no-Repeat,bold,italic,hidden,visible," +
                     "lightblue,white,silver,gray,black,red,maroon,yellow,olive,lime,aqua,teal,blue,navy,fuchsia,purple"


; 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 scStyleHTMLCommentColot = RGB(0, 255, 0)

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

Global scStyleCSSKeywordColor = RGB(0, 0, 205)
Global scStyleCSSProperty = RGB(0, 120, 255)
Global scStyleCSSValue = RGB(0, 170, 120)

; 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)
  
Global commentCSSStartPattern = AllocateMemory(5)
Global commentCSSEndPattern   = 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)

; Déterminer le string précédent le curseur de saisie
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 mots clés JavaScript
Declare ColorizeJSKeywords(gadget, startPos, endPos)

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

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

; Retourne les positions de début et fin du code CSS
Declare GetCSSRange(gadget, *start.Integer, *end.Integer)

; Colorer des mots clés CSS
Declare ColorizeCSS(gadget, startPos, endPos)

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

PokeS(commentCSSStartPattern, "/*", -1, #PB_UTF8)
PokeS(commentCSSEndPattern,   "*/",  -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, scStyleHTMLCommentColot)
  
  ; 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 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)
  
  
  ; Styles : Sélecteurs CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Selector, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Selector, scStyleCSSKeywordColor)
  
  ; Syles : Propriétés CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Property, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Property, scStyleCSSProperty)
  
  ; Styles : Valeurs CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Value, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Value, RGB(0, 170, 120))
  
  ; Styles : Nombres CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Number, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Number, RGB(0, 200, 200))
  
  ; Styles : Strings CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_String, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_String, RGB(180, 0, 180))
  
  ; Styles : Commentaires CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Comment, RGB(0, 150, 0))
  
  ; Styles : Ponctuation CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Punct, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Punct, RGB(200, 200, 0))
  
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>
  
  Protected cssStart, cssEnd ; Ou commence et se termine la déclaration du code CSS
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(gadget, #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
        ; Coloration HTML et Javascript
        ColorizeHTMLTags(gadget, 0, textLength, htmlKeyWords)
                
        ; Coloration CSS
        GetCSSRange(gadget, @cssStart, @cssEnd)       
        If cssStart <> -1 And cssEnd > cssStart
          ColorizeCSS(gadget, cssStart, cssEnd)
        EndIf
        
        ; Folding
        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

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


;- CSS

; Retourne les positions de début et fin du code CSS
Procedure GetCSSRange(gadget, *start.Integer, *end.Integer)
  
  Protected textLen = ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0)
  Protected pos = 0
  Protected inStyle = #False
  Protected cssStart = -1
  Protected cssEnd   = -1
  Protected word.s
  
  While pos < textLen
    
    If ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) = '<'
      
      word = LCase(GetScintillaWord(gadget, pos + 1, pos + 20))
      
      If FindString(word, "style") And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) <> '/'
        inStyle = #True
        cssStart = pos
        
        ; avancer après >
        While pos < textLen And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) <> '>'
          pos + 1
        Wend
        
        cssStart = pos + 1
      EndIf
      
      If FindString(word, "/style")
        cssEnd = pos
        
        *start\i = cssStart
        *end\i   = cssEnd
        ProcedureReturn
      EndIf
    EndIf
    
    pos + 1
  Wend
  
  *start\i = -1
  *end\i   = -1
  
EndProcedure


; Colorater les mots clés CSS
Procedure ColorizeCSS(gadget, startPos, endPos)
  Protected pos = startPos
  Protected ch, start, word.s
  Protected inSelector = #True
  Protected inBlock = #False
  Protected commentEnd
  Protected quote
  
  While pos < endPos
    
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    
    ; Commentaire CSS
    
    ; Recherche début de commentaire CSS "/*"
    If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '*'      
      ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos + 2)
      ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
      
      ; Recherche fin de commentaire CSS "*/
      commentEnd = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 2, commentCSSEndPattern)
      
      If commentEnd = -1
        commentEnd = endPos
      Else
        commentEnd + 2
      EndIf
      
      ; Invocation du style commentaire et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Comment)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, pos, commentEnd - pos)
      
      pos = commentEnd
      Continue
    EndIf
    
    ; String CSS
    If ch = 34 Or ch = 39   ; tester " ou '
      quote = ch
      start = pos
      pos + 1
      
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        
        ; fermeture non échappée
        If ch = quote And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos - 1, 0) <> 92
          pos + 1
          Break
        EndIf
        
        pos + 1
      Wend
      
      ; Invocation du style sting et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_String, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
      Continue
    EndIf
    
    
    ; Accolades / ponctuation
    If ch = '{' Or ch = '}' Or ch = ':' Or ch = ';'
      
      ; Invocation du style punctuation et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Punct, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, pos, 1)
      
      If ch = '{'
        inBlock = #True
        inSelector = #False
      ElseIf ch = '}'
        inBlock = #False
        inSelector = #True
      EndIf
      
      pos + 1
      Continue
    EndIf
    
    ; Nombre CSS
    If (ch >= '0' And ch <= '9')
      
      start = pos
      pos + 1
      
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        If Not ((ch >= '0' And ch <= '9') Or ch = '.' Or ch = '%' Or (ch >= 'a' And ch <= 'z'))
          Break
        EndIf
        pos + 1
      Wend
      
      ; Invocation du style nombre et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Number, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
      Continue
    EndIf
    
    ; Identifiant CSS
    If (ch >= 'a' And ch <= 'z') Or (ch >= 'A' And ch <= 'Z') Or ch = '.' Or ch = '#'
      
      start = pos
      pos + 1
      
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        If Not ((ch >= 'a' And ch <= 'z') Or (ch >= 'A' And ch <= 'Z') Or ch = '-' Or (ch >= '0' And ch <= '9'))
          Break
        EndIf
        pos + 1
      Wend
      
      word = LCase(GetScintillaWord(gadget, start, pos))
      
      If inSelector
        
        ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Selector, 0)
        ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
        
      Else
        
        If isKeyword(word, cssProperties)
          ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Property, 0)
          ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
          
        ElseIf iskeyword(word, cssvalues)
          ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Value, 0)
          ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
        EndIf
        
      EndIf
      
      Continue
    EndIf
    
    pos + 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


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 me suis aperçu que la gestion des commentaires Javascript était pas correct.
Si un mot clé JavaScript se trouvait dans les commentaires, il était coloré avec le style Javascript.

Les versions 1.10, 1.20 et 1.30 sont corrigées.
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.40 - Quelques colorations supplémentaires.

➡️ Objectif :
Coloration des nombres
Coloration des strings entre guillemets
Coloration des brackets
Coloration des parenthèses


➡️ Quels sont les ajouts effectués :
- Ajout des propriétés de style dans la procédure ScintillaProperties()
#Style_JS_Number, #Style_JS_String , #Style_JS_Bracket, #Style_JS_Parentheses

- Ajout de quatre procédures :
ColorizeJSNumbers(gadget, startPos, endPos) - Coloration des nombres.
ColorizeJSStrings(gadget, startPos, endPos) - Coloration des string entre guillemets.
ColorizeJSBrackets(gadget, startPos, endPos) - Coloration des brackets '{' '}' '[' ']'
ColorizeJSParentheses(gadget, startPos, endPos) - Coloration des parenthèses

Ces colorations sont exécutées dans la procédure ColorizeHTMLTags().

➡️ Code récapitulatif incluant ces nouvelles colorations.

Code : Tout sélectionner

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

; PureBasic 6.30 (x64)
; Mise à jour du 2 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
; Auto-fermeture des tag <tag> -> </tag> automatique
; Coloration CSS

; Ajout
; Coloration des nombres
; Coloration des strings entre guillemets
; Coloration des brackets 
; Coloration des parenthéses

EnableExplicit

Enumeration window
  #app
EndEnumeration

Enumeration gadgets
  #editor
EndEnumeration

Enumeration styles
  #Style_HTML_Comment
  #Style_HTML_Keyword
  
  #Style_JS_Comment
  #Style_JS_KeyWord
  #Style_JS_Number
  #Style_JS_String 
  #Style_JS_Bracket
  #Style_JS_Parentheses
  
  #Style_CSS_Selector
  #Style_CSS_Property
  #Style_CSS_Value
  #Style_CSS_Number
  #Style_CSS_String
  #Style_CSS_Comment
  #Style_CSS_Punct
EndEnumeration

Define version.s = "1.40"

; 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 (C'est un jeu de test)
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 (C'est un jeu de test)
Global KeywordsFolding.s = "html,head,body,div,section,article,nav,ul,ol,table"

; Liste des mots clés CSS propriétés (C'est un jeu de test)
Global cssProperties.s = "color,background,background-color,margin,padding,width,height,display," + 
                         "position,top,left,right,bottom,font-size,font-family,border,border-radius," + 
                         "box-shadow,opacity,z-index|overflow,text-align,line-height"

; Liste des mots clé CSS valeur (C'est un jeu de test)
Global cssValues.s = "auto,inherit,initial,unset,none,block,inline,flex,grid,absolute,relative,fixed," + 
                     "sticky,solid,dashed,center,cover,contain,Repeat,no-Repeat,bold,italic,hidden,visible," +
                     "lightblue,white,silver,gray,black,red,maroon,yellow,olive,lime,aqua,teal,blue,navy,fuchsia,purple"

; 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 scStyleHTMLCommentColot = RGB(0, 255, 0)

Global scStyleJSCommentColor = RGB(0, 255, 0)
Global scStyleJSKeywordColor = RGB(0, 0, 205)
Global scStyleJSNumber = RGB(0, 180, 200)
Global scStyleJSString = RGB(160, 90, 200)
Global scStyleJSSBracket = RGB(0, 0, 255)
Global scStyleJSParentheses = RGB(255, 0, 0)

Global scStyleCSSKeywordColor = RGB(0, 0, 205)
Global scStyleCSSProperty = RGB(0, 120, 255)
Global scStyleCSSValue = RGB(0, 170, 120)

; 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)
  
Global commentCSSStartPattern = AllocateMemory(5)
Global commentCSSEndPattern   = 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)

; Déterminer le string précédent le curseur de saisie
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 mots clés JavaScript
Declare ColorizeJSKeywords(gadget, startPos, endPos)

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

; Coloration des nomnbres 
Declare ColorizeJSNumbers(gadget, startPos, endPos)

; Coloration des string entre guillemets
Declare ColorizeJSStrings(gadget, startPos, endPos)

; Coloration des brackets '{' '}' '[' ']'
Declare ColorizeJSBrackets(gadget, startPos, endPos)

; Coloration des parenthéses
Declare ColorizeJSParentheses(gadget, startPos, endPos) 

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

; Retourne les positions de début et fin du code CSS
Declare GetCSSRange(gadget, *start.Integer, *end.Integer)

; Colorer des mots clés CSS
Declare ColorizeCSS(gadget, startPos, endPos)

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

PokeS(commentCSSStartPattern, "/*", -1, #PB_UTF8)
PokeS(commentCSSEndPattern,   "*/",  -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_HTML_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_HTML_Comment, scStyleHTMLCommentColot)
  
  ; 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 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)
  
  ; Styles : Coloration des Nombres JavaScript
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_Number, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_Number, scStyleJSNumber)
  
  ; Styles : Strings JS 
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_String, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_String, scStyleJSString)
  
  ; Styles : Brackets JS 
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_Bracket, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_Bracket, scStyleJSSBracket)
  
  ; Styles : Parentheses JS 
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_Parentheses, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_JS_Parentheses, scStyleJSParentheses)
  
  ; Styles : Sélecteurs CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Selector, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Selector, scStyleCSSKeywordColor)
  
  ; Syles : Propriétés CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Property, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Property, scStyleCSSProperty)
  
  ; Styles : Valeurs CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Value, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Value, RGB(0, 170, 120))
  
  ; Styles : Nombres CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Number, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Number, RGB(0, 200, 200))
  
  ; Styles : Strings CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_String, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_String, RGB(180, 0, 180))
  
  ; Styles : Commentaires CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Comment, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Comment, RGB(0, 150, 0))
  
  ; Styles : Ponctuation CSS
  ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_CSS_Punct, #INDIC_TEXTFORE)
  ScintillaSendMessage(gadget, #SCI_INDICSETFORE,  #Style_CSS_Punct, RGB(200, 200, 0))
  
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>
  
  Protected cssStart, cssEnd ; Ou commence et se termine la déclaration du code CSS
  
  ; Calculer la longueur du texte contenu dans le gadget scintilla
  textLength = ScintillaSendMessage(gadget, #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
        ; Coloration HTML et Javascript
        ColorizeHTMLTags(gadget, 0, textLength, htmlKeyWords)
                
        ; Coloration CSS
        GetCSSRange(gadget, @cssStart, @cssEnd)       
        If cssStart <> -1 And cssEnd > cssStart
          ColorizeCSS(gadget, cssStart, cssEnd)
        EndIf
        
        ; Folding
        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_HTML_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_HTML_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)    
      ColorizeJSStrings(gadget, startPos, endPos)
      ColorizeJSComments(gadget, startPos, endPos) 
      ColorizeJSNumbers(gadget, startPos, endPos)
      ColorizeJSKeywords(gadget, startPos, endPos)
      ColorizeJSBrackets(gadget, startPos, endPos)
      ColorizeJSParentheses(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

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

Procedure ColorizeJSNumbers(gadget, startPos, endPos)
  
  Protected pos = startPos
  Protected ch, nextCh
  Protected numberStart
  Protected hasDot, hasExp
  
  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
    
    
    ; Début possible de nombre
    If (ch >= '0' And ch <= '9') Or
       (ch = '.' And (ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) >= '0' And
                      ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) <= '9'))
      
      numberStart = pos
      hasDot = #False
      hasExp = #False
      
      ; hex / bin / oct
      If ch = '0'
        nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
        If nextCh = 'x' Or nextCh = 'X' Or nextCh = 'b' Or nextCh = 'B' Or nextCh = 'o' Or nextCh = 'O'
          pos + 2
          While pos < endPos
            ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
            If (ch >= '0' And ch <= '9') Or
               (ch >= 'a' And ch <= 'f') Or
               (ch >= 'A' And ch <= 'F')
              pos + 1
            Else
              Break
            EndIf
          Wend
          
          ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Number, 0)
          ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, numberStart, pos - numberStart)
          
          Continue
        EndIf
      EndIf
      
      ; Décimal / flottant / scientifique
      While pos < endPos
        
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        
        If ch >= '0' And ch <= '9'
          pos + 1
          Continue
        EndIf
        
        If ch = '.' And hasDot = #False
          hasDot = #True
          pos + 1
          Continue
        EndIf
        
        If (ch = 'e' Or ch = 'E') And hasExp = #False
          hasExp = #True
          pos + 1
          
          ; Signe optionnel après e
          ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
          If ch = '+' Or ch = '-'
            pos + 1
          EndIf
          
          Continue
        EndIf
        
        Break
      Wend
      
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Number, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, numberStart, pos - numberStart)
      
      Continue
    EndIf
    
    pos + 1
  Wend
  
EndProcedure


Procedure ColorizeJSStrings(gadget, startPos, endPos)
  Protected pos = startPos
  Protected ch, quote
  Protected stringStart, stringEnd
  Protected escaped
  
  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
        
    ; Détecter début des string : caractére " ou '  `
    If ch = 34 Or ch = 39 Or ch = 96
      quote = ch
      stringStart = pos
      pos + 1
      escaped = #False
      
      While pos < endPos
        
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        
        If escaped
          escaped = #False
          pos + 1
          Continue
        EndIf
        
        If ch = 92   ; backslash \
          escaped = #True
          pos + 1
          Continue
        EndIf
        
        ; fermeture string
        If ch = quote
          pos + 1
          Break
        EndIf
        
        pos + 1
      Wend
      
      stringEnd = pos
      
      ; Coloration du string 
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_String, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, stringStart, stringEnd - stringStart)
      
      Continue
    EndIf
    
    pos + 1
  Wend  
EndProcedure

; Coloration des brackets '{' '}' '[' ']'
Procedure ColorizeJSBrackets(gadget, startPos, endPos)
  Protected pos, ch
  
  For pos = startPos To endPos - 1
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    
    If ch = '{' Or ch = '}' Or ch = '[' Or ch = ']'
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Bracket)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, pos, 1)
    EndIf
  Next
EndProcedure

; Coloration des parenthéses
Procedure ColorizeJSParentheses(gadget, startPos, endPos)  
  Protected pos = startPos
  Protected ch
  
  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
        
    If ch = '(' Or ch = ')'
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Parentheses, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, pos, 1)
    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


;- CSS

; Retourne les positions de début et fin du code CSS
Procedure GetCSSRange(gadget, *start.Integer, *end.Integer)
  
  Protected textLen = ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0)
  Protected pos = 0
  Protected inStyle = #False
  Protected cssStart = -1
  Protected cssEnd   = -1
  Protected word.s
  
  While pos < textLen
    
    If ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) = '<'
      
      word = LCase(GetScintillaWord(gadget, pos + 1, pos + 20))
      
      If FindString(word, "style") And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) <> '/'
        inStyle = #True
        cssStart = pos
        
        ; avancer après >
        While pos < textLen And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) <> '>'
          pos + 1
        Wend
        
        cssStart = pos + 1
      EndIf
      
      If FindString(word, "/style")
        cssEnd = pos
        
        *start\i = cssStart
        *end\i   = cssEnd
        ProcedureReturn
      EndIf
    EndIf
    
    pos + 1
  Wend
  
  *start\i = -1
  *end\i   = -1
  
EndProcedure


; Colorater les mots clés CSS
Procedure ColorizeCSS(gadget, startPos, endPos)
  Protected pos = startPos
  Protected ch, start, word.s
  Protected inSelector = #True
  Protected inBlock = #False
  Protected commentEnd
  Protected quote
  
  While pos < endPos
    
    ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
    
    ; Commentaire CSS
    
    ; Recherche début de commentaire CSS "/*"
    If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '*'      
      ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos + 2)
      ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
      
      ; Recherche fin de commentaire CSS "*/
      commentEnd = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 2, commentCSSEndPattern)
      
      If commentEnd = -1
        commentEnd = endPos
      Else
        commentEnd + 2
      EndIf
      
      ; Invocation du style commentaire et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Comment)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, pos, commentEnd - pos)
      
      pos = commentEnd
      Continue
    EndIf
    
    ; String CSS
    If ch = 34 Or ch = 39   ; tester " ou '
      quote = ch
      start = pos
      pos + 1
      
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        
        ; fermeture non échappée
        If ch = quote And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos - 1, 0) <> 92
          pos + 1
          Break
        EndIf
        
        pos + 1
      Wend
      
      ; Invocation du style sting et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_String, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
      Continue
    EndIf
    
    
    ; Accolades / ponctuation
    If ch = '{' Or ch = '}' Or ch = ':' Or ch = ';'
      
      ; Invocation du style punctuation et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Punct, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, pos, 1)
      
      If ch = '{'
        inBlock = #True
        inSelector = #False
      ElseIf ch = '}'
        inBlock = #False
        inSelector = #True
      EndIf
      
      pos + 1
      Continue
    EndIf
    
    ; Nombre CSS
    If (ch >= '0' And ch <= '9')
      
      start = pos
      pos + 1
      
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        If Not ((ch >= '0' And ch <= '9') Or ch = '.' Or ch = '%' Or (ch >= 'a' And ch <= 'z'))
          Break
        EndIf
        pos + 1
      Wend
      
      ; Invocation du style nombre et coloration
      ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Number, 0)
      ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
      Continue
    EndIf
    
    ; Identifiant CSS
    If (ch >= 'a' And ch <= 'z') Or (ch >= 'A' And ch <= 'Z') Or ch = '.' Or ch = '#'
      
      start = pos
      pos + 1
      
      While pos < endPos
        ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
        If Not ((ch >= 'a' And ch <= 'z') Or (ch >= 'A' And ch <= 'Z') Or ch = '-' Or (ch >= '0' And ch <= '9'))
          Break
        EndIf
        pos + 1
      Wend
      
      word = LCase(GetScintillaWord(gadget, start, pos))
      
      If inSelector
        
        ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Selector, 0)
        ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
        
      Else
        
        If isKeyword(word, cssProperties)
          ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Property, 0)
          ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
          
        ElseIf iskeyword(word, cssvalues)
          ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_CSS_Value, 0)
          ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, start, pos - start)
        EndIf
        
      EndIf
      
      Continue
    EndIf
    
    pos + 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


J'ai d'autres idées à mettre en œuvres comme le match des parenthèses et des brackets.
Quand on sélectionne une parenthèse, celle-ci est mise en valeur par une coloration spécifique ainsi que la parenthèse fermente.
Il en serait de même pour les brackets "{'" ... "}" et les crochets "[" ... "]"

Mais je vais m'arrêter là pour ce sujet. Le code commence à être lourd à digérer 😁
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 »

Un bonus avec la liste normalement complète de chaque variable contenant des mots clés.

Code : Tout sélectionner

htmlKeyWords.s = "<!DOCTYPE>,html,head,title,body,base,link,meta,style,header,nav,main,section,article,aside,footer,address,h1,h2,h3,h4,h5,h6,p,br,hr,pre,blockquote,ol,ul,li,dl,dt,dd,figure,figcaption,div,a,em,strong,small,s,cite,q,dfn,abbr,data,time,code,var,samp,kbd,sub,sup,i,b,u,mark,ruby,rt,rp,bdi,bdo,span,wbr,img,audio,video,source,track,picture,map,area,iframe,embed,object,param,script,noscript,canvas,svg,form,label,input,button,select,datalist,optgroup,option,textarea,output,progress,meter,fieldset,legend,details,summary,dialog,table,caption,colgroup,col,thead,tbody,tfoot,tr,th,td"

Code : Tout sélectionner

jsKeywords.s = "await,break,case,catch,class,const,continue,debugger,default,delete,do,else,enum,export,extends,false,finally,for,function,if,implements,import,in,instanceof,interface,let,new,null,package,private,protected,public,return,super,switch,static,this,throw,true,try,typeof,var,void,while,with,yield,true,false,null,undefined,NaN,Infinity,Array,ArrayBuffer,Boolean,BigInt,DataView,Date,Error,EvalError,FinalizationRegistry,Float32Array,Float64Array,Function,Intl,JSON,Map,Math,Number,Object,Promise,Proxy,RangeError,ReferenceError,Reflect,RegExp,Set,SharedArrayBuffer,String,Symbol,SyntaxError,TypeError,URIError,WeakMap,WeakRef,WeakSet,eval,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent"

Code : Tout sélectionner

cssProperties.s = "align-content,align-items,align-self,all,animation,animation-delay,animation-direction,animation-duration,animation-fill-mode,animation-iteration-count,animation-name,animation-play-state,animation-timing-function,backdrop-filter,backface-visibility,background,background-attachment,background-blend-mode,background-clip,background-color,background-image,background-origin,background-position,background-repeat,background-size,border,border-bottom,border-bottom-color,border-bottom-left-radius,border-bottom-right-radius,border-bottom-style,border-bottom-width,border-collapse,border-color,border-image,border-image-outset,border-image-repeat,border-image-slice,border-image-source,border-image-width,border-left,border-left-color,border-left-style,border-left-width,border-radius,border-right,border-right-color,border-right-style,border-right-width,border-spacing,border-style,border-top,border-top-color,border-top-left-radius,border-top-right-radius,border-top-style,border-top-width,border-width,bottom,box-decoration-break,box-shadow,box-sizing,caption-side,caret-color,clear,clip,clip-path,color,column-count,column-fill,column-gap,column-rule,column-rule-color,column-rule-style,column-rule-width,column-span,column-width,columns,content,counter-increment,counter-reset,cursor,direction,display,empty-cells,filter,flex,flex-basis,flex-direction,flex-flow,flex-grow,flex-shrink,flex-wrap,float,font,font-family,font-feature-settings,font-kerning,font-language-override,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-variant-alternates,font-variant-caps,font-variant-east-asian,font-variant-ligatures,font-variant-numeric,font-variant-position,font-weight,gap,grid,grid-area,grid-auto-columns,grid-auto-flow,grid-auto-rows,grid-column,grid-column-end,grid-column-gap,grid-column-start,grid-gap,grid-row,grid-row-end,grid-row-gap,grid-row-start,grid-template,grid-template-areas,grid-template-columns,grid-template-rows,hanging-punctuation,height,hyphens,image-rendering,inline-size,inset,isolation,justify-content,justify-items,justify-self,left,letter-spacing,line-break,line-height,list-style,list-style-image,list-style-position,list-style-type,margin,margin-bottom,margin-left,margin-right,margin-top,mask,mask-image,mask-mode,mask-position,mask-repeat,mask-size,max-height,max-width,min-height,min-width,mix-blend-mode,object-fit,object-position,opacity,order,orphans,outline,outline-color,outline-offset,outline-style,outline-width,overflow,overflow-wrap,overflow-x,overflow-y,padding,padding-bottom,padding-left,padding-right,padding-top,page-break-after,page-break-before,page-break-inside,perspective,perspective-origin,place-content,place-items,place-self,pointer-events,position,quotes,resize,right,rotate,row-gap,scale,scroll-behavior,shape-image-threshold,shape-margin,shape-outside,tab-size,table-layout,text-align,text-align-last,text-combine-upright,text-decoration,text-decoration-color,text-decoration-line,text-decoration-style,text-decoration-thickness,text-emphasis,text-emphasis-color,text-emphasis-position,text-emphasis-style,text-indent,text-justify,text-orientation,text-overflow,text-shadow,text-transform,top,transform,transform-origin,transform-style,transition,transition-delay,transition-duration,transition-property,transition-timing-function,translate,unicode-bidi,user-select,vertical-align,visibility,white-space,widows,width,will-change,word-break,word-spacing,word-wrap,writing-mode,z-index"

Code : Tout sélectionner

cssValues.s = "auto,none,inherit,initial,unset,revert,block,inline,inline-block,flex,inline-flex,grid,inline-grid,contents,flow-root,absolute,relative,fixed,sticky,static,left,right,top,bottom,center,row,row-reverse,column,column-reverse,nowrap,wrap,wrap-reverse,flex-start,flex-end,space-between,space-around,space-evenly,stretch,solid,dashed,dotted,double,groove,ridge,inset,outset,hidden,visible,bold,bolder,lighter,normal,italic,oblique,small-caps,uppercase,lowercase,capitalize,pointer,default,move,text,crosshair,wait,help,not-allowed,grab,grabbing,cover,contain,fill,scale-down,repeat,no-repeat,repeat-x,repeat-y,round,space,scroll,fixed,local,border-box,padding-box,content-box,ease,ease-in,ease-out,ease-in-out,linear,step-start,step-end,visible,collapse,separate,table-row,table-cell,table-column,ltr,rtl,portrait,landscape,monospace,serif,sans-serif,cursive,fantasy,system-ui,red,green,blue,black,white,gray,silver,maroon,olive,navy,teal,purple,yellow,orange,pink,transparent,currentColor,px,em,rem,%,vh,vw,vmin,vmax,deg,rad,turn,s,ms"
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