108 lines
3.1 KiB
Python
108 lines
3.1 KiB
Python
|
import sublime_plugin, sublime
|
||
|
|
||
|
class KillRing:
|
||
|
def __init__(self):
|
||
|
self.limit = 16
|
||
|
self.buffer = [None for i in xrange(self.limit)]
|
||
|
self.head = 0
|
||
|
self.len = 0
|
||
|
self.kill_points = []
|
||
|
self.kill_id = 0
|
||
|
|
||
|
def top(self):
|
||
|
return self.buffer[self.head]
|
||
|
|
||
|
def seal(self):
|
||
|
self.kill_points = []
|
||
|
self.kill_id = 0
|
||
|
|
||
|
def push(self, text):
|
||
|
self.head = (self.head + 1) % self.limit
|
||
|
self.buffer[self.head] = text
|
||
|
if self.len < self.limit:
|
||
|
self.len += 1
|
||
|
|
||
|
def add(self, view_id, text, regions, forward):
|
||
|
if view_id != self.kill_id:
|
||
|
# view has changed, ensure the last kill ring entry will not be
|
||
|
# appended to
|
||
|
self.seal()
|
||
|
|
||
|
begin_points = []
|
||
|
end_points = []
|
||
|
for r in regions:
|
||
|
begin_points.append(r.begin())
|
||
|
end_points.append(r.end())
|
||
|
|
||
|
if forward:
|
||
|
compare_points = begin_points
|
||
|
else:
|
||
|
compare_points = end_points
|
||
|
|
||
|
if compare_points == self.kill_points:
|
||
|
# Selection hasn't moved since the last kill, append/prepend the
|
||
|
# text to the current entry
|
||
|
if forward:
|
||
|
self.buffer[self.head] = self.buffer[self.head] + text
|
||
|
else:
|
||
|
self.buffer[self.head] = text + self.buffer[self.head]
|
||
|
else:
|
||
|
# Create a new entry in the kill ring for this text
|
||
|
self.push(text)
|
||
|
|
||
|
self.kill_points = begin_points
|
||
|
self.kill_id = view_id
|
||
|
|
||
|
def get(self, index):
|
||
|
return self.buffer[(self.head + index) % self.limit]
|
||
|
|
||
|
def __len__(self):
|
||
|
return self.len
|
||
|
|
||
|
kill_ring = KillRing()
|
||
|
|
||
|
class YankCommand(sublime_plugin.TextCommand):
|
||
|
def run(self, edit):
|
||
|
kill_ring.seal()
|
||
|
text = kill_ring.top()
|
||
|
|
||
|
lines = text.splitlines()
|
||
|
|
||
|
regions = [r for r in self.view.sel()]
|
||
|
regions.reverse()
|
||
|
|
||
|
if len(regions) > 1 and len(regions) == len(lines):
|
||
|
# insert one line from the top of the kill ring at each
|
||
|
# corresponding selection
|
||
|
for i in xrange(len(regions)):
|
||
|
s = regions[i]
|
||
|
line = lines[i]
|
||
|
num = self.view.insert(edit, s.begin(), line)
|
||
|
self.view.erase(edit, sublime.Region(s.begin() + num,
|
||
|
s.end() + num))
|
||
|
else:
|
||
|
# insert the top of the kill ring at each selection
|
||
|
for s in regions:
|
||
|
num = self.view.insert(edit, s.begin(), text)
|
||
|
self.view.erase(edit, sublime.Region(s.begin() + num,
|
||
|
s.end() + num))
|
||
|
|
||
|
def is_enabled(self):
|
||
|
return len(kill_ring) > 0
|
||
|
|
||
|
class AddToKillRingCommand(sublime_plugin.TextCommand):
|
||
|
def run(self, edit, forward):
|
||
|
delta = 1
|
||
|
if not forward:
|
||
|
delta = -1
|
||
|
|
||
|
text = []
|
||
|
regions = []
|
||
|
for s in self.view.sel():
|
||
|
if s.empty():
|
||
|
s = sublime.Region(s.a, s.a + delta)
|
||
|
text.append(self.view.substr(s))
|
||
|
regions.append(s)
|
||
|
|
||
|
kill_ring.add(self.view.id(), "\n".join(text), regions, forward)
|