Middle button paste deleted text in Sublime 3

点点圈 提交于 2020-01-03 15:50:09

问题


(Note: This question is different from Move cursor on middle button paste in Sublime Text 3 )

I am using Sublime Text 3 on Linux (but it also applies to Sublime Text 2).

In both emacs and vim, it is possible to highlight some text (this copies it to the clipboard), delete the text, then paste it elsewhere with the middle mouse button. This is my usual workflow to move some text (select->delete->middleclick).

On Sublime however, it doesn't paste anything, i.e., the middle button paste functionality only works with non-deleted text, apparently. Does anyone know how to make it work with deleted text too?


回答1:


I've came with plugin like this:

import sublime, sublime_plugin
import re

class MyListener(sublime_plugin.EventListener):
  def __init__(self):
    sublime_plugin.EventListener.__init__(self)
    self.deleted = '' 
    self.mark_for_clear = ''
    self.clipboard_save = ''
    self.empty_matcher = re.compile('^\s+$')

  # Clear last deleted word if user made highlight of another one
  # Delete if you want to e.g delete one word and highlight another to replace
  def on_selection_modified(self, view):
    selected_text = view.substr(view.sel()[0])
    if self.mark_for_clear != '' and self.mark_for_clear != self.deleted:
      self.deleted = ''
      self.mark_for_clear = ''
    if len(selected_text) > 0 and not self.empty_matcher.match(selected_text):
      self.mark_for_clear = selected_text

  def on_text_command(self, view, name, args):
    # Save deleted word if command was deletion command
    if name in ['right_delete', 'left_delete']:
      self.deleted = view.substr(view.sel()[0])
      #print("Deleted: %s " % self.deleted)
    # Propagate saved deleted word to clipboard and change command to
    # standard paste (we can only control standard paste clipboard)
    if name == "paste_selection_clipboard" and len(self.deleted) > 0:
      #print("Pasting:%s" % self.deleted)
      self.clipboard_save = sublime.get_clipboard()
      sublime.set_clipboard(self.deleted)
      # Comment line below to enable multiple middle-click pasting of deleted words:
      self.deleted = ''  
      return("paste", 'HackedByAlkuzad')

  # If we are after paste_selection_clipboard command, return old clipboard
  def on_post_text_command(self, view, name, args):
    if name == 'paste' and len(self.clipboard_save) > 0 and args == 'HackedByAlkuzad':
      sublime.set_clipboard(self.clipboard_save)
      self.clipboard_save = ''

This plugin will detect delete comamnd (right = delete, left = backspace) and copy deleted content to memory. Then if user uses middle-click paste it replaces clipboard with deleted content and pastes it. After paste it restores saved clipboard.

I assumed that the copy from deletion should work on empty space (ST does not have insert mode without Vintage). To change that behaviour you can delete on_selection_modified function to stop checking for that explictly, however highlighting the new word will not copy it to middle-button clipboard.

Edit: Version for system-wide clipboard using Linux xclip (taken from pyperclip)

import sublime, sublime_plugin
import re
from subprocess import Popen, PIPE, check_call, CalledProcessError

class DeletedToClipboard(sublime_plugin.EventListener):
  empty_matcher = re.compile('^\s*$')

  def __init__(self):
    sublime_plugin.EventListener.__init__(self)
    try:
      check_call(['which','xclip'])
    except CalledProcessError:
      sublime.error_message("You have to have xclip installed to use DeletedToClipboard")

  @classmethod
  def _is_empty(cls, text):
    return len(text) <= 0 or cls.empty_matcher.match(text) 
        # Thanks pyperclip :)
  @classmethod
  def _copy_to_system_clipboard(cls, text):
    # try secondary if not working
    p = Popen(['xclip', '-selection', 'primary'], stdin=PIPE)
    try:
        p.communicate(input=bytes(text, 'utf-8'))
    except Exception as e:
      print("Error on paste to clipboard, is xclip installed ? \n{}".format(e))

  def on_text_command(self, view, name, args):
    # Save deleted word if command was deletion command and selected text was not empty
     if name in ['right_delete', 'left_delete']:
      deleted = []
      for region in view.sel():
        text = view.substr(region)
        if not DeletedToClipboard._is_empty(text):
          deleted.append(text)
      if deleted != []:
        self._copy_to_system_clipboard("\n".join(deleted))


来源:https://stackoverflow.com/questions/31251817/middle-button-paste-deleted-text-in-sublime-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!