disables using change_id() as it was introducing complications.

moved view population outside of buffer adding, but it is still broken.
This commit is contained in:
cschen 2024-11-19 19:50:31 +01:00
parent 904c27c6d5
commit 017f43a922
6 changed files with 64 additions and 43 deletions

View file

@ -94,9 +94,11 @@ class CodempBrowseServerCommand(sublime_plugin.WindowCommand):
class CodempReplaceTextCommand(sublime_plugin.TextCommand): class CodempReplaceTextCommand(sublime_plugin.TextCommand):
def run(self, edit, start, end, content, change_id): def run(self, edit, start, end, content, change_id = None):
# we modify the region to account for any change that happened in the mean time # we modify the region to account for any change that happened in the mean time
region = self.view.transform_region_from(sublime.Region(start, end), change_id) region = sublime.Region(start, end)
if change_id:
region = self.view.transform_region_from(sublime.Region(start, end), change_id)
self.view.replace(edit, region, content) self.view.replace(edit, region, content)
@ -155,7 +157,7 @@ class CodempClientViewEventListener(sublime_plugin.ViewEventListener):
return return
vws.send_cursor(vbuff.id, start, end) vws.send_cursor(vbuff.id, start, end)
logger.debug(f"selection modified! {vws.id}, {vbuff.id} - {start}, {end}") # logger.debug(f"selection modified! {vws.id}, {vbuff.id} - {start}, {end}")
def on_activated(self): def on_activated(self):
logger.debug(f"'{self.view}' view activated!") logger.debug(f"'{self.view}' view activated!")

View file

@ -7,7 +7,7 @@ from ..core.workspace import workspaces
from ..core.buffers import buffers from ..core.buffers import buffers
from ..text_listener import TEXT_LISTENER from ..text_listener import TEXT_LISTENER
from ..utils import safe_listener_attach, safe_listener_detach from ..utils import safe_listener_attach, safe_listener_detach, populate_view
from ..input_handlers import SimpleListInput, SimpleTextInput from ..input_handlers import SimpleListInput, SimpleTextInput
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -67,11 +67,11 @@ class CodempJoinBufferCommand(sublime_plugin.WindowCommand):
# now we can defer the attaching process # now we can defer the attaching process
logger.debug(f"attempting to attach to {buffer_id}...") logger.debug(f"attempting to attach to {buffer_id}...")
promise = vws.handle.attach_buffer(buffer_id) ctl_promise = vws.handle.attach_buffer(buffer_id)
def _(): def _():
try: try:
buff_ctl = promise.wait() buff_ctl = ctl_promise.wait()
logger.debug("attach successfull!") logger.debug("attach successfull!")
except Exception as e: except Exception as e:
logging.error(f"error when attaching to buffer '{id}':\n\n {e}") logging.error(f"error when attaching to buffer '{id}':\n\n {e}")
@ -79,8 +79,11 @@ class CodempJoinBufferCommand(sublime_plugin.WindowCommand):
return return
safe_listener_detach(TEXT_LISTENER) safe_listener_detach(TEXT_LISTENER)
content_promise = buff_ctl.content()
vbuff = buffers.add(buff_ctl, vws) vbuff = buffers.add(buff_ctl, vws)
content = content_promise.wait()
populate_view(vbuff.view, content)
if self.window.active_view() == vbuff.view: if self.window.active_view() == vbuff.view:
# if view is already active focusing it won't trigger `on_activate`. # if view is already active focusing it won't trigger `on_activate`.
safe_listener_attach(TEXT_LISTENER, vbuff.view.buffer()) safe_listener_attach(TEXT_LISTENER, vbuff.view.buffer())
@ -115,8 +118,8 @@ class CodempLeaveBufferCommand(sublime_plugin.WindowCommand):
buffers.lookupId(buffer_id) buffers.lookupId(buffer_id)
vws = workspaces.lookupId(workspace_id) vws = workspaces.lookupId(workspace_id)
except KeyError: except KeyError:
sublime.error_message(f"You are not attached to the buffer '{id}'") sublime.error_message(f"You are not attached to the buffer '{buffer_id}'")
logging.warning(f"You are not attached to the buffer '{id}'") logging.warning(f"You are not attached to the buffer '{buffer_id}'")
return return
if not vws.handle.get_buffer(buffer_id): if not vws.handle.get_buffer(buffer_id):

View file

@ -7,10 +7,12 @@ if TYPE_CHECKING:
import sublime import sublime
import os import os
import logging import logging
import threading
from codemp import TextChange from codemp import TextChange
from .. import globals as g from .. import globals as g
from ..utils import populate_view from ..utils import populate_view
from ..utils import get_contents
from ..utils import safe_listener_attach from ..utils import safe_listener_attach
from ..utils import safe_listener_detach from ..utils import safe_listener_detach
from ..utils import bidict from ..utils import bidict
@ -18,44 +20,54 @@ from ..utils import bidict
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def bind_callback(v: sublime.View): def bind_callback(v: sublime.View):
# we need this lock to prevent multiple instance of try_recv() to spin up
# which would cause out of order insertion of changes.
multi_tryrecv_lock = threading.Lock()
def _callback(bufctl: codemp.BufferController): def _callback(bufctl: codemp.BufferController):
def _(): def _():
change_id = v.change_id() try:
while buffup := bufctl.try_recv().wait(): # change_id = v.change_id()
logger.debug("received remote buffer change!") change_id = None
if buffup is None: while buffup := bufctl.try_recv().wait():
break logger.debug("received remote buffer change!")
if buffup is None:
break
if buffup.change.is_empty(): if buffup.change.is_empty():
logger.debug("change is empty. skipping.") logger.debug("change is empty. skipping.")
continue continue
# In case a change arrives to a background buffer, just apply it. # In case a change arrives to a background buffer, just apply it.
# We are not listening on it. Otherwise, interrupt the listening # We are not listening on it. Otherwise, interrupt the listening
# to avoid echoing back the change just received. # to avoid echoing back the change just received.
if v == sublime.active_window().active_view(): if v == sublime.active_window().active_view():
v.settings()[g.CODEMP_IGNORE_NEXT_TEXT_CHANGE] = True v.settings()[g.CODEMP_IGNORE_NEXT_TEXT_CHANGE] = True
# we need to go through a sublime text command, since the method,
# view.replace needs an edit token, that is obtained only when calling
# a textcommand associated with a view.
# we need to go through a sublime text command, since the method,
# view.replace needs an edit token, that is obtained only when calling
# a textcommand associated with a view.
try:
change = buffup.change change = buffup.change
v.run_command( v.run_command(
"codemp_replace_text", "codemp_replace_text",
{ {
"start": change.start, "start": change.start_idx,
"end": change.end, "end": change.end_idx,
"content": change.content, "content": change.content,
"change_id": change_id, "change_id": change_id,
}, # pyright: ignore }, # pyright: ignore
) )
except Exception as e:
raise e
bufctl.ack(buffup.version) bufctl.ack(buffup.version)
sublime.set_timeout(_) except Exception as e:
raise e
finally:
logger.debug("releasing lock")
multi_tryrecv_lock.release()
if multi_tryrecv_lock.acquire(blocking=False):
logger.debug("acquiring lock")
sublime.set_timeout(_)
return _callback return _callback
class BufferManager(): class BufferManager():
@ -78,11 +90,11 @@ class BufferManager():
# sequential indexing, assuming the changes are applied in the order they are received. # sequential indexing, assuming the changes are applied in the order they are received.
for change in changes: for change in changes:
region = sublime.Region(change.a.pt, change.b.pt) region = sublime.Region(change.a.pt, change.b.pt)
logger.debug( # logger.debug(
"sending txt change: Reg({} {}) -> '{}'".format( # "sending txt change: Reg({} {}) -> '{}'".format(
region.begin(), region.end(), change.str # region.begin(), region.end(), change.str
) # )
) # )
# we must block and wait the send request to make sure the change went through ok # we must block and wait the send request to make sure the change went through ok
self.handle.send(TextChange(start=region.begin(), end=region.end(), content=change.str)) self.handle.send(TextChange(start=region.begin(), end=region.end(), content=change.str))
@ -91,9 +103,14 @@ class BufferManager():
promise = self.handle.content() promise = self.handle.content()
def _(): def _():
content = promise.wait() content = promise.wait()
current_contents = get_contents(self.view)
if content == current_contents:
return
safe_listener_detach(text_listener) safe_listener_detach(text_listener)
populate_view(self.view, content) populate_view(self.view, content)
safe_listener_attach(text_listener, self.view.buffer()) safe_listener_attach(text_listener, self.view.buffer())
sublime.status_message("Syncd contents.")
sublime.set_timeout_async(_) sublime.set_timeout_async(_)
class BufferRegistry(): class BufferRegistry():
@ -120,8 +137,7 @@ class BufferRegistry():
bid = bhandle.path() bid = bhandle.path()
# tmpfile = os.path.join(wsm.rootdir, bid) # tmpfile = os.path.join(wsm.rootdir, bid)
# open(tmpfile, "a").close() # open(tmpfile, "a").close()
content = bhandle.content()
win = sublime.active_window() win = sublime.active_window()
view = win.open_file(bid) view = win.open_file(bid)
view.set_scratch(True) view.set_scratch(True)
@ -129,7 +145,6 @@ class BufferRegistry():
view.settings().set(g.CODEMP_VIEW_TAG, True) view.settings().set(g.CODEMP_VIEW_TAG, True)
view.settings().set(g.CODEMP_BUFFER_ID, bid) view.settings().set(g.CODEMP_BUFFER_ID, bid)
view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]") view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]")
populate_view(view, content.wait())
tmpfile = "DISABLE" tmpfile = "DISABLE"
bfm = BufferManager(bhandle, view, tmpfile) bfm = BufferManager(bhandle, view, tmpfile)

View file

@ -51,7 +51,7 @@ def cursor_callback(ctl: codemp.CursorController):
def _(): def _():
while event := ctl.try_recv().wait(): while event := ctl.try_recv().wait():
if event is None: break if event is None: break
try: bfm = buffers.lookupId(event.sel.buffer) try: bfm = buffers.lookupId(event.sel.buffer)
except KeyError: continue except KeyError: continue

View file

@ -1,3 +1,4 @@
import sublime
import sublime_plugin import sublime_plugin
import logging import logging

View file

@ -88,7 +88,7 @@ def populate_view(view, content):
"start": 0, "start": 0,
"end": view.size(), "end": view.size(),
"content": content, "content": content,
"change_id": view.change_id(), "change_id": None,
}, },
) )
@ -105,7 +105,7 @@ def draw_cursor_region(view, start, end, user):
reg_flags = sublime.RegionFlags.DRAW_EMPTY reg_flags = sublime.RegionFlags.DRAW_EMPTY
user_hash = hash(user) user_hash = hash(user)
view.add_regions( view.add_regions(
f"{g.SUBLIME_REGIONS_PREFIX}-{user_hash}", f"{g.SUBLIME_REGIONS_PREFIX}-{user_hash}",
[reg], [reg],