Permalink
Browse files

Replace bloody GtkSourceCompletion with an uxie one

  • Loading branch information...
baverman committed Nov 27, 2011
1 parent e48fadf commit b6f711ae6027a4d9ba271d76c0bdb836cca85c18
View
@@ -0,0 +1,98 @@
+from bisect import bisect
+import gtk
+
+from uxie.complete import TextViewCompleter
+
+completer = None
+
+def init(injector):
+ injector.bind('textview-active', 'complete', 'Edit/Complete', complete)
+
+def complete(textview):
+ if not hasattr(textview, 'completer'):
+ textview.get_toplevel().message('Where is your attached completer now?',
+ 'warn', parent=textview)
+ return
+
+ textview.completer.complete(textview)
+
+def add_completion_provider(buf, provider, priority=None):
+ if priority is None:
+ priority = 0
+
+ value = (-priority, provider)
+ if not hasattr(buf, 'completion_providers'):
+ buf.completion_providers = []
+
+ buf.completion_providers.insert(bisect(buf.completion_providers, value), value)
+
+def create_completer():
+ model = gtk.ListStore(object, str, object, bool) # provider, match, object, selection
+ view = gtk.TreeView(model)
+ view.set_headers_visible(False)
+ view.append_column(gtk.TreeViewColumn('None', gtk.CellRendererText(),
+ markup=1, sensitive=3))
+
+ view.get_selection().set_select_function(lambda info: model[info[0]][3])
+
+ return TextViewCompleter(view)
+
+def get_completer():
+ global completer
+ if not completer:
+ completer = create_completer()
+
+ return completer
+
+def fill_callback(view, textview, check, providers=None, it=None):
+ buf = textview.get_buffer()
+ model = view.get_model()
+ model.clear()
+
+ is_interactive = it is None
+
+ it = it or buf.get_iter_at_mark(buf.get_insert())
+ providers = providers or (r[1] for r in buf.completion_providers)
+ provider_iters = []
+ for provider in providers:
+ if is_interactive:
+ ctx = provider.is_match(it.copy())
+ else:
+ ctx = it.copy()
+
+ if ctx is not None:
+ is_any_items = False
+ for name, obj in provider.complete(ctx, is_interactive):
+ next(check)
+ start_iter = model.append((provider, name, obj, True))
+ if not is_any_items:
+ provider_iters.append((provider, start_iter))
+ is_any_items = True
+
+ if len(provider_iters) > 1:
+ for p, it in provider_iters:
+ model.insert_before(it, (None, '<b>%s</b>' % p.get_name(), None, False))
+
+def activate_callback(view, path, textview, is_final):
+ if is_final:
+ provider, _, obj = tuple(view.get_model()[path])[:3]
+ provider.activate(textview, obj)
+
+def attach_completer(textview):
+ completer = get_completer()
+ completer.attach(textview, fill_callback, activate_callback)
+ textview.completer = completer
+
+
+class Provider(object):
+ def is_match(self, it):
+ return None
+
+ def complete(self, ctx, is_interactive):
+ return []
+
+ def get_name():
+ return 'Unknown'
+
+ def activate(self, textview, obj):
+ pass
@@ -31,6 +31,7 @@ def create_widget(editor):
widget.completion = EntryCompleter(create_simple_complete_view())
widget.completion.attach(entry, fill_func, activate_func)
+ widget.completion.pass_enter_key = True
widget.entry = entry
@@ -50,11 +51,6 @@ def on_entry_activate(entry, editor, widget):
hide(editor, widget)
editor.window.open_or_activate(filename)
-def on_entry_changed(entry, model):
- path = os.path.dirname(entry.get_text())
- if path != model.last_path:
- fill_model(model, path, entry)
-
def get_pos(entry):
try:
start, end = entry.get_selection_bounds()
@@ -71,39 +67,32 @@ def fill_func(view, entry, check):
model = view.get_model()
model.clear()
- view.set_model(None)
dirs = []
files = []
- for p in os.listdir(root):
- if not next(check, False):
- return
+ try:
+ for p in os.listdir(root):
+ next(check)
- if p.startswith(key):
- if os.path.isdir(os.path.join(root, p)):
- dirs.append(p + '/')
- else:
- files.append(p)
+ if p.startswith(key):
+ if os.path.isdir(os.path.join(root, p)):
+ dirs.append(p + '/')
+ else:
+ files.append(p)
+ except OSError:
+ pass
for p in sorted(dirs) + sorted(files):
model.append((p,))
- view.set_model(model)
-
- completer = view.get_toplevel()
- if not len(model):
- idle(completer.popdown, entry)
- else:
- view.set_cursor((0,))
- view.get_selection().unselect_all()
- completer.set_position(entry)
+ #view.get_selection().unselect_all()
def activate_func(view, path, entry, is_final):
- pos = get_pos(entry)
- root, key = get_key(entry)
- if root[-1] != '/':
- root += '/'
-
if is_final:
+ pos = get_pos(entry)
+ root, key = get_key(entry)
+ if root[-1] != '/':
+ root += '/'
+
entry.set_text(root + view.get_model()[path][0])
entry.set_position(-1)
idle(entry.emit, 'changed')
View
@@ -1,5 +1,4 @@
import os.path
-import weakref
import gtk
import gtksourceview2
@@ -24,6 +23,7 @@
import snaked.core.console
import snaked.core.spot
import snaked.core.monitor
+import snaked.core.completer
prefs.add_option('RESTORE_POSITION', True, 'Restore snaked windows position')
prefs.add_option('CONSOLE_FONT', 'Monospace 8', 'Font used in console panel')
@@ -48,6 +48,7 @@
keymap.map_generic('prev', '<ctrl>Up', 1)
keymap.map_generic('next', '<ctrl>Down', 1)
+keymap.map_generic('complete', '<ctrl>space', 1)
keymap.map_generic('goto-definition', 'F3')
keymap.map_generic('show-outline', '<ctrl>o')
keymap.map_generic('show-calltip', '<ctrl>Return', 1)
@@ -109,6 +110,7 @@ def __init__(self, session):
self.plugin_manager.add_plugin(snaked.core.console)
self.plugin_manager.add_plugin(snaked.core.spot)
self.plugin_manager.add_plugin(snaked.core.monitor)
+ self.plugin_manager.add_plugin(snaked.core.completer)
self.spot_manager = snaked.core.spot.Manager()
@@ -179,7 +181,7 @@ def open(self, filename, line=None, contexts=None):
idle(self.plugin_manager.ready, 'editor-with-new-buffer', editor)
- self.plugin_manager.ready('editor', editor)
+ idle(self.plugin_manager.ready, 'editor', editor)
return editor
def open_or_activate(self, uri, window=None, line=None):
@@ -1,13 +1,10 @@
import textwrap
import weakref
+from glib import markup_escape_text
-import gtk
-from gtksourceview2 import CompletionProvider, CompletionProposal
-from gtksourceview2 import COMPLETION_ACTIVATION_USER_REQUESTED
+from snaked.core.completer import Provider
-import gobject
-from glib import markup_escape_text
def pangonify_rst(text):
result = ''
@@ -61,58 +58,17 @@ def add_paragraph():
return result
-class Proposal(gobject.GObject, CompletionProposal):
- def __init__(self, proposal):
- gobject.GObject.__init__(self)
- self.proposal = proposal
-
- def do_get_label(self):
- return self.proposal
-
- def do_get_text(self):
- return self.proposal
-
- #def do_get_info(self):
- # info = self.proposal.get_doc()
- # if info:
- # return pangonify_rst(info)
- # else:
- # return ''
-
-class RopeCompletionProvider(gobject.GObject, CompletionProvider):
+class RopeCompletionProvider(Provider):
def __init__(self, plugin):
- gobject.GObject.__init__(self)
self.plugin = weakref.ref(plugin)
- self.info_widget = gtk.ScrolledWindow()
- self.info_widget.set_size_request(400, 300)
- self.info_widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- label = gtk.Label()
- label.set_alignment(0, 0)
- label.set_line_wrap(False)
- self.info_widget.add_with_viewport(label)
- self.info_widget.label = label
- self.info_widget.show_all()
-
- def do_get_name(self):
- return 'python'
- def do_get_priority(self):
- return 100
-
- def do_set_priority(self):
- pass
-
- def do_get_activation(self):
- return COMPLETION_ACTIVATION_USER_REQUESTED
-
- #def do_get_info_widget(self, proposal):
- # self.info_widget.label.set_markup(proposal.get_info())
- # return self.info_widget
+ def get_name(self):
+ return 'python'
- def do_update_info(self, proposal, info):
- info.get_widget().label.set_markup(proposal.get_info())
+ def is_match(self, it):
+ return it
- def do_populate(self, context):
+ def complete(self, it, is_interactive):
env = self.plugin().env
root = self.plugin().project_path
try:
@@ -122,14 +78,22 @@ def do_populate(self, context):
import traceback
traceback.print_exc()
self.plugin().editor.message(str(e), 'error', 5000)
- context.add_proposals(self, [], True)
return
if proposals:
- context.add_proposals(self, [Proposal(p) for p in proposals], True)
+ for r in proposals:
+ yield r, (r, match)
else:
- context.add_proposals(self, [], True)
self.plugin().editor.message("Can't assist")
+ return
+
+ def activate(self, textview, (proposal, match)):
+ buf = textview.get_buffer()
-gobject.type_register(RopeCompletionProvider)
-gobject.type_register(Proposal)
+ buf.begin_user_action()
+ cursor = buf.get_iter_at_mark(buf.get_insert())
+ start = cursor.copy()
+ start.backward_chars(len(match))
+ buf.delete(start, cursor)
+ buf.insert_at_cursor(proposal)
+ buf.end_user_action()
@@ -5,6 +5,7 @@
from snaked.util import lazy_property
from snaked.signals import connect_external, connect_all
+from snaked.core.completer import add_completion_provider, attach_completer
from .utils import get_executable
@@ -19,8 +20,12 @@ def __init__(self, editor):
def init_completion(self):
provider = self.completion_provider
- completion = self.editor.view.get_completion()
- completion.add_provider(provider)
+
+ if not hasattr(self.editor.buffer, 'python_completion_added'):
+ add_completion_provider(self.editor.buffer, provider, 100)
+ self.editor.buffer.python_completion_added = True
+
+ attach_completer(self.editor.view)
@property
def env(self):
Oops, something went wrong.

0 comments on commit b6f711a

Please sign in to comment.