-
Notifications
You must be signed in to change notification settings - Fork 33
/
edit.py
143 lines (109 loc) · 3.52 KB
/
edit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# edit.py
# buffer editing for both ST2 and ST3 that "just works"
import inspect
import sublime
import sublime_plugin
try:
sublime.actualvim_edit_storage
except AttributeError:
sublime.actualvim_edit_storage = {}
def run_callback(func, *args, **kwargs):
spec = inspect.getfullargspec(func)
if spec.args or spec.varargs:
return func(*args, **kwargs)
else:
return func()
class EditFuture:
def __init__(self, func):
self.func = func
def resolve(self, view, edit):
return self.func(view, edit)
class EditStep:
def __init__(self, cmd, *args):
self.cmd = cmd
self.args = args
def run(self, view, edit):
if self.cmd == 'callback':
return run_callback(self.args[0], view, edit)
def insert(edit, pos, text):
pos = min(view.size(), pos)
view.insert(edit, pos, text)
funcs = {
'insert': insert,
'erase': view.erase,
'replace': view.replace,
}
func = funcs.get(self.cmd)
if func:
args = self.resolve_args(view, edit)
func(edit, *args)
def resolve_args(self, view, edit):
args = []
for arg in self.args:
if isinstance(arg, EditFuture):
arg = arg.resolve(view, edit)
args.append(arg)
return args
class Edit:
def __init__(self, view):
self.view = view
self.steps = []
def __nonzero__(self):
return bool(self.steps)
@classmethod
def future(cls, func):
return EditFuture(func)
@classmethod
def defer(cls, view, func):
with Edit(view) as edit:
edit.callback(func)
def step(self, cmd, *args):
step = EditStep(cmd, *args)
self.steps.append(step)
def insert(self, point, string):
self.step('insert', point, string)
def erase(self, region):
self.step('erase', region)
def replace(self, region, string):
self.step('replace', region, string)
def callback(self, func):
self.step('callback', func)
def reselect(self, pos):
def select(view, edit):
region = pos
if hasattr(pos, '__call__'):
region = run_callback(pos, view)
if isinstance(region, int):
region = sublime.Region(region, region)
elif isinstance(region, (tuple, list)):
region = sublime.Region(*region)
view.sel().clear()
view.sel().add(region)
view.show(region, False)
self.callback(select)
def append(self, text):
self.insert(self.view.size(), text)
def run(self, view, edit):
read_only = False
if view.is_read_only():
read_only = True
view.set_read_only(False)
for step in self.steps:
step.run(view, edit)
if read_only:
view.set_read_only(True)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
view = self.view
if sublime.version().startswith('2'):
edit = view.begin_edit()
self.run(edit)
view.end_edit(edit)
else:
key = str(hash(tuple(self.steps)))
sublime.actualvim_edit_storage[key] = self.run
view.run_command('apply_actualvim_edit', {'key': key})
class apply_actualvim_edit(sublime_plugin.TextCommand):
def run(self, edit, key):
sublime.actualvim_edit_storage.pop(key)(self.view, edit)