Creating an IDE

Just starting out? Need help? Post your questions and find answers here.
User avatar
captain_skank
Enthusiast
Enthusiast
Posts: 641
Joined: Fri Oct 06, 2006 3:57 pm
Location: England

Creating an IDE

Post by captain_skank »

Hi all,

I've been pratting around with creating my own form designer that fits my own specific needs.

I'm quite happy with what i've come up with but want to extend it to be able to include code.

But i have no idea on the best way to acheive this as i'd like to include the funtionality of the default pb ide such as completion, syntax colouring etc.

Is there a simple way to do this E.G importing from the PB IDE or has this all got be coded from scratch using the scinitilla gadget ??

cheers
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: Creating an IDE

Post by mestnyi »

using scintilla gadget ?? yay
I think it would be better, especially since there are examples for this
Я очень доволен тем, что я придумал
It was very interesting to see :)
User avatar
captain_skank
Enthusiast
Enthusiast
Posts: 641
Joined: Fri Oct 06, 2006 3:57 pm
Location: England

Re: Creating an IDE

Post by captain_skank »

Does the existing PB ide utilise scintilla ?? and is there a way of exporting the parser ??

Cos doin this from scratch just seems like reinventing the wheel :)
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Creating an IDE

Post by Tenaja »

captain_skank wrote:Does the existing PB ide utilise scintilla ??
Yes.
and is there a way of exporting the parser ??

Cos doin this from scratch just seems like reinventing the wheel :)
No.

However, if you use GoScintilla (a very powerful lexer by srod), you get most of PB's lexer capabilities by loading variables with keywords plus a few lines of setup calls.
User avatar
ostapas
Enthusiast
Enthusiast
Posts: 192
Joined: Thu Feb 18, 2010 11:10 pm

Re: Creating an IDE

Post by ostapas »

Just an idea - if I had the same purpose and wanted to achieve the result as fast as possible - just used some mainstream programming language + human usable IDE(e.g. Delphi or VS) + some commercial components, e.g. http://www.econtrol.ru/formdsn.html
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: Creating an IDE

Post by freak »

The IDE's syntax parser (the one that does the coloring) is available as a dll in the purebasic package in the SDK folder. This make it easy to add coloring to a project. A basic example is provided below. Features like auto completion will be more work as you need to scan the source code yourself to extract tokens such as variables and functions for the completion list.

Scintilla documentation: http://www.scintilla.org/ScintillaDoc.html

Code: Select all

; Color values returned in the Dll callback
;
Enumeration
  #SYNTAX_Text
  #SYNTAX_Keyword  
  #SYNTAX_Comment
  #SYNTAX_Constant
  #SYNTAX_String
  #SYNTAX_Function
  #SYNTAX_Asm
  #SYNTAX_Operator
  #SYNTAX_Structure
  #SYNTAX_Number
  #SYNTAX_Pointer
  #SYNTAX_Separator
  #SYNTAX_Label  
  #SYNTAX_Module
EndEnumeration

; Define protype for the dll function
;
Prototype SyntaxHighlight(*Buffer, Length, *Callback, Asm)
Global SyntaxHighlight.SyntaxHighlight

; Callback for the syntax parser
;
Procedure ColorCallback(*Position, Length, Color)
  ScintillaSendMessage(0, #SCI_SETSTYLING, Length, Color)
EndProcedure

; Callback for scintilla events
;
Procedure ScintillaCallback(Gadget, *scinotify.SCNotification)
  Protected LastStyled, Range.TextRange

  ; This event indicates that new coloring is needed. The #SCI_GETENDSTYLED message and *scinotify\position indicate the range to color
  If *scinotify\nmhdr\code = #SCN_STYLENEEDED
  
    ; calculate the range to color
    ; always start coloring at the line start 
    LastStyled = ScintillaSendMessage(Gadget, #SCI_GETENDSTYLED)
    Range\chrg\cpMin = ScintillaSendMessage(Gadget, #SCI_POSITIONFROMLINE, ScintillaSendMessage(Gadget, #SCI_LINEFROMPOSITION, LastStyled))
    Range\chrg\cpMax = *scinotify\position
    Range\lpstrText = AllocateMemory(Range\chrg\cpMax - Range\chrg\cpMin + 1)
    
    If Range\lpstrText
      ; retrieve the text range
      ScintillaSendMessage(Gadget, #SCI_GETTEXTRANGE, 0, @Range)   
      
      ; start coloring
      ScintillaSendMessage(Gadget, #SCI_STARTSTYLING, Range\chrg\cpMin, $FF)   
      
      ; call the parser function in the dll
      ; the callback above will apply the colors to the returned tokens      
      SyntaxHighlight(Range\lpstrText, Range\chrg\cpMax - Range\chrg\cpMin, @ColorCallback(), #False)      
      
      FreeMemory(Range\lpstrText)
    EndIf
    
  EndIf  
EndProcedure


If InitScintilla() And OpenLibrary(0, #PB_Compiler_Home + "SDK\Syntax Highlighting\SyntaxHilighting.dll")

  ; get the syntax parser function
  SyntaxHighlight = GetFunction(0, "SyntaxHighlight")

  ; create window and gadget
  OpenWindow(0, 0, 0, 640, 480, "Tiny Editor", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget)
  ScintillaGadget(0, 0, 0, 640, 480, @ScintillaCallback())
  
  ; Important: tell the gadget to send the #SCN_STYLENEEDED notification to the callback if coloring is needed
  ScintillaSendMessage(0, #SCI_SETLEXER, #SCLEX_CONTAINER)
  
  ; Enable line numbers
  ScintillaSendMessage(0, #SCI_SETMARGINTYPEN, 0, #SC_MARGIN_NUMBER)
      
  ; Set common style info
  Define *FontName = AllocateMemory(StringByteLength("Courier New", #PB_Ascii) + 1)
  If *FontName
    PokeS(*FontName, "Courier New", -1, #PB_Ascii)
    ScintillaSendMessage(0, #SCI_STYLESETFONT, #STYLE_DEFAULT, *FontName)    
    FreeMemory(*FontName)
  EndIf  
  ScintillaSendMessage(0, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 12) 
  ScintillaSendMessage(0, #SCI_STYLESETBACK, #SCI_STYLESETFORE, 0)
  ScintillaSendMessage(0, #SCI_STYLESETBACK, #STYLE_DEFAULT, $DFFFFF)
  ScintillaSendMessage(0, #SCI_STYLECLEARALL)
    
  ; Set individual colors
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Text, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Keyword, $666600)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Comment, $AAAA00)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Constant, $724B92)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_String, $FF8000)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Function, $666600)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Asm, $DFFFFF)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Operator, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Structure, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Number, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Pointer, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Separator, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Label, 0)
  ScintillaSendMessage(0, #SCI_STYLESETFORE, #SYNTAX_Module, 0)
  ScintillaSendMessage(0, #SCI_STYLESETBOLD, #SYNTAX_Keyword, #True)
  
  ; Minimalistic event loop
  Define Event
  Repeat 
    Event = WaitWindowEvent()
    If Event = #PB_Event_SizeWindow
      ResizeGadget(0, 0, 0, WindowWidth(0), WindowHeight(0))
    EndIf
  Until Event = #PB_Event_CloseWindow

Else
  MessageRequester("Error", "Cannot load scintilla or parser dll")
EndIf
quidquid Latine dictum sit altum videtur
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Re: Creating an IDE

Post by registrymechanic22 »

Hi

Please show an example of how to highlight the syntax?

For example:
for, goto - green
next, add - red

I do not understand how to use this code.
Thank you!

Best regards.
User avatar
falsam
Enthusiast
Enthusiast
Posts: 632
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Creating an IDE

Post by falsam »

registrymechanic22 wrote:Please show an example of how to highlight the syntax?

For example: for, goto - green next, add - red
A piece of code without the sdk Syntax Highlighting

Code: Select all

EnableExplicit

Enumeration Highlight
  #Style_KeyWord_Green
  #Style_KeyWord_Red
  #Style_NonKeyWord
EndEnumeration

Enumeration Form
  #Mainform
EndEnumeration

Enumeration Gadget  
  #Editor
EndEnumeration

;-Déclaration variable et procédures 
Global WindowStyle.i=#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget

;Your KeyWords
Global KeyWordGreen.s = "For|Goto"
Global KeyWordRed.s = "Next|Add"
Global KeyWordSep.s = "|" 

;Summary
Declare Start()
Declare ScintillaCallBack(Gadget, *scinotify.SCNotification)
Declare ScintillaProperties(Gadget)
Declare KeyWord(Key.s)
Declare Highlight(Gadget.l, EndPos.l)
Declare ScintillaGetLineEndPosition(Gadget, Line)
Declare ScintillaLineFromPosition(gadget, Pos)
Declare MainFormClose()

Start()

Procedure Start()  
  OpenWindow(#MainForm,  0,  0, 1024, 768, "ScintillaGadget : Custom Highlight", WindowStyle)
  
  If InitScintilla()
    ScintillaGadget(#Editor, 10, 40, 1004, 668, @ScintillaCallBack())
    ScintillaProperties(#Editor)
    SetActiveGadget(#Editor)
  EndIf
  RemoveKeyboardShortcut(#Mainform, #PB_Shortcut_Tab) ;Tab key enable  
  BindEvent(#PB_Event_CloseWindow, @MainFormClose(), #MainForm)
  Repeat : WaitWindowEvent(10) : ForEver
EndProcedure

;Scintilla Properties
Procedure ScintillaProperties(Gadget)
  ;Character between each word in the KeyWord list 
  ScintillaSendMessage(Gadget, #SCI_AUTOCSETSEPARATOR, Asc(KeyWordSep))
  
  ;Style KeyWord Green
  ScintillaSendMessage(Gadget, #SCI_STYLESETFORE, #Style_KeyWord_Green, RGB(50, 205, 50))    
  
  ;Style KeyWord Red
  ScintillaSendMessage(Gadget, #SCI_STYLESETFORE, #Style_KeyWord_Red, RGB(255, 0, 0))    
  
  ;Style NonKeyWord
  ScintillaSendMessage(Gadget, #SCI_STYLESETFORE, #Style_NonKeyWord, RGB(0, 0, 0))      
EndProcedure

;Scintilla CallBack
Procedure ScintillaCallBack(Gadget, *scinotify.SCNotification)
  Select *scinotify\nmhdr\code          
    Case #SCN_STYLENEEDED
      Highlight(Gadget, *scinotify\position)
      
  EndSelect 
EndProcedure


Procedure KeyWord(Key.s)
  Protected n
  
  If Key=""
    ProcedureReturn -1
  EndIf 
  
  ;KeyWordGreen
  For n=1 To CountString(KeyWordGreen, KeyWordSep) + 1
    If LCase(StringField(KeyWordGreen, n, KeyWordSep)) = LCase(Key)
      ProcedureReturn #Style_KeyWord_Green
    EndIf
  Next
  
  ;KeyWordRed
  For n=1 To CountString(KeyWordRed, KeyWordSep) + 1
    If LCase(StringField(KeyWordRed, n, KeyWordSep)) = LCase(Key)
      ProcedureReturn #Style_KeyWord_Red  
    EndIf
  Next
  
  ProcedureReturn #Style_NonKeyWord
EndProcedure

Procedure Highlight(Gadget.l, EndPos.l)
  Protected Char.i, KeyWord.s, StyleID.i
  Protected CurrentPos.i = 0, EndLinePos.i
  
  EndPos = ScintillaGetLineEndPosition(Gadget, ScintillaLineFromPosition(Gadget, EndPos))
  ScintillaSendMessage(Gadget, #SCI_STARTSTYLING, CurrentPos, $1F | #INDICS_MASK)
  
  While CurrentPos <= EndPos
    Char = ScintillaSendMessage(Gadget, #SCI_GETCHARAT, CurrentPos)
    
    Select Char
      Case 'a' To 'z', 'A' To 'Z'
        EndLinePos = ScintillaGetLineEndPosition(Gadget, ScintillaLineFromPosition(Gadget, CurrentPos))
        KeyWord = Chr(Char)
        
        While CurrentPos < EndLinePos
          CurrentPos + 1
          Char = ScintillaSendMessage(Gadget, #SCI_GETCHARAT, CurrentPos)
          If Not ((Char >= 'a' And Char <= 'z') Or (Char >= 'A' And Char <= 'Z') Or Char = '_'Or (Char >= '0' And Char <= '9'))
            CurrentPos-1
            Break
          EndIf
          KeyWord + Chr(Char)
        Wend
        
        ;-KeyWord or not KeyWord ?
        Select KeyWord(KeyWord)  
          Case #Style_KeyWord_Green
            StyleID = #Style_KeyWord_Green
            
          Case #Style_KeyWord_Red
            StyleID = #Style_KeyWord_Red
            
          Default
            StyleID = #Style_NonKeyWord
        EndSelect    
        
        ScintillaSendMessage(Gadget, #SCI_SETSTYLING, Len(KeyWord), StyleID) 
        
      Default
        ScintillaSendMessage(Gadget, #SCI_SETSTYLING, 1, #Style_NonKeyWord)
        
    EndSelect
    CurrentPos+1
  Wend 
EndProcedure

Procedure ScintillaGetLineEndPosition(Gadget, Line)
  ProcedureReturn ScintillaSendMessage(Gadget, #SCI_GETLINEENDPOSITION, Line)
EndProcedure

Procedure ScintillaLineFromPosition(gadget, Pos)
  ProcedureReturn ScintillaSendMessage(Gadget, #SCI_LINEFROMPOSITION, Pos)
EndProcedure

Procedure MainFormClose()
  End
EndProcedure

➽ Windows 11 64-bit - PB 6.21 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect 🤪
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Re: Creating an IDE

Post by registrymechanic22 »

falsam wrote:....
Wonderful and simple example!
Thank you so much!
Best regards.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Creating an IDE

Post by Keya »

i agree thats a really nice example! :) it also compiles to just 40kb x86 Windows exe - i didn't realise how lightweight Scintilla is!?!?
User avatar
kenmo
Addict
Addict
Posts: 2042
Joined: Tue Dec 23, 2003 3:54 am

Re: Creating an IDE

Post by kenmo »

Keya wrote:it also compiles to just 40kb x86 Windows exe - i didn't realise how lightweight Scintilla is!?!?
You have to include the Scintilla DLL with your program, which adds ~400 kB.
(On Mac/Linux Scintilla is automatically included in your executable)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Creating an IDE

Post by Keya »

ahh i see. I had a look at the .exe dependencies and couldnt see scintilla.dll linked, so i guess InitScintilla() loads it dynamically. 40kb standalone for a full-featured editor gadget probably was asking a bit much :D
Post Reply