Syntax highlighting?
This commit is contained in:
parent
2f1fdfaf5a
commit
343dc115d9
|
|
@ -0,0 +1,254 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from GUI import Application, ScrollableView, Window, Font, Colors
|
||||||
|
from pygments import highlight
|
||||||
|
from pygments.lexers import ActionScriptLexer
|
||||||
|
from pygments.formatter import Formatter
|
||||||
|
from pygments.filters import NameHighlightFilter
|
||||||
|
from pygments.token import Token
|
||||||
|
|
||||||
|
def hex2rgb(hex):
|
||||||
|
a=hex[1]
|
||||||
|
b=hex[2]
|
||||||
|
c=hex[3]
|
||||||
|
if len(hex)==7:
|
||||||
|
d=hex[4]
|
||||||
|
e=hex[5]
|
||||||
|
f=hex[6]
|
||||||
|
ab = a+b
|
||||||
|
cd = c+d
|
||||||
|
ef = e+f
|
||||||
|
return (int(ab, 16)/256.0, int(cd, 16)/256.0, int(ef, 16)/256.0)
|
||||||
|
elif len(hex)==9:
|
||||||
|
d=hex[4]
|
||||||
|
e=hex[5]
|
||||||
|
f=hex[6]
|
||||||
|
g=hex[7]
|
||||||
|
h=hex[8]
|
||||||
|
ab = a+b
|
||||||
|
cd = c+d
|
||||||
|
ef = e+f
|
||||||
|
gh = g+h
|
||||||
|
return (int(ab, 16)/256.0, int(cd, 16)/256.0, int(ef, 16)/256.0, int(gh, 16)/256.0)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return (int(a, 16)/16.0, int(b, 16)/16.0, int(c, 16)/16.0)
|
||||||
|
|
||||||
|
class EverythingHighlightFilter(NameHighlightFilter):
|
||||||
|
def __init__(self, names, tokentype, names2, tokentype2, names3, tokentype3):
|
||||||
|
NameHighlightFilter.__init__(self, names=names, tokentype=tokentype)
|
||||||
|
self.names2 = names2
|
||||||
|
self.tokentype2 = tokentype2
|
||||||
|
self.names3 = names3
|
||||||
|
self.tokentype3 = tokentype3
|
||||||
|
def filter(self, lexer, stream):
|
||||||
|
define = False
|
||||||
|
for ttype, value in stream:
|
||||||
|
if value in self.names:
|
||||||
|
ttype = self.tokentype
|
||||||
|
elif value in self.names2:
|
||||||
|
ttype = self.tokentype2
|
||||||
|
elif value in self.names3:
|
||||||
|
ttype = self.tokentype3
|
||||||
|
yield ttype, value
|
||||||
|
|
||||||
|
class PyGUIFormatter(Formatter):
|
||||||
|
def __init__(self, **options):
|
||||||
|
Formatter.__init__(self, **options)
|
||||||
|
self.styles = {}
|
||||||
|
for token, style in self.style:
|
||||||
|
self.styles[token] = {}
|
||||||
|
if style['color']:
|
||||||
|
self.styles[token]['color'] = Colors.rgb(*hex2rgb(style['color']))
|
||||||
|
|
||||||
|
def format(self, tokensource, outfile):
|
||||||
|
for ttype, value in tokensource:
|
||||||
|
self.lines = 0
|
||||||
|
self.tabs = 0
|
||||||
|
self.cr.gsave()
|
||||||
|
if 'color' in self.styles[ttype]:
|
||||||
|
self.cr.textcolor = self.styles[ttype]['color']
|
||||||
|
else:
|
||||||
|
if ttype==Token.Text:
|
||||||
|
self.lines+=value.count('\n')
|
||||||
|
self.tabs+=value.count('\t')
|
||||||
|
self.cr.show_text(value)
|
||||||
|
self.cr.stroke()
|
||||||
|
self.cr.grestore()
|
||||||
|
if self.lines:
|
||||||
|
self.cr.rmoveto(-self.cr.current_point[0],self.lines*self.height)
|
||||||
|
if self.tabs:
|
||||||
|
self.cr.rmoveto(self.tabwidth*self.tabs, 0)
|
||||||
|
class CodeEditor(ScrollableView):
|
||||||
|
def __init__(self):
|
||||||
|
ScrollableView.__init__(self)
|
||||||
|
self.text = "var a = {b:5, c:[3, 'df \\'']};\n_xscale\nif (this.hitTest(_root._xmouse, root._ymouse, false)) {\n\n\ttrace('hi');\n}"
|
||||||
|
self.font = Font('Courier', 16)
|
||||||
|
self.selecting = False
|
||||||
|
self.lexer = ActionScriptLexer()
|
||||||
|
self.cursorpos = 0
|
||||||
|
self.scursorpos = 0
|
||||||
|
self.formatter = PyGUIFormatter()
|
||||||
|
# self.filter = NameHighlightFilter(
|
||||||
|
self.filter = EverythingHighlightFilter(
|
||||||
|
names=['trace'],
|
||||||
|
tokentype=Token.Keyword,
|
||||||
|
names2=['_root', '_global'],
|
||||||
|
tokentype2=Token.Name.Builtin,
|
||||||
|
names3=['_alpha', 'blendMode', 'cacheAsBitmap', '_currentframe', '_droptarget', 'enabled', 'filters',
|
||||||
|
'focusEnabled', '_focusRect', 'forceSmoothing', '_framesloaded', '_height', '_highquality',
|
||||||
|
'hitArea', '_lockroot', 'menu', 'opaqueBackground', '_parent', '_quality', '_rotation', 'scale9Grid',
|
||||||
|
'scrollRect', '_soundbuftime', 'tabChildren', 'tabEnabled', 'tabIndex', '_target', 'totalframes',
|
||||||
|
'trackAsMenu', 'transform', '_url', 'useHandCursor', '_visible', '_width', '_x', '_xmouse',
|
||||||
|
'_xscale', '_y', '_ymouse', '_yscale'],
|
||||||
|
tokentype3=Token.Name.Variable.Class
|
||||||
|
)
|
||||||
|
self.extent = (self.width, self.height)
|
||||||
|
# Not working - no idea why - disabled to add speed
|
||||||
|
self.lexer.add_filter(self.filter)
|
||||||
|
def container_resized(self, event):
|
||||||
|
self.extent = (self.width, self.height)
|
||||||
|
ScrollableView.container_resized(self, event)
|
||||||
|
def draw(self, cr, update_rect):
|
||||||
|
cr.fillcolor = Colors.rgb(1,1,1)
|
||||||
|
cr.fill_rect(update_rect)
|
||||||
|
d = self.font.descent
|
||||||
|
h = self.font.height
|
||||||
|
w = self.font.width(' ')
|
||||||
|
cr.font = self.font
|
||||||
|
if '\n' in self.text[:self.scursorpos]:
|
||||||
|
scw = self.font.width(self.text[self.text.rindex('\n',0,self.scursorpos):self.scursorpos])
|
||||||
|
else:
|
||||||
|
scw = self.font.width(self.text[:self.scursorpos])
|
||||||
|
if '\n' in self.text[:self.cursorpos]:
|
||||||
|
cw = self.font.width(self.text[self.text.rindex('\n',0,self.cursorpos):self.cursorpos])
|
||||||
|
else:
|
||||||
|
cw = self.font.width(self.text[:self.cursorpos])
|
||||||
|
selines = self.text[:self.scursorpos].count('\n')+1
|
||||||
|
elines = self.text[:self.cursorpos].count('\n')+1
|
||||||
|
if self.selecting:
|
||||||
|
cr.fillcolor = Colors.rgb(0.5,0.75,1)
|
||||||
|
cr.moveto(scw,d+h*selines)
|
||||||
|
cr.lineto(scw,-h+h*selines)
|
||||||
|
if selines!=elines:
|
||||||
|
cr.lineto(self.extent[0],-h+h*selines)
|
||||||
|
cr.lineto(self.extent[0],-h+h*elines)
|
||||||
|
cr.lineto(cw,-h+h*elines)
|
||||||
|
cr.lineto(cw,d+h*elines)
|
||||||
|
if selines != elines:
|
||||||
|
cr.lineto(0,d+h*elines)
|
||||||
|
cr.lineto(0,d+h*selines)
|
||||||
|
cr.fill()
|
||||||
|
# cr.fill_rect([scw,d+h*elines,cw,-h+h*elines])
|
||||||
|
cr.newpath()
|
||||||
|
cr.moveto(0,self.font.height)
|
||||||
|
self.formatter.cr = cr
|
||||||
|
self.formatter.height = self.font.height
|
||||||
|
self.formatter.tabwidth = self.font.width('\t')
|
||||||
|
highlight(self.text, self.lexer, self.formatter)
|
||||||
|
cr.newpath()
|
||||||
|
cr.moveto(cw,d+h*elines)
|
||||||
|
cr.lineto(cw,-h+h*elines)
|
||||||
|
cr.stroke()
|
||||||
|
# cr.show_text(self.text)
|
||||||
|
# cr.stroke()
|
||||||
|
def mouse_down(self, event):
|
||||||
|
self.become_target()
|
||||||
|
x, y = event.position
|
||||||
|
self.selecting = False
|
||||||
|
# self.cursorpos = self.text.replace('\n',' ',int(y/self.font.height)-1).find('\n')
|
||||||
|
# if self.cursorpos==-1:
|
||||||
|
# self.cursorpos = len(self.text)-1
|
||||||
|
# self.cursorpos+=1
|
||||||
|
# self.cursorpos = min(self.cursorpos+int(x/self.font.width(' ')), max(self.text.find('\n',self.cursorpos+1),0) or len(self.text))
|
||||||
|
lns = self.text.splitlines()
|
||||||
|
self.cursorpos = sum([len(i) for i in lns[:int(y/self.font.height)]])
|
||||||
|
try:
|
||||||
|
self.cursorpos += min(int(x/self.font.width(' '))+1,lns[int(y/self.font.height)])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.scursorpos = self.cursorpos
|
||||||
|
if int(y/self.font.height):
|
||||||
|
self.cursorpos+=1
|
||||||
|
self.invalidate_rect([0,0,self.extent[0],self.extent[1]])
|
||||||
|
def mouse_drag(self, event):
|
||||||
|
x, y = event.position
|
||||||
|
self.selecting = True
|
||||||
|
lns = self.text.splitlines()
|
||||||
|
self.cursorpos = sum([len(i) for i in lns[:int(y/self.font.height)]])
|
||||||
|
try:
|
||||||
|
self.cursorpos += min(int(x/self.font.width(' '))+1,lns[int(y/self.font.height)])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if int(y/self.font.height):
|
||||||
|
self.cursorpos+=1
|
||||||
|
self.invalidate_rect([0,0,self.extent[0],self.extent[1]])
|
||||||
|
def key_down(self, event):
|
||||||
|
keydict = {127:"backspace",63272:"delete",63232:"up_arrow",63233:"down_arrow",
|
||||||
|
63235:"right_arrow",63234:"left_arrow",13:"enter",9:"tab",
|
||||||
|
63236:"F1",63237:"F2",63238:"F3",63239:"F4",63240:"F5",
|
||||||
|
63241:"F6",63242:"F7",63243:"F8",27:"escape"}
|
||||||
|
if not event.unichars=='':
|
||||||
|
if ord(event.unichars) in keydict:
|
||||||
|
key = keydict[ord(event.unichars)]
|
||||||
|
else:
|
||||||
|
key = event.unichars
|
||||||
|
else:
|
||||||
|
key = event.key.upper()
|
||||||
|
if key == "\b":
|
||||||
|
if self.cursorpos>0:
|
||||||
|
self.text = self.text[:self.cursorpos-1]+self.text[self.cursorpos:]
|
||||||
|
elif key == "enter":
|
||||||
|
self.text = self.text[:self.cursorpos]+"\n"+self.text[self.cursorpos:]
|
||||||
|
self.height = self.font.height*(self.text.count('\n')+1)
|
||||||
|
self.cursorpos += 1
|
||||||
|
elif key == "backspace":
|
||||||
|
if self.cursorpos>0:
|
||||||
|
self.text = self.text[:self.cursorpos-1]+self.text[self.cursorpos:]
|
||||||
|
self.cursorpos -= 1
|
||||||
|
elif key == "delete":
|
||||||
|
if self.cursorpos<len(self.text):
|
||||||
|
self.text = self.text[:self.cursorpos]+self.text[self.cursorpos+1:]
|
||||||
|
elif key == "left_arrow":
|
||||||
|
if self.cursorpos>0:
|
||||||
|
self.cursorpos -= 1
|
||||||
|
elif key == "right_arrow":
|
||||||
|
if self.cursorpos<len(self.text):
|
||||||
|
self.cursorpos += 1
|
||||||
|
elif key == "up_arrow":
|
||||||
|
if '\n' in self.text[:self.cursorpos]:
|
||||||
|
lpos = self.text[:self.cursorpos].rindex('\n', 0, self.cursorpos)
|
||||||
|
if '\n' in self.text[:lpos]:
|
||||||
|
llpos = self.text[:lpos].rindex('\n',0,lpos)
|
||||||
|
else:
|
||||||
|
llpos = -1 # to account for no \n preceding it
|
||||||
|
self.cursorpos = min(self.cursorpos-lpos+llpos,lpos)
|
||||||
|
elif key == "down_arrow":
|
||||||
|
if '\n' in self.text[self.cursorpos:]:
|
||||||
|
if '\n' in self.text[:self.cursorpos]:
|
||||||
|
lpos = self.text[:self.cursorpos].rindex('\n', 0, self.cursorpos)
|
||||||
|
else:
|
||||||
|
lpos = -1
|
||||||
|
npos = self.text[self.cursorpos:].index('\n')
|
||||||
|
if '\n' in self.text[self.cursorpos+npos+1:]:
|
||||||
|
nnpos = self.text[self.cursorpos+npos+1:].index('\n')
|
||||||
|
else:
|
||||||
|
nnpos = len(self.text[self.cursorpos:])
|
||||||
|
self.cursorpos = min(self.cursorpos+npos+self.cursorpos-lpos,self.cursorpos+npos+nnpos+1)
|
||||||
|
else:
|
||||||
|
self.text=self.text[:self.cursorpos]+str(key)+self.text[self.cursorpos:]
|
||||||
|
self.cursorpos += 1
|
||||||
|
self.invalidate_rect([0,0,self.extent[0],self.extent[1]])
|
||||||
|
class test(Application):
|
||||||
|
def __init__(self):
|
||||||
|
Application.__init__(self)
|
||||||
|
self.make_window()
|
||||||
|
def make_window(self):
|
||||||
|
win = Window(size = (400,400))
|
||||||
|
tex = CodeEditor()
|
||||||
|
win.place(tex, left=0, top=0, right=0, bottom=0, sticky='nesw')
|
||||||
|
win.show()
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
test().run()
|
||||||
|
|
@ -314,6 +314,9 @@ elif sys.platform=="darwin":
|
||||||
TEMPDIR="/tmp"
|
TEMPDIR="/tmp"
|
||||||
sep = "/"
|
sep = "/"
|
||||||
|
|
||||||
|
if SYSTEM=="osx":
|
||||||
|
from codeeditor import CodeEditor
|
||||||
|
|
||||||
FILE = tarfile.open(name=TEMPDIR+"/Untitled",mode="w:gz")
|
FILE = tarfile.open(name=TEMPDIR+"/Untitled",mode="w:gz")
|
||||||
FILE.close()
|
FILE.close()
|
||||||
|
|
||||||
|
|
@ -1221,7 +1224,8 @@ class TextView(Widget):
|
||||||
def mouse_down(self, event):
|
def mouse_down(self, event):
|
||||||
self.become_target()
|
self.become_target()
|
||||||
GUI.TextEditor.mouse_down(self, event)
|
GUI.TextEditor.mouse_down(self, event)
|
||||||
self.box = OSXTextEditor(scrolling="hv")
|
# self.box = OSXTextEditor(scrolling="hv")
|
||||||
|
self.box = CodeEditor()
|
||||||
self.box.font = Font("Courier", 12, [])
|
self.box.font = Font("Courier", 12, [])
|
||||||
if width and height:
|
if width and height:
|
||||||
self.box.size = (width, height)
|
self.box.size = (width, height)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue