##// END OF EJS Templates
Add `wait` optional argument to `hooks.editor`...
Takafumi Arakaki -
Show More
@@ -1,228 +1,231 b''
1 """hooks for IPython.
1 """hooks for IPython.
2
2
3 In Python, it is possible to overwrite any method of any object if you really
3 In Python, it is possible to overwrite any method of any object if you really
4 want to. But IPython exposes a few 'hooks', methods which are _designed_ to
4 want to. But IPython exposes a few 'hooks', methods which are _designed_ to
5 be overwritten by users for customization purposes. This module defines the
5 be overwritten by users for customization purposes. This module defines the
6 default versions of all such hooks, which get used by IPython if not
6 default versions of all such hooks, which get used by IPython if not
7 overridden by the user.
7 overridden by the user.
8
8
9 hooks are simple functions, but they should be declared with 'self' as their
9 hooks are simple functions, but they should be declared with 'self' as their
10 first argument, because when activated they are registered into IPython as
10 first argument, because when activated they are registered into IPython as
11 instance methods. The self argument will be the IPython running instance
11 instance methods. The self argument will be the IPython running instance
12 itself, so hooks have full access to the entire IPython object.
12 itself, so hooks have full access to the entire IPython object.
13
13
14 If you wish to define a new hook and activate it, you need to put the
14 If you wish to define a new hook and activate it, you need to put the
15 necessary code into a python file which can be either imported or execfile()'d
15 necessary code into a python file which can be either imported or execfile()'d
16 from within your profile's ipython_config.py configuration.
16 from within your profile's ipython_config.py configuration.
17
17
18 For example, suppose that you have a module called 'myiphooks' in your
18 For example, suppose that you have a module called 'myiphooks' in your
19 PYTHONPATH, which contains the following definition:
19 PYTHONPATH, which contains the following definition:
20
20
21 import os
21 import os
22 from IPython.core import ipapi
22 from IPython.core import ipapi
23 ip = ipapi.get()
23 ip = ipapi.get()
24
24
25 def calljed(self,filename, linenum):
25 def calljed(self,filename, linenum):
26 "My editor hook calls the jed editor directly."
26 "My editor hook calls the jed editor directly."
27 print "Calling my own editor, jed ..."
27 print "Calling my own editor, jed ..."
28 if os.system('jed +%d %s' % (linenum,filename)) != 0:
28 if os.system('jed +%d %s' % (linenum,filename)) != 0:
29 raise TryNext()
29 raise TryNext()
30
30
31 ip.set_hook('editor', calljed)
31 ip.set_hook('editor', calljed)
32
32
33 You can then enable the functionality by doing 'import myiphooks'
33 You can then enable the functionality by doing 'import myiphooks'
34 somewhere in your configuration files or ipython command line.
34 somewhere in your configuration files or ipython command line.
35 """
35 """
36
36
37 #*****************************************************************************
37 #*****************************************************************************
38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
39 #
39 #
40 # Distributed under the terms of the BSD License. The full license is in
40 # Distributed under the terms of the BSD License. The full license is in
41 # the file COPYING, distributed as part of this software.
41 # the file COPYING, distributed as part of this software.
42 #*****************************************************************************
42 #*****************************************************************************
43
43
44 import os, bisect
44 import os, bisect
45 import subprocess
45 import sys
46 import sys
46
47
47 from IPython.core.error import TryNext
48 from IPython.core.error import TryNext
48
49
49 # List here all the default hooks. For now it's just the editor functions
50 # List here all the default hooks. For now it's just the editor functions
50 # but over time we'll move here all the public API for user-accessible things.
51 # but over time we'll move here all the public API for user-accessible things.
51
52
52 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor',
53 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor',
53 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
54 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
54 'show_in_pager','pre_prompt_hook',
55 'show_in_pager','pre_prompt_hook',
55 'pre_run_code_hook', 'clipboard_get']
56 'pre_run_code_hook', 'clipboard_get']
56
57
57 def editor(self,filename, linenum=None):
58 def editor(self, filename, linenum=None, wait=True):
58 """Open the default editor at the given filename and linenumber.
59 """Open the default editor at the given filename and linenumber.
59
60
60 This is IPython's default editor hook, you can use it as an example to
61 This is IPython's default editor hook, you can use it as an example to
61 write your own modified one. To set your own editor function as the
62 write your own modified one. To set your own editor function as the
62 new editor hook, call ip.set_hook('editor',yourfunc)."""
63 new editor hook, call ip.set_hook('editor',yourfunc)."""
63
64
64 # IPython configures a default editor at startup by reading $EDITOR from
65 # IPython configures a default editor at startup by reading $EDITOR from
65 # the environment, and falling back on vi (unix) or notepad (win32).
66 # the environment, and falling back on vi (unix) or notepad (win32).
66 editor = self.editor
67 editor = self.editor
67
68
68 # marker for at which line to open the file (for existing objects)
69 # marker for at which line to open the file (for existing objects)
69 if linenum is None or editor=='notepad':
70 if linenum is None or editor=='notepad':
70 linemark = ''
71 linemark = ''
71 else:
72 else:
72 linemark = '+%d' % int(linenum)
73 linemark = '+%d' % int(linenum)
73
74
74 # Enclose in quotes if necessary and legal
75 # Enclose in quotes if necessary and legal
75 if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
76 if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
76 editor = '"%s"' % editor
77 editor = '"%s"' % editor
77
78
78 # Call the actual editor
79 # Call the actual editor
79 if os.system('%s %s %s' % (editor,linemark,filename)) != 0:
80 proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
81 shell=True)
82 if wait and proc.wait() != 0:
80 raise TryNext()
83 raise TryNext()
81
84
82 import tempfile
85 import tempfile
83 def fix_error_editor(self,filename,linenum,column,msg):
86 def fix_error_editor(self,filename,linenum,column,msg):
84 """Open the editor at the given filename, linenumber, column and
87 """Open the editor at the given filename, linenumber, column and
85 show an error message. This is used for correcting syntax errors.
88 show an error message. This is used for correcting syntax errors.
86 The current implementation only has special support for the VIM editor,
89 The current implementation only has special support for the VIM editor,
87 and falls back on the 'editor' hook if VIM is not used.
90 and falls back on the 'editor' hook if VIM is not used.
88
91
89 Call ip.set_hook('fix_error_editor',youfunc) to use your own function,
92 Call ip.set_hook('fix_error_editor',youfunc) to use your own function,
90 """
93 """
91 def vim_quickfix_file():
94 def vim_quickfix_file():
92 t = tempfile.NamedTemporaryFile()
95 t = tempfile.NamedTemporaryFile()
93 t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg))
96 t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg))
94 t.flush()
97 t.flush()
95 return t
98 return t
96 if os.path.basename(self.editor) != 'vim':
99 if os.path.basename(self.editor) != 'vim':
97 self.hooks.editor(filename,linenum)
100 self.hooks.editor(filename,linenum)
98 return
101 return
99 t = vim_quickfix_file()
102 t = vim_quickfix_file()
100 try:
103 try:
101 if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name):
104 if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name):
102 raise TryNext()
105 raise TryNext()
103 finally:
106 finally:
104 t.close()
107 t.close()
105
108
106
109
107 def synchronize_with_editor(self, filename, linenum, column):
110 def synchronize_with_editor(self, filename, linenum, column):
108 pass
111 pass
109
112
110
113
111 class CommandChainDispatcher:
114 class CommandChainDispatcher:
112 """ Dispatch calls to a chain of commands until some func can handle it
115 """ Dispatch calls to a chain of commands until some func can handle it
113
116
114 Usage: instantiate, execute "add" to add commands (with optional
117 Usage: instantiate, execute "add" to add commands (with optional
115 priority), execute normally via f() calling mechanism.
118 priority), execute normally via f() calling mechanism.
116
119
117 """
120 """
118 def __init__(self,commands=None):
121 def __init__(self,commands=None):
119 if commands is None:
122 if commands is None:
120 self.chain = []
123 self.chain = []
121 else:
124 else:
122 self.chain = commands
125 self.chain = commands
123
126
124
127
125 def __call__(self,*args, **kw):
128 def __call__(self,*args, **kw):
126 """ Command chain is called just like normal func.
129 """ Command chain is called just like normal func.
127
130
128 This will call all funcs in chain with the same args as were given to this
131 This will call all funcs in chain with the same args as were given to this
129 function, and return the result of first func that didn't raise
132 function, and return the result of first func that didn't raise
130 TryNext """
133 TryNext """
131
134
132 for prio,cmd in self.chain:
135 for prio,cmd in self.chain:
133 #print "prio",prio,"cmd",cmd #dbg
136 #print "prio",prio,"cmd",cmd #dbg
134 try:
137 try:
135 return cmd(*args, **kw)
138 return cmd(*args, **kw)
136 except TryNext, exc:
139 except TryNext, exc:
137 if exc.args or exc.kwargs:
140 if exc.args or exc.kwargs:
138 args = exc.args
141 args = exc.args
139 kw = exc.kwargs
142 kw = exc.kwargs
140 # if no function will accept it, raise TryNext up to the caller
143 # if no function will accept it, raise TryNext up to the caller
141 raise TryNext(*args, **kw)
144 raise TryNext(*args, **kw)
142
145
143 def __str__(self):
146 def __str__(self):
144 return str(self.chain)
147 return str(self.chain)
145
148
146 def add(self, func, priority=0):
149 def add(self, func, priority=0):
147 """ Add a func to the cmd chain with given priority """
150 """ Add a func to the cmd chain with given priority """
148 bisect.insort(self.chain,(priority,func))
151 bisect.insort(self.chain,(priority,func))
149
152
150 def __iter__(self):
153 def __iter__(self):
151 """ Return all objects in chain.
154 """ Return all objects in chain.
152
155
153 Handy if the objects are not callable.
156 Handy if the objects are not callable.
154 """
157 """
155 return iter(self.chain)
158 return iter(self.chain)
156
159
157
160
158 def input_prefilter(self,line):
161 def input_prefilter(self,line):
159 """ Default input prefilter
162 """ Default input prefilter
160
163
161 This returns the line as unchanged, so that the interpreter
164 This returns the line as unchanged, so that the interpreter
162 knows that nothing was done and proceeds with "classic" prefiltering
165 knows that nothing was done and proceeds with "classic" prefiltering
163 (%magics, !shell commands etc.).
166 (%magics, !shell commands etc.).
164
167
165 Note that leading whitespace is not passed to this hook. Prefilter
168 Note that leading whitespace is not passed to this hook. Prefilter
166 can't alter indentation.
169 can't alter indentation.
167
170
168 """
171 """
169 #print "attempt to rewrite",line #dbg
172 #print "attempt to rewrite",line #dbg
170 return line
173 return line
171
174
172
175
173 def shutdown_hook(self):
176 def shutdown_hook(self):
174 """ default shutdown hook
177 """ default shutdown hook
175
178
176 Typically, shotdown hooks should raise TryNext so all shutdown ops are done
179 Typically, shotdown hooks should raise TryNext so all shutdown ops are done
177 """
180 """
178
181
179 #print "default shutdown hook ok" # dbg
182 #print "default shutdown hook ok" # dbg
180 return
183 return
181
184
182
185
183 def late_startup_hook(self):
186 def late_startup_hook(self):
184 """ Executed after ipython has been constructed and configured
187 """ Executed after ipython has been constructed and configured
185
188
186 """
189 """
187 #print "default startup hook ok" # dbg
190 #print "default startup hook ok" # dbg
188
191
189
192
190 def show_in_pager(self,s):
193 def show_in_pager(self,s):
191 """ Run a string through pager """
194 """ Run a string through pager """
192 # raising TryNext here will use the default paging functionality
195 # raising TryNext here will use the default paging functionality
193 raise TryNext
196 raise TryNext
194
197
195
198
196 def pre_prompt_hook(self):
199 def pre_prompt_hook(self):
197 """ Run before displaying the next prompt
200 """ Run before displaying the next prompt
198
201
199 Use this e.g. to display output from asynchronous operations (in order
202 Use this e.g. to display output from asynchronous operations (in order
200 to not mess up text entry)
203 to not mess up text entry)
201 """
204 """
202
205
203 return None
206 return None
204
207
205
208
206 def pre_run_code_hook(self):
209 def pre_run_code_hook(self):
207 """ Executed before running the (prefiltered) code in IPython """
210 """ Executed before running the (prefiltered) code in IPython """
208 return None
211 return None
209
212
210
213
211 def clipboard_get(self):
214 def clipboard_get(self):
212 """ Get text from the clipboard.
215 """ Get text from the clipboard.
213 """
216 """
214 from IPython.lib.clipboard import (
217 from IPython.lib.clipboard import (
215 osx_clipboard_get, tkinter_clipboard_get,
218 osx_clipboard_get, tkinter_clipboard_get,
216 win32_clipboard_get
219 win32_clipboard_get
217 )
220 )
218 if sys.platform == 'win32':
221 if sys.platform == 'win32':
219 chain = [win32_clipboard_get, tkinter_clipboard_get]
222 chain = [win32_clipboard_get, tkinter_clipboard_get]
220 elif sys.platform == 'darwin':
223 elif sys.platform == 'darwin':
221 chain = [osx_clipboard_get, tkinter_clipboard_get]
224 chain = [osx_clipboard_get, tkinter_clipboard_get]
222 else:
225 else:
223 chain = [tkinter_clipboard_get]
226 chain = [tkinter_clipboard_get]
224 dispatcher = CommandChainDispatcher()
227 dispatcher = CommandChainDispatcher()
225 for func in chain:
228 for func in chain:
226 dispatcher.add(func)
229 dispatcher.add(func)
227 text = dispatcher()
230 text = dispatcher()
228 return text
231 return text
General Comments 0
You need to be logged in to leave comments. Login now