Ooops
March 05, 2021, 07:06:48 AM

Author Topic: [bmx] CodeArea Gadget by JoshK [ 1+ years ago ]  (Read 641 times)

Offline BlitzBot

[bmx] CodeArea Gadget by JoshK [ 1+ years ago ]
« on: June 29, 2017, 12:28:40 AM »
Title : CodeArea Gadget
Author : JoshK
Posted : 1+ years ago

Description : This should work 100% correctly.  The syntax highlighter will support BlitzMax, Lua, and C, with multi-line comments.  Lua double and single-quote strings are supported.

GO TO THE BOTTOM OF THIS THREAD FOR THE MOST RECENT VERSION


Code :
Code: BlitzMax
  1. SuperStrict
  2.  
  3. Import maxgui.drivers
  4. Import maxgui.proxygadgets
  5.  
  6. 'Codearea style constants
  7. Const CODEAREA_SYNTAXHIGHLIGHTING:Int=1
  8. Const CODEAREA_CANUNDO:Int=2
  9. Const CODEAREA_CORRECTCASE:Int=4
  10. Const CODEAREA_READONLY:Int=8
  11. Const CODEAREA_DEFAULT:Int=CODEAREA_SYNTAXHIGHLIGHTING|CODEAREA_CANUNDO|CODEAREA_CORRECTCASE
  12.  
  13. 'Codearea format constants
  14. Const CODEAREA_PLAIN:Int=0
  15. Const CODEAREA_STRING:Int=1
  16. Const CODEAREA_COMMENT:Int=2
  17. Const CODEAREA_KEYWORD:Int=3
  18. Const CODEAREA_PREPROCESSOR:Int=4
  19.  
  20. 'CodeArea language constants
  21. Const CODEAREA_C:Int=0
  22. Const CODEAREA_LUA:Int=1
  23. Const CODEAREA_BMX:Int=2
  24.  
  25. Private
  26.  
  27. Type TAction
  28.        
  29.         Field add:String
  30.         Field addpos:Int
  31.         Field addlen:Int
  32.         Field remove:String
  33.         Field removepos:Int
  34.         Field removelen:Int
  35.         Field beforepos:Int
  36.         Field beforelen:Int
  37.         Field afterpos:Int
  38.         Field afterlen:Int
  39.        
  40.         Method Undo(codearea:TCodeArea)
  41.                 Local n:Int
  42.                
  43.                 SetTextAreaText codearea,remove,addpos,addlen
  44.                 SelectTextAreaText codearea,beforepos,beforelen
  45.                 If (CODEAREA_SYNTAXHIGHLIGHTING & codearea.style)
  46.                         LockTextArea codearea.textarea
  47.                         For n=TextAreaLine(codearea.textarea,beforepos) To TextAreaLine(codearea.textarea,beforepos+beforelen)
  48.                                 If codearea.FormatLine(n) Exit
  49.                         Next
  50.                         UnlockTextArea codearea.textarea
  51.                 EndIf
  52.                 EmitEvent CreateEvent(EVENT_GADGETSELECT,codearea,addpos-remove.length)
  53.         EndMethod
  54.        
  55.         Method Redo(codearea:TCodeArea)
  56.                 Local n:Int
  57.  
  58.                 SetTextAreaText codearea,add,removepos,removelen
  59.                 SelectTextAreaText codearea,afterpos,afterlen
  60.                 If (CODEAREA_SYNTAXHIGHLIGHTING & codearea.style)
  61.                         LockTextArea codearea.textarea
  62.                         For n=TextAreaLine(codearea.textarea,afterpos) To TextAreaLine(codearea.textarea,afterpos+afterlen)
  63.                                 If codearea.FormatLine(n) Exit
  64.                         Next
  65.                         UnlockTextArea codearea.textarea
  66.                 EndIf
  67.                 EmitEvent CreateEvent(EVENT_GADGETSELECT,codearea,removepos+add.length)
  68.         EndMethod
  69.        
  70. EndType
  71.  
  72. Type TFormat
  73.        
  74.         Field r:Int
  75.         Field g:Int
  76.         Field b:Int
  77.         Field style:Int
  78.        
  79.         Function Create:TFormat(r:Int,g:Int,b:Int,style:Int)
  80.                 Local format:TFormat=New TFormat
  81.                 format.r=r
  82.                 format.g=g
  83.                 format.b=b
  84.                 format.style=style
  85.                 Return format
  86.         EndFunction
  87.        
  88. EndType
  89.  
  90. Public
  91.  
  92. Type TCodeArea Extends TProxyGadget
  93.        
  94.         Global dummywindow:TGadget' used to hold dummy textarea
  95.         Global dummytextarea:TGadget' used for paste operations
  96.         Global maxundolevels:Int=0' set to 0 to disable limit
  97.        
  98.         Field textarea:TGadget
  99.         Field selpos:Int
  100.         Field sellen:Int
  101.         Field text:String
  102.         Field undoposition:Int=-1
  103.         Field actions:TAction[]
  104.         Field format:TFormat[6]
  105.         Field needsreformat:Int
  106.         Field locked:Int
  107.         Field keywords:TMap=New TMap
  108.         Field token_comment:String="//"
  109.         Field token_multilinecommentbegin:String="/*"
  110.         Field token_multilinecommentend:String="*/"
  111.         Field token_string:String="~q"
  112.         Field token_string2:String' Lua uses multiple string tokens
  113.         Field token_preprocessor:String="#"
  114.         Field multilinecommentstyle:Int
  115.         Field lineincommentblock:Byte[]
  116.         Field multilinecommentschanged:Int
  117.        
  118.         Method New()
  119.                 format[CODEAREA_PLAIN]=TFormat.Create(0,0,0,0)
  120.                 format[CODEAREA_STRING]=TFormat.Create(128,0,128,0)
  121.                 format[CODEAREA_COMMENT]=TFormat.Create(0,128,0,0)
  122.                 format[CODEAREA_PREPROCESSOR]=TFormat.Create(255,0,0,0)
  123.                 format[CODEAREA_KEYWORD]=TFormat.Create(0,0,255,0)
  124.         EndMethod
  125.        
  126.         Method Cleanup()
  127.                 RemoveHook EmitEventHook,EventHook,Self
  128.         EndMethod
  129.        
  130.         '---------------------------------------------------------------------------------------------
  131.         'Syntax highlighting
  132.         '--------------------------------------------------------------------------------------------- 
  133.         Method SetLanguage(language:Int)
  134.                 Select language
  135.                
  136.                 Case CODEAREA_C
  137.                         token_comment="//"
  138.                         token_multilinecommentbegin="/*"
  139.                         token_multilinecommentend="*/"
  140.                         token_string="~q"
  141.                         token_string2=""
  142.                         token_preprocessor="#"                 
  143.                         multilinecommentstyle=0
  144.                
  145.                 Case CODEAREA_LUA
  146.                         token_comment="--"
  147.                         token_multilinecommentbegin="--[["
  148.                         token_multilinecommentend="]]--"
  149.                         token_string="~q"
  150.                         token_string2="'"
  151.                         token_preprocessor=""
  152.                         multilinecommentstyle=0
  153.                
  154.                 Case CODEAREA_BMX
  155.                         token_comment="'"
  156.                         token_multilinecommentbegin="Rem"
  157.                         token_multilinecommentend="EndRem"
  158.                         token_string="~q"
  159.                         token_string2=""
  160.                         token_preprocessor="?"
  161.                         multilinecommentstyle=1
  162.                
  163.                 EndSelect
  164.                
  165.                 FormatAll()
  166.         EndMethod
  167.        
  168.         Method LockText()
  169.                 locked=True
  170.                 textarea.LockText()
  171.         EndMethod
  172.        
  173.         Method UnlockText()
  174.                 textarea.UnlockText()
  175.                 locked=False
  176.                 If needsreformat FormatAll()
  177.         EndMethod
  178.        
  179.         Method SetFont(font:TGUIFont)
  180.                 Local n:Int
  181.                
  182.                 format[CODEAREA_PLAIN].style=FontStyle(font)
  183.                 textarea.SetFont(font)
  184.                 FormatAll()
  185.         EndMethod
  186.        
  187.         Method SetTextColor(r:Int,g:Int,b:Int)
  188.                 Local n:Int
  189.                
  190.                 format[CODEAREA_PLAIN].r=r
  191.                 format[CODEAREA_PLAIN].g=g
  192.                 format[CODEAREA_PLAIN].b=b
  193.                 FormatAll()
  194.         EndMethod
  195.        
  196.         Method AddKeyword(word:String)
  197.                 keywords.insert(word.tolower(),word)
  198.         EndMethod
  199.        
  200.         Method ClearKeywords()
  201.                 keywords.Clear()
  202.         EndMethod
  203.        
  204.         Method KeywordExists:Int(word:String)
  205.                 Local keyword:String
  206.                 keyword=String(keywords.valueforkey(word.tolower()))
  207.                 If keyword
  208.                         If Not (CODEAREA_CORRECTCASE & style)
  209.                                 If keyword=word
  210.                                         Return True
  211.                                 Else
  212.                                         Return False
  213.                                 EndIf
  214.                         Else
  215.                                 Return True
  216.                         EndIf
  217.                 Else
  218.                         Return False
  219.                 EndIf
  220.         EndMethod
  221.        
  222.         Method SetFormat(element:Int,r:Int,g:Int,b:Int,style:Int)
  223.                 format[element]=TFormat.Create(r,g,b,style)
  224.                 FormatAll()
  225.         EndMethod
  226.        
  227.         Field dontupdatemultilinecomments:Int
  228.        
  229.         Method FormatAll()
  230.                 Print "FORMATALL"
  231.                 Local n:Int
  232.                 Local multilinecommentbegun:Int
  233.                 For n=0 To lineincommentblock.length-1
  234.                         lineincommentblock[n]=0
  235.                 Next
  236.                
  237.                 dontupdatemultilinecomments=True
  238.                 If locked
  239.                         needsreformat=True
  240.                 Else
  241.                         LockTextArea textarea
  242.                         For n=0 To TextAreaLen(textarea,TEXTAREA_LINES)-1
  243.                                 If FormatLine(n) Exit
  244.                         Next
  245.                         UnlockTextArea textarea
  246.                         needsreformat=False                    
  247.                 EndIf
  248.                 dontupdatemultilinecomments=False
  249.         EndMethod
  250.        
  251.         Method CharacterInQuotes:Int(s:String,c:Int)
  252.                 Local n:Int
  253.                 Local char:String
  254.                 Local stringopen:Int
  255.                 Local string2open:Int
  256.                 Local stringopenpos:Int
  257.                 Local string2openpos:Int
  258.                
  259.                 For n=0 To c
  260.                         char=Chr(s[n])
  261.                         Select char
  262.                         Case token_string
  263.                                 stringopen=Not stringopen
  264.                                 stringopenpos=n
  265.                         Case token_string2
  266.                                 If token_string2<>token_string
  267.                                         string2open=Not string2open
  268.                                         string2openpos=n
  269.                                 EndIf
  270.                         EndSelect
  271.                 Next
  272.                 If stringopen
  273.                         If s.Find(token_string,stringopenpos+1)>-1 Return True
  274.                 EndIf
  275.                 If string2open
  276.                         If s.Find(token_string2,string2openpos+1)>-1 Return True
  277.                 EndIf
  278.         EndMethod
  279.        
  280.         Rem
  281.         Method FormatMultiLineComments()
  282.                 Local p0:Int=-1,p1:Int,s:String
  283.                
  284.                 s=TextAreaText(textarea)
  285.                 Repeat
  286.                         p0=s.Find(token_multilinecommentblockbegin,p0+1)
  287.                         If p0>-1
  288.                                 If Not CharacterInQuotes(s,p0)
  289.                                         p1=s.Find(token_multilinecommentblockend,p0+1)
  290.                                         If p1>-1
  291.                                                 If Not CharacterInQuotes(s,p0)
  292.                                                         FormatTextAreaText textarea,format[FORMAT_COMMENT].r,format[FORMAT_COMMENT].g,format[FORMAT_COMMENT].b,format[FORMAT_COMMENT].style,p0,p1-p0
  293.                                                 EndIf
  294.                                         Else
  295.                                                 Exit
  296.                                         EndIf
  297.                                 EndIf
  298.                         Else
  299.                                 Exit
  300.                         EndIf
  301.                 Forever
  302.                
  303.         EndMethod
  304.         EndRem
  305.        
  306.         Method FormatLine:Int(line:Int,multilinecommentbegun:Int=False)
  307.                 Local s:String=TextAreaText(textarea,line,1,TEXTAREA_LINES)
  308.                 Local pos:Int,p2:Int
  309.                 Local l:Int
  310.                 Local word:String
  311.                 Local c:String
  312.                 Local stringopen:Int
  313.                 Local n:Int
  314.                 Local word2:String
  315.                 Local stringreplacement:String
  316.                 Local commentbegun:Int
  317.                 Local multilinecommentstate:Int
  318.                
  319.                 'Print line+", "+TextAreaLen(textarea,TEXTAREA_LINES)
  320.                 'If line>TextAreaLen(textarea,TEXTAREA_LINES) Return False
  321.                
  322.                
  323.                 If line>lineincommentblock.length-1
  324.                         lineincommentblock=lineincommentblock[..line+1]
  325.                 EndIf
  326.  
  327.                 multilinecommentstate=lineincommentblock[line]
  328.  
  329.                
  330.                 'If Not multilinecommentbegun
  331.                 '       If lineincommentblock[line]>1 multilinecommentbegun=True
  332.                 'EndIf
  333.                
  334.                 'If previous line is commented, so is this one
  335.                 If line>0
  336.                         If lineincommentblock[line-1]=1 Or lineincommentblock[line-1]=2
  337.                                 lineincommentblock[line]=2
  338.                         'Else
  339.                         '       lineincommentblock[line]=0
  340.                         EndIf
  341.                 EndIf
  342.                
  343.                 If token_string2="" token_string2=token_string
  344.                
  345.                 FormatTextAreaText textarea,format[CODEAREA_PLAIN].r,format[CODEAREA_PLAIN].g,format[CODEAREA_PLAIN].b,format[CODEAREA_PLAIN].style,line,1,TEXTAREA_LINES
  346.                
  347.                 pos=-1
  348.                
  349.                 'Remove multi-line comments
  350.  
  351.                         'Rem
  352.                         If lineincommentblock[line]=2
  353.                                 lineincommentblock[line]=0
  354.                                
  355.                                 If multilinecommentstyle=1
  356.                                         If (CODEAREA_CORRECTCASE & style)
  357.                                                 p2=s.tolower().Find(token_multilinecommentend.tolower(),pos+1)
  358.                                         Else
  359.                                                 p2=s.Find(token_multilinecommentend,pos+1)
  360.                                         EndIf
  361.                                 Else
  362.                                         p2=s.Find(token_multilinecommentend,pos+1)
  363.                                 EndIf
  364.                                
  365.                                 'Print s+", "+token_multilinecommentend
  366.                                 'If p2>-1 End
  367.                                
  368.                                 'BlitzMax does not allow multi-line comment begin/end tokens in the middle of a string
  369.                                 If p2>-1
  370.                                         If multilinecommentstyle=1
  371.                                                 If (CODEAREA_CORRECTCASE & style)
  372.                                                         If s.Trim().tolower()<>token_multilinecommentend.tolower()
  373.                                                                 p2=-1
  374.                                                         Else
  375.                                                                 If s.Trim()<>token_multilinecommentend SetTextAreaText textarea,token_multilinecommentend,TextAreaChar(textarea,line)+p2,token_multilinecommentend.length
  376.                                                         EndIf
  377.                                                 Else
  378.                                                         If s.Trim()<>token_multilinecommentend p2=-1
  379.                                                 EndIf
  380.                                         EndIf
  381.                                 EndIf
  382.                                
  383.                                 If CharacterInQuotes(s,p2) p2=-1
  384.                                 If p2>-1
  385.                                         stringreplacement=""
  386.                                         For n=pos To p2+token_multilinecommentend.length-1
  387.                                                 FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+n,1,TEXTAREA_CHARS
  388.                                                 stringreplacement:+"|"
  389.                                         Next
  390.                                         lineincommentblock[line]=3' terminates comment block
  391.                                         s=s[..pos]+stringreplacement+s[(p2+token_multilinecommentend.length-1)..]
  392.                                 Else
  393.                                         FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,line,1,TEXTAREA_LINES
  394.                                         lineincommentblock[line]=2' inside comment block
  395.                                         'Print s
  396.                                         s=""
  397.                                 EndIf
  398.                         EndIf
  399.                         'EndRem
  400.                        
  401.                         If lineincommentblock[line]=1 lineincommentblock[line]=0
  402.                         pos=-1
  403.                         Repeat
  404.                                 If multilinecommentstyle=1
  405.                                         If (CODEAREA_CORRECTCASE & style)
  406.                                                 pos=s.tolower().Find(token_multilinecommentbegin.tolower(),pos+1)
  407.                                         Else
  408.                                                 pos=s.Find(token_multilinecommentbegin,pos+1)                                  
  409.                                         EndIf
  410.                                 Else
  411.                                         pos=s.Find(token_multilinecommentbegin,pos+1)  
  412.                                 EndIf
  413.                                
  414.                                 'BlitzMax does not allow multi-line comment begin/end tokens in the middle of a string
  415.                                 If pos>-1
  416.                                         If multilinecommentstyle=1
  417.                                                 If (CODEAREA_CORRECTCASE & style)
  418.                                                         If s.Trim().tolower()<>token_multilinecommentbegin.tolower()
  419.                                                                 pos=-1
  420.                                                         Else
  421.                                                                 If s.Trim()<>token_multilinecommentbegin SetTextAreaText textarea,token_multilinecommentbegin,TextAreaChar(textarea,line)+pos,token_multilinecommentbegin.length
  422.                                                         EndIf
  423.                                                 Else
  424.                                                         If s.Trim()<>token_multilinecommentbegin pos=-1
  425.                                                 EndIf
  426.                                         EndIf
  427.                                 EndIf
  428.                                
  429.                                 If pos>-1
  430.                                         If Not CharacterInQuotes(s,pos)
  431.                                                 p2=s.Find(token_multilinecommentend,pos+1)
  432.                                                 If CharacterInQuotes(s,p2) p2=-1
  433.                                                 If p2>-1
  434.                                                         stringreplacement=""
  435.                                                         For n=pos To p2+token_multilinecommentend.length-1
  436.                                                                 FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+n,1,TEXTAREA_CHARS
  437.                                                                 stringreplacement:+"|"
  438.                                                         Next
  439.                                                         s=s[..pos]+stringreplacement+s[(p2+token_multilinecommentend.length-1)..]
  440.                                                         lineincommentblock[line]=0' comment block is contained within this line
  441.                                                 Else
  442.                                                         l=s.length-pos'-token_multilinecommentbegin.length
  443.                                                         s=s[..pos]
  444.                                                         'Print l+", "+s
  445.                                                         'pos=TextAreaChar(textarea,line)+pos
  446.                                                         FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+pos,l,TEXTAREA_CHARS
  447.                                                         lineincommentblock[line]=1' begins comment block
  448.                                                         'commentbegun=True
  449.                                                 EndIf
  450.                                         EndIf
  451.                                 Else
  452.                                         Exit
  453.                                 EndIf
  454.                         Forever
  455.                
  456.                 'Remove trailing comments
  457.                 pos=-1
  458.                 Repeat
  459.                         pos=s.Find(token_comment,pos+1)
  460.                         If pos>-1
  461.                                 If Not CharacterInQuotes(s,pos)
  462.                                         l=s.length-pos+1-token_comment.length
  463.                                         s=s[..pos]
  464.                                         FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+pos,l,TEXTAREA_CHARS
  465.                                         Exit
  466.                                 EndIf
  467.                         Else
  468.                                 Exit
  469.                         EndIf
  470.                 Forever
  471.                
  472.                 'Format strings
  473.                 pos=-1
  474.                 pos=s.Find(token_string,pos+1)
  475.                 While pos>-1
  476.                         p2=s.Find(token_string,pos+1)
  477.                         If p2>-1
  478.                                 FormatTextAreaText textarea,format[CODEAREA_STRING].r,format[CODEAREA_STRING].g,format[CODEAREA_STRING].b,format[CODEAREA_STRING].style,TextAreaChar(textarea,line)+pos,p2-pos+1,TEXTAREA_CHARS
  479.                                 'pos=s.Find(token_string,p2+1)
  480.                                 stringreplacement=""
  481.                                 For n=pos To p2
  482.                                         stringreplacement:+"|"
  483.                                 Next
  484.                                 Local pl:Int=s.length
  485.                                 s=s[..pos]+stringreplacement+s[(p2+1)..]
  486.                                 'Notify s.length+", "+pl
  487.                         Else
  488.                                 Exit
  489.                         EndIf
  490.                         pos=s.Find(token_string,pos+1)
  491.                 Wend
  492.                
  493.                 'Lua uses two string tokens
  494.                 Rem
  495.                 If token_string2<>token_string
  496.                         pos=s.Find(token_string2)
  497.                         While pos>-1
  498.                                 p2=s.Find(token_string2,pos+1)
  499.                                 If p2>-1
  500.                                         FormatTextAreaText textarea,format[CODEAREA_STRING].r,format[CODEAREA_STRING].g,format[CODEAREA_STRING].b,format[CODEAREA_STRING].style,TextAreaChar(textarea,line)+pos,p2-pos+1,TEXTAREA_CHARS
  501.                                         pos=s.Find(token_string2,p2+1)
  502.                                         stringreplacement=""
  503.                                         For n=pos To p2
  504.                                                 stringreplacement:+"|"
  505.                                         Next
  506.                                         s=s[..pos]+stringreplacement+s[(p2+1)..]
  507.                                 Else
  508.                                         Exit
  509.                                 EndIf                  
  510.                         Wend           
  511.                 EndIf
  512.                 EndRem
  513.                                
  514.                 'Remove defines
  515.                 If token_preprocessor
  516.                         pos=s.Trim().Find(token_preprocessor)
  517.                         If pos=0
  518.                                 pos=s.Find(token_preprocessor)
  519.                                 l=s.length-pos+1-token_preprocessor.length
  520.                                 s=s[..pos]
  521.                                 pos=TextAreaChar(textarea,line)+pos
  522.                                 FormatTextAreaText textarea,format[CODEAREA_PREPROCESSOR].r,format[CODEAREA_PREPROCESSOR].g,format[CODEAREA_PREPROCESSOR].b,format[CODEAREA_PREPROCESSOR].style,pos,l,TEXTAREA_CHARS
  523.                         EndIf
  524.                 EndIf
  525.                
  526.                 'Add this in case this is the last line of the text
  527.                 If Right(s,1).Trim()<>"" s=s+"~n"
  528.                
  529.                 'Format keywords
  530.                 For n=0 To s.length-1
  531.                         c=Chr(s[n])
  532.                         Select c.Trim()
  533.                         Case "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9","_"
  534.                                 If Not stringopen
  535.                                         word:+c
  536.                                 EndIf
  537.                         Case token_string,token_string2
  538.                                 stringopen=CharacterInQuotes(s,n)
  539.                                 'word=""
  540.                                 'stringopen=Not stringopen
  541.                         Default
  542.                                 If Not stringopen
  543.                                         If word
  544.                                                 If KeywordExists(word)
  545.                                                         If (CODEAREA_CORRECTCASE & style)
  546.                                                                 word2=String(keywords.valueforkey(word.tolower()))
  547.                                                                 If word<>word2
  548.                                                                         'Print word2
  549.                                                                         SetTextAreaText textarea,word2,TextAreaChar(textarea,line)+n-word.length,word.length
  550.                                                                 EndIf
  551.                                                         EndIf  
  552.                                                         FormatTextAreaText textarea,format[CODEAREA_KEYWORD].r,format[CODEAREA_KEYWORD].r,format[CODEAREA_KEYWORD].b,format[CODEAREA_KEYWORD].style,TextAreaChar(textarea,line)+n-word.length,word.length,TEXTAREA_CHARS       
  553.                                                 EndIf
  554.                                         EndIf
  555.                                 EndIf
  556.                                 word=""
  557.                         EndSelect
  558.                 Next
  559.                
  560.                 If multilinecommentstate<>lineincommentblock[line]
  561.                         If Not dontupdatemultilinecomments
  562.                                 Print "CHANGE"
  563.                                 FormatAll()
  564.                                 Return True
  565.                         EndIf
  566.                 EndIf
  567.                
  568.                 Return False
  569.         EndMethod
  570.        
  571.         '---------------------------------------------------------------------------------------------
  572.         'Undo/redo functionality
  573.         '---------------------------------------------------------------------------------------------
  574.         Method ClearUndos()
  575.                 If (CODEAREA_CANUNDO & style)
  576.                         actions=Null
  577.                         undoposition=-1
  578.                 EndIf
  579.         EndMethod
  580.        
  581.         Method AddAction(action:TAction)
  582.                 If (CODEAREA_CANUNDO & style)
  583.                         undoposition:+1
  584.                         actions=actions[..undoposition+1]
  585.                         actions[undoposition]=action
  586.                         If maxundolevels>0
  587.                                 If undoposition>maxundolevels
  588.                                         undoposition:-1
  589.                                         actions=actions[1..]
  590.                                 EndIf
  591.                         EndIf
  592.                 EndIf
  593.         EndMethod
  594.        
  595.         Method CanUndo:Int()
  596.                 If (CODEAREA_CANUNDO & style)
  597.                         If undoposition>-1 Return True         
  598.                 EndIf
  599.         EndMethod
  600.        
  601.         Method CanRedo:Int()
  602.                 If (CODEAREA_CANUNDO & style)
  603.                         If undoposition<=actions.length-2 Return True
  604.                 EndIf
  605.         EndMethod
  606.        
  607.         Method Undo()
  608.                 If CanUndo()
  609.                         actions[undoposition].Undo(Self)
  610.                         undoposition:-1
  611.                 EndIf
  612.         EndMethod
  613.        
  614.         Method Redo()
  615.                 If CanRedo()
  616.                         actions[undoposition+1].Redo(Self)             
  617.                         undoposition:+1
  618.                 EndIf
  619.         EndMethod
  620.                
  621.         '---------------------------------------------------------------------------------------------
  622.         'Event handling
  623.         '---------------------------------------------------------------------------------------------
  624.         Method ProcessEvent:Int(event:TEvent)
  625.                 Select event.source
  626.                 Case Self,textarea
  627.                         Select event.id
  628.                        
  629.                         Case EVENT_GADGETACTION
  630.                                 text=TextAreaText(textarea)
  631.                                 selpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
  632.                                 sellen=TextAreaSelLen(textarea,TEXTAREA_CHARS)
  633.                                
  634.                         Case EVENT_GADGETSELECT
  635.                                 selpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
  636.                                 sellen=TextAreaSelLen(textarea,TEXTAREA_CHARS)
  637.                        
  638.                         EndSelect
  639.                 EndSelect
  640.                 Return True
  641.         EndMethod
  642.        
  643.         Method SetText(text:String)
  644.                 Local n:Int
  645.                
  646.                 textarea.SetText(text)
  647.                 If (CODEAREA_SYNTAXHIGHLIGHTING & style)
  648.                         LockTextArea textarea
  649.                         For n=0 To TextAreaLen(textarea,TEXTAREA_LINES)
  650.                                 If FormatLine(n) Exit
  651.                         Next
  652.                         UnlockTextArea textarea
  653.                 EndIf
  654.         EndMethod
  655.        
  656.         Method ReplaceText(pos:Int,count:Int,text:String,units:Int)
  657.                 Local n:Int
  658.                
  659.                 textarea.ReplaceText(pos,count,text,units)
  660.                 If (CODEAREA_SYNTAXHIGHLIGHTING & style)
  661.                         LockTextArea textarea
  662.                         If units=TEXTAREA_CHARS
  663.                                 For n=TextAreaLine(textarea,pos) To TextAreaLine(textarea,pos+count)
  664.                                         If FormatLine(n) Exit
  665.                                 Next
  666.                         Else
  667.                                 For n=pos To pos+count
  668.                                         If FormatLine(n) Exit
  669.                                 Next                           
  670.                         EndIf
  671.                         UnlockTextArea textarea
  672.                 EndIf
  673.         EndMethod      
  674.        
  675.         Method Activate(command:Int)
  676.                 Local n:Int
  677.                 Local clipboardtext:String
  678.                
  679.                 Select command
  680.                 Case ACTIVATE_PASTE
  681.                         SetTextAreaText dummytextarea,""
  682.                         GadgetPaste(dummytextarea)
  683.                         ActivateGadget textarea
  684.                         clipboardtext=TextAreaText(dummytextarea)
  685.                        
  686.                         Update()
  687.                         Local action:TAction
  688.                         action=New TAction
  689.                         AddAction action
  690.                         action.add=clipboardtext
  691.                         action.addpos=selpos
  692.                         action.addlen=clipboardtext.length
  693.                         action.beforepos=selpos
  694.                         action.beforelen=sellen
  695.                         action.remove=Mid(text,selpos+1,sellen)
  696.                         action.removepos=selpos
  697.                         action.removelen=sellen
  698.                         action.afterpos=selpos+clipboardtext.length
  699.                         action.afterlen=0
  700.                         'action.afterpos=selpos
  701.                         'action.afterlen=clipboardtext.length  
  702.                         action.Redo(Self)
  703.                         EmitEvent CreateEvent(EVENT_GADGETACTION,Self)
  704.                         If (CODEAREA_SYNTAXHIGHLIGHTING & style)
  705.                                 LockTextArea textarea
  706.                                 'Notify TextAreaLine(textarea,action.afterpos)+", "+TextAreaLine(textarea,action.afterpos+action.afterlen)
  707.                                 For n=TextAreaLine(textarea,action.beforepos) To TextAreaLine(textarea,action.beforepos+clipboardtext.length)
  708.                                         If FormatLine(n) Exit
  709.                                 Next
  710.                                 UnlockTextArea textarea
  711.                         EndIf
  712.                        
  713.                 Case ACTIVATE_CUT
  714.                         If sellen
  715.                                 textarea.activate(ACTIVATE_COPY)
  716.                                 Filter(CreateEvent(EVENT_KEYCHAR,textarea,8))
  717.                         EndIf
  718.                 Default
  719.                         textarea.activate(command)
  720.                 EndSelect
  721.         EndMethod
  722.        
  723.         Method Update()
  724.                 selpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
  725.                 sellen=TextAreaSelLen(textarea,TEXTAREA_CHARS)
  726.                 text=TextAreaText(textarea)
  727.         EndMethod
  728.        
  729.         Method Filter:Int(event:TEvent)
  730.                 Local action:TAction
  731.                
  732.                 Select event.id
  733.                 Case EVENT_KEYDOWN
  734.                         Select event.data
  735.                         Case KEY_UP,KEY_DOWN,KEY_RIGHT,KEY_LEFT
  736.                                 Return True
  737.                         EndSelect
  738.                 Case EVENT_KEYCHAR
  739.                         If MODIFIER_COMMAND & event.mods Return False
  740.                         If MODIFIER_OPTION & event.mods Return False
  741.                         Update()
  742.                         If event.data=8
  743.                                 action=New TAction
  744.                                 AddAction action
  745.                                 action.add=""
  746.                                 action.addlen=0
  747.                                 action.beforepos=selpos
  748.                                 action.beforelen=sellen
  749.                                 If sellen=0
  750.                                         action.addpos=selpos-1
  751.                                         action.afterpos=selpos-1
  752.                                         action.afterlen=0
  753.                                         action.removelen=1
  754.                                         action.removepos=selpos-1
  755.                                         action.remove=Mid(text,1+selpos-action.removelen,action.removelen)
  756.                                 Else
  757.                                         action.addpos=selpos
  758.                                         action.afterpos=selpos
  759.                                         action.afterlen=0
  760.                                         action.removepos=selpos
  761.                                         action.removelen=sellen
  762.                                         action.remove=Mid(text,1+selpos,sellen)
  763.                                 EndIf
  764.                                 action.Redo(Self)      
  765.                                 EmitEvent CreateEvent(EVENT_GADGETACTION,Self)
  766.                                 'action.Undo(self)' test to make sure this is reversable
  767.                         ElseIf event.data>31 And event.data<127 Or event.data=13
  768.                                 action=New TAction
  769.                                 AddAction action
  770.                                 action.add=Chr(event.data)
  771.                                 action.addpos=selpos
  772.                                 action.addlen=1
  773.                                 action.beforepos=selpos
  774.                                 action.beforelen=sellen
  775.                                 action.remove=Mid(text,selpos+1,sellen)
  776.                                 action.removepos=selpos
  777.                                 action.removelen=sellen
  778.                                 action.afterpos=selpos+1
  779.                                 action.afterlen=0
  780.                                 action.Redo(Self)
  781.                                 EmitEvent CreateEvent(EVENT_GADGETACTION,Self)
  782.                                 'action.Undo(self)' test to make sure this is reversable
  783.                         EndIf
  784.                 EndSelect
  785.                 Return False
  786.         EndMethod
  787.        
  788.         Function Callback:Int(event:TEvent,context:Object)
  789.                 Local codearea:TCodeArea=New TCodeArea
  790.                 codearea=TCodeArea(context)
  791.                 If codearea
  792.                         Return codearea.Filter(event)
  793.                 EndIf
  794.         EndFunction
  795.        
  796.         Function EventHook:Object(id:Int,data:Object,context:Object)
  797.                 Local event:TEvent=TEvent(data)
  798.                 Local codearea:TCodeArea
  799.                
  800.                 If event
  801.                         codearea=TCodeArea(context)
  802.                         If codearea
  803.                                 If Not codearea.ProcessEvent(event) Return data'Null
  804.                         EndIf
  805.                 EndIf
  806.                 Return data
  807.         EndFunction
  808.        
  809.         '---------------------------------------------------------------------------------------------
  810.         'Creation
  811.         '--------------------------------------------------------------------------------------------- 
  812.         Function Create:TCodeArea(x:Int,y:Int,width:Int,height:Int,group:TGadget,style:Int=CODEAREA_DEFAULT)
  813.                 Local codearea:TCodeArea=New TCodeArea
  814.                 Local textareastyle:Int
  815.                
  816.                 If Not dummywindow
  817.                         dummywindow=CreateWindow("",0,0,400,300,Null,WINDOW_HIDDEN)
  818.                         dummytextarea=CreateTextArea(0,0,300,200,dummywindow)
  819.                 EndIf
  820.                 codearea.style=style
  821.                 If (CODEAREA_READONLY & style) textareastyle=TEXTAREA_READONLY
  822.                 codearea.textarea=CreateTextArea(x,y,width,height,group,textareastyle)
  823.                 SetGadgetFilter codearea.textarea,Callback,codearea
  824.                 codearea.SetProxy(codearea.textarea)
  825.                 AddHook EmitEventHook,EventHook,codearea
  826.                 Return codearea
  827.         EndFunction
  828.        
  829. EndType
  830.  
  831. '---------------------------------------------------------------------------------------------
  832. 'Procedural functions
  833. '---------------------------------------------------------------------------------------------
  834. Function CreateCodeArea:TCodeArea(x:Int,y:Int,width:Int,height:Int,group:TGadget,style:Int=CODEAREA_DEFAULT)
  835.         Return TCodeArea.Create(x,y,width,height,group,style)
  836. EndFunction
  837.  
  838. Function AddCodeAreaKeyword(codearea:TCodeArea,word:String)
  839.         codearea.AddKeyword(word)
  840. EndFunction
  841.  
  842. Function SetCodeAreaFormat(codearea:TCodeArea,element:Int,r:Int,g:Int,b:Int,style:Int=0)
  843.         codearea.SetFormat(element,r,g,b,style)
  844. EndFunction
  845.  
  846. Function CodeAreaClearUndos(codearea:TCodeArea)
  847.         codearea.ClearUndos()
  848. EndFunction
  849.  
  850. Function CodeAreaCanUndo:Int(codearea:TCodeArea)
  851.         Return codearea.CanUndo()
  852. EndFunction
  853.  
  854. Function CodeAreaCanRedo:Int(codearea:TCodeArea)
  855.         Return codearea.CanRedo()      
  856. EndFunction
  857.  
  858. Function CodeAreaUndo(codearea:TCodeArea)
  859.         codearea.Undo()
  860. EndFunction
  861.  
  862. Function CodeAreaRedo(codearea:TCodeArea)
  863.         codearea.Redo()
  864. EndFunction
  865.  
  866. Function SetCodeAreaLanguage(codearea:TCodeArea,language:Int)
  867.         codearea.SetLanguage language
  868. EndFunction
  869.  
  870.  
  871. '---------------------------------------------------------------------------------------------
  872. 'Example
  873. '---------------------------------------------------------------------------------------------
  874.  
  875.  
  876. 'Create window
  877. Local window:TGadget=CreateWindow("CodeArea Example",0,0,1024,768,Null,WINDOW_DEFAULT|WINDOW_CENTER)
  878.  
  879. 'Create menu
  880. Local root:TGadget=CreateMenu("Edit",0,WindowMenu(window))
  881. Local menu:TGadget[6]
  882. menu[0]=CreateMenu("Undo",0,root,KEY_Z,MODIFIER_COMMAND)
  883. menu[1]=CreateMenu("Redo",1,root,KEY_Z,MODIFIER_COMMAND|MODIFIER_OPTION)
  884. CreateMenu("",0,root)
  885. DisableMenu menu[0]
  886. DisableMenu menu[1]
  887. menu[2]=CreateMenu("Clear Undos",2,root)
  888. CreateMenu("",0,root)
  889. menu[3]=CreateMenu("Cut",3,root,KEY_X,MODIFIER_COMMAND)
  890. menu[4]=CreateMenu("Copy",4,root,KEY_C,MODIFIER_COMMAND)
  891. menu[5]=CreateMenu("Paste",5,root,KEY_V,MODIFIER_COMMAND)
  892. DisableMenu menu[3]
  893. DisableMenu menu[4]
  894. UpdateWindowMenu window
  895.  
  896. 'Create CodeArea gadget
  897. Local codearea:TCodeArea=CreateCodearea(0,0,ClientWidth(window),ClientHeight(window),window)
  898. SetGadgetLayout codearea,1,1,1,1
  899.  
  900. 'Add some keywords
  901. AddCodeAreaKeyword codearea,"Allegience"
  902. AddCodeAreaKeyword codearea,"Flag"
  903. AddCodeAreaKeyword codearea,"Justice"
  904.  
  905. 'Adjust the syntax highlighting
  906. SetCodeAreaFormat codearea,CODEAREA_KEYWORD,0,0,255,FONT_BOLD
  907. SetCodeAreaFormat codearea,CODEAREA_COMMENT,0,128,0,FONT_ITALIC
  908.  
  909. 'Set the language and add some text
  910.  
  911. 'C/C++
  912. SetCodeAreaLanguage codearea,CODEAREA_C
  913. SetGadgetText codearea,"#define whatever 3~n~nI ~qpledge~q allegience to the flag of the United States of /*America~nAnd to the republic for which it stands~n~qOne nation~q, under God,*/ indivisible~nWith liberty and justice //for all.~n"
  914.  
  915. 'Lua
  916. 'SetCodeAreaLanguage codearea,CODEAREA_LUA
  917. 'SetGadgetText codearea,"I ~qpledge~q allegience to 'the' flag of the United States of --[[America~nAnd to the republic for which it stands~n~qOne nation~q, under God,]]-- indivisible~nWith liberty and justice --for all.~n"
  918.  
  919. 'BlitzMax
  920. 'SetCodeAreaLanguage codearea,CODEAREA_BMX
  921. 'SetGadgetText codearea,"?debug~nPrint ~qHello~q~n?~n~nI ~qpledge~q allegience To the flag of the United States of America~nRem~nAnd To the republic For which it stands~n~qOne nation~q, under God, indivisible~nEndRem~nWith liberty and justice 'for all.~n"
  922.  
  923.  
  924. 'Set the font (we can do this any time)
  925. SetGadgetFont codearea,LoadGuiFont("Courier New",10)
  926.  
  927. 'Set the gadget text and background colors (we can do this at any time)
  928. SetGadgetColor codearea,240,240,240,True
  929. SetGadgetColor codearea,0,0,0,False
  930.  
  931.  
  932.  
  933. While WaitEvent()
  934.         Select EventID()
  935.                
  936.                 Case EVENT_GADGETSELECT
  937.                         If TextAreaSelLen(codearea)
  938.                                 EnableMenu menu[3]
  939.                                 EnableMenu menu[4]
  940.                         Else
  941.                                 DisableMenu menu[3]
  942.                                 DisableMenu menu[4]
  943.                         EndIf
  944.                         UpdateWindowMenu window
  945.                        
  946.                 Case EVENT_GADGETACTION
  947.                         If TextAreaSelLen(codearea)
  948.                                 EnableMenu menu[3]
  949.                                 EnableMenu menu[4]
  950.                         Else
  951.                                 DisableMenu menu[3]
  952.                                 DisableMenu menu[4]
  953.                         EndIf
  954.                         If codearea.canundo() EnableMenu menu[0] Else DisableMenu menu[0]
  955.                         If codearea.canredo() EnableMenu menu[1] Else DisableMenu menu[1]
  956.                         UpdateWindowMenu window                
  957.                        
  958.                 Case EVENT_MENUACTION
  959.                         Select EventData()
  960.                         Case 1 codearea.redo()
  961.                         Case 0 codearea.undo()
  962.                         Case 2 codearea.ClearUndos()
  963.                         Case 3 GadgetCut(codearea)
  964.                         Case 4 GadgetCopy(codearea)
  965.                         Case 5 GadgetPaste(codearea)
  966.                         EndSelect
  967.                         If codearea.canundo() EnableMenu menu[0] Else DisableMenu menu[0]
  968.                         If codearea.canredo() EnableMenu menu[1] Else DisableMenu menu[1]
  969.                         UpdateWindowMenu window
  970.                        
  971.                 Case EVENT_WINDOWCLOSE
  972.                         End
  973.                        
  974.         EndSelect
  975.         'Print CurrentEvent.ToString()
  976. Wend


Comments :


JoshK(Posted 1+ years ago)

 I'm going to post new versions below in case I mess anything up.  This version will handle End, Home, PageUp, PageDown, Delete, and Insert keys:
Code: [Select]
SuperStrict

Import maxgui.drivers
Import maxgui.proxygadgets

'Codearea style constants
Const CODEAREA_SYNTAXHIGHLIGHTING:Int=1
Const CODEAREA_CANUNDO:Int=2
Const CODEAREA_CORRECTCASE:Int=4
Const CODEAREA_READONLY:Int=8
Const CODEAREA_DEFAULT:Int=CODEAREA_SYNTAXHIGHLIGHTING|CODEAREA_CANUNDO|CODEAREA_CORRECTCASE

'Codearea format constants
Const CODEAREA_PLAIN:Int=0
Const CODEAREA_STRING:Int=1
Const CODEAREA_COMMENT:Int=2
Const CODEAREA_KEYWORD:Int=3
Const CODEAREA_PREPROCESSOR:Int=4

'CodeArea language constants
Const CODEAREA_C:Int=0
Const CODEAREA_LUA:Int=1
Const CODEAREA_BMX:Int=2

Private

Type TAction

Field add:String
Field addpos:Int
Field addlen:Int
Field remove:String
Field removepos:Int
Field removelen:Int
Field beforepos:Int
Field beforelen:Int
Field afterpos:Int
Field afterlen:Int

Method Undo(codearea:TCodeArea)
Local n:Int

SetTextAreaText codearea,remove,addpos,addlen
SelectTextAreaText codearea,beforepos,beforelen
If (CODEAREA_SYNTAXHIGHLIGHTING & codearea.style)
LockTextArea codearea.textarea
For n=TextAreaLine(codearea.textarea,beforepos) To TextAreaLine(codearea.textarea,beforepos+beforelen)
If codearea.FormatLine(n) Exit
Next
UnlockTextArea codearea.textarea
EndIf
EmitEvent CreateEvent(EVENT_GADGETSELECT,codearea,addpos-remove.length)
EndMethod

Method Redo(codearea:TCodeArea)
Local n:Int

SetTextAreaText codearea,add,removepos,removelen
SelectTextAreaText codearea,afterpos,afterlen
If (CODEAREA_SYNTAXHIGHLIGHTING & codearea.style)
LockTextArea codearea.textarea
For n=TextAreaLine(codearea.textarea,afterpos) To TextAreaLine(codearea.textarea,afterpos+afterlen)
If codearea.FormatLine(n) Exit
Next
UnlockTextArea codearea.textarea
EndIf
EmitEvent CreateEvent(EVENT_GADGETSELECT,codearea,removepos+add.length)
EndMethod

EndType

Type TFormat

Field r:Int
Field g:Int
Field b:Int
Field style:Int

Function Create:TFormat(r:Int,g:Int,b:Int,style:Int)
Local format:TFormat=New TFormat
format.r=r
format.g=g
format.b=b
format.style=style
Return format
EndFunction

EndType

Public

Type TCodeArea Extends TProxyGadget

Global dummywindow:TGadget' used to hold dummy textarea
Global dummytextarea:TGadget' used for paste operations
Global maxundolevels:Int=0' set to 0 to disable limit

Field textarea:TGadget
Field selpos:Int
Field sellen:Int
Field insertmode:Int
Field text:String
Field undoposition:Int=-1
Field actions:TAction[]
Field format:TFormat[6]
Field needsreformat:Int
Field locked:Int
Field keywords:TMap=New TMap
Field token_comment:String="//"
Field token_multilinecommentbegin:String="/*"
Field token_multilinecommentend:String="*/"
Field token_string:String="~q"
Field token_string2:String' Lua uses multiple string tokens
Field token_preprocessor:String="#"
Field multilinecommentstyle:Int
Field lineincommentblock:Byte[]
Field multilinecommentschanged:Int

Method New()
format[CODEAREA_PLAIN]=TFormat.Create(0,0,0,0)
format[CODEAREA_STRING]=TFormat.Create(128,0,128,0)
format[CODEAREA_COMMENT]=TFormat.Create(0,128,0,0)
format[CODEAREA_PREPROCESSOR]=TFormat.Create(255,0,0,0)
format[CODEAREA_KEYWORD]=TFormat.Create(0,0,255,0)
EndMethod

Method Cleanup()
RemoveHook EmitEventHook,EventHook,Self
EndMethod

'---------------------------------------------------------------------------------------------
'Syntax highlighting
'---------------------------------------------------------------------------------------------
Method SetLanguage(language:Int)
Select language

Case CODEAREA_C
token_comment="//"
token_multilinecommentbegin="/*"
token_multilinecommentend="*/"
token_string="~q"
token_string2=""
token_preprocessor="#"
multilinecommentstyle=0

Case CODEAREA_LUA
token_comment="--"
token_multilinecommentbegin="--[["
token_multilinecommentend="]]--"
token_string="~q"
token_string2="'"
token_preprocessor=""
multilinecommentstyle=0

Case CODEAREA_BMX
token_comment="'"
token_multilinecommentbegin="Rem"
token_multilinecommentend="EndRem"
token_string="~q"
token_string2=""
token_preprocessor="?"
multilinecommentstyle=1

EndSelect

FormatAll()
EndMethod

Method LockText()
locked=True
textarea.LockText()
EndMethod

Method UnlockText()
textarea.UnlockText()
locked=False
If needsreformat FormatAll()
EndMethod

Method SetFont(font:TGUIFont)
Local n:Int

format[CODEAREA_PLAIN].style=FontStyle(font)
textarea.SetFont(font)
FormatAll()
EndMethod

Method SetTextColor(r:Int,g:Int,b:Int)
Local n:Int

format[CODEAREA_PLAIN].r=r
format[CODEAREA_PLAIN].g=g
format[CODEAREA_PLAIN].b=b
FormatAll()
EndMethod

Method AddKeyword(word:String)
keywords.insert(word.tolower(),word)
EndMethod

Method ClearKeywords()
keywords.Clear()
EndMethod

Method KeywordExists:Int(word:String)
Local keyword:String
keyword=String(keywords.valueforkey(word.tolower()))
If keyword
If Not (CODEAREA_CORRECTCASE & style)
If keyword=word
Return True
Else
Return False
EndIf
Else
Return True
EndIf
Else
Return False
EndIf
EndMethod

Method SetFormat(element:Int,r:Int,g:Int,b:Int,style:Int)
format[element]=TFormat.Create(r,g,b,style)
FormatAll()
EndMethod

Field dontupdatemultilinecomments:Int

Method FormatAll()
Print "FORMATALL"
Local n:Int
Local multilinecommentbegun:Int
For n=0 To lineincommentblock.length-1
lineincommentblock[n]=0
Next

dontupdatemultilinecomments=True
If locked
needsreformat=True
Else
LockTextArea textarea
For n=0 To TextAreaLen(textarea,TEXTAREA_LINES)-1
If FormatLine(n) Exit
Next
UnlockTextArea textarea
needsreformat=False
EndIf
dontupdatemultilinecomments=False
EndMethod

Method CharacterInQuotes:Int(s:String,c:Int)
Local n:Int
Local char:String
Local stringopen:Int
Local string2open:Int
Local stringopenpos:Int
Local string2openpos:Int

For n=0 To c
char=Chr(s[n])
Select char
Case token_string
stringopen=Not stringopen
stringopenpos=n
Case token_string2
If token_string2<>token_string
string2open=Not string2open
string2openpos=n
EndIf
EndSelect
Next
If stringopen
If s.Find(token_string,stringopenpos+1)>-1 Return True
EndIf
If string2open
If s.Find(token_string2,string2openpos+1)>-1 Return True
EndIf
EndMethod

Rem
Method FormatMultiLineComments()
Local p0:Int=-1,p1:Int,s:String

s=TextAreaText(textarea)
Repeat
p0=s.Find(token_multilinecommentblockbegin,p0+1)
If p0>-1
If Not CharacterInQuotes(s,p0)
p1=s.Find(token_multilinecommentblockend,p0+1)
If p1>-1
If Not CharacterInQuotes(s,p0)
FormatTextAreaText textarea,format[FORMAT_COMMENT].r,format[FORMAT_COMMENT].g,format[FORMAT_COMMENT].b,format[FORMAT_COMMENT].style,p0,p1-p0
EndIf
Else
Exit
EndIf
EndIf
Else
Exit
EndIf
Forever

EndMethod
EndRem

Method FormatLine:Int(line:Int,multilinecommentbegun:Int=False)
Local s:String=TextAreaText(textarea,line,1,TEXTAREA_LINES)
Local pos:Int,p2:Int
Local l:Int
Local word:String
Local c:String
Local stringopen:Int
Local n:Int
Local word2:String
Local stringreplacement:String
Local commentbegun:Int
Local multilinecommentstate:Int

'Print line+", "+TextAreaLen(textarea,TEXTAREA_LINES)
'If line>TextAreaLen(textarea,TEXTAREA_LINES) Return False


If line>lineincommentblock.length-1
lineincommentblock=lineincommentblock[..line+1]
EndIf

multilinecommentstate=lineincommentblock[line]


'If Not multilinecommentbegun
' If lineincommentblock[line]>1 multilinecommentbegun=True
'EndIf

'If previous line is commented, so is this one
If line>0
If lineincommentblock[line-1]=1 Or lineincommentblock[line-1]=2
lineincommentblock[line]=2
'Else
' lineincommentblock[line]=0
EndIf
EndIf

If token_string2="" token_string2=token_string

FormatTextAreaText textarea,format[CODEAREA_PLAIN].r,format[CODEAREA_PLAIN].g,format[CODEAREA_PLAIN].b,format[CODEAREA_PLAIN].style,line,1,TEXTAREA_LINES

pos=-1

'Remove multi-line comments

'Rem
If lineincommentblock[line]=2
lineincommentblock[line]=0

If multilinecommentstyle=1
If (CODEAREA_CORRECTCASE & style)
p2=s.tolower().Find(token_multilinecommentend.tolower(),pos+1)
Else
p2=s.Find(token_multilinecommentend,pos+1)
EndIf
Else
p2=s.Find(token_multilinecommentend,pos+1)
EndIf

'Print s+", "+token_multilinecommentend
'If p2>-1 End

'BlitzMax does not allow multi-line comment begin/end tokens in the middle of a string
If p2>-1
If multilinecommentstyle=1
If (CODEAREA_CORRECTCASE & style)
If s.Trim().tolower()<>token_multilinecommentend.tolower()
p2=-1
Else
If s.Trim()<>token_multilinecommentend SetTextAreaText textarea,token_multilinecommentend,TextAreaChar(textarea,line)+p2,token_multilinecommentend.length
EndIf
Else
If s.Trim()<>token_multilinecommentend p2=-1
EndIf
EndIf
EndIf

If CharacterInQuotes(s,p2) p2=-1
If p2>-1
stringreplacement=""
For n=pos To p2+token_multilinecommentend.length-1
FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+n,1,TEXTAREA_CHARS
stringreplacement:+"|"
Next
lineincommentblock[line]=3' terminates comment block
s=s[..pos]+stringreplacement+s[(p2+token_multilinecommentend.length-1)..]
Else
FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,line,1,TEXTAREA_LINES
lineincommentblock[line]=2' inside comment block
'Print s
s=""
EndIf
EndIf
'EndRem

If lineincommentblock[line]=1 lineincommentblock[line]=0
pos=-1
Repeat
If multilinecommentstyle=1
If (CODEAREA_CORRECTCASE & style)
pos=s.tolower().Find(token_multilinecommentbegin.tolower(),pos+1)
Else
pos=s.Find(token_multilinecommentbegin,pos+1)
EndIf
Else
pos=s.Find(token_multilinecommentbegin,pos+1)
EndIf

'BlitzMax does not allow multi-line comment begin/end tokens in the middle of a string
If pos>-1
If multilinecommentstyle=1
If (CODEAREA_CORRECTCASE & style)
If s.Trim().tolower()<>token_multilinecommentbegin.tolower()
pos=-1
Else
If s.Trim()<>token_multilinecommentbegin SetTextAreaText textarea,token_multilinecommentbegin,TextAreaChar(textarea,line)+pos,token_multilinecommentbegin.length
EndIf
Else
If s.Trim()<>token_multilinecommentbegin pos=-1
EndIf
EndIf
EndIf

If pos>-1
If Not CharacterInQuotes(s,pos)
p2=s.Find(token_multilinecommentend,pos+1)
If CharacterInQuotes(s,p2) p2=-1
If p2>-1
stringreplacement=""
For n=pos To p2+token_multilinecommentend.length-1
FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+n,1,TEXTAREA_CHARS
stringreplacement:+"|"
Next
s=s[..pos]+stringreplacement+s[(p2+token_multilinecommentend.length-1)..]
lineincommentblock[line]=0' comment block is contained within this line
Else
l=s.length-pos'-token_multilinecommentbegin.length
s=s[..pos]
'Print l+", "+s
'pos=TextAreaChar(textarea,line)+pos
FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+pos,l,TEXTAREA_CHARS
lineincommentblock[line]=1' begins comment block
'commentbegun=True
EndIf
EndIf
Else
Exit
EndIf
Forever

'Remove trailing comments
pos=-1
Repeat
pos=s.Find(token_comment,pos+1)
If pos>-1
If Not CharacterInQuotes(s,pos)
l=s.length-pos+1-token_comment.length
s=s[..pos]
FormatTextAreaText textarea,format[CODEAREA_COMMENT].r,format[CODEAREA_COMMENT].g,format[CODEAREA_COMMENT].b,format[CODEAREA_COMMENT].style,TextAreaChar(textarea,line)+pos,l,TEXTAREA_CHARS
Exit
EndIf
Else
Exit
EndIf
Forever

'Format strings
pos=-1
pos=s.Find(token_string,pos+1)
While pos>-1
p2=s.Find(token_string,pos+1)
If p2>-1
FormatTextAreaText textarea,format[CODEAREA_STRING].r,format[CODEAREA_STRING].g,format[CODEAREA_STRING].b,format[CODEAREA_STRING].style,TextAreaChar(textarea,line)+pos,p2-pos+1,TEXTAREA_CHARS
'pos=s.Find(token_string,p2+1)
stringreplacement=""
For n=pos To p2
stringreplacement:+"|"
Next
Local pl:Int=s.length
s=s[..pos]+stringreplacement+s[(p2+1)..]
'Notify s.length+", "+pl
Else
Exit
EndIf
pos=s.Find(token_string,pos+1)
Wend

'Lua uses two string tokens
Rem
If token_string2<>token_string
pos=s.Find(token_string2)
While pos>-1
p2=s.Find(token_string2,pos+1)
If p2>-1
FormatTextAreaText textarea,format[CODEAREA_STRING].r,format[CODEAREA_STRING].g,format[CODEAREA_STRING].b,format[CODEAREA_STRING].style,TextAreaChar(textarea,line)+pos,p2-pos+1,TEXTAREA_CHARS
pos=s.Find(token_string2,p2+1)
stringreplacement=""
For n=pos To p2
stringreplacement:+"|"
Next
s=s[..pos]+stringreplacement+s[(p2+1)..]
Else
Exit
EndIf
Wend
EndIf
EndRem

'Remove defines
If token_preprocessor
pos=s.Trim().Find(token_preprocessor)
If pos=0
pos=s.Find(token_preprocessor)
l=s.length-pos+1-token_preprocessor.length
s=s[..pos]
pos=TextAreaChar(textarea,line)+pos
FormatTextAreaText textarea,format[CODEAREA_PREPROCESSOR].r,format[CODEAREA_PREPROCESSOR].g,format[CODEAREA_PREPROCESSOR].b,format[CODEAREA_PREPROCESSOR].style,pos,l,TEXTAREA_CHARS
EndIf
EndIf

'Add this in case this is the last line of the text
If Right(s,1).Trim()<>"" s=s+"~n"

'Format keywords
For n=0 To s.length-1
c=Chr(s[n])
Select c.Trim()
Case "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9","_"
If Not stringopen
word:+c
EndIf
Case token_string,token_string2
stringopen=CharacterInQuotes(s,n)
'word=""
'stringopen=Not stringopen
Default
If Not stringopen
If word
If KeywordExists(word)
If (CODEAREA_CORRECTCASE & style)
word2=String(keywords.valueforkey(word.tolower()))
If word<>word2
'Print word2
SetTextAreaText textarea,word2,TextAreaChar(textarea,line)+n-word.length,word.length
EndIf
EndIf
FormatTextAreaText textarea,format[CODEAREA_KEYWORD].r,format[CODEAREA_KEYWORD].r,format[CODEAREA_KEYWORD].b,format[CODEAREA_KEYWORD].style,TextAreaChar(textarea,line)+n-word.length,word.length,TEXTAREA_CHARS
EndIf
EndIf
EndIf
word=""
EndSelect
Next

If multilinecommentstate<>lineincommentblock[line]
If Not dontupdatemultilinecomments
Print "CHANGE"
FormatAll()
Return True
EndIf
EndIf

Return False
EndMethod

'---------------------------------------------------------------------------------------------
'Undo/redo functionality
'---------------------------------------------------------------------------------------------
Method ClearUndos()
If (CODEAREA_CANUNDO & style)
actions=Null
undoposition=-1
EndIf
EndMethod

Method AddAction(action:TAction)
If (CODEAREA_CANUNDO & style)
undoposition:+1
actions=actions[..undoposition+1]
actions[undoposition]=action
If maxundolevels>0
If undoposition>maxundolevels
undoposition:-1
actions=actions[1..]
EndIf
EndIf
EndIf
EndMethod

Method CanUndo:Int()
If (CODEAREA_CANUNDO & style)
If undoposition>-1 Return True
EndIf
EndMethod

Method CanRedo:Int()
If (CODEAREA_CANUNDO & style)
If undoposition<=actions.length-2 Return True
EndIf
EndMethod

Method Undo()
If CanUndo()
actions[undoposition].Undo(Self)
undoposition:-1
EndIf
EndMethod

Method Redo()
If CanRedo()
actions[undoposition+1].Redo(Self)
undoposition:+1
EndIf
EndMethod

'---------------------------------------------------------------------------------------------
'Event handling
'---------------------------------------------------------------------------------------------
Method ProcessEvent:Int(event:TEvent)
Select event.source
Case Self,textarea
Select event.id

Case EVENT_GADGETACTION
text=TextAreaText(textarea)
selpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
sellen=TextAreaSelLen(textarea,TEXTAREA_CHARS)

Case EVENT_GADGETSELECT
selpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
sellen=TextAreaSelLen(textarea,TEXTAREA_CHARS)

EndSelect
EndSelect
Return True
EndMethod

Method SetText(text:String)
Local n:Int

textarea.SetText(text)
If (CODEAREA_SYNTAXHIGHLIGHTING & style)
LockTextArea textarea
For n=0 To TextAreaLen(textarea,TEXTAREA_LINES)
If FormatLine(n) Exit
Next
UnlockTextArea textarea
EndIf
EndMethod

Method ReplaceText(pos:Int,count:Int,text:String,units:Int)
Local n:Int

textarea.ReplaceText(pos,count,text,units)
If (CODEAREA_SYNTAXHIGHLIGHTING & style)
LockTextArea textarea
If units=TEXTAREA_CHARS
For n=TextAreaLine(textarea,pos) To TextAreaLine(textarea,pos+count)
If FormatLine(n) Exit
Next
Else
For n=pos To pos+count
If FormatLine(n) Exit
Next
EndIf
UnlockTextArea textarea
EndIf
EndMethod

Method Activate(command:Int)
Local n:Int
Local clipboardtext:String

Select command
Case ACTIVATE_PASTE
SetTextAreaText dummytextarea,""
GadgetPaste(dummytextarea)
ActivateGadget textarea
clipboardtext=TextAreaText(dummytextarea)

Update()
Local action:TAction
action=New TAction
AddAction action
action.add=clipboardtext
action.addpos=selpos
action.addlen=clipboardtext.length
action.beforepos=selpos
action.beforelen=sellen
action.remove=Mid(text,selpos+1,sellen)
action.removepos=selpos
action.removelen=sellen
action.afterpos=selpos+clipboardtext.length
action.afterlen=0
'action.afterpos=selpos
'action.afterlen=clipboardtext.length
action.Redo(Self)
EmitEvent CreateEvent(EVENT_GADGETACTION,Self)
If (CODEAREA_SYNTAXHIGHLIGHTING & style)
LockTextArea textarea
'Notify TextAreaLine(textarea,action.afterpos)+", "+TextAreaLine(textarea,action.afterpos+action.afterlen)
For n=TextAreaLine(textarea,action.beforepos) To TextAreaLine(textarea,action.beforepos+clipboardtext.length)
If FormatLine(n) Exit
Next
UnlockTextArea textarea
EndIf

Case ACTIVATE_CUT
If sellen
textarea.activate(ACTIVATE_COPY)
Filter(CreateEvent(EVENT_KEYCHAR,textarea,8))
EndIf
Default
textarea.activate(command)
EndSelect
EndMethod

Method Update()
selpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
sellen=TextAreaSelLen(textarea,TEXTAREA_CHARS)
text=TextAreaText(textarea)
EndMethod

Method Filter:Int(event:TEvent)
Local action:TAction

Select event.id
Case EVENT_KEYDOWN
Select event.data
Case KEY_UP,KEY_DOWN,KEY_RIGHT,KEY_LEFT,KEY_HOME,KEY_END,KEY_PAGEUP,KEY_PAGEDOWN
Return True
Case KEY_INSERT
insertmode=Not insertmode
Case KEY_DELETE
If TextAreaSelLen(textarea)
Filter(CreateEvent(EVENT_KEYCHAR,Self,8))
Else
Filter(CreateEvent(EVENT_KEYCHAR,Self,128))
EndIf
EndSelect
Case EVENT_KEYCHAR
If MODIFIER_COMMAND & event.mods Return False
If MODIFIER_OPTION & event.mods Return False
Update()

'Backspace
If event.data=8
action=New TAction
AddAction action
action.add=""
action.addlen=0
action.beforepos=selpos
action.beforelen=sellen
If sellen=0
action.addpos=selpos-1
action.afterpos=selpos-1
action.afterlen=0
action.removelen=1
action.removepos=selpos-1
action.remove=Mid(text,1+selpos-action.removelen,action.removelen)
Else
action.addpos=selpos
action.afterpos=selpos
action.afterlen=0
action.removepos=selpos
action.removelen=sellen
action.remove=Mid(text,1+selpos,sellen)
EndIf
action.Redo(Self)
EmitEvent CreateEvent(EVENT_GADGETACTION,Self)
'action.Undo(self)' test to make sure this is reversable

'Delete
ElseIf event.data=128
action=New TAction
AddAction action
action.add=""
action.addlen=0
action.beforepos=selpos
action.beforelen=0
action.addpos=selpos
action.afterpos=selpos
action.afterlen=0
action.removelen=1
action.removepos=selpos
action.remove=Mid(text,1+selpos,1)
action.Redo(Self)
EmitEvent CreateEvent(EVENT_GADGETACTION,Self)

'All other allowed characters
ElseIf event.data>31 And event.data<127 Or event.data=13
action=New TAction
AddAction action
action.add=Chr(event.data)
action.addpos=selpos
action.addlen=1
action.beforepos=selpos
action.beforelen=sellen
action.removepos=selpos
If insertmode
If sellen=0
action.removelen=1
Else
action.removelen=sellen
EndIf
Else
action.removelen=sellen
EndIf
action.remove=Mid(text,selpos+1,action.removelen)
action.afterpos=selpos+1
action.afterlen=0
action.Redo(Self)
EmitEvent CreateEvent(EVENT_GADGETACTION,Self)
'action.Undo(self)' test to make sure this is reversable
EndIf
EndSelect
Return False
EndMethod

Function Callback:Int(event:TEvent,context:Object)
Local codearea:TCodeArea=New TCodeArea
codearea=TCodeArea(context)
If codearea
Return codearea.Filter(event)
EndIf
EndFunction

Function EventHook:Object(id:Int,data:Object,context:Object)
Local event:TEvent=TEvent(data)
Local codearea:TCodeArea

If event
codearea=TCodeArea(context)
If codearea
If Not codearea.ProcessEvent(event) Return data'Null
EndIf
EndIf
Return data
EndFunction

'---------------------------------------------------------------------------------------------
'Creation
'---------------------------------------------------------------------------------------------
Function Create:TCodeArea(x:Int,y:Int,width:Int,height:Int,group:TGadget,style:Int=CODEAREA_DEFAULT)
Local codearea:TCodeArea=New TCodeArea
Local textareastyle:Int

If Not dummywindow
dummywindow=CreateWindow("",0,0,400,300,Null,WINDOW_HIDDEN)
dummytextarea=CreateTextArea(0,0,300,200,dummywindow)
EndIf
codearea.style=style
If (CODEAREA_READONLY & style) textareastyle=TEXTAREA_READONLY
codearea.textarea=CreateTextArea(x,y,width,height,group,textareastyle)
SetGadgetFilter codearea.textarea,Callback,codearea
codearea.SetProxy(codearea.textarea)
AddHook EmitEventHook,EventHook,codearea
Return codearea
EndFunction

EndType

'---------------------------------------------------------------------------------------------
'Procedural functions
'---------------------------------------------------------------------------------------------
Function CreateCodeArea:TCodeArea(x:Int,y:Int,width:Int,height:Int,group:TGadget,style:Int=CODEAREA_DEFAULT)
Return TCodeArea.Create(x,y,width,height,group,style)
EndFunction

Function AddCodeAreaKeyword(codearea:TCodeArea,word:String)
codearea.AddKeyword(word)
EndFunction

Function SetCodeAreaFormat(codearea:TCodeArea,element:Int,r:Int,g:Int,b:Int,style:Int=0)
codearea.SetFormat(element,r,g,b,style)
EndFunction

Function CodeAreaClearUndos(codearea:TCodeArea)
codearea.ClearUndos()
EndFunction

Function CodeAreaCanUndo:Int(codearea:TCodeArea)
Return codearea.CanUndo()
EndFunction

Function CodeAreaCanRedo:Int(codearea:TCodeArea)
Return codearea.CanRedo()
EndFunction

Function CodeAreaUndo(codearea:TCodeArea)
codearea.Undo()
EndFunction

Function CodeAreaRedo(codearea:TCodeArea)
codearea.Redo()
EndFunction

Function SetCodeAreaLanguage(codearea:TCodeArea,language:Int)
codearea.SetLanguage language
EndFunction


'---------------------------------------------------------------------------------------------
'Example
'---------------------------------------------------------------------------------------------


'Create window
Local window:TGadget=CreateWindow("CodeArea Example",0,0,1024,768,Null,WINDOW_DEFAULT|WINDOW_CENTER)

'Create menu
Local root:TGadget=CreateMenu("Edit",0,WindowMenu(window))
Local menu:TGadget[6]
menu[0]=CreateMenu("Undo",0,root,KEY_Z,MODIFIER_COMMAND)
menu[1]=CreateMenu("Redo",1,root,KEY_Z,MODIFIER_COMMAND|MODIFIER_OPTION)
CreateMenu("",0,root)
DisableMenu menu[0]
DisableMenu menu[1]
menu[2]=CreateMenu("Clear Undos",2,root)
CreateMenu("",0,root)
menu[3]=CreateMenu("Cut",3,root,KEY_X,MODIFIER_COMMAND)
menu[4]=CreateMenu("Copy",4,root,KEY_C,MODIFIER_COMMAND)
menu[5]=CreateMenu("Paste",5,root,KEY_V,MODIFIER_COMMAND)
DisableMenu menu[3]
DisableMenu menu[4]
UpdateWindowMenu window

'Create CodeArea gadget
Local codearea:TCodeArea=CreateCodearea(0,0,ClientWidth(window),ClientHeight(window),window)
SetGadgetLayout codearea,1,1,1,1

'Add some keywords
AddCodeAreaKeyword codearea,"Allegience"
AddCodeAreaKeyword codearea,"Flag"
AddCodeAreaKeyword codearea,"Justice"

'Adjust the syntax highlighting
SetCodeAreaFormat codearea,CODEAREA_KEYWORD,0,0,255,FONT_BOLD
SetCodeAreaFormat codearea,CODEAREA_COMMENT,0,128,0,FONT_ITALIC

'Set the language and add some text

'C/C++
SetCodeAreaLanguage codearea,CODEAREA_C
SetGadgetText codearea,"#define whatever 3~n~nI ~qpledge~q allegience to the flag of the United States of /*America~nAnd to the republic for which it stands~n~qOne nation~q, under God,*/ indivisible~nWith liberty and justice //for all.~n"

'Lua
'SetCodeAreaLanguage codearea,CODEAREA_LUA
'SetGadgetText codearea,"I ~qpledge~q allegience to 'the' flag of the United States of --[[America~nAnd to the republic for which it stands~n~qOne nation~q, under God,]]-- indivisible~nWith liberty and justice --for all.~n"

'BlitzMax
'SetCodeAreaLanguage codearea,CODEAREA_BMX
'SetGadgetText codearea,"?debug~nPrint ~qHello~q~n?~n~nI ~qpledge~q allegience To the flag of the United States of America~nRem~nAnd To the republic For which it stands~n~qOne nation~q, under God, indivisible~nEndRem~nWith liberty and justice 'for all.~n"


'Set the font (we can do this any time)
SetGadgetFont codearea,LoadGuiFont("Courier New",10)

'Set the gadget text and background colors (we can do this at any time)
SetGadgetColor codearea,240,240,240,True
SetGadgetColor codearea,0,0,0,False



While WaitEvent()
Select EventID()

Case EVENT_GADGETSELECT
If TextAreaSelLen(codearea)
EnableMenu menu[3]
EnableMenu menu[4]
Else
DisableMenu menu[3]
DisableMenu menu[4]
EndIf
UpdateWindowMenu window

Case EVENT_GADGETACTION
If TextAreaSelLen(codearea)
EnableMenu menu[3]
EnableMenu menu[4]
Else
DisableMenu menu[3]
DisableMenu menu[4]
EndIf
If codearea.canundo() EnableMenu menu[0] Else DisableMenu menu[0]
If codearea.canredo() EnableMenu menu[1] Else DisableMenu menu[1]
UpdateWindowMenu window

Case EVENT_MENUACTION
Select EventData()
Case 1 codearea.redo()
Case 0 codearea.undo()
Case 2 codearea.ClearUndos()
Case 3 GadgetCut(codearea)
Case 4 GadgetCopy(codearea)
Case 5 GadgetPaste(codearea)
EndSelect
If codearea.canundo() EnableMenu menu[0] Else DisableMenu menu[0]
If codearea.canredo() EnableMenu menu[1] Else DisableMenu menu[1]
UpdateWindowMenu window

Case EVENT_WINDOWCLOSE
End

EndSelect
'Print CurrentEvent.ToString()
Wend




Oddball(Posted 1+ years ago)

 This looks very interesting. I don't need it for anything at the moment, but I'll bookmark it just in case it's useful at a later date. Thanks for sharing.


impixi(Posted 1+ years ago)

 Impressive!


degac(Posted 1+ years ago)

 Thanks for sharing, very good!


JoshK(Posted 1+ years ago)

 The multi-line comments still don't work right.  This is really hard.


JoshK(Posted 1+ years ago)

 I tried a different approach for handling the multi-line comments.  When a line changes its begin or end mult-line comment state, it crawls in one direction or the other looking for its corresponding begin or end statement.  It's super fast and I haven't been able to produce any errors yet:[code]SuperStrict

Import maxgui.drivers
Import maxgui.proxygadgets

'Codearea style constants
Const CODEAREA_SYNTAXHIGHLIGHTING:Int=1
Const CODEAREA_CANUNDO:Int=2
Const CODEAREA_CORRECTCASE:Int=4
Const CODEAREA_READONLY:Int=8
Const CODEAREA_DEFAULT:Int=CODEAREA_SYNTAXHIGHLIGHTING|CODEAREA_CANUNDO|CODEAREA_CORRECTCASE

'Codearea format constants
Const CODEAREA_PLAIN:Int=0
Const CODEAREA_STRING:Int=1
Const CODEAREA_COMMENT:Int=2
Const CODEAREA_KEYWORD:Int=3
Const CODEAREA_PREPROCESSOR:Int=4

'CodeArea language constants
Const CODEAREA_C:Int=0
Const CODEAREA_LUA:Int=1
Const CODEAREA_BMX:Int=2

Private

Type TAction
   
   Field add:String
   Field addpos:Int
   Field addlen:Int
   Field remove:String
   Field removepos:Int
   Field removelen:Int
   Field beforepos:Int
   Field beforelen:Int
   Field afterpos:Int
   Field afterlen:Int
   
   Method Undo(codearea:TCodeArea)
      Local n:Int
      
      SetTextAreaText codearea,remove,addpos,addlen
      SelectTextAreaText codearea,beforepos,beforelen
      If (CODEAREA_SYNTAXHIGHLIGHTING & codearea.style)
         'Locking the text here will cause errors
         'LockTextArea codearea'.textarea
         For n=TextAreaLine(codearea.textarea,Min(afterpos,beforepos)) To TextAreaLine(codearea.textarea,Max(beforepos+beforelen,afterpos+afterlen))
            'codearea.lineincommentblock[n]=0
         'For n=TextAreaLine(codearea.textarea,beforepos) To TextAreaLine(codearea.textarea,beforepos+beforelen)
            n=codearea.FormatLine(n)
         Next
         'UnlockTextArea codearea'.textarea
      EndIf
      EmitEvent CreateEvent(EVENT_GADGETSELECT,codearea,addpos-remove.length)
   EndMethod
   
   Method Redo(codearea:TCodeArea)
      Local n:Int

      SetTextAreaText codearea,add,removepos,removelen
      SelectTextAreaText codearea,afterpos,afterlen
      If (CODEAREA_SYNTAXHIGHLIGHTING & codearea.style)
         'Locking the text here will cause errors
         'LockTextArea codearea'.textarea
         'For n=TextAreaLine(codearea.textarea,afterpos) To TextAreaLine(codearea.textarea,afterpos+afterlen)
         For n=TextAreaLine(codearea.textarea,Min(afterpos,beforepos)) To TextAreaLine(codearea.textarea,Max(beforepos+beforelen,afterpos+afterlen))
            'codearea.lineincommentblock[n]=0
            n=codearea.FormatLine(n)
         Next
         'UnlockTextArea codearea'.textarea
      EndIf
      EmitEvent CreateEvent(EVENT_GADGETSELECT,codearea,removepos+add.length)
   EndMethod
   
EndType

Type TFormat
   
   Field r:Int
   Field g:Int
   Field b:Int
   Field style:Int
   
   Function Create:TFormat(r:Int,g:Int,b:Int,style:Int)
      Local format:TFormat=New TFormat
      format.r=r
      format.g=g
      format.b=b
      format.style=style
      Return format
   EndFunction
   
EndType

Public

Type TCodeArea Extends TProxyGadget
   
   Global dummywindow:TGadget' used to hold dummy textarea
   Global dummytextarea:TGadget' used for paste operations
   Global maxundolevels:Int=0' set to 0 to disable limit
   
   Field textarea:TGadget
   Field selpos:Int
   Field sellen:Int
   Field insertmode:Int
   Field text:String
   Field undoposition:Int=-1
   Field actions:TAction[]
   Field format:TFormat[6]
   Field needsreformat:Int
   Field locked:Int
   Field keywords:TMap=New TMap
   Field token_comment:String="//"
   Field token_multilinecommentbegin:String="/*"
   Field token_multilinecommentend:String="*/"
   Field token_string:String="~q"
   Field token_string2:String' Lua uses multiple string tokens
   Field token_preprocessor:String="#"
   Field multilinecommentstyle:Int
   Field lineincommentblock:Byte[]
   Field multilinecommentschanged:Int
   
   Method New()
      format[CODEAREA_PLAIN]=TFormat.Create(0,0,0,0)
      format[CODEAREA_STRING]=TFormat.Create(128,0,128,0)
      format[CODEAREA_COMMENT]=TFormat.Create(0,128,0,0)
      format[CODEAREA_PREPROCESSOR]=TFormat.Create(255,0,0,0)
      format[CODEAREA_KEYWORD]=TFormat.Create(0,0,255,0)
   EndMethod
   
   Method Cleanup()
      RemoveHook EmitEventHook,EventHook,Self
   EndMethod
   
   '---------------------------------------------------------------------------------------------
   'Syntax highlighting
   '---------------------------------------------------------------------------------------------   
   Method SetLanguage(language:Int)
      Select language
      
      Case CODEAREA_C
         token_comment="//"
         token_multilinecommentbegin=

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal