1 """Extra magics for terminal use.""" 2 3 # Copyright (c) IPython Development Team. 4 # Distributed under the terms of the Modified BSD License. 5 6 7 from logging import error 8 import os 9 import sys 10 11 from IPython.core.error import TryNext, UsageError 12 from IPython.core.magic import Magics, magics_class, line_magic 13 from IPython.lib.clipboard import ClipboardEmpty 14 from IPython.testing.skipdoctest import skip_doctest 15 from IPython.utils.text import SList, strip_email_quotes 16 from IPython.utils import py3compat 17 18 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False): 19 """ Yield pasted lines until the user enters the given sentinel value. 20 """ 21 if not quiet: 22 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \ 23 % sentinel) 24 prompt = ":" 25 else: 26 prompt = "" 27 while True: 28 try: 29 l = l_input(prompt) 30 if l == sentinel: 31 return 32 else: 33 yield l 34 except EOFError: 35 print('<EOF>') 36 return 37 38 39 @magics_class 40 class TerminalMagics(Magics): 41 def __init__(self, shell): 42 super(TerminalMagics, self).__init__(shell) 43 44 def store_or_execute(self, block, name, store_history=False): 45 """ Execute a block, or store it in a variable, per the user's request. 46 """ 47 if name: 48 # If storing it for further editing 49 self.shell.user_ns[name] = SList(block.splitlines()) 50 print("Block assigned to '%s'" % name) 51 else: 52 b = self.preclean_input(block) 53 self.shell.user_ns['pasted_block'] = b 54 self.shell.using_paste_magics = True 55 try: 56 self.shell.run_cell(b, store_history) 57 finally: 58 self.shell.using_paste_magics = False 59 60 def preclean_input(self, block): 61 lines = block.splitlines() 62 while lines and not lines[0].strip(): 63 lines = lines[1:] 64 return strip_email_quotes('\n'.join(lines)) 65 66 def rerun_pasted(self, name='pasted_block'): 67 """ Rerun a previously pasted command. 68 """ 69 b = self.shell.user_ns.get(name) 70 71 # Sanity checks 72 if b is None: 73 raise UsageError('No previous pasted block available') 74 if not isinstance(b, str): 75 raise UsageError( 76 "Variable 'pasted_block' is not a string, can't execute") 77 78 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))) 79 self.shell.run_cell(b) 80 81 @line_magic 82 def autoindent(self, parameter_s = ''): 83 """Toggle autoindent on/off (deprecated)""" 84 self.shell.set_autoindent() 85 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent]) 86 87 @skip_doctest 88 @line_magic 89 def cpaste(self, parameter_s=''): 90 """Paste & execute a pre-formatted code block from clipboard. 91 92 You must terminate the block with '--' (two minus-signs) or Ctrl-D 93 alone on the line. You can also provide your own sentinel with '%paste 94 -s %%' ('%%' is the new sentinel for this operation). 95 96 The block is dedented prior to execution to enable execution of method 97 definitions. '>' and '+' characters at the beginning of a line are 98 ignored, to allow pasting directly from e-mails, diff files and 99 doctests (the '...' continuation prompt is also stripped). The 100 executed block is also assigned to variable named 'pasted_block' for 101 later editing with '%edit pasted_block'. 102 103 You can also pass a variable name as an argument, e.g. '%cpaste foo'. 104 This assigns the pasted block to variable 'foo' as string, without 105 dedenting or executing it (preceding >>> and + is still stripped) 106 107 '%cpaste -r' re-executes the block previously entered by cpaste. 108 '%cpaste -q' suppresses any additional output messages. 109 110 Do not be alarmed by garbled output on Windows (it's a readline bug). 111 Just press enter and type -- (and press enter again) and the block 112 will be what was just pasted. 113 114 Shell escapes are not supported (yet). 115 116 See Also 117 -------- 118 paste : automatically pull code from clipboard. 119 120 Examples 121 -------- 122 :: 123 124 In [8]: %cpaste 125 Pasting code; enter '--' alone on the line to stop. 126 :>>> a = ["world!", "Hello"] 127 :>>> print(" ".join(sorted(a))) 128 :-- 129 Hello world! 130 131 :: 132 In [8]: %cpaste 133 Pasting code; enter '--' alone on the line to stop. 134 :>>> %alias_magic t timeit 135 :>>> %t -n1 pass 136 :-- 137 Created `%t` as an alias for `%timeit`. 138 Created `%%t` as an alias for `%%timeit`. 139 354 ns ± 224 ns per loop (mean ± std. dev. of 7 runs, 1 loop each) 140 """ 141 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string') 142 if 'r' in opts: 143 self.rerun_pasted() 144 return 145 146 quiet = ('q' in opts) 147 148 sentinel = opts.get('s', u'--') 149 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet)) 150 self.store_or_execute(block, name, store_history=True) 151 152 @line_magic 153 def paste(self, parameter_s=''): 154 """Paste & execute a pre-formatted code block from clipboard. 155 156 The text is pulled directly from the clipboard without user 157 intervention and printed back on the screen before execution (unless 158 the -q flag is given to force quiet mode). 159 160 The block is dedented prior to execution to enable execution of method 161 definitions. '>' and '+' characters at the beginning of a line are 162 ignored, to allow pasting directly from e-mails, diff files and 163 doctests (the '...' continuation prompt is also stripped). The 164 executed block is also assigned to variable named 'pasted_block' for 165 later editing with '%edit pasted_block'. 166 167 You can also pass a variable name as an argument, e.g. '%paste foo'. 168 This assigns the pasted block to variable 'foo' as string, without 169 executing it (preceding >>> and + is still stripped). 170 171 Options: 172 173 -r: re-executes the block previously entered by cpaste. 174 175 -q: quiet mode: do not echo the pasted text back to the terminal. 176 177 IPython statements (magics, shell escapes) are not supported (yet). 178 179 See Also 180 -------- 181 cpaste : manually paste code into terminal until you mark its end. 182 """ 183 opts, name = self.parse_options(parameter_s, 'rq', mode='string') 184 if 'r' in opts: 185 self.rerun_pasted() 186 return 187 try: 188 block = self.shell.hooks.clipboard_get() 189 except TryNext as clipboard_exc: 190 message = getattr(clipboard_exc, 'args') 191 if message: 192 error(message[0]) 193 else: 194 error('Could not get text from the clipboard.') 195 return 196 except ClipboardEmpty as e: 197 raise UsageError("The clipboard appears to be empty") from e 198 199 # By default, echo back to terminal unless quiet mode is requested 200 if 'q' not in opts: 201 sys.stdout.write(self.shell.pycolorize(block)) 202 if not block.endswith("\n"): 203 sys.stdout.write("\n") 204 sys.stdout.write("## -- End pasted text --\n") 205 206 self.store_or_execute(block, name, store_history=True) 207 208 # Class-level: add a '%cls' magic only on Windows 209 if sys.platform == 'win32': 210 @line_magic 211 def cls(self, s): 212 """Clear screen. 213 """ 214 os.system("cls") 215