##// END OF EJS Templates
new completer for qtconsole...
Matthias BUSSONNIER -
Show More
@@ -1,7 +1,116 b''
1 """a navigable completer for the qtconsole"""
2 # coding : utf-8
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012, IPython Development Team.$
5 #
6 # Distributed under the terms of the Modified BSD License.$
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
1 # System library imports
11 # System library imports
12 import IPython.utils.text as text
13
2 from IPython.external.qt import QtCore, QtGui
14 from IPython.external.qt import QtCore, QtGui
3 import IPython.utils.html_utils as html_utils
4
15
16 #--------------------------------------------------------------------------
17 # Return an HTML table with selected item in a special class
18 #--------------------------------------------------------------------------
19 def html_tableify(item_matrix, select=None, header=None , footer=None) :
20 """ returnr a string for an html table"""
21 if not item_matrix :
22 return ''
23 html_cols = []
24 tds = lambda text : u'<td>'+text+u' </td>'
25 trs = lambda text : u'<tr>'+text+u'</tr>'
26 tds_items = [map(tds, row) for row in item_matrix]
27 if select :
28 row, col = select
29 tds_items[row][col] = u'<td class="inverted">'\
30 +item_matrix[row][col]\
31 +u' </td>'
32 #select the right item
33 html_cols = map(trs, (u''.join(row) for row in tds_items))
34 head = ''
35 foot = ''
36 if header :
37 head = (u'<tr>'\
38 +''.join((u'<td>'+header+u'</td>')*len(item_matrix[0]))\
39 +'</tr>')
40
41 if footer :
42 foot = (u'<tr>'\
43 +''.join((u'<td>'+footer+u'</td>')*len(item_matrix[0]))\
44 +'</tr>')
45 html = (u'<table class="completion" style="white-space:pre">'+head+(u''.join(html_cols))+foot+u'</table>')
46 return html
47
48 class SlidingInterval(object):
49 """a bound interval that follows a cursor
50
51 internally used to scoll the completion view when the cursor
52 try to go beyond the edges, and show '...' when rows are hidden
53 """
54
55 _min = 0
56 _max = 1
57 _current = 0
58 def __init__(self, maximum=1, width=6, minimum=0, sticky_lenght=1):
59 """Create a new bounded interval
60
61 any value return by this will be bound between maximum and
62 minimum. usual width will be 'width', and sticky_length
63 set when the return interval should expand to max and min
64 """
65 self._min = minimum
66 self._max = maximum
67 self._start = 0
68 self._width = width
69 self._stop = self._start+self._width+1
70 self._sticky_lenght = sticky_lenght
71
72 @property
73 def current(self):
74 """current cursor position"""
75 return self._current
76
77 @current.setter
78 def current(self, value):
79 """set current cursor position"""
80 current = min(max(self._min, value), self._max)
81
82 self._current = current
83
84 if current > self._stop :
85 self._stop = current
86 self._start = current-self._width
87 elif current < self._start :
88 self._start = current
89 self._stop = current + self._width
90
91 if abs(self._start - self._min) <= self._sticky_lenght :
92 self._start = self._min
93
94 if abs(self._stop - self._max) <= self._sticky_lenght :
95 self._stop = self._max
96
97 @property
98 def start(self):
99 """begiiing of interval to show"""
100 return self._start
101
102 @property
103 def stop(self):
104 """end of interval to show"""
105 return self._stop
106
107 @property
108 def width(self):
109 return self._stop - self._start
110
111 @property
112 def nth(self):
113 return self.current - self.start
5
114
6 class CompletionHtml(QtGui.QWidget):
115 class CompletionHtml(QtGui.QWidget):
7 """ A widget for tab completion, navigable by arrow keys """
116 """ A widget for tab completion, navigable by arrow keys """
@@ -16,6 +125,8 b' class CompletionHtml(QtGui.QWidget):'
16 _size = (1, 1)
125 _size = (1, 1)
17 _old_cursor = None
126 _old_cursor = None
18 _start_position = 0
127 _start_position = 0
128 _slice_start = 0
129 _slice_len = 4
19
130
20 def __init__(self, console_widget):
131 def __init__(self, console_widget):
21 """ Create a completion widget that is attached to the specified Qt
132 """ Create a completion widget that is attached to the specified Qt
@@ -27,6 +138,8 b' class CompletionHtml(QtGui.QWidget):'
27 self._text_edit = console_widget._control
138 self._text_edit = console_widget._control
28 self._console_widget = console_widget
139 self._console_widget = console_widget
29 self._text_edit.installEventFilter(self)
140 self._text_edit.installEventFilter(self)
141 self._sliding_interval = None
142 self._justified_items = None
30
143
31 # Ensure that the text edit keeps focus when widget is displayed.
144 # Ensure that the text edit keeps focus when widget is displayed.
32 self.setFocusProxy(self._text_edit)
145 self.setFocusProxy(self._text_edit)
@@ -71,24 +184,36 b' class CompletionHtml(QtGui.QWidget):'
71 self.select_left()
184 self.select_left()
72 self._update_list()
185 self._update_list()
73 return True
186 return True
187 elif key in ( QtCore.Qt.Key_Escape,):
188 self.cancel_completion()
189 return True
74 else :
190 else :
75 self._cancel_completion()
191 self.cancel_completion()
76 else:
192 else:
77 self._cancel_completion()
193 self.cancel_completion()
78
194
79 elif etype == QtCore.QEvent.FocusOut:
195 elif etype == QtCore.QEvent.FocusOut:
80 self._cancel_completion()
196 self.cancel_completion()
81
197
82 return super(CompletionHtml, self).eventFilter(obj, event)
198 return super(CompletionHtml, self).eventFilter(obj, event)
83
199
84 #--------------------------------------------------------------------------
200 #--------------------------------------------------------------------------
85 # 'CompletionHtml' interface
201 # 'CompletionHtml' interface
86 #--------------------------------------------------------------------------
202 #--------------------------------------------------------------------------
87 def _cancel_completion(self):
203 def cancel_completion(self):
88 """Cancel the completion, reseting internal variable, clearing buffer """
204 """Cancel the completion
205
206 should be called when the completer have to be dismissed
207
208 This reset internal variable, clearing the temporary buffer
209 of the console where the completion are shown.
210 """
89 self._consecutive_tab = 0
211 self._consecutive_tab = 0
212 self._slice_start = 0
90 self._console_widget._clear_temporary_buffer()
213 self._console_widget._clear_temporary_buffer()
91 self._index = (0, 0)
214 self._index = (0, 0)
215 if(self._sliding_interval):
216 self._sliding_interval = None
92
217
93 #
218 #
94 # ... 2 4 4 4 4 4 4 4 4 4 4 4 4
219 # ... 2 4 4 4 4 4 4 4 4 4 4 4 4
@@ -147,6 +272,12 b' class CompletionHtml(QtGui.QWidget):'
147 have gone before : %d:%d (%d:%d)"%(row, col, nr, nc) )
272 have gone before : %d:%d (%d:%d)"%(row, col, nr, nc) )
148
273
149
274
275 @property
276 def _slice_end(self):
277 end = self._slice_start+self._slice_len
278 if end > len(self._items) :
279 return None
280 return end
150
281
151 def select_up(self):
282 def select_up(self):
152 """move cursor up"""
283 """move cursor up"""
@@ -176,27 +307,42 b' class CompletionHtml(QtGui.QWidget):'
176 return
307 return
177 self._start_position = cursor.position()
308 self._start_position = cursor.position()
178 self._consecutive_tab = 1
309 self._consecutive_tab = 1
179 ci = html_utils.columnize_info(items, empty=' ')
310 items_m, ci = text.compute_item_matrix(items, empty=' ')
180 self._items = ci['item_matrix']
311 self._sliding_interval = SlidingInterval(len(items_m)-1)
181 self._size = (ci['rows_number'], ci['columns_number'])
312
313 self._items = items_m
314 self._size = (ci['rows_numbers'], ci['columns_numbers'])
182 self._old_cursor = cursor
315 self._old_cursor = cursor
183 self._index = (0, 0)
316 self._index = (0, 0)
317 sjoin = lambda x : [ y.ljust(w, ' ') for y, w in zip(x, ci['columns_width'])]
318 self._justified_items = map(sjoin, items_m)
184 self._update_list(hilight=False)
319 self._update_list(hilight=False)
185
320
186
321
322
323
187 def _update_list(self, hilight=True):
324 def _update_list(self, hilight=True):
188 """ update the list of completion and hilight the currently selected completion """
325 """ update the list of completion and hilight the currently selected completion """
189 if len(self._items) > 100:
326 self._sliding_interval.current = self._index[0]
190 items = self._items[:100]
327 head = None
191 else :
328 foot = None
192 items = self._items
329 if self._sliding_interval.start > 0 :
193 items_m = items
330 head = '...'
331
332 if self._sliding_interval.stop < self._sliding_interval._max:
333 foot = '...'
334 items_m = self._justified_items[\
335 self._sliding_interval.start:\
336 self._sliding_interval.stop+1\
337 ]
194
338
195 self._console_widget._clear_temporary_buffer()
339 self._console_widget._clear_temporary_buffer()
196 if(hilight):
340 if(hilight):
197 strng = html_utils.html_tableify(items_m, select=self._index)
341 sel = (self._sliding_interval.nth, self._index[1])
198 else:
342 else :
199 strng = html_utils.html_tableify(items_m, select=None)
343 sel = None
344
345 strng = html_tableify(items_m, select=sel, header=head, footer=foot)
200 self._console_widget._fill_temporary_buffer(self._old_cursor, strng, html=True)
346 self._console_widget._fill_temporary_buffer(self._old_cursor, strng, html=True)
201
347
202 #--------------------------------------------------------------------------
348 #--------------------------------------------------------------------------
@@ -211,7 +357,7 b' class CompletionHtml(QtGui.QWidget):'
211 item = item.strip()
357 item = item.strip()
212 if item :
358 if item :
213 self._current_text_cursor().insertText(item)
359 self._current_text_cursor().insertText(item)
214 self._cancel_completion()
360 self.cancel_completion()
215
361
216 def _current_text_cursor(self):
362 def _current_text_cursor(self):
217 """ Returns a cursor with text between the start position and the
363 """ Returns a cursor with text between the start position and the
@@ -223,4 +369,3 b' class CompletionHtml(QtGui.QWidget):'
223 QtGui.QTextCursor.KeepAnchor)
369 QtGui.QTextCursor.KeepAnchor)
224 return cursor
370 return cursor
225
371
226
@@ -1,6 +1,15 b''
1 """a simple completer for the qtconsole"""
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2012, IPython Development Team.$
4 #
5 # Distributed under the terms of the Modified BSD License.$
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-------------------------------------------------------------------
9
1 # System library imports
10 # System library imports
2 from IPython.external.qt import QtCore, QtGui
11 from IPython.external.qt import QtCore, QtGui
3 import IPython.utils.html_utils as html_utils
12 import IPython.utils.text as text
4
13
5
14
6 class CompletionPlain(QtGui.QWidget):
15 class CompletionPlain(QtGui.QWidget):
@@ -10,10 +19,6 b' class CompletionPlain(QtGui.QWidget):'
10 # 'QObject' interface
19 # 'QObject' interface
11 #--------------------------------------------------------------------------
20 #--------------------------------------------------------------------------
12
21
13 _items = ()
14 _index = (0, 0)
15 _old_cursor = None
16
17 def __init__(self, console_widget):
22 def __init__(self, console_widget):
18 """ Create a completion widget that is attached to the specified Qt
23 """ Create a completion widget that is attached to the specified Qt
19 text edit widget.
24 text edit widget.
@@ -33,18 +38,17 b' class CompletionPlain(QtGui.QWidget):'
33 if obj == self._text_edit:
38 if obj == self._text_edit:
34 etype = event.type()
39 etype = event.type()
35
40
36 if etype == QtCore.QEvent.KeyPress:
41 if etype in( QtCore.QEvent.KeyPress, QtCore.QEvent.FocusOut ):
37 self._cancel_completion()
42 self.cancel_completion()
38
43
39 return super(CompletionPlain, self).eventFilter(obj, event)
44 return super(CompletionPlain, self).eventFilter(obj, event)
40
45
41 #--------------------------------------------------------------------------
46 #--------------------------------------------------------------------------
42 # 'CompletionPlain' interface
47 # 'CompletionPlain' interface
43 #--------------------------------------------------------------------------
48 #--------------------------------------------------------------------------
44 def _cancel_completion(self):
49 def cancel_completion(self):
45 """Cancel the completion, reseting internal variable, clearing buffer """
50 """Cancel the completion, reseting internal variable, clearing buffer """
46 self._console_widget._clear_temporary_buffer()
51 self._console_widget._clear_temporary_buffer()
47 self._index = (0, 0)
48
52
49
53
50 def show_items(self, cursor, items):
54 def show_items(self, cursor, items):
@@ -53,21 +57,6 b' class CompletionPlain(QtGui.QWidget):'
53 """
57 """
54 if not items :
58 if not items :
55 return
59 return
56
60 self.cancel_completion()
57 ci = html_utils.columnize_info(items, empty=' ')
61 strng = text.columnize(items)
58 self._items = ci['item_matrix']
62 self._console_widget._fill_temporary_buffer(cursor, strng, html=False)
59 self._old_cursor = cursor
60 self._update_list()
61
62
63 def _update_list(self):
64 """ update the list of completion and hilight the currently selected completion """
65 if len(self._items) > 100:
66 items = self._items[:100]
67 else :
68 items = self._items
69 items_m = items
70
71 self._console_widget._clear_temporary_buffer()
72 strng = html_utils.html_tableify(items_m, select=None)
73 self._console_widget._fill_temporary_buffer(self._old_cursor, strng, html=True)
@@ -134,5 +134,5 b' class CompletionWidget(QtGui.QListWidget):'
134 else:
134 else:
135 self.hide()
135 self.hide()
136
136
137 def _cancel_completion(self):
137 def cancel_completion(self):
138 self.hide()
138 self.hide()
@@ -843,7 +843,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
843 def _cancel_completion(self):
843 def _cancel_completion(self):
844 """ If text completion is progress, cancel it.
844 """ If text completion is progress, cancel it.
845 """
845 """
846 self._completion_widget._cancel_completion()
846 self._completion_widget.cancel_completion()
847
847
848 def _clear_temporary_buffer(self):
848 def _clear_temporary_buffer(self):
849 """ Clears the "temporary text" buffer, i.e. all the text following
849 """ Clears the "temporary text" buffer, i.e. all the text following
@@ -105,13 +105,6 b' qt_flags = {'
105 "Disable rich text support."),
105 "Disable rich text support."),
106 }
106 }
107
107
108 # not quite sure on how this works
109 #qt_flags.update(boolean_flag(
110 # 'gui-completion', 'ConsoleWidget.gui_completion',
111 # "use a GUI widget for tab completion",
112 # "use plaintext output for completion"
113 #))
114
115 # and app_flags from the Console Mixin
108 # and app_flags from the Console Mixin
116 qt_flags.update(app_flags)
109 qt_flags.update(app_flags)
117 # add frontend flags to the full set
110 # add frontend flags to the full set
@@ -690,7 +690,7 b' def _get_or_default(mylist, i, default=None):'
690 return mylist[i]
690 return mylist[i]
691
691
692 @skip_doctest
692 @skip_doctest
693 def compute_item_matrix(items, *args, **kwargs) :
693 def compute_item_matrix(items, empty=None, *args, **kwargs) :
694 """Returns a nested list, and info to columnize items
694 """Returns a nested list, and info to columnize items
695
695
696 Parameters :
696 Parameters :
@@ -698,6 +698,8 b' def compute_item_matrix(items, *args, **kwargs) :'
698
698
699 items :
699 items :
700 list of strings to columize
700 list of strings to columize
701 empty : (default None)
702 default value to fill list if needed
701 separator_size : int (default=2)
703 separator_size : int (default=2)
702 How much caracters will be used as a separation between each columns.
704 How much caracters will be used as a separation between each columns.
703 displaywidth : int (default=80)
705 displaywidth : int (default=80)
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now