Page 1 of 1

PCRE Highlighter in Scintilla

Posted: Sat Jan 23, 2010 7:50 pm
by mdp
Hi All,
the following is code for a scintilla gadget that recieves highlighting instructions in realtime, internally using the "char,style,char,style" scintilla format, according to regular expressions.

Why: one of my masters used to say "real men work on b/w consoles, 80x25". My best man here states "the eye can be trained to discriminate the '#' starting comments to the actual configuration lines".
For us the sloppy confused-sighted backbonless that cannot promptly say "aha!" at first glance of an strace dump...

How: Left area for text to be analyzed. In the right area you can add expressions like
<hl_properties><spc><PCRE>
where the hl_properties can be combinations of:
s i u w l d k r g b c m y W L D K R G B C M Y
standing for
strong, italics, underline, white, lightgrey, darkgrey, black, red, green, blue, cyan, magenta, yellow (capitals for background)
Eg.:

Code: Select all

#An example    | sm    .*?=
asd=123        | iuYb  =.*
qwe=zxc        | W     =
               | gG    [0-9]
               | Dl    #.*
What for: use it vanilla, hack it into putties, make a text editor out of it, embed plink,make it a log explorer...

Code: Select all


Global K_fontface.s, K_fontsize
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    K_fontface = "!Monospace" : K_fontsize=9
CompilerElse
    K_fontface = "Lucida Console" : K_fontsize=9
    InitScintilla()
CompilerEndIf


 Global sci_buf = AllocateMemory(1024*1024)

Global Dim ScintillaStyleStack(1024)
Global ScintillaStyleStack_ptr

ImportC "" 
  pcre_exec(*pcre,*extra,subject.s,length,startoffset,options,*ovector,ovecsize)
EndImport

Enumeration
   #mwin
   #g_sci
   #g_rules
   #g_splitter
EndEnumeration

Enumeration
   #rxp_tmp
EndEnumeration

Procedure NextRegularExpressionMatch( regexp_handle , string.s , *result_start.long , *result_end.long )
   Static Dim pcre_results(2)
   If pcre_exec(PeekL(regexp_handle),0,string,Len(string),pcre_results(1),0,@pcre_results(),2) = 1
      *result_start\l=pcre_results(0)
      *result_end\l  =pcre_results(1)
      ProcedureReturn 1
   Else
      ProcedureReturn 0
   EndIf
EndProcedure

Procedure ScintillaStyleText( rules.s )
   l = ScintillaSendMessage(#g_sci,#SCI_GETLENGTH,0,0)+1 
   txt.s=Space(l) : ScintillaSendMessage(#g_sci,#SCI_GETTEXT,l,@txt) 
   marks.s=Space(l) : FillMemory(@marks,l-1)
   ; --- marking stylecodes into _marks_ according to regxp
   p=0 : q=0                                          
   For a=1 To CountString(rules,#LF$)+1
      s.s=StringField(rules,a,#LF$) : wspc=FindString(s," ",1)
      If wspc
         s=LTrim(Right(s,Len(s)-wspc)) 
         If Len(s)>0 And rulenum<9
            rulenum+1
            rxh=CreateRegularExpression(#rxp_tmp,s)
            If rxh
               While NextRegularExpressionMatch(rxh,txt,@p,@q)
                  *m.ascii=@marks+p : stop=@marks+q
                  While *m<stop
                     *m\a=rulenum : *m+1
                  Wend
               Wend 
               FreeRegularExpression(#rxp_tmp)
            EndIf
         EndIf
      EndIf
   Next
   ; --- filling buffer for scintilla through alternation of char and stylebyte
   *t.ascii=@txt
   *m.ascii=@marks
   *s.ascii=sci_buf
   For a=0 To l-1
      *s\a=*t\a : *s+1
      *s\a=*m\a : *s+1
      *t+1 : *m+1
   Next
   *s\a=0 : *s+1 : *s\a=0
       p=ScintillaSendMessage(#g_sci,#SCI_GETSELECTIONSTART,0,0)
       q=ScintillaSendMessage(#g_sci,#SCI_GETSELECTIONEND,  0,0)
       n=ScintillaSendMessage(#g_sci,#SCI_GETFIRSTVISIBLELINE,0,0) 
       ScintillaSendMessage(#g_sci,#SCI_CLEARALL,0,0)
       ScintillaSendMessage(#g_sci,#SCI_ADDSTYLEDTEXT,(l-1)<<1,sci_buf)
       ScintillaSendMessage(#g_sci,#SCI_SETSELECTIONSTART,p,0)
       ScintillaSendMessage(#g_sci,#SCI_SETSELECTIONEND,  q,0)
       ScintillaSendMessage(#g_sci,#SCI_LINESCROLL,0,n)
EndProcedure

Procedure UpdateScintillaStyles( rules.s )
   ScintillaSendMessage(#g_sci,#SCI_STYLECLEARALL,0,0)
   For a=1 To CountString(rules,#LF$)+1
      s.s=StringField(StringField(rules,a,#LF$),1," ")
      If Len(s)>0 And style<9
         style+1
         For b=1 To Len(s)
            c.s=Mid(s,b,1)
            Select c
               Case "s" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBOLD,      style,#True)
               Case "i" : ScintillaSendMessage(#g_sci,#SCI_STYLESETITALIC,    style,#True)
               Case "u" : ScintillaSendMessage(#g_sci,#SCI_STYLESETUNDERLINE, style,#True)
               Case "w" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$FFFFFF)
               Case "l" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$AAAAAA)
               Case "d" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$555555)
               Case "k" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$000000)
               Case "r" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$0000AA)
               Case "g" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$00AA00)
               Case "b" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$AA0000)
               Case "c" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$AAAA00)
               Case "m" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$AA00AA)
               Case "y" : ScintillaSendMessage(#g_sci,#SCI_STYLESETFORE,      style,$00AAAA)
               Case "W" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$FFFFFF)
               Case "L" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$AAAAAA)
               Case "D" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$555555)
               Case "K" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$000000)
               Case "R" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$7777FF)
               Case "G" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$77FF77)
               Case "B" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$FFAAAA)
               Case "C" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$FFFF77)
               Case "M" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$FF77FF)
               Case "Y" : ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,      style,$77FFFF)
            EndSelect
         Next
      EndIf
   Next
EndProcedure

Procedure.s GetCleanRulesExpression()
   s.s=GetGadgetText(#g_rules)
   s=ReplaceString(s,#CR$,"")
   s=ReplaceString(s,#TAB$," ")
   While FindString(s,#LF$+" ",1)   : s=ReplaceString(s,#LF$+" ",#LF$)    : Wend
   While FindString(s,#LF$+#LF$,1)  : s=ReplaceString(s,#LF$+#LF$,#LF$)   : Wend 
   ProcedureReturn LTrim(Trim(s,#LF$))
EndProcedure

Procedure CheckRulesUpdate( cleanexpr.s )
   Static oldrules.s 
   If oldrules<>cleanexpr : r=1 : Else : r=0 :EndIf
   oldrules=cleanexpr
   ProcedureReturn r
EndProcedure


; --------

ProcedureDLL ScintillaCallBack(Gadget, *scinotify.SCNotification)
EndProcedure

Procedure OpenMWin()
   Enumeration : #fnt_rules : EndEnumeration
   LoadFont(#fnt_rules,K_fontface,9)
   flgs=#PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MaximizeGadget|#PB_Window_MinimizeGadget
   OpenWindow(#mwin,0,0,400,400,"Scintilla",flgs)
   ScintillaGadget(#g_sci,    0,0,200,400,@ScintillaCallback()) 
      ScintillaSendMessage(#g_sci,#SCI_STYLESETFONT,#STYLE_DEFAULT,@K_fontface)
      ScintillaSendMessage(#g_sci,#SCI_STYLESETSIZE,#STYLE_DEFAULT,9)
      ScintillaSendMessage(#g_sci,#SCI_STYLESETBACK,#STYLE_DEFAULT,$D4E4E8)
      ScintillaSendMessage(#g_sci,#SCI_STYLECLEARALL,0,0)
   EditorGadget(   #g_rules,200,0,200,400)
      SetGadgetFont(#g_rules,FontID(#fnt_rules))
      SetGadgetColor(#g_rules,#PB_Gadget_BackColor,$C4D4D8)
   SplitterGadget(#g_splitter,0,0,400,400,#g_sci,#g_rules,#PB_Splitter_Vertical)
   SetGadgetState(#g_splitter,GadgetWidth(#g_splitter)*0.75)
EndProcedure

Procedure ResizeMWin()
   ResizeGadget(#g_splitter,0,0,WindowWidth(#mwin),WindowHeight(#mwin))
EndProcedure


OpenMWin()

Repeat
   EvID=WaitWindowEvent()
   Select EvID
      Case #PB_Event_Gadget
         EvG=EventGadget()
         Select EvG
            Case #g_rules
               rules.s=GetCleanRulesExpression()
               If CheckRulesUpdate(rules) 
                  UpdateScintillaStyles(rules) 
               EndIf
               ScintillaStyleText(rules)
            Case #g_sci
               If ScintillaSendMessage(#g_sci,#SCI_GETMODIFY,0,0)
                  ScintillaStyleText(rules)
                  ScintillaSendMessage(#g_sci,#SCI_SETSAVEPOINT,0,0)
               EndIf
            
         EndSelect
      Case #PB_Event_SizeWindow
         ResizeMWin()
   EndSelect
Until EvID=#PB_Event_CloseWindow
EDIT: sorry, corrected the first lines of code about Linux (InitScintilla() moved in the compiler conditionals, trailing '!' in fontname for Pango rendering)
EDIT: added proper scrolling code