diff --git a/IPython/frontend/qt/console/completion_html.py b/IPython/frontend/qt/console/completion_html.py
index 0875627..852fcf3 100644
--- a/IPython/frontend/qt/console/completion_html.py
+++ b/IPython/frontend/qt/console/completion_html.py
@@ -1,7 +1,116 @@
+"""a navigable completer for the qtconsole"""
+# coding : utf-8
+#-----------------------------------------------------------------------------
+# Copyright (c) 2012, IPython Development Team.$
+#
+# Distributed under the terms of the Modified BSD License.$
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
 # System library imports
+import IPython.utils.text as text
+
 from IPython.external.qt import QtCore, QtGui
-import IPython.utils.html_utils as html_utils
 
+#--------------------------------------------------------------------------
+# Return an HTML table with selected item in a special class
+#--------------------------------------------------------------------------
+def html_tableify(item_matrix, select=None, header=None , footer=None) :
+    """ returnr a string for an html table"""
+    if not item_matrix :
+        return ''
+    html_cols = []
+    tds = lambda text : u'<td>'+text+u'  </td>'
+    trs = lambda text : u'<tr>'+text+u'</tr>'
+    tds_items = [map(tds, row) for row in item_matrix]
+    if select :
+        row, col = select
+        tds_items[row][col] = u'<td class="inverted">'\
+                +item_matrix[row][col]\
+                +u'  </td>'
+    #select the right item
+    html_cols = map(trs, (u''.join(row) for row in tds_items))
+    head = ''
+    foot = ''
+    if header :
+        head = (u'<tr>'\
+            +''.join((u'<td>'+header+u'</td>')*len(item_matrix[0]))\
+            +'</tr>')
+
+    if footer : 
+        foot = (u'<tr>'\
+            +''.join((u'<td>'+footer+u'</td>')*len(item_matrix[0]))\
+            +'</tr>')
+    html = (u'<table class="completion" style="white-space:pre">'+head+(u''.join(html_cols))+foot+u'</table>')
+    return html
+
+class SlidingInterval(object): 
+    """a bound interval that follows a cursor
+    
+    internally used to scoll the completion view when the cursor 
+    try to go beyond the edges, and show '...' when rows are hidden
+    """
+    
+    _min = 0
+    _max = 1
+    _current = 0
+    def __init__(self, maximum=1, width=6, minimum=0, sticky_lenght=1):
+        """Create a new bounded interval
+        
+        any value return by this will be bound between maximum and 
+        minimum. usual width will be 'width', and sticky_length 
+        set when the return  interval should expand to max and min
+        """
+        self._min = minimum 
+        self._max = maximum
+        self._start = 0
+        self._width = width
+        self._stop = self._start+self._width+1
+        self._sticky_lenght = sticky_lenght
+        
+    @property
+    def current(self):
+        """current cursor position"""
+        return self._current
+    
+    @current.setter
+    def current(self, value):
+        """set current cursor position"""
+        current = min(max(self._min, value), self._max)
+
+        self._current = current
+
+        if current > self._stop : 
+            self._stop = current
+            self._start = current-self._width
+        elif current < self._start : 
+            self._start = current
+            self._stop = current + self._width
+
+        if abs(self._start - self._min) <= self._sticky_lenght :
+            self._start = self._min
+        
+        if abs(self._stop - self._max) <= self._sticky_lenght :
+            self._stop = self._max
+
+    @property 
+    def start(self):
+        """begiiing of interval to show"""
+        return self._start
+        
+    @property
+    def stop(self):
+        """end of interval to show"""
+        return self._stop
+
+    @property
+    def width(self):
+        return self._stop - self._start
+
+    @property 
+    def nth(self):
+        return self.current - self.start
 
 class CompletionHtml(QtGui.QWidget):
     """ A widget for tab completion,  navigable by arrow keys """
@@ -16,6 +125,8 @@ class CompletionHtml(QtGui.QWidget):
     _size = (1, 1)
     _old_cursor = None
     _start_position = 0
+    _slice_start = 0
+    _slice_len = 4
 
     def __init__(self, console_widget):
         """ Create a completion widget that is attached to the specified Qt
@@ -27,6 +138,8 @@ class CompletionHtml(QtGui.QWidget):
         self._text_edit = console_widget._control
         self._console_widget = console_widget
         self._text_edit.installEventFilter(self)
+        self._sliding_interval = None
+        self._justified_items = None
 
         # Ensure that the text edit keeps focus when widget is displayed.
         self.setFocusProxy(self._text_edit)
@@ -71,24 +184,36 @@ class CompletionHtml(QtGui.QWidget):
                         self.select_left()
                         self._update_list()
                         return True
+                    elif key in ( QtCore.Qt.Key_Escape,):
+                        self.cancel_completion()
+                        return True
                     else :
-                        self._cancel_completion()
+                        self.cancel_completion()
                 else:
-                    self._cancel_completion()
+                    self.cancel_completion()
 
             elif etype == QtCore.QEvent.FocusOut:
-                self._cancel_completion()
+                self.cancel_completion()
 
         return super(CompletionHtml, self).eventFilter(obj, event)
 
     #--------------------------------------------------------------------------
     # 'CompletionHtml' interface
     #--------------------------------------------------------------------------
-    def _cancel_completion(self):
-        """Cancel the completion, reseting internal variable, clearing buffer """
+    def cancel_completion(self):
+        """Cancel the completion
+
+        should be called when the completer have to be dismissed
+
+        This reset internal variable, clearing the temporary buffer
+        of the console where the completion are shown.
+        """
         self._consecutive_tab = 0
+        self._slice_start = 0
         self._console_widget._clear_temporary_buffer()
         self._index = (0, 0)
+        if(self._sliding_interval):
+            self._sliding_interval = None
 
     #
     #  ...  2 4 4 4 4 4 4 4 4 4 4  4  4
@@ -147,6 +272,12 @@ class CompletionHtml(QtGui.QWidget):
                            have gone before : %d:%d (%d:%d)"%(row, col, nr, nc) )
 
 
+    @property
+    def _slice_end(self):
+        end = self._slice_start+self._slice_len
+        if end > len(self._items) :
+            return None
+        return end
 
     def select_up(self):
         """move cursor up"""
@@ -176,27 +307,42 @@ class CompletionHtml(QtGui.QWidget):
             return
         self._start_position = cursor.position()
         self._consecutive_tab = 1
-        ci = html_utils.columnize_info(items, empty=' ')
-        self._items = ci['item_matrix']
-        self._size = (ci['rows_number'], ci['columns_number'])
+        items_m, ci = text.compute_item_matrix(items, empty=' ')
+        self._sliding_interval = SlidingInterval(len(items_m)-1)
+
+        self._items = items_m
+        self._size = (ci['rows_numbers'], ci['columns_numbers'])
         self._old_cursor = cursor
         self._index = (0, 0)
+        sjoin = lambda x : [ y.ljust(w, ' ') for y, w in zip(x, ci['columns_width'])]
+        self._justified_items = map(sjoin, items_m)
         self._update_list(hilight=False)
 
 
+
+
     def _update_list(self, hilight=True):
         """ update the list of completion and hilight the currently selected completion """
-        if len(self._items) > 100:
-            items = self._items[:100]
-        else :
-            items = self._items
-        items_m = items
+        self._sliding_interval.current = self._index[0]
+        head = None
+        foot = None
+        if self._sliding_interval.start > 0 : 
+            head = '...'
+
+        if self._sliding_interval.stop < self._sliding_interval._max:
+            foot = '...'
+        items_m = self._justified_items[\
+                       self._sliding_interval.start:\
+                       self._sliding_interval.stop+1\
+                                       ]
 
         self._console_widget._clear_temporary_buffer()
         if(hilight):
-            strng = html_utils.html_tableify(items_m, select=self._index)
-        else:
-            strng = html_utils.html_tableify(items_m, select=None)
+            sel = (self._sliding_interval.nth, self._index[1])
+        else :
+            sel = None
+
+        strng = html_tableify(items_m, select=sel, header=head, footer=foot)
         self._console_widget._fill_temporary_buffer(self._old_cursor, strng, html=True)
 
     #--------------------------------------------------------------------------
@@ -211,7 +357,7 @@ class CompletionHtml(QtGui.QWidget):
         item = item.strip()
         if item :
             self._current_text_cursor().insertText(item)
-        self._cancel_completion()
+        self.cancel_completion()
 
     def _current_text_cursor(self):
         """ Returns a cursor with text between the start position and the
@@ -223,4 +369,3 @@ class CompletionHtml(QtGui.QWidget):
                                QtGui.QTextCursor.KeepAnchor)
         return cursor
 
-
diff --git a/IPython/frontend/qt/console/completion_plain.py b/IPython/frontend/qt/console/completion_plain.py
index 8db0069..d6b4066 100644
--- a/IPython/frontend/qt/console/completion_plain.py
+++ b/IPython/frontend/qt/console/completion_plain.py
@@ -1,6 +1,15 @@
+"""a simple completer for the qtconsole"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2012, IPython Development Team.$
+#
+# Distributed under the terms of the Modified BSD License.$
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-------------------------------------------------------------------
+
 # System library imports
 from IPython.external.qt import QtCore, QtGui
-import IPython.utils.html_utils as html_utils
+import IPython.utils.text as text
 
 
 class CompletionPlain(QtGui.QWidget):
@@ -10,10 +19,6 @@ class CompletionPlain(QtGui.QWidget):
     # 'QObject' interface
     #--------------------------------------------------------------------------
 
-    _items = ()
-    _index = (0, 0)
-    _old_cursor = None
-
     def __init__(self, console_widget):
         """ Create a completion widget that is attached to the specified Qt
             text edit widget.
@@ -33,18 +38,17 @@ class CompletionPlain(QtGui.QWidget):
         if obj == self._text_edit:
             etype = event.type()
 
-            if etype == QtCore.QEvent.KeyPress:
-                self._cancel_completion()
+            if etype in( QtCore.QEvent.KeyPress, QtCore.QEvent.FocusOut ):
+                self.cancel_completion()
 
         return super(CompletionPlain, self).eventFilter(obj, event)
 
     #--------------------------------------------------------------------------
     # 'CompletionPlain' interface
     #--------------------------------------------------------------------------
-    def _cancel_completion(self):
+    def cancel_completion(self):
         """Cancel the completion, reseting internal variable, clearing buffer """
         self._console_widget._clear_temporary_buffer()
-        self._index = (0, 0)
 
 
     def show_items(self, cursor, items):
@@ -53,21 +57,6 @@ class CompletionPlain(QtGui.QWidget):
         """
         if not items :
             return
-
-        ci = html_utils.columnize_info(items, empty=' ')
-        self._items = ci['item_matrix']
-        self._old_cursor = cursor
-        self._update_list()
-
-
-    def _update_list(self):
-        """ update the list of completion and hilight the currently selected completion """
-        if len(self._items) > 100:
-            items = self._items[:100]
-        else :
-            items = self._items
-        items_m = items
-
-        self._console_widget._clear_temporary_buffer()
-        strng = html_utils.html_tableify(items_m, select=None)
-        self._console_widget._fill_temporary_buffer(self._old_cursor, strng, html=True)
+        self.cancel_completion()
+        strng = text.columnize(items)
+        self._console_widget._fill_temporary_buffer(cursor, strng, html=False)
diff --git a/IPython/frontend/qt/console/completion_widget.py b/IPython/frontend/qt/console/completion_widget.py
index 8103f05..b258775 100644
--- a/IPython/frontend/qt/console/completion_widget.py
+++ b/IPython/frontend/qt/console/completion_widget.py
@@ -134,5 +134,5 @@ class CompletionWidget(QtGui.QListWidget):
         else:
             self.hide()
 
-    def _cancel_completion(self):
+    def cancel_completion(self):
         self.hide()
diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py
index 75bb12e..cd2a93c 100644
--- a/IPython/frontend/qt/console/console_widget.py
+++ b/IPython/frontend/qt/console/console_widget.py
@@ -843,7 +843,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):
     def _cancel_completion(self):
         """ If text completion is progress, cancel it.
         """
-        self._completion_widget._cancel_completion()
+        self._completion_widget.cancel_completion()
 
     def _clear_temporary_buffer(self):
         """ Clears the "temporary text" buffer, i.e. all the text following
diff --git a/IPython/frontend/qt/console/qtconsoleapp.py b/IPython/frontend/qt/console/qtconsoleapp.py
index e1eac4c..1735d9b 100644
--- a/IPython/frontend/qt/console/qtconsoleapp.py
+++ b/IPython/frontend/qt/console/qtconsoleapp.py
@@ -105,13 +105,6 @@ qt_flags = {
             "Disable rich text support."),
 }
 
-# not quite sure on how this works
-#qt_flags.update(boolean_flag(
-#    'gui-completion', 'ConsoleWidget.gui_completion',
-#    "use a GUI widget for tab completion",
-#    "use plaintext output for completion"
-#))
-
 # and app_flags from the Console Mixin
 qt_flags.update(app_flags)
 # add frontend flags to the full set
diff --git a/IPython/utils/html_utils.py b/IPython/utils/html_utils.py
deleted file mode 100644
index aaf2f2b..0000000
--- a/IPython/utils/html_utils.py
+++ /dev/null
@@ -1,124 +0,0 @@
-"""some html utilis"""
-from IPython.core.display import HTML
-
-
-def columnize_info(items, separator_width=1, displaywidth=80, empty=None):
-    """ Get info on a list of string to display it as a multicolumns list
-
-    returns :
-    ---------
-
-    a dict containing several parameters:
-
-    'item_matrix'  : list of list with the innermost list representing a row
-    'columns_number': number of columns
-    'rows_number'   : number of rown
-    'columns_width' : a list indicating the maximum length of the element in each columns
-
-    Parameters :
-    ------------
-    separator_width : when trying to ajust the number of column, consider a separator size of this much caracters
-    displaywidth    : try to fit the columns in this width
-    empty           : if the number of items is different from nrows * ncols, fill with empty
-
-    """
-    # Note: this code is adapted from columnize 0.3.2.
-    # See http://code.google.com/p/pycolumnize/
-
-    # Some degenerate cases.
-    size = len(items)
-    if size == 0:
-        return {'item_matrix' :[[empty]],
-                'columns_number':1,
-                'rows_number':1,
-                'columns_width':[0]}
-    elif size == 1:
-        return {'item_matrix' :[[items[0]]],
-                'columns_number':1,
-                'rows_number':1,
-                'columns_width':[len(items[0])]}
-
-    # Special case: if any item is longer than the maximum width, there's no
-    # point in triggering the logic below...
-    item_len = map(len, items) # save these, we can reuse them below
-    #longest = max(item_len)
-    #if longest >= displaywidth:
-    #    return (items, [longest])
-
-    # Try every row count from 1 upwards
-    array_index = lambda nrows, row, col: nrows*col + row
-    nrows = 1
-    for nrows in range(1, size):
-        ncols = (size + nrows - 1) // nrows
-        colwidths = []
-        totwidth = -separator_width
-        for col in range(ncols):
-            # Get max column width for this column
-            colwidth = 0
-            for row in range(nrows):
-                i = array_index(nrows, row, col)
-                if i >= size:
-                    break
-                len_x = item_len[i]
-                colwidth = max(colwidth, len_x)
-            colwidths.append(colwidth)
-            totwidth += colwidth + separator_width
-            if totwidth > displaywidth:
-                break
-        if totwidth <= displaywidth:
-            break
-
-    # The smallest number of rows computed and the max widths for each
-    # column has been obtained. Now we just have to format each of the rows.
-    reorderd_items = []
-    for row in range(nrows):
-        texts = []
-        for col in range(ncols):
-            i = row + nrows*col
-            if i >= size:
-                texts.append(empty)
-            else:
-                texts.append(items[i])
-        #while texts and not texts[-1]:
-        #    del texts[-1]
-        #for col in range(len(texts)):
-        #    texts[col] = texts[col].ljust(colwidths[col])
-        reorderd_items.append(texts)
-
-    return {'item_matrix' :reorderd_items,
-            'columns_number':ncols,
-            'rows_number':nrows,
-            'columns_width':colwidths}
-
-
-def column_table(items, select=None) :
-    """ return a html table of the item with a select class on one"""
-    items_m = columnize_info(items)['item_matrix']
-    return HTML(html_tableify(items_m, select=select))
-
-def html_tableify(item_matrix, select=None) :
-    """ returnr a string for an html table"""
-    if not item_matrix :
-        return ''
-    html_cols = []
-    tds = lambda text : u'<td>'+text+u'</td>'
-    trs = lambda text : u'<tr>'+text+u'</tr>'
-    tds_items = [map(tds, row) for row in item_matrix ]
-    if select :
-        row, col = select
-        try :
-            tds_items[row][col] = u'<td class="inverted">'\
-                    +item_matrix[row][col]\
-                    +u'</td>'
-        except IndexError :
-            pass
-    #select the right item
-    html_cols = map(trs, (u''.join(row) for row in tds_items))
-    html = (u'<table class="completion">'+(u''.join(html_cols))+u'</table>')
-    css = u"""
-    <style>
-    table.completion tr td
-    { padding-right : 4px; }
-    </style>
-    """
-    return css+html
diff --git a/IPython/utils/text.py b/IPython/utils/text.py
index 85db442..0df0bec 100644
--- a/IPython/utils/text.py
+++ b/IPython/utils/text.py
@@ -690,7 +690,7 @@ def _get_or_default(mylist, i, default=None):
         return mylist[i]
 
 @skip_doctest
-def compute_item_matrix(items, *args, **kwargs) :
+def compute_item_matrix(items, empty=None, *args, **kwargs) :
     """Returns a nested list, and info to columnize items
 
     Parameters :
@@ -698,6 +698,8 @@ def compute_item_matrix(items, *args, **kwargs) :
 
     items :
         list of strings to columize
+    empty : (default None)
+        default value to fill list if needed
     separator_size : int (default=2)
         How much caracters will be used as a separation between each columns.
     displaywidth : int (default=80)