##// END OF EJS Templates
json is json, not string....
Matthias Bussonnier -
Show More
@@ -1,213 +1,211 b''
1 1 """MagicHelper - dockable widget showing magic commands for the MainWindow
2 2 """
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Imports
9 9 #-----------------------------------------------------------------------------
10 10
11 11 # stdlib imports
12 12 import json
13 13 import re
14 14 import sys
15 15
16 16 # System library imports
17 17 from IPython.external.qt import QtGui,QtCore
18 18
19 19 from IPython.core.magic import magic_escapes
20 20
21 21 class MagicHelper(QtGui.QDockWidget):
22 22 """MagicHelper - dockable widget for convenient search and running of
23 23 magic command for IPython QtConsole.
24 24 """
25 25
26 26 #---------------------------------------------------------------------------
27 27 # signals
28 28 #---------------------------------------------------------------------------
29 29
30 30 pasteRequested = QtCore.Signal(str, name = 'pasteRequested')
31 31 """This signal is emitted when user wants to paste selected magic
32 32 command into the command line.
33 33 """
34 34
35 35 runRequested = QtCore.Signal(str, name = 'runRequested')
36 36 """This signal is emitted when user wants to execute selected magic command
37 37 """
38 38
39 39 readyForUpdate = QtCore.Signal(name = 'readyForUpdate')
40 40 """This signal is emitted when MagicHelper is ready to be populated.
41 41 Since kernel querying mechanisms are out of scope of this class,
42 42 it expects its owner to invoke MagicHelper.populate_magic_helper()
43 43 as a reaction on this event.
44 44 """
45 45
46 46 #---------------------------------------------------------------------------
47 47 # constructor
48 48 #---------------------------------------------------------------------------
49 49
50 50 def __init__(self, name, parent):
51 51 super(MagicHelper, self).__init__(name, parent)
52 52
53 53 self.data = None
54 54
55 55 class MinListWidget(QtGui.QListWidget):
56 56 """Temp class to overide the default QListWidget size hint
57 57 in order to make MagicHelper narrow
58 58 """
59 59 def sizeHint(self):
60 60 s = QtCore.QSize()
61 61 s.setHeight(super(MinListWidget,self).sizeHint().height())
62 62 s.setWidth(self.sizeHintForColumn(0))
63 63 return s
64 64
65 65 # construct content
66 66 self.frame = QtGui.QFrame()
67 67 self.search_label = QtGui.QLabel("Search:")
68 68 self.search_line = QtGui.QLineEdit()
69 69 self.search_class = QtGui.QComboBox()
70 70 self.search_list = MinListWidget()
71 71 self.paste_button = QtGui.QPushButton("Paste")
72 72 self.run_button = QtGui.QPushButton("Run")
73 73
74 74 # layout all the widgets
75 75 main_layout = QtGui.QVBoxLayout()
76 76 search_layout = QtGui.QHBoxLayout()
77 77 search_layout.addWidget(self.search_label)
78 78 search_layout.addWidget(self.search_line, 10)
79 79 main_layout.addLayout(search_layout)
80 80 main_layout.addWidget(self.search_class)
81 81 main_layout.addWidget(self.search_list, 10)
82 82 action_layout = QtGui.QHBoxLayout()
83 83 action_layout.addWidget(self.paste_button)
84 84 action_layout.addWidget(self.run_button)
85 85 main_layout.addLayout(action_layout)
86 86
87 87 self.frame.setLayout(main_layout)
88 88 self.setWidget(self.frame)
89 89
90 90 # connect all the relevant signals to handlers
91 91 self.visibilityChanged[bool].connect( self._update_magic_helper )
92 92 self.search_class.activated[int].connect(
93 93 self.class_selected
94 94 )
95 95 self.search_line.textChanged[str].connect(
96 96 self.search_changed
97 97 )
98 98 self.search_list.itemDoubleClicked.connect(
99 99 self.paste_requested
100 100 )
101 101 self.paste_button.clicked[bool].connect(
102 102 self.paste_requested
103 103 )
104 104 self.run_button.clicked[bool].connect(
105 105 self.run_requested
106 106 )
107 107
108 108 #---------------------------------------------------------------------------
109 109 # implementation
110 110 #---------------------------------------------------------------------------
111 111
112 112 def _update_magic_helper(self, visible):
113 113 """Start update sequence.
114 114 This method is called when MagicHelper becomes visible. It clears
115 115 the content and emits readyForUpdate signal. The owner of the
116 116 instance is expected to invoke populate_magic_helper() when magic
117 117 info is available.
118 118 """
119 119 if not visible or self.data is not None:
120 120 return
121 121 self.data = {}
122 122 self.search_class.clear()
123 123 self.search_class.addItem("Populating...")
124 124 self.search_list.clear()
125 125 self.readyForUpdate.emit()
126 126
127 127 def populate_magic_helper(self, data):
128 128 """Expects data returned by lsmagics query from kernel.
129 129 Populates the search_class and search_list with relevant items.
130 130 """
131 131 self.search_class.clear()
132 132 self.search_list.clear()
133 133
134 self.data = json.loads(
135 data['data'].get('application/json', {})
136 )
134 self.data = data['data'].get('application/json', {})
137 135
138 136 self.search_class.addItem('All Magics', 'any')
139 137 classes = set()
140 138
141 139 for mtype in sorted(self.data):
142 140 subdict = self.data[mtype]
143 141 for name in sorted(subdict):
144 142 classes.add(subdict[name])
145 143
146 144 for cls in sorted(classes):
147 145 label = re.sub("([a-zA-Z]+)([A-Z][a-z])","\g<1> \g<2>", cls)
148 146 self.search_class.addItem(label, cls)
149 147
150 148 self.filter_magic_helper('.', 'any')
151 149
152 150 def class_selected(self, index):
153 151 """Handle search_class selection changes
154 152 """
155 153 item = self.search_class.itemData(index)
156 154 regex = self.search_line.text()
157 155 self.filter_magic_helper(regex = regex, cls = item)
158 156
159 157 def search_changed(self, search_string):
160 158 """Handle search_line text changes.
161 159 The text is interpreted as a regular expression
162 160 """
163 161 item = self.search_class.itemData(
164 162 self.search_class.currentIndex()
165 163 )
166 164 self.filter_magic_helper(regex = search_string, cls = item)
167 165
168 166 def _get_current_search_item(self, item = None):
169 167 """Retrieve magic command currently selected in the search_list
170 168 """
171 169 text = None
172 170 if not isinstance(item, QtGui.QListWidgetItem):
173 171 item = self.search_list.currentItem()
174 172 text = item.text()
175 173 return text
176 174
177 175 def paste_requested(self, item = None):
178 176 """Emit pasteRequested signal with currently selected item text
179 177 """
180 178 text = self._get_current_search_item(item)
181 179 if text is not None:
182 180 self.pasteRequested.emit(text)
183 181
184 182 def run_requested(self, item = None):
185 183 """Emit runRequested signal with currently selected item text
186 184 """
187 185 text = self._get_current_search_item(item)
188 186 if text is not None:
189 187 self.runRequested.emit(text)
190 188
191 189 def filter_magic_helper(self, regex, cls):
192 190 """Update search_list with magic commands whose text match
193 191 regex and class match cls.
194 192 If cls equals 'any' - any class matches.
195 193 """
196 194 if regex == "" or regex is None:
197 195 regex = '.'
198 196 if cls is None:
199 197 cls = 'any'
200 198
201 199 self.search_list.clear()
202 200 for mtype in sorted(self.data):
203 201 subdict = self.data[mtype]
204 202 prefix = magic_escapes[mtype]
205 203
206 204 for name in sorted(subdict):
207 205 mclass = subdict[name]
208 206 pmagic = prefix + name
209 207
210 208 if (re.match(regex, name) or re.match(regex, pmagic)) and \
211 209 (cls == 'any' or cls == mclass):
212 210 self.search_list.addItem(pmagic)
213 211
General Comments 0
You need to be logged in to leave comments. Login now