Show More
@@ -0,0 +1,56 b'' | |||||
|
1 | """ Utilities for accessing the platform's clipboard. | |||
|
2 | """ | |||
|
3 | ||||
|
4 | import subprocess | |||
|
5 | import sys | |||
|
6 | ||||
|
7 | from IPython.ipapi import TryNext | |||
|
8 | ||||
|
9 | ||||
|
10 | def win32_clipboard_get(): | |||
|
11 | """ Get the current clipboard's text on Windows. | |||
|
12 | ||||
|
13 | Requires Mark Hammond's pywin32 extensions. | |||
|
14 | """ | |||
|
15 | try: | |||
|
16 | import win32clipboard | |||
|
17 | except ImportError: | |||
|
18 | message = ("Getting text from the clipboard requires the pywin32 " | |||
|
19 | "extensions: http://sourceforge.net/projects/pywin32/") | |||
|
20 | raise TryNext(message) | |||
|
21 | win32clipboard.OpenClipboard() | |||
|
22 | text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT) | |||
|
23 | # FIXME: convert \r\n to \n? | |||
|
24 | win32clipboard.CloseClipboard() | |||
|
25 | return text | |||
|
26 | ||||
|
27 | def osx_clipboard_get(): | |||
|
28 | """ Get the clipboard's text on OS X. | |||
|
29 | """ | |||
|
30 | p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'], | |||
|
31 | stdout=subprocess.PIPE) | |||
|
32 | text, stderr = p.communicate() | |||
|
33 | # Text comes in with old Mac \r line endings. Change them to \n. | |||
|
34 | text = text.replace('\r', '\n') | |||
|
35 | return text | |||
|
36 | ||||
|
37 | def tkinter_clipboard_get(): | |||
|
38 | """ Get the clipboard's text using Tkinter. | |||
|
39 | ||||
|
40 | This is the default on systems that are not Windows or OS X. It may | |||
|
41 | interfere with other UI toolkits and should be replaced with an | |||
|
42 | implementation that uses that toolkit. | |||
|
43 | """ | |||
|
44 | try: | |||
|
45 | import Tkinter | |||
|
46 | except ImportError: | |||
|
47 | message = ("Getting text from the clipboard on this platform " | |||
|
48 | "requires Tkinter.") | |||
|
49 | raise TryNext(message) | |||
|
50 | root = Tkinter.Tk() | |||
|
51 | root.withdraw() | |||
|
52 | text = root.clipboard_get() | |||
|
53 | root.destroy() | |||
|
54 | return text | |||
|
55 | ||||
|
56 |
@@ -44,6 +44,7 b' somewhere in your configuration files or ipython command line.' | |||||
44 | from IPython.core import ipapi |
|
44 | from IPython.core import ipapi | |
45 |
|
45 | |||
46 | import os,bisect |
|
46 | import os, bisect | |
|
47 | import sys | |||
47 | from IPython.utils.genutils import Term,shell |
|
48 | from IPython.utils.genutils import Term, shell | |
48 | from pprint import PrettyPrinter |
|
49 | from pprint import PrettyPrinter | |
49 |
|
50 | |||
@@ -53,7 +54,8 b' from pprint import PrettyPrinter' | |||||
53 | __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display', |
|
54 | __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display', | |
54 | 'input_prefilter', 'shutdown_hook', 'late_startup_hook', |
|
55 | 'input_prefilter', 'shutdown_hook', 'late_startup_hook', | |
55 | 'generate_prompt', 'generate_output_prompt','shell_hook', |
|
56 | 'generate_prompt', 'generate_output_prompt','shell_hook', | |
56 |
'show_in_pager','pre_prompt_hook', 'pre_runcode_hook' |
|
57 | 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook', | |
|
58 | 'clipboard_get'] | |||
57 | # vds: << |
|
59 | # vds: << | |
58 |
|
60 | |||
59 | pformat = PrettyPrinter().pformat |
|
61 | pformat = PrettyPrinter().pformat | |
@@ -244,4 +246,21 b' def pre_runcode_hook(self):' | |||||
244 | """ Executed before running the (prefiltered) code in IPython """ |
|
246 | """ Executed before running the (prefiltered) code in IPython """ | |
245 | return None |
|
247 | return None | |
246 |
|
248 | |||
247 |
|
249 | def clipboard_get(self): | ||
|
250 | """ Get text from the clipboard. | |||
|
251 | """ | |||
|
252 | from IPython.lib.clipboard import ( | |||
|
253 | osx_clipboard_get, tkinter_clipboard_get, | |||
|
254 | win32_clipboard_get | |||
|
255 | ) | |||
|
256 | if sys.platform == 'win32': | |||
|
257 | chain = [win32_clipboard_get, tkinter_clipboard_get] | |||
|
258 | elif sys.platform == 'darwin': | |||
|
259 | chain = [osx_clipboard_get, tkinter_clipboard_get] | |||
|
260 | else: | |||
|
261 | chain = [tkinter_clipboard_get] | |||
|
262 | dispatcher = CommandChainDispatcher() | |||
|
263 | for func in chain: | |||
|
264 | dispatcher.add(func) | |||
|
265 | text = dispatcher() | |||
|
266 | return text |
@@ -3262,6 +3262,61 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3262 | page(self.shell.pycolorize(cont), |
|
3262 | page(self.shell.pycolorize(cont), | |
3263 | screen_lines=self.shell.rc.screen_length) |
|
3263 | screen_lines=self.shell.rc.screen_length) | |
3264 |
|
3264 | |||
|
3265 | def _rerun_pasted(self): | |||
|
3266 | """ Rerun a previously pasted command. | |||
|
3267 | """ | |||
|
3268 | b = self.user_ns.get('pasted_block', None) | |||
|
3269 | if b is None: | |||
|
3270 | raise UsageError('No previous pasted block available') | |||
|
3271 | print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)) | |||
|
3272 | exec b in self.user_ns | |||
|
3273 | ||||
|
3274 | def _get_pasted_lines(self, sentinel): | |||
|
3275 | """ Yield pasted lines until the user enters the given sentinel value. | |||
|
3276 | """ | |||
|
3277 | from IPython.core import iplib | |||
|
3278 | print "Pasting code; enter '%s' alone on the line to stop." % sentinel | |||
|
3279 | while True: | |||
|
3280 | l = iplib.raw_input_original(':') | |||
|
3281 | if l == sentinel: | |||
|
3282 | return | |||
|
3283 | else: | |||
|
3284 | yield l | |||
|
3285 | ||||
|
3286 | def _strip_pasted_lines_for_code(self, raw_lines): | |||
|
3287 | """ Strip non-code parts of a sequence of lines to return a block of | |||
|
3288 | code. | |||
|
3289 | """ | |||
|
3290 | # Regular expressions that declare text we strip from the input: | |||
|
3291 | strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt | |||
|
3292 | r'^\s*(\s?>)+', # Python input prompt | |||
|
3293 | r'^\s*\.{3,}', # Continuation prompts | |||
|
3294 | r'^\++', | |||
|
3295 | ] | |||
|
3296 | ||||
|
3297 | strip_from_start = map(re.compile,strip_re) | |||
|
3298 | ||||
|
3299 | lines = [] | |||
|
3300 | for l in raw_lines: | |||
|
3301 | for pat in strip_from_start: | |||
|
3302 | l = pat.sub('',l) | |||
|
3303 | lines.append(l) | |||
|
3304 | ||||
|
3305 | block = "\n".join(lines) + '\n' | |||
|
3306 | #print "block:\n",block | |||
|
3307 | return block | |||
|
3308 | ||||
|
3309 | def _execute_block(self, block, par): | |||
|
3310 | """ Execute a block, or store it in a variable, per the user's request. | |||
|
3311 | """ | |||
|
3312 | if not par: | |||
|
3313 | b = textwrap.dedent(block) | |||
|
3314 | self.user_ns['pasted_block'] = b | |||
|
3315 | exec b in self.user_ns | |||
|
3316 | else: | |||
|
3317 | self.user_ns[par] = SList(block.splitlines()) | |||
|
3318 | print "Block assigned to '%s'" % par | |||
|
3319 | ||||
3265 | def magic_cpaste(self, parameter_s=''): |
|
3320 | def magic_cpaste(self, parameter_s=''): | |
3266 | """Allows you to paste & execute a pre-formatted code block from clipboard. |
|
3321 | """Allows you to paste & execute a pre-formatted code block from clipboard. | |
3267 |
|
3322 | |||
@@ -3287,49 +3342,59 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3287 | will be what was just pasted. |
|
3342 | will be what was just pasted. | |
3288 |
|
3343 | |||
3289 | IPython statements (magics, shell escapes) are not supported (yet). |
|
3344 | IPython statements (magics, shell escapes) are not supported (yet). | |
|
3345 | ||||
|
3346 | See also | |||
|
3347 | -------- | |||
|
3348 | %paste: automatically pull code from clipboard. | |||
3290 | """ |
|
3349 | """ | |
|
3350 | ||||
3291 | opts,args = self.parse_options(parameter_s,'rs:',mode='string') |
|
3351 | opts,args = self.parse_options(parameter_s,'rs:',mode='string') | |
3292 | par = args.strip() |
|
3352 | par = args.strip() | |
3293 | if opts.has_key('r'): |
|
3353 | if opts.has_key('r'): | |
3294 |
|
|
3354 | self._rerun_pasted() | |
3295 | if b is None: |
|
|||
3296 | raise UsageError('No previous pasted block available') |
|
|||
3297 | print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)) |
|
|||
3298 | exec b in self.user_ns |
|
|||
3299 | return |
|
3355 | return | |
3300 |
|
3356 | |||
3301 | sentinel = opts.get('s','--') |
|
3357 | sentinel = opts.get('s','--') | |
3302 |
|
3358 | |||
3303 | # Regular expressions that declare text we strip from the input: |
|
3359 | block = self._strip_pasted_lines_for_code( | |
3304 | strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt |
|
3360 | self._get_pasted_lines(sentinel)) | |
3305 | r'^\s*(\s?>)+', # Python input prompt |
|
|||
3306 | r'^\s*\.{3,}', # Continuation prompts |
|
|||
3307 | r'^\++', |
|
|||
3308 | ] |
|
|||
3309 |
|
3361 | |||
3310 | strip_from_start = map(re.compile,strip_re) |
|
3362 | self._execute_block(block, par) | |
3311 |
|
3363 | |||
3312 | from IPython.core import iplib |
|
3364 | def magic_paste(self, parameter_s=''): | |
3313 | lines = [] |
|
3365 | """Allows you to paste & execute a pre-formatted code block from clipboard. | |
3314 | print "Pasting code; enter '%s' alone on the line to stop." % sentinel |
|
|||
3315 | while 1: |
|
|||
3316 | l = iplib.raw_input_original(':') |
|
|||
3317 | if l ==sentinel: |
|
|||
3318 | break |
|
|||
3319 |
|
|
3366 | ||
3320 | for pat in strip_from_start: |
|
3367 | The text is pulled directly from the clipboard without user | |
3321 | l = pat.sub('',l) |
|
3368 | intervention. | |
3322 | lines.append(l) |
|
|||
3323 |
|
3369 | |||
3324 | block = "\n".join(lines) + '\n' |
|
3370 | The block is dedented prior to execution to enable execution of method | |
3325 | #print "block:\n",block |
|
3371 | definitions. '>' and '+' characters at the beginning of a line are | |
3326 | if not par: |
|
3372 | ignored, to allow pasting directly from e-mails, diff files and | |
3327 | b = textwrap.dedent(block) |
|
3373 | doctests (the '...' continuation prompt is also stripped). The | |
3328 | self.user_ns['pasted_block'] = b |
|
3374 | executed block is also assigned to variable named 'pasted_block' for | |
3329 | exec b in self.user_ns |
|
3375 | later editing with '%edit pasted_block'. | |
3330 |
|
|
3376 | ||
3331 | self.user_ns[par] = SList(block.splitlines()) |
|
3377 | You can also pass a variable name as an argument, e.g. '%paste foo'. | |
3332 | print "Block assigned to '%s'" % par |
|
3378 | This assigns the pasted block to variable 'foo' as string, without | |
|
3379 | dedenting or executing it (preceding >>> and + is still stripped) | |||
|
3380 | ||||
|
3381 | '%paste -r' re-executes the block previously entered by cpaste. | |||
|
3382 | ||||
|
3383 | IPython statements (magics, shell escapes) are not supported (yet). | |||
|
3384 | ||||
|
3385 | See also | |||
|
3386 | -------- | |||
|
3387 | %cpaste: manually paste code into terminal until you mark its end. | |||
|
3388 | """ | |||
|
3389 | opts,args = self.parse_options(parameter_s,'r:',mode='string') | |||
|
3390 | par = args.strip() | |||
|
3391 | if opts.has_key('r'): | |||
|
3392 | self._rerun_pasted() | |||
|
3393 | return | |||
|
3394 | ||||
|
3395 | text = self.shell.hooks.clipboard_get() | |||
|
3396 | block = self._strip_pasted_lines_for_code(text.splitlines()) | |||
|
3397 | self._execute_block(block, par) | |||
3333 |
|
3398 | |||
3334 | def magic_quickref(self,arg): |
|
3399 | def magic_quickref(self,arg): | |
3335 | """ Show a quick reference sheet """ |
|
3400 | """ Show a quick reference sheet """ |
@@ -252,3 +252,39 b' class TestMagicRun(object):' | |||||
252 |
|
252 | |||
253 | def teardown(self): |
|
253 | def teardown(self): | |
254 | self.tmpfile.close() |
|
254 | self.tmpfile.close() | |
|
255 | ||||
|
256 | # Multiple tests for clipboard pasting | |||
|
257 | def test_paste(): | |||
|
258 | ||||
|
259 | def paste(txt): | |||
|
260 | hooks.clipboard_get = lambda : txt | |||
|
261 | _ip.magic('paste') | |||
|
262 | ||||
|
263 | # Inject fake clipboard hook but save original so we can restore it later | |||
|
264 | hooks = _ip.IP.hooks | |||
|
265 | user_ns = _ip.user_ns | |||
|
266 | original_clip = hooks.clipboard_get | |||
|
267 | ||||
|
268 | try: | |||
|
269 | # Run tests with fake clipboard function | |||
|
270 | user_ns.pop('x', None) | |||
|
271 | paste('x=1') | |||
|
272 | yield (nt.assert_equal, user_ns['x'], 1) | |||
|
273 | ||||
|
274 | user_ns.pop('x', None) | |||
|
275 | paste('>>> x=2') | |||
|
276 | yield (nt.assert_equal, user_ns['x'], 2) | |||
|
277 | ||||
|
278 | paste(""" | |||
|
279 | >>> x = [1,2,3] | |||
|
280 | >>> y = [] | |||
|
281 | >>> for i in x: | |||
|
282 | ... y.append(i**2) | |||
|
283 | ... | |||
|
284 | """) | |||
|
285 | yield (nt.assert_equal, user_ns['x'], [1,2,3]) | |||
|
286 | yield (nt.assert_equal, user_ns['y'], [1,4,9]) | |||
|
287 | ||||
|
288 | finally: | |||
|
289 | # Restore original hook | |||
|
290 | hooks.clipboard_get = original_clip |
General Comments 0
You need to be logged in to leave comments.
Login now