Example #1
0
    def __init__(self, plugin, window):
        self._window = window
        self._plugin = plugin
        self._model = SettingsModel(self)
        self._model.load()

        self.completion = None
        self.id_name = 'AutoCompleteID'
        self.tip = Tip(self._window)
        self.words = {}
        self.dictionary_words = []
        self.last_typed_line = None
        self.regex_completion = 0

        l_ids = []
        for signal in ('tab-added', 'tab-removed'):
            method = getattr(self, 'on_window_' + signal.replace('-', '_'))
            l_ids.append(window.connect(signal, method))
        window.set_data(self.id_name, l_ids)

        for view in window.get_views():
            self.connect_view(view)

        for doc in window.get_documents():
            self.connect_document(doc)
            self.scan(doc)
Example #2
0
    def __init__(self, caller):
        self._plugin = caller
        self._model = SettingsModel(self)
        self._model.load()

        self.current_source = ""

        gtk.Dialog.__init__(self, "AutoComplete settings", None,
                            gtk.DIALOG_DESTROY_WITH_PARENT)
        self.set_resizable(False)

        # Definitions
        source_label = gtk.Label("<b>Completion source:</b>")
        source_label.set_use_markup(True)
        source_label.set_justify(gtk.JUSTIFY_LEFT)

        self.mixed_radio = gtk.RadioButton(None, "Mixed")
        self.all_documents_radio = gtk.RadioButton(self.mixed_radio,
                                                   "All documents")
        self.library_radio = gtk.RadioButton(self.mixed_radio, "Library")

        if self._model.get_source() == "ALL_DOCUMENTS":
            self.all_documents_radio.set_active(True)
        if self._model.get_source() == "LIBRARY":
            self.library_radio.set_active(True)

        self.mixed_radio.connect("toggled", self.source_change, "MIXED")
        self.all_documents_radio.connect("toggled", self.source_change,
                                         "ALL_DOCUMENTS")
        self.library_radio.connect("toggled", self.source_change, "LIBRARY")

        # Positioning
        option_a_box = gtk.HBox()
        option_b_box = gtk.HBox()
        option_c_box = gtk.HBox()

        option_a_box.pack_start(self.mixed_radio, False, False, 0)
        option_b_box.pack_start(self.all_documents_radio, False, False, 0)
        option_c_box.pack_start(self.library_radio, False, False, 0)

        self.vbox.pack_start(source_label, True, True, 10)
        self.vbox.pack_start(option_a_box, True, True, 0)
        self.vbox.pack_start(option_b_box, True, True, 0)
        self.vbox.pack_start(option_c_box, True, True, 0)

        # Buttons
        close_button = self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
        close_button.grab_default()
        close_button.connect_object("clicked", gtk.Widget.destroy, self)

        help_button = self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
        help_button.connect_object("clicked", self.show_help_dialog, None)

        # Display
        self.vbox.show_all()
        self.show()
Example #3
0
class GoPlugin(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)
        self._instances = {}
        self.views = {}
        self.icons = {}
        self._icons_path = self.get_install_dir() + os.sep + self.__module__ + os.sep + "icons" + os.sep

        self.model = SettingsModel(self)
        self.model.load()
        self.update_path()

        # load completion icons
        self._load_completion_icons()

    def activate(self, window):
        self._instances[window] = GoWindowHelper(self, window)

    def deactivate(self, window):
        self._instances[window].deactivate()
        del self._instances[window]

    def update_ui(self, window):
        self._instances[window].update_ui()

    def update_all_ui(self):
        for instance in self._instances:
            self.update_ui(instance)

    def is_configurable(self):
        return True

    def create_configure_dialog(self):
        return ConfigurationDialog(self).dialog

    def update_path(self):
        # make sure $GOBIN is in $PATH
        if self.model.gobin_path not in os.getenv("PATH", "").split(":"):
            os.environ["PATH"] += ":" + self.model.gobin_path

    def _load_completion_icons(self):
        self.icons['var'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "var16.png")
        self.icons['const'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "const16.png")
        self.icons['func'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "func16.png")
        self.icons['interface'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "interface16.png")
        self.icons['package'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "package16.png")
        self.icons['struct'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "struct16.png")
        self.icons['gopher'] = gtk.gdk.pixbuf_new_from_file(self._icons_path + "gopher16.png")
 def __init__(self, plugin, window):
     self._window = window
     self._plugin = plugin
     self._model = SettingsModel(self)
     self._model.load()
     
     self.completion = None
     self.id_name = 'AutoCompleteID'
     self.tip = Tip(self._window)
     self.words = {}
     self.dictionary_words = []
     self.last_typed_line = None
     self.regex_completion = 0
     
     l_ids = []
     for signal in ('tab-added', 'tab-removed'):
         method = getattr(self, 'on_window_' + signal.replace('-', '_'))
         l_ids.append(window.connect(signal, method))
     window.set_data(self.id_name, l_ids)
     
     for view in window.get_views():
         self.connect_view(view)
     
     for doc in window.get_documents():
         self.connect_document(doc)
         self.scan(doc)
Example #5
0
 def __init__(self):
     self.app = QApplication(sys.argv)
     self.menu = QMenu()
     self.icon = QSystemTrayIcon()
     self.timer = QTimer()
     self.engine = Engine()
     self.settings = Settings(flags=Q_FLAGS())
     self.settingsModel = SettingsModel.getSettingsModel()
     self.gi_initialized = False
 def __init__(self, caller):
     self._plugin = caller
     self._model = SettingsModel(self)
     self._model.load()
     
     self.current_source = ""
     
     gtk.Dialog.__init__(self, "AutoComplete settings", None, gtk.DIALOG_DESTROY_WITH_PARENT)
     self.set_resizable(False)
     
     # Definitions
     source_label = gtk.Label("<b>Completion source:</b>")
     source_label.set_use_markup(True)
     source_label.set_justify(gtk.JUSTIFY_LEFT)
     
     self.mixed_radio = gtk.RadioButton(None, "Mixed")
     self.all_documents_radio = gtk.RadioButton(self.mixed_radio, "All documents")
     self.library_radio = gtk.RadioButton(self.mixed_radio, "Library")
     
     if self._model.get_source() == "ALL_DOCUMENTS":
         self.all_documents_radio.set_active(True)
     if self._model.get_source() == "LIBRARY":
         self.library_radio.set_active(True)
     
     self.mixed_radio.connect("toggled", self.source_change, "MIXED")
     self.all_documents_radio.connect("toggled", self.source_change, "ALL_DOCUMENTS")
     self.library_radio.connect("toggled", self.source_change, "LIBRARY")
     
     # Positioning
     option_a_box = gtk.HBox()
     option_b_box = gtk.HBox()
     option_c_box = gtk.HBox()
     
     option_a_box.pack_start(self.mixed_radio, False, False, 0)
     option_b_box.pack_start(self.all_documents_radio, False, False, 0)
     option_c_box.pack_start(self.library_radio, False, False, 0)
     
     self.vbox.pack_start(source_label, True, True, 10)
     self.vbox.pack_start(option_a_box, True, True, 0)
     self.vbox.pack_start(option_b_box, True, True, 0)
     self.vbox.pack_start(option_c_box, True, True, 0)
     
     # Buttons
     close_button = self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
     close_button.grab_default()
     close_button.connect_object("clicked", gtk.Widget.destroy, self)
     
     help_button = self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
     help_button.connect_object("clicked", self.show_help_dialog, None)
     
     # Display
     self.vbox.show_all()
     self.show()
Example #7
0
    def save_and_exit(self):

        self.settings = SettingsModel.getSettingsModel()
        self.settings.save()

        if self.gi_initialized:
            import gi
            gi.require_version("Notify", "0.7")
            from gi.repository import Notify
            Notify.uninit()

        self.app.exit(0)
Example #8
0
    def __init__(self):
        gedit.Plugin.__init__(self)
        self._instances = {}
        self.views = {}
        self.icons = {}
        self._icons_path = self.get_install_dir() + os.sep + self.__module__ + os.sep + "icons" + os.sep

        self.model = SettingsModel(self)
        self.model.load()
        self.update_path()

        # load completion icons
        self._load_completion_icons()
class AutoComplete:
    
    """Automatically complete words with <Return>"""
    
    def __init__(self, plugin, window):
        self._window = window
        self._plugin = plugin
        self._model = SettingsModel(self)
        self._model.load()
        
        self.completion = None
        self.id_name = 'AutoCompleteID'
        self.tip = Tip(self._window)
        self.words = {}
        self.dictionary_words = []
        self.last_typed_line = None
        self.regex_completion = 0
        
        l_ids = []
        for signal in ('tab-added', 'tab-removed'):
            method = getattr(self, 'on_window_' + signal.replace('-', '_'))
            l_ids.append(window.connect(signal, method))
        window.set_data(self.id_name, l_ids)
        
        for view in window.get_views():
            self.connect_view(view)
        
        for doc in window.get_documents():
            self.connect_document(doc)
            self.scan(doc)
    
    def deactivate(self):
        self.hide_tip()
        
        widgets = [self._window] + self._window.get_views() + self._window.get_documents()
        for widget in widgets:
            l_ids = widget.get_data(self.id_name)
            for l_id in l_ids:
                widget.disconnect(l_id)
            widget.set_data(self.id_name, None)
        
        self.tip = None
        self.words = {}
        
        self._window = None
        self._plugin = None
    
    def update_ui(self):
        pass
    
    def show_tip(self, text, x, y):
        """Show a completion tip in the main window's coordinates."""
        
        (root_x, root_y) = self._window.get_position()
        self.tip.move(root_x + x + 48, root_y + y + 48)
        self.tip.set_text(text)
        self.tip.show_all()
    
    def hide_tip(self):
        """Hide the completion tip."""
        
        self.tip.hide()
        self.completion = None
    
    def complete(self):
        """Complete the current word."""
        
        doc = self._window.get_active_document()
        if self.regex_completion:
            insert = doc.get_iter_at_mark(doc.get_insert())
            start = insert.copy()
            for i in range(0, self.regex_completion):
                start.backward_char()
            doc.delete(start, insert)
        doc.insert_at_cursor(self.completion)
    
    def cancel(self):
        """Hide the completion tip and return False."""
        
        self.hide_tip()
        return False
    
    def connect_document(self, doc):
        """Connect to document's signals."""
        
        l_ids = []
        for signal in ('end-user-action', 'loaded'):
            method = getattr(self, 'on_document_' + signal.replace('-', '_'))
            l_ids.append(doc.connect(signal, method))
        doc.set_data(self.id_name, l_ids)
    
    def connect_view(self, view):
        """Connect to view's signals."""
        
        l_ids = []
        for signal in ('focus-out-event', 'key-press-event'):
            method = getattr(self, 'on_view_' + signal.replace('-', '_'))
            l_ids.append(view.connect(signal, method))
        view.set_data(self.id_name, l_ids)
    
    def on_document_end_user_action(self, doc):
        """Scan document for words."""
        
        current_position = doc.get_iter_at_mark(doc.get_insert())
        if self.last_typed_line != current_position.get_line():
            self.scan(doc)
        elif current_position.backward_char() and len(doc.get_text(doc.get_start_iter(), doc.get_end_iter(), False)) < 10000:
            if RE_SIMPLE_WORD_SYNTAX.match(current_position.get_char()):
                if current_position.backward_char():
                    if not RE_SIMPLE_WORD_SYNTAX.match(current_position.get_char()):
                        self.scan(doc)
        self.last_typed_line = current_position.get_line()
        return
    
    def on_document_loaded(self, doc, *args):
        """Scan document for words."""
        
        self.scan(doc)
    
    def on_view_focus_out_event(self, view, event):
        """Hide the completion tip."""
        
        doc = view.get_buffer()
        self.scan(doc)
        self.hide_tip()
    
    def len_compare(self, x, y):
        """This is the comparing function for the alternative words to autocomplete"""
        
        x1 = ''
        for a in x:
            if a in AUTOCOMPLETE_BREAKS:
                x1 += str(AUTOCOMPLETE_BREAKS.index(a))
            else:
                x1 += '9'
        
        y1 = ''
        for a in y:
            if a in AUTOCOMPLETE_BREAKS:
                y1 += str(AUTOCOMPLETE_BREAKS.index(a))
            else:
                y1 += '9'
        
        d = len(y1) - len(x1)
        if d > 0:
            for i in range(0, d):
                x1 += ' '
        else:
            for i in range(0, d):
                y1 += ' '
        
        if x1 < y1:
            return -1
        elif x1 == y1:
            return 0
        else:
            return 1
    
    def len_compare___alphaSomething(self, x, y):
        """This is the comparing function for the alternative words to autocomplete"""
        
        x1 = ''
        for a in x:
            if a in AUTOCOMPLETE_BREAKS:
                x1 += chr(ord(' ') - AUTOCOMPLETE_BREAKS.index(a))
            else:
                x1 += a
        
        y1 = ''
        for a in y:
            if a in AUTOCOMPLETE_BREAKS:
                y1 += chr(ord(' ') - AUTOCOMPLETE_BREAKS.index(a))
            else:
                y1 += a
        
        d = len(y1) - len(x1)
        if d > 0:
            for i in range(0, d):
                x1 += ' '
        else:
            for i in range(0, d):
                y1 += ' '
        
        if x1 < y1:
            return -1
        elif x1 == y1:
            return 0
        else:
            return 1
    
    def startswith_filter(self, list_to_filter, reference_item):
        """Filters the list of words"""
        
        list_to_filter_len = len(list_to_filter)
        if list_to_filter_len <= 1:
            return []
        if len(reference_item) < MIN_CHARACTERS_BEFORE_AUTOCOMPLETE:
            return []
        
        list_to_filter_start = 0
        list_to_filter_end = list_to_filter_len - 1
        list_to_filter_search = int(list_to_filter_start + list_to_filter_end) / 2
        
        while True:
            if (list_to_filter[list_to_filter_search])[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] == reference_item[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
                while list_to_filter_search >= 0 and (list_to_filter[list_to_filter_search])[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] == reference_item[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
                    list_to_filter_search -= 1
                list_to_filter_search += 1
                break
            elif reference_item[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] > (list_to_filter[list_to_filter_search])[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
                list_to_filter_start = list_to_filter_search
                list_to_filter_search = int(list_to_filter_start + list_to_filter_end) / 2
                if list_to_filter_search == list_to_filter_start:
                    list_to_filter_search += 1
                    if list_to_filter_search == list_to_filter_len:
                        list_to_filter_search -= 1
                        break
            elif list_to_filter_search != list_to_filter_end:
                list_to_filter_end = list_to_filter_search
                list_to_filter_search = int(list_to_filter_start + list_to_filter_end) / 2
            else:
                break
        
        new_list = list()
        
        while list_to_filter_search != list_to_filter_len and reference_item[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] == (list_to_filter[list_to_filter_search])[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
            if list_to_filter[list_to_filter_search].startswith(reference_item) and list_to_filter[list_to_filter_search] != reference_item:
                new_list.append(list_to_filter[list_to_filter_search])
            list_to_filter_search += 1
        
        return new_list
    
    def startswith_filter_linear(self, list_to_filter, reference_item):
        """Filters the list of words"""
        
        if not list_to_filter:
            return []
        if len(reference_item) < MIN_CHARACTERS_BEFORE_AUTOCOMPLETE:
            return []
        
        new_list = list()
        for item in list_to_filter:
            if item.startswith(reference_item) and item != reference_item:
                new_list.append(item)
        
        return new_list
    
    def simple_contains_filter(self, list_to_filter, reference_item):
        new_list = list()
        current_position = doc.get_iter_at_mark(doc.get_insert())
        for item in list_to_filter:
            if not RE_COMPOUND_WORD_SYNTAX.match(item) and reference_item in item:
                emph_item = item.replace(reference_item, TIP_EMPHASIS[0] + reference_item + TIP_EMPHASIS[1])
                new_list.append(emph_item)
        return new_list
    
    def re_contains_filter(self, list_to_filter, reference_item):
        new_list = list()
        reference_item_case_insensitive = ''
        for c in reference_item:
            if c >= 'a' and c <= 'z' or c >= 'A' and c <= 'Z':
                reference_item_case_insensitive += '[' + c.lower() + c.upper() + ']'
            else:
                reference_item_case_insensitive += c
        for item in list_to_filter:
            if not RE_COMPOUND_WORD_SYNTAX.match(item) and re.findall(reference_item_case_insensitive, item):
                new_list.append(item)
        return new_list
    
    def on_view_key_press_event(self, view, event):
        """Display a completion or complete the current word."""
        
        if event.state & gtk.gdk.CONTROL_MASK:
            return self.cancel()
        if event.state & gtk.gdk.MOD1_MASK and event.string != '/':
            return self.cancel()
        
        key = gtk.gdk.keyval_name(event.keyval)
        if key == 'Return':
            if self.completion is None:
                return self.cancel()
            self.complete()
            complete_key_pressed = True
        else:
            complete_key_pressed = False
        
        if key == 'Down':
            if self.completion is None:
                return self.cancel()
            self.select_alternative('Down')
            return True
        
        if key == 'Up':
            if self.completion is None:
                return self.cancel()
            self.select_alternative('Up')
            return True
        
        doc = view.get_buffer()
        insert = doc.get_iter_at_mark(doc.get_insert())
        if event.keyval >= 128:  # non-alphanumeric key
            if gtk.gdk.keyval_name(event.keyval) == 'BackSpace':
                doc = view.get_buffer()
                insert = doc.get_iter_at_mark(doc.get_insert())
                insert.backward_char()
            elif not complete_key_pressed:
                return self.cancel()
        
        selection_iters = view.get_buffer().get_selection_bounds()
        if selection_iters:
            regex_word = doc.get_text(selection_iters[0], selection_iters[1], False)
        else:
            start = insert.copy()
            while not start.is_start():
                start.backward_char()
                if re.match("\s", start.get_char()):
                    start.forward_char()
                    break
            regex_word = doc.get_text(start, insert, False)
        
        start = insert.copy()
        while start.backward_char():
            match_list = RE_SIMPLE_WORD_SYNTAX.findall(doc.get_text(start, insert, False))
            if len(match_list) == 1 and len(match_list[0]) == len(doc.get_text(start, insert, False)):
                continue
            else:
                start.forward_char()
                break
        incomplete_simple_word = doc.get_text(start, insert, False)
        
        if not complete_key_pressed:
            incomplete_simple_word += event.string
        
        start_compound = start.copy()
        match_success = True
        while match_success == True:
            match_success = False
            if start.is_start():
                break
            for i in range(0, MAX_COMPOSITION_TOKEN_SIZE + 1):  # +1: need to catch the char before the token
                start.backward_char()
                match_list = RE_BEGINNING_OF_COMPOUND_WORD_SYNTAX.findall(doc.get_text(start, start_compound, False))
                if len(match_list) == 1 and len(match_list[0]) == len(doc.get_text(start, start_compound, False)):
                    match_success = True
                    break
        for i in range(0, MAX_COMPOSITION_TOKEN_SIZE + 1):
            start.forward_char()
        incomplete_compound_word = doc.get_text(start, insert, False)
        
        if not complete_key_pressed:
            incomplete_compound_word += event.string
        
        compound_word_alternatives = self.startswith_filter(self.dictionary_words, incomplete_compound_word)
        compound_word_alternatives.sort(self.len_compare)
        compound_word_alternatives = self.aggressive_filter(compound_word_alternatives, incomplete_compound_word)
        alternatives = compound_word_alternatives
        incomplete = incomplete_compound_word
        
        if not compound_word_alternatives:
            simple_word_alternatives = self.startswith_filter(self.dictionary_words, incomplete_simple_word)
            simple_word_alternatives.sort(self.len_compare)
            simple_word_alternatives = self.aggressive_filter(simple_word_alternatives, incomplete_simple_word)
            alternatives = simple_word_alternatives
            incomplete = incomplete_simple_word
        
        if event.string == '/' and event.state & gtk.gdk.MOD1_MASK:
            words_containing_regex = self.re_contains_filter(self.dictionary_words, regex_word)
            alternatives = words_containing_regex
            incomplete = ''
            self.regex_completion = len(regex_word)
        else:
            self.regex_completion = 0
        
        self.complete_word = None
        display_string = ''
        alternatives_counter = 0
        alternatives.sort()
        for word in alternatives:
            if not self.complete_word:
                self.complete_word = word
                display_string += MARKER
            else:
                display_string += SPACES
            display_string = display_string + word + '\n'
            alternatives_counter += 1
            if alternatives_counter == MAX_SUGGESTIONS:
                break
        
        if gtk.gdk.keyval_name(event.keyval) == 'BackSpace':
            insert.forward_char()
        
        if self.complete_word is None:
            self.cancel()
            if complete_key_pressed:
                return True
            else:
                return False
        
        self.completion = self.complete_word[len(incomplete):]
        window = gtk.TEXT_WINDOW_TEXT
        rect = view.get_iter_location(insert)
        (x, y) = view.buffer_to_window_coords(window, rect.x, rect.y)
        (x, y) = view.translate_coordinates(self._window, x, y)
        
        self.show_tip(display_string, x, y)
        
        if complete_key_pressed:
            return True
        else:
            return False
    
    def aggressive_filter(self, initial_alternatives, incomplete):
        cursor_pos = len(incomplete)
        if cursor_pos < MIN_CHARACTERS_BEFORE_AUTOCOMPLETE:
            return []
        
        if len(initial_alternatives) < MAX_SUGGESTIONS_BEFORE_USE_BREAKS:
            return initial_alternatives
        
        filtered_alternatives = []
        for item in initial_alternatives:
            break_pos = len(item)
            item_end = item[cursor_pos:]
            for separator in list(AUTOCOMPLETE_BREAKS):
                if separator in item_end:
                    break_pos = min(break_pos, item_end.index(separator))
            if not item[:break_pos + cursor_pos + 1] in filtered_alternatives:
                filtered_alternatives += [item[:break_pos + cursor_pos + 1]]
        
        filtered_alternatives.sort(self.len_compare)
        return filtered_alternatives
    
    def on_window_tab_added(self, window, tab):
        """Connect the document and view in tab."""
        
        context = tab.get_view().get_pango_context()
        font_desc = context.get_font_description()
        self.tip.set_font_description(font_desc)
        
        self.connect_document(tab.get_document())
        self.connect_view(tab.get_view())
    
    def on_window_tab_removed(self, window, tab):
        """Remove document's word set."""
        
        doc = tab.get_document()
        if doc in self.words:
            self.words.pop(doc)
    
    def scan(self, doc, what_to_scan='ALL_WORDS'):
        """Scan document for new words."""
        
        text = doc.get_text(*doc.get_bounds())
        self.words[doc] = frozenset([])
        
        if self._model.get_source() != "LIBRARY":
            if what_to_scan == 'ALL_WORDS':
                self.words[doc] = self.words[doc].union(RE_COMPOUND_WORD_SYNTAX.findall(text))
                self.words[doc] = self.words[doc].union(RE_SIMPLE_WORD_SYNTAX.findall(text))
            elif what_to_scan == 'SIMPLE_WORDS':
                self.words[doc] = self.words[doc].union(RE_SIMPLE_WORD_SYNTAX.findall(text))
            elif what_to_scan == 'COMPOUND_WORDS':
                self.words[doc] = self.words[doc].union(RE_COMPOUND_WORD_SYNTAX.findall(text))
        
        if self._window.get_active_document() == doc:
            if self._model.get_source() != "ALL_DOCUMENTS":
                lang = doc.get_language()
                if lang != None:
                    lang = lang.get_name().lower()
                    lang_static_words = self._model.get_words(lang)
                    self.words[doc] = self.words[doc].union(lang_static_words)
                    
                    lang_library = self._model.get_language_library(lang)
                    if lang_library:
                        identificators = lang_library["dynamic"]["identificators"]
                        
                        for identificator in identificators:
                            RE_IDENTIFICATOR = re.compile(r'%s'%identificator, re.UNICODE)
                            for m in RE_IDENTIFICATOR.finditer(text):
                                tokens = lang_library["dynamic"]["members"].get(m.group("class"))
                                if tokens:
                                    tokens = tokens.split(' ')
                                    self.words[doc] = self.words[doc].union(["%s%s%s" % (m.group("instance"), lang_library["dynamic"]["tokenSeparator"], token) for token in tokens])
        
        self.dictionary_words = set([])
        for word in self.words.values():
            self.dictionary_words.update(word)
        self.dictionary_words = list(self.dictionary_words)
        self.dictionary_words.sort()
    
#    def refresh_tip_on_complete(self):
#        """Refresh the alternative word list when <Return> is pressed and a completion is done."""
#        
#        display_string = ''
#        local_complete_word = self.complete_word
#        for current_line in (self.tip.get_text() + '\n').splitlines(True):
#            if current_line.startswith(SPACES + local_complete_word):
#                if display_string == '':
#                    display_string += current_line.replace(SPACES, MARKER)
#                    self.completion = current_line.strip()[len(local_complete_word):]
#                    self.complete_word = current_line.strip(' \n')
#                else:
#                    display_string += current_line
#        if len(display_string) != 0:
#            self.tip.set_text(display_string.rstrip('\n'))
#        else:
#            self.hide_tip()
#        return True
    
    def select_alternative(self, direction=None):
        """Makes all the necessary modifications when an alternative word is selected from the list."""
        
        display_string = self.tip.get_text() + '\n'
        previous_line = ''
        first_line = None
        marker_moved = False
        display_lines = display_string.splitlines(True)
        if len(display_lines) == 1:
            return True
        
        for current_line in display_lines:
            if first_line is None:
                first_line = current_line
            if direction == 'Down':
                if previous_line == MARKER + self.complete_word + '\n':
                    marker_moved = True
                    display_string = display_string.replace(previous_line, previous_line.replace(MARKER, SPACES))
                    display_string = display_string.replace(current_line, current_line.replace(SPACES, MARKER))
                    self.completion = current_line.strip()[len(self.complete_word) - len(self.completion):]
                    self.complete_word = current_line.strip()
                    break
            if direction == 'Up':
                if current_line == MARKER + self.complete_word + '\n' and previous_line != '':
                    marker_moved = True
                    display_string = display_string.replace(current_line, current_line.replace(MARKER, SPACES))
                    display_string = display_string.replace(previous_line, previous_line.replace(SPACES, MARKER))
                    self.completion = previous_line.strip()[len(self.complete_word) - len(self.completion):]
                    self.complete_word = previous_line.strip()
                    break
            previous_line = current_line
        if not marker_moved:
            if direction == 'Down':
                display_string = display_string.replace(current_line, current_line.replace(MARKER, SPACES))
                display_string = display_string.replace(first_line, first_line.replace(SPACES, MARKER))
                self.completion = first_line.strip()[len(self.complete_word) - len(self.completion):]
                self.complete_word = first_line.strip()
            if direction == 'Up':
                display_string = display_string.replace(current_line, current_line.replace(SPACES, MARKER))
                display_string = display_string.replace(first_line, first_line.replace(MARKER, SPACES))
                self.completion = current_line.strip()[len(self.complete_word) - len(self.completion):]
                self.complete_word = current_line.strip()
        self.tip.set_text(display_string.rstrip('\n'))
        return True
Example #10
0
 def __init__(self):
     super().__init__()
     self.settings = SettingsModel.getSettingsModel()
Example #11
0
class AutoComplete:
    """Automatically complete words with <Return>"""
    def __init__(self, plugin, window):
        self._window = window
        self._plugin = plugin
        self._model = SettingsModel(self)
        self._model.load()

        self.completion = None
        self.id_name = 'AutoCompleteID'
        self.tip = Tip(self._window)
        self.words = {}
        self.dictionary_words = []
        self.last_typed_line = None
        self.regex_completion = 0

        l_ids = []
        for signal in ('tab-added', 'tab-removed'):
            method = getattr(self, 'on_window_' + signal.replace('-', '_'))
            l_ids.append(window.connect(signal, method))
        window.set_data(self.id_name, l_ids)

        for view in window.get_views():
            self.connect_view(view)

        for doc in window.get_documents():
            self.connect_document(doc)
            self.scan(doc)

    def deactivate(self):
        self.hide_tip()

        widgets = [self._window
                   ] + self._window.get_views() + self._window.get_documents()
        for widget in widgets:
            l_ids = widget.get_data(self.id_name)
            for l_id in l_ids:
                widget.disconnect(l_id)
            widget.set_data(self.id_name, None)

        self.tip = None
        self.words = {}

        self._window = None
        self._plugin = None

    def update_ui(self):
        pass

    def show_tip(self, text, x, y):
        """Show a completion tip in the main window's coordinates."""

        (root_x, root_y) = self._window.get_position()
        self.tip.move(root_x + x + 48, root_y + y + 48)
        self.tip.set_text(text)
        self.tip.show_all()

    def hide_tip(self):
        """Hide the completion tip."""

        self.tip.hide()
        self.completion = None

    def complete(self):
        """Complete the current word."""

        doc = self._window.get_active_document()
        if self.regex_completion:
            insert = doc.get_iter_at_mark(doc.get_insert())
            start = insert.copy()
            for i in range(0, self.regex_completion):
                start.backward_char()
            doc.delete(start, insert)
        doc.insert_at_cursor(self.completion)

    def cancel(self):
        """Hide the completion tip and return False."""

        self.hide_tip()
        return False

    def connect_document(self, doc):
        """Connect to document's signals."""

        l_ids = []
        for signal in ('end-user-action', 'loaded'):
            method = getattr(self, 'on_document_' + signal.replace('-', '_'))
            l_ids.append(doc.connect(signal, method))
        doc.set_data(self.id_name, l_ids)

    def connect_view(self, view):
        """Connect to view's signals."""

        l_ids = []
        for signal in ('focus-out-event', 'key-press-event'):
            method = getattr(self, 'on_view_' + signal.replace('-', '_'))
            l_ids.append(view.connect(signal, method))
        view.set_data(self.id_name, l_ids)

    def on_document_end_user_action(self, doc):
        """Scan document for words."""

        current_position = doc.get_iter_at_mark(doc.get_insert())
        if self.last_typed_line != current_position.get_line():
            self.scan(doc)
        elif current_position.backward_char() and len(
                doc.get_text(doc.get_start_iter(), doc.get_end_iter(),
                             False)) < 10000:
            if RE_SIMPLE_WORD_SYNTAX.match(current_position.get_char()):
                if current_position.backward_char():
                    if not RE_SIMPLE_WORD_SYNTAX.match(
                            current_position.get_char()):
                        self.scan(doc)
        self.last_typed_line = current_position.get_line()
        return

    def on_document_loaded(self, doc, *args):
        """Scan document for words."""

        self.scan(doc)

    def on_view_focus_out_event(self, view, event):
        """Hide the completion tip."""

        doc = view.get_buffer()
        self.scan(doc)
        self.hide_tip()

    def len_compare(self, x, y):
        """This is the comparing function for the alternative words to autocomplete"""

        x1 = ''
        for a in x:
            if a in AUTOCOMPLETE_BREAKS:
                x1 += str(AUTOCOMPLETE_BREAKS.index(a))
            else:
                x1 += '9'

        y1 = ''
        for a in y:
            if a in AUTOCOMPLETE_BREAKS:
                y1 += str(AUTOCOMPLETE_BREAKS.index(a))
            else:
                y1 += '9'

        d = len(y1) - len(x1)
        if d > 0:
            for i in range(0, d):
                x1 += ' '
        else:
            for i in range(0, d):
                y1 += ' '

        if x1 < y1:
            return -1
        elif x1 == y1:
            return 0
        else:
            return 1

    def len_compare___alphaSomething(self, x, y):
        """This is the comparing function for the alternative words to autocomplete"""

        x1 = ''
        for a in x:
            if a in AUTOCOMPLETE_BREAKS:
                x1 += chr(ord(' ') - AUTOCOMPLETE_BREAKS.index(a))
            else:
                x1 += a

        y1 = ''
        for a in y:
            if a in AUTOCOMPLETE_BREAKS:
                y1 += chr(ord(' ') - AUTOCOMPLETE_BREAKS.index(a))
            else:
                y1 += a

        d = len(y1) - len(x1)
        if d > 0:
            for i in range(0, d):
                x1 += ' '
        else:
            for i in range(0, d):
                y1 += ' '

        if x1 < y1:
            return -1
        elif x1 == y1:
            return 0
        else:
            return 1

    def startswith_filter(self, list_to_filter, reference_item):
        """Filters the list of words"""

        list_to_filter_len = len(list_to_filter)
        if list_to_filter_len <= 1:
            return []
        if len(reference_item) < MIN_CHARACTERS_BEFORE_AUTOCOMPLETE:
            return []

        list_to_filter_start = 0
        list_to_filter_end = list_to_filter_len - 1
        list_to_filter_search = int(list_to_filter_start +
                                    list_to_filter_end) / 2

        while True:
            if (list_to_filter[list_to_filter_search]
                )[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] == reference_item[
                    0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
                while list_to_filter_search >= 0 and (
                        list_to_filter[list_to_filter_search]
                )[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] == reference_item[
                        0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
                    list_to_filter_search -= 1
                list_to_filter_search += 1
                break
            elif reference_item[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] > (
                    list_to_filter[list_to_filter_search]
            )[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
                list_to_filter_start = list_to_filter_search
                list_to_filter_search = int(list_to_filter_start +
                                            list_to_filter_end) / 2
                if list_to_filter_search == list_to_filter_start:
                    list_to_filter_search += 1
                    if list_to_filter_search == list_to_filter_len:
                        list_to_filter_search -= 1
                        break
            elif list_to_filter_search != list_to_filter_end:
                list_to_filter_end = list_to_filter_search
                list_to_filter_search = int(list_to_filter_start +
                                            list_to_filter_end) / 2
            else:
                break

        new_list = list()

        while list_to_filter_search != list_to_filter_len and reference_item[
                0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE] == (
                    list_to_filter[list_to_filter_search]
                )[0:MIN_CHARACTERS_BEFORE_AUTOCOMPLETE]:
            if list_to_filter[list_to_filter_search].startswith(
                    reference_item
            ) and list_to_filter[list_to_filter_search] != reference_item:
                new_list.append(list_to_filter[list_to_filter_search])
            list_to_filter_search += 1

        return new_list

    def startswith_filter_linear(self, list_to_filter, reference_item):
        """Filters the list of words"""

        if not list_to_filter:
            return []
        if len(reference_item) < MIN_CHARACTERS_BEFORE_AUTOCOMPLETE:
            return []

        new_list = list()
        for item in list_to_filter:
            if item.startswith(reference_item) and item != reference_item:
                new_list.append(item)

        return new_list

    def simple_contains_filter(self, list_to_filter, reference_item):
        new_list = list()
        current_position = doc.get_iter_at_mark(doc.get_insert())
        for item in list_to_filter:
            if not RE_COMPOUND_WORD_SYNTAX.match(
                    item) and reference_item in item:
                emph_item = item.replace(
                    reference_item,
                    TIP_EMPHASIS[0] + reference_item + TIP_EMPHASIS[1])
                new_list.append(emph_item)
        return new_list

    def re_contains_filter(self, list_to_filter, reference_item):
        new_list = list()
        reference_item_case_insensitive = ''
        for c in reference_item:
            if c >= 'a' and c <= 'z' or c >= 'A' and c <= 'Z':
                reference_item_case_insensitive += '[' + c.lower() + c.upper(
                ) + ']'
            else:
                reference_item_case_insensitive += c
        for item in list_to_filter:
            if not RE_COMPOUND_WORD_SYNTAX.match(item) and re.findall(
                    reference_item_case_insensitive, item):
                new_list.append(item)
        return new_list

    def on_view_key_press_event(self, view, event):
        """Display a completion or complete the current word."""

        if event.state & gtk.gdk.CONTROL_MASK:
            return self.cancel()
        if event.state & gtk.gdk.MOD1_MASK and event.string != '/':
            return self.cancel()

        key = gtk.gdk.keyval_name(event.keyval)
        if key == 'Return':
            if self.completion is None:
                return self.cancel()
            self.complete()
            complete_key_pressed = True
        else:
            complete_key_pressed = False

        if key == 'Down':
            if self.completion is None:
                return self.cancel()
            self.select_alternative('Down')
            return True

        if key == 'Up':
            if self.completion is None:
                return self.cancel()
            self.select_alternative('Up')
            return True

        doc = view.get_buffer()
        insert = doc.get_iter_at_mark(doc.get_insert())
        if event.keyval >= 128:  # non-alphanumeric key
            if gtk.gdk.keyval_name(event.keyval) == 'BackSpace':
                doc = view.get_buffer()
                insert = doc.get_iter_at_mark(doc.get_insert())
                insert.backward_char()
            elif not complete_key_pressed:
                return self.cancel()

        selection_iters = view.get_buffer().get_selection_bounds()
        if selection_iters:
            regex_word = doc.get_text(selection_iters[0], selection_iters[1],
                                      False)
        else:
            start = insert.copy()
            while not start.is_start():
                start.backward_char()
                if re.match("\s", start.get_char()):
                    start.forward_char()
                    break
            regex_word = doc.get_text(start, insert, False)

        start = insert.copy()
        while start.backward_char():
            match_list = RE_SIMPLE_WORD_SYNTAX.findall(
                doc.get_text(start, insert, False))
            if len(match_list) == 1 and len(match_list[0]) == len(
                    doc.get_text(start, insert, False)):
                continue
            else:
                start.forward_char()
                break
        incomplete_simple_word = doc.get_text(start, insert, False)

        if not complete_key_pressed:
            incomplete_simple_word += event.string

        start_compound = start.copy()
        match_success = True
        while match_success == True:
            match_success = False
            if start.is_start():
                break
            for i in range(0, MAX_COMPOSITION_TOKEN_SIZE +
                           1):  # +1: need to catch the char before the token
                start.backward_char()
                match_list = RE_BEGINNING_OF_COMPOUND_WORD_SYNTAX.findall(
                    doc.get_text(start, start_compound, False))
                if len(match_list) == 1 and len(match_list[0]) == len(
                        doc.get_text(start, start_compound, False)):
                    match_success = True
                    break
        for i in range(0, MAX_COMPOSITION_TOKEN_SIZE + 1):
            start.forward_char()
        incomplete_compound_word = doc.get_text(start, insert, False)

        if not complete_key_pressed:
            incomplete_compound_word += event.string

        compound_word_alternatives = self.startswith_filter(
            self.dictionary_words, incomplete_compound_word)
        compound_word_alternatives.sort(self.len_compare)
        compound_word_alternatives = self.aggressive_filter(
            compound_word_alternatives, incomplete_compound_word)
        alternatives = compound_word_alternatives
        incomplete = incomplete_compound_word

        if not compound_word_alternatives:
            simple_word_alternatives = self.startswith_filter(
                self.dictionary_words, incomplete_simple_word)
            simple_word_alternatives.sort(self.len_compare)
            simple_word_alternatives = self.aggressive_filter(
                simple_word_alternatives, incomplete_simple_word)
            alternatives = simple_word_alternatives
            incomplete = incomplete_simple_word

        if event.string == '/' and event.state & gtk.gdk.MOD1_MASK:
            words_containing_regex = self.re_contains_filter(
                self.dictionary_words, regex_word)
            alternatives = words_containing_regex
            incomplete = ''
            self.regex_completion = len(regex_word)
        else:
            self.regex_completion = 0

        self.complete_word = None
        display_string = ''
        alternatives_counter = 0
        alternatives.sort()
        for word in alternatives:
            if not self.complete_word:
                self.complete_word = word
                display_string += MARKER
            else:
                display_string += SPACES
            display_string = display_string + word + '\n'
            alternatives_counter += 1
            if alternatives_counter == MAX_SUGGESTIONS:
                break

        if gtk.gdk.keyval_name(event.keyval) == 'BackSpace':
            insert.forward_char()

        if self.complete_word is None:
            self.cancel()
            if complete_key_pressed:
                return True
            else:
                return False

        self.completion = self.complete_word[len(incomplete):]
        window = gtk.TEXT_WINDOW_TEXT
        rect = view.get_iter_location(insert)
        (x, y) = view.buffer_to_window_coords(window, rect.x, rect.y)
        (x, y) = view.translate_coordinates(self._window, x, y)

        self.show_tip(display_string, x, y)

        if complete_key_pressed:
            return True
        else:
            return False

    def aggressive_filter(self, initial_alternatives, incomplete):
        cursor_pos = len(incomplete)
        if cursor_pos < MIN_CHARACTERS_BEFORE_AUTOCOMPLETE:
            return []

        if len(initial_alternatives) < MAX_SUGGESTIONS_BEFORE_USE_BREAKS:
            return initial_alternatives

        filtered_alternatives = []
        for item in initial_alternatives:
            break_pos = len(item)
            item_end = item[cursor_pos:]
            for separator in list(AUTOCOMPLETE_BREAKS):
                if separator in item_end:
                    break_pos = min(break_pos, item_end.index(separator))
            if not item[:break_pos + cursor_pos + 1] in filtered_alternatives:
                filtered_alternatives += [item[:break_pos + cursor_pos + 1]]

        filtered_alternatives.sort(self.len_compare)
        return filtered_alternatives

    def on_window_tab_added(self, window, tab):
        """Connect the document and view in tab."""

        context = tab.get_view().get_pango_context()
        font_desc = context.get_font_description()
        self.tip.set_font_description(font_desc)

        self.connect_document(tab.get_document())
        self.connect_view(tab.get_view())

    def on_window_tab_removed(self, window, tab):
        """Remove document's word set."""

        doc = tab.get_document()
        if doc in self.words:
            self.words.pop(doc)

    def scan(self, doc, what_to_scan='ALL_WORDS'):
        """Scan document for new words."""

        text = doc.get_text(*doc.get_bounds())
        self.words[doc] = frozenset([])

        if self._model.get_source() != "LIBRARY":
            if what_to_scan == 'ALL_WORDS':
                self.words[doc] = self.words[doc].union(
                    RE_COMPOUND_WORD_SYNTAX.findall(text))
                self.words[doc] = self.words[doc].union(
                    RE_SIMPLE_WORD_SYNTAX.findall(text))
            elif what_to_scan == 'SIMPLE_WORDS':
                self.words[doc] = self.words[doc].union(
                    RE_SIMPLE_WORD_SYNTAX.findall(text))
            elif what_to_scan == 'COMPOUND_WORDS':
                self.words[doc] = self.words[doc].union(
                    RE_COMPOUND_WORD_SYNTAX.findall(text))

        if self._window.get_active_document() == doc:
            if self._model.get_source() != "ALL_DOCUMENTS":
                lang = doc.get_language()
                if lang != None:
                    lang = lang.get_name().lower()
                    lang_static_words = self._model.get_words(lang)
                    self.words[doc] = self.words[doc].union(lang_static_words)

                    lang_library = self._model.get_language_library(lang)
                    if lang_library:
                        identificators = lang_library["dynamic"][
                            "identificators"]

                        for identificator in identificators:
                            RE_IDENTIFICATOR = re.compile(
                                r'%s' % identificator, re.UNICODE)
                            for m in RE_IDENTIFICATOR.finditer(text):
                                tokens = lang_library["dynamic"][
                                    "members"].get(m.group("class"))
                                if tokens:
                                    tokens = tokens.split(' ')
                                    self.words[doc] = self.words[doc].union([
                                        "%s%s%s" % (m.group("instance"),
                                                    lang_library["dynamic"]
                                                    ["tokenSeparator"], token)
                                        for token in tokens
                                    ])

        self.dictionary_words = set([])
        for word in self.words.values():
            self.dictionary_words.update(word)
        self.dictionary_words = list(self.dictionary_words)
        self.dictionary_words.sort()


#    def refresh_tip_on_complete(self):
#        """Refresh the alternative word list when <Return> is pressed and a completion is done."""
#
#        display_string = ''
#        local_complete_word = self.complete_word
#        for current_line in (self.tip.get_text() + '\n').splitlines(True):
#            if current_line.startswith(SPACES + local_complete_word):
#                if display_string == '':
#                    display_string += current_line.replace(SPACES, MARKER)
#                    self.completion = current_line.strip()[len(local_complete_word):]
#                    self.complete_word = current_line.strip(' \n')
#                else:
#                    display_string += current_line
#        if len(display_string) != 0:
#            self.tip.set_text(display_string.rstrip('\n'))
#        else:
#            self.hide_tip()
#        return True

    def select_alternative(self, direction=None):
        """Makes all the necessary modifications when an alternative word is selected from the list."""

        display_string = self.tip.get_text() + '\n'
        previous_line = ''
        first_line = None
        marker_moved = False
        display_lines = display_string.splitlines(True)
        if len(display_lines) == 1:
            return True

        for current_line in display_lines:
            if first_line is None:
                first_line = current_line
            if direction == 'Down':
                if previous_line == MARKER + self.complete_word + '\n':
                    marker_moved = True
                    display_string = display_string.replace(
                        previous_line, previous_line.replace(MARKER, SPACES))
                    display_string = display_string.replace(
                        current_line, current_line.replace(SPACES, MARKER))
                    self.completion = current_line.strip(
                    )[len(self.complete_word) - len(self.completion):]
                    self.complete_word = current_line.strip()
                    break
            if direction == 'Up':
                if current_line == MARKER + self.complete_word + '\n' and previous_line != '':
                    marker_moved = True
                    display_string = display_string.replace(
                        current_line, current_line.replace(MARKER, SPACES))
                    display_string = display_string.replace(
                        previous_line, previous_line.replace(SPACES, MARKER))
                    self.completion = previous_line.strip(
                    )[len(self.complete_word) - len(self.completion):]
                    self.complete_word = previous_line.strip()
                    break
            previous_line = current_line
        if not marker_moved:
            if direction == 'Down':
                display_string = display_string.replace(
                    current_line, current_line.replace(MARKER, SPACES))
                display_string = display_string.replace(
                    first_line, first_line.replace(SPACES, MARKER))
                self.completion = first_line.strip()[len(self.complete_word) -
                                                     len(self.completion):]
                self.complete_word = first_line.strip()
            if direction == 'Up':
                display_string = display_string.replace(
                    current_line, current_line.replace(SPACES, MARKER))
                display_string = display_string.replace(
                    first_line, first_line.replace(MARKER, SPACES))
                self.completion = current_line.strip(
                )[len(self.complete_word) - len(self.completion):]
                self.complete_word = current_line.strip()
        self.tip.set_text(display_string.rstrip('\n'))
        return True