Commits

nakamura committed ef7dfe0

add complete word functionality

  • Participants
  • Parent commits a174b00

Comments (0)

Files changed (1)

File yomogi/terminal.py

     def do_key_press(self, terminal, event):
         keyname = gtk.gdk.keyval_name(event.keyval)
 
-        if event.state == gtk.gdk.CONTROL_MASK|gtk.gdk.MOD1_MASK and \
-           keyname == 'm':
-            # Ctrl + Alt + m
-            self.do_popup(event)
-            return True
+        if event.state == gtk.gdk.CONTROL_MASK|gtk.gdk.MOD1_MASK:
+            # Ctrl + Alt + ...
+            if keyname == 'm':
+                self.do_popup(event)
+                return True
+
+            elif keyname == 'n':
+                self.complete_word()
+                return True
 
         if gtk.gdk.keyval_name(event.keyval) == 'Menu':
             self.do_popup(event)
             if buf:
                 yield ''.join(buf)
 
+    def complete_word(self):
+        word = self.get_word_before_cursor()
+        candidates = self.get_complete_candidates(word)
+        if not candidates:
+            return
+
+        elif len(candidates) == 1:
+            self._terminal.feed_child(candidates[0][len(word):])
+
+        else:
+            menu = _Menu()
+            for w in candidates:
+                item = gtk.MenuItem(w)
+                menu.append(item)
+                item.connect('activate',
+                             lambda *x: self._terminal.feed_child(x[-1]),
+                             w[len(word):])
+
+            menu.show_all()
+            self.popup_near_cursor(menu)
+
+    def popup_near_cursor(self, menu):
+        cursor_x, cursor_y = self.get_cursor_pos_pixel()
+        parent_x, parent_y = self.get_parent_window().get_position()
+        x = parent_x + cursor_x
+        y = parent_y + cursor_y
+        menu.popup(None, None, lambda *_: (x, y, True), 3, 0)
+
+    def get_cursor_pos_pixel(self):
+        col, row = self._terminal.get_cursor_position()
+
+        font_width = self.get_char_width()
+        font_height = self.get_char_height()
+
+        xpad, ypad = self.get_padding()
+
+        return (xpad / 2 + font_width * col, ypad / 2 + font_height * row)
+
+    def get_complete_candidates(self, word):
+        candidates = set()
+        for w in self.extract_words(u'\n'.join(self.get_utext_as_seen())):
+            if w != word and w.startswith(word):
+                candidates.add(w)
+
+        return sorted(candidates)
+
+    def get_word_before_cursor(self):
+        text = self.get_text_before_cursor()
+        word = []
+        for c in reversed(text):
+            if not self._terminal.is_word_char(c):
+                break
+
+            word.insert(0, c)
+
+        return ''.join(word)
+
+    def get_text_before_cursor(self):
+        col, row = self._terminal.get_cursor_position()
+        return self._terminal.get_text_range(row, 0, row, col, lambda *x: True)[:col]
+
+    def extract_words(self, text):
+        word = []
+        for c in text:
+            if self._terminal.is_word_char(c):
+                word.append(c)
+
+            elif word:
+                yield ''.join(word)
+                word = []
+
 
 def get_unicode_char_width(c):
     eaw = unicodedata.east_asian_width(c)
                 self.do_term_popup(terminal, event)
                 return True
 
+            elif keyname == 'n':
+                terminal.complete_word()
+                return True
+
         if gtk.gdk.keyval_name(event.keyval) == 'Menu':
             self.do_term_popup(terminal, event)