Skip to content

Commit

Permalink
Fix applying document edits by using regions added to the document
Browse files Browse the repository at this point in the history
  • Loading branch information
tomv564 committed Aug 16, 2017
1 parent 797b373 commit f3f1ace
Showing 1 changed file with 32 additions and 38 deletions.
70 changes: 32 additions & 38 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1690,8 +1690,11 @@ def run(self, changes):
view = self.window.open_file(path)
if view:
if view.is_loading():
# TODO: schedule
debug('view not ready', view)
# TODO: wait for event instead.
sublime.set_timeout_async(
lambda: view.run_command('apply_document_edit', {'changes': file_changes}),
500
)
else:
view.run_command('apply_document_edit',
{'changes': file_changes})
Expand All @@ -1701,43 +1704,34 @@ def run(self, changes):

class ApplyDocumentEditCommand(sublime_plugin.TextCommand):
def run(self, edit, changes):
changes.sort(key=lambda change: self.get_change_sortkey(change))
# per line, maintain a char offset
# if newline inserted, maintian a line offset
current_line = -1
char_offset = 0
for change in changes:
newText = change.get('newText')
# TODO create a Range type
start = change.get('range').get('start')
end = change.get('range').get('end')

# reset char offset on new lines
if start.get('line') != current_line:
current_line = start.get('line')
char_offset = 0

debug('char offset at', char_offset)

start_position = self.view.text_point(
start.get('line'), start.get('character'))
end_position = self.view.text_point(
end.get('line'), end.get('character'))
region = sublime.Region(start_position + char_offset, end_position + char_offset)
if region.empty():
self.view.insert(edit, start_position, newText)
char_offset += len(newText)
else:
if len(newText) > 0:
self.view.replace(edit, region, newText)
char_offset += (len(newText) - region.size())
else:
self.view.erase(edit, region)
char_offset -= region.size()
regions = list(self.create_region(change) for change in changes)
replacements = list(change.get('newText') for change in changes)

self.view.add_regions('lsp_edit', regions, "source.python")

index = 0
# use regions from view as they are correctly updated after edits.
for newText in replacements:
region = self.view.get_regions('lsp_edit')[index]
self.apply_change(region, newText, edit)
index += 1

def get_change_sortkey(self, change):
start = change.get('range').get('start')
return "{0:05d}-{1:05d}".format(start.get('line'), start.get('character'))
self.view.erase_regions('lsp_edit')

def create_region(self, change):
range = Range.from_lsp(change.get('range'))
start_position = self.view.text_point(*range.start)
end_position = self.view.text_point(*range.end)
return sublime.Region(start_position, end_position)

def apply_change(self, region, newText, edit):
if region.empty():
self.view.insert(edit, region.a, newText)
else:
if len(newText) > 0:
self.view.replace(edit, region, newText)
else:
self.view.erase(edit, region)


class CloseListener(sublime_plugin.EventListener):
Expand Down

0 comments on commit f3f1ace

Please sign in to comment.