Created
January 27, 2019 21:22
-
-
Save mattst/4470cd5747f1e8975a153cad2c02eec9 to your computer and use it in GitHub Desktop.
Enhanced version of the default Sublime Text paste_from_history.py plugin.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# My enhanced version of the default ST paste_from_history.py plugin. | |
# | |
# Alterations to do the following: | |
# | |
# 1) Select the paste to text from an overlay instead of a pop-up menu. | |
# 2) Allow operation from widgets, i.e. console and input panel. | |
# 3) Ensure that text copied or cut with my various copy_and_cut_text | |
# plugins gets added to the ClipboardHistory storage list. | |
# 4) is_enabled() replaced by a "clipboard history empty" status message. | |
# 5) Changes made to the display text, including the addition of a line | |
# count (if >1), an increase of the display length, and far superior | |
# display name formatting and efficiency for large clipboards. | |
# | |
# Replace paste_from_history command with this enhanced version. | |
# {"keys": ["ctrl+k", "ctrl+v"], "command": "paste_from_history_enhanced"} | |
# | |
import re | |
import sublime | |
import sublime_plugin | |
class ClipboardHistory(): | |
""" Stores the current clipboard history. """ | |
def __init__(self): | |
self.storage = [] | |
def push_text(self, text): | |
LIST_LIMIT = 15 | |
if not text: | |
return | |
display_text = self.build_display_text(text) | |
self.delete_duplicates(text) | |
self.storage.insert(0, (display_text, text)) | |
if len(self.storage) > LIST_LIMIT: | |
del self.storage[LIST_LIMIT:] | |
def build_display_text(self, text): | |
DOTS = "..." | |
DISPLAY_LENGTH = 70 | |
REDUCE_LENGTH_THRESHOLD = 1024 | |
# A threshold is used to avoid poor performance caused by | |
# a regex substitution on v. large (multi MB) clipboards. | |
if len(text) <= REDUCE_LENGTH_THRESHOLD: | |
display_text = text | |
else: | |
num_significant_chars = 0 | |
for cut_pos, char in enumerate(text, start=1): | |
if not char.isspace(): | |
num_significant_chars += 1 | |
if num_significant_chars > DISPLAY_LENGTH: | |
break | |
display_text = text[:cut_pos] | |
# Keep only significant chars, neatly space delimited. | |
# Like isspace(), '\s' matches ALL Unicode whitespace. | |
display_text = re.sub(r"\s+", " ", display_text) | |
display_text = display_text.strip() | |
num_lines = text.count("\n") + 1 | |
if num_lines == 1: | |
if len(display_text) > DISPLAY_LENGTH: | |
cut_pos = DISPLAY_LENGTH - len(DOTS) | |
display_text = display_text[:cut_pos] + DOTS | |
elif num_lines > 1: | |
lines_str = " [{} lines]".format(num_lines) | |
if len(display_text) + len(lines_str) <= DISPLAY_LENGTH: | |
display_text = display_text + lines_str | |
else: | |
cut_pos = DISPLAY_LENGTH - len(lines_str) - len(DOTS) | |
display_text = display_text[:cut_pos] + DOTS + lines_str | |
return display_text | |
def get(self): | |
return self.storage | |
def delete_duplicates(self, text): | |
self.storage = [s for s in self.storage if s[1] != text] | |
def empty(self): | |
return len(self.storage) == 0 | |
g_clipboard_history = ClipboardHistory() | |
class ClipboardHistoryUpdater(sublime_plugin.EventListener): | |
""" | |
Listens for ST command events and adds the clipboard's content to | |
the clipboard history when a clipboard altering command is run. | |
""" | |
def on_post_text_command(self, view, command_name, args): | |
# Include my copy_and_cut_text plugins so that text | |
# cut or copied with them gets added to the history. | |
clipboard_commands = ["copy", "cut", | |
"copy_and_cut_text_copy_line", | |
"copy_and_cut_text_copy_file", | |
"copy_and_cut_text_cut_line", | |
"copy_and_cut_text_cut_file", | |
"copy_and_cut_text_copy_current_word"] | |
if command_name in clipboard_commands: | |
g_clipboard_history.push_text(sublime.get_clipboard()) | |
class PasteFromHistoryEnhancedCommand(sublime_plugin.TextCommand): | |
""" | |
Displays the clipboard history in an overlay and pastes the selected item. | |
""" | |
def run(self, edit): | |
if g_clipboard_history.empty(): | |
message = "The clipboard history is empty" | |
self.view.window().status_message(message) | |
return | |
paste_list = g_clipboard_history.get() | |
items = [item[0] for item in paste_list] | |
self.view.window().show_quick_panel(items, self.on_done, | |
sublime.MONOSPACE_FONT) | |
def on_done(self, index): | |
if index == -1: | |
return | |
paste_text = g_clipboard_history.get()[index][1] | |
# Move paste_text to the top of history. | |
g_clipboard_history.push_text(paste_text) | |
sublime.set_clipboard(paste_text) | |
self.view.run_command("paste") | |
# If necessary restore the focus to the view the plugin was | |
# launched from. When run from a widget, i.e. the console or | |
# an input panel, the active text buffer gets automatically | |
# focused, this code restores the focus to the correct view. | |
if self.view.window().active_view() != self.view: | |
self.view.window().focus_view(self.view) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment