hooks.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. """Hooks for IPython.
  2. In Python, it is possible to overwrite any method of any object if you really
  3. want to. But IPython exposes a few 'hooks', methods which are *designed* to
  4. be overwritten by users for customization purposes. This module defines the
  5. default versions of all such hooks, which get used by IPython if not
  6. overridden by the user.
  7. Hooks are simple functions, but they should be declared with ``self`` as their
  8. first argument, because when activated they are registered into IPython as
  9. instance methods. The self argument will be the IPython running instance
  10. itself, so hooks have full access to the entire IPython object.
  11. If you wish to define a new hook and activate it, you can make an :doc:`extension
  12. </config/extensions/index>` or a :ref:`startup script <startup_files>`. For
  13. example, you could use a startup file like this::
  14. import os
  15. def calljed(self,filename, linenum):
  16. "My editor hook calls the jed editor directly."
  17. print("Calling my own editor, jed ...")
  18. if os.system('jed +%d %s' % (linenum,filename)) != 0:
  19. raise TryNext()
  20. def load_ipython_extension(ip):
  21. ip.set_hook('editor', calljed)
  22. """
  23. #*****************************************************************************
  24. # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
  25. #
  26. # Distributed under the terms of the BSD License. The full license is in
  27. # the file COPYING, distributed as part of this software.
  28. #*****************************************************************************
  29. import os
  30. import subprocess
  31. import sys
  32. from .error import TryNext
  33. # List here all the default hooks. For now it's just the editor functions
  34. # but over time we'll move here all the public API for user-accessible things.
  35. __all__ = [
  36. "editor",
  37. "synchronize_with_editor",
  38. "show_in_pager",
  39. "clipboard_get",
  40. ]
  41. def editor(self, filename, linenum=None, wait=True):
  42. """Open the default editor at the given filename and linenumber.
  43. This is IPython's default editor hook, you can use it as an example to
  44. write your own modified one. To set your own editor function as the
  45. new editor hook, call ip.set_hook('editor',yourfunc)."""
  46. # IPython configures a default editor at startup by reading $EDITOR from
  47. # the environment, and falling back on vi (unix) or notepad (win32).
  48. editor = self.editor
  49. # marker for at which line to open the file (for existing objects)
  50. if linenum is None or editor=='notepad':
  51. linemark = ''
  52. else:
  53. linemark = '+%d' % int(linenum)
  54. # Enclose in quotes if necessary and legal
  55. if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
  56. editor = '"%s"' % editor
  57. # Call the actual editor
  58. proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
  59. shell=True)
  60. if wait and proc.wait() != 0:
  61. raise TryNext()
  62. def synchronize_with_editor(self, filename, linenum, column):
  63. pass
  64. class CommandChainDispatcher:
  65. """ Dispatch calls to a chain of commands until some func can handle it
  66. Usage: instantiate, execute "add" to add commands (with optional
  67. priority), execute normally via f() calling mechanism.
  68. """
  69. def __init__(self,commands=None):
  70. if commands is None:
  71. self.chain = []
  72. else:
  73. self.chain = commands
  74. def __call__(self,*args, **kw):
  75. """ Command chain is called just like normal func.
  76. This will call all funcs in chain with the same args as were given to
  77. this function, and return the result of first func that didn't raise
  78. TryNext"""
  79. last_exc = TryNext()
  80. for prio,cmd in self.chain:
  81. # print("prio",prio,"cmd",cmd) # dbg
  82. try:
  83. return cmd(*args, **kw)
  84. except TryNext as exc:
  85. last_exc = exc
  86. # if no function will accept it, raise TryNext up to the caller
  87. raise last_exc
  88. def __str__(self):
  89. return str(self.chain)
  90. def add(self, func, priority=0):
  91. """ Add a func to the cmd chain with given priority """
  92. self.chain.append((priority, func))
  93. self.chain.sort(key=lambda x: x[0])
  94. def __iter__(self):
  95. """ Return all objects in chain.
  96. Handy if the objects are not callable.
  97. """
  98. return iter(self.chain)
  99. def show_in_pager(self, data, start, screen_lines):
  100. """ Run a string through pager """
  101. # raising TryNext here will use the default paging functionality
  102. raise TryNext
  103. def clipboard_get(self):
  104. """ Get text from the clipboard.
  105. """
  106. from ..lib.clipboard import (
  107. osx_clipboard_get,
  108. tkinter_clipboard_get,
  109. win32_clipboard_get,
  110. wayland_clipboard_get,
  111. )
  112. if sys.platform == 'win32':
  113. chain = [win32_clipboard_get, tkinter_clipboard_get]
  114. elif sys.platform == 'darwin':
  115. chain = [osx_clipboard_get, tkinter_clipboard_get]
  116. else:
  117. chain = [wayland_clipboard_get, tkinter_clipboard_get]
  118. dispatcher = CommandChainDispatcher()
  119. for func in chain:
  120. dispatcher.add(func)
  121. text = dispatcher()
  122. return text