##// END OF EJS Templates
Backport PR #10239: IPython/lib/editorhooks.py: wait for process even if wait=False...
Thomas Kluyver -
Show More
@@ -1,129 +1,129 b''
1 1 """ 'editor' hooks for common editors that work well with ipython
2 2
3 3 They should honor the line number argument, at least.
4 4
5 5 Contributions are *very* welcome.
6 6 """
7 7 from __future__ import print_function
8 8
9 9 import os
10 10 import pipes
11 11 import shlex
12 12 import subprocess
13 13 import sys
14 14
15 15 from IPython import get_ipython
16 16 from IPython.core.error import TryNext
17 17 from IPython.utils import py3compat
18 18
19 19
20 20 def install_editor(template, wait=False):
21 21 """Installs the editor that is called by IPython for the %edit magic.
22 22
23 23 This overrides the default editor, which is generally set by your EDITOR
24 24 environment variable or is notepad (windows) or vi (linux). By supplying a
25 25 template string `run_template`, you can control how the editor is invoked
26 26 by IPython -- (e.g. the format in which it accepts command line options)
27 27
28 28 Parameters
29 29 ----------
30 30 template : basestring
31 31 run_template acts as a template for how your editor is invoked by
32 32 the shell. It should contain '{filename}', which will be replaced on
33 33 invokation with the file name, and '{line}', $line by line number
34 34 (or 0) to invoke the file with.
35 35 wait : bool
36 36 If `wait` is true, wait until the user presses enter before returning,
37 37 to facilitate non-blocking editors that exit immediately after
38 38 the call.
39 39 """
40 40
41 41 # not all editors support $line, so we'll leave out this check
42 42 # for substitution in ['$file', '$line']:
43 43 # if not substitution in run_template:
44 44 # raise ValueError(('run_template should contain %s'
45 45 # ' for string substitution. You supplied "%s"' % (substitution,
46 46 # run_template)))
47 47
48 48 def call_editor(self, filename, line=0):
49 49 if line is None:
50 50 line = 0
51 51 cmd = template.format(filename=pipes.quote(filename), line=line)
52 52 print(">", cmd)
53 53 # pipes.quote doesn't work right on Windows, but it does after splitting
54 54 if sys.platform.startswith('win'):
55 55 cmd = shlex.split(cmd)
56 56 proc = subprocess.Popen(cmd, shell=True)
57 if wait and proc.wait() != 0:
57 if proc.wait() != 0:
58 58 raise TryNext()
59 59 if wait:
60 60 py3compat.input("Press Enter when done editing:")
61 61
62 62 get_ipython().set_hook('editor', call_editor)
63 63 get_ipython().editor = template
64 64
65 65
66 66 # in these, exe is always the path/name of the executable. Useful
67 67 # if you don't have the editor directory in your path
68 68 def komodo(exe=u'komodo'):
69 69 """ Activestate Komodo [Edit] """
70 70 install_editor(exe + u' -l {line} {filename}', wait=True)
71 71
72 72
73 73 def scite(exe=u"scite"):
74 74 """ SciTE or Sc1 """
75 75 install_editor(exe + u' {filename} -goto:{line}')
76 76
77 77
78 78 def notepadplusplus(exe=u'notepad++'):
79 79 """ Notepad++ http://notepad-plus.sourceforge.net """
80 80 install_editor(exe + u' -n{line} {filename}')
81 81
82 82
83 83 def jed(exe=u'jed'):
84 84 """ JED, the lightweight emacsish editor """
85 85 install_editor(exe + u' +{line} {filename}')
86 86
87 87
88 88 def idle(exe=u'idle'):
89 89 """ Idle, the editor bundled with python
90 90
91 91 Parameters
92 92 ----------
93 93 exe : str, None
94 94 If none, should be pretty smart about finding the executable.
95 95 """
96 96 if exe is None:
97 97 import idlelib
98 98 p = os.path.dirname(idlelib.__filename__)
99 99 # i'm not sure if this actually works. Is this idle.py script
100 100 # guarenteed to be executable?
101 101 exe = os.path.join(p, 'idle.py')
102 102 install_editor(exe + u' {filename}')
103 103
104 104
105 105 def mate(exe=u'mate'):
106 106 """ TextMate, the missing editor"""
107 107 # wait=True is not required since we're using the -w flag to mate
108 108 install_editor(exe + u' -w -l {line} {filename}')
109 109
110 110
111 111 # ##########################################
112 112 # these are untested, report any problems
113 113 # ##########################################
114 114
115 115
116 116 def emacs(exe=u'emacs'):
117 117 install_editor(exe + u' +{line} {filename}')
118 118
119 119
120 120 def gnuclient(exe=u'gnuclient'):
121 121 install_editor(exe + u' -nw +{line} {filename}')
122 122
123 123
124 124 def crimson_editor(exe=u'cedt.exe'):
125 125 install_editor(exe + u' /L:{line} {filename}')
126 126
127 127
128 128 def kate(exe=u'kate'):
129 129 install_editor(exe + u' -u -l {line} {filename}')
@@ -1,37 +1,38 b''
1 1 """Test installing editor hooks"""
2 2 import sys
3 3
4 4 try:
5 5 import mock
6 6 except ImportError:
7 7 from unittest import mock
8 8
9 9 import nose.tools as nt
10 10
11 11 from IPython import get_ipython
12 12 from IPython.lib import editorhooks
13 13
14 14 def test_install_editor():
15 15 called = []
16 16 def fake_popen(*args, **kwargs):
17 17 called.append({
18 18 'args': args,
19 19 'kwargs': kwargs,
20 20 })
21 return mock.MagicMock(**{'wait.return_value': 0})
21 22 editorhooks.install_editor('foo -l {line} -f {filename}', wait=False)
22 23
23 24 with mock.patch('subprocess.Popen', fake_popen):
24 25 get_ipython().hooks.editor('the file', 64)
25 26
26 27 nt.assert_equal(len(called), 1)
27 28 args = called[0]['args']
28 29 kwargs = called[0]['kwargs']
29 30
30 31 nt.assert_equal(kwargs, {'shell': True})
31 32
32 33 if sys.platform.startswith('win'):
33 34 expected = ['foo', '-l', '64', '-f', 'the file']
34 35 else:
35 36 expected = "foo -l 64 -f 'the file'"
36 37 cmd = args[0]
37 38 nt.assert_equal(cmd, expected)
General Comments 0
You need to be logged in to leave comments. Login now