Updated PyCrust contrib from Patrick O'Brian.
Added an enhanced wxEditor from Steve Howell and Adam Feuer. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12782 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,10 +1,77 @@
|
||||
PLEASE NOTE: This is experimental code. It needs an overhall in the
|
||||
drawing and update code, and there is occasionally a
|
||||
mysteriously disappearing line...
|
||||
wxEditor component
|
||||
------------------
|
||||
|
||||
I am working on a StyledTextEditor that will likely
|
||||
render this editor obsolete... But this one is at
|
||||
least somewhat functional now while the other is still
|
||||
vapor.
|
||||
The wxEditor class implements a simple text editor using wxPython. You
|
||||
can create a custom editor by subclassing wxEditor. Even though much of
|
||||
the editor is implemented in Python, it runs surprisingly smoothly on
|
||||
normal hardware with small files.
|
||||
|
||||
- Robin
|
||||
|
||||
Keys
|
||||
----
|
||||
Keys are similar to Windows-based editors:
|
||||
|
||||
Tab: 1 to 4 spaces (to next tab stop)
|
||||
Cursor movement: Arrow keys
|
||||
Beginning of line: Home
|
||||
End of line: End
|
||||
Beginning of buffer: Control-Home
|
||||
End of the buffer: Control-End
|
||||
Select text: Hold down Shift while moving the cursor
|
||||
Copy: Shift-Insert, Control-C
|
||||
Cut: Shift-Delete, Control-X
|
||||
Paste: Control-Insert, Control-V
|
||||
|
||||
How to use it
|
||||
-------------
|
||||
The demo code (demo/wxEditor.py) shows how to use it as a simple text
|
||||
box. Use the SetText() and GetText() methods to set or get text from
|
||||
the component; these both return a list of strings.
|
||||
|
||||
The samples/FrogEdit directory has an example of a simple text editor
|
||||
application that uses the wxEditor component.
|
||||
|
||||
Subclassing
|
||||
-----------
|
||||
To add or change functionality, you can subclass this
|
||||
component. One example of this might be to change the key
|
||||
Alt key commands. In that case you would (for example) override the
|
||||
SetAltFuncs() method.
|
||||
|
||||
History
|
||||
-------
|
||||
The original author of this component was Dirk Holtwic. It originally
|
||||
had limited support for syntax highlighting, but was not a usable text
|
||||
editor, as it didn't implement select (with keys or mouse), or any of
|
||||
the usual key sequences you'd expect in an editor. Robin Dunn did some
|
||||
refactoring work to make it more usable. Steve Howell and Adam Feuer
|
||||
did a lot of refactoring, and added some functionality, including
|
||||
keyboard and mouse select, properly working scrollbars, and
|
||||
overridable keys. Adam and Steve also removed support for
|
||||
syntax-highlighting while refactoring the code.
|
||||
|
||||
To do
|
||||
-----
|
||||
Alt/Ctrl Arrow keys move by word
|
||||
Descriptive help text for keys
|
||||
Speed improvements
|
||||
Different fonts/colors
|
||||
|
||||
|
||||
Authors
|
||||
-------
|
||||
Steve Howell, Adam Feuer, Dirk Holtwic, Robin Dunn
|
||||
|
||||
|
||||
Contact
|
||||
-------
|
||||
You can find the latest code for wxEditor here:
|
||||
http://www.pobox.com/~adamf/software/
|
||||
|
||||
We're not actively maintaining this code, but we can answer
|
||||
questions about it. You can email us at:
|
||||
|
||||
Adam Feuer <adamf at pobox dot com>
|
||||
Steve Howell <showell at zipcon dot net>
|
||||
|
||||
29 November 2001
|
||||
|
@@ -15,4 +15,3 @@
|
||||
|
||||
# import the main classes into the package namespace.
|
||||
from editor import wxEditor
|
||||
from py_editor import wxPyEditor
|
||||
|
File diff suppressed because it is too large
Load Diff
20
wxPython/wxPython/lib/editor/images.py
Normal file
20
wxPython/wxPython/lib/editor/images.py
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
# images converted with wxPython's img2py.py tool
|
||||
|
||||
from wxPython.wx import wxBitmapFromXPMData, wxImageFromBitmap
|
||||
import cPickle, zlib
|
||||
|
||||
##----------- Common Functions
|
||||
|
||||
def GetBitmap(ImageData):
|
||||
return wxBitmapFromXPMData(ImageData)
|
||||
|
||||
def GetImage(ImageData):
|
||||
return wxImageFromBitmap(GetBitmap(ImageData))
|
||||
|
||||
##----------- Image Data
|
||||
|
||||
EofImageData = cPickle.loads(zlib.decompress(
|
||||
'x\xda\xd3\xc8)0\xe4\nV7W0W0R0T\xe7J\x0cV\xd7SHVp\xcaIL\xce\x06\xf3\x14\x80<\
|
||||
\xbf\xfc\xbcT(GA\x0f\x88\xa1l===\x18[\x0f\x04 l=\x08\xc0\x10GQ\x0f7G\x0f\x00\
|
||||
\xec\xa2\x19\x96' ))
|
@@ -1,211 +0,0 @@
|
||||
# (C)opyright by Dirk Holtwick, 1999
|
||||
# ----------------------------------
|
||||
# holtwick@spirito.de
|
||||
# http://www.spirito.de/pyde
|
||||
|
||||
from editor import *
|
||||
from string import *
|
||||
from keyword import *
|
||||
from tokenizer import *
|
||||
|
||||
"""
|
||||
This module will be loaded by the main
|
||||
window. It implements some methods that
|
||||
are typical for Python sources.
|
||||
"""
|
||||
|
||||
class wxPyEditor(wxEditor):
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __init__(self, parent, id,
|
||||
pos=wxDefaultPosition, size=wxDefaultSize, style=0):
|
||||
wxEditor.__init__(self, parent, id, pos, size, style)
|
||||
self.SetFontTab([
|
||||
wxNamedColour('black'),
|
||||
wxNamedColour('blue'),
|
||||
wxNamedColour('red'),
|
||||
wxNamedColour('darkgreen'),
|
||||
wxNamedColour('brown')
|
||||
])
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnUpdateHighlight(self, line = -1):
|
||||
if line>=0:
|
||||
t = self.text[line].text
|
||||
syn = []
|
||||
|
||||
toks = Tokenizer(t).tokens()
|
||||
for type, string, begin, end in toks:
|
||||
if type == "KEY":
|
||||
syn.append((begin, 1))
|
||||
syn.append((end, 0))
|
||||
elif type == "COMMENT":
|
||||
syn.append((begin, 2))
|
||||
elif type == "STRING":
|
||||
syn.append((begin, 3))
|
||||
syn.append((end, 0))
|
||||
elif type == "NUMBER":
|
||||
syn.append((begin, 4))
|
||||
syn.append((end, 0))
|
||||
elif type == "NAME":
|
||||
if string=="self":
|
||||
syn.append((begin, 4))
|
||||
syn.append((end, 0))
|
||||
else:
|
||||
pass
|
||||
self.text[line].syntax = syn
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnUpdateSyntax(self, line = -1):
|
||||
if line>=0:
|
||||
"""
|
||||
tx, syn, m = self.text[line]
|
||||
pre = 0
|
||||
for i in range(0,len(tx)):
|
||||
if tx[i] != " ":
|
||||
pre = i
|
||||
break
|
||||
t = tx[pre:]
|
||||
|
||||
t = Tokenizer(t).line()
|
||||
|
||||
t = tx[:pre] + t
|
||||
self.text[line] = t, syn, m
|
||||
"""
|
||||
self.OnUpdateHighlight(line)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnTabulator(self, event):
|
||||
add = +1
|
||||
if event.ShiftDown():
|
||||
add = -1
|
||||
t = self.GetTextLine(self.cy)
|
||||
if strip(t):
|
||||
indent = self.GetIndent(t)
|
||||
# print indent
|
||||
t = t[indent:]
|
||||
tabs = indent / self.tabsize
|
||||
# for i in range(0,tabs+add):
|
||||
t = (" " * 4 * (tabs+add)) + t
|
||||
self.SetTextLine(self.cy, t)
|
||||
elif add>0:
|
||||
self.InsertText(" ")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def FindQuote(self, lineno, quote_type='"""', direction=1):
|
||||
"""find line containing the matching quote"""
|
||||
l =lineno +direction
|
||||
while (l < len(self.text)-1) and (l >= 0):
|
||||
if find(self.text[l].text, quote_type) >=0: return l
|
||||
l =l +direction
|
||||
return None
|
||||
|
||||
def FindNextLine(self, lineno, direction=1):
|
||||
"""get the next line of code (skipping comment lines and empty lines)"""
|
||||
l =lineno +direction
|
||||
while (l < len(self.text)-1) and (l >= 0):
|
||||
str =lstrip(self.text[l].text)
|
||||
if (len(str) >0) and (str[0] !="#"): return l
|
||||
l =l +direction
|
||||
return None
|
||||
|
||||
def Fold(self):
|
||||
l = self.GetLine(self.cy)
|
||||
line = self.text[l]
|
||||
t = line.text
|
||||
|
||||
# fold ...
|
||||
if line.editable:
|
||||
|
||||
# 3*quotes
|
||||
qpos =find(t, '"""')
|
||||
if qpos >=0: qtype ='"""'
|
||||
else:
|
||||
qpos =find(t, "'''")
|
||||
if qpos >=0: qtype ="'''"
|
||||
|
||||
if (qpos >=0) and (find(t[qpos+3:], qtype) <0):
|
||||
closing_quote =self.FindQuote(l, qtype)
|
||||
if closing_quote !=None:
|
||||
line.editable = not line.editable
|
||||
l =l +1
|
||||
while l <= closing_quote:
|
||||
self.text[l].visible =self.text[l].visible +1
|
||||
l =l +1
|
||||
|
||||
else: # try normal fold on leading whitespace
|
||||
lim = self.GetIndent(t)
|
||||
lnext =self.FindNextLine(l)
|
||||
if (lnext !=None) \
|
||||
and (self.GetIndent(self.text[lnext].text) >lim):
|
||||
line.editable =FALSE
|
||||
lstart =l +1
|
||||
l =self.FindNextLine(l)
|
||||
while (l !=None) \
|
||||
and (self.GetIndent(self.text[l].text) >lim):
|
||||
l =self.FindNextLine(l)
|
||||
if l ==None:
|
||||
# fold till the end
|
||||
l =len(self.text)
|
||||
for line in self.text[lstart:l]:
|
||||
line.visible =line.visible +1
|
||||
|
||||
# ... or unfold
|
||||
else:
|
||||
lim = line.visible + 1
|
||||
line.editable = not line.editable
|
||||
|
||||
l = l + 1
|
||||
line = self.text[l]
|
||||
while (l < (len(self.text) -1)) and (line.visible>=lim):
|
||||
line.visible = line.visible - 1
|
||||
l = l + 1
|
||||
line = self.text[l]
|
||||
|
||||
def FoldAll(self):
|
||||
self.CalcLines()
|
||||
self.cx = 0
|
||||
self.cy = len(self.lines) - 1
|
||||
prev_indent =0
|
||||
# following loop is exited in two cases:
|
||||
# when self.cy becomes 0 (topmost level is not folded by FoldAll)
|
||||
# or when FindNextLine() returns None (all remaining lines till
|
||||
# the beginning of the text are empty or comments)
|
||||
while self.cy:
|
||||
t = self.GetTextLine(self.cy)
|
||||
# indent-based folding
|
||||
indent =self.GetIndent(t)
|
||||
if indent <prev_indent:
|
||||
self.Fold()
|
||||
prev_indent =indent
|
||||
# triple-quote folding
|
||||
qpos =find(t, '"""')
|
||||
if qpos >=0: qtype ='"""'
|
||||
else:
|
||||
qpos =find(t, "'''")
|
||||
if qpos >=0: qtype ="'''"
|
||||
if (qpos >=0) and (find(t[qpos+3:], qtype) <0):
|
||||
closing_quote =self.FindQuote(self.cy, qtype, -1)
|
||||
if closing_quote !=None:
|
||||
# XXX potential bug: unmatched triple quotes
|
||||
self.cy =closing_quote
|
||||
self.Fold()
|
||||
self.cy =self.FindNextLine(self.cy, -1)
|
||||
if self.cy ==None: self.cy =0
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnFold(self):
|
||||
self.Fold()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnInit(self):
|
||||
#self.FoldAll()
|
||||
pass
|
||||
|
42
wxPython/wxPython/lib/editor/selection.py
Normal file
42
wxPython/wxPython/lib/editor/selection.py
Normal file
@@ -0,0 +1,42 @@
|
||||
TRUE = 1
|
||||
FALSE = 0
|
||||
|
||||
def RestOfLine(sx, width, data, bool):
|
||||
if len(data) == 0 and sx == 0:
|
||||
return [('', bool)]
|
||||
if sx >= len(data):
|
||||
return []
|
||||
return [(data[sx:sx+width], bool)]
|
||||
|
||||
def Selection(SelectBegin,SelectEnd, sx, width, line, data):
|
||||
if SelectEnd is None or SelectBegin is None:
|
||||
return RestOfLine(sx, width, data, FALSE)
|
||||
(bRow, bCol) = SelectBegin
|
||||
(eRow, eCol) = SelectEnd
|
||||
if (eRow < bRow):
|
||||
(bRow, bCol) = SelectEnd
|
||||
(eRow, eCol) = SelectBegin
|
||||
if (line < bRow or eRow < line):
|
||||
return RestOfLine(sx, width, data, FALSE)
|
||||
if (bRow < line and line < eRow):
|
||||
return RestOfLine(sx, width, data, TRUE)
|
||||
if (bRow == eRow) and (eCol < bCol):
|
||||
(bCol, eCol) = (eCol, bCol)
|
||||
# selection either starts or ends on this line
|
||||
end = min(sx+width, len(data))
|
||||
if (bRow < line):
|
||||
bCol = 0
|
||||
if (line < eRow):
|
||||
eCol = end
|
||||
pieces = []
|
||||
if (sx < bCol):
|
||||
if bCol <= end:
|
||||
pieces += [(data[sx:bCol], FALSE)]
|
||||
else:
|
||||
return [(data[sx:end], FALSE)]
|
||||
pieces += [(data[max(bCol,sx):min(eCol,end)], TRUE)]
|
||||
if (eCol < end):
|
||||
pieces += [(data[eCol:end], FALSE)]
|
||||
return pieces
|
||||
|
||||
|
@@ -1,60 +0,0 @@
|
||||
from tokenize import *
|
||||
from keyword import *
|
||||
from string import *
|
||||
|
||||
class Tokenizer:
|
||||
"""
|
||||
Simple class to create a list of token-tuples like:
|
||||
|
||||
(type, string, first, last)
|
||||
|
||||
Example:
|
||||
t = Tokenizer('def hallo(du): # juchee')
|
||||
print t.tokens()
|
||||
"""
|
||||
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.toks = []
|
||||
try:
|
||||
tokenize(self.readline, self.get)
|
||||
except TokenError:
|
||||
pass
|
||||
|
||||
def tokens(self):
|
||||
return self.toks
|
||||
|
||||
def get(self, type, string, begin, end, l):
|
||||
#print begin,end
|
||||
h1, b = begin
|
||||
h2, e = end
|
||||
tname = tok_name[type]
|
||||
if iskeyword(string):
|
||||
tname = "KEY"
|
||||
self.toks.append( (tname, string, b, e) )
|
||||
|
||||
def readline(self):
|
||||
t = self.text
|
||||
self.text = ""
|
||||
return t
|
||||
|
||||
def line(self):
|
||||
pre = ""
|
||||
out = ""
|
||||
for type, string, begin, end in self.toks:
|
||||
if (pre in ["NAME","KEY"]) and (not string in [".",",","("]):
|
||||
out = out + " "
|
||||
|
||||
if type in ["NAME","KEY"]:
|
||||
out = out + string
|
||||
elif type=="OP":
|
||||
if string in [",",":"]:
|
||||
out = out + string + " "
|
||||
else:
|
||||
out = out + string
|
||||
else:
|
||||
out = out + string
|
||||
pre = type
|
||||
return out
|
||||
|
||||
|
Reference in New Issue
Block a user