--[[LuaCS, by Yatto]] --[[LuaColorationSytaxique, ou LuaCodeSource]] --[[ compile avec Luna-0.2a, de ExtendeD http://ndlessly.wordpress.com ]] --Utilise un bout de Universal Menu, de Spirikoi --[[Merci a: Critor, Adriweb, Levak, Excale, Monstercrunch, Laurae et ses NYAN et YATTOFLOW, et tous ceux que j'oublie, pour m'avoir supporte, aide, trouve des bugs, proposer des ameliorations, des idees quand j'avais des problemes, bref, merci pour tout ce qui a fait de cette idee un programme. =) ]] local x,y y=1 z=0 i=0 j=0 x=0 isColor=true cutCalled=false isSelection=false selx=0 sely=0 tmp="" copy="" undoIndex = 1 buffer = { [1]="", } -- cs{ [n]={"mot", "couleur", "le mot doit-il etre isole?"}, } cs={ [1]={"function", "orange", true}, [2]={"do", "darkred", true}, [3]={"if", "blue", true}, [4]={"then", "blue", true}, [5]={"end", "green", true}, [6]={"while", "darkred", true}, [7]={"=", "brown", false}, [8]={"else" , "blue", true}, [9]={"elseif", "blue", true}, [10]={"true", "gray", true}, [11]={"false", "gray", true}, [12]={"or", "royalblue", true}, [13]={"do", "darkred", true}, [14]={"return", "purple", true}, [15]={"nil", "gray", false}, [16]={"platform.window:invalidate()", "darkblue", true}, [17]={"<", "brown", false}, [18]={">", "brown", false}, [19]={"and", "royalblue", true}, [20]={"for", "darkred", true}, -- [21]={"--.*", "turquoise", false}, } UndoTable={} function test(arg) return arg and 1 or 0 end function addChar(ch,posx,posy) buffer[posy] = buffer[posy]:sub(0, posx)..ch..buffer[posy]:sub(posx + 1) x=posx +1 y=posy end function delChar(ch,posx,posy) buffer[posy] = buffer[posy]:sub(0, posx-1)..buffer[posy]:sub(posx + 1) x=posx-1 y=posy end function addLine(posx,posy,dummy) -- car les fonctions undo/redo renvoient 3 arguments table.insert(buffer, posy, string.sub(buffer[posy-1],posx+1)) buffer[posy]=string.sub(buffer[posy],0,posx) x=posx y=posy end function delLine(posx, posy, dummy) -- car les fonctions undo/redo renvoient 3 arguments buffer[posy-1]=buffer[posy-1]..buffer[posy] table.remove(buffer,posy) x=posx y=posy-1 end function pastedo(chaine, oldselx, oldsely, oldx, oldy) copy=chaine selx=oldselx sely=oldsely x=oldx y=oldy clipboard.addText(copy) callbyitself=false -- on ne veut pas rajouter une ligne à l'undo! pastepp() end function cutdo(chaine, oldselx, oldsely, oldx, oldy) selx=oldselx sely=oldsely x=oldx y=oldy callbyitself=false -- on ne veut pas rajouter une ligne à l'undo! cutpp() end HistoryMap = { [delChar]=addChar, [addChar]=delChar, [addLine]=delLine, [delLine]=addLine, [cutdo]=pastedo, [pastedo]=cutdo, } function addUndo(fonct, param1, param2, param3, param4, param5) if undoIndex>1 then while undoIndex > 0 do table.remove(UndoTable, undoIndex) undoIndex = undoIndex - 1 end undoIndex=1 end table.insert(UndoTable,1,{fonct, param1, param2, param3, param4, param5}) end function setColor(theColor) -- It's a "Better lua API" script that Spirikoi have modified, in his "Universal Menu", thanks to him theColor = string.lower(theColor) platform.gc():setColorRGB(0,0,0) -- set black as default is nothing else valid is found if theColor == "blue" then platform.gc():setColorRGB(0,0,255) elseif theColor == "brown" then platform.gc():setColorRGB(165,42,42) elseif theColor == "cyan" then platform.gc():setColorRGB(0,255,255) elseif theColor == "darkblue" then platform.gc():setColorRGB(0,0,139) elseif theColor == "darkred" then platform.gc():setColorRGB(139,0,0) elseif theColor == "fuchsia" then platform.gc():setColorRGB(255,0,255) elseif theColor == "gold" then platform.gc():setColorRGB(255,215,0) elseif theColor == "gray" or theColor == "grey" then platform.gc():setColorRGB(127,127,127) elseif theColor == "green" then platform.gc():setColorRGB(0,128,0) elseif theColor == "lightblue" then platform.gc():setColorRGB(173,216,230) elseif theColor == "lightgreen" then platform.gc():setColorRGB(144,238,144) elseif theColor == "magenta" then platform.gc():setColorRGB(255,0,255) elseif theColor == "maroon" then platform.gc():setColorRGB(128,0,0) elseif theColor == "navyblue" then platform.gc():setColorRGB(159,175,223) elseif theColor == "orange" then platform.gc():setColorRGB(255,125,0) elseif theColor == "palegreen" then platform.gc():setColorRGB(152,251,152) elseif theColor == "pink" then platform.gc():setColorRGB(255,192,203) elseif theColor == "purple" then platform.gc():setColorRGB(128,0,128) elseif theColor == "red" then platform.gc():setColorRGB(255,0,0) elseif theColor == "royalblue" then platform.gc():setColorRGB(65,105,225) elseif theColor == "salmon" then platform.gc():setColorRGB(250,128,114) elseif theColor == "seagreen" then platform.gc():setColorRGB(46,139,87) elseif theColor == "silver" then platform.gc():setColorRGB(192,192,192) elseif theColor == "turquoise" then platform.gc():setColorRGB(64,224,208) elseif theColor == "violet" then platform.gc():setColorRGB(238,130,238) elseif theColor == "white" then platform.gc():setColorRGB(255,255,255) elseif theColor == "yellow" then platform.gc():setColorRGB(255,255,0) elseif theColor == "paleyellow" then platform.gc():setColorRGB(255,255,150) end end function on.charIn(ch) if isSelection then cutpp() -- on suppr. la selection clipboard.addText("") -- on vide le pp end prex = string.sub(buffer[y],0,x) postx = string.sub(buffer[y],x+1) buffer[y] = prex..ch..postx --insert char x=x+1 -- pos. char suivant addUndo(delChar,ch,x,y,nil) platform.window:invalidate() end function on.paint(gc) setColor("black") prex = string.sub(buffer[y],0,x) postx = string.sub(buffer[y],x+1) width=(13+(math.floor(math.log10(y))+1)*8) i=i-j --i: var de la ligne de debut d'ecriture l=table.getn(buffer) if y>i+14 then --si le curseur sort de l'ecran par le bas i=y-14 end if yy+1 do --y+1 pour traiter la derniere ligne a part. k=k-1 gc:fillRect(((math.floor(math.log10(k))+1)*8)+9+z, (k-1)*15, gc:getStringWidth(buffer[k])+2,15) end end -- comme on a une ligne colore sur la position y, on traitera sely=y aprs qu'on ait dessine la ligne jaune. setColor("black") end while iy then gc:fillRect((math.floor(math.log10(y))+1)*8+9 + gc:getStringWidth(string.sub(buffer[y],0,x))+z, (y-1)*15, gc:getStringWidth(string.sub(buffer[y],x+test(x~=0))) +2 , 15) end if sely == y then if selxx then gc:fillRect(((math.floor(math.log10(y))+1)*8)+9+z + gc:getStringWidth(string.sub(buffer[y],0,x)) , (y-1)*15, gc:getStringWidth(string.sub(buffer[y],x+test(x~=0),selx))+2, 15) end end end setColor("black") end -- j2 sera reutilise plus tard... if gc:getStringWidth(chainy)>289 then -- si la chaine depasse l'ecran (la place pour le texte est d'environ 289 px) if i==y then sub=string.sub(chainy,0,x+math.floor(math.log10(y))+1+2) --[[ la ligne ci-dessus est un peu bizarre, mais logique au fond. On veut trouver la longueur de la ligne avec les caractere pretapes: le numero de la ligne et les deux espaces. Or le numero de ligne change! si la ligne est dans les dizaines, elle a deux chiffres, dans les centaines, trois... D'ou l'arrondi du logarithme: il permet de recuperer 0 s'il n'y a qu'une unite, 1 s'il y a des dizaines, 2 avec les centaines... On rajoute a cela "+1" pour avoir le nombre correct (1 pour unite, 2 pour dizaines...) et on rajoute enfin "+2" qui correspondent aux deux espaces entre le numero et la ligne proprement dite. ]] if gc:getStringWidth(sub)>289 then z=289-gc:getStringWidth(sub) else z=0 end else z=0 end end gc:drawString(chainy,z,j*15) --coloration syntaxique if isColor then e=1 a=1 t=1 preligne = math.floor(math.log10(i))+1+2 -- le nombre de caracteres dans le preligne (nombre+.+%s%s) while t<=table.getn(cs) do e,a=0,1 testcs=cs[t] while not(a==nil) do a,b=string.find(chainy,testcs[1],e) prechar=nil postchar=nil if testcs[3] then -- si le mot doit etre isole... if a~=nil then --si a existe, a est forcement apres le preligne... donc il vaut au moins 5 !! prechar=chainy:sub(a-1,a-1) if prechar==" " then prechar=true else prechar=false end if b~=#chainy then --si b n'est pas en fin de ligne (pas besoin de tester si b existe: si a existe, b existe.) postchar=chainy:sub(b+1,b+1) -- on regarde le caractere suivant if postchar==" " then postchar=true else postchar=false end else -- si b existe mais b==fin de ligne postchar=true end end end -- a existe, et ( pas besoin d'isoler OU (prechar ET postchar sont conformes à l'isolation) if a~=nil and ( not(testcs[3]) or (prechar and postchar)) then -- on colorie! m=gc:getStringWidth(string.sub(chainy,0,a-1 )) setColor(testcs[2]) gc:drawString(string.sub(chainy,a,b),m+z,j*15) -- setColor("black") e=b -- on test a partir de la fin du mot end e=e+1 end t=t+1 end end end -- endWhile: fin de la boucle d'affichage du texte --curseur fantome sub2=string.sub(buffer[y],0,x) lsub2=gc:getStringWidth(sub2)+ gc:getStringWidth(y..". ")+2 if lsub2>294 then lsub2=294 end gc:drawString("|",lsub2,j2*15) --ascenceur gc:drawString("#",305,((201*(y-1))/l)+15) -- cadre de l'ascenseur gc:setPen("medium", "smooth") gc:drawLine(304, 0, 304, ((201*(l-1))/l)+10) gc:drawLine(303, ((201*(l-1))/l)+12,320,((201*(l-1))/l)+12) -- affichage d'aide pendant les versions WIP --gc:drawString(x,10,200) --pos x --gc:drawString(y,300,200) -- pos y --gc:drawString(width,150,200) --gc:drawString(undoIndex,300,200) -- pos de l'index des Undo --gc:drawString(table.getn(UndoTable),50,200) --gc:drawString(selx,10,200) --gc:drawString(sely,260,200) if isSelection then gc:drawString("Select",120,200) -- ça fait tres "version beta" mais ca reste simple et clair... end end function on.backspaceKey() if isSelection then cutpp() -- on suppr. la selection clipboard.addText("") -- on vide le pp else if x==0 and y>1 then x=#buffer[y-1] buffer[y-1]=buffer[y-1]..buffer[y] table.remove(buffer,y) y=y-1 addUndo(addLine,x,y,nil,nil) -- le 0 serait le 3e argument renvoye, il ne sert a rien mais les fonctions undo-redo ont besoin de 3 arguments elseif x>0 then addUndo(addChar,string.sub(buffer[y],x,x),x,y,nil) buffer[y]=string.sub(buffer[y],0,x-1)..string.sub(buffer[y],x+1) x=x-1 end end platform.window:invalidate() end function on.enterKey() if isSelection then cutpp() -- on suppr. la selection clipboard.addText("") -- on vide le pp end prex = string.sub(buffer[y],0,x) postx = string.sub(buffer[y],x+1) table.insert(buffer, y+1, postx) k=0 while k<100 do tabul=string.sub(buffer[y],0,k) g=0 tabulcomp="" while g1 then y=y-1 if #buffer[y+1]>#buffer[y] then x=#buffer[y] end platform.window:invalidate() end end function on.arrowDown() if (table.getn(buffer))>y then y=y+1 if #buffer[y-1]>#buffer[y] then x=#buffer[y] end platform.window:invalidate() end end function on.arrowLeft() if x>0 then x=x-1 elseif y>1 then y=y-1 x=#buffer[y] end platform.window:invalidate() end function on.arrowRight() if x<#buffer[y] then x=x+1 else if not(buffer[y+1]==nil) then x=0 y=y+1 end end platform.window:invalidate() end function on.mouseDown(mx,my) width=(13+(math.floor(math.log10(y))+1)*8) length=platform.gc():getStringWidth(buffer[y]) a=i-j b=math.floor(a + (my/15))+1 if b<=table.getn(buffer) then y= b -- +1 parce que ca arrondit (math.floor) 1 ligne en dessous end k=0 b=true mx=mx-width while k<=#buffer[y] and b do sub=string.sub(buffer[y],0,k) a= platform.gc():getStringWidth(sub) if a+z >=mx then -- "-z":= si la fenetre est decalee x=k b=false end k=k+1 end if width+length < mx then x=#buffer[y] end platform.window:invalidate() end function on.backtabKey() undo() end function on.clearKey() redo() end function on.tabKey() if not(isSelection) then isSelection=true selx, sely = x, y else isSelection=false end end function undo() if table.getn(UndoTable) > 1 and undoIndex<=table.getn(UndoTable) then -- si la liste des actions effectuees n'est pas vide && si on peut encore annuler (s'il existe des actions au dessous de l'index) local elt = UndoTable[undoIndex] elt[1](elt[2], elt[3], elt[4],elt[5],elt[6]) -- on execute la fonction contraire a celle faite (n UndoIndex), avec ses parametres (sous-table) undoIndex = undoIndex + 1 platform.window:invalidate() end end function redo() if undoIndex > 1 then -- Si on a fait au moins un Undo local elt = UndoTable[undoIndex-1] --on prend l'action qu'on vient d'annuler HistoryMap[elt[1]](elt[2], elt[3], elt[4], elt[5], elt[6]) -- on fait l'inverse du Undo qu'on retrouve avec la table de correspondance HistoryMap undoIndex = undoIndex-1 platform.window:invalidate() end end function on.copy() callbyitself=true copypp() end function on.cut() callbyitself=true cutpp() end function on.paste() callbyitself=true pastepp() end function copypp() copy="" if sely==y then if selxx then copy=buffer[y]:sub(x+test(x~=0),selx) end elseif selyy then copy=buffer[y]:sub(x+test(x~=0)).."\n" k=y while kx then buffer[y]=buffer[y]:sub(0,x)..buffer[y]:sub(selx+1) -- selx exclu x=selx end end if selyy then buffer[y]=buffer[y]:sub(0,x)..buffer[sely]:sub(selx+test(selx~=0)) --l=sely while y0 then y=vary platform.window:invalidate() end end function sauver() tmp=table.concat(buffer,"@@eol@@") tmp = tmp.."@@eol@@" var.store("txt",tmp) end function charger() dummy=0 copie=var.recallstr("txt") tmp=string.sub(copie,2,(#copie)-1) -- enleve les "" a=0 while a~=nil do a=string.find(tmp,[[""]]) --]] resolution d'un bug de CS de ZEUS if not(a==nil) then tmp=string.sub(tmp,0,a)..string.sub(tmp,a+2) -- on supprime le 2e guillemet cr?? par l'importateur Lua quand on fait un guillemet. end end k=1 tablelongueur=table.getn(buffer) -- il faut definir la longueur en tant que variable pour ne pas que dans la condition la valeur bouge while buffer[k]~=nil do -- on teste s'il reste une ou des lignes a supprimer table.remove(buffer,k) -- il va toujours supprimer la ligne 1, et la ligne d'apres deviendra la ligne 1 end -- le buffer est vide, et n'a aucune ligne table.insert(buffer,1,"") -- le buffer a une ligne vide k=0 a=0 while not(a==nil) do k=k+1 a=string.find(tmp,"@@eol@@") if a~=nil then table.insert(buffer,k,string.sub(tmp,0,a-1)) -- on colle la ligne dans le buffer tmp=string.sub(tmp,a+7) -- on supprime ce qu'on a colle dans le buffer end end platform.window:invalidate() -- le buffer est rempli par la sauvegarde, mais il a une ligne vide a la fin, qu'on va supprimer table.remove(buffer, table.getn(buffer)) y=table.getn(buffer) x=#buffer[y] end function on.create() var.store("y",1) var.monitor("y") end function ecrire(mot,h) prex = string.sub(buffer[y],0,x) postx = string.sub(buffer[y],x+1) buffer[y]=prex..mot..postx x = x + h -- on positionne le curseur la ou on veut dans l'expression qu'on a rajoute platform.window:invalidate() end function fIfThen() ecrire("if then", 3) end function fElse() ecrire("else", 5) end function fEnd() ecrire("end", 3) end function fWhileDo() ecrire("while do",6) end function fForDo() ecrire("for do", 4) end function fPWI() ecrire("platform.window:invalidate()",28) end function fVarMonit() ecrire("var.monitor()", 12) end function fVarUnmonit() ecrire("var.unmonitor()", 14) end function fVarRecall() ecrire("var.recall()", 11) end function fVarRecallstr() ecrire("var.recallstr()", 14) end function fVarStore() ecrire("var.store(,)",10) end function fVarList() ecrire("var.list()",9) end function fFunction() ecrire("function",8) end function fReturn() ecrire("return",6) end function fAccol() ecrire("{}",1) end function fBrackets() ecrire("[]",1) end function fColorSyntax() if isColor then isColor=false else isColor=true end end menu = { {"Fichier...", {"Sauvegarder", sauver}, {"Charger", charger}, {"Selectionner tout", selectAll}, }, {"Blocs conditionnels/boucles", {"if then", fIfThen}, {"else", fElse}, {"end", fEnd}, {"while do", fWhileDo}, {"for do", fForDo}, }, {"fonction/termes usuels", {"function", fFunction}, {"return", fReturn}, {"platform.window:invalidate()", fPWI}, }, {"Var. -->", {"var.monitor()", fVarMonit}, {"var.unmonitor()", fVarUnmonit}, {"var.recall()", fVarRecall}, {"var.recallstr()", fVarRecallstr}, {"var.store()", fVarStore}, {"var.list()", fVarList}, }, {"Caract"..string.uchar(232).."res sp"..string.uchar(233).."ciaux", -- un caprice de ma part pour avoir un accent. {"{}", fAccol}, {"[]", fBrackets}, }, {"Options", {"Activer/desactiver la coloration syntaxique", fColorSyntax}, } } toolpalette.register(menu) toolpalette.enablePaste(true) toolpalette.enableCut(true) toolpalette.enableCopy(true)