##// END OF EJS Templates
Merge pull request #956 from Carreau/all-magic-menu-live...
Fernando Perez -
r5419:8fa65442 merge
parent child Browse files
Show More
@@ -4,6 +4,7 from __future__ import print_function
4 4 from collections import namedtuple
5 5 import sys
6 6 import time
7 import uuid
7 8
8 9 # System library imports
9 10 from pygments.lexers import PythonLexer
@@ -137,6 +138,7 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
137 138 self._input_splitter = self._input_splitter_class(input_mode='cell')
138 139 self._kernel_manager = None
139 140 self._request_info = {}
141 self._callback_dict = {}
140 142
141 143 # Configure the ConsoleWidget.
142 144 self.tab_width = 4
@@ -311,6 +313,62 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
311 313 cursor.movePosition(QtGui.QTextCursor.Left, n=len(text))
312 314 self._complete_with_items(cursor, rep['content']['matches'])
313 315
316 def _silent_exec_callback(self, expr, callback):
317 """Silently execute `expr` in the kernel and call `callback` with reply
318
319 the `expr` is evaluated silently in the kernel (without) output in
320 the frontend. Call `callback` with the
321 `repr <http://docs.python.org/library/functions.html#repr> `_ as first argument
322
323 Parameters
324 ----------
325 expr : string
326 valid string to be executed by the kernel.
327 callback : function
328 function accepting one arguement, as a string. The string will be
329 the `repr` of the result of evaluating `expr`
330
331 The `callback` is called with the 'repr()' of the result of `expr` as
332 first argument. To get the object, do 'eval()' onthe passed value.
333
334 See Also
335 --------
336 _handle_exec_callback : private method, deal with calling callback with reply
337
338 """
339
340 # generate uuid, which would be used as a indication of wether or not
341 # the unique request originate from here (can use msg id ?)
342 local_uuid = str(uuid.uuid1())
343 msg_id = self.kernel_manager.shell_channel.execute('',
344 silent=True, user_expressions={ local_uuid:expr })
345 self._callback_dict[local_uuid] = callback
346 self._request_info['execute'] = self._ExecutionRequest(msg_id, 'silent_exec_callback')
347
348 def _handle_exec_callback(self, msg):
349 """Execute `callback` corresonding to `msg` reply, after ``_silent_exec_callback``
350
351 Parameters
352 ----------
353 msg : raw message send by the kernel containing an `user_expressions`
354 and having a 'silent_exec_callback' kind.
355
356 Notes
357 -----
358 This fonction will look for a `callback` associated with the
359 corresponding message id. Association has been made by
360 `_silent_exec_callback`. `callback` is then called with the `repr()`
361 of the value of corresponding `user_expressions` as argument.
362 `callback` is then removed from the known list so that any message
363 coming again with the same id won't trigger it.
364
365 """
366
367 user_exp = msg['content']['user_expressions']
368 for expression in user_exp:
369 if expression in self._callback_dict:
370 self._callback_dict.pop(expression)(user_exp[expression])
371
314 372 def _handle_execute_reply(self, msg):
315 373 """ Handles replies for code execution.
316 374 """
@@ -342,6 +400,9 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
342 400
343 401 self._show_interpreter_prompt_for_reply(msg)
344 402 self.executed.emit(msg)
403 elif info and info.id == msg['parent_header']['msg_id'] and \
404 info.kind == 'silent_exec_callback' and not self._hidden:
405 self._handle_exec_callback(msg)
345 406 else:
346 407 super(FrontendWidget, self)._handle_execute_reply(msg)
347 408
@@ -20,6 +20,7 Authors:
20 20
21 21 # stdlib imports
22 22 import sys
23 import re
23 24 import webbrowser
24 25 from threading import Thread
25 26
@@ -544,10 +545,89 class MainWindow(QtGui.QMainWindow):
544 545
545 546 self.kernel_menu.addSeparator()
546 547
548 def _make_dynamic_magic(self,magic):
549 """Return a function `fun` that will execute `magic` on active frontend.
550
551 Parameters
552 ----------
553 magic : string
554 string that will be executed as is when the returned function is called
555
556 Returns
557 -------
558 fun : function
559 function with no parameters, when called will execute `magic` on the
560 current active frontend at call time
561
562 See Also
563 --------
564 populate_all_magic_menu : generate the "All Magics..." menu
565
566 Notes
567 -----
568 `fun` execute `magic` an active frontend at the moment it is triggerd,
569 not the active frontend at the moment it has been created.
570
571 This function is mostly used to create the "All Magics..." Menu at run time.
572 """
573 # need to level nested function to be sure to past magic
574 # on active frontend **at run time**.
575 def inner_dynamic_magic():
576 self.active_frontend.execute(magic)
577 inner_dynamic_magic.__name__ = "dynamics_magic_s"
578 return inner_dynamic_magic
579
580 def populate_all_magic_menu(self, listofmagic=None):
581 """Clean "All Magics..." menu and repopulate it with `listofmagic`
582
583 Parameters
584 ----------
585 listofmagic : string,
586 repr() of a list of strings, send back by the kernel
587
588 Notes
589 -----
590 `listofmagic`is a repr() of list because it is fed with the result of
591 a 'user_expression'
592 """
593 alm_magic_menu = self.all_magic_menu
594 alm_magic_menu.clear()
595
596 # list of protected magic that don't like to be called without argument
597 # append '?' to the end to print the docstring when called from the menu
598 protected_magic = set(["more","less","load_ext","pycat","loadpy","save"])
599 magics=re.findall('\w+', listofmagic)
600 for magic in magics:
601 if magic in protected_magic:
602 pmagic = '%s%s%s'%('%',magic,'?')
603 else:
604 pmagic = '%s%s'%('%',magic)
605 xaction = QtGui.QAction(pmagic,
606 self,
607 triggered=self._make_dynamic_magic(pmagic)
608 )
609 alm_magic_menu.addAction(xaction)
610
611 def update_all_magic_menu(self):
612 """ Update the list on magic in the "All Magics..." Menu
613
614 Request the kernel with the list of availlable magic and populate the
615 menu with the list received back
616
617 """
618 # first define a callback which will get the list of all magic and put it in the menu.
619 self.active_frontend._silent_exec_callback('get_ipython().lsmagic()', self.populate_all_magic_menu)
620
547 621 def init_magic_menu(self):
548 622 self.magic_menu = self.menuBar().addMenu("&Magic")
549 623 self.all_magic_menu = self.magic_menu.addMenu("&All Magics")
550
624
625 # this action should not appear as it will be cleard when menu
626 # will be updated at first kernel response.
627 self.pop = QtGui.QAction("&Update All Magic Menu ",
628 self, triggered=self.update_all_magic_menu)
629 self.add_menu_action(self.all_magic_menu, self.pop)
630
551 631 self.reset_action = QtGui.QAction("&Reset",
552 632 self,
553 633 statusTip="Clear all varible from workspace",
@@ -583,34 +663,7 class MainWindow(QtGui.QMainWindow):
583 663 statusTip="List interactive variable with detail",
584 664 triggered=self.whos_magic_active_frontend)
585 665 self.add_menu_action(self.magic_menu, self.whos_action)
586
587 # allmagics submenu:
588
589 #for now this is just a copy and paste, but we should get this dynamically
590 magiclist=["%alias", "%autocall", "%automagic", "%bookmark", "%cd", "%clear",
591 "%colors", "%debug", "%dhist", "%dirs", "%doctest_mode", "%ed", "%edit", "%env", "%gui",
592 "%guiref", "%hist", "%history", "%install_default_config", "%install_profiles",
593 "%less", "%load_ext", "%loadpy", "%logoff", "%logon", "%logstart", "%logstate",
594 "%logstop", "%lsmagic", "%macro", "%magic", "%man", "%more", "%notebook", "%page",
595 "%pastebin", "%pdb", "%pdef", "%pdoc", "%pfile", "%pinfo", "%pinfo2", "%popd", "%pprint",
596 "%precision", "%profile", "%prun", "%psearch", "%psource", "%pushd", "%pwd", "%pycat",
597 "%pylab", "%quickref", "%recall", "%rehashx", "%reload_ext", "%rep", "%rerun",
598 "%reset", "%reset_selective", "%run", "%save", "%sc", "%sx", "%tb", "%time", "%timeit",
599 "%unalias", "%unload_ext", "%who", "%who_ls", "%whos", "%xdel", "%xmode"]
600
601 def make_dynamic_magic(i):
602 def inner_dynamic_magic():
603 self.active_frontend.execute(i)
604 inner_dynamic_magic.__name__ = "dynamics_magic_%s" % i
605 return inner_dynamic_magic
606
607 for magic in magiclist:
608 xaction = QtGui.QAction(magic,
609 self,
610 triggered=make_dynamic_magic(magic)
611 )
612 self.all_magic_menu.addAction(xaction)
613
666
614 667 def init_window_menu(self):
615 668 self.window_menu = self.menuBar().addMenu("&Window")
616 669 if sys.platform == 'darwin':
@@ -451,6 +451,10 class IPythonQtConsoleApp(BaseIPythonApplication):
451 451 self.window.log = self.log
452 452 self.window.add_tab_with_frontend(self.widget)
453 453 self.window.init_menu_bar()
454
455 # we need to populate the 'Magic Menu' once the kernel has answer at least once
456 self.kernel_manager.shell_channel.first_reply.connect(self.window.pop.trigger)
457
454 458 self.window.setWindowTitle('Python' if self.pure else 'IPython')
455 459
456 460 def init_colors(self):
General Comments 0
You need to be logged in to leave comments. Login now