Example46: Lexer - Container (Simple)

Category: Controls - Scintilla

Date: 03-28-2012

Return to Index


 
'A lexer scans text and breaks it up into separate language objects,
'e.g. keywords, strings, operators. The lexer then uses a different style
'to draw each object, typically with common background colors but with
'different foreground colors.  This is often referred to as syntax
'highlighting.
 
'In addition to defining white space, punctuation characters, and other
'source code syntax characters, most lexers work off a single set of
'keywords to which syntax highlighting is applied.
 
'Some languages, however, such as HTML, may use several sets of keywords.
'This may be useful, for example, for keeping JavaScript or other embedded
'languages separate from the HTML language.
 
'Each language lexer implements its own unique styling.
 
'Once text is styled, the application can further style the text (such
'as creating URL hotspots).
 
'You can implement a lexer in 3 different ways
'1. Built-In (part of the Scintilla DLL)
    SendMessage hSci, %SCI_SETLEXER,  %SCLEX_PowerBASIC, 0  'built-in PB index
 
'2. External Lexer (create your own custom DLL)
    txt = "powerbasic_lexer.dll"
    SendMessage hSci, %SCI_LoadLexerLibrary, 0, StrPTR$(txt) 'load the custom DLL
    txt = "powerbasic_custom"
    SendMessage hSci, %SCI_SETLEXERLANGUAGE, 0, StrPTR$(txt) 'use name of language to load the lexer
 
'3. Container (write the lexer code in container application)
    SendMessage hSci, %SCI_SETLEXER,  %SCLEX_CONTAINER, 0  'built-in PB index
 
'This snippet discusses implementing the lexer within the container application.
 
'While Scintilla provides built-in lexers for dozens of languages, it also
'provides the capability for the container application to provide the lexer,
'written in the language of the container application.
 
'The two big advantages of allowing a custom lexer are
'1. You can override/modify the built-in lexers to meet your editing
'   requirements or preferences.
'2. If Scintilla has no built-in support for your language you can provide
    'one of your own.
 
'The approach to using an internal lexer is to send a message to Scintilla
'telling it to use a container lexer in lieu of a built-in lexer, and then to
'provide a container function to provide the lexing.  Scintilla will send a
'SCN_StyleNeeded message to the container whenever a lexing action is required.
 
'On receiving the message, you need to set the style of the text from the
'line that contains the position returned by SCI_GETENDSTYLED up to the
'position passed in SCNotification.position by the message.
 
'Writing the custom lexer is the responsibility of the programmer, but the source
'code for the built-in lexers are available to help provide guidance.  This snippet
'also provides a simple example of a lexer - one that sets the style of the current
'line to a specified style.
 
 
'Primary Code
'Send this message to tell Scintilla to use a lexer function from within
'the container application.
 
      SendMessage hSci, %SCI_SETLEXER,  %SCLEX_CONTAINER, 0         'container does lexing
 
'In addition to stopping Scintilla from using a built-in lexer, the message
'above will tell Scintilla to send a %WM_Notify/SCN_StyleNeeded message to
'the container application whenever lexing is required. Use this code to
'capture the message and to execute the container lexer function.
 
      Case %WM_Notify
         If CB.Ctl = %ID_Sci Then
            pNSC = CB.lParam
            Select Case @pNSC.hdr.Code
               Case %SCN_StyleNeeded
                  CustomLexer @pNSC.position
           End Select
         End If
 
'As was stated above, in response to the message you need to set the style of
'the text from the line that contains the position returned by SCI_GETENDSTYLED
'up to the position passed in SCNotification.position.
 
   iPos = SendMessage(hSci, %SCI_GetEndStyled,0,0)           'position where styling starts
   iLine  = SendMessage(hSci, %SCI_LineFromPosition,iPos,0)  'line where styling starts
   iStart = SendMessage(hSci, %SCI_PositionFromLine,iLine,0) 'start of line where styling starts
   SendMessage(hSci, %SCI_StartStyling,iStart,31)            'set styling starting pos
   iLineLength = SendMessage(hSci, %SCI_LineLength, iLine, 0)
   c = Chr$(SendMessage(hSci, %SCI_GetCharAt, iStart, 0))
   If c = "'Then
      SendMessage(hSci, %SCI_SetStyling, iLineLength, %SCE_Style_Green)
   Else
      SendMessage(hSci, %SCI_SetStyling, iLineLength, %Style_Default)
   End If
 
 
'Compilable Example:
#Compiler PBWin 9, PBWin 10
#Compile EXE
#Dim All
#Include "Win32API.inc"
#Include "scintilla_gb.inc"
 
%ID_Sci = 1000
%SCE_Style_Green = 1
 
Global hDlg, hSci, hLib As DWord
 
Function PBMain() As Long
   hLib = LoadLibrary("SCILEXER.DLL")
   Dialog New Pixels, 0, "Scintilla: Container Lexer",300,300,200,150, %WS_OverlappedWindow To hDlg
   Control Add "Scintilla", hDlg, %ID_Sci, "", 10,10,180,130, %WS_Child Or %WS_Visible
   Control Handle hDlg, %ID_Sci To hSci     'get handle to Scintilla window
   Dialog Show Modal hDlg Call DlgProc
End Function
 
CallBack Function DlgProc() As Long
   Local pNSC As SCNotification Ptr       ' // Scintilla notification messages
   Select Case CB.Msg
      Case %WM_InitDialog
         InitializeSci
         PostMessage hSci, %SCI_SetSel, 0,0 'unselect initially
      Case %WM_Notify
         Select Case CB.NmID
            Case %ID_Sci
               pNSC = CB.lParam
               Select Case @pNSC.hdr.Code
                  Case %SCN_StyleNeeded
                     CustomPBLexer @pNSC.position
               End Select
         End Select
      Case %WM_Size
         Control Set Size hDlg, %ID_Sci, Lo(Word, CB.lParam)-20, Hi(Word, CB.lParam)-20
      Case %WM_Destroy
         If hLib Then FreeLibrary hLib             ' Free the Scintilla library
   End Select
End Function
 
Sub InitializeSci
   Local txt As String
   txt = "Select Case" + $CrLf
   txt = txt + "'   Case " + Chr$(34) + "cat" + Chr$(34) + $CrLf
   txt = txt + "'   Case " + Chr$(34) + "dog" + Chr$(34) + $CrLf
   txt = txt + "End Select" + Chr$(0)
   SendMessage(hSci, %SCI_SetText,         0, StrPTR(txt))       'set example text
   SendMessage hSci, %SCI_SetMarginWidthN, 0, 20                 'display line numbers
   SendMessage hSci, %SCI_StyleSetFore, %SCE_Style_Green, %Green 'style 11 FG is now blue
   SendMessage hSci, %SCI_SETLEXER,  %SCLEX_CONTAINER, 0         'container does lexing
End Sub
 
Sub CustomPBLexer (ByVal iEndPos As Long)
   Local i, iPos, iStartPos, iStartLine, iEndLine, iLineLength As Long, c As String
 
   If 1 Then
      'only lines from position returned by GetEndStyle to line containing SCNotification.position
      iStartPos = SendMessage(hSci, %SCI_GetEndStyled,0,0)
      iStartLine  = SendMessage(hSci, %SCI_LineFromPosition,iStartPos,0) 'start line
      iEndLine = SendMessage(hSci, %SCI_LineFromPosition,iEndPos,0)      'end line
   Else
      'entire document
      iStartLine = 0                                              'first line
      iEndLine = SendMessage( hSci, %SCI_GetLineCount, 0, 0) - 1  'last line
   End If
 
   For i = iStartLine To iEndLine
      iStartPos = SendMessage(hSci, %SCI_PositionFromLine,i,0)
      SendMessage(hSci, %SCI_StartStyling,iStartPos,31)
      iLineLength = SendMessage(hSci, %SCI_LineLength, i, 0)
      c = Chr$(SendMessage(hSci, %SCI_GetCharAt, iStartPos, 0))
      If c = "'Then
         SendMessage(hSci, %SCI_SetStyling, iLineLength, %SCE_Style_Green) 'style iLineLength characters
      Else
         SendMessage(hSci, %SCI_SetStyling, iLineLength, %Style_Default) 'style iLineLength characters
      End If
   Next i
End Sub
 
'gbs_00664
'Date: 03-10-2012


created by gbSnippets
http://www.garybeene.com/sw/gbsnippets.htm