Example42: Intellisense

Category: Controls - Scintilla

Date: 03-28-2012

Return to Index


 
'Most programmers have come to expect an editor to provide capabilities
'like Intellisense, as Microsoft calls it. In Scintilla terminology
'the features that Intellisense offers are:
 
'1. AutoCompletion lists when a member of a keyword group is being
'   typed, giving the user a selectable list of group members
'2. Call Tips to list the arguments of functions, with highlighting
'   of which argument is currently being typed
 
 
'Primary Code:
 
'This displays a completion list.
   txtOptions = "if ifone iffive iffour ifthree iftwo" + Chr$(0)
   SendMessage hSci, %SCI_AutoCShow, 2, StrPTR(txtOptions)
 
'To cancel any displayed autopletion list, use this:
   SendMessage hSci, %SCI_AutoCCancel, 0, 0
 
 
 
'Compilable Example:
#Compiler PBWin 9, PBWin 10
#Compile EXE
#Dim All
#Debug Error On     'catch array/pointer errors - OFF in production
#Debug Display On   'display untrapped errors   - OFF in production
#Include "Win32API.inc"
#Include "scintilla_gb.inc"
 
%ID_Sci = 1000
Global hDlg, hSci, hLib As DWord
Global txtOptions As String
Global ListSeparator As Long
 
'Intellisense globals
Global Ref_MemTerm1() As String,  Ref_MemMember1() As String
Global Ref_MemTerm2() As String,  Ref_MemMember2() As String
Global Ref_Term1() As String, Ref_Desc1() As String, Ref_Syntax1() As String
Global Ref_Term2() As String, Ref_Desc2() As String, Ref_Syntax2() As String
Global Ref_Term3() As String, Ref_Desc3() As String, Ref_Syntax3() As String
 
Function PBMain() As Long
   hLib = LoadLibrary("SCILEXER.DLL")
   Dialog New Pixels, 0, "Scintilla Example",300,300,300,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 CharAtLeft As String
   Local iPos as Long
   Local pNSC As SCNotification Ptr       ' // Scintilla notification messages
   Select Case CB.Msg
      Case %WM_InitDialog
         InitializeScintilla
         InitializeIntellisense
         PostMessage hSci, %SCI_SetSel, 0,0 'unselect initially
      Case %WM_NOTIFY
         Select Case CB.NmID
            Case %ID_Sci
               pNSC = CB.lParam
               CharAtLeft = Chr$(@pNSC.ch)
               iPos = SendMessage( hSci, %SCI_GetCurrentPos, 0, 0)  'get current position
               Select Case @pNSC.hdr.Code
                  Case %SCN_CHARADDED
                     If Instr("(. ", CharAtLeft) Then
                        Intellisense(iPos, CharAtLeft)
                     Else
                        Dialog Set Text hDlg, Str$(iPos) + " " + CharAtLeft
                     End If
                  Case %SCN_AutoCSelection
                     'if want to override selection, do something here
               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 InitializeScintilla
   Local txt As String
   txt = "If x = 2 Then" + $CrLf + "   'do nothing" + $Crlf
   txt = txt + "Else" + $crlf + "   x = 0" + $crlf + "End If" + Chr$(0)
   SendMessage hSci, %SCI_SetText, 0, StrPTR(txt)
   SendMessage hSci, %SCI_SetMarginWidthN, 0, 20
   SendMessage hSci, %SCI_GoToPos, 2, 0    'no selection (set anchor=curpos=iPos)
   Control Set Focus hDlg, %ID_Sci
End Sub
 
Sub InitializeIntellisense
   Dim Ref_Term1(0), Ref_Desc1(0), Ref_Syntax1(0)
   Dim Ref_Term2(0), Ref_Desc2(0), Ref_Syntax2(0)
   Dim Ref_Term3(0), Ref_Desc3(0), Ref_Syntax3(0)
   Dim Ref_MemTerm1(0), Ref_MemMember1(0)
   Dim Ref_MemTerm2(0), Ref_MemMember2(0)
   LoadRef "word1_short.txt", Ref_Term1(), Ref_Syntax1()
   LoadRef "word2_short.txt", Ref_Term2(), Ref_Syntax2()
   LoadRef "word3_short.txt", Ref_Term3(), Ref_Syntax3()
   LoadRef "members1.txt", Ref_memTerm1(), Ref_memMember1()
   LoadRef "members2.txt", Ref_memTerm2(), Ref_memMember2()
 
   ListSeparator = Asc(".")   'not use space because PowerBASIC uses 3-word keyword groups
   SendMessage hSci, %SCI_AutoCSetSeparator, ListSeparator, 0  'set separator
End Sub
 
Sub LoadRef (sFile$, ArrayTerm() As String, ArraySyntax() As String)
   'load any of the 5 reference files - all use the same content format   sWord:::::sSyntax
   Local temp$, i As Long
   Open sFile$ For Binary as #1 : Get$ #1, Lof(1), temp$ : Close
   temp$ = RTrim$(temp$,$crlf)
   ReDim ArrayTerm(ParseCount(temp$,$crlf)-1) As String, ArraySyntax(UBound(ArrayTerm)) As String
   Parse temp$,ArrayTerm(),$crlf
   For i = 0 to UBound(ArrayTerm)
      ArraySyntax(i) = Parse$(ArrayTerm(i),":::::", 2)
      ArrayTerm(i) = Parse$(ArrayTerm(i),":::::", 1)
   Next i
End Sub
 
Function WordsToLeft(WA As String, WB As String, WC As String, iPos As LongAs Long
   Local iCount, iLine, iStart As Long, LeftText As String, TR as Sci_TextRange
 
   'get LeftText
   iLine  = SendMessage( hSci, %SCI_LineFromPosition, iPos, 0)  'line that contains iPos
   iStart  = SendMessage( hSci, %SCI_PositionFromLine, iLine, 0)  'position of 1st char in line
   TR.chrg.cpmin = iStart  'first character to get
   TR.chrg.cpmax = iPos-1    'last character to get
   LeftText = String$(iPos-iStart, " ") + $Nul
   TR.lpstrText = StrPTR(LeftText)
   SendMessage hSci, %SCI_GetTextRange, 0, VarPTR(TR)  'get range of text
   LeftText = Trim$(TR.@lpstrText)
   LeftText = Retain$(LeftText, Any Chr$(65 To 90, 97 To 122, 48 To 57, $Spc, "$&#%?!"))  'remove all but word characters
 
   'get right-most 3 words of text
   iCount = ParseCount(LeftText, " ")
   WC = Parse$(LeftText," ",iCount)
   WB = Parse$(LeftText," ",iCount-1)
   WA = Parse$(LeftText," ",iCount-2)
End Function
 
Function BSearch(ByVal sWord As String, iArrayPos&, ArrayTerm() As String, ArraySyntax() As StringAs Long
   Local Upper As Long, Lower As Long
   Lower = LBound(ArrayTerm) : Upper = UBound(ArrayTerm) : sWord = LCase$(sWord)
   'test boundary values
   If sWord = ArrayTerm(Lower) Then iArrayPos& = Lower : Function = 1 : Exit Function
   If sWord = ArrayTerm(Upper) Then iArrayPos& = Upper : Function = 1 : Exit Function
   If sWord < ArrayTerm(Lower) Then iArrayPos& = Lower - 1 : Function = 0 : Exit Function
   If sWord > ArrayTerm(Upper) Then iArrayPos& = Upper + 1 : Function = 0 : Exit Function
   'loop through remaining entries until searchterm found, or it's determined that term is not in the array
   Do Until (Upper <= (Lower+1))
      iArrayPos& = (Lower + Upper) / 2
      If sWord > ArrayTerm(iArrayPos&) Then
         Lower = iArrayPos&
      ElseIf sWord < ArrayTerm(iArrayPos&) Then
         Upper = iArrayPos&
      Else
         Function = 1 : Exit Function
      End If
   Loop
End Function
 
Sub Intellisense(iPos As Long, CharAtLeft As String)
   Local WA, WB, WC, sWord, sSyntax As String
   Local LeftPos, iReturn As Long
 
   'get prior 3 words
   WordsToLeft(WA,WB,WC,iPos)
   Dialog Set Text hDlg, "Pos: " + Str$(iPos) + "  Char: " + CharAtLeft + " " _
      + "  Words:  " +  "___" + WA + " " + WB + " " + WC + "___"
 
   '   If SearchWordABC(WordA,WordB,WordC,WordList,LeftPos) Then
 
   If Len(WA) AND BSearch(Build$(WA,$spc,WB,$spc,WC), iReturn, Ref_Term3(), Ref_Syntax3()) Then
      '3 word sequence was found - display arguments
      sWord$ = Build$(WA,$spc,WB,$spc,WC)
      sSyntax = Ref_Syntax3(iReturn)
      SendMessage hSci, %SCI_CallTipShow, iPos, StrPTR(sSyntax)
      '       DisplaySyntaxLabel (sSyntax)
   ElseIf Len(WB) AND BSearch(Build$(WB,$spc,WC), iReturn, Ref_memTerm2(), Ref_memMember2()) Then
      '2 word sequence was found - display 3rd members
      sWord$ = Build$(WB,$spc,WC)
      sSyntax = Ref_memMember2(iReturn)
      SendMessage hSci, %SCI_AutoCShow, LeftPos, StrPTR(sSyntax)
      '       DisplaySyntaxListbox (sSyntax)
   ElseIf Len(WB) AND BSearch(Build$(WB,$spc,WC), iReturn, Ref_Term2(), Ref_Syntax2()) Then
      '2 word sequence was found with syntax - display arguments
      sWord$ = Build$(WB,$spc,WC)
      sSyntax = Ref_Syntax2(iReturn)
      SendMessage hSci, %SCI_CallTipShow, iPos, StrPTR(sSyntax)
      '       DisplaySyntaxLabel (sSyntax)
   ElseIf Len(WC) AND BSearch(WC, iReturn, Ref_memTerm1(), Ref_memMember1()) Then
      '1 word sequence was found - display 2nd member
      sWord$ = WC
      sSyntax = Ref_memMember1(iReturn)
      SendMessage hSci, %SCI_AutoCShow, LeftPos, StrPTR(sSyntax)
      '       DisplaySyntaxListBox (sSyntax)
   ElseIf Len(WC) AND BSearch(WC, iReturn, Ref_Term1(), Ref_Syntax1()) Then
      '1 word sequence was found - display arguments
      sWord$ = WC
      sSyntax = ModifySyntax(CharAtLeft, Ref_Syntax1(iReturn))
      SendMessage hSci, %SCI_CallTipShow, iPos, StrPTR(sSyntax)
      '       DisplaySyntaxLabel (sSyntax)
   Else
      'no matches were found close call tips and autocomplete
      SendMessage hSci, %SCI_CallTipCancel, 0, 0
      SendMessage hSci, %SCI_AutoCCancel, 0, 0
   End If
End Sub
 
Function ModifySyntax (sChar$, ByVal sSyntax$) As String
   '    If sChar$ = " " AND Left$(sSyntax$,1) = "(" Then             'optional way to skip leading (
   '        sSyntax$ = Mid$(sSyntax$, 2, Len(sSyntax$)-2)
   If sChar$ = "(AND Left$(sSyntax$,1) = "(Then
      sSyntax$ = Mid$(sSyntax$, 2)         'do not allow ((
   ElseIf sChar$ = "(AND Left$(sSyntax$,1) <> "(Then
      sSyntax$ = ""                        'if sChar is (, then sSyntax must also start with (, otherwise, don't show sSyntax
   End If
   Function = sSyntax$
End Function
 
'gbs_00660
'Date: 03-10-2012


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