diff --git a/application.py b/application.py index edb9c20..188896f 100755 --- a/application.py +++ b/application.py @@ -2,9 +2,9 @@ import curses, curses.ascii, getpass, os, re, string, sets, sys, termios, time import traceback -import buffer2, bufferlist, color, completer, keyinput, method, minibuffer, mode, mode2 +import buffer, bufferlist, color, completer, keyinput, method, minibuffer, mode, mode2 import util, window2 -from point2 import Point +from point import Point def run(buffers, jump_to_line=None, init_mode=None): # save terminal state so we can restore it when the program exits @@ -113,10 +113,10 @@ class Application(object): # initialize our buffers # note that the first buffer in buffers will be initially visible - buffers.append(buffer2.ScratchBuffer()) - buffers.append(buffer2.ConsoleBuffer()) + buffers.append(buffer.ScratchBuffer()) + buffers.append(buffer.ConsoleBuffer()) if self.rcerror: - buffers.insert(0, buffer2.DataBuffer('*RcError*', self.rcerror)) + buffers.insert(0, buffer.DataBuffer('*RcError*', self.rcerror)) self.bufferlist = bufferlist.BufferList(height, width) self.active_slot = 0 @@ -223,11 +223,11 @@ class Application(object): if cipher is None: if not os.path.exists(path) or os.path.isfile(path): if binary: - b = buffer2.Binary32Buffer(path, name=name) + b = buffer.Binary32Buffer(path, name=name) else: - b = buffer2.FileBuffer(path, name=name) + b = buffer.FileBuffer(path, name=name) elif os.path.isdir(path): - b = buffer2.DirBuffer(path, name=name) + b = buffer.DirBuffer(path, name=name) mode_name = 'dir' else: raise Exception, "not a file or dir: %r" % path @@ -235,7 +235,7 @@ class Application(object): if not password: raise Exception, "password is required" if not os.path.exists(path) or os.path.isfile(path): - b = buffer2.AesBuffer(path, password, name=name) + b = buffer.AesBuffer(path, password, name=name) else: raise Exception, "not a file or dir: %r" % path b.open() @@ -297,7 +297,7 @@ class Application(object): f = open(path, 'w') f.write(data) f.close() - b = buffer2.FileBuffer(path) + b = buffer.FileBuffer(path) b.open() window2.Window(b, self, height=0, width=0) self.add_buffer(b) @@ -307,7 +307,7 @@ class Application(object): if self.has_buffer_name(name): b = self.bufferlist.buffer_names[name] self.remove_buffer(b) - b = buffer2.DataBuffer(name, data) + b = buffer.DataBuffer(name, data) if modename is not None: b.modename = modename window2.Window(b, self, height=0, width=0) @@ -742,17 +742,17 @@ class Application(object): def open_aes_file(path, nl, name=None): if os.path.isfile(path) or not os.path.exists(path): p = getpass.getpass("Please enter the AES password: ") - return buffer2.AesBuffer(path, p, nl, name) + return buffer.AesBuffer(path, p, nl, name) else: raise Exception, "can't open %r; unsupported file type" % path def open_plain_file(path, nl, name=None, binary=False): if os.path.isfile(path) or not os.path.exists(path): if binary: - return buffer2.Binary32Buffer(path, nl, name) + return buffer.Binary32Buffer(path, nl, name) else: - return buffer2.FileBuffer(path, nl, name) + return buffer.FileBuffer(path, nl, name) elif os.path.isdir(path): - return buffer2.DirBuffer(path, nl, name) + return buffer.DirBuffer(path, nl, name) else: raise Exception, "can't open %r; unsupported file type" % path @@ -832,7 +832,7 @@ if __name__ == "__main__": try: b = f(path, nl, name, opts.binary) b.open() - except buffer2.BinaryDataException, e: + except buffer.BinaryDataException, e: b = f(path, nl, name, True) b.open() diff --git a/buffer.py b/buffer.py new file mode 100644 index 0000000..19f37b1 --- /dev/null +++ b/buffer.py @@ -0,0 +1,607 @@ +import datetime, grp, md5, os, pwd, re, sets, shutil, stat, string +import aes, dirutil, regex, highlight2 +from point import Point + +# undo/redo stack constants +ACT_NORM = 0 +ACT_UNDO = 1 +ACT_REDO = 2 +STACK_LIMIT = 1024 + +# used for undo/redo stacks when text will need to be added back +class AddMove: + def __init__(self, buffer, p, lines): + self.buffer = buffer + self.p = p + self.lines = lines + def restore(self, act=ACT_UNDO): + assert act == ACT_UNDO or act == ACT_REDO + self.buffer.insert_lines(self.p, self.lines, act) + def getpos(self): + return self.p + +# used for undo/redo stacks when text will need to be removed +class DelMove: + def __init__(self, buffer, p1, p2): + self.buffer = buffer + self.p1 = p1 + self.p2 = p2 + def restore(self, act): + assert act == ACT_UNDO or act == ACT_REDO + self.buffer.delete(self.p1, self.p2, act) + def getpos(self): + return self.p1 + +# abstract class +class Buffer(object): + btype = 'generic' + def __init__(self, nl='\n', stack_limit=STACK_LIMIT): + assert nl in ('\n', '\r', '\r\n'), "Invalid line ending" + self.lines = [""] + self.windows = [] + self.undo_stack = [] + self.redo_stack = [] + self.stack_limit = stack_limit + self.nl = nl + self.modified = False + self.highlights = {} + + # 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 _stack_trim(self, stack): + if self.stack_limit: + while len(stack) > self.stack_limit: + stack.pop(0) + def add_to_stack(self, move, act): + if act == ACT_NORM: + self.redo_stack = [] + self.undo_stack.append(move) + self._stack_trim(self.undo_stack) + elif act == ACT_UNDO: + self.redo_stack.append(move) + self._stack_trim(self.redo_stack) + elif act == ACT_REDO: + self.undo_stack.append(move) + self._stack_trim(self.undo_stack) + else: + raise Exception, "Invalid act: %d" % (act) + def undo(self): + if len(self.undo_stack): + move = self.undo_stack.pop(-1) + move.restore(ACT_UNDO) + return move.getpos() + else: + raise Exception, "Nothing to Undo!" + def redo(self): + if len(self.redo_stack): + move = self.redo_stack.pop(-1) + move.restore(ACT_REDO) + return move.getpos() + else: + raise Exception, "Nothing to Redo!" + + # window-buffer communication + def add_window(self, w): + if w not in self.windows: + self.windows.append(w) + modename = w.mode.name() + if modename not in self.highlights and w.mode.lexer is not None: + self.highlights[modename] = highlight2.Highlighter(w.mode.lexer) + self.highlights[modename].highlight(self.lines) + #if modename not in self.tabbing and w.mode.tabber is not None: + # self.tabbing[modename] = + def remove_window(self, w): + if w in self.windows: + self.windows.remove(w) + modename = w.mode.name() + found = False + for w2 in self.windows: + if w2.mode.name() == modename: + found = True + break + if not found: + del self.highlights[modename] + def _region_add(self, p1, p2, lines, act): + move = DelMove(self, p1, p2) + self.add_to_stack(move, act) + for w in self.windows: + w.region_added(p1, lines) + for name in self.highlights: + self.highlights[name].relex_add(self.lines, p1.y, p1.x, lines) + def _region_del(self, p1, p2, lines, act): + move = AddMove(self, p1, lines) + self.add_to_stack(move, act) + for w in self.windows: + w.region_removed(p1, p2) + for name in self.highlights: + self.highlights[name].relex_del(self.lines, p1.y, p1.x, p2.y, p2.x) + + # 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)) + + # deal with the actual logical document string + def num_chars(self): + n = 0 + for line in self.lines[:-1]: + n += len(line) + 1 + n += len(self.lines[-1]) + return n + def num_lines(self): + return len(self.lines) + def make_string(self, nl='\n'): + return nl.join(self.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(0, 0) + def get_buffer_end(self): + return Point(len(self.lines[-1]), len(self.lines) - 1) + + # data retrieval + def get_sublines(self, p1, p2): + self._validate_point(p1) + self._validate_point(p2) + assert p1 <= p2, "p1.x (%d) > p2.x (%d)" % (p1.x, p2.x) + lines = [] + x = p1.x + for i in range(p1.y, p2.y): + lines.append(self.lines[i][x:]) + x = 0 + lines.append(self.lines[p2.y][x:p2.x]) + return lines + def get_substring(self, p1, p2): + lines = self.get_sublines(p1, p2) + return '\n'.join(lines) + + # buffer set + def set_lines(self, lines, 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(start, end, force=force) + self.insert_lines(start, lines, force=force) + self.modified = True + def set_data(self, data, force=False): + lines = data.split('\n') + self.set_lines(lines, force) + + # insertion into buffer + def insert_lines(self, p, lines, act=ACT_NORM, force=False): + #if lines == ['(']: + # raise Exception, "damn" + llen = len(lines) + assert llen > 0 + if not force: + assert not self.readonly(), "insert_string: buffer is read-only" + p2 = p.vadd(len(lines[-1]), llen - 1) + if llen > 1: + self.lines.insert(p.y + 1, []) + self.lines[p.y + 1] = lines[-1] + self.lines[p.y][p.x:] + self.lines[p.y] = self.lines[p.y][:p.x] + lines[0] + for i in range(1, llen - 1): + self.lines.insert(p.y + i, lines[i]) + else: + self.lines[p.y] = self.lines[p.y][:p.x] + lines[-1] + self.lines[p.y][p.x:] + self._region_add(p, p2, lines, act) + self.modified = True + def insert_string(self, p, s, act=ACT_NORM, force=False): + lines = s.split("\n") + self.insert_lines(p, lines, act, force) + + # deletion from buffer + def delete(self, p1, p2, act=ACT_NORM, 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_point(p1) + self._validate_point(p2) + if p1 == p2: + return + assert p1 < p2, "p1 %r > p2 %r" % (p1, p2) + lines = self.get_sublines(p1, p2) + line1 = self.lines[p1.y] + line2 = self.lines[p2.y] + self.lines[p1.y:p2.y+1] = ["%s%s" % (line1[:p1.x], line2[p2.x:])] + self._region_del(p1, p2, lines, act) + self.modified = True + def delete_char(self, p, act=ACT_NORM, force=False): + if p.x == len(self.lines[p.y]): + p2 = Point(0, p.y + 1) + else: + p2 = Point(p.x + 1, p.y) + self.delete(p, p2, act=act, force=force) + def overwrite_char(self, p, c, act=ACT_NORM, force=False): + self.delete_char(p, act=act, force=force) + self.insert_string(p, c, act=act, force=force) + + # 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" + +# scratch is a singleton +scratch = None +class ScratchBuffer(Buffer): + btype = 'scratch' + 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): + btype = 'data' + 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): + btype = 'console' + 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) + self.clear() + def clear(self): + 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 BinaryDataException(Exception): + pass + +class FileBuffer(Buffer): + btype = 'file' + 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) + data = data.replace("\t", " ") + for i in range(0, min(len(data), 8)): + if data[i] not in string.printable: + raise BinaryDataException, "binary files are not supported" + #FIXME: this is horrible...but maybe not as horrible as using tabs?? + 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) + if self.windows[0].mode.savetabs: + data = data.replace(" ", "\t") + + 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): + btype = 'aesfile' + def __init__(self, path, password, nl='\n', name=None): + '''fb = FileBuffer(path)''' + FileBuffer.__init__(self, path, nl, name) + self.password = password + def read_filter(self, data): + return aes.decrypt_data(data, self.password) + def write_filter(self, data): + return aes.encrypt_data(data, self.password) + +class Binary32Buffer(FileBuffer): + btype = 'bin32file' + wordsize = 4 + numwords = 4 + def __init__(self, path, nl='\n', name=None): + '''fb = FileBuffer(path)''' + FileBuffer.__init__(self, path, nl, name) + def read_filter(self, data): + lines = [] + i = 0 + while i < len(data): + j = 0 + words = [] + while j < self.numwords * self.wordsize and i + j < len(data): + nibbles = [] + for c in data[i + j:i + j + self.wordsize]: + nibbles.append(string.hexdigits[ord(c) / 16]) + nibbles.append(string.hexdigits[ord(c) % 16]) + words.append(''.join(nibbles)) + j += self.wordsize + lines.append(' '.join(words)) + i += self.numwords * self.wordsize + return '\n'.join(lines) + def write_filter(self, data): + bytes = [] + lastc = None + for c in data: + if c not in '0123456789abcdefABCDEF': + pass + elif lastc is None: + lastc = c + else: + bytes.append(chr(int(lastc + c, 16))) + lastc = None + if lastc is not None: + bytes.append(chr(int(lastc + '0', 16))) + return ''.join(bytes) + +class Binary64Buffer(Binary32Buffer): + wordsize = 8 + numwords = 2 + +class DirBuffer(Buffer): + btype = 'dir' + def __init__(self, path, nl='\n', name=None): + Buffer.__init__(self, nl) + self.path = os.path.realpath(path) + def changed(self): + return False + def readonly(self): + return True + def name(self): + return self.path + def path_exists(self): + return os.path.exists(self.path) + + def _get_names(self): + if not self.path_exists(): + raise Exception, "directory %r does not exists" % self.path + names = os.listdir(self.path) + if self.path != '/': + names.insert(0, '..') + names.insert(0, '.') + return names + def _make_path(self, name): + return os.path.join(self.path, name) + def _get_lines(self): + names = self._get_names() + + fieldlines = [] + maxlens = [0] * 5 + for name in names: + path = self._make_path(name) + fields = dirutil.path_fields(path, name) + for i in range(0, 5): + try: + maxlens[i] = max(maxlens[i], len(fields[i])) + except: + raise Exception, '%d %r' % (i, fields[i]) + fieldlines.append(fields) + + fieldlines.sort(cmp=dirutil.path_sort) + fmt = '%%%ds %%-%ds %%-%ds %%%ds %%%ds %%s' % tuple(maxlens) + + lines = [] + for fields in fieldlines: + s = fmt % fields + lines.append(s) + return lines + def open(self): + self.lines = self._get_lines() + def reload(self): + lines = self._get_lines() + self.set_lines(lines, force=True) + def save(self, force=False): + raise Exception, "can't save a directory buffer" + def save_as(self, path): + raise Exception, "can't save a directory buffer" + +class PathListBuffer(DirBuffer): + btype = 'pathlist' + def __init__(self, name, paths, nl='\n'): + Buffer.__init__(self, nl) + self.paths = paths + self.path = os.getcwd() + self._name = name + def path_exists(self): + raise Exception + def _get_names(self): + cwd = os.getcwd() + return [x.replace(cwd, '.', 1) for x in self.paths] + def _make_path(self, name): + if name.startswith('.'): + return name.replace('.', os.getcwd(), 1) + else: + return name + def name(self): + return self._name diff --git a/buffer2.py b/buffer2.py index 821716d..19f37b1 100644 --- a/buffer2.py +++ b/buffer2.py @@ -1,6 +1,6 @@ import datetime, grp, md5, os, pwd, re, sets, shutil, stat, string import aes, dirutil, regex, highlight2 -from point2 import Point +from point import Point # undo/redo stack constants ACT_NORM = 0 diff --git a/dirutil.py b/dirutil.py index 8ee715d..2b239c7 100644 --- a/dirutil.py +++ b/dirutil.py @@ -1,5 +1,5 @@ import datetime, grp, os, pwd, re, stat -from point2 import Point +from point import Point def resolve_token(w, y=None): if y is None: diff --git a/lex3.py b/lex3.py index ed3a32c..6c9ac41 100755 --- a/lex3.py +++ b/lex3.py @@ -1,6 +1,6 @@ import curses, re import regex, util -from point2 import Point +from point import Point class Token(object): def __init__(self, name, rule, y, x, s, color=None, parent=None, matchd={}, link=None): diff --git a/method.py b/method.py index 5ad6468..dab734a 100644 --- a/method.py +++ b/method.py @@ -1,6 +1,6 @@ import os, commands, popen2, re, sets -import buffer2, default, dirutil, regex, util, window2 -from point2 import Point +import buffer, default, dirutil, regex, util, window2 +from point import Point WHITESPACE = [' ', '\n'] @@ -879,7 +879,7 @@ class OpenConsole(Method): def execute(self, w, **vargs): a = w.application if not a.has_buffer_name('*Console*'): - a.add_buffer(buffer2.ConsoleBuffer()) + a.add_buffer(buffer.ConsoleBuffer()) b = a.bufferlist.get_buffer_by_name('*Console*') if a.window().buffer is not b: a.switch_buffer(b) diff --git a/minibuffer.py b/minibuffer.py index a4a9fce..c74719d 100644 --- a/minibuffer.py +++ b/minibuffer.py @@ -1,11 +1,11 @@ -import buffer2 +import buffer class MiniBufferError(Exception): pass # minibuffer is a singleton mini = None -class MiniBuffer(buffer2.Buffer): +class MiniBuffer(buffer.Buffer): btype = 'mini' def __new__(cls, *args, **kwargs): global mini @@ -14,7 +14,7 @@ class MiniBuffer(buffer2.Buffer): return mini # the callback function should take one argument (window) def __init__(self, func, method=None, tabber=None, modename=None): - buffer2.Buffer.__init__(self) + buffer.Buffer.__init__(self) self.callback = func self.method = method self.tabber = tabber diff --git a/mode/blame.py b/mode/blame.py index bdf9062..139842f 100644 --- a/mode/blame.py +++ b/mode/blame.py @@ -1,6 +1,6 @@ import color, mode2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, RegionRule class MetadataGrammar(Grammar): diff --git a/mode/consolemini.py b/mode/consolemini.py index 72b324c..07d9408 100644 --- a/mode/consolemini.py +++ b/mode/consolemini.py @@ -1,7 +1,7 @@ import code, string, StringIO, sys, traceback import color, completer, method, mode2 from lex3 import Grammar, PatternRule -from point2 import Point +from point import Point class ConsoleMini(mode2.Fundamental): modename = 'ConsoleMini' diff --git a/mode/css.py b/mode/css.py index 726c09f..27de867 100644 --- a/mode/css.py +++ b/mode/css.py @@ -1,6 +1,6 @@ import color, mode2 from lex3 import Grammar, PatternRule, NocasePatternRule, RegionRule, NocaseRegionRule -from point2 import Point +from point import Point class StringGrammar(Grammar): rules = [ diff --git a/mode/dir.py b/mode/dir.py index 694b7d5..289a954 100644 --- a/mode/dir.py +++ b/mode/dir.py @@ -1,7 +1,7 @@ import commands, dirutil, grp, method, mode2, os.path, pwd, re -import buffer2, window2 +import buffer, window2 from lex3 import Grammar, PatternRule, RegionRule, PatternGroupRule -from point2 import Point +from point import Point from method import Method, Argument class PermGrammar(Grammar): @@ -94,7 +94,7 @@ class DirGrep(Method): (status, output) = commands.getstatusoutput(cmd) paths = output.split('\n') bufname = '*%s*' % self.name.title() - b = buffer2.PathListBuffer(bufname, paths) + b = buffer.PathListBuffer(bufname, paths) b.modename = 'dir' b.open() window2.Window(b, w.application, height=0, width=0) diff --git a/mode/elisp.py b/mode/elisp.py index 4c26674..428eb6a 100644 --- a/mode/elisp.py +++ b/mode/elisp.py @@ -1,6 +1,6 @@ import commands, os.path, sets, string, sys, traceback import color, completer, default, mode2, method, regex, tab2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, RegionRule, OverridePatternRule class StringGrammar(Grammar): diff --git a/mode/hex.py b/mode/hex.py index 70e7b67..3b6d024 100644 --- a/mode/hex.py +++ b/mode/hex.py @@ -2,7 +2,7 @@ import string import color, mode2 from lex3 import Grammar, PatternRule, RegionRule from method import Method, Argument -from point2 import Point +from point import Point class HexGrammar(Grammar): rules = [ diff --git a/mode/javascript.py b/mode/javascript.py index a0a187e..c3f7461 100644 --- a/mode/javascript.py +++ b/mode/javascript.py @@ -1,6 +1,6 @@ import color, mode2, tab2 from lex3 import Grammar, PatternRule, RegionRule -from point2 import Point +from point import Point from mode.python import StringGrammar class JavascriptGrammar(Grammar): diff --git a/mode/lisp.py b/mode/lisp.py index db932a2..c342a06 100644 --- a/mode/lisp.py +++ b/mode/lisp.py @@ -1,6 +1,6 @@ import commands, os.path, sets, string, sys, traceback import color, completer, default, mode2, method, regex, tab2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, RegionRule, OverridePatternRule from mode.python import StringGrammar diff --git a/mode/ocaml.py b/mode/ocaml.py index 68d640d..2c6bff4 100644 --- a/mode/ocaml.py +++ b/mode/ocaml.py @@ -1,6 +1,6 @@ import commands, os.path, sets, string, sys, traceback import color, completer, default, mode2, method, regex, tab2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, RegionRule, NocasePatternRule class StringGrammar(Grammar): diff --git a/mode/perl.py b/mode/perl.py index ac36258..24b5f40 100644 --- a/mode/perl.py +++ b/mode/perl.py @@ -1,6 +1,6 @@ import re, sets, string, sys import color, commands, default, method, mode2, regex, tab2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, ContextPatternRule, RegionRule, OverridePatternRule, PatternGroupRule from method import Argument, Method, WrapParagraph diff --git a/mode/python.py b/mode/python.py index 9be9f34..abcf7c8 100644 --- a/mode/python.py +++ b/mode/python.py @@ -1,6 +1,6 @@ import commands, os.path, sets, string, sys, traceback import color, completer, default, mode2, method, regex, tab2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, RegionRule, OverridePatternRule class StringGrammar(Grammar): diff --git a/mode/replace.py b/mode/replace.py index c99a6ce..9eae4a8 100644 --- a/mode/replace.py +++ b/mode/replace.py @@ -1,7 +1,7 @@ import re, sets, string import color, method, minibuffer, mode2, searchutil -from point2 import Point +from point import Point class Replace(mode2.Fundamental): modename = 'Replace' diff --git a/mode/scheme.py b/mode/scheme.py index 4626ad1..96e6bbf 100644 --- a/mode/scheme.py +++ b/mode/scheme.py @@ -1,6 +1,6 @@ import commands, os.path, sets, string, sys, traceback import color, completer, default, mode2, method, regex, tab2 -from point2 import Point +from point import Point from lex3 import Grammar, PatternRule, RegionRule, OverridePatternRule import mode.lisp diff --git a/mode/search.py b/mode/search.py index 65a5a19..36cfcc3 100644 --- a/mode/search.py +++ b/mode/search.py @@ -1,7 +1,7 @@ import re, sets, string import color, method, minibuffer, mode2, searchutil -from point2 import Point +from point import Point selected_color = 'magenta' unselected_color = 'yellow' diff --git a/mode/which.py b/mode/which.py index 29ca5f1..6423ae6 100644 --- a/mode/which.py +++ b/mode/which.py @@ -1,5 +1,5 @@ import color, method, mode2 -from point2 import Point +from point import Point class Which(mode2.Fundamental): modename = 'Which' diff --git a/mode2.py b/mode2.py index 8145d32..44cada0 100644 --- a/mode2.py +++ b/mode2.py @@ -1,7 +1,7 @@ import os, sets, string import color, method from lex3 import Lexer -from point2 import Point +from point import Point DEBUG = False diff --git a/point.py b/point.py new file mode 100644 index 0000000..c011239 --- /dev/null +++ b/point.py @@ -0,0 +1,42 @@ +class Point(tuple): + '''Represents an (x,y) coordinate''' + def __new__(cls, x, y): + return tuple.__new__(cls, (y, x)) + def __getattr__(self, name): + if name == "x": + return self[1] + elif name == 'y': + return self[0] + else: + raise AttributeError + def __repr__(self): + return '' % (self[1], self[0]) + def __str__(self): + return '(%d,%d)' % (self[1], self[0]) + + def xy(self): + '''Returns a tuple (x,y)''' + return (self[1], self[0]) + def yx(self): + '''Returns a tuple (x,y)''' + return tuple(self) + def add(self, xdelta, ydelta): + '''Returns a new point, adding xdelta and ydelta''' + return Point(self[1] + xdelta, self[0] + ydelta) + def vadd(self, xdelta, ydelta): + '''Returns a new point. If ydelta != 0, xdelta is absolute; otherwise, xdelta is relative''' + assert xdelta >= 0 and ydelta >= 0, str((xdelta, ydelta)) + if ydelta != 0: + return Point(xdelta, self[0] + ydelta) + else: + return Point(self[1] + xdelta, self[0]) + #def sub(self, xdelta, ydelta): + # '''Returns a new point, subtracing xdelta and ydelta''' + # return Point(self[1] - xdelta, self[0] - ydelta) + #def vsub(self, xdelta, ydelta): + # '''Returns a new point. If ydelta != 0, xdelta is absolute; otherwise, xdelta is relative''' + # assert xdelta >= 0 and ydelta >= 0, str((xdelta, ydelta)) + # if ydelta != 0: + # return Point(self[1], self[0] - ydelta) + # else: + # return Point(self[1] - xdelta, self[0]) diff --git a/searchutil.py b/searchutil.py index dc5cd72..8695cfa 100644 --- a/searchutil.py +++ b/searchutil.py @@ -1,6 +1,6 @@ import re import regex -from point2 import Point +from point import Point bg_color = 'black' selected_color = 'magenta' diff --git a/tab2.py b/tab2.py index 35c5332..a3215e5 100644 --- a/tab2.py +++ b/tab2.py @@ -1,5 +1,5 @@ import regex, util -from point2 import Point +from point import Point class Marker: def __init__(self, name, level): diff --git a/window2.py b/window2.py index 48dcf43..e35c178 100644 --- a/window2.py +++ b/window2.py @@ -1,6 +1,6 @@ import os.path, string import highlight2, regex -from point2 import Point +from point import Point WORD_LETTERS = list(string.letters + string.digits)