Page 1 of 1

Creating an IDE

Posted: Wed Jan 07, 2015 11:38 am
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

Re: Creating an IDE

Posted: Wed Jan 07, 2015 11:53 am
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 :)

Re: Creating an IDE

Posted: Wed Jan 07, 2015 5:21 pm
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 :)

Re: Creating an IDE

Posted: Wed Jan 07, 2015 6:26 pm
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.

Re: Creating an IDE

Posted: Wed Jan 07, 2015 8:12 pm
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

Re: Creating an IDE

Posted: Wed Jan 07, 2015 8:35 pm
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

Re: Creating an IDE

Posted: Mon Apr 04, 2016 2:34 pm
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.

Re: Creating an IDE

Posted: Tue Apr 05, 2016 1:19 pm
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

Re: Creating an IDE

Posted: Tue Apr 05, 2016 9:55 pm
by registrymechanic22
falsam wrote:....
Wonderful and simple example!
Thank you so much!
Best regards.

Re: Creating an IDE

Posted: Tue Apr 05, 2016 10:05 pm
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!?!?

Re: Creating an IDE

Posted: Wed Apr 06, 2016 1:55 am
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)

Re: Creating an IDE

Posted: Wed Apr 06, 2016 6:52 am
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