##// END OF EJS Templates
Merge pull request #12932 from minrk/pipes-quote...
Matthias Bussonnier -
r26506:bbd5c45a merge
parent child Browse files
Show More
@@ -1,321 +1,321 b''
1 """Magic functions for running cells in various scripts."""
1 """Magic functions for running cells in various scripts."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import errno
6 import errno
7 import os
7 import os
8 import sys
8 import sys
9 import signal
9 import signal
10 import time
10 import time
11 import asyncio
11 import asyncio
12 import atexit
12 import atexit
13
13
14 from subprocess import CalledProcessError
14 from subprocess import CalledProcessError
15
15
16 from IPython.core import magic_arguments
16 from IPython.core import magic_arguments
17 from IPython.core.magic import (
17 from IPython.core.magic import (
18 Magics, magics_class, line_magic, cell_magic
18 Magics, magics_class, line_magic, cell_magic
19 )
19 )
20 from IPython.lib.backgroundjobs import BackgroundJobManager
20 from IPython.lib.backgroundjobs import BackgroundJobManager
21 from IPython.utils.process import arg_split
21 from IPython.utils.process import arg_split
22 from traitlets import List, Dict, default
22 from traitlets import List, Dict, default
23
23
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Magic implementation classes
26 # Magic implementation classes
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 def script_args(f):
29 def script_args(f):
30 """single decorator for adding script args"""
30 """single decorator for adding script args"""
31 args = [
31 args = [
32 magic_arguments.argument(
32 magic_arguments.argument(
33 '--out', type=str,
33 '--out', type=str,
34 help="""The variable in which to store stdout from the script.
34 help="""The variable in which to store stdout from the script.
35 If the script is backgrounded, this will be the stdout *pipe*,
35 If the script is backgrounded, this will be the stdout *pipe*,
36 instead of the stderr text itself and will not be auto closed.
36 instead of the stderr text itself and will not be auto closed.
37 """
37 """
38 ),
38 ),
39 magic_arguments.argument(
39 magic_arguments.argument(
40 '--err', type=str,
40 '--err', type=str,
41 help="""The variable in which to store stderr from the script.
41 help="""The variable in which to store stderr from the script.
42 If the script is backgrounded, this will be the stderr *pipe*,
42 If the script is backgrounded, this will be the stderr *pipe*,
43 instead of the stderr text itself and will not be autoclosed.
43 instead of the stderr text itself and will not be autoclosed.
44 """
44 """
45 ),
45 ),
46 magic_arguments.argument(
46 magic_arguments.argument(
47 '--bg', action="store_true",
47 '--bg', action="store_true",
48 help="""Whether to run the script in the background.
48 help="""Whether to run the script in the background.
49 If given, the only way to see the output of the command is
49 If given, the only way to see the output of the command is
50 with --out/err.
50 with --out/err.
51 """
51 """
52 ),
52 ),
53 magic_arguments.argument(
53 magic_arguments.argument(
54 '--proc', type=str,
54 '--proc', type=str,
55 help="""The variable in which to store Popen instance.
55 help="""The variable in which to store Popen instance.
56 This is used only when --bg option is given.
56 This is used only when --bg option is given.
57 """
57 """
58 ),
58 ),
59 magic_arguments.argument(
59 magic_arguments.argument(
60 '--no-raise-error', action="store_false", dest='raise_error',
60 '--no-raise-error', action="store_false", dest='raise_error',
61 help="""Whether you should raise an error message in addition to
61 help="""Whether you should raise an error message in addition to
62 a stream on stderr if you get a nonzero exit code.
62 a stream on stderr if you get a nonzero exit code.
63 """
63 """
64 )
64 )
65 ]
65 ]
66 for arg in args:
66 for arg in args:
67 f = arg(f)
67 f = arg(f)
68 return f
68 return f
69
69
70 @magics_class
70 @magics_class
71 class ScriptMagics(Magics):
71 class ScriptMagics(Magics):
72 """Magics for talking to scripts
72 """Magics for talking to scripts
73
73
74 This defines a base `%%script` cell magic for running a cell
74 This defines a base `%%script` cell magic for running a cell
75 with a program in a subprocess, and registers a few top-level
75 with a program in a subprocess, and registers a few top-level
76 magics that call %%script with common interpreters.
76 magics that call %%script with common interpreters.
77 """
77 """
78 script_magics = List(
78 script_magics = List(
79 help="""Extra script cell magics to define
79 help="""Extra script cell magics to define
80
80
81 This generates simple wrappers of `%%script foo` as `%%foo`.
81 This generates simple wrappers of `%%script foo` as `%%foo`.
82
82
83 If you want to add script magics that aren't on your path,
83 If you want to add script magics that aren't on your path,
84 specify them in script_paths
84 specify them in script_paths
85 """,
85 """,
86 ).tag(config=True)
86 ).tag(config=True)
87 @default('script_magics')
87 @default('script_magics')
88 def _script_magics_default(self):
88 def _script_magics_default(self):
89 """default to a common list of programs"""
89 """default to a common list of programs"""
90
90
91 defaults = [
91 defaults = [
92 'sh',
92 'sh',
93 'bash',
93 'bash',
94 'perl',
94 'perl',
95 'ruby',
95 'ruby',
96 'python',
96 'python',
97 'python2',
97 'python2',
98 'python3',
98 'python3',
99 'pypy',
99 'pypy',
100 ]
100 ]
101 if os.name == 'nt':
101 if os.name == 'nt':
102 defaults.extend([
102 defaults.extend([
103 'cmd',
103 'cmd',
104 ])
104 ])
105
105
106 return defaults
106 return defaults
107
107
108 script_paths = Dict(
108 script_paths = Dict(
109 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
109 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
110
110
111 Only necessary for items in script_magics where the default path will not
111 Only necessary for items in script_magics where the default path will not
112 find the right interpreter.
112 find the right interpreter.
113 """
113 """
114 ).tag(config=True)
114 ).tag(config=True)
115
115
116 def __init__(self, shell=None):
116 def __init__(self, shell=None):
117 super(ScriptMagics, self).__init__(shell=shell)
117 super(ScriptMagics, self).__init__(shell=shell)
118 self._generate_script_magics()
118 self._generate_script_magics()
119 self.job_manager = BackgroundJobManager()
119 self.job_manager = BackgroundJobManager()
120 self.bg_processes = []
120 self.bg_processes = []
121 atexit.register(self.kill_bg_processes)
121 atexit.register(self.kill_bg_processes)
122
122
123 def __del__(self):
123 def __del__(self):
124 self.kill_bg_processes()
124 self.kill_bg_processes()
125
125
126 def _generate_script_magics(self):
126 def _generate_script_magics(self):
127 cell_magics = self.magics['cell']
127 cell_magics = self.magics['cell']
128 for name in self.script_magics:
128 for name in self.script_magics:
129 cell_magics[name] = self._make_script_magic(name)
129 cell_magics[name] = self._make_script_magic(name)
130
130
131 def _make_script_magic(self, name):
131 def _make_script_magic(self, name):
132 """make a named magic, that calls %%script with a particular program"""
132 """make a named magic, that calls %%script with a particular program"""
133 # expand to explicit path if necessary:
133 # expand to explicit path if necessary:
134 script = self.script_paths.get(name, name)
134 script = self.script_paths.get(name, name)
135
135
136 @magic_arguments.magic_arguments()
136 @magic_arguments.magic_arguments()
137 @script_args
137 @script_args
138 def named_script_magic(line, cell):
138 def named_script_magic(line, cell):
139 # if line, add it as cl-flags
139 # if line, add it as cl-flags
140 if line:
140 if line:
141 line = "%s %s" % (script, line)
141 line = "%s %s" % (script, line)
142 else:
142 else:
143 line = script
143 line = script
144 return self.shebang(line, cell)
144 return self.shebang(line, cell)
145
145
146 # write a basic docstring:
146 # write a basic docstring:
147 named_script_magic.__doc__ = \
147 named_script_magic.__doc__ = \
148 """%%{name} script magic
148 """%%{name} script magic
149
149
150 Run cells with {script} in a subprocess.
150 Run cells with {script} in a subprocess.
151
151
152 This is a shortcut for `%%script {script}`
152 This is a shortcut for `%%script {script}`
153 """.format(**locals())
153 """.format(**locals())
154
154
155 return named_script_magic
155 return named_script_magic
156
156
157 @magic_arguments.magic_arguments()
157 @magic_arguments.magic_arguments()
158 @script_args
158 @script_args
159 @cell_magic("script")
159 @cell_magic("script")
160 def shebang(self, line, cell):
160 def shebang(self, line, cell):
161 """Run a cell via a shell command
161 """Run a cell via a shell command
162
162
163 The `%%script` line is like the #! line of script,
163 The `%%script` line is like the #! line of script,
164 specifying a program (bash, perl, ruby, etc.) with which to run.
164 specifying a program (bash, perl, ruby, etc.) with which to run.
165
165
166 The rest of the cell is run by that program.
166 The rest of the cell is run by that program.
167
167
168 Examples
168 Examples
169 --------
169 --------
170 ::
170 ::
171
171
172 In [1]: %%script bash
172 In [1]: %%script bash
173 ...: for i in 1 2 3; do
173 ...: for i in 1 2 3; do
174 ...: echo $i
174 ...: echo $i
175 ...: done
175 ...: done
176 1
176 1
177 2
177 2
178 3
178 3
179 """
179 """
180
180
181 async def _handle_stream(stream, stream_arg, file_object):
181 async def _handle_stream(stream, stream_arg, file_object):
182 while True:
182 while True:
183 line = (await stream.readline()).decode("utf8")
183 line = (await stream.readline()).decode("utf8")
184 if not line:
184 if not line:
185 break
185 break
186 if stream_arg:
186 if stream_arg:
187 self.shell.user_ns[stream_arg] = line
187 self.shell.user_ns[stream_arg] = line
188 else:
188 else:
189 file_object.write(line)
189 file_object.write(line)
190 file_object.flush()
190 file_object.flush()
191
191
192 async def _stream_communicate(process, cell):
192 async def _stream_communicate(process, cell):
193 process.stdin.write(cell)
193 process.stdin.write(cell)
194 process.stdin.close()
194 process.stdin.close()
195 stdout_task = asyncio.create_task(
195 stdout_task = asyncio.create_task(
196 _handle_stream(process.stdout, args.out, sys.stdout)
196 _handle_stream(process.stdout, args.out, sys.stdout)
197 )
197 )
198 stderr_task = asyncio.create_task(
198 stderr_task = asyncio.create_task(
199 _handle_stream(process.stderr, args.err, sys.stderr)
199 _handle_stream(process.stderr, args.err, sys.stderr)
200 )
200 )
201 await asyncio.wait([stdout_task, stderr_task])
201 await asyncio.wait([stdout_task, stderr_task])
202 await process.wait()
202 await process.wait()
203
203
204 if sys.platform.startswith("win"):
204 if sys.platform.startswith("win"):
205 asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
205 asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
206 loop = asyncio.get_event_loop()
206 loop = asyncio.get_event_loop()
207
207
208 argv = arg_split(line, posix=not sys.platform.startswith("win"))
208 argv = arg_split(line, posix=not sys.platform.startswith("win"))
209 args, cmd = self.shebang.parser.parse_known_args(argv)
209 args, cmd = self.shebang.parser.parse_known_args(argv)
210 try:
210 try:
211 p = loop.run_until_complete(
211 p = loop.run_until_complete(
212 asyncio.create_subprocess_exec(
212 asyncio.create_subprocess_exec(
213 *cmd,
213 *cmd,
214 stdout=asyncio.subprocess.PIPE,
214 stdout=asyncio.subprocess.PIPE,
215 stderr=asyncio.subprocess.PIPE,
215 stderr=asyncio.subprocess.PIPE,
216 stdin=asyncio.subprocess.PIPE
216 stdin=asyncio.subprocess.PIPE,
217 )
217 )
218 )
218 )
219 except OSError as e:
219 except OSError as e:
220 if e.errno == errno.ENOENT:
220 if e.errno == errno.ENOENT:
221 print("Couldn't find program: %r" % cmd[0])
221 print("Couldn't find program: %r" % cmd[0])
222 return
222 return
223 else:
223 else:
224 raise
224 raise
225
225
226 if not cell.endswith('\n'):
226 if not cell.endswith('\n'):
227 cell += '\n'
227 cell += '\n'
228 cell = cell.encode('utf8', 'replace')
228 cell = cell.encode('utf8', 'replace')
229 if args.bg:
229 if args.bg:
230 self.bg_processes.append(p)
230 self.bg_processes.append(p)
231 self._gc_bg_processes()
231 self._gc_bg_processes()
232 to_close = []
232 to_close = []
233 if args.out:
233 if args.out:
234 self.shell.user_ns[args.out] = p.stdout
234 self.shell.user_ns[args.out] = p.stdout
235 else:
235 else:
236 to_close.append(p.stdout)
236 to_close.append(p.stdout)
237 if args.err:
237 if args.err:
238 self.shell.user_ns[args.err] = p.stderr
238 self.shell.user_ns[args.err] = p.stderr
239 else:
239 else:
240 to_close.append(p.stderr)
240 to_close.append(p.stderr)
241 self.job_manager.new(self._run_script, p, cell, to_close, daemon=True)
241 self.job_manager.new(self._run_script, p, cell, to_close, daemon=True)
242 if args.proc:
242 if args.proc:
243 self.shell.user_ns[args.proc] = p
243 self.shell.user_ns[args.proc] = p
244 return
244 return
245
245
246 try:
246 try:
247 loop.run_until_complete(_stream_communicate(p, cell))
247 loop.run_until_complete(_stream_communicate(p, cell))
248 except KeyboardInterrupt:
248 except KeyboardInterrupt:
249 try:
249 try:
250 p.send_signal(signal.SIGINT)
250 p.send_signal(signal.SIGINT)
251 time.sleep(0.1)
251 time.sleep(0.1)
252 if p.returncode is not None:
252 if p.returncode is not None:
253 print("Process is interrupted.")
253 print("Process is interrupted.")
254 return
254 return
255 p.terminate()
255 p.terminate()
256 time.sleep(0.1)
256 time.sleep(0.1)
257 if p.returncode is not None:
257 if p.returncode is not None:
258 print("Process is terminated.")
258 print("Process is terminated.")
259 return
259 return
260 p.kill()
260 p.kill()
261 print("Process is killed.")
261 print("Process is killed.")
262 except OSError:
262 except OSError:
263 pass
263 pass
264 except Exception as e:
264 except Exception as e:
265 print("Error while terminating subprocess (pid=%i): %s" % (p.pid, e))
265 print("Error while terminating subprocess (pid=%i): %s" % (p.pid, e))
266 return
266 return
267 if args.raise_error and p.returncode!=0:
267 if args.raise_error and p.returncode!=0:
268 # If we get here and p.returncode is still None, we must have
268 # If we get here and p.returncode is still None, we must have
269 # killed it but not yet seen its return code. We don't wait for it,
269 # killed it but not yet seen its return code. We don't wait for it,
270 # in case it's stuck in uninterruptible sleep. -9 = SIGKILL
270 # in case it's stuck in uninterruptible sleep. -9 = SIGKILL
271 rc = p.returncode or -9
271 rc = p.returncode or -9
272 raise CalledProcessError(rc, cell)
272 raise CalledProcessError(rc, cell)
273
273
274 def _run_script(self, p, cell, to_close):
274 def _run_script(self, p, cell, to_close):
275 """callback for running the script in the background"""
275 """callback for running the script in the background"""
276 p.stdin.write(cell)
276 p.stdin.write(cell)
277 p.stdin.close()
277 p.stdin.close()
278 for s in to_close:
278 for s in to_close:
279 s.close()
279 s.close()
280 p.wait()
280 p.wait()
281
281
282 @line_magic("killbgscripts")
282 @line_magic("killbgscripts")
283 def killbgscripts(self, _nouse_=''):
283 def killbgscripts(self, _nouse_=''):
284 """Kill all BG processes started by %%script and its family."""
284 """Kill all BG processes started by %%script and its family."""
285 self.kill_bg_processes()
285 self.kill_bg_processes()
286 print("All background processes were killed.")
286 print("All background processes were killed.")
287
287
288 def kill_bg_processes(self):
288 def kill_bg_processes(self):
289 """Kill all BG processes which are still running."""
289 """Kill all BG processes which are still running."""
290 if not self.bg_processes:
290 if not self.bg_processes:
291 return
291 return
292 for p in self.bg_processes:
292 for p in self.bg_processes:
293 if p.returncode is None:
293 if p.returncode is None:
294 try:
294 try:
295 p.send_signal(signal.SIGINT)
295 p.send_signal(signal.SIGINT)
296 except:
296 except:
297 pass
297 pass
298 time.sleep(0.1)
298 time.sleep(0.1)
299 self._gc_bg_processes()
299 self._gc_bg_processes()
300 if not self.bg_processes:
300 if not self.bg_processes:
301 return
301 return
302 for p in self.bg_processes:
302 for p in self.bg_processes:
303 if p.returncode is None:
303 if p.returncode is None:
304 try:
304 try:
305 p.terminate()
305 p.terminate()
306 except:
306 except:
307 pass
307 pass
308 time.sleep(0.1)
308 time.sleep(0.1)
309 self._gc_bg_processes()
309 self._gc_bg_processes()
310 if not self.bg_processes:
310 if not self.bg_processes:
311 return
311 return
312 for p in self.bg_processes:
312 for p in self.bg_processes:
313 if p.returncode is None:
313 if p.returncode is None:
314 try:
314 try:
315 p.kill()
315 p.kill()
316 except:
316 except:
317 pass
317 pass
318 self._gc_bg_processes()
318 self._gc_bg_processes()
319
319
320 def _gc_bg_processes(self):
320 def _gc_bg_processes(self):
321 self.bg_processes = [p for p in self.bg_processes if p.returncode is None]
321 self.bg_processes = [p for p in self.bg_processes if p.returncode is None]
@@ -1,128 +1,127 b''
1 """ 'editor' hooks for common editors that work well with ipython
1 """ 'editor' hooks for common editors that work well with ipython
2
2
3 They should honor the line number argument, at least.
3 They should honor the line number argument, at least.
4
4
5 Contributions are *very* welcome.
5 Contributions are *very* welcome.
6 """
6 """
7
7
8 import os
8 import os
9 import pipes
10 import shlex
9 import shlex
11 import subprocess
10 import subprocess
12 import sys
11 import sys
13
12
14 from IPython import get_ipython
13 from IPython import get_ipython
15 from IPython.core.error import TryNext
14 from IPython.core.error import TryNext
16 from IPython.utils import py3compat
15 from IPython.utils import py3compat
17
16
18
17
19 def install_editor(template, wait=False):
18 def install_editor(template, wait=False):
20 """Installs the editor that is called by IPython for the %edit magic.
19 """Installs the editor that is called by IPython for the %edit magic.
21
20
22 This overrides the default editor, which is generally set by your EDITOR
21 This overrides the default editor, which is generally set by your EDITOR
23 environment variable or is notepad (windows) or vi (linux). By supplying a
22 environment variable or is notepad (windows) or vi (linux). By supplying a
24 template string `run_template`, you can control how the editor is invoked
23 template string `run_template`, you can control how the editor is invoked
25 by IPython -- (e.g. the format in which it accepts command line options)
24 by IPython -- (e.g. the format in which it accepts command line options)
26
25
27 Parameters
26 Parameters
28 ----------
27 ----------
29 template : basestring
28 template : basestring
30 run_template acts as a template for how your editor is invoked by
29 run_template acts as a template for how your editor is invoked by
31 the shell. It should contain '{filename}', which will be replaced on
30 the shell. It should contain '{filename}', which will be replaced on
32 invocation with the file name, and '{line}', $line by line number
31 invocation with the file name, and '{line}', $line by line number
33 (or 0) to invoke the file with.
32 (or 0) to invoke the file with.
34 wait : bool
33 wait : bool
35 If `wait` is true, wait until the user presses enter before returning,
34 If `wait` is true, wait until the user presses enter before returning,
36 to facilitate non-blocking editors that exit immediately after
35 to facilitate non-blocking editors that exit immediately after
37 the call.
36 the call.
38 """
37 """
39
38
40 # not all editors support $line, so we'll leave out this check
39 # not all editors support $line, so we'll leave out this check
41 # for substitution in ['$file', '$line']:
40 # for substitution in ['$file', '$line']:
42 # if not substitution in run_template:
41 # if not substitution in run_template:
43 # raise ValueError(('run_template should contain %s'
42 # raise ValueError(('run_template should contain %s'
44 # ' for string substitution. You supplied "%s"' % (substitution,
43 # ' for string substitution. You supplied "%s"' % (substitution,
45 # run_template)))
44 # run_template)))
46
45
47 def call_editor(self, filename, line=0):
46 def call_editor(self, filename, line=0):
48 if line is None:
47 if line is None:
49 line = 0
48 line = 0
50 cmd = template.format(filename=pipes.quote(filename), line=line)
49 cmd = template.format(filename=shlex.quote(filename), line=line)
51 print(">", cmd)
50 print(">", cmd)
52 # pipes.quote doesn't work right on Windows, but it does after splitting
51 # shlex.quote doesn't work right on Windows, but it does after splitting
53 if sys.platform.startswith('win'):
52 if sys.platform.startswith('win'):
54 cmd = shlex.split(cmd)
53 cmd = shlex.split(cmd)
55 proc = subprocess.Popen(cmd, shell=True)
54 proc = subprocess.Popen(cmd, shell=True)
56 if proc.wait() != 0:
55 if proc.wait() != 0:
57 raise TryNext()
56 raise TryNext()
58 if wait:
57 if wait:
59 py3compat.input("Press Enter when done editing:")
58 py3compat.input("Press Enter when done editing:")
60
59
61 get_ipython().set_hook('editor', call_editor)
60 get_ipython().set_hook('editor', call_editor)
62 get_ipython().editor = template
61 get_ipython().editor = template
63
62
64
63
65 # in these, exe is always the path/name of the executable. Useful
64 # in these, exe is always the path/name of the executable. Useful
66 # if you don't have the editor directory in your path
65 # if you don't have the editor directory in your path
67 def komodo(exe=u'komodo'):
66 def komodo(exe=u'komodo'):
68 """ Activestate Komodo [Edit] """
67 """ Activestate Komodo [Edit] """
69 install_editor(exe + u' -l {line} {filename}', wait=True)
68 install_editor(exe + u' -l {line} {filename}', wait=True)
70
69
71
70
72 def scite(exe=u"scite"):
71 def scite(exe=u"scite"):
73 """ SciTE or Sc1 """
72 """ SciTE or Sc1 """
74 install_editor(exe + u' {filename} -goto:{line}')
73 install_editor(exe + u' {filename} -goto:{line}')
75
74
76
75
77 def notepadplusplus(exe=u'notepad++'):
76 def notepadplusplus(exe=u'notepad++'):
78 """ Notepad++ http://notepad-plus.sourceforge.net """
77 """ Notepad++ http://notepad-plus.sourceforge.net """
79 install_editor(exe + u' -n{line} {filename}')
78 install_editor(exe + u' -n{line} {filename}')
80
79
81
80
82 def jed(exe=u'jed'):
81 def jed(exe=u'jed'):
83 """ JED, the lightweight emacsish editor """
82 """ JED, the lightweight emacsish editor """
84 install_editor(exe + u' +{line} {filename}')
83 install_editor(exe + u' +{line} {filename}')
85
84
86
85
87 def idle(exe=u'idle'):
86 def idle(exe=u'idle'):
88 """ Idle, the editor bundled with python
87 """ Idle, the editor bundled with python
89
88
90 Parameters
89 Parameters
91 ----------
90 ----------
92 exe : str, None
91 exe : str, None
93 If none, should be pretty smart about finding the executable.
92 If none, should be pretty smart about finding the executable.
94 """
93 """
95 if exe is None:
94 if exe is None:
96 import idlelib
95 import idlelib
97 p = os.path.dirname(idlelib.__filename__)
96 p = os.path.dirname(idlelib.__filename__)
98 # i'm not sure if this actually works. Is this idle.py script
97 # i'm not sure if this actually works. Is this idle.py script
99 # guaranteed to be executable?
98 # guaranteed to be executable?
100 exe = os.path.join(p, 'idle.py')
99 exe = os.path.join(p, 'idle.py')
101 install_editor(exe + u' {filename}')
100 install_editor(exe + u' {filename}')
102
101
103
102
104 def mate(exe=u'mate'):
103 def mate(exe=u'mate'):
105 """ TextMate, the missing editor"""
104 """ TextMate, the missing editor"""
106 # wait=True is not required since we're using the -w flag to mate
105 # wait=True is not required since we're using the -w flag to mate
107 install_editor(exe + u' -w -l {line} {filename}')
106 install_editor(exe + u' -w -l {line} {filename}')
108
107
109
108
110 # ##########################################
109 # ##########################################
111 # these are untested, report any problems
110 # these are untested, report any problems
112 # ##########################################
111 # ##########################################
113
112
114
113
115 def emacs(exe=u'emacs'):
114 def emacs(exe=u'emacs'):
116 install_editor(exe + u' +{line} {filename}')
115 install_editor(exe + u' +{line} {filename}')
117
116
118
117
119 def gnuclient(exe=u'gnuclient'):
118 def gnuclient(exe=u'gnuclient'):
120 install_editor(exe + u' -nw +{line} {filename}')
119 install_editor(exe + u' -nw +{line} {filename}')
121
120
122
121
123 def crimson_editor(exe=u'cedt.exe'):
122 def crimson_editor(exe=u'cedt.exe'):
124 install_editor(exe + u' /L:{line} {filename}')
123 install_editor(exe + u' /L:{line} {filename}')
125
124
126
125
127 def kate(exe=u'kate'):
126 def kate(exe=u'kate'):
128 install_editor(exe + u' -u -l {line} {filename}')
127 install_editor(exe + u' -u -l {line} {filename}')
General Comments 0
You need to be logged in to leave comments. Login now