##// END OF EJS Templates
Escaped commands
Thomas Kluyver -
Show More
@@ -191,6 +191,121 b' class SystemAssign:'
191
191
192 return lines_before + [new_line] + lines_after
192 return lines_before + [new_line] + lines_after
193
193
194 # The escape sequences that define the syntax transformations IPython will
195 # apply to user input. These can NOT be just changed here: many regular
196 # expressions and other parts of the code may use their hardcoded values, and
197 # for all intents and purposes they constitute the 'IPython syntax', so they
198 # should be considered fixed.
199
200 ESC_SHELL = '!' # Send line to underlying system shell
201 ESC_SH_CAP = '!!' # Send line to system shell and capture output
202 ESC_HELP = '?' # Find information about object
203 ESC_HELP2 = '??' # Find extra-detailed information about object
204 ESC_MAGIC = '%' # Call magic function
205 ESC_MAGIC2 = '%%' # Call cell-magic function
206 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
207 ESC_QUOTE2 = ';' # Quote all args as a single string, call
208 ESC_PAREN = '/' # Call first argument with rest of line as arguments
209
210 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
211 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
212
213 def _make_help_call(target, esc, next_input=None):
214 """Prepares a pinfo(2)/psearch call from a target name and the escape
215 (i.e. ? or ??)"""
216 method = 'pinfo2' if esc == '??' \
217 else 'psearch' if '*' in target \
218 else 'pinfo'
219 arg = " ".join([method, target])
220 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
221 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
222 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
223 if next_input is None:
224 return 'get_ipython().run_line_magic(%r, %r)' % (t_magic_name, t_magic_arg_s)
225 else:
226 return 'get_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
227 (next_input, t_magic_name, t_magic_arg_s)
228
229 def _tr_help(content):
230 "Translate lines escaped with: ?"
231 # A naked help line should just fire the intro help screen
232 if not content:
233 return 'get_ipython().show_usage()'
234
235 return _make_help_call(content, '?')
236
237 def _tr_help2(content):
238 "Translate lines escaped with: ??"
239 # A naked help line should just fire the intro help screen
240 if not content:
241 return 'get_ipython().show_usage()'
242
243 return _make_help_call(content, '??')
244
245 def _tr_magic(content):
246 "Translate lines escaped with: %"
247 name, _, args = content.partition(' ')
248 return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
249
250 def _tr_quote(content):
251 "Translate lines escaped with: ,"
252 name, _, args = content.partition(' ')
253 return '%s("%s")' % (name, '", "'.join(args.split()) )
254
255 def _tr_quote2(content):
256 "Translate lines escaped with: ;"
257 name, _, args = content.partition(' ')
258 return '%s("%s")' % (name, args)
259
260 def _tr_paren(content):
261 "Translate lines escaped with: /"
262 name, _, args = content.partition(' ')
263 return '%s(%s)' % (name, ", ".join(args.split()))
264
265 tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
266 ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
267 ESC_HELP : _tr_help,
268 ESC_HELP2 : _tr_help2,
269 ESC_MAGIC : _tr_magic,
270 ESC_QUOTE : _tr_quote,
271 ESC_QUOTE2 : _tr_quote2,
272 ESC_PAREN : _tr_paren }
273
274 class EscapedCommand:
275 @staticmethod
276 def find(tokens_by_line):
277 """Find the first escaped command (%foo, !foo, etc.) in the cell.
278
279 Returns (line, column) of the escape if found, or None. *line* is 1-indexed.
280 """
281 for line in tokens_by_line:
282 ix = 0
283 while line[ix].type in {tokenize2.INDENT, tokenize2.DEDENT}:
284 ix += 1
285 if line[ix].string in ESCAPE_SINGLES:
286 return line[ix].start
287
288 @staticmethod
289 def transform(lines, start):
290 start_line = start[0] - 1 # Shift from 1-index to 0-index
291 start_col = start[1]
292
293 indent = lines[start_line][:start_col]
294 end_line = find_end_of_continued_line(lines, start_line)
295 line = assemble_continued_line(lines, (start_line, start_col), end_line)
296
297 if line[:2] in ESCAPE_DOUBLES:
298 escape, content = line[:2], line[2:]
299 else:
300 escape, content = line[:1], line[1:]
301 call = tr[escape](content)
302
303 lines_before = lines[:start_line]
304 new_line = indent + call + '\n'
305 lines_after = lines[end_line + 1:]
306
307 return lines_before + [new_line] + lines_after
308
194 def make_tokens_by_line(lines):
309 def make_tokens_by_line(lines):
195 tokens_by_line = [[]]
310 tokens_by_line = [[]]
196 for token in generate_tokens(iter(lines).__next__):
311 for token in generate_tokens(iter(lines).__next__):
@@ -3,6 +3,17 b' import nose.tools as nt'
3 from IPython.core import inputtransformer2 as ipt2
3 from IPython.core import inputtransformer2 as ipt2
4 from IPython.core.inputtransformer2 import make_tokens_by_line
4 from IPython.core.inputtransformer2 import make_tokens_by_line
5
5
6 MULTILINE_MAGIC = ("""\
7 a = f()
8 %foo \\
9 bar
10 g()
11 """.splitlines(keepends=True), """\
12 a = f()
13 get_ipython().run_line_magic('foo', ' bar')
14 g()
15 """.splitlines(keepends=True))
16
6 MULTILINE_MAGIC_ASSIGN = ("""\
17 MULTILINE_MAGIC_ASSIGN = ("""\
7 a = f()
18 a = f()
8 b = %foo \\
19 b = %foo \\
@@ -58,3 +69,14 b' def test_find_assign_system():'
58 def test_transform_assign_system():
69 def test_transform_assign_system():
59 res = ipt2.SystemAssign.transform(MULTILINE_SYSTEM_ASSIGN[0], (2, 4))
70 res = ipt2.SystemAssign.transform(MULTILINE_SYSTEM_ASSIGN[0], (2, 4))
60 nt.assert_equal(res, MULTILINE_SYSTEM_ASSIGN[1])
71 nt.assert_equal(res, MULTILINE_SYSTEM_ASSIGN[1])
72
73 def test_find_magic_escape():
74 tbl = make_tokens_by_line(MULTILINE_MAGIC[0])
75 nt.assert_equal(ipt2.EscapedCommand.find(tbl), (2, 0))
76
77 tbl = make_tokens_by_line(MULTILINE_MAGIC_ASSIGN[0]) # Shouldn't find a = %foo
78 nt.assert_equal(ipt2.EscapedCommand.find(tbl), None)
79
80 def test_transform_magic_escape():
81 res = ipt2.EscapedCommand.transform(MULTILINE_MAGIC[0], (2, 0))
82 nt.assert_equal(res, MULTILINE_MAGIC[1])
General Comments 0
You need to be logged in to leave comments. Login now