Version 1.20 - Auto fermeture des tag.
Objectif : Vous tapez un tag. Par exemple <html>. Le code va générer automatiquement le tag de fermeture </tag>. Whaouuu c'est génial
- Ajout de la procédure GetOpeningTagBeforeCaret(Gadget) pour rechercher le tag précédent le curseur de de saisie.
Voici le code.
Code : Tout sélectionner
; Web Framework - Trame d'un editeur HTML/JavaScript
; Version 1.20
; PureBasic 6.30 (x64)
; Mise à jour du 1 Février 2026
; Pas d'API & Scintilla natif
; Fonctionnalités
; ===============
; Mise en place du gadget Scintilla
; Propriété du gadget Scintilla
; Scintilla callback pour gérer les évenements Scintilla
; Indentation
; Autocomplétion
; Coloration des mots clés HTML
; Coloration des commentaires
; Folding (Pliage et dépliage du code)
; Coloration des mots clés Javascript
; Ajout
; Auto-fermeture des tag <tag> -> </tag> automatique
EnableExplicit
Enumeration window
#app
EndEnumeration
Enumeration gadgets
#editor
EndEnumeration
Enumeration styles
#Style_Comment
#Style_HTML_Keyword
#Style_JS_Comment
#Style_JS_KeyWord
EndEnumeration
Define version.s = "1.20"
; Liste des mots clés (C'est un jeu de test)
Global htmlKeyWords.s = "html,head,body,title,script,style,div,canvas,meta,h1,h2,h3,h4,h5,h6,button,p"
; Liste des mots clés Javascript
Global jsKeywords.s = "break,case,catch,class,const,continue,debugger,default,delete,do," +
"else,export,extends,finally,for,function,if,import,in,instanceof," +
"let,new,return,super,switch,this,throw,try,typeof,var,void,while," +
"with,yield,await,enum,implements,interface,package,private," +
"protected,public,static,null,true,false,undefined"
; Liste des mots clés déclencheur de pliage/dépliage de code
Global KeywordsFolding.s = "html,head,body,div,section,article,nav,ul,ol,table"
; Séparateur des mots clés
Global KeyWordSep.s = ","
; Largeur de la marge de numérotation des lignes
Global scMarginSizeDefault = 50
; Couleurs
Global scFrontColor = RGB(105,105, 105)
Global scBackColor = RGB(250, 240, 230)
Global scCurrentLineColor = RGB(255, 228, 181)
Global scMasterFolder = RGB(255, 0, 0)
; Police de caractére
Global scFont.s = "Lucida Console"
Global scFontSize = 12
; Couleur des styles par defaut
Global scStyleHTMLKeyWordColor = RGB(255, 0, 0)
Global scStyleHTMLCommentColor = RGB(0, 255, 0)
Global scStyleJSCommentColor = RGB(0, 255, 0)
Global scStyleJSKeywordColor = RGB(0, 0, 205)
; Indentation
Global scIndent, scLine, scPos, scCol
; Pour la recherche des blocs commentaires "<!--" et "-->"
; Ces deux chaines doivent être stockées dans un buffer UTF8
Global commentStartPattern = AllocateMemory(5)
Global commentEndPattern = AllocateMemory(4)
;- Sommaire des procédures
; Définir les paramétres du gadget scintilla
Declare ScintillaProperties(gadget)
; Callback évenementielle du gadget scintilla
Declare ScintillaCallBack(gadget, *scn.scNotification)
; Obtenir le texte de la ligne en cours de saisie
Declare.s GetScintillaLineText(gadget, line)
; Obtenir le mot se trouvant entre deux position
Declare.s getScintillaWord(gadget, startPos, endPos)
; Tester si un mot est un mot clé
Declare.b isKeyword(word.s, keyWords.s)
;
Declare.s GetOpeningTagBeforeCaret(gadget)
; Tester si un mot est une clé de pliage
Declare.b isFoldingKeyWord(word.s, keyWordfoldingDown.s)
; Vérifier que la coloration du code JavaScript se trouve entre les balise <script> </script>
Declare.b IsInsideScriptBlock(gadget, pos)
; Coloration des mots clés HTML
Declare ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)
; Ignorer les lignes de commentaires JavaScript "//"
Declare SkipJSLineComment(gadget, pos)
; Ignorer les blocs de commentaires JavaScript "/* .. */"
Declare SkipJSBlockComment(gadget, pos)
; Coloration des commentaires JavaScripts
Declare ColorizeJSComments(gadget, startPos, endPos)
; Coloration des mots clés JavaScript
Declare ColorizeJSKeywords(gadget, startPos, endPos)
; Mettre à jour le pliage/dépliage
Declare UpdateHTMLFolding(gadget, KeywordsFolding.s)
; Texte au format UTF8
Declare MakeUTF8Text(text.s)
;- Fenetre de l'application
OpenWindow(#app, 0, 0, 800, 600, "WebBase " + version, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
; Neutraliser la touche TAB et les caractéres spéciaux
RemoveKeyboardShortcut(#app, #PB_Shortcut_Tab)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_B, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_G, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_E, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_R, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_O, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_P, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_Q, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_S, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_F, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_H, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_K, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_W, 0)
AddKeyboardShortcut(#app, #PB_Shortcut_Control+#PB_Shortcut_N, 0)
; Editeur Scintilla gadget associé à un callback
ScintillaGadget(#editor, 10, 10, 780, 580, @scintillaCallBack())
;- Parametres Scintilla (Couleur, font, numerotation, style, etc ...)
ScintillaProperties(#editor)
; Positionner le curseur de saisie dans l'éditeur
SetActiveGadget(#editor)
; "<!--" et "-->" convertis au format UTF8
PokeS(commentStartPattern, "<!--", -1, #PB_UTF8)
PokeS(commentEndPattern, "-->", -1, #PB_UTF8)
;- Boucle évenementielle
Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow
;-
;- Liste des procédures
; Parametres du gadget scintilla
Procedure ScintillaProperties(gadget)
;- 1 Style par défaut
; Couleur et police de caractéres
ScintillaSendMessage(gadget, #SCI_STYLESETFORE, #STYLE_DEFAULT, scFrontColor)
ScintillaSendMessage(gadget, #SCI_STYLESETBACK, #STYLE_DEFAULT, scBackColor)
ScintillaSendMessage(gadget, #SCI_STYLESETFONT,#STYLE_DEFAULT, @scFont)
ScintillaSendMessage(gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, scFontSize)
;- 2 Propager vers tous les styles
ScintillaSendMessage(gadget, #SCI_STYLECLEARALL)
;- 3 Définir des styles spécifiques
; Activation et couleur de la ligne en cours d'édition
ScintillaSendMessage(gadget, #SCI_SETCARETLINEVISIBLE, #True)
ScintillaSendMessage(gadget, #SCI_SETCARETLINEBACK, scCurrentLineColor)
; Les tabulations sont remplacées par des espaces
ScintillaSendMessage(gadget, #SCI_SETUSETABS, #False)
; Nombre d'espaces pour une tabulation
ScintillaSendMessage(gadget, #SCI_SETINDENT, 4)
; Création de la colonne de numérotation des lignes
ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 1, #SC_MARGIN_NUMBER)
ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 1, scMarginSizeDefault)
; Autocomplétion : Parametres de la liste des mots clés
ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXHEIGHT, 40)
ScintillaSendMessage(gadget, #SCI_AUTOCSETMAXWIDTH, 150)
ScintillaSendMessage(gadget, #SCI_AUTOCSETAUTOHIDE, #True)
ScintillaSendMessage(gadget, #SCI_AUTOCSETCHOOSESINGLE, #True)
ScintillaSendMessage(gadget, #SCI_AUTOCSETIGNORECASE, #True)
; Autocomplétion : Caractére séparant chaque mot de la liste des mots clés
ScintillaSendMessage(gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
; Autocomplétion : Caractére sélectionnant le mot de la liste d'autocomplétion
ScintillaSendMessage(gadget, #SCI_AUTOCSETFILLUPS, 0, @" ")
; Autocomplétion : Tri de la liste
ScintillaSendMessage(gadget, #SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT)
; Folding : Création de la colonne de pliages/dépliage
ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, #True)
; Folding : Choix des icones de pliages du code 5
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEROPEN, #SC_MARK_CIRCLEMINUS)
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDER, #SC_MARK_CIRCLEPLUS)
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERSUB, #SC_MARK_VLINE) ;Ligne verticale
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERTAIL, #SC_MARK_LCORNERCURVE) ;fin arborescence
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEREND, #SC_MARK_CIRCLEPLUSCONNECTED) ;Dépliage
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDEROPENMID, #SC_MARK_CIRCLEMINUSCONNECTED) ;Pliage
ScintillaSendMessage(gadget, #SCI_MARKERDEFINE, #SC_MARKNUM_FOLDERMIDTAIL, #SC_MARK_TCORNERCURVE)
; Folding : Couleur des icones de pliages/dépliage
ScintillaSendMessage(gadget, #SCI_MARKERSETFORE, #SC_MARKNUM_FOLDER, scMasterFolder)
ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDER, RGB(0, 0, 0))
ScintillaSendMessage(gadget, #SCI_MARKERSETFORE, #SC_MARKNUM_FOLDEROPEN, scMasterFolder)
ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDEROPEN, RGB(0, 0, 0))
ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDEROPENMID, RGB(0, 0, 0))
ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERSUB, RGB(0, 0, 0))
ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERTAIL, RGB(0, 0, 0))
ScintillaSendMessage(gadget, #SCI_MARKERSETBACK, #SC_MARKNUM_FOLDERMIDTAIL, RGB(0, 0, 0))
;- Folding : Activation du folding
ScintillaSendMessage(gadget, #SCI_SETMARGINTYPEN, 2, #SC_MARGIN_SYMBOL)
ScintillaSendMessage(gadget, #SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS)
ScintillaSendMessage(gadget, #SCI_SETMARGINSENSITIVEN, 2, 1)
ScintillaSendMessage(gadget, #SCI_SETMARGINWIDTHN, 2, 20)
;ScintillaSendMessage(gadget, #SCI_SETPROPERTY, @"fold", @"2")
;- Définit les styles
; Styles : Coloration des mots clés HTML
ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_HTML_Keyword, #INDIC_TEXTFORE)
ScintillaSendMessage(gadget, #SCI_INDICSETFORE, #Style_HTML_Keyword, scStyleHTMLKeyWordColor)
; Style commentaires HTML
ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_Comment, #INDIC_TEXTFORE)
ScintillaSendMessage(gadget, #SCI_INDICSETFORE, #Style_Comment, scStyleHTMLCommentColor)
; Styles : Coloration des commentaire JavaScript
ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_Comment, #INDIC_TEXTFORE)
ScintillaSendMessage(gadget, #SCI_INDICSETFORE, #Style_JS_Comment, scStyleJSCommentColor)
; Syles : Coloration des mots clés JavaScript
ScintillaSendMessage(gadget, #SCI_INDICSETSTYLE, #Style_JS_KeyWord, #INDIC_TEXTFORE)
ScintillaSendMessage(gadget, #SCI_INDICSETFORE, #Style_JS_KeyWord, scStyleJSKeywordColor)
EndProcedure
;-
; Callback evenementielle du gadget scintilla
Procedure scintillaCallBack(gadget, *scn.scNotification)
Protected textLength
Protected SciCurrentPos, SciWordStartPos
Protected curPos, curPos2
Protected *buf, *buf2
Protected tag.s ;Rechercher le tag entre "<" et ">" pour auto-fermeture du tag
Protected close.s ;Création du tag de fermeture "</tag>
; Calculer la longueur du texte contenu dans le gadget scintilla
textLength = ScintillaSendMessage(#editor, #SCI_GETLENGTH)
; Analyser les evenement scintilla
Select *scn\nmhdr\code
Case #SCN_CHARADDED
; Un caractére est saisie
Select *scn\ch
Case 13
;- Indentation
; Vous avez pressé la touche entrée
; Quel est la position du décalages du texte au niveau de la marge.
scIndent = ScintillaSendMessage(gadget, #SCI_GETLINEINDENTATION, scLine)
; Passer à la ligne suivante
; et positionner le curseur
ScintillaSendMessage(gadget, #SCI_SETLINEINDENTATION, scLine+1, scIndent)
; Touche entrée préssée : Le curseur ne passera pas à la ligne suivante.
; Forcer le passage à la ligne en insérant la longueur de #CRLF$
If scIndent=0
scPos = scPos + Len(#CRLF$)
EndIf
; Positionner le curseur de saisie
ScintillaSendMessage(gadget, #SCI_GOTOPOS, scPos + scIndent)
Case 'a' To 'z', 'A' To 'Z'
;- Autocomplétion (Affichage d'une liste contenant les mots clés HTML
; Affichage du mot selectionné si autocomplétion
SciCurrentPos = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS)
SciWordStartPos = ScintillaSendMessage(gadget, #SCI_WORDSTARTPOSITION, SciCurrentPos, 1)
ScintillaSendMessage(0, #SCI_AUTOCSHOW, SciCurrentPos - SciWordStartPos, MakeUTF8Text(htmlKeyWords))
Case '>'
;- Auto fermeture de tag <tag>|</tag>
; Obtenir le tag de fermeture
tag = GetOpeningTagBeforeCaret(gadget)
If tag <> ""
curPos2 = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS, 0, 0)
close = "</" + tag + ">"
*buf2 = AllocateMemory(StringByteLength(close, #PB_UTF8) + 1)
PokeS(*buf2, close, -1, #PB_UTF8)
ScintillaSendMessage(gadget, #SCI_INSERTTEXT, curPos2, *buf2)
FreeMemory(*buf2)
; On ne modidie pas la position du curseur.
; Il est positionné entre le tag d'ouverture et le tag de fermeture
EndIf
EndSelect
Case #SCN_UPDATEUI
; Une mise à jour du gadget Scintilla est effectué
; Style & folding UNIQUEMENT si le contenu change
If *scn\updated & #SC_UPDATE_CONTENT
ColorizeHTMLTags(gadget, 0, textLength, htmlKeyWords)
UpdateHTMLFolding(gadget, KeywordsFolding)
EndIf
Case #SCN_MARGINCLICK
; Mise en oeuvre du pliage dépliage (folding)
; Clique sur la deuxiéme colonne
If *scn\margin = 2
; Ligne réelle à partir de la position du clic
Protected line = ScintillaSendMessage(gadget, #SCI_LINEFROMPOSITION, *scn\position, 0)
Protected level = ScintillaSendMessage(gadget, #SCI_GETFOLDLEVEL, line, 0)
; Autoriser uniquement sur les lignes HEADER
If level & #SC_FOLDLEVELHEADERFLAG
ScintillaSendMessage(gadget, #SCI_TOGGLEFOLD, line)
EndIf
EndIf
EndSelect
; Important pour le fonctionnement de l'indentation
; Trouver la position du curseur de saisie
scPos = ScintillaSendMessage(gadget, #SCI_GETANCHOR)
; Trouver la ligne ou se touve le curseur
scLine = ScintillaSendMessage(gadget, #SCI_LINEFROMPOSITION, scPos)
; Trouver la colonne en cours
scCol = ScintillaSendMessage(gadget, #SCI_GETCOLUMN, scPos)
EndProcedure
;-
; Obtenir le texte de la ligne en cours de saisie
Procedure.s getScintillaLineText(gadget, line)
Protected lineLength, *buffer, result.s
; Longueur de la ligne
lineLength = ScintillaSendMessage(gadget, #SCI_LINELENGTH, line)
; Initialisation du buffer UTF8
*buffer = AllocateMemory(lineLength + 1)
If *buffer > 0
; Obtenir et renvoyer le contenu de la ligne
ScintillaSendMessage(gadget, #SCI_GETLINE, line, *buffer)
result.s = PeekS(*buffer, -1, #PB_UTF8)
FreeMemory(*buffer)
EndIf
ProcedureReturn result
EndProcedure
; Obtenir le mot (ou texte) se trouvant entre deux positions
Procedure.s getScintillaWord(gadget, startPos, endPos)
Protected tr.scTextRange, *buffer, length, result.s
length = endPos - startPos
If length > 0
*buffer = AllocateMemory(length + 1)
tr\chrg\cpMin = startPos
tr\chrg\cpMax = endPos
tr\lpstrText = *buffer
ScintillaSendMessage(gadget, #SCI_GETTEXTRANGE, 0, @tr)
; Lecture UTF-8 correcte
result = PeekS(*buffer, -1, #PB_UTF8)
FreeMemory(*buffer)
EndIf
ProcedureReturn result
EndProcedure
; Tester si un mot est un mot clé
Procedure.b isKeyword(word.s, keyWords.s)
Protected countWords = CountString(keyWords, KeyWordSep), n
Protected result.b
For n = 1 To countWords + 1
If LCase(StringField(keyWords, n, KeyWordSep)) = LCase(word)
result = #True
EndIf
Next
ProcedureReturn result
EndProcedure
; Rechercher le tag précédent le curseur de saisie
Procedure.s GetOpeningTagBeforeCaret(gadget)
Protected curPos, startPos, endPos, text.s, name.s, i, ch
; Déterminer la position du curseur
curPos = ScintillaSendMessage(gadget, #SCI_GETCURRENTPOS, 0, 0)
startPos = curPos - 2 ; juste avant '>'
If startPos < 0 : ProcedureReturn "" : EndIf
; Remonter jusqu'à '<'
For i = startPos To 0 Step -1
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, i, 0)
If ch = '<'
startPos = i
Break
EndIf
Next
If ch <> '<' : ProcedureReturn "" : EndIf
; lire le contenu <...>
endPos = curPos - 1
text = GetScintillaWord(gadget, startPos, endPos)
text = Trim(text)
; Rejeter </tag> et <br/>
If Left(text, 2) = "</" : ProcedureReturn "" : EndIf
If Right(text, 2) = "/>" : ProcedureReturn "" : EndIf
; Extraire nom après '<'
For i = 2 To Len(text)
ch = Asc(Mid(text, i, 1))
If (ch >= 'a' And ch <= 'z') Or (ch >= 'A' And ch <= 'Z') Or
(ch >= '0' And ch <= '9') Or ch = '-' Or ch = '_'
name + Chr(ch)
Else
Break
EndIf
Next
ProcedureReturn name
EndProcedure
; Tester si un mot trouvé dans un string déclenche le folding
Procedure.b isFoldingKeyWord(text.s, keyWordsfolding.s)
Protected countWords, n
Protected result.b
; Compter le nombre de mots clés folding contenu dans la variable KeyWordsFolding
countWords = CountString(keyWordsfolding, KeyWordSep)
; Pour chaque mots clé folding
For n = 1 To countWords + 1
; Vérifier que le mot clé se trouve dans dans la chaine reçu
; Il doit se trouver au début (Position 1) de la chaine testé (text.s)
If FindString(LCase(text), LCase(StringField(keyWordsfolding, n, KeyWordSep))) = 1
result = #True
EndIf
Next
ProcedureReturn result
EndProcedure
Procedure.b IsInsideScriptBlock(gadget, pos)
Protected textStart = 0
Protected textEnd = pos
Protected text.s = GetScintillaWord(gadget, textStart, textEnd)
Protected openCount = CountString(LCase(text), "<script")
Protected closeCount = CountString(LCase(text), "</script>")
If openCount > closeCount
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
;-
; Coloration des mots clés
Procedure ColorizeHTMLTags(gadget, startPos, endPos, keyWords.s)
Protected pos ; Position actuelle de l'indice de parcours du string
Protected lowerTag ; Position du prochain "<"
Protected upperTag ; Position du prochain ">"
Protected tagStart ; Premier caractère après "<"
Protected tagEnd ; Fin du nom de la balise sans ">"
Protected originalTagStart ; Début logique de la balise (après "<")
Protected tagName.s ; Tag sans balise d'ouverture/fermeture "<tag> -> "tag"
Protected nameStart ; Premier caractère après "<"
Protected isClosing ; Indicateur de balise fermée
Protected space ; Position d'un espace à l'intérieur de "<" et ">"
Protected commentStart, commentEnd ;Position de début et fin d'un commentaire
; La coloration se fera en plusieurs passage
; - 1 Commentaires
; - 2 Tags HTML <tag> </tag>
; Reset des indicateurs de styles
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_Comment, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
;- ■ 1 Pass commentaires <!-- Commentaire -->
pos = startPos
While pos < endPos
; Définir le target de recherche
ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos)
ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
; Rechercher la chaine de début de commentaire "<!--" (Longueur 4)
commentStart = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 4, commentStartPattern)
; Il y en a pas, on s'arrete !
If commentStart = -1 : Break : EndIf
; Nouveau target de recherche qui commencera aprés "<!--"
ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, commentStart + 4)
ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
; Rechercher la chaine de fin de commentaire "-->" (Longueur 3)
commentEnd = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 3, commentEndPattern)
If commentEnd <> -1
commentEnd + 3
Else
commentEnd = endPos
EndIf
; colorer le commentaire
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_Comment)
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
pos = commentEnd
Wend
;- ■ 2 Pass tag HTML "<html>"
pos = startPos
While pos < endPos
; Définir le target de recherche
ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, pos)
ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
; Chercher le caractére '<' dans la zone de scan
lowerTag = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @"<")
; Il y en a pas. On sort de la boucle
If lowerTag = -1 : Break : EndIf
; "<" est trouvé
; Nouveau target de recherche qui commencera aprés "<"
ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, lowerTag + 1)
ScintillaSendMessage(gadget, #SCI_SETTARGETEND, endPos)
; Chercher le prochain '>'
upperTag = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @">")
If upperTag = -1
;ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword, 0)
;ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
Break
EndIf
; Bonne nouvelle nous avons maintenant localisé "<" et ">"
originalTagStart = lowerTag + 1
tagStart = originalTagStart
; Nouveau target de recherche qui commencera aprés "<" et se termine à ">"
ScintillaSendMessage(gadget, #SCI_SETTARGETSTART, tagStart)
ScintillaSendMessage(gadget, #SCI_SETTARGETEND, upperTag)
; Recherche du caractéres espace dans las chaine située entre "<" et ">"
space = ScintillaSendMessage(gadget, #SCI_SEARCHINTARGET, 1, @" ")
If space = -1
tagEnd = upperTag
Else
tagEnd = space
EndIf
; Rechercher le mot situé entre "<" et ">"
If tagEnd > tagStart
tagName = GetScintillaWord(gadget, tagStart, tagEnd)
isClosing = #False
nameStart = tagStart
; Détecter </tag>
If Left(tagName, 1) = "/"
isClosing = #True
tagName = Mid(tagName, 2)
nameStart = tagStart + 1
EndIf
; Indiquer le début de la coloration style #Style_HTML_Keyword
; Indiquer la position de débug et fin de la coloration
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_HTML_Keyword)
ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, originalTagStart, upperTag - originalTagStart)
; Coloration de la balise "<" - position de début sur une longueur de 1
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, lowerTag, 1)
; Coloration de "/" si balise fermante - position de début sur une longueur de 1
If isClosing
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, tagStart, 1)
EndIf
; Coloration du nom de balise (ouvrante OU fermante) - Exemple html
If IsKeyword(tagName, keyWords)
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, nameStart, tagEnd - nameStart)
EndIf
; Coloration de ">" - position de fin sur une longueur de 1
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, upperTag, 1)
EndIf
;-■ 3 Coloration JavaScript
If IsInsideScriptBlock(gadget, pos)
ColorizeJSComments(gadget, startPos, endPos)
ColorizeJSKeywords(gadget, startPos, endPos)
EndIf
; AU suivant ...
pos = upperTag + 1
Wend
EndProcedure
; Chercher la fin d'un commentaire
Procedure SkipJSLineComment(gadget, pos)
Protected ch
While pos < ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0)
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
If ch = 10 Or ch = 13
Break
EndIf
pos + 1
Wend
ProcedureReturn pos
EndProcedure
; Ignorer les blocks de commentaires JavaScript "/* ... */"
Procedure SkipJSBlockComment(gadget, pos)
pos + 2
While pos < ScintillaSendMessage(gadget, #SCI_GETLENGTH, 0, 0) - 1
If ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0) = '*' And
ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '/'
pos + 2
Break
EndIf
pos + 1
Wend
ProcedureReturn pos
EndProcedure
; Colorer les mots clés JavaScript
Procedure ColorizeJSKeywords(gadget, startPos, endPos)
Protected pos = startPos
Protected wordStart, wordEnd, word.s
Protected ch
; Reset de la coloration des mots clés JavaScript
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_KeyWord, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
While pos < endPos
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
; Ignorer les lignes de commentaires JavaScript "//"
If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '/'
pos = SkipJSLineComment(gadget, pos)
Continue
EndIf
; Ignorer les lignes de bloc de commentaires JavaScript "/* ... */"
If ch = '/' And ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0) = '*'
pos = SkipJSBlockComment(gadget, pos)
Continue
EndIf
; Sauter non-lettres
If (ch < 'A' Or ch > 'Z') And (ch < 'a' Or ch > 'z') And ch <> '_'
pos + 1
Continue
EndIf
; Lire mot
wordStart = pos
While pos < endPos
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
If (ch >= 'A' And ch <= 'Z') Or (ch >= 'a' And ch <= 'z') Or
(ch >= '0' And ch <= '9') Or ch = '_'
pos + 1
Else
Break
EndIf
Wend
wordEnd = pos
word = GetScintillaWord(gadget, wordStart, wordEnd)
If IsKeyword(word, jsKeywords)
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_KeyWord, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, wordStart, wordEnd - wordStart)
EndIf
Wend
EndProcedure
; Coloration des commentaires JavaScript
Procedure ColorizeJSComments(gadget, startPos, endPos)
Protected pos = startPos
Protected ch, nextCh
Protected commentStart, commentEnd
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORCLEARRANGE, startPos, endPos - startPos)
While pos < endPos - 1
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
; // commentaire ligne
If ch = '/' And nextCh = '/'
commentStart = pos
; aller jusqu'à fin de ligne ou fin zone
pos + 2
While pos < endPos
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
If ch = 10 Or ch = 13 ; LF ou CR
Break
EndIf
pos + 1
Wend
commentEnd = pos
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
Continue
EndIf
; /* commentaire bloc */
If ch = '/' And nextCh = '*'
commentStart = pos
pos + 2
While pos < endPos - 1
ch = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos, 0)
nextCh = ScintillaSendMessage(gadget, #SCI_GETCHARAT, pos + 1, 0)
If ch = '*' And nextCh = '/'
pos + 2
Break
EndIf
pos + 1
Wend
commentEnd = pos
ScintillaSendMessage(gadget, #SCI_SETINDICATORCURRENT, #Style_JS_Comment, 0)
ScintillaSendMessage(gadget, #SCI_INDICATORFILLRANGE, commentStart, commentEnd - commentStart)
Continue
EndIf
pos + 1
Wend
EndProcedure
;-
; Mettre à jour le folding (Pliage/Dépliage)
Procedure UpdateHTMLFolding(gadget, KeywordsFolding.s)
Protected lineCount, i
Protected level = 0
Protected text.s
Protected buffer.s
; Traitement du pliage/depliage
; Ligne par ligne depuis la premiére ligne
; Obtenir le nombre de lignes
lineCount = ScintillaSendMessage(gadget, #SCI_GETLINECOUNT, 0, 0)
; Parcourir les lignes
For i = 0 To lineCount - 1
; Obtenir le texte de la ligne
text = GetScintillaLineText(gadget, i)
; Important : Supprimer #CRLF$
text = Trim(RemoveString(text, #CRLF$))
; Supprimer les chaines entourant le déclencheur de folding
; Exemples "<html>" -> html ou "</html>" -> html
buffer = RemoveString(text, "<")
buffer = RemoveString(buffer, ">")
buffer = RemoveString(buffer, "/")
; Supprimer les espaces encadrant le texte
buffer = Trim(buffer)
; Traitement balise de fermeture, on décremente aprés
If Bool(Left(text, 2) = "</" And isFoldingKeyWord(buffer, KeywordsFolding))
ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level)
level - 1
If level < 0 : level = 0 : EndIf
Continue
EndIf
; Niveau normal
ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level)
; Traitement balise ouvrante
If Bool(Left(text, 1) = "<" And Mid(text, 2, 1) <> "/" And Right(text, 1)=">" And isFoldingKeyWord(buffer, KeywordsFolding))
ScintillaSendMessage(gadget, #SCI_SETFOLDLEVEL, i, #SC_FOLDLEVELBASE + level | #SC_FOLDLEVELHEADERFLAG)
level + 1
EndIf
Next
EndProcedure
;-
;- Utilitaire(s)
; Obtenir un UTF8 d'un string
Procedure MakeUTF8Text(text.s)
Static buffer.s
buffer = Space(StringByteLength(text, #PB_UTF8) + 1)
PokeS(@buffer, text, -1, #PB_UTF8)
ProcedureReturn @buffer
EndProcedure