--HG--
branch : pmacs2
This commit is contained in:
moculus 2007-06-04 07:29:37 +00:00
parent d769305721
commit bb2716a532
5 changed files with 231 additions and 267 deletions

View File

@ -1,9 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
import curses, curses.ascii, getpass, os, re, string, sys, termios, time import curses, curses.ascii, getpass, os, re, string, sets, sys, termios, time
import traceback import traceback
import buffer, bufferlist, color, completer, keyinput, method, minibuffer import buffer2, bufferlist, color, completer, keyinput, method, minibuffer
import mode, point, sets, util, window import mode2, util, window2
from point2 import Point
# modes # modes
import mode, mode_c, mode_mini, mode_python, mode_nasm, mode_perl, mode_search import mode, mode_c, mode_mini, mode_python, mode_nasm, mode_perl, mode_search
@ -75,61 +76,62 @@ class Application:
self.set_error("Dynamic color not available") self.set_error("Dynamic color not available")
# initialize our modes # initialize our modes
self.modes = { self.modes = {'fundamental': mode2.Fundamental}
'blame': mode_blame.Blame, # self.modes = {
'c': mode_c.C, # 'blame': mode_blame.Blame,
'console': mode_console.Console, # 'c': mode_c.C,
'diff': mode_diff.Diff, # 'console': mode_console.Console,
'fundamental': mode.Fundamental, # 'diff': mode_diff.Diff,
'mini': mode_mini.Mini, # 'fundamental': mode.Fundamental,
'nasm': mode_nasm.Nasm, # 'mini': mode_mini.Mini,
'perl': mode_perl.Perl, # 'nasm': mode_nasm.Nasm,
'python': mode_python.Python, # 'perl': mode_perl.Perl,
'replace': mode_replace.Replace, # 'python': mode_python.Python,
'search': mode_search.Search, # 'replace': mode_replace.Replace,
'sh': mode_sh.Sh, # 'search': mode_search.Search,
'text': mode_text.Text, # 'sh': mode_sh.Sh,
'which': mode_which.Which, # 'text': mode_text.Text,
'xml': mode_xml.XML, # 'which': mode_which.Which,
'mutt': mode_mutt.Mutt, # 'xml': mode_xml.XML,
'sql': mode_sql.Sql, # 'mutt': mode_mutt.Mutt,
'javascript': mode_javascript.Javascript, # 'sql': mode_sql.Sql,
'template': mode_tt.Template, # 'javascript': mode_javascript.Javascript,
} # 'template': mode_tt.Template,
# }
# these are used in this order to determine which mode to open certain # these are used in this order to determine which mode to open certain
# kinds of files # kinds of files
self.mode_paths = { self.mode_paths = {
'/etc/profile': 'sh', #'/etc/profile': 'sh',
} }
self.mode_basenames = { self.mode_basenames = {
'.bashrc': 'sh', #'.bashrc': 'sh',
'.bash_profile': 'sh', #'.bash_profile': 'sh',
'.profile': 'sh', #'.profile': 'sh',
} }
self.mode_extensions = { self.mode_extensions = {
'.py': 'python', # '.py': 'python',
'.pl': 'perl', # '.pl': 'perl',
'.pm': 'perl', # '.pm': 'perl',
'.t': 'perl', # '.t': 'perl',
'.c': 'c', # '.c': 'c',
'.txt': 'text', # '.txt': 'text',
'.s': 'nasm', # '.s': 'nasm',
'.sh': 'sh', # '.sh': 'sh',
'.bash': 'sh', # '.bash': 'sh',
'.xml': 'xml', # '.xml': 'xml',
'.xml.in': 'xml', # '.xml.in': 'xml',
'.html': 'xml', # '.html': 'xml',
'.htm': 'xml', # '.htm': 'xml',
'.sql': 'sql', # '.sql': 'sql',
'.js': 'javascript', # '.js': 'javascript',
'.tt': 'template' # '.tt': 'template'
} }
self.mode_detection = { self.mode_detection = {
'python': 'python', # 'python': 'python',
'perl': 'perl', # 'perl': 'perl',
'sh': 'sh', # 'sh': 'sh',
'bash': 'sh', # 'bash': 'sh',
} }
# initialize our methods # initialize our methods
@ -153,17 +155,17 @@ class Application:
# initialize our buffers # initialize our buffers
# note that the first buffer in buffers will be initially visible # note that the first buffer in buffers will be initially visible
buffers.append(buffer.ScratchBuffer()) buffers.append(buffer2.ScratchBuffer())
buffers.append(buffer.ConsoleBuffer()) buffers.append(buffer2.ConsoleBuffer())
self.bufferlist = bufferlist.BufferList(height, width) self.bufferlist = bufferlist.BufferList(height, width)
self.active_slot = 0 self.active_slot = 0
self.resize_slots() self.resize_slots()
# build windows for our buffers # build windows for our buffers
for b in buffers: for b in buffers:
window.Window(b, self, height, width, slot=self.active_slot, window2.Window(b, self, height, width, mode_name=init_mode)
mode_name=init_mode)
self.bufferlist.add_buffer(b) self.bufferlist.add_buffer(b)
self.bufferlist.set_slot(0, buffers[0])
self.resize_windows() self.resize_windows()
# see if the user has requested that we go to a particular line # see if the user has requested that we go to a particular line
@ -203,21 +205,17 @@ class Application:
return locals() return locals()
def add_slot(self): def add_slot(self):
# XYZ
b = self.bufferlist.slots[self.active_slot].buffer b = self.bufferlist.slots[self.active_slot].buffer
n = self.bufferlist.add_slot(0, 0, 0, b) n = self.bufferlist.add_slot()
self.resize_slots() self.bufferlist.set_slot(n, b)
self.add_window_to_buffer(b, n) def remove_slot(self, n):
self.resize_windows()
def remove_slot(self, slotname):
assert len(self.bufferlist.slots) > 1, "oh no you didn't!" assert len(self.bufferlist.slots) > 1, "oh no you didn't!"
assert slotname >= 0 and slotname < len(self.bufferlist.slots), \ assert n >= 0 and n < len(self.bufferlist.slots), \
"invalid slot: %r (%r)" % (slotname, len(self.bufferlist.slots)) "invalid slot: %r (%r)" % (n, len(self.bufferlist.slots))
b = self.bufferlist.slots[slotname].buffer self.bufferlist.remove_slot(n)
self.bufferlist.remove_slot(slotname)
if self.active_slot > slotname: if self.active_slot > slotname:
self.active_slot = max(0, self.active_slot - 1) self.active_slot = max(0, self.active_slot - 1)
self.resize_slots()
self.resize_windows()
def single_slot(self): def single_slot(self):
while len(self.bufferlist.slots) > 1: while len(self.bufferlist.slots) > 1:
if self.active_slot == 0: if self.active_slot == 0:
@ -225,10 +223,10 @@ class Application:
else: else:
self.remove_slot(0) self.remove_slot(0)
def get_window_height_width(self, slotname): def get_window_height_width(self, i):
assert slotname >= 0 and slotname < len(self.bufferlist.slots), \ assert i >= 0 and i < len(self.bufferlist.slots), \
"invalid slot: %r" % slotname "invalid slot: %r" % slotname
slot = self.bufferlist.slots[slotname] slot = self.bufferlist.slots[i]
return (slot.height, slot.width) return (slot.height, slot.width)
# mini buffer handling # mini buffer handling
@ -243,7 +241,7 @@ class Application:
self.mini_prompt = prompt self.mini_prompt = prompt
self.mini_buffer = minibuffer.MiniBuffer(callback, method, tabber, self.mini_buffer = minibuffer.MiniBuffer(callback, method, tabber,
modename) modename)
window.Window(self.mini_buffer, self, height=1, window2.Window(self.mini_buffer, self, height=1,
width=self.x-1-len(self.mini_prompt)-1, slot='mini') width=self.x-1-len(self.mini_prompt)-1, slot='mini')
self.mini_active = True self.mini_active = True
def exec_mini_buffer(self): def exec_mini_buffer(self):
@ -273,8 +271,8 @@ class Application:
else: else:
assert 0 <= self.active_slot and self.active_slot < len(self.bufferlist.slots), \ assert 0 <= self.active_slot and self.active_slot < len(self.bufferlist.slots), \
"0 <= %d < %d" % (self.active_slot, len(self.bufferlist.slots)) "0 <= %d < %d" % (self.active_slot, len(self.bufferlist.slots))
slotname = self.active_slot i = self.active_slot
return self.bufferlist.slots[slotname].buffer.get_window(slotname) return self.bufferlist.slots[i].window
# buffer handling # buffer handling
def file_buffer(self, path, data, switch_to=True): def file_buffer(self, path, data, switch_to=True):
@ -283,7 +281,7 @@ class Application:
f = open(path, 'w') f = open(path, 'w')
f.write(data) f.write(data)
f.close() f.close()
b = buffer.FileBuffer(path) b = buffer2.FileBuffer(path)
b.open() b.open()
self.add_window_to_buffer(b, self.active_slot) self.add_window_to_buffer(b, self.active_slot)
self.add_buffer(b) self.add_buffer(b)
@ -293,7 +291,7 @@ class Application:
if self.has_buffer_name(name): if self.has_buffer_name(name):
b = self.bufferlist.buffer_names[name] b = self.bufferlist.buffer_names[name]
self.remove_buffer(b) self.remove_buffer(b)
b = buffer.DataBuffer(name, data) b = buffer2.DataBuffer(name, data)
if modename is not None: if modename is not None:
b.modename = modename b.modename = modename
self.add_window_to_buffer(b, self.active_slot) self.add_window_to_buffer(b, self.active_slot)
@ -328,7 +326,7 @@ class Application:
def add_window_to_buffer(self, b, slotname): def add_window_to_buffer(self, b, slotname):
if not b.has_window(slotname): if not b.has_window(slotname):
slot = self.bufferlist.slots[slotname] slot = self.bufferlist.slots[slotname]
window.Window(b, self, height=slot.height, width=slot.width, slot=slotname) window2.Window(b, self, height=slot.height, width=slot.width)
# error string handling # error string handling
def set_error(self, s): def set_error(self, s):
@ -355,16 +353,16 @@ class Application:
y_offset += y + 1 y_offset += y + 1
slot = self.bufferlist.slots[n-1].resize(y_pool, x, y_offset) slot = self.bufferlist.slots[n-1].resize(y_pool, x, y_offset)
def resize_windows(self): def resize_windows(self):
for b in self.bufferlist.buffers: #for slot in
keys = b.windows.keys() pass
for name in keys: # for b in self.bufferlist.buffers:
try: # keys = b.windows.keys()
(height, width) = self.get_window_height_width(name) # for w in b.windows:
b.windows[name].set_size(width, height) # try:
except: # (height, width) = self.get_window_height_width(name)
w = b.windows[name] # b.windows[name].set_size(width, height)
del b.windows[name] # except:
# kill w now # b.windows.remove(w)
# hide the curses cursor # hide the curses cursor
def hide_cursor(self): def hide_cursor(self):
@ -398,12 +396,12 @@ class Application:
# undo/redo # undo/redo
def undo(self): def undo(self):
try: try:
self.window().buffer.undo() self.window().undo()
except Exception, e: except Exception, e:
self.set_error("%s" % (e)) self.set_error("%s" % (e))
def redo(self): def redo(self):
try: try:
self.window().buffer.redo() self.window().redo()
except Exception, e: except Exception, e:
self.set_error("%s" % (e)) self.set_error("%s" % (e))
@ -503,101 +501,38 @@ class Application:
self.draw_slot(i) self.draw_slot(i)
self.draw_status_bar(i) self.draw_status_bar(i)
def draw_slot(self, slotname): def draw_slot(self, i):
slot = self.bufferlist.slots[slotname] #return
if not slot.buffer.has_window(slotname): slot = self.bufferlist.slots[i]
if slot.window is None:
return return
w = slot.buffer.get_window(slotname) w = slot.window
lines = w.visible_lines()
regions = w.mode.visible_regions()
## FIXME: why isn't this always the same????
assert (len(lines) == len(regions) or
len(lines) == len(regions) - 1), "%d,%d" % (len(lines),
len(regions)-1)
assert len(lines) > 0, "no lines... why?"
m = min(len(lines), slot.height)
assert m > 0
x = slot.width
y = slot.height
y_offset = slot.offset
assert x > 0 lines = w.buffer.lines
assert y > 0 count = 0
red_attr = color.build_attr(color.pairs('red', 'default')) (x, y) = w.first.xy()
for i in range(0, m): cursor = w.logical_cursor()
j = 0 (cx, cy) = cursor.xy()
line = lines[i] (px, py) = (None, None)
for r in regions[i]: while count < slot.height:
try: if y >= len(lines):
# start, end, attr, value, ttype = r self.win.addstr(count, 0, '~' + ' ' * (slot.width - 1))
assert 0 <= r.start, "0 <= %d" % (r.start)
assert r.start <= r.end, "%d <= %d" % (r.start, r.end)
assert r.end <= len(line), "%d <= %d" % (r.end, len(line))
except Exception, e:
s = "\n".join([repr(x) for x in regions])
raise Exception, "%s\n%s\n\n%s\n\n%s\n\n%s\n\n%d" % \
(e, s, regions[i], r, repr(line), len(line))
assert line[r.start:r.end] == r.value, \
"%r != %r" % (line[r.start:r.end], r.value)
try:
if DARK_BACKGROUND:
attr = r.attr | curses.A_BOLD
else:
attr = r.attr
self.win.addnstr(i + y_offset, r.start, r.value, r.end - r.start, attr)
except Exception, e:
raise Exception, "%s\n%s %s %s %s" % \
(e, repr(i), repr(r.start), repr(r.value), repr(r.end - r.start))
j = r.end
if j < len(line):
# this is cheating... FIXME
self.win.addnstr(i + y_offset, j, line[j:], len(line) - j)
j += len(line) - j
if j < x:
self.win.addnstr(i + y_offset, j, ' ' * (x-j), (x-j))
if w.continued_visible_line(i):
self.win.addch(i + y_offset, x, '\\', red_attr)
else: else:
self.win.addch(i + y_offset, x, ' ') if cy == y and cx >= x and cx < x + slot.width:
px = cx - x
py = count
line = lines[y]
subline = line[x:x + slot.width]
if len(subline) < slot.width:
subline += ' ' * (slot.width - len(subline))
self.win.addstr(slot.offset + count, 0, line[x:x + slot.width])
for i in range(m, y): if x + slot.width >= len(line):
self.win.addnstr(i + y_offset, 0, '~' + ' ' * (x), x + 1, red_attr) x = 0
y += 1
for (high_w, lp1, lp2) in self.highlighted_ranges:
if lp1.y != lp2.y:
# this region is incoherent, so skip it, or die, whatever
#raise Exception, "haddock %d != %d" % (lp1.y, lp2.y)
pass
elif w is not high_w:
# this region isn't in the current window so skip it
pass
else:
(pp1, pp2) = (w.physical_point(lp1), w.physical_point(lp2))
vo = w.visible_offset()
(vp1, vp2) = (pp1.offset(0, -vo), pp2.offset(0, -vo))
if vp2.y < 0 or vp1.y > w.height:
# this region is not visible, so skip it
pass
else: else:
# first let's fix our points so we're sure they're visible x += slot.width
if vp1.y < 0: count += 1
vp1 = point.Point(0,0)
if vp2.y > w.height:
vp2 = point.Point(len(lines[-1]), w.height-1)
if vp1.y == vp2.y:
# our region physically fits on one line; this is easy
b = lines[vp1.y][vp1.x:vp2.x]
self.win.addstr(vp1.y + y_offset, vp1.x, b, curses.A_REVERSE)
else:
# our region spans multiple physical lines, so deal
b1 = lines[vp1.y][vp1.x:]
self.win.addstr(vp1.y + y_offset, vp1.x, b1, curses.A_REVERSE)
for i in range(vp1.y + 1, vp2.y):
b = lines[i]
self.wind.addstr(i + y_offset, 0, b, curses.A_REVERSE)
b2 = lines[vp2.y][:vp2.x]
self.win.addstr(vp2.y + y_offset, 0, b2, curses.A_REVERSE)
if self.margins_visible: if self.margins_visible:
for (limit, shade) in self.margins: for (limit, shade) in self.margins:
@ -606,44 +541,42 @@ class Application:
# the actual character is the lower 8 bits, and the # the actual character is the lower 8 bits, and the
# attribute is the upper 8 bits; we will ignore the # attribute is the upper 8 bits; we will ignore the
# attribute and just get the character # attribute and just get the character
char = self.win.inch(i + y_offset, limit) & 255 char = self.win.inch(i + slot.offset, limit) & 255
attr = color.build('default', shade, 'bold') attr = color.build('default', shade, 'bold')
self.win.addch(i + y_offset, limit, char, attr) self.win.addch(i + slot.offset, limit, char, attr)
if self.mini_active is False and self.active_slot == slotname: if self.mini_active is False and self.active_slot == i:
if w.active_point is not None and w.point_is_visible(w.active_point): if False and w.active_point is not None and w.point_is_visible(w.active_point):
pa = w.physical_point(w.active_point) pa = w.physical_point(w.active_point)
va = pa.offset(0, -w.visible_offset()) va = pa.offset(0, -w.visible_offset())
if len(lines[va.y]): if len(lines[va.y]):
a = lines[va.y][va.x] a = lines[va.y][va.x]
else: else:
a = ' ' a = ' '
self.win.addch(va.y + y_offset, va.x, a, curses.A_REVERSE) self.win.addch(va.y + slot.offset, va.x, a, curses.A_REVERSE)
else: else:
cursor = w.visible_cursor() assert px is not None and py is not None
cx, cy = (cursor.x, cursor.y)
if cy >= len(lines): if cy >= len(lines):
self.set_error('in main1: cursor error; %d >= %d' % self.set_error('in main1: cursor error; %d >= %d' % (cy, len(lines)))
(cy, len(lines)))
return return
elif cx == len(lines[cy]): elif cx == len(lines[cy]):
c = ' ' c = ' '
elif cx > len(lines[cy]): elif px > len(lines[cy]):
self.set_error('why? %r %r' % (cursor, len(lines[cy]))) self.set_error('why? %r %r' % (cx, len(lines[cy])))
return return
else: else:
c = lines[cy][cx] c = lines[cy][cx]
self.win.addch(cy + y_offset, cx, c, curses.A_REVERSE) self.win.addch(slot.offset + py , px, c, curses.A_REVERSE)
def draw_status_bar(self, slotname): def draw_status_bar(self, slotname):
slot = self.bufferlist.slots[slotname] slot = self.bufferlist.slots[slotname]
if not slot.buffer.has_window(slotname): if slot.window is None:
return return
w = slot.buffer.get_window(slotname) w = slot.window
b = w.buffer b = w.buffer
cursor = w.logical_cursor() cursor = w.logical_cursor()
pcursor = w.physical_cursor()
first = w.first first = w.first
last = w.last last = w.last
@ -661,7 +594,7 @@ class Application:
if w.mark: if w.mark:
mark = w.mark mark = w.mark
else: else:
mark = point.Point(-1, -1) mark = Point(-1, -1)
name = b.name() name = b.name()
if w.first_is_visible(): if w.first_is_visible():
@ -673,8 +606,10 @@ class Application:
# XYZ: we should actually use more of the 'state' variables # XYZ: we should actually use more of the 'state' variables
format = "----:%s-Fl %-18s (%s)--L%d--C%d--%s" #format = "----:%s-Fl %-18s (%s)--L%d--C%d--%s"
status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, perc) #status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, perc)
format = "----:%s-Fl %-18s (%s)--L%d--C%d--%s--%s--%s"
status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, w.first, w.last, perc)
status = status[:slot.width + 1] status = status[:slot.width + 1]
status += "-" * (slot.width - len(status) + 1) status += "-" * (slot.width - len(status) + 1)
self.win.addnstr(slot.height + slot.offset, 0, status, slot.width + 1, self.win.addnstr(slot.height + slot.offset, 0, status, slot.width + 1,
@ -729,11 +664,11 @@ class Application:
def open_aes_file(path, nl, name=None): def open_aes_file(path, nl, name=None):
p = getpass.getpass("Please enter the AES password: ") p = getpass.getpass("Please enter the AES password: ")
b = buffer.AesBuffer(path, p, nl, name) b = buffer2.AesBuffer(path, p, nl, name)
return b return b
def open_plain_file(path, nl, name=None): def open_plain_file(path, nl, name=None):
b = buffer.FileBuffer(path, nl, name) b = buffer2.FileBuffer(path, nl, name)
return b return b
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,66 +1,105 @@
import sets import sets
class Slot: class Slot:
def __init__(self, height, width, offset, buffer=None): def __init__(self, height, width, offset):
self.height = height self.height = height
self.width = width self.width = width
self.offset = offset self.offset = offset
self.buffer = buffer self.window = None
self.resize(height, width, offset)
def is_empty(self): def is_empty(self):
return self.buffer is None return self.window is None
def resize(self, height, width, offset): def resize(self, height, width, offset):
self.height = height self.height = height
self.width = width self.width = width
self.offset = offset self.offset = offset
# possible callbacks if self.window is not None:
def remove(self): self.window.set_size(self.width, self.height)
# possible callbacks def set(self, w):
pass self.window = w
w.set_size(self.width, self.height)
def unset(self):
if not self.is_empty():
old_w = self.window
self.window = None
return old_w
else:
return None
class BufferList: class BufferList:
def __init__(self, height, width, buffers=()): def __init__(self, height, width, buffers=()):
self.slots = [] self.height = height
self.add_slot(height, width, 0) self.width = width
self.buffers = sets.Set()
self.buffers = sets.Set() self.buffer_names = {}
self.buffer_names = {}
self.hidden_buffers = [] self.hidden_buffers = []
self.slots = []
self.add_slot()
self.fit_slots()
for b in buffers: for b in buffers:
self.add_buffer(b) self.add_buffer(b)
def fit_slots(self):
heights = [self.height / len(self.slots)] * len(self.slots)
for i in range(0, self.height % len(self.slots)):
heights[i] += 1
offsets = [0]
for i in range(1, len(self.slots)):
offsets.insert(i, offsets[i - 1] + heights[i - 1])
for i in range(0, len(self.slots)):
self.slots[i].resize(heights[i], self.width, offsets[i])
def resize(self, height, width):
self.height = height
self.width = width
self.fit_slots()
def is_window_visible(self, w):
for slot in self.slots:
if w is slot.window:
return True
return False
def is_buffer_visible(self, b):
for slot in self.slots:
if slot.window is not None and b is slot.window.buffer:
return True
return False
# manipulate slots # manipulate slots
def add_slot(self, height, width, offset=0, buffer=None): def add_slot(self):
self.slots.append(Slot(height, width, offset, buffer)) self.slots.append(Slot(self.height, self.width, 0))
self.fit_slots()
return len(self.slots) - 1 return len(self.slots) - 1
def empty_slot(self, i): def empty_slot(self, i):
assert i > -1 and i < len(self.slots), "slot %d does not exist" % i assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
return self.slots[i].is_empty() return self.slots[i].is_empty()
def unset_slot(self, i):
assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
old_w = self.slots[i].unset()
if old_w is not None:
old_b = old_w.buffer
if not self.is_buffer_visible(old_b):
self.hidden_buffers.insert(0, old_b)
if len(old_b.windows) > 1:
old_b.remove_window(old_w)
def set_slot(self, i, b): def set_slot(self, i, b):
assert i > -1 and i < len(self.slots), "slot %d does not exist" % i assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
assert b in self.buffers, "buffer %s does not exist" % (b.name()) assert b in self.buffers, "buffer %s does not exist" % (b.name())
self.unset_slot(i)
if b in self.hidden_buffers: if b in self.hidden_buffers:
self.hidden_buffers.remove(b) self.hidden_buffers.remove(b)
if not self.slots[i].is_empty(): if self.is_window_visible(b.windows[0]):
b2 = self.slots[i].buffer app = b.windows[0].application
self.hidden_buffers.insert(0, b2) w = window2.Window(b, app, height=slot.height, width=slot.width)
self.slots[i].buffer = b else:
w = b.windows[0]
self.slots[i].set(w)
def remove_slot(self, i): def remove_slot(self, i):
assert i > -1 and i < len(self.slots), "slot %d does not exist" % i assert i > -1 and i < len(self.slots), "slot %d does not exist" % i
if not self.slots[i].is_empty(): self.unset_slot(i)
b = self.slots[i].buffer
self.hidden_buffers.insert(0, b)
self.slots[i].remove()
del self.slots[i] del self.slots[i]
self.fit_slots()
# now fix the stored slot numbers for all the
for b in self.buffers:
for j in range(i, len(self.slots)):
if b.has_window(j+1):
w = b.get_window(j+1)
del b.windows[j+1]
w.slot = j
b.windows[j] = w
# add/remove buffers # add/remove buffers
def add_buffer(self, b): def add_buffer(self, b):
@ -68,9 +107,6 @@ class BufferList:
self.buffers.add(b) self.buffers.add(b)
self.buffer_names[b.name()] = b self.buffer_names[b.name()] = b
self.hidden_buffers.append(b) self.hidden_buffers.append(b)
for i in range(0, len(self.slots)):
if self.empty_slot(i):
self.set_slot(i, b)
def has_buffer(self, b): def has_buffer(self, b):
return b in self.buffers return b in self.buffers
def has_buffer_name(self, name): def has_buffer_name(self, name):
@ -84,9 +120,10 @@ class BufferList:
return None return None
def remove_buffer(self, b): def remove_buffer(self, b):
assert b in self.buffers, "buffer %s does not exist" % (b.name()) assert b in self.buffers, "buffer %s does not exist" % (b.name())
for slot in self.slots: for i in range(0, len(self.slots)):
if slot.buffer is b: slot = self.slots[i]
slot.buffer = None if self.slots[i].window is not None and self.slots[i].window.buffer is b:
self.unset_slot(i)
self.buffers.remove(b) self.buffers.remove(b)
del self.buffer_names[b.name()] del self.buffer_names[b.name()]
if b in self.hidden_buffers: if b in self.hidden_buffers:
@ -96,9 +133,9 @@ class BufferList:
def is_buffer_hidden(self, b): def is_buffer_hidden(self, b):
assert b in self.buffers, "buffer %s does not exist" % (b.name()) assert b in self.buffers, "buffer %s does not exist" % (b.name())
return b in self.hidden_buffers return b in self.hidden_buffers
def is_buffer_visible(self, b): # def is_buffer_visible(self, b):
assert b in self.buffers, "buffer %s does not exist" % (b.name()) # assert b in self.buffers, "buffer %s does not exist" % (b.name())
for slot in self.slots: # for slot in self.slots:
if slot.buffer is b: # if slot.buffer is b:
return True # return True
return False # return False

View File

@ -4,7 +4,7 @@ import lex2
color_list = [] color_list = []
color_list.extend(['\033[3%dm' % x for x in range(0, 8)]) color_list.extend(['\033[3%dm' % x for x in range(0, 8)])
color_list.extend(['\033[3%d;1m' % x for x in range(0, 8)]) color_list.extend(['\033[3%d;1m' % x for x in range(0, 8)])
color_list.append('\033[0m') color_list.extend(['\033[0m'])
color_names = [ color_names = [
'black', 'dred', 'dgreen', 'brown', 'dblue', 'dpurple', 'dcyan', 'lgrey', 'black', 'dred', 'dgreen', 'brown', 'dblue', 'dpurple', 'dcyan', 'lgrey',
@ -158,7 +158,7 @@ class Highlighter:
tx2 = token.x + len(token.string) tx2 = token.x + len(token.string)
# the notation "*|*| " refers to what the text spans, i.e.: # the notation "*|*| " refers to what the text spans, i.e.:
# before|during|after # before|during|after the deletion
if (y, tx2) <= (y1, x1): if (y, tx2) <= (y1, x1):
# *| | # *| |
newtokens[y].append(token) newtokens[y].append(token)

View File

@ -336,7 +336,7 @@ class InsertString(Method):
self.help = "Insert %r into the current buffer." % s self.help = "Insert %r into the current buffer." % s
self.string = s self.string = s
def _execute(self, window, **vargs): def _execute(self, window, **vargs):
window.insert_string(self.string) window.insert_string_at_cursor(self.string)
# killing/copying/etc. # killing/copying/etc.
class Kill(Method): class Kill(Method):
@ -487,18 +487,18 @@ class SwitchMark(Method):
class InsertNewline(Method): class InsertNewline(Method):
'''Insert newline into buffer at the cursor''' '''Insert newline into buffer at the cursor'''
def _execute(self, window, **vargs): def _execute(self, window, **vargs):
window.insert_string('\n') window.insert_string_at_cursor('\n')
class InsertSpace(Method): class InsertSpace(Method):
'''Insert space into buffer at the cursor''' '''Insert space into buffer at the cursor'''
def _execute(self, window, **vargs): def _execute(self, window, **vargs):
window.insert_string(' ') window.insert_string_at_cursor(' ')
class InsertTab(Method): class InsertTab(Method):
'''Insert tab into buffer, or tabbify line, depending on mode''' '''Insert tab into buffer, or tabbify line, depending on mode'''
def _execute(self, window, **vargs): def _execute(self, window, **vargs):
cursor = window.logical_cursor() cursor = window.logical_cursor()
i = window.mode.get_indentation_level(cursor.y) i = window.mode.get_indentation_level(cursor.y)
if i is None: if i is None:
window.insert_string(' ') window.insert_string_at_cursor(' ')
else: else:
j = window.buffer.count_leading_whitespace(cursor.y) j = window.buffer.count_leading_whitespace(cursor.y)
if i != j: if i != j:
@ -541,7 +541,7 @@ class CommentRegion(Method):
window.input_line = "Empty kill region" window.input_line = "Empty kill region"
return return
for y in range(p1.y, p2.y): for y in range(p1.y, p2.y):
window.buffer.insert_string(point.Point(0, y), "#") window.buffer.insert_string_at_cursor(point.Point(0, y), "#")
class UncommentRegion(Method): class UncommentRegion(Method):
'''Remove a comment from every line in the current buffer''' '''Remove a comment from every line in the current buffer'''
def _execute(self, w, **vargs): def _execute(self, w, **vargs):
@ -582,7 +582,7 @@ class WrapLine(Method):
old_cursor.y += 1 old_cursor.y += 1
window.goto(point.Point(j, i)) window.goto(point.Point(j, i))
window.right_delete() window.right_delete()
window.insert_string('\n') window.insert_string_at_cursor('\n')
i += 1 i += 1
l = len(window.buffer.lines[old_cursor.y]) l = len(window.buffer.lines[old_cursor.y])
@ -627,7 +627,7 @@ class JustifyRight(Method):
if i >= len(prev_line): if i >= len(prev_line):
return return
s = ' ' * (i - cursor.x) s = ' ' * (i - cursor.x)
window.insert_string(s) window.insert_string_at_cursor(s)
class JustifyLeft(Method): class JustifyLeft(Method):
'''Justify text with the previous line left from the cursor by whitespace''' '''Justify text with the previous line left from the cursor by whitespace'''
def _execute(self, window, **vargs): def _execute(self, window, **vargs):
@ -767,7 +767,7 @@ class UnindentBlock(Method):
if lines[i].startswith(' '): if lines[i].startswith(' '):
lines[i] = lines[i][4:] lines[i] = lines[i][4:]
w.buffer.delete_string(point.Point(0, p1.y), point.Point(0, p2.y)) w.buffer.delete_string(point.Point(0, p1.y), point.Point(0, p2.y))
w.buffer.insert_string(point.Point(0, p1.y), '\n'.join(lines) + '\n') w.buffer.insert_string_at_cursor(point.Point(0, p1.y), '\n'.join(lines) + '\n')
class IndentBlock(Method): class IndentBlock(Method):
'''Add 4 spaces to each line in region''' '''Add 4 spaces to each line in region'''
def _execute(self, w, **vargs): def _execute(self, w, **vargs):
@ -785,7 +785,7 @@ class IndentBlock(Method):
for i in range(0, len(lines)): for i in range(0, len(lines)):
lines[i] = ' ' + lines[i] lines[i] = ' ' + lines[i]
w.buffer.delete_string(point.Point(0, p1.y), point.Point(0, p2.y)) w.buffer.delete_string(point.Point(0, p1.y), point.Point(0, p2.y))
w.buffer.insert_string(point.Point(0, p1.y), '\n'.join(lines) + '\n') w.buffer.insert_string_at_cursor(point.Point(0, p1.y), '\n'.join(lines) + '\n')
class CodeComplete(Method): class CodeComplete(Method):
'''Complete based on tokenized strings''' '''Complete based on tokenized strings'''
@ -830,7 +830,7 @@ class CodeComplete(Method):
pass pass
elif sofar: elif sofar:
w.buffer.delete_string(p1, p2) w.buffer.delete_string(p1, p2)
w.buffer.insert_string(p1, sofar) w.buffer.insert_string_at_cursor(p1, sofar)
if num_seen == 1: if num_seen == 1:
w.application.set_error('Unique!') w.application.set_error('Unique!')
else: else:
@ -1279,7 +1279,7 @@ class CloseTag(Method):
def _execute(self, w, **vargs): def _execute(self, w, **vargs):
# if w.mode doesn't do tag matching, just insert the character return # if w.mode doesn't do tag matching, just insert the character return
if not w.mode.tag_matching: if not w.mode.tag_matching:
w.insert_string(self.mytag) w.insert_string_at_cursor(self.mytag)
return return
# first, de-reference some variables and actually do the insertion # first, de-reference some variables and actually do the insertion
@ -1289,7 +1289,7 @@ class CloseTag(Method):
buffer = w.buffer buffer = w.buffer
#cursor = w.physical_cursor() #cursor = w.physical_cursor()
tag_stack = [] tag_stack = []
w.insert_string(self.mytag) w.insert_string_at_cursor(self.mytag)
cursor = w.physical_cursor() cursor = w.physical_cursor()
assert cursor.x > 0, "my assumptions made an ass out of u and me" assert cursor.x > 0, "my assumptions made an ass out of u and me"

View File

@ -3,7 +3,8 @@ import sets, string
import color, default, highlight, method, point import color, default, highlight, method, point
DEBUG = False #DEBUG = False
DEBUG = True
class Handler: class Handler:
def __init__(self): def __init__(self):
@ -191,8 +192,6 @@ class Fundamental(Handler):
self.window.application.set_error(err) self.window.application.set_error(err)
def invalidate(self): def invalidate(self):
if self.tabber is not None:
self.tabber.invalidate()
if self.lexer is not None: if self.lexer is not None:
self.highlighter.invalidate_regions() self.highlighter.invalidate_regions()
@ -212,20 +211,13 @@ class Fundamental(Handler):
regions = self.get_regions() regions = self.get_regions()
return regions[i:i+self.window.height] return regions[i:i+self.window.height]
def region_added(self, p, xdiff, ydiff, s): def region_added(self, p, newlines):
if self.lexer is not None: if self.lexer is not None:
if self.tabber is not None and s != ' ' and s != ' ': self.highlighter.relex_add(lines, p.y, p.x, newlines)
self.tabber.invalidate()
self.highlighter.region_added(p, xdiff, ydiff, s)
def region_removed(self, p1, p2, s): def region_removed(self, p1, p2):
if self.lexer is not None: if self.lexer is not None:
if self.tabber is not None: self.highlighter.relex_del(lines, p1, p2)
self.tabber.invalidate()
self.highlighter.region_removed(p1, p2, s)
def get_indentation_level(self, y): def get_indentation_level(self, y):
if self.tabber is None: return None
return None
else:
return self.tabber.get_indentation_level(y)