parent
c17738be12
commit
b1322c70ab
517
buffer.py
517
buffer.py
|
@ -1,517 +0,0 @@
|
||||||
import md5, os, sets, shutil
|
|
||||||
import aes, point, method, regexjgejgew
|
|
||||||
|
|
||||||
# set this to 0 or less to have infinite undo/redo
|
|
||||||
REDO_STACK_LIMIT = 1024
|
|
||||||
UNDO_STACK_LIMIT = 1024
|
|
||||||
|
|
||||||
# abstract class
|
|
||||||
class Buffer(object):
|
|
||||||
def __init__(self, nl='\n'):
|
|
||||||
self.lines = [""]
|
|
||||||
self.windows = {}
|
|
||||||
self.undo_stack = []
|
|
||||||
self.redo_stack = []
|
|
||||||
assert nl in ('\n', '\r', '\r\n'), "Invalid line ending"
|
|
||||||
self.nl = nl
|
|
||||||
self.modified = False
|
|
||||||
pass
|
|
||||||
|
|
||||||
def num_chars(self):
|
|
||||||
n = 0
|
|
||||||
for line in self.lines[:-1]:
|
|
||||||
n += len(line) + 1
|
|
||||||
n += len(self.lines[-1])
|
|
||||||
return n
|
|
||||||
|
|
||||||
# basic file operation stuff
|
|
||||||
def _open_file_r(self, path):
|
|
||||||
path = os.path.realpath(path)
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
raise Exception, "Path '%s' does not exist" % (path)
|
|
||||||
if not os.access(path, os.R_OK):
|
|
||||||
raise Exception, "Path '%s' cannot be read" % (path)
|
|
||||||
f = open(path, 'r')
|
|
||||||
return f
|
|
||||||
def _open_file_w(self, path):
|
|
||||||
if os.path.isfile(path):
|
|
||||||
raise Exception, "Path '%s' already exists" % (path)
|
|
||||||
d = os.path.dirname(path)
|
|
||||||
if not os.access(d, os.R_OK):
|
|
||||||
raise Exception, "Dir '%s' cannot be read" % (path)
|
|
||||||
if not os.access(d, os.W_OK):
|
|
||||||
raise Exception, "Dir '%s' cannot be written" % (path)
|
|
||||||
f = open(path, 'w')
|
|
||||||
return f
|
|
||||||
def _temp_path(self, path):
|
|
||||||
(dirname, basename) = os.path.split(path)
|
|
||||||
return os.path.join(dirname, ".__%s__pmacs" % (basename))
|
|
||||||
|
|
||||||
# undo/redo stack
|
|
||||||
def add_to_stack(self, move, stack="undo"):
|
|
||||||
if stack == "undo":
|
|
||||||
self.redo_stack = []
|
|
||||||
self.undo_stack.append(move)
|
|
||||||
if UNDO_STACK_LIMIT > 0:
|
|
||||||
while len(self.undo_stack) > UNDO_STACK_LIMIT:
|
|
||||||
self.undo_stack.pop(0)
|
|
||||||
elif stack == "redo":
|
|
||||||
self.redo_stack.append(move)
|
|
||||||
if REDO_STACK_LIMIT > 0:
|
|
||||||
while len(self.redo_stack) > REDO_STACK_LIMIT:
|
|
||||||
self.redo_stack.pop(0)
|
|
||||||
elif stack == "none":
|
|
||||||
self.undo_stack.append(move)
|
|
||||||
if UNDO_STACK_LIMIT > 0:
|
|
||||||
while len(self.undo_stack) > UNDO_STACK_LIMIT:
|
|
||||||
self.undo_stack.pop(0)
|
|
||||||
else:
|
|
||||||
raise Exception, "Invalid stack to add to: %s" % (stack)
|
|
||||||
def restore_move(self, move, stack="redo"):
|
|
||||||
if move[0] == "insert":
|
|
||||||
self.insert_string(move[1], move[2], stack=stack)
|
|
||||||
elif move[0] == "delete":
|
|
||||||
self.delete_string(move[1], move[2], stack=stack)
|
|
||||||
else:
|
|
||||||
raise Exception, "Invalid undo move type: '%s'" % (move[0])
|
|
||||||
def undo(self):
|
|
||||||
if len(self.undo_stack):
|
|
||||||
move = self.undo_stack.pop(-1)
|
|
||||||
self.restore_move(move, stack="redo")
|
|
||||||
else:
|
|
||||||
raise Exception, "Nothing to Undo!"
|
|
||||||
def redo(self):
|
|
||||||
if len(self.redo_stack):
|
|
||||||
move = self.redo_stack.pop(-1)
|
|
||||||
self.restore_move(move, stack="none")
|
|
||||||
else:
|
|
||||||
raise Exception, "Nothing to Redo!"
|
|
||||||
|
|
||||||
# window-buffer communication
|
|
||||||
def add_window(self, w, name):
|
|
||||||
assert name not in self.windows, "window %r already exists" % name
|
|
||||||
self.windows[name] = w
|
|
||||||
def remove_window(self, name):
|
|
||||||
del self.windows[name]
|
|
||||||
def _region_added(self, p, xdiff, ydiff, str=None, stack="undo"):
|
|
||||||
y = p.y + ydiff
|
|
||||||
if ydiff == 0:
|
|
||||||
x = p.x + xdiff
|
|
||||||
else:
|
|
||||||
x = xdiff
|
|
||||||
p2 = point.Point(x, y)
|
|
||||||
move = ["delete", p, p2, str]
|
|
||||||
self.add_to_stack(move, stack)
|
|
||||||
for w in self.windows.itervalues():
|
|
||||||
w._region_added(p, xdiff, ydiff, str)
|
|
||||||
def _region_removed(self, p1, p2, str=None, stack="undo"):
|
|
||||||
move = ["insert", p1, str]
|
|
||||||
self.add_to_stack(move, stack)
|
|
||||||
for w in self.windows.itervalues():
|
|
||||||
w._region_removed(p1, p2, str)
|
|
||||||
def has_window(self, name):
|
|
||||||
return name in self.windows
|
|
||||||
def get_window(self, name):
|
|
||||||
if name in self.windows:
|
|
||||||
return self.windows[name]
|
|
||||||
else:
|
|
||||||
raise Exception, "uh oh %r" % self.windows
|
|
||||||
|
|
||||||
# internal validation
|
|
||||||
def _validate_point(self, p):
|
|
||||||
self._validate_xy(p.x, p.y)
|
|
||||||
def _validate_xy(self, x, y):
|
|
||||||
assert y >= 0 and y < len(self.lines), \
|
|
||||||
"xy1: %d >= 0 and %d < %d" % (y, y, len(self.lines))
|
|
||||||
assert x >= 0 and x <= len(self.lines[y]), \
|
|
||||||
"xy2: %d >= 0 and %d <= %d" % (x, x, len(self.lines[y]))
|
|
||||||
def _validate_y(self, y):
|
|
||||||
assert y >= 0 and y < len(self.lines), \
|
|
||||||
"y: %d >= 0 and %d < %d" % (y, y, len(self.lines))
|
|
||||||
|
|
||||||
# internal
|
|
||||||
def make_string(self, start=0, end=None, nl='\n'):
|
|
||||||
assert end is None or start < end
|
|
||||||
if start == 0 and end is None:
|
|
||||||
return nl.join(self.lines)
|
|
||||||
else:
|
|
||||||
lines = []
|
|
||||||
i = 0
|
|
||||||
offset = 0
|
|
||||||
while i < len(self.lines):
|
|
||||||
l = self.lines[i]
|
|
||||||
if offset + len(l) < start:
|
|
||||||
pass
|
|
||||||
elif offset <= start:
|
|
||||||
if end is None or offset + len(l) < end:
|
|
||||||
lines.append(l[start - offset:])
|
|
||||||
else:
|
|
||||||
lines.append(l[start - offset:end - offset])
|
|
||||||
elif end is None or offset + len(l) < end:
|
|
||||||
lines.append(l)
|
|
||||||
else:
|
|
||||||
lines.append(l[:end])
|
|
||||||
offset += len(l) + 1
|
|
||||||
i += 1
|
|
||||||
return nl.join(lines)
|
|
||||||
|
|
||||||
# methods to be overridden by subclasses
|
|
||||||
def name(self):
|
|
||||||
return "Generic"
|
|
||||||
def close(self):
|
|
||||||
pass
|
|
||||||
def open(self):
|
|
||||||
pass
|
|
||||||
def changed(self):
|
|
||||||
return self.modified
|
|
||||||
def reload(self):
|
|
||||||
raise Exception, "%s reload: Unimplemented" % (self.name())
|
|
||||||
def save_as(self, path, force=False):
|
|
||||||
# check to see if the path exists, and if we're prepared to overwrite it
|
|
||||||
# if yes to both, get its mode so we can preserve the path's permissions
|
|
||||||
mode = None
|
|
||||||
if os.path.exists(path):
|
|
||||||
if force:
|
|
||||||
mode = os.stat(self.path)[0]
|
|
||||||
else:
|
|
||||||
raise Exception, "oh no! %r already exists" % path
|
|
||||||
|
|
||||||
# create the string that we're going to write into the file
|
|
||||||
data = self.write_filter(self.make_string(nl=self.nl))
|
|
||||||
|
|
||||||
# create a safe temporary path to write to, and write out data to it
|
|
||||||
temp_path = self._temp_path()
|
|
||||||
f2 = self._open_file_w(temp_path)
|
|
||||||
f2.write(data)
|
|
||||||
f2.close()
|
|
||||||
|
|
||||||
# move the temporary file to the actual path; maybe change permissions
|
|
||||||
shutil.move(temp_path, path)
|
|
||||||
if mode:
|
|
||||||
os.chmod(path, mode)
|
|
||||||
|
|
||||||
# the file has not been modified now
|
|
||||||
self.modified = False
|
|
||||||
def readonly(self):
|
|
||||||
return False
|
|
||||||
def read_filter(self, data):
|
|
||||||
return data
|
|
||||||
def write_filter(self, data):
|
|
||||||
return data
|
|
||||||
|
|
||||||
# point retrieval
|
|
||||||
def get_buffer_start(self):
|
|
||||||
return point.Point(0, 0, "logical")
|
|
||||||
def get_buffer_end(self):
|
|
||||||
y = len(self.lines) - 1
|
|
||||||
return point.Point(len(self.lines[y]), y, "logical")
|
|
||||||
def get_line_start(self, y):
|
|
||||||
self._validate_y(y)
|
|
||||||
return Point(0, y, "logical")
|
|
||||||
def get_line_end(self, y):
|
|
||||||
self._validate_y(y)
|
|
||||||
return Point(len(self.lines[y]), y, "logical")
|
|
||||||
def get_point_offset(self, p):
|
|
||||||
'''used to find positions in data string'''
|
|
||||||
self._validate_point(p)
|
|
||||||
offset = 0
|
|
||||||
for line in self.lines[:p.y]:
|
|
||||||
offset += len(line) + 1
|
|
||||||
offset += p.x
|
|
||||||
return offset
|
|
||||||
def get_offset_point(self, offset):
|
|
||||||
i = 0
|
|
||||||
y = 0
|
|
||||||
for line in self.lines:
|
|
||||||
if i + len(line) + 1 > offset:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
i += len(line) + 1
|
|
||||||
y += 1
|
|
||||||
return point.Point(offset - i, y)
|
|
||||||
|
|
||||||
# data retrieval
|
|
||||||
def get_character(self, p):
|
|
||||||
self._validate_point(p)
|
|
||||||
if p.x == len(self.lines[p.y]):
|
|
||||||
if p1.y < len(self.lines):
|
|
||||||
return "\n"
|
|
||||||
else:
|
|
||||||
return ""
|
|
||||||
else:
|
|
||||||
return self.lines[p.y][p.x]
|
|
||||||
def get_substring(self, p1, p2):
|
|
||||||
self._validate_point(p1)
|
|
||||||
self._validate_point(p2)
|
|
||||||
assert p1 <= p2, "p1.x (%d) > p2.x (%d)" % (p1.x, p2.x)
|
|
||||||
if p1 == p2:
|
|
||||||
return ""
|
|
||||||
elif p1.y == p2.y:
|
|
||||||
return self.lines[p1.y][p1.x:p2.x]
|
|
||||||
else:
|
|
||||||
if p1.x == 0:
|
|
||||||
text = "%s\n" % (self.lines[p1.y])
|
|
||||||
else:
|
|
||||||
text = "%s\n" % (self.lines[p1.y][p1.x:])
|
|
||||||
for i in range(p1.y+1, p2.y):
|
|
||||||
text = "%s%s\n" % (text, self.lines[i])
|
|
||||||
if p2.x > 0:
|
|
||||||
text = "%s%s" % (text, self.lines[p2.y][:p2.x])
|
|
||||||
return text
|
|
||||||
|
|
||||||
def set_data(self, d, force=False):
|
|
||||||
if not force and self.readonly():
|
|
||||||
raise Exception, "set_data: buffer is readonly"
|
|
||||||
start = self.get_buffer_start()
|
|
||||||
end = self.get_buffer_end()
|
|
||||||
self.delete_string(start, end, force=force)
|
|
||||||
self.insert_string(start, d, force=force)
|
|
||||||
self.modified = True
|
|
||||||
|
|
||||||
# insertion into buffer
|
|
||||||
def insert_string(self, p, s, stack="undo", force=False):
|
|
||||||
if not force:
|
|
||||||
assert not self.readonly(), "insert_string: buffer is read-only"
|
|
||||||
new_lines = s.split("\n")
|
|
||||||
if len(new_lines) > 1:
|
|
||||||
xdiff = len(new_lines[-1]) - p.x
|
|
||||||
else:
|
|
||||||
xdiff = len(new_lines[-1])
|
|
||||||
ydiff = len(new_lines) - 1
|
|
||||||
new_lines[0] = self.lines[p.y][:p.x] + new_lines[0]
|
|
||||||
new_lines[-1] = new_lines[-1] + self.lines[p.y][p.x:]
|
|
||||||
self.lines[p.y:p.y+1] = new_lines
|
|
||||||
self._region_added(p, xdiff, ydiff, s, stack)
|
|
||||||
self.modified = True
|
|
||||||
|
|
||||||
# deletion from buffer
|
|
||||||
def delete_character(self, p, stack="undo", force=False):
|
|
||||||
"""delete character at (x,y) from the buffer"""
|
|
||||||
if not force:
|
|
||||||
assert not self.readonly(), "delete_character: buffer is read-only"
|
|
||||||
self._validate_point(p)
|
|
||||||
x, y = p.x, p.y
|
|
||||||
if p.x < len(self.lines[p.y]):
|
|
||||||
s = self.lines[y][x]
|
|
||||||
self.lines[y] = "%s%s" % (self.lines[y][:x], self.lines[y][x+1:])
|
|
||||||
self._region_removed(p, p.offset(1, 0, "logical"), str=s, stack=stack)
|
|
||||||
elif p.y < len(self.lines) - 1:
|
|
||||||
s = "\n"
|
|
||||||
self.lines[y:y+2] = ["%s%s" % (self.lines[y], self.lines[y+1])]
|
|
||||||
self._region_removed(p, point.Point(0, p.y + 1, "logical"), str="\n", stack=stack)
|
|
||||||
self.modified = True
|
|
||||||
def delete_string(self, p1, p2, stack="undo", force=False):
|
|
||||||
"""delete characters from p1 up to p2 from the buffer"""
|
|
||||||
if not force:
|
|
||||||
assert not self.readonly(), "delete_string: buffer is read-only"
|
|
||||||
self._validate_xy(p1.x, p1.y)
|
|
||||||
self._validate_xy(p2.x, p2.y)
|
|
||||||
if p1 == p2:
|
|
||||||
return
|
|
||||||
assert p1 < p2, "p1 %r > p2 %r" % (p1, p2)
|
|
||||||
|
|
||||||
s = self.get_substring(p1, p2)
|
|
||||||
|
|
||||||
if p1.y < p2.y:
|
|
||||||
start_line = self.lines[p1.y][:p1.x]
|
|
||||||
end_line = self.lines[p2.y][p2.x:]
|
|
||||||
self.lines[p1.y:p2.y+1] = ["%s%s" % (start_line, end_line)]
|
|
||||||
elif p1.y == p2.y:
|
|
||||||
if p1.x == p2.x - 1:
|
|
||||||
s = self.lines[p1.y][p1.x]
|
|
||||||
self.delete_character(p1, stack=stack)
|
|
||||||
# make sure we don't call _region_removed twice, so return
|
|
||||||
return
|
|
||||||
elif p1.x < p2.x:
|
|
||||||
s = self.lines[p1.y][p1.x:p2.x]
|
|
||||||
self.lines[p1.y] = "%s%s" % (self.lines[p1.y][:p1.x],
|
|
||||||
self.lines[p1.y][p2.x:])
|
|
||||||
else:
|
|
||||||
raise Exception, "p1.x (%d) >= p2.x (%d)" % (p1.x, p2.x)
|
|
||||||
else:
|
|
||||||
raise Exception, "p1.y (%d) > p2.y (%d)" % (p1.y, p2.y)
|
|
||||||
|
|
||||||
self._region_removed(p1, p2, str=s, stack=stack)
|
|
||||||
self.modified = True
|
|
||||||
|
|
||||||
# random
|
|
||||||
def count_leading_whitespace(self, y):
|
|
||||||
line = self.lines[y]
|
|
||||||
m = regex.leading_whitespace.match(line)
|
|
||||||
if m:
|
|
||||||
return m.end()
|
|
||||||
else:
|
|
||||||
# should not happen
|
|
||||||
raise Exception, "iiiijjjj"
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# scratch is a singleton
|
|
||||||
scratch = None
|
|
||||||
class ScratchBuffer(Buffer):
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
global scratch
|
|
||||||
if scratch is None:
|
|
||||||
scratch = object.__new__(ScratchBuffer, *args, **kwargs)
|
|
||||||
return scratch
|
|
||||||
def name(self):
|
|
||||||
return "*Scratch*"
|
|
||||||
def close(self):
|
|
||||||
global scratch
|
|
||||||
scratch = None
|
|
||||||
|
|
||||||
class DataBuffer(Buffer):
|
|
||||||
def __init__(self, name, data, nl='\n'):
|
|
||||||
Buffer.__init__(self, nl)
|
|
||||||
self._name = name
|
|
||||||
self.lines = data.split("\n")
|
|
||||||
def name(self):
|
|
||||||
return self._name
|
|
||||||
def close(self):
|
|
||||||
pass
|
|
||||||
def readonly(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# console is another singleton
|
|
||||||
console = None
|
|
||||||
class ConsoleBuffer(Buffer):
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
global console
|
|
||||||
if console is None:
|
|
||||||
b = object.__new__(ConsoleBuffer, *args, **kwargs)
|
|
||||||
console = b
|
|
||||||
return console
|
|
||||||
def __init__(self, nl='\n'):
|
|
||||||
Buffer.__init__(self, nl)
|
|
||||||
lines = ['Python Console\n',
|
|
||||||
"Evaluate python expressions in the editor's context (self)\n",
|
|
||||||
'Press Control-] to exit\n',
|
|
||||||
'\n']
|
|
||||||
console.set_data(''.join(lines), force=True)
|
|
||||||
def name(self):
|
|
||||||
return '*Console*'
|
|
||||||
def changed(self):
|
|
||||||
return False
|
|
||||||
def close(self):
|
|
||||||
global console
|
|
||||||
console = None
|
|
||||||
def readonly(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
class FileBuffer(Buffer):
|
|
||||||
def __init__(self, path, nl='\n', name=None):
|
|
||||||
'''fb = FileBuffer(path)'''
|
|
||||||
Buffer.__init__(self, nl)
|
|
||||||
self.path = os.path.realpath(path)
|
|
||||||
self.checksum = None
|
|
||||||
if name is None:
|
|
||||||
self._name = os.path.basename(self.path)
|
|
||||||
else:
|
|
||||||
self._name = name
|
|
||||||
if os.path.exists(self.path) and not os.access(self.path, os.W_OK):
|
|
||||||
self._readonly = True
|
|
||||||
else:
|
|
||||||
self._readonly = False
|
|
||||||
def readonly(self):
|
|
||||||
return self._readonly
|
|
||||||
|
|
||||||
def _open_file_r(self, path=None):
|
|
||||||
if path is None:
|
|
||||||
path = self.path
|
|
||||||
path = os.path.realpath(path)
|
|
||||||
self.path = path
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
raise Exception, "Path '%s' does not exist" % (path)
|
|
||||||
if not os.access(path, os.R_OK):
|
|
||||||
raise Exception, "Path '%s' cannot be read" % (path)
|
|
||||||
f = open(path, 'r')
|
|
||||||
return f
|
|
||||||
def _open_file_w(self, path=None):
|
|
||||||
if path is None:
|
|
||||||
path = self.path
|
|
||||||
if os.path.isfile(path):
|
|
||||||
raise Exception, "Path '%s' already exists" % (path)
|
|
||||||
d = os.path.dirname(path)
|
|
||||||
if not os.access(d, os.R_OK):
|
|
||||||
raise Exception, "Dir '%s' cannot be read" % (path)
|
|
||||||
if not os.access(d, os.W_OK):
|
|
||||||
raise Exception, "Dir '%s' cannot be written" % (path)
|
|
||||||
f = open(path, 'w')
|
|
||||||
return f
|
|
||||||
def _temp_path(self, path=None):
|
|
||||||
if path is None:
|
|
||||||
path = self.path
|
|
||||||
(dirname, basename) = os.path.split(path)
|
|
||||||
return os.path.join(dirname, ".__%s__pmacs" % (basename))
|
|
||||||
|
|
||||||
# methods for dealing with the underlying resource, etc.
|
|
||||||
def name(self):
|
|
||||||
#return self.path
|
|
||||||
return self._name
|
|
||||||
def path_exists(self):
|
|
||||||
return os.path.exists(self.path)
|
|
||||||
def store_checksum(self, data):
|
|
||||||
self.checksum = md5.new(data)
|
|
||||||
def read(self):
|
|
||||||
if self.path_exists():
|
|
||||||
f = self._open_file_r()
|
|
||||||
data = f.read()
|
|
||||||
f.close()
|
|
||||||
self.store_checksum(data)
|
|
||||||
else:
|
|
||||||
data = ''
|
|
||||||
data = self.read_filter(data)
|
|
||||||
#FIXME: this is horrible...but maybe not as horrible as using tabs??
|
|
||||||
data = data.replace("\t", " ")
|
|
||||||
return data
|
|
||||||
def open(self):
|
|
||||||
data = self.read()
|
|
||||||
self.lines = data.split(self.nl)
|
|
||||||
def reload(self):
|
|
||||||
self.open()
|
|
||||||
def changed_on_disk(self):
|
|
||||||
assert self.checksum is not None
|
|
||||||
f = open(self.path)
|
|
||||||
data = f.read()
|
|
||||||
f.close()
|
|
||||||
m = md5.new(data)
|
|
||||||
return self.checksum.digest() != m.digest()
|
|
||||||
def save(self, force=False):
|
|
||||||
if self.readonly():
|
|
||||||
raise Exception, "can't save a read-only file"
|
|
||||||
|
|
||||||
if self.checksum is not None and force is False:
|
|
||||||
# the file already existed and we took a checksum so make sure it's
|
|
||||||
# still the same right now
|
|
||||||
if not self.path_exists():
|
|
||||||
raise Exception, "oh no! %r disappeared!" % self.path
|
|
||||||
if self.changed_on_disk():
|
|
||||||
raise Exception, "oh no! %r has changed on-disk!" % self.path
|
|
||||||
|
|
||||||
temp_path = self._temp_path()
|
|
||||||
data = self.make_string(nl=self.nl)
|
|
||||||
data = self.write_filter(data)
|
|
||||||
|
|
||||||
f2 = self._open_file_w(temp_path)
|
|
||||||
f2.write(data)
|
|
||||||
f2.close()
|
|
||||||
|
|
||||||
if self.path_exists():
|
|
||||||
mode = os.stat(self.path)[0]
|
|
||||||
os.chmod(temp_path, mode)
|
|
||||||
|
|
||||||
shutil.move(temp_path, self.path)
|
|
||||||
self.store_checksum(data)
|
|
||||||
self.modified = False
|
|
||||||
def save_as(self, path):
|
|
||||||
self.path = path
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
class AesBuffer(FileBuffer):
|
|
||||||
def __init__(self, path, password, nl='\n'):
|
|
||||||
'''fb = FileBuffer(path)'''
|
|
||||||
FileBuffer.__init__(self, path, nl)
|
|
||||||
self.password = password
|
|
||||||
def read_filter(self, data):
|
|
||||||
return aes.decrypt(data, self.password)
|
|
||||||
def write_filter(self, data):
|
|
||||||
return aes.encrypt(data, self.password)
|
|
231
mode.py
231
mode.py
|
@ -1,231 +0,0 @@
|
||||||
import os
|
|
||||||
import sets, string
|
|
||||||
|
|
||||||
import color, default, highlight, method, point
|
|
||||||
|
|
||||||
DEBUG = False
|
|
||||||
#DEBUG = True
|
|
||||||
|
|
||||||
class Handler:
|
|
||||||
def __init__(self):
|
|
||||||
self.prefixes = sets.Set(["C-x", "C-c", "C-u"])
|
|
||||||
self.last_sequence = ''
|
|
||||||
self.curr_tokens = []
|
|
||||||
self.bindings = {}
|
|
||||||
|
|
||||||
# handle adding and removing actions
|
|
||||||
def add_action(self, action):
|
|
||||||
if action.name in self.window.application.methods:
|
|
||||||
return
|
|
||||||
assert action.name not in self.window.application.methods, \
|
|
||||||
"Action %r already found" % action.name
|
|
||||||
self.window.application.methods[action.name] = action
|
|
||||||
def del_action(self, name):
|
|
||||||
#del self.window.application.methods[name]
|
|
||||||
for binding in self.bindings.keys():
|
|
||||||
if self.bindings[binding] == name:
|
|
||||||
del self.bindings[binding]
|
|
||||||
def add_binding(self, name, sequence):
|
|
||||||
#assert name in self.actions, "No action called %r found" % name
|
|
||||||
assert name in self.window.application.methods, \
|
|
||||||
"No action called %r found" % name
|
|
||||||
self.bindings[sequence] = name
|
|
||||||
def add_bindings(self, name, sequences):
|
|
||||||
for sequence in sequences:
|
|
||||||
self.add_binding(name, sequence)
|
|
||||||
def del_binding(self, sequence):
|
|
||||||
del self.bindings[sequence]
|
|
||||||
def add_action_and_bindings(self, action, sequences):
|
|
||||||
self.add_action(action)
|
|
||||||
for sequence in sequences:
|
|
||||||
self.add_binding(action.name, sequence)
|
|
||||||
|
|
||||||
def handle_token(self, t):
|
|
||||||
'''self.handle_token(token): returns None, or the action to
|
|
||||||
take. raises an exception on unknown input'''
|
|
||||||
self.curr_tokens.append(t)
|
|
||||||
sequence = " ".join(self.curr_tokens)
|
|
||||||
if sequence in self.bindings:
|
|
||||||
name = self.bindings[sequence]
|
|
||||||
#act = self.actions[name]
|
|
||||||
act = self.window.application.methods[name]
|
|
||||||
self.curr_tokens = []
|
|
||||||
self.last_sequence = sequence
|
|
||||||
return act
|
|
||||||
elif t in self.prefixes:
|
|
||||||
for binding in self.bindings:
|
|
||||||
if binding.startswith(sequence):
|
|
||||||
return None
|
|
||||||
self.curr_tokens = []
|
|
||||||
self.last_sequence = sequence
|
|
||||||
raise Exception, "no action defined for %r" % (sequence)
|
|
||||||
|
|
||||||
class Fundamental(Handler):
|
|
||||||
'''This is the default mode'''
|
|
||||||
def __init__(self, w):
|
|
||||||
self.window = w
|
|
||||||
|
|
||||||
Handler.__init__(self)
|
|
||||||
|
|
||||||
#self.actions = {}
|
|
||||||
self.bindings = {}
|
|
||||||
self.add_bindings('start-of-line', ('C-a', 'HOME',))
|
|
||||||
self.add_bindings('end-of-line', ('C-e', 'END',))
|
|
||||||
self.add_bindings('backward', ('C-b', 'L_ARROW',))
|
|
||||||
self.add_bindings('forward', ('C-f', 'R_ARROW',))
|
|
||||||
self.add_bindings('center-view', ('C-l',))
|
|
||||||
self.add_bindings('next-line', ('C-n', 'D_ARROW',))
|
|
||||||
self.add_bindings('previous-line', ('C-p', 'U_ARROW',))
|
|
||||||
self.add_bindings('next-section', ('M-n', 'M-D_ARROW',))
|
|
||||||
self.add_bindings('previous-section', ('M-p', 'M-U_ARROW',))
|
|
||||||
self.add_bindings('page-down', ('C-v', 'PG_DN',))
|
|
||||||
self.add_bindings('page-up', ('M-v', 'PG_UP',))
|
|
||||||
self.add_bindings('goto-beginning', ('M-<',))
|
|
||||||
self.add_bindings('goto-end', ('M->',))
|
|
||||||
self.add_bindings('delete-left', ('DELETE', 'BACKSPACE',))
|
|
||||||
self.add_bindings('delete-left-word', ('M-DELETE', 'M-BACKSPACE',))
|
|
||||||
self.add_bindings('delete-right', ('C-d',))
|
|
||||||
self.add_bindings('delete-right-word', ('M-d',))
|
|
||||||
self.add_bindings('kill-region', ('C-w',))
|
|
||||||
self.add_bindings('copy-region', ('M-w',))
|
|
||||||
self.add_bindings('kill', ('C-k',))
|
|
||||||
self.add_bindings('copy', ('M-k',))
|
|
||||||
self.add_bindings('yank', ('C-y',))
|
|
||||||
self.add_bindings('pop-kill', ('M-y',))
|
|
||||||
self.add_bindings('right-word', ('M-f',))
|
|
||||||
self.add_bindings('left-word', ('M-b',))
|
|
||||||
self.add_bindings('set-mark', ('C-@',))
|
|
||||||
self.add_bindings('switch-buffer', ('C-x b',))
|
|
||||||
self.add_bindings('switch-mark', ('C-x C-x',))
|
|
||||||
self.add_bindings('undo', ('C-/', 'C-x u',))
|
|
||||||
self.add_bindings('redo', ('M-/', 'M-_', 'C-x r',))
|
|
||||||
self.add_bindings('goto-line', ('M-g',))
|
|
||||||
self.add_bindings('forward-chars', ('C-x M-c',))
|
|
||||||
self.add_bindings('forward-lines', ('C-x M-n',))
|
|
||||||
self.add_bindings('search', ('C-s',))
|
|
||||||
self.add_bindings('reverse-search', ('C-r',))
|
|
||||||
self.add_bindings('toggle-margins', ('M-m',))
|
|
||||||
self.add_bindings('replace', ('M-%',))
|
|
||||||
self.add_bindings('open-file', ('C-x C-f',))
|
|
||||||
self.add_bindings('kill-buffer', ('C-x k',))
|
|
||||||
self.add_bindings('list-buffers', ('C-x C-b',))
|
|
||||||
self.add_bindings('meta-x', ('M-x',))
|
|
||||||
self.add_bindings('wrap-line', ('M-q',))
|
|
||||||
self.add_bindings('transpose-words', ('M-t',))
|
|
||||||
self.add_bindings('save-buffer', ('C-x C-s',))
|
|
||||||
self.add_bindings('save-buffer-as', ('C-x C-w',))
|
|
||||||
self.add_bindings('relex-buffer', ('M-r',))
|
|
||||||
self.add_bindings('exit', ('C-x C-c',))
|
|
||||||
self.add_bindings('exit2', ('C-c C-c',))
|
|
||||||
self.add_bindings('split-window', ('C-x s',))
|
|
||||||
self.add_bindings('unsplit-window', ('C-u s',))
|
|
||||||
self.add_bindings('toggle-window', ('C-x o',))
|
|
||||||
self.add_bindings('delete-left-whitespace', ('C-c DELETE', 'C-c BACKSPACE',))
|
|
||||||
self.add_bindings('delete-right-whitespace', ('C-c d',))
|
|
||||||
self.add_bindings('insert-space', ('SPACE',))
|
|
||||||
self.add_bindings('insert-tab', ('TAB',))
|
|
||||||
self.add_bindings('insert-newline', ('RETURN',))
|
|
||||||
self.add_bindings('comment-region', ('C-c #',))
|
|
||||||
self.add_bindings('uncomment-region', ('C-u C-c #',))
|
|
||||||
self.add_bindings('justify-right', ('C-c f',))
|
|
||||||
self.add_bindings('justify-left', ('C-c b',))
|
|
||||||
self.add_bindings('indent-block', ('C-c >',))
|
|
||||||
self.add_bindings('unindent-block', ('C-c <',))
|
|
||||||
self.add_bindings('code-complete', ('M-c',))
|
|
||||||
self.add_bindings('shell-cmd', ('C-c !',))
|
|
||||||
self.add_bindings('open-aes-file', ('C-c a',))
|
|
||||||
self.add_bindings('open-console', ('M-e',))
|
|
||||||
self.add_bindings('show-bindings-buffer', ('C-c M-h','C-c M-?',))
|
|
||||||
self.add_bindings('which-command', ('M-?',))
|
|
||||||
self.add_bindings('cmd-help-buffer', ('M-h',))
|
|
||||||
self.add_bindings('set-mode', ('C-x m',))
|
|
||||||
self.add_bindings('cancel', ('C-]',))
|
|
||||||
self.add_bindings('close-paren', (')',))
|
|
||||||
self.add_bindings('close-brace', ('}',))
|
|
||||||
self.add_bindings('close-bracket', (']',))
|
|
||||||
|
|
||||||
# create all the insert actions for the character ranges we like
|
|
||||||
for c in string.letters + string.digits + string.punctuation:
|
|
||||||
## closing tags are handled differently
|
|
||||||
if c == ')' or c == ']' or c == '}':
|
|
||||||
continue
|
|
||||||
self.add_binding('insert-string-%s' % c, c)
|
|
||||||
|
|
||||||
# initialize some stuff
|
|
||||||
self.grammar = None
|
|
||||||
self.lexer = None
|
|
||||||
self.tabber = None
|
|
||||||
|
|
||||||
# initialize the default colors, highlighter, etc.
|
|
||||||
self.default_color = color.pairs('default', 'default')
|
|
||||||
self.colors = {}
|
|
||||||
self.highlighter = highlight.Highlighter(self)
|
|
||||||
|
|
||||||
# get mode name
|
|
||||||
def name(self):
|
|
||||||
return "Fundamental"
|
|
||||||
|
|
||||||
# handle input tokens
|
|
||||||
def handle_token(self, t):
|
|
||||||
'''self.handle_token(token): handles input "token"'''
|
|
||||||
self.window.active_point = None
|
|
||||||
if DEBUG:
|
|
||||||
# debug mode is crash prone
|
|
||||||
act = Handler.handle_token(self, t)
|
|
||||||
if act is None:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.window.application.clear_error()
|
|
||||||
act.execute(self.window)
|
|
||||||
self.window.application.last_action = act.name
|
|
||||||
else:
|
|
||||||
# regular mode is hard to get stack traces from
|
|
||||||
try:
|
|
||||||
act = Handler.handle_token(self, t)
|
|
||||||
if act is None:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.window.application.clear_error()
|
|
||||||
act.execute(self.window)
|
|
||||||
self.window.application.last_action = act.name
|
|
||||||
except Exception, e:
|
|
||||||
if DEBUG:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
err = "%s in mode '%s'" % (e, self.name())
|
|
||||||
self.window.application.set_error(err)
|
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
if self.tabber is not None:
|
|
||||||
self.tabber.invalidate()
|
|
||||||
if self.lexer is not None:
|
|
||||||
self.highlighter.invalidate_regions()
|
|
||||||
|
|
||||||
def get_regions(self):
|
|
||||||
if self.lexer is not None:
|
|
||||||
return self.highlighter.get_regions()
|
|
||||||
else:
|
|
||||||
return [[] for l in self.window.get_physical_lines()]
|
|
||||||
|
|
||||||
def visible_regions(self):
|
|
||||||
i = self.window.visible_offset()
|
|
||||||
regions = self.get_regions()
|
|
||||||
return regions[i:i+self.window.height]
|
|
||||||
|
|
||||||
def region_added(self, p, xdiff, ydiff, s):
|
|
||||||
if self.lexer is not None:
|
|
||||||
if self.tabber is not None and s != ' ' and s != ' ':
|
|
||||||
self.tabber.invalidate()
|
|
||||||
self.highlighter.region_added(p, xdiff, ydiff, s)
|
|
||||||
|
|
||||||
def region_removed(self, p1, p2, s):
|
|
||||||
if self.lexer is not None:
|
|
||||||
if self.tabber is not None:
|
|
||||||
self.tabber.invalidate()
|
|
||||||
self.highlighter.region_removed(p1, p2, s)
|
|
||||||
|
|
||||||
def get_indentation_level(self, y):
|
|
||||||
if self.tabber is None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return self.tabber.get_indentation_level(y)
|
|
Loading…
Reference in New Issue