completion buffers huzzah!!

--HG--
branch : pmacs2
This commit is contained in:
moculus 2008-05-04 02:41:58 +00:00
parent b9d304e2c7
commit dddfa7a347
6 changed files with 141 additions and 15 deletions

View File

@ -143,6 +143,7 @@ class Application(object):
# buffer list stuff # buffer list stuff
self.bufferlist = bufferlist.BufferList(height, width) self.bufferlist = bufferlist.BufferList(height, width)
self.active_slot = 0 self.active_slot = 0
self.complete_slot = None
# run user custom code here # run user custom code here
self.rcerror = None self.rcerror = None
@ -199,6 +200,70 @@ class Application(object):
curses.nonl() curses.nonl()
curses.def_prog_mode() curses.def_prog_mode()
def completion_window_is_open(self):
n = self.complete_slot
if n is None:
pass
elif n >= len(self.bufferlist.slots):
self.complete_slot = None
elif self.bufferlist.slots[n].window is None:
self.complete_slot = None
elif not hasattr(self.bufferlist.slots[n].window.buffer, '_completion'):
self.complete_slot = None
else:
return True
return False
def get_completion_window(self):
return self.bufferlist.slots[self.complete_slot].window
def open_completion_buffer(self, s, candidates):
opened = False
previous = None
if len(self.bufferlist.slots) == 1:
self.add_slot()
opened = True
n = len(self.bufferlist.slots) - 1
if self.active_slot == n:
n -= 1
if not opened:
previous = self.bufferlist.slots[n].window.buffer
lines = ["This is a completion buffer:", ""]
if len(candidates) > self.bufferlist.slots[n].height:
m = len(candidates) - (len(candidates) // 2)
mlen = 0
for c in candidates[:m]:
mlen = max(mlen, len(c))
for i in range(0, m):
if m + i < len(candidates):
c1, c2 = candidates[i * 2], candidates[i * 2 + 1]
lines.append("%-*s %-s" % (mlen, c1, c2))
else:
lines.append(candidates[i * 2])
else:
lines = list(candidates)
data = '\n'.join(lines)
b = self.data_buffer("*Completions*", data, switch_to=False)
b._completion = s
b._opened = opened
b._previous = previous
self.bufferlist.set_slot(n, b)
self.complete_slot = n
def close_completion_buffer(self):
w = self.get_completion_window()
opened = w.buffer._opened
if opened:
self.bufferlist.remove_slot(self.complete_slot)
else:
self.bufferlist.set_slot(self.complete_slot, w.buffer._previous)
self.close_buffer(w.buffer)
self.complete_slot = None
def set_completer(self, datatype, completer): def set_completer(self, datatype, completer):
method.DATATYPES[datatype] = completer method.DATATYPES[datatype] = completer
@ -246,6 +311,17 @@ class Application(object):
return (slot.height, slot.width) return (slot.height, slot.width)
# files and stuff # files and stuff
def close_buffer(self, b):
self.bufferlist.remove_buffer(b)
b.close()
active_slot = self.bufferlist.slots[self.active_slot]
for i in range(0, len(self.bufferlist.slots)):
if self.bufferlist.slots[i].is_empty():
if self.bufferlist.hidden_buffers:
self.bufferlist.set_slot(i, self.bufferlist.hidden_buffers[0])
else:
self.bufferlist.set_slot(i, active_slot.window.buffer)
def open_path(self, path, binary=False, cipher=None, password=None): def open_path(self, path, binary=False, cipher=None, password=None):
path = os.path.abspath(os.path.realpath(util.expand_tilde(path))) path = os.path.abspath(os.path.realpath(util.expand_tilde(path)))
b = self.get_buffer_by_path(path) b = self.get_buffer_by_path(path)
@ -369,6 +445,7 @@ class Application(object):
self.add_buffer(b) self.add_buffer(b)
if switch_to: if switch_to:
self.switch_buffer(b) self.switch_buffer(b)
return b
def color_data_buffer(self, name, data, switch_to=True, modename='colortext'): def color_data_buffer(self, name, data, switch_to=True, modename='colortext'):
if self.has_buffer_name(name): if self.has_buffer_name(name):
b = self.bufferlist.buffer_names[name] b = self.bufferlist.buffer_names[name]

View File

@ -125,6 +125,11 @@ class BufferList(object):
if hasattr(b, 'path') and b.path == path: if hasattr(b, 'path') and b.path == path:
return b return b
return None return None
def close_buffer(self, b):
for i in range(0, len(self.slots)):
slot = self.slots[i]
if self.slots[i].window is not None and self.slots[i].window.buffer is b:
self.unset_slot(i)
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 i in range(0, len(self.slots)): for i in range(0, len(self.slots)):

View File

@ -809,6 +809,8 @@ class Cancel(Method):
'''Cancel command in-progress, and return to the main buffer''' '''Cancel command in-progress, and return to the main buffer'''
def execute(self, w, **vargs): def execute(self, w, **vargs):
w.application.close_mini_buffer() w.application.close_mini_buffer()
if w.application.completion_window_is_open():
w.application.close_completion_buffer()
w.set_error('Cancel') w.set_error('Cancel')
class SplitWindow(Method): class SplitWindow(Method):

View File

@ -70,10 +70,7 @@ class KillBuffer(Method):
def _doit(self): def _doit(self):
a = self._old_window.application a = self._old_window.application
b = self._to_kill b = self._to_kill
if a.bufferlist.is_buffer_visible(b): a.close_buffer(b)
a.bufferlist.set_slot(a.active_slot, a.bufferlist.hidden_buffers[0])
a.bufferlist.remove_buffer(b)
b.close()
def _callback(self, v): def _callback(self, v):
a = self._old_window.application a = self._old_window.application
if v == 'yes': if v == 'yes':

View File

@ -1,25 +1,70 @@
import method, mode import string
import buffer, method, mode, window
class MiniInsertString(method.InsertString):
_is_method = False
def __init__(self, s):
method.InsertString.__init__(self, s)
self.name = "mini-insert-string-%s" % s
def _execute(self, w, **vargs):
try:
app = w.application
w.insert_string_at_cursor(self.string)
if app.completion_window_is_open():
app.close_completion_buffer()
except buffer.ReadOnlyError:
w.set_error('Buffer is read-only')
class MiniInsertSpace(method.Method):
def _execute(self, w, **vargs):
try:
app = w.application
w.insert_string_at_cursor(' ')
if app.completion_window_is_open():
app.close_completion_buffer()
except buffer.ReadOnlyError:
w.set_error('Buffer is read-only')
class MiniCallback(method.Method): class MiniCallback(method.Method):
def execute(self, window, **vargs): def execute(self, w, **vargs):
window.buffer.do_callback() app = w.application
if app.completion_window_is_open():
app.close_completion_buffer()
w.buffer.do_callback()
class MiniTabComplete(method.Method): class MiniTabComplete(method.Method):
def execute(self, window, **vargs): def execute(self, w, **vargs):
b = window.buffer app = w.application
b = w.buffer
if b.tabber is None: if b.tabber is None:
window.application.set_error("No tab completion") w.application.set_error("No tab completion")
return return
s1 = b.make_string() s1 = b.make_string()
s2, exists, complete = b.tabber.tab_string(s1, window) s2, exists, complete = b.tabber.tab_string(s1, w)
b.set_data(s2) b.set_data(s2)
if app.completion_window_is_open():
w2 = app.get_completion_window()
if w2.last_is_visible():
w2.goto_beginning()
else:
w2.page_down()
else:
candidates = sorted(b.tabber.get_candidates(s1))
if len(candidates) > 1:
app.open_completion_buffer(s2, candidates)
class Mini(mode.Fundamental): class Mini(mode.Fundamental):
modename = 'Mini' modename = 'Mini'
actions = [MiniCallback, MiniTabComplete] actions = [MiniCallback, MiniTabComplete, MiniInsertSpace]
def __init__(self, w): def __init__(self, w):
mode.Fundamental.__init__(self, w) mode.Fundamental.__init__(self, w)
self.add_bindings('mini-callback', ('RETURN',)) self.add_bindings('mini-callback', ('RETURN',))
self.add_bindings('mini-tab-complete', ('TAB',)) self.add_bindings('mini-tab-complete', ('TAB',))
# create all the insert actions for the basic text input
for c in string.letters + string.digits + string.punctuation:
self.add_action_and_bindings(MiniInsertString(c), (c,))
self.add_bindings('mini-insert-space', ('SPACE',))
install = Mini.install install = Mini.install

View File

@ -73,7 +73,7 @@ def find(r, w, move=False, direction='next', start=None, end=None):
break break
if newc: if newc:
w.goto(newc[0]) w.goto(newc[0])
else: elif ranges:
i = 0 i = 0
if direction == 'next': if direction == 'next':
i = -1 i = -1