| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -962,6 +962,10 @@ def p_key(self, key): | |||
| 962 | 962 | self.pastebin() | |
| 963 | 963 | return '' | |
| 964 | 964 | ||
| 965 | + elif key in key_dispatch[config.copy_clipboard_key]: | ||
| 966 | + self.copy2clipboard() | ||
| 967 | + return '' | ||
| 968 | + | ||
| 965 | 969 | elif key in key_dispatch[config.last_output_key]: | |
| 966 | 970 | page(self.stdout_hist[self.prev_block_finished:-4]) | |
| 967 | 971 | return '' | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,67 @@ | |||
| 1 | + # The MIT License | ||
| 2 | + # | ||
| 3 | + # Copyright (c) 2015 the bpython authors. | ||
| 4 | + # | ||
| 5 | + # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | + # of this software and associated documentation files (the "Software"), to deal | ||
| 7 | + # in the Software without restriction, including without limitation the rights | ||
| 8 | + # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | + # copies of the Software, and to permit persons to whom the Software is | ||
| 10 | + # furnished to do so, subject to the following conditions: | ||
| 11 | + # | ||
| 12 | + # The above copyright notice and this permission notice shall be included in | ||
| 13 | + # all copies or substantial portions of the Software. | ||
| 14 | + # | ||
| 15 | + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | + # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | + # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | + # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | + # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 21 | + # THE SOFTWARE. | ||
| 22 | + | ||
| 23 | + import subprocess | ||
| 24 | + import os | ||
| 25 | + import platform | ||
| 26 | + from locale import getpreferredencoding | ||
| 27 | + | ||
| 28 | + class CopyFailed(Exception): | ||
| 29 | + pass | ||
| 30 | + | ||
| 31 | + class XClipboard(object): | ||
| 32 | + """Manage clipboard with xclip.""" | ||
| 33 | + | ||
| 34 | + def copy(self, content): | ||
| 35 | + process = subprocess.Popen(['xclip', '-i', '-selection', 'clipboard'], | ||
| 36 | + stdin=subprocess.PIPE) | ||
| 37 | + process.communicate(content.encode(getpreferredencoding())) | ||
| 38 | + if process.returncode != 0: | ||
| 39 | + raise CopyFailed() | ||
| 40 | + | ||
| 41 | + class OSXClipboard(object): | ||
| 42 | + """Manage clipboard with pbcopy.""" | ||
| 43 | + | ||
| 44 | + def copy(self, content): | ||
| 45 | + process = subprocess.Popen(['pbcopy', 'w'], stdin=subprocess.PIPE) | ||
| 46 | + process.communicate(content.encode(getpreferredencoding())) | ||
| 47 | + if process.returncode != 0: | ||
| 48 | + raise CopyFailed() | ||
| 49 | + | ||
| 50 | + def command_exists(command): | ||
| 51 | + process = subprocess.Popen(['which', command], stderr=subprocess.STDOUT, | ||
| 52 | + stdout=subprocess.PIPE) | ||
| 53 | + process.communicate() | ||
| 54 | + | ||
| 55 | + return process.returncode == 0 | ||
| 56 | + | ||
| 57 | + def get_clipboard(): | ||
| 58 | + """Get best clipboard handling implemention for current system.""" | ||
| 59 | + | ||
| 60 | + if platform.system() == 'Darwin': | ||
| 61 | + if command_exists('pbcopy'): | ||
| 62 | + return OSXClipboard() | ||
| 63 | + if platform.system() in ('Linux', 'FreeBSD', 'OpenBSD') and os.getenv('DISPLAY') is not None: | ||
| 64 | + if command_exists('xclip'): | ||
| 65 | + return XClipboard() | ||
| 66 | + | ||
| 67 | + return None | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -82,6 +82,7 @@ def loadini(struct, configfile): | |||
| 82 | 82 | 'edit_current_block': 'C-x', | |
| 83 | 83 | 'help': 'F1', | |
| 84 | 84 | 'last_output': 'F9', | |
| 85 | + 'copy_clipboard': 'F10', | ||
| 85 | 86 | 'pastebin': 'F8', | |
| 86 | 87 | 'save': 'C-s', | |
| 87 | 88 | 'show_source': 'F2', | |
@@ -139,6 +140,7 @@ def get_key_no_doublebind(attr, already_used={}): | |||
| 139 | 140 | struct.flush_output = config.getboolean('general', 'flush_output') | |
| 140 | 141 | ||
| 141 | 142 | struct.pastebin_key = get_key_no_doublebind('pastebin') | |
| 143 | + struct.copy_clipboard_key = get_key_no_doublebind('copy_clipboard') | ||
| 142 | 144 | struct.save_key = get_key_no_doublebind('save') | |
| 143 | 145 | struct.search_key = get_key_no_doublebind('search') | |
| 144 | 146 | struct.show_source_key = get_key_no_doublebind('show_source') | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -143,6 +143,7 @@ def confirm(self, q): | |||
| 143 | 143 | self.prompt = q | |
| 144 | 144 | self.in_confirm = True | |
| 145 | 145 | return self.main_greenlet.switch(q) | |
| 146 | + | ||
| 146 | 147 | def file_prompt(self, s): | |
| 147 | 148 | """Expected to return a file name, given """ | |
| 148 | 149 | self.request_greenlet = greenlet.getcurrent() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -547,6 +547,8 @@ def process_key_event(self, e): | |||
| 547 | 547 | greenlet.greenlet(self.write2file).switch() | |
| 548 | 548 | elif e in key_dispatch[self.config.pastebin_key]: # F8 for pastebin | |
| 549 | 549 | greenlet.greenlet(self.pastebin).switch() | |
| 550 | + elif e in key_dispatch[self.config.copy_clipboard_key]: | ||
| 551 | + greenlet.greenlet(self.copy2clipboard).switch() | ||
| 550 | 552 | elif e in key_dispatch[self.config.external_editor_key]: | |
| 551 | 553 | self.send_session_to_external_editor() | |
| 552 | 554 | elif e in key_dispatch[self.config.edit_config_key]: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -48,6 +48,7 @@ | |||
| 48 | 48 | from bpython._py3compat import PythonLexer, py3 | |
| 49 | 49 | from bpython.formatter import Parenthesis | |
| 50 | 50 | from bpython.translations import _ | |
| 51 | + from bpython.clipboard import get_clipboard, CopyFailed | ||
| 51 | 52 | import bpython.autocomplete as autocomplete | |
| 52 | 53 | ||
| 53 | 54 | ||
@@ -446,6 +447,7 @@ def __init__(self, interp, config): | |||
| 446 | 447 | # Necessary to fix mercurial.ui.ui expecting sys.stderr to have this | |
| 447 | 448 | # attribute | |
| 448 | 449 | self.closed = False | |
| 450 | + self.clipboard = get_clipboard() | ||
| 449 | 451 | ||
| 450 | 452 | pythonhist = os.path.expanduser(self.config.hist_file) | |
| 451 | 453 | if os.path.exists(pythonhist): | |
@@ -768,6 +770,21 @@ def write2file(self): | |||
| 768 | 770 | else: | |
| 769 | 771 | self.interact.notify('Saved to %s.' % (fn, )) | |
| 770 | 772 | ||
| 773 | + def copy2clipboard(self): | ||
| 774 | + """Copy current content to clipboard.""" | ||
| 775 | + | ||
| 776 | + if self.clipboard is None: | ||
| 777 | + self.interact.notify(_('No clipboard available.')) | ||
| 778 | + return | ||
| 779 | + | ||
| 780 | + content = self.formatforfile(self.getstdout()) | ||
| 781 | + try: | ||
| 782 | + self.clipboard.copy(content) | ||
| 783 | + except CopyFailed: | ||
| 784 | + self.interact.notify(_('Could not copy to clipboard.')) | ||
| 785 | + else: | ||
| 786 | + self.interact.notify(_('Copied content to clipboard.')) | ||
| 787 | + | ||
| 771 | 788 | def pastebin(self, s=None): | |
| 772 | 789 | """Upload to a pastebin and display the URL in the status bar.""" | |
| 773 | 790 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments