##// END OF EJS Templates
Add --term-title-format flag to customize terminal title format
Tory Haavik -
Show More
@@ -0,0 +1,2 b''
1 An additional flag `--term-title-format` is introduced to allow the user to control the format of the terminal
2 title. It is specified as a python format string, and currently the only variable it will format is `{cwd}`.
@@ -1,793 +1,793 b''
1 1 """Implementation of magic functions for interaction with the OS.
2 2
3 3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 4 builtin.
5 5 """
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 import io
10 10 import os
11 11 import re
12 12 import sys
13 13 from pprint import pformat
14 14
15 15 from IPython.core import magic_arguments
16 16 from IPython.core import oinspect
17 17 from IPython.core import page
18 18 from IPython.core.alias import AliasError, Alias
19 19 from IPython.core.error import UsageError
20 20 from IPython.core.magic import (
21 21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
22 22 )
23 23 from IPython.testing.skipdoctest import skip_doctest
24 24 from IPython.utils.openpy import source_to_unicode
25 25 from IPython.utils.process import abbrev_cwd
26 26 from IPython.utils import py3compat
27 27 from IPython.utils.terminal import set_term_title
28 28
29 29
30 30 @magics_class
31 31 class OSMagics(Magics):
32 32 """Magics to interact with the underlying OS (shell-type functionality).
33 33 """
34 34
35 35 @skip_doctest
36 36 @line_magic
37 37 def alias(self, parameter_s=''):
38 38 """Define an alias for a system command.
39 39
40 40 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
41 41
42 42 Then, typing 'alias_name params' will execute the system command 'cmd
43 43 params' (from your underlying operating system).
44 44
45 45 Aliases have lower precedence than magic functions and Python normal
46 46 variables, so if 'foo' is both a Python variable and an alias, the
47 47 alias can not be executed until 'del foo' removes the Python variable.
48 48
49 49 You can use the %l specifier in an alias definition to represent the
50 50 whole line when the alias is called. For example::
51 51
52 52 In [2]: alias bracket echo "Input in brackets: <%l>"
53 53 In [3]: bracket hello world
54 54 Input in brackets: <hello world>
55 55
56 56 You can also define aliases with parameters using %s specifiers (one
57 57 per parameter)::
58 58
59 59 In [1]: alias parts echo first %s second %s
60 60 In [2]: %parts A B
61 61 first A second B
62 62 In [3]: %parts A
63 63 Incorrect number of arguments: 2 expected.
64 64 parts is an alias to: 'echo first %s second %s'
65 65
66 66 Note that %l and %s are mutually exclusive. You can only use one or
67 67 the other in your aliases.
68 68
69 69 Aliases expand Python variables just like system calls using ! or !!
70 70 do: all expressions prefixed with '$' get expanded. For details of
71 71 the semantic rules, see PEP-215:
72 72 http://www.python.org/peps/pep-0215.html. This is the library used by
73 73 IPython for variable expansion. If you want to access a true shell
74 74 variable, an extra $ is necessary to prevent its expansion by
75 75 IPython::
76 76
77 77 In [6]: alias show echo
78 78 In [7]: PATH='A Python string'
79 79 In [8]: show $PATH
80 80 A Python string
81 81 In [9]: show $$PATH
82 82 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
83 83
84 84 You can use the alias facility to access all of $PATH. See the %rehashx
85 85 function, which automatically creates aliases for the contents of your
86 86 $PATH.
87 87
88 88 If called with no parameters, %alias prints the current alias table
89 89 for your system. For posix systems, the default aliases are 'cat',
90 90 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
91 91 aliases are added. For windows-based systems, the default aliases are
92 92 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
93 93
94 94 You can see the definition of alias by adding a question mark in the
95 95 end::
96 96
97 97 In [1]: cat?
98 98 Repr: <alias cat for 'cat'>"""
99 99
100 100 par = parameter_s.strip()
101 101 if not par:
102 102 aliases = sorted(self.shell.alias_manager.aliases)
103 103 # stored = self.shell.db.get('stored_aliases', {} )
104 104 # for k, v in stored:
105 105 # atab.append(k, v[0])
106 106
107 107 print("Total number of aliases:", len(aliases))
108 108 sys.stdout.flush()
109 109 return aliases
110 110
111 111 # Now try to define a new one
112 112 try:
113 113 alias,cmd = par.split(None, 1)
114 114 except TypeError:
115 115 print(oinspect.getdoc(self.alias))
116 116 return
117 117
118 118 try:
119 119 self.shell.alias_manager.define_alias(alias, cmd)
120 120 except AliasError as e:
121 121 print(e)
122 122 # end magic_alias
123 123
124 124 @line_magic
125 125 def unalias(self, parameter_s=''):
126 126 """Remove an alias"""
127 127
128 128 aname = parameter_s.strip()
129 129 try:
130 130 self.shell.alias_manager.undefine_alias(aname)
131 131 except ValueError as e:
132 132 print(e)
133 133 return
134 134
135 135 stored = self.shell.db.get('stored_aliases', {} )
136 136 if aname in stored:
137 137 print("Removing %stored alias",aname)
138 138 del stored[aname]
139 139 self.shell.db['stored_aliases'] = stored
140 140
141 141 @line_magic
142 142 def rehashx(self, parameter_s=''):
143 143 """Update the alias table with all executable files in $PATH.
144 144
145 145 rehashx explicitly checks that every entry in $PATH is a file
146 146 with execute access (os.X_OK).
147 147
148 148 Under Windows, it checks executability as a match against a
149 149 '|'-separated string of extensions, stored in the IPython config
150 150 variable win_exec_ext. This defaults to 'exe|com|bat'.
151 151
152 152 This function also resets the root module cache of module completer,
153 153 used on slow filesystems.
154 154 """
155 155 from IPython.core.alias import InvalidAliasError
156 156
157 157 # for the benefit of module completer in ipy_completers.py
158 158 del self.shell.db['rootmodules_cache']
159 159
160 160 path = [os.path.abspath(os.path.expanduser(p)) for p in
161 161 os.environ.get('PATH','').split(os.pathsep)]
162 162
163 163 syscmdlist = []
164 164 # Now define isexec in a cross platform manner.
165 165 if os.name == 'posix':
166 166 isexec = lambda fname:os.path.isfile(fname) and \
167 167 os.access(fname,os.X_OK)
168 168 else:
169 169 try:
170 170 winext = os.environ['pathext'].replace(';','|').replace('.','')
171 171 except KeyError:
172 172 winext = 'exe|com|bat|py'
173 173 if 'py' not in winext:
174 174 winext += '|py'
175 175 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
176 176 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
177 177 savedir = os.getcwd()
178 178
179 179 # Now walk the paths looking for executables to alias.
180 180 try:
181 181 # write the whole loop for posix/Windows so we don't have an if in
182 182 # the innermost part
183 183 if os.name == 'posix':
184 184 for pdir in path:
185 185 try:
186 186 os.chdir(pdir)
187 187 dirlist = os.listdir(pdir)
188 188 except OSError:
189 189 continue
190 190 for ff in dirlist:
191 191 if isexec(ff):
192 192 try:
193 193 # Removes dots from the name since ipython
194 194 # will assume names with dots to be python.
195 195 if not self.shell.alias_manager.is_alias(ff):
196 196 self.shell.alias_manager.define_alias(
197 197 ff.replace('.',''), ff)
198 198 except InvalidAliasError:
199 199 pass
200 200 else:
201 201 syscmdlist.append(ff)
202 202 else:
203 203 no_alias = Alias.blacklist
204 204 for pdir in path:
205 205 try:
206 206 os.chdir(pdir)
207 207 dirlist = os.listdir(pdir)
208 208 except OSError:
209 209 continue
210 210 for ff in dirlist:
211 211 base, ext = os.path.splitext(ff)
212 212 if isexec(ff) and base.lower() not in no_alias:
213 213 if ext.lower() == '.exe':
214 214 ff = base
215 215 try:
216 216 # Removes dots from the name since ipython
217 217 # will assume names with dots to be python.
218 218 self.shell.alias_manager.define_alias(
219 219 base.lower().replace('.',''), ff)
220 220 except InvalidAliasError:
221 221 pass
222 222 syscmdlist.append(ff)
223 223 self.shell.db['syscmdlist'] = syscmdlist
224 224 finally:
225 225 os.chdir(savedir)
226 226
227 227 @skip_doctest
228 228 @line_magic
229 229 def pwd(self, parameter_s=''):
230 230 """Return the current working directory path.
231 231
232 232 Examples
233 233 --------
234 234 ::
235 235
236 236 In [9]: pwd
237 237 Out[9]: '/home/tsuser/sprint/ipython'
238 238 """
239 239 try:
240 240 return os.getcwd()
241 241 except FileNotFoundError:
242 242 raise UsageError("CWD no longer exists - please use %cd to change directory.")
243 243
244 244 @skip_doctest
245 245 @line_magic
246 246 def cd(self, parameter_s=''):
247 247 """Change the current working directory.
248 248
249 249 This command automatically maintains an internal list of directories
250 250 you visit during your IPython session, in the variable _dh. The
251 251 command %dhist shows this history nicely formatted. You can also
252 252 do 'cd -<tab>' to see directory history conveniently.
253 253
254 254 Usage:
255 255
256 256 cd 'dir': changes to directory 'dir'.
257 257
258 258 cd -: changes to the last visited directory.
259 259
260 260 cd -<n>: changes to the n-th directory in the directory history.
261 261
262 262 cd --foo: change to directory that matches 'foo' in history
263 263
264 264 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
265 265 (note: cd <bookmark_name> is enough if there is no
266 266 directory <bookmark_name>, but a bookmark with the name exists.)
267 267 'cd -b <tab>' allows you to tab-complete bookmark names.
268 268
269 269 Options:
270 270
271 271 -q: quiet. Do not print the working directory after the cd command is
272 272 executed. By default IPython's cd command does print this directory,
273 273 since the default prompts do not display path information.
274 274
275 275 Note that !cd doesn't work for this purpose because the shell where
276 276 !command runs is immediately discarded after executing 'command'.
277 277
278 278 Examples
279 279 --------
280 280 ::
281 281
282 282 In [10]: cd parent/child
283 283 /home/tsuser/parent/child
284 284 """
285 285
286 286 try:
287 287 oldcwd = os.getcwd()
288 288 except FileNotFoundError:
289 289 # Happens if the CWD has been deleted.
290 290 oldcwd = None
291 291
292 292 numcd = re.match(r'(-)(\d+)$',parameter_s)
293 293 # jump in directory history by number
294 294 if numcd:
295 295 nn = int(numcd.group(2))
296 296 try:
297 297 ps = self.shell.user_ns['_dh'][nn]
298 298 except IndexError:
299 299 print('The requested directory does not exist in history.')
300 300 return
301 301 else:
302 302 opts = {}
303 303 elif parameter_s.startswith('--'):
304 304 ps = None
305 305 fallback = None
306 306 pat = parameter_s[2:]
307 307 dh = self.shell.user_ns['_dh']
308 308 # first search only by basename (last component)
309 309 for ent in reversed(dh):
310 310 if pat in os.path.basename(ent) and os.path.isdir(ent):
311 311 ps = ent
312 312 break
313 313
314 314 if fallback is None and pat in ent and os.path.isdir(ent):
315 315 fallback = ent
316 316
317 317 # if we have no last part match, pick the first full path match
318 318 if ps is None:
319 319 ps = fallback
320 320
321 321 if ps is None:
322 322 print("No matching entry in directory history")
323 323 return
324 324 else:
325 325 opts = {}
326 326
327 327
328 328 else:
329 329 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
330 330 # jump to previous
331 331 if ps == '-':
332 332 try:
333 333 ps = self.shell.user_ns['_dh'][-2]
334 334 except IndexError:
335 335 raise UsageError('%cd -: No previous directory to change to.')
336 336 # jump to bookmark if needed
337 337 else:
338 338 if not os.path.isdir(ps) or 'b' in opts:
339 339 bkms = self.shell.db.get('bookmarks', {})
340 340
341 341 if ps in bkms:
342 342 target = bkms[ps]
343 343 print('(bookmark:%s) -> %s' % (ps, target))
344 344 ps = target
345 345 else:
346 346 if 'b' in opts:
347 347 raise UsageError("Bookmark '%s' not found. "
348 348 "Use '%%bookmark -l' to see your bookmarks." % ps)
349 349
350 350 # at this point ps should point to the target dir
351 351 if ps:
352 352 try:
353 353 os.chdir(os.path.expanduser(ps))
354 354 if hasattr(self.shell, 'term_title') and self.shell.term_title:
355 set_term_title('IPython: ' + abbrev_cwd())
355 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
356 356 except OSError:
357 357 print(sys.exc_info()[1])
358 358 else:
359 359 cwd = os.getcwd()
360 360 dhist = self.shell.user_ns['_dh']
361 361 if oldcwd != cwd:
362 362 dhist.append(cwd)
363 363 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
364 364
365 365 else:
366 366 os.chdir(self.shell.home_dir)
367 367 if hasattr(self.shell, 'term_title') and self.shell.term_title:
368 set_term_title('IPython: ' + '~')
368 set_term_title(self.shell.term_title_format.format(cwd="~"))
369 369 cwd = os.getcwd()
370 370 dhist = self.shell.user_ns['_dh']
371 371
372 372 if oldcwd != cwd:
373 373 dhist.append(cwd)
374 374 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
375 375 if not 'q' in opts and self.shell.user_ns['_dh']:
376 376 print(self.shell.user_ns['_dh'][-1])
377 377
378 378 @line_magic
379 379 def env(self, parameter_s=''):
380 380 """Get, set, or list environment variables.
381 381
382 382 Usage:\\
383 383
384 384 %env: lists all environment variables/values
385 385 %env var: get value for var
386 386 %env var val: set value for var
387 387 %env var=val: set value for var
388 388 %env var=$val: set value for var, using python expansion if possible
389 389 """
390 390 if parameter_s.strip():
391 391 split = '=' if '=' in parameter_s else ' '
392 392 bits = parameter_s.split(split)
393 393 if len(bits) == 1:
394 394 key = parameter_s.strip()
395 395 if key in os.environ:
396 396 return os.environ[key]
397 397 else:
398 398 err = "Environment does not have key: {0}".format(key)
399 399 raise UsageError(err)
400 400 if len(bits) > 1:
401 401 return self.set_env(parameter_s)
402 402 return dict(os.environ)
403 403
404 404 @line_magic
405 405 def set_env(self, parameter_s):
406 406 """Set environment variables. Assumptions are that either "val" is a
407 407 name in the user namespace, or val is something that evaluates to a
408 408 string.
409 409
410 410 Usage:\\
411 411 %set_env var val: set value for var
412 412 %set_env var=val: set value for var
413 413 %set_env var=$val: set value for var, using python expansion if possible
414 414 """
415 415 split = '=' if '=' in parameter_s else ' '
416 416 bits = parameter_s.split(split, 1)
417 417 if not parameter_s.strip() or len(bits)<2:
418 418 raise UsageError("usage is 'set_env var=val'")
419 419 var = bits[0].strip()
420 420 val = bits[1].strip()
421 421 if re.match(r'.*\s.*', var):
422 422 # an environment variable with whitespace is almost certainly
423 423 # not what the user intended. what's more likely is the wrong
424 424 # split was chosen, ie for "set_env cmd_args A=B", we chose
425 425 # '=' for the split and should have chosen ' '. to get around
426 426 # this, users should just assign directly to os.environ or use
427 427 # standard magic {var} expansion.
428 428 err = "refusing to set env var with whitespace: '{0}'"
429 429 err = err.format(val)
430 430 raise UsageError(err)
431 431 os.environ[py3compat.cast_bytes_py2(var)] = py3compat.cast_bytes_py2(val)
432 432 print('env: {0}={1}'.format(var,val))
433 433
434 434 @line_magic
435 435 def pushd(self, parameter_s=''):
436 436 """Place the current dir on stack and change directory.
437 437
438 438 Usage:\\
439 439 %pushd ['dirname']
440 440 """
441 441
442 442 dir_s = self.shell.dir_stack
443 443 tgt = os.path.expanduser(parameter_s)
444 444 cwd = os.getcwd().replace(self.shell.home_dir,'~')
445 445 if tgt:
446 446 self.cd(parameter_s)
447 447 dir_s.insert(0,cwd)
448 448 return self.shell.magic('dirs')
449 449
450 450 @line_magic
451 451 def popd(self, parameter_s=''):
452 452 """Change to directory popped off the top of the stack.
453 453 """
454 454 if not self.shell.dir_stack:
455 455 raise UsageError("%popd on empty stack")
456 456 top = self.shell.dir_stack.pop(0)
457 457 self.cd(top)
458 458 print("popd ->",top)
459 459
460 460 @line_magic
461 461 def dirs(self, parameter_s=''):
462 462 """Return the current directory stack."""
463 463
464 464 return self.shell.dir_stack
465 465
466 466 @line_magic
467 467 def dhist(self, parameter_s=''):
468 468 """Print your history of visited directories.
469 469
470 470 %dhist -> print full history\\
471 471 %dhist n -> print last n entries only\\
472 472 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
473 473
474 474 This history is automatically maintained by the %cd command, and
475 475 always available as the global list variable _dh. You can use %cd -<n>
476 476 to go to directory number <n>.
477 477
478 478 Note that most of time, you should view directory history by entering
479 479 cd -<TAB>.
480 480
481 481 """
482 482
483 483 dh = self.shell.user_ns['_dh']
484 484 if parameter_s:
485 485 try:
486 486 args = map(int,parameter_s.split())
487 487 except:
488 488 self.arg_err(self.dhist)
489 489 return
490 490 if len(args) == 1:
491 491 ini,fin = max(len(dh)-(args[0]),0),len(dh)
492 492 elif len(args) == 2:
493 493 ini,fin = args
494 494 fin = min(fin, len(dh))
495 495 else:
496 496 self.arg_err(self.dhist)
497 497 return
498 498 else:
499 499 ini,fin = 0,len(dh)
500 500 print('Directory history (kept in _dh)')
501 501 for i in range(ini, fin):
502 502 print("%d: %s" % (i, dh[i]))
503 503
504 504 @skip_doctest
505 505 @line_magic
506 506 def sc(self, parameter_s=''):
507 507 """Shell capture - run shell command and capture output (DEPRECATED use !).
508 508
509 509 DEPRECATED. Suboptimal, retained for backwards compatibility.
510 510
511 511 You should use the form 'var = !command' instead. Example:
512 512
513 513 "%sc -l myfiles = ls ~" should now be written as
514 514
515 515 "myfiles = !ls ~"
516 516
517 517 myfiles.s, myfiles.l and myfiles.n still apply as documented
518 518 below.
519 519
520 520 --
521 521 %sc [options] varname=command
522 522
523 523 IPython will run the given command using commands.getoutput(), and
524 524 will then update the user's interactive namespace with a variable
525 525 called varname, containing the value of the call. Your command can
526 526 contain shell wildcards, pipes, etc.
527 527
528 528 The '=' sign in the syntax is mandatory, and the variable name you
529 529 supply must follow Python's standard conventions for valid names.
530 530
531 531 (A special format without variable name exists for internal use)
532 532
533 533 Options:
534 534
535 535 -l: list output. Split the output on newlines into a list before
536 536 assigning it to the given variable. By default the output is stored
537 537 as a single string.
538 538
539 539 -v: verbose. Print the contents of the variable.
540 540
541 541 In most cases you should not need to split as a list, because the
542 542 returned value is a special type of string which can automatically
543 543 provide its contents either as a list (split on newlines) or as a
544 544 space-separated string. These are convenient, respectively, either
545 545 for sequential processing or to be passed to a shell command.
546 546
547 547 For example::
548 548
549 549 # Capture into variable a
550 550 In [1]: sc a=ls *py
551 551
552 552 # a is a string with embedded newlines
553 553 In [2]: a
554 554 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
555 555
556 556 # which can be seen as a list:
557 557 In [3]: a.l
558 558 Out[3]: ['setup.py', 'win32_manual_post_install.py']
559 559
560 560 # or as a whitespace-separated string:
561 561 In [4]: a.s
562 562 Out[4]: 'setup.py win32_manual_post_install.py'
563 563
564 564 # a.s is useful to pass as a single command line:
565 565 In [5]: !wc -l $a.s
566 566 146 setup.py
567 567 130 win32_manual_post_install.py
568 568 276 total
569 569
570 570 # while the list form is useful to loop over:
571 571 In [6]: for f in a.l:
572 572 ...: !wc -l $f
573 573 ...:
574 574 146 setup.py
575 575 130 win32_manual_post_install.py
576 576
577 577 Similarly, the lists returned by the -l option are also special, in
578 578 the sense that you can equally invoke the .s attribute on them to
579 579 automatically get a whitespace-separated string from their contents::
580 580
581 581 In [7]: sc -l b=ls *py
582 582
583 583 In [8]: b
584 584 Out[8]: ['setup.py', 'win32_manual_post_install.py']
585 585
586 586 In [9]: b.s
587 587 Out[9]: 'setup.py win32_manual_post_install.py'
588 588
589 589 In summary, both the lists and strings used for output capture have
590 590 the following special attributes::
591 591
592 592 .l (or .list) : value as list.
593 593 .n (or .nlstr): value as newline-separated string.
594 594 .s (or .spstr): value as space-separated string.
595 595 """
596 596
597 597 opts,args = self.parse_options(parameter_s, 'lv')
598 598 # Try to get a variable name and command to run
599 599 try:
600 600 # the variable name must be obtained from the parse_options
601 601 # output, which uses shlex.split to strip options out.
602 602 var,_ = args.split('=', 1)
603 603 var = var.strip()
604 604 # But the command has to be extracted from the original input
605 605 # parameter_s, not on what parse_options returns, to avoid the
606 606 # quote stripping which shlex.split performs on it.
607 607 _,cmd = parameter_s.split('=', 1)
608 608 except ValueError:
609 609 var,cmd = '',''
610 610 # If all looks ok, proceed
611 611 split = 'l' in opts
612 612 out = self.shell.getoutput(cmd, split=split)
613 613 if 'v' in opts:
614 614 print('%s ==\n%s' % (var, pformat(out)))
615 615 if var:
616 616 self.shell.user_ns.update({var:out})
617 617 else:
618 618 return out
619 619
620 620 @line_cell_magic
621 621 def sx(self, line='', cell=None):
622 622 """Shell execute - run shell command and capture output (!! is short-hand).
623 623
624 624 %sx command
625 625
626 626 IPython will run the given command using commands.getoutput(), and
627 627 return the result formatted as a list (split on '\\n'). Since the
628 628 output is _returned_, it will be stored in ipython's regular output
629 629 cache Out[N] and in the '_N' automatic variables.
630 630
631 631 Notes:
632 632
633 633 1) If an input line begins with '!!', then %sx is automatically
634 634 invoked. That is, while::
635 635
636 636 !ls
637 637
638 638 causes ipython to simply issue system('ls'), typing::
639 639
640 640 !!ls
641 641
642 642 is a shorthand equivalent to::
643 643
644 644 %sx ls
645 645
646 646 2) %sx differs from %sc in that %sx automatically splits into a list,
647 647 like '%sc -l'. The reason for this is to make it as easy as possible
648 648 to process line-oriented shell output via further python commands.
649 649 %sc is meant to provide much finer control, but requires more
650 650 typing.
651 651
652 652 3) Just like %sc -l, this is a list with special attributes:
653 653 ::
654 654
655 655 .l (or .list) : value as list.
656 656 .n (or .nlstr): value as newline-separated string.
657 657 .s (or .spstr): value as whitespace-separated string.
658 658
659 659 This is very useful when trying to use such lists as arguments to
660 660 system commands."""
661 661
662 662 if cell is None:
663 663 # line magic
664 664 return self.shell.getoutput(line)
665 665 else:
666 666 opts,args = self.parse_options(line, '', 'out=')
667 667 output = self.shell.getoutput(cell)
668 668 out_name = opts.get('out', opts.get('o'))
669 669 if out_name:
670 670 self.shell.user_ns[out_name] = output
671 671 else:
672 672 return output
673 673
674 674 system = line_cell_magic('system')(sx)
675 675 bang = cell_magic('!')(sx)
676 676
677 677 @line_magic
678 678 def bookmark(self, parameter_s=''):
679 679 """Manage IPython's bookmark system.
680 680
681 681 %bookmark <name> - set bookmark to current dir
682 682 %bookmark <name> <dir> - set bookmark to <dir>
683 683 %bookmark -l - list all bookmarks
684 684 %bookmark -d <name> - remove bookmark
685 685 %bookmark -r - remove all bookmarks
686 686
687 687 You can later on access a bookmarked folder with::
688 688
689 689 %cd -b <name>
690 690
691 691 or simply '%cd <name>' if there is no directory called <name> AND
692 692 there is such a bookmark defined.
693 693
694 694 Your bookmarks persist through IPython sessions, but they are
695 695 associated with each profile."""
696 696
697 697 opts,args = self.parse_options(parameter_s,'drl',mode='list')
698 698 if len(args) > 2:
699 699 raise UsageError("%bookmark: too many arguments")
700 700
701 701 bkms = self.shell.db.get('bookmarks',{})
702 702
703 703 if 'd' in opts:
704 704 try:
705 705 todel = args[0]
706 706 except IndexError:
707 707 raise UsageError(
708 708 "%bookmark -d: must provide a bookmark to delete")
709 709 else:
710 710 try:
711 711 del bkms[todel]
712 712 except KeyError:
713 713 raise UsageError(
714 714 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
715 715
716 716 elif 'r' in opts:
717 717 bkms = {}
718 718 elif 'l' in opts:
719 719 bks = sorted(bkms)
720 720 if bks:
721 721 size = max(map(len, bks))
722 722 else:
723 723 size = 0
724 724 fmt = '%-'+str(size)+'s -> %s'
725 725 print('Current bookmarks:')
726 726 for bk in bks:
727 727 print(fmt % (bk, bkms[bk]))
728 728 else:
729 729 if not args:
730 730 raise UsageError("%bookmark: You must specify the bookmark name")
731 731 elif len(args)==1:
732 732 bkms[args[0]] = os.getcwd()
733 733 elif len(args)==2:
734 734 bkms[args[0]] = args[1]
735 735 self.shell.db['bookmarks'] = bkms
736 736
737 737 @line_magic
738 738 def pycat(self, parameter_s=''):
739 739 """Show a syntax-highlighted file through a pager.
740 740
741 741 This magic is similar to the cat utility, but it will assume the file
742 742 to be Python source and will show it with syntax highlighting.
743 743
744 744 This magic command can either take a local filename, an url,
745 745 an history range (see %history) or a macro as argument ::
746 746
747 747 %pycat myscript.py
748 748 %pycat 7-27
749 749 %pycat myMacro
750 750 %pycat http://www.example.com/myscript.py
751 751 """
752 752 if not parameter_s:
753 753 raise UsageError('Missing filename, URL, input history range, '
754 754 'or macro.')
755 755
756 756 try :
757 757 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
758 758 except (ValueError, IOError):
759 759 print("Error: no such file, variable, URL, history range or macro")
760 760 return
761 761
762 762 page.page(self.shell.pycolorize(source_to_unicode(cont)))
763 763
764 764 @magic_arguments.magic_arguments()
765 765 @magic_arguments.argument(
766 766 '-a', '--append', action='store_true', default=False,
767 767 help='Append contents of the cell to an existing file. '
768 768 'The file will be created if it does not exist.'
769 769 )
770 770 @magic_arguments.argument(
771 771 'filename', type=str,
772 772 help='file to write'
773 773 )
774 774 @cell_magic
775 775 def writefile(self, line, cell):
776 776 """Write the contents of the cell to a file.
777 777
778 778 The file will be overwritten unless the -a (--append) flag is specified.
779 779 """
780 780 args = magic_arguments.parse_argstring(self.writefile, line)
781 781 filename = os.path.expanduser(args.filename)
782 782
783 783 if os.path.exists(filename):
784 784 if args.append:
785 785 print("Appending to %s" % filename)
786 786 else:
787 787 print("Overwriting %s" % filename)
788 788 else:
789 789 print("Writing %s" % filename)
790 790
791 791 mode = 'a' if args.append else 'w'
792 792 with io.open(filename, mode, encoding='utf-8') as f:
793 793 f.write(cell)
@@ -1,525 +1,530 b''
1 1 """IPython terminal interface using prompt_toolkit"""
2 2
3 3 import os
4 4 import sys
5 5 import warnings
6 6 from warnings import warn
7 7
8 8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 9 from IPython.utils import io
10 10 from IPython.utils.py3compat import cast_unicode_py2, input
11 11 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 12 from IPython.utils.process import abbrev_cwd
13 13 from traitlets import (
14 14 Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union,
15 15 Any,
16 16 )
17 17
18 18 from prompt_toolkit.document import Document
19 19 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
20 20 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
21 21 from prompt_toolkit.history import InMemoryHistory
22 22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
23 23 from prompt_toolkit.interface import CommandLineInterface
24 24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 25 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 26 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
27 27
28 28 from pygments.styles import get_style_by_name, get_all_styles
29 29 from pygments.style import Style
30 30 from pygments.token import Token
31 31
32 32 from .debugger import TerminalPdb, Pdb
33 33 from .magics import TerminalMagics
34 34 from .pt_inputhooks import get_inputhook_name_and_func
35 35 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
36 36 from .ptutils import IPythonPTCompleter, IPythonPTLexer
37 37 from .shortcuts import register_ipython_shortcuts
38 38
39 39 DISPLAY_BANNER_DEPRECATED = object()
40 40
41 41
42 42 class _NoStyle(Style): pass
43 43
44 44
45 45
46 46 _style_overrides_light_bg = {
47 47 Token.Prompt: '#0000ff',
48 48 Token.PromptNum: '#0000ee bold',
49 49 Token.OutPrompt: '#cc0000',
50 50 Token.OutPromptNum: '#bb0000 bold',
51 51 }
52 52
53 53 _style_overrides_linux = {
54 54 Token.Prompt: '#00cc00',
55 55 Token.PromptNum: '#00bb00 bold',
56 56 Token.OutPrompt: '#cc0000',
57 57 Token.OutPromptNum: '#bb0000 bold',
58 58 }
59 59
60 60
61 61
62 62 def get_default_editor():
63 63 try:
64 64 return os.environ['EDITOR']
65 65 except KeyError:
66 66 pass
67 67 except UnicodeError:
68 68 warn("$EDITOR environment variable is not pure ASCII. Using platform "
69 69 "default editor.")
70 70
71 71 if os.name == 'posix':
72 72 return 'vi' # the only one guaranteed to be there!
73 73 else:
74 74 return 'notepad' # same in Windows!
75 75
76 76 # conservatively check for tty
77 77 # overridden streams can result in things like:
78 78 # - sys.stdin = None
79 79 # - no isatty method
80 80 for _name in ('stdin', 'stdout', 'stderr'):
81 81 _stream = getattr(sys, _name)
82 82 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
83 83 _is_tty = False
84 84 break
85 85 else:
86 86 _is_tty = True
87 87
88 88
89 89 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
90 90
91 91 class TerminalInteractiveShell(InteractiveShell):
92 92 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
93 93 'to reserve for the completion menu'
94 94 ).tag(config=True)
95 95
96 96 def _space_for_menu_changed(self, old, new):
97 97 self._update_layout()
98 98
99 99 pt_cli = None
100 100 debugger_history = None
101 101 _pt_app = None
102 102
103 103 simple_prompt = Bool(_use_simple_prompt,
104 104 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
105 105
106 106 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
107 107 IPython own testing machinery, and emacs inferior-shell integration through elpy.
108 108
109 109 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
110 110 environment variable is set, or the current terminal is not a tty."""
111 111 ).tag(config=True)
112 112
113 113 @property
114 114 def debugger_cls(self):
115 115 return Pdb if self.simple_prompt else TerminalPdb
116 116
117 117 confirm_exit = Bool(True,
118 118 help="""
119 119 Set to confirm when you try to exit IPython with an EOF (Control-D
120 120 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
121 121 you can force a direct exit without any confirmation.""",
122 122 ).tag(config=True)
123 123
124 124 editing_mode = Unicode('emacs',
125 125 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
126 126 ).tag(config=True)
127 127
128 128 mouse_support = Bool(False,
129 129 help="Enable mouse support in the prompt"
130 130 ).tag(config=True)
131 131
132 132 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
133 133 help="""The name or class of a Pygments style to use for syntax
134 134 highlighting: \n %s""" % ', '.join(get_all_styles())
135 135 ).tag(config=True)
136 136
137 137
138 138 @observe('highlighting_style')
139 139 @observe('colors')
140 140 def _highlighting_style_changed(self, change):
141 141 self.refresh_style()
142 142
143 143 def refresh_style(self):
144 144 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
145 145
146 146
147 147 highlighting_style_overrides = Dict(
148 148 help="Override highlighting format for specific tokens"
149 149 ).tag(config=True)
150 150
151 151 true_color = Bool(False,
152 152 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
153 153 "If your terminal supports true color, the following command "
154 154 "should print 'TRUECOLOR' in orange: "
155 155 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
156 156 ).tag(config=True)
157 157
158 158 editor = Unicode(get_default_editor(),
159 159 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
160 160 ).tag(config=True)
161 161
162 162 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
163 163
164 164 prompts = Instance(Prompts)
165 165
166 166 @default('prompts')
167 167 def _prompts_default(self):
168 168 return self.prompts_class(self)
169 169
170 170 @observe('prompts')
171 171 def _(self, change):
172 172 self._update_layout()
173 173
174 174 @default('displayhook_class')
175 175 def _displayhook_class_default(self):
176 176 return RichPromptDisplayHook
177 177
178 178 term_title = Bool(True,
179 179 help="Automatically set the terminal title"
180 180 ).tag(config=True)
181 181
182 term_title_format = Unicode("IPython: {cwd}",
183 help="Customize the terminal title format. This is a python format string. " +
184 "Available substitutions are: {cwd}."
185 ).tag(config=True)
186
182 187 display_completions = Enum(('column', 'multicolumn','readlinelike'),
183 188 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
184 189 "'readlinelike'. These options are for `prompt_toolkit`, see "
185 190 "`prompt_toolkit` documentation for more information."
186 191 ),
187 192 default_value='multicolumn').tag(config=True)
188 193
189 194 highlight_matching_brackets = Bool(True,
190 195 help="Highlight matching brackets.",
191 196 ).tag(config=True)
192 197
193 198 extra_open_editor_shortcuts = Bool(False,
194 199 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
195 200 "This is in addition to the F2 binding, which is always enabled."
196 201 ).tag(config=True)
197 202
198 203 handle_return = Any(None,
199 204 help="Provide an alternative handler to be called when the user presses "
200 205 "Return. This is an advanced option intended for debugging, which "
201 206 "may be changed or removed in later releases."
202 207 ).tag(config=True)
203 208
204 209 @observe('term_title')
205 210 def init_term_title(self, change=None):
206 211 # Enable or disable the terminal title.
207 212 if self.term_title:
208 213 toggle_set_term_title(True)
209 set_term_title('IPython: ' + abbrev_cwd())
214 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
210 215 else:
211 216 toggle_set_term_title(False)
212 217
213 218 def init_display_formatter(self):
214 219 super(TerminalInteractiveShell, self).init_display_formatter()
215 220 # terminal only supports plain text
216 221 self.display_formatter.active_types = ['text/plain']
217 222 # disable `_ipython_display_`
218 223 self.display_formatter.ipython_display_formatter.enabled = False
219 224
220 225 def init_prompt_toolkit_cli(self):
221 226 if self.simple_prompt:
222 227 # Fall back to plain non-interactive output for tests.
223 228 # This is very limited, and only accepts a single line.
224 229 def prompt():
225 230 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
226 231 self.prompt_for_code = prompt
227 232 return
228 233
229 234 # Set up keyboard shortcuts
230 235 kbmanager = KeyBindingManager.for_prompt(
231 236 enable_open_in_editor=self.extra_open_editor_shortcuts,
232 237 )
233 238 register_ipython_shortcuts(kbmanager.registry, self)
234 239
235 240 # Pre-populate history from IPython's history database
236 241 history = InMemoryHistory()
237 242 last_cell = u""
238 243 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
239 244 include_latest=True):
240 245 # Ignore blank lines and consecutive duplicates
241 246 cell = cell.rstrip()
242 247 if cell and (cell != last_cell):
243 248 history.append(cell)
244 249 last_cell = cell
245 250
246 251 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
247 252 self.style = DynamicStyle(lambda: self._style)
248 253
249 254 editing_mode = getattr(EditingMode, self.editing_mode.upper())
250 255
251 256 def patch_stdout(**kwargs):
252 257 return self.pt_cli.patch_stdout_context(**kwargs)
253 258
254 259 self._pt_app = create_prompt_application(
255 260 editing_mode=editing_mode,
256 261 key_bindings_registry=kbmanager.registry,
257 262 history=history,
258 263 completer=IPythonPTCompleter(shell=self,
259 264 patch_stdout=patch_stdout),
260 265 enable_history_search=True,
261 266 style=self.style,
262 267 mouse_support=self.mouse_support,
263 268 **self._layout_options()
264 269 )
265 270 self._eventloop = create_eventloop(self.inputhook)
266 271 self.pt_cli = CommandLineInterface(
267 272 self._pt_app, eventloop=self._eventloop,
268 273 output=create_output(true_color=self.true_color))
269 274
270 275 def _make_style_from_name_or_cls(self, name_or_cls):
271 276 """
272 277 Small wrapper that make an IPython compatible style from a style name
273 278
274 279 We need that to add style for prompt ... etc.
275 280 """
276 281 style_overrides = {}
277 282 if name_or_cls == 'legacy':
278 283 legacy = self.colors.lower()
279 284 if legacy == 'linux':
280 285 style_cls = get_style_by_name('monokai')
281 286 style_overrides = _style_overrides_linux
282 287 elif legacy == 'lightbg':
283 288 style_overrides = _style_overrides_light_bg
284 289 style_cls = get_style_by_name('pastie')
285 290 elif legacy == 'neutral':
286 291 # The default theme needs to be visible on both a dark background
287 292 # and a light background, because we can't tell what the terminal
288 293 # looks like. These tweaks to the default theme help with that.
289 294 style_cls = get_style_by_name('default')
290 295 style_overrides.update({
291 296 Token.Number: '#007700',
292 297 Token.Operator: 'noinherit',
293 298 Token.String: '#BB6622',
294 299 Token.Name.Function: '#2080D0',
295 300 Token.Name.Class: 'bold #2080D0',
296 301 Token.Name.Namespace: 'bold #2080D0',
297 302 Token.Prompt: '#009900',
298 303 Token.PromptNum: '#00ff00 bold',
299 304 Token.OutPrompt: '#990000',
300 305 Token.OutPromptNum: '#ff0000 bold',
301 306 })
302 307
303 308 # Hack: Due to limited color support on the Windows console
304 309 # the prompt colors will be wrong without this
305 310 if os.name == 'nt':
306 311 style_overrides.update({
307 312 Token.Prompt: '#ansidarkgreen',
308 313 Token.PromptNum: '#ansigreen bold',
309 314 Token.OutPrompt: '#ansidarkred',
310 315 Token.OutPromptNum: '#ansired bold',
311 316 })
312 317 elif legacy =='nocolor':
313 318 style_cls=_NoStyle
314 319 style_overrides = {}
315 320 else :
316 321 raise ValueError('Got unknown colors: ', legacy)
317 322 else :
318 323 if isinstance(name_or_cls, str):
319 324 style_cls = get_style_by_name(name_or_cls)
320 325 else:
321 326 style_cls = name_or_cls
322 327 style_overrides = {
323 328 Token.Prompt: '#009900',
324 329 Token.PromptNum: '#00ff00 bold',
325 330 Token.OutPrompt: '#990000',
326 331 Token.OutPromptNum: '#ff0000 bold',
327 332 }
328 333 style_overrides.update(self.highlighting_style_overrides)
329 334 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
330 335 style_dict=style_overrides)
331 336
332 337 return style
333 338
334 339 def _layout_options(self):
335 340 """
336 341 Return the current layout option for the current Terminal InteractiveShell
337 342 """
338 343 return {
339 344 'lexer':IPythonPTLexer(),
340 345 'reserve_space_for_menu':self.space_for_menu,
341 346 'get_prompt_tokens':self.prompts.in_prompt_tokens,
342 347 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
343 348 'multiline':True,
344 349 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
345 350
346 351 # Highlight matching brackets, but only when this setting is
347 352 # enabled, and only when the DEFAULT_BUFFER has the focus.
348 353 'extra_input_processors': [ConditionalProcessor(
349 354 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
350 355 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
351 356 Condition(lambda cli: self.highlight_matching_brackets))],
352 357 }
353 358
354 359 def _update_layout(self):
355 360 """
356 361 Ask for a re computation of the application layout, if for example ,
357 362 some configuration options have changed.
358 363 """
359 364 if self._pt_app:
360 365 self._pt_app.layout = create_prompt_layout(**self._layout_options())
361 366
362 367 def prompt_for_code(self):
363 368 document = self.pt_cli.run(
364 369 pre_run=self.pre_prompt, reset_current_buffer=True)
365 370 return document.text
366 371
367 372 def enable_win_unicode_console(self):
368 373 if sys.version_info >= (3, 6):
369 374 # Since PEP 528, Python uses the unicode APIs for the Windows
370 375 # console by default, so WUC shouldn't be needed.
371 376 return
372 377
373 378 import win_unicode_console
374 379 win_unicode_console.enable()
375 380
376 381 def init_io(self):
377 382 if sys.platform not in {'win32', 'cli'}:
378 383 return
379 384
380 385 self.enable_win_unicode_console()
381 386
382 387 import colorama
383 388 colorama.init()
384 389
385 390 # For some reason we make these wrappers around stdout/stderr.
386 391 # For now, we need to reset them so all output gets coloured.
387 392 # https://github.com/ipython/ipython/issues/8669
388 393 # io.std* are deprecated, but don't show our own deprecation warnings
389 394 # during initialization of the deprecated API.
390 395 with warnings.catch_warnings():
391 396 warnings.simplefilter('ignore', DeprecationWarning)
392 397 io.stdout = io.IOStream(sys.stdout)
393 398 io.stderr = io.IOStream(sys.stderr)
394 399
395 400 def init_magics(self):
396 401 super(TerminalInteractiveShell, self).init_magics()
397 402 self.register_magics(TerminalMagics)
398 403
399 404 def init_alias(self):
400 405 # The parent class defines aliases that can be safely used with any
401 406 # frontend.
402 407 super(TerminalInteractiveShell, self).init_alias()
403 408
404 409 # Now define aliases that only make sense on the terminal, because they
405 410 # need direct access to the console in a way that we can't emulate in
406 411 # GUI or web frontend
407 412 if os.name == 'posix':
408 413 for cmd in ['clear', 'more', 'less', 'man']:
409 414 self.alias_manager.soft_define_alias(cmd, cmd)
410 415
411 416
412 417 def __init__(self, *args, **kwargs):
413 418 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
414 419 self.init_prompt_toolkit_cli()
415 420 self.init_term_title()
416 421 self.keep_running = True
417 422
418 423 self.debugger_history = InMemoryHistory()
419 424
420 425 def ask_exit(self):
421 426 self.keep_running = False
422 427
423 428 rl_next_input = None
424 429
425 430 def pre_prompt(self):
426 431 if self.rl_next_input:
427 432 # We can't set the buffer here, because it will be reset just after
428 433 # this. Adding a callable to pre_run_callables does what we need
429 434 # after the buffer is reset.
430 435 s = cast_unicode_py2(self.rl_next_input)
431 436 def set_doc():
432 437 self.pt_cli.application.buffer.document = Document(s)
433 438 if hasattr(self.pt_cli, 'pre_run_callables'):
434 439 self.pt_cli.pre_run_callables.append(set_doc)
435 440 else:
436 441 # Older version of prompt_toolkit; it's OK to set the document
437 442 # directly here.
438 443 set_doc()
439 444 self.rl_next_input = None
440 445
441 446 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
442 447
443 448 if display_banner is not DISPLAY_BANNER_DEPRECATED:
444 449 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
445 450
446 451 self.keep_running = True
447 452 while self.keep_running:
448 453 print(self.separate_in, end='')
449 454
450 455 try:
451 456 code = self.prompt_for_code()
452 457 except EOFError:
453 458 if (not self.confirm_exit) \
454 459 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
455 460 self.ask_exit()
456 461
457 462 else:
458 463 if code:
459 464 self.run_cell(code, store_history=True)
460 465
461 466 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
462 467 # An extra layer of protection in case someone mashing Ctrl-C breaks
463 468 # out of our internal code.
464 469 if display_banner is not DISPLAY_BANNER_DEPRECATED:
465 470 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
466 471 while True:
467 472 try:
468 473 self.interact()
469 474 break
470 475 except KeyboardInterrupt as e:
471 476 print("\n%s escaped interact()\n" % type(e).__name__)
472 477 finally:
473 478 # An interrupt during the eventloop will mess up the
474 479 # internal state of the prompt_toolkit library.
475 480 # Stopping the eventloop fixes this, see
476 481 # https://github.com/ipython/ipython/pull/9867
477 482 if hasattr(self, '_eventloop'):
478 483 self._eventloop.stop()
479 484
480 485 _inputhook = None
481 486 def inputhook(self, context):
482 487 if self._inputhook is not None:
483 488 self._inputhook(context)
484 489
485 490 active_eventloop = None
486 491 def enable_gui(self, gui=None):
487 492 if gui:
488 493 self.active_eventloop, self._inputhook =\
489 494 get_inputhook_name_and_func(gui)
490 495 else:
491 496 self.active_eventloop = self._inputhook = None
492 497
493 498 # Run !system commands directly, not through pipes, so terminal programs
494 499 # work correctly.
495 500 system = InteractiveShell.system_raw
496 501
497 502 def auto_rewrite_input(self, cmd):
498 503 """Overridden from the parent class to use fancy rewriting prompt"""
499 504 if not self.show_rewritten_input:
500 505 return
501 506
502 507 tokens = self.prompts.rewrite_prompt_tokens()
503 508 if self.pt_cli:
504 509 self.pt_cli.print_tokens(tokens)
505 510 print(cmd)
506 511 else:
507 512 prompt = ''.join(s for t, s in tokens)
508 513 print(prompt, cmd, sep='')
509 514
510 515 _prompts_before = None
511 516 def switch_doctest_mode(self, mode):
512 517 """Switch prompts to classic for %doctest_mode"""
513 518 if mode:
514 519 self._prompts_before = self.prompts
515 520 self.prompts = ClassicPrompts(self)
516 521 elif self._prompts_before:
517 522 self.prompts = self._prompts_before
518 523 self._prompts_before = None
519 524 self._update_layout()
520 525
521 526
522 527 InteractiveShellABC.register(TerminalInteractiveShell)
523 528
524 529 if __name__ == '__main__':
525 530 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now