Date: 02-16-2022
Return to Index
created by gbSnippets
'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: (Jose Includes)
#Compiler PBWin 9, PBWin 10
#Compile EXE
#Dim All
%Unicode=1
#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
http://www.garybeene.com/sw/gbsnippets.htm