fix: attach listener upon creation to go around the on_activate event not firing on

a newly spawned view.

Former-commit-id: 078a306921278905a50fc97630012a06a00b0cd3
This commit is contained in:
cschen 2024-09-02 11:38:11 +02:00
parent 95694dc2ec
commit a481b79b76
3 changed files with 48 additions and 26 deletions

View file

@ -6,7 +6,7 @@ import logging
import codemp import codemp
from Codemp.src import globals as g from Codemp.src import globals as g
from Codemp.src.utils import populate_view from Codemp.src.utils import populate_view, safe_listener_attach, safe_listener_detach
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -66,7 +66,7 @@ class VirtualBuffer:
self.tmpfile = os.path.join(rootdir, self.id) self.tmpfile = os.path.join(rootdir, self.id)
open(self.tmpfile, "a").close() open(self.tmpfile, "a").close()
# self.view.set_scratch(True) self.view.set_scratch(True)
self.view.set_name(self.id) self.view.set_name(self.id)
self.view.retarget(self.tmpfile) self.view.retarget(self.tmpfile)
@ -74,13 +74,17 @@ class VirtualBuffer:
self.view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]") self.view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]")
s[g.CODEMP_BUFFER_TAG] = True s[g.CODEMP_BUFFER_TAG] = True
self.sync()
logger.info(f"registering a callback for buffer: {self.id}") logger.info(f"registering a callback for buffer: {self.id}")
self.buffctl.callback(make_bufferchange_cb(self)) self.buffctl.callback(make_bufferchange_cb(self))
self.isactive = True self.isactive = True
def __del__(self): def __del__(self):
logger.debug("__del__ buffer called.")
def __hash__(self) -> int:
return hash(self.id)
def uninstall(self):
logger.info(f"clearing a callback for buffer: {self.id}") logger.info(f"clearing a callback for buffer: {self.id}")
self.buffctl.clear_callback() self.buffctl.clear_callback()
self.buffctl.stop() self.buffctl.stop()
@ -96,15 +100,14 @@ class VirtualBuffer:
self.view.close(onclose) self.view.close(onclose)
def __hash__(self) -> int: def sync(self, text_listener):
return hash(self.id)
def sync(self):
promise = self.buffctl.content() promise = self.buffctl.content()
def defer_sync(promise): def defer_sync(promise):
content = promise.wait() content = promise.wait()
safe_listener_detach(text_listener)
populate_view(self.view, content) populate_view(self.view, content)
safe_listener_attach(text_listener, self.view.buffer())
sublime.set_timeout_async(lambda: defer_sync(promise)) sublime.set_timeout_async(lambda: defer_sync(promise))

View file

@ -21,8 +21,8 @@ logger = logging.getLogger(__name__)
# bidir: VirtualBuffer <-> VirtualWorkspace # bidir: VirtualBuffer <-> VirtualWorkspace
# bidir: VirtualBuffer <-> Sublime.View # bidir: VirtualBuffer <-> Sublime.View
# bidir: VirtualWorkspace <-> Sublime.Window # bidir: VirtualWorkspace <-> Sublime.Window
def log_async(msg): # def log_async(msg):
sublime.set_timeout_async(lambda: logger.log(logger.level, msg)) # sublime.set_timeout_async(lambda: logger.log(logger.level, msg))
class VirtualClient: class VirtualClient:
@ -36,11 +36,12 @@ class VirtualClient:
self._view2buff: dict[sublime.View, VirtualBuffer] = {} self._view2buff: dict[sublime.View, VirtualBuffer] = {}
self._buff2workspace: bidict[VirtualBuffer, VirtualWorkspace] = bidict() self._buff2workspace: bidict[VirtualBuffer, VirtualWorkspace] = bidict()
# self._workspace2window: bidict[VirtualWorkspace, sublime.Window] = bidict()
self._workspace2window: dict[VirtualWorkspace, sublime.Window] = bidict() self._workspace2window: dict[VirtualWorkspace, sublime.Window] = bidict()
def dump(self): def dump(self):
logger.debug("CLIENT STATUS:") logger.debug("CLIENT STATUS:")
logger.debug(f"codemp: {self.codemp is not None}")
logger.debug(f"drived: {self.driver is not None}")
logger.debug("WORKSPACES:") logger.debug("WORKSPACES:")
logger.debug(f"{self._id2workspace}") logger.debug(f"{self._id2workspace}")
logger.debug(f"{self._workspace2window}") logger.debug(f"{self._workspace2window}")
@ -103,6 +104,7 @@ class VirtualClient:
logger.info("disconnecting from the current client") logger.info("disconnecting from the current client")
# for each workspace tell it to clean up after itself. # for each workspace tell it to clean up after itself.
for vws in self.all_workspaces(): for vws in self.all_workspaces():
self.uninstall_workspace(vws)
self.codemp.leave_workspace(vws.id) self.codemp.leave_workspace(vws.id)
self._id2workspace.clear() self._id2workspace.clear()
@ -110,6 +112,9 @@ class VirtualClient:
self._buff2workspace.clear() self._buff2workspace.clear()
self._view2buff.clear() self._view2buff.clear()
self._workspace2window.clear() self._workspace2window.clear()
self.driver.stop()
self.driver = None
self.codemp = None self.codemp = None
def connect(self, host: str, user: str, password: str): def connect(self, host: str, user: str, password: str):
@ -119,7 +124,11 @@ class VirtualClient:
if self.driver is None: if self.driver is None:
self.driver = codemp.init() self.driver = codemp.init()
codemp.set_logger(log_async, False) logger.debug("registering logger callback...")
if not codemp.set_logger(lambda msg: logger.debug(msg), False):
logger.debug(
"could not register the logger... If reconnecting it's ok, the previous logger is still registered"
)
self.codemp = codemp.connect(host, user, password).wait() self.codemp = codemp.connect(host, user, password).wait()
id = self.codemp.user_id() id = self.codemp.user_id()
@ -140,7 +149,8 @@ class VirtualClient:
del self._id2workspace[vws.id] del self._id2workspace[vws.id]
for vbuff in self.all_buffers(vws): for vbuff in self.all_buffers(vws):
self.unregister_buffer(vbuff) self.unregister_buffer(vbuff)
del vws
vws.uninstall()
# self._buff2workspace.inverse_del(vws) - if we delete all straight # self._buff2workspace.inverse_del(vws) - if we delete all straight
# keys the last delete will remove also the empty key. # keys the last delete will remove also the empty key.

View file

@ -9,7 +9,7 @@ import logging
import codemp import codemp
from Codemp.src import globals as g from Codemp.src import globals as g
from Codemp.src.buffers import VirtualBuffer from Codemp.src.buffers import VirtualBuffer
from Codemp.src.utils import draw_cursor_region from Codemp.src.utils import draw_cursor_region, safe_listener_attach, sublime_plugin
from Codemp.src.utils import bidict from Codemp.src.utils import bidict
@ -51,7 +51,6 @@ class VirtualWorkspace:
self.codemp.fetch_buffers() self.codemp.fetch_buffers()
self.codemp.fetch_users() self.codemp.fetch_users()
self._buff2view: bidict[VirtualBuffer, sublime.View] = bidict()
self._id2buff: dict[str, VirtualBuffer] = {} self._id2buff: dict[str, VirtualBuffer] = {}
tmpdir = tempfile.mkdtemp(prefix="codemp_") tmpdir = tempfile.mkdtemp(prefix="codemp_")
@ -71,10 +70,25 @@ class VirtualWorkspace:
self.isactive = True self.isactive = True
def __del__(self): def __del__(self):
logger.debug("workspace destroyed!")
def __hash__(self) -> int:
# so we can use these as dict keys!
return hash(self.id)
def uninstall(self):
self.curctl.clear_callback() self.curctl.clear_callback()
self.isactive = False self.isactive = False
self.curctl.stop() self.curctl.stop()
for vbuff in self._id2buff.values():
vbuff.uninstall()
if not self.codemp.detach(vbuff.id):
logger.warning(
f"could not detach from '{vbuff.id}' for workspace '{self.id}'."
)
self._id2buff.clear()
proj: dict = self.window.project_data() # type:ignore proj: dict = self.window.project_data() # type:ignore
if proj is None: if proj is None:
raise raise
@ -91,34 +105,29 @@ class VirtualWorkspace:
logger.info(f"cleaning up virtual workspace '{self.id}'") logger.info(f"cleaning up virtual workspace '{self.id}'")
shutil.rmtree(self.rootdir, ignore_errors=True) shutil.rmtree(self.rootdir, ignore_errors=True)
if not all(self.codemp.detach(buff) for buff in self._id2buff.keys()):
logger.warning(
f"could not detach from all buffers for workspace '{self.id}'."
)
self._id2buff.clear()
def __hash__(self) -> int:
# so we can use these as dict keys!
return hash(self.id)
def all_buffers(self) -> list[VirtualBuffer]: def all_buffers(self) -> list[VirtualBuffer]:
return list(self._id2buff.values()) return list(self._id2buff.values())
def buff_by_id(self, id: str) -> Optional[VirtualBuffer]: def buff_by_id(self, id: str) -> Optional[VirtualBuffer]:
return self._id2buff.get(id) return self._id2buff.get(id)
def install_buffer(self, buff: codemp.BufferController) -> VirtualBuffer: def install_buffer(
self, buff: codemp.BufferController, listener: sublime_plugin.TextChangeListener
) -> VirtualBuffer:
logger.debug(f"installing buffer {buff.name()}") logger.debug(f"installing buffer {buff.name()}")
view = self.window.new_file() view = self.window.new_file()
vbuff = VirtualBuffer(buff, view, self.rootdir) vbuff = VirtualBuffer(buff, view, self.rootdir)
self._id2buff[vbuff.id] = vbuff self._id2buff[vbuff.id] = vbuff
vbuff.sync(listener)
return vbuff return vbuff
def uninstall_buffer(self, vbuff: VirtualBuffer): def uninstall_buffer(self, vbuff: VirtualBuffer):
del self._id2buff[vbuff.id] del self._id2buff[vbuff.id]
self.codemp.detach(vbuff.id) self.codemp.detach(vbuff.id)
vbuff.uninstall()
def send_cursor(self, id: str, start: Tuple[int, int], end: Tuple[int, int]): def send_cursor(self, id: str, start: Tuple[int, int], end: Tuple[int, int]):
# we can safely ignore the promise, we don't really care if everything # we can safely ignore the promise, we don't really care if everything