fix: switched to the proper config

chore: switched to bundled codemp library in sublime
fix: fixed circular dependency
contd: small step towards rewrite.
This commit is contained in:
cschen 2024-09-28 19:55:20 +02:00
parent 89df99b850
commit 74f386e819
8 changed files with 39 additions and 148 deletions

View file

@ -3,11 +3,11 @@ import sublime
import sublime_plugin import sublime_plugin
import logging import logging
from lib import codemp import codemp
from .plugin.utils import safe_listener_detach from .plugin.utils import safe_listener_detach
from .plugin.core.session import session from .plugin.core.session import session
from .plugin.core.registry import workspaces from .plugin.core.workspace import workspaces
from .plugin.core.registry import buffers from .plugin.core.buffers import buffers
from .plugin.commands.client import CodempConnectCommand from .plugin.commands.client import CodempConnectCommand
from .plugin.commands.client import CodempDisconnectCommand from .plugin.commands.client import CodempDisconnectCommand

View file

@ -3,10 +3,10 @@ import sublime_plugin
import logging import logging
import random import random
from ...lib import codemp import codemp
from ..core.session import session from ..core.session import session
from ..core.registry import workspaces from ..core.workspace import workspaces
from ..core.registry import buffers from ..core.buffers import buffers
from input_handlers import SimpleTextInput from input_handlers import SimpleTextInput
from input_handlers import SimpleListInput from input_handlers import SimpleListInput
@ -14,14 +14,13 @@ from input_handlers import SimpleListInput
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class CodempConnectCommand(sublime_plugin.WindowCommand): class CodempConnectCommand(sublime_plugin.WindowCommand):
def run(self, server_host, user_name, password): # pyright: ignore[reportIncompatibleMethodOverride] def run(self, server_host, user_name, password): # pyright: ignore[reportIncompatibleMethodOverride]
def _(): def _():
try: try:
config = codemp.get_default_config() config = codemp.Config(
config.host = server_host username = user_name,
config.username = user_name password = password,
config.password = password host = server_host)
session.connect(config) session.connect(config)
except Exception as e: except Exception as e:
sublime.error_message( sublime.error_message(
@ -72,15 +71,14 @@ class CodempDisconnectCommand(sublime_plugin.WindowCommand):
# Join Workspace Command # Join Workspace Command
class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand): class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
return client.codemp is not None return session.is_active()
def run(self, workspace_id): # pyright: ignore[reportIncompatibleMethodOverride] def run(self, workspace_id): # pyright: ignore[reportIncompatibleMethodOverride]
assert client.codemp is not None
if workspace_id is None: if workspace_id is None:
return return
logger.info(f"Joining workspace: '{workspace_id}'...") logger.info(f"Joining workspace: '{workspace_id}'...")
promise = client.codemp.join_workspace(workspace_id) promise = session.client.join_workspace(workspace_id)
active_window = sublime.active_window() active_window = sublime.active_window()
def _(): def _():
@ -92,19 +90,15 @@ class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
) )
sublime.error_message(f"Could not join workspace '{workspace_id}'") sublime.error_message(f"Could not join workspace '{workspace_id}'")
return return
client.install_workspace(workspace, active_window) workspaces.add(workspace)
sublime.set_timeout_async(_) sublime.set_timeout_async(_)
# the else shouldn't really happen, and if it does, it should already be instantiated.
# ignore.
def input_description(self): def input_description(self):
return "Join:" return "Join:"
def input(self, args): def input(self, args):
assert client.codemp is not None
if "workspace_id" not in args: if "workspace_id" not in args:
list = client.codemp.list_workspaces(True, True) list = session.client.list_workspaces(True, True)
return SimpleListInput( return SimpleListInput(
("workspace_id", list.wait()), ("workspace_id", list.wait()),
) )

View file

@ -1,8 +1,8 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from .workspace import WorkspaceManager from .workspace import WorkspaceManager
from ...lib import codemp import codemp
import sublime import sublime
import os import os
@ -16,10 +16,10 @@ from ..utils import bidict
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def bind_buffer_manager(buff: BufferManager): def bind_callback(v: sublime.View):
def text_callback(bufctl: codemp.BufferController): def _callback(bufctl: codemp.BufferController):
def _(): def _():
change_id = buff.view.change_id() change_id = v.change_id()
while change := bufctl.try_recv().wait(): while change := bufctl.try_recv().wait():
logger.debug("received remote buffer change!") logger.debug("received remote buffer change!")
if change is None: if change is None:
@ -32,13 +32,13 @@ def bind_buffer_manager(buff: BufferManager):
# 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 buff.view.id() == g.ACTIVE_CODEMP_VIEW: if v.id() == g.ACTIVE_CODEMP_VIEW:
buff.view.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, # we need to go through a sublime text command, since the method,
# view.replace needs an edit token, that is obtained only when calling # view.replace needs an edit token, that is obtained only when calling
# a textcommand associated with a view. # a textcommand associated with a view.
buff.view.run_command( v.run_command(
"codemp_replace_text", "codemp_replace_text",
{ {
"start": change.start, "start": change.start,
@ -48,7 +48,7 @@ def bind_buffer_manager(buff: BufferManager):
}, # pyright: ignore }, # pyright: ignore
) )
sublime.set_timeout(_) sublime.set_timeout(_)
return text_callback return _callback
class BufferManager(): class BufferManager():
def __init__(self, handle: codemp.BufferController, v: sublime.View, filename: str): def __init__(self, handle: codemp.BufferController, v: sublime.View, filename: str):
@ -56,6 +56,7 @@ class BufferManager():
self.view: sublime.View = v self.view: sublime.View = v
self.id = self.handle.path() self.id = self.handle.path()
self.filename = filename self.filename = filename
self.handle.callback(bind_callback(self.view))
def __del__(self): def __del__(self):
logger.debug(f"dropping buffer {self.id}") logger.debug(f"dropping buffer {self.id}")
@ -80,7 +81,6 @@ class BufferManager():
def sync(self, text_listener): def sync(self, text_listener):
promise = self.handle.content() promise = self.handle.content()
def _(): def _():
content = promise.wait() content = promise.wait()
safe_listener_detach(text_listener) safe_listener_detach(text_listener)
@ -92,13 +92,13 @@ class BufferRegistry():
def __init__(self): def __init__(self):
self._buffers: bidict[BufferManager, WorkspaceManager] = bidict() self._buffers: bidict[BufferManager, WorkspaceManager] = bidict()
def lookup(self, ws: WorkspaceManager | None = None) -> list[BufferManager]: def lookup(self, ws: Optional[WorkspaceManager] = None) -> list[BufferManager]:
if not ws: if not ws:
return list(self._buffers.keys()) return list(self._buffers.keys())
bf = self._buffers.inverse.get(ws) bf = self._buffers.inverse.get(ws)
return bf if bf else [] return bf if bf else []
def lookupId(self, bid: str) -> BufferManager | None: def lookupId(self, bid: str) -> Optional[BufferManager]:
return next((bf for bf in self._buffers if bf.id == bid), None) return next((bf for bf in self._buffers if bf.id == bid), None)
def add(self, bhandle: codemp.BufferController, wsm: WorkspaceManager): def add(self, bhandle: codemp.BufferController, wsm: WorkspaceManager):
@ -115,17 +115,17 @@ class BufferRegistry():
view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]") view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]")
bfm = BufferManager(bhandle, view, tmpfile) bfm = BufferManager(bhandle, view, tmpfile)
self._buffers[bfm] = wsm
def remove(self, bf: BufferManager | str | None): def remove(self, bf: Optional[BufferManager | str]):
if isinstance(bf, str): if isinstance(bf, str):
bf = self.lookupId(bf) bf = self.lookupId(bf)
if not bf: return if not bf: return
del self._buffers[bf] del self._buffers[bf]
bf.view.close() bf.view.close()
buffers = BufferRegistry()

View file

@ -1,96 +0,0 @@
from __future__ import annotations
from typing import Optional
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..workspace.workspace import VirtualWorkspace
import sublime
import logging
from ..utils import bidict
logger = logging.getLogger(__name__)
class VirtualClient:
def __init__(self):
self.codemp: Optional[codemp.Client] = None
self.driver: Optional[codemp.Driver] = None
# bookkeeping corner
self._id2buffer: dict[str, VirtualBuffer] = {}
self._id2workspace: dict[str, VirtualWorkspace] = {}
self._view2buff: dict[sublime.View, VirtualBuffer] = {}
self._buff2workspace: bidict[VirtualBuffer, VirtualWorkspace] = bidict()
self._workspace2window: dict[VirtualWorkspace, sublime.Window] = {}
def disconnect(self):
if self.codemp is None:
return
logger.info("disconnecting from the current client")
# for each workspace tell it to clean up after itself.
for vws in self.all_workspaces():
self.uninstall_workspace(vws)
self.codemp.leave_workspace(vws.id)
self._id2workspace.clear()
self._id2buffer.clear()
self._buff2workspace.clear()
self._view2buff.clear()
self._workspace2window.clear()
if self.driver is not None:
self.driver.stop()
self.driver = None
self.codemp = None
def connect(self, host: str, user: str, password: str):
if self.codemp is not None:
logger.info("Disconnecting from previous client.")
return self.disconnect()
if self.driver is None:
self.driver = codemp.init()
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"
)
config = codemp.get_default_config()
config.username = user
config.host = host
config.password = password
self.codemp = codemp.connect(config).wait()
id = self.codemp.user_id()
logger.debug(f"Connected to '{host}' as user {user} (id: {id})")
def install_workspace(self, workspace: codemp.Workspace, window: sublime.Window):
vws = VirtualWorkspace(workspace, window)
self._workspace2window[vws] = window
self._id2workspace[vws.id] = vws
def uninstall_workspace(self, vws: VirtualWorkspace):
# we aim at dropping all references to the workspace
# as well as all the buffers associated with it.
# if we did a good job the dunder del method will kick
# and continue with the cleanup.
logger.info(f"Uninstalling workspace '{vws.id}'...")
del self._workspace2window[vws]
del self._id2workspace[vws.id]
for vbuff in self.all_buffers(vws):
self.unregister_buffer(vbuff)
vws.uninstall()
def workspaces_in_server(self):
return self.codemp.active_workspaces() if self.codemp else []
def user_id(self):
return self.codemp.user_id() if self.codemp else None
client = VirtualClient()

View file

@ -1,5 +0,0 @@
from .workspace import WorkspaceRegistry
from .buffers import BufferRegistry
workspaces = WorkspaceRegistry()
buffers = BufferRegistry()

View file

@ -1,5 +1,5 @@
import logging import logging
from ...lib import codemp import codemp
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -54,5 +54,4 @@ class SessionManager():
def drop_client(self): def drop_client(self):
self._client = None self._client = None
session = SessionManager() session = SessionManager()

View file

@ -3,7 +3,7 @@ from typing import Optional, Tuple
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from ...main import CodempClientTextChangeListener from ...main import CodempClientTextChangeListener
from ...lib import codemp import codemp
import sublime import sublime
import shutil import shutil
@ -13,7 +13,7 @@ import logging
from .. import globals as g from .. import globals as g
from ..utils import draw_cursor_region from ..utils import draw_cursor_region
from ..utils import bidict from ..utils import bidict
from ..core.registry import buffers from .buffers import buffers
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -64,11 +64,11 @@ class WorkspaceManager():
self.curctl: codemp.CursorController = self.handle.cursor() self.curctl: codemp.CursorController = self.handle.cursor()
self.rootdir: str = rootdir self.rootdir: str = rootdir
self.id: str = self.handle.id() self.id: str = self.handle.id()
self.curctl.callback(cursor_callback)
def __del__(self): def __del__(self):
logger.debug(f"dropping workspace {self.id}") logger.debug(f"dropping workspace {self.id}")
self.curctl.clear_callback() self.curctl.clear_callback()
self.curctl.stop()
for buff in self.handle.buffer_list(): for buff in self.handle.buffer_list():
if not self.handle.detach(buff): if not self.handle.detach(buff):
@ -76,9 +76,8 @@ class WorkspaceManager():
f"could not detach from '{buff}' for workspace '{self.id}'." f"could not detach from '{buff}' for workspace '{self.id}'."
) )
bfm = buffers.lookupId(buff) for bfm in buffers.lookup(self):
if bfm: buffers.remove(bfm)
buffers.remove(bfm)
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
@ -89,13 +88,13 @@ class WorkspaceRegistry():
def __init__(self) -> None: def __init__(self) -> None:
self._workspaces: bidict[WorkspaceManager, sublime.Window] = bidict() self._workspaces: bidict[WorkspaceManager, sublime.Window] = bidict()
def lookup(self, w: sublime.Window | None = None) -> list[WorkspaceManager]: def lookup(self, w: Optional[sublime.Window] = None) -> list[WorkspaceManager]:
if not w: if not w:
return list(self._workspaces.keys()) return list(self._workspaces.keys())
ws = self._workspaces.inverse.get(w) ws = self._workspaces.inverse.get(w)
return ws if ws else [] return ws if ws else []
def lookupId(self, wid: str) -> WorkspaceManager | None: def lookupId(self, wid: str) -> Optional[WorkspaceManager]:
return next((ws for ws in self._workspaces if ws.id == wid), None) return next((ws for ws in self._workspaces if ws.id == wid), None)
def add(self, wshandle: codemp.Workspace) -> WorkspaceManager: def add(self, wshandle: codemp.Workspace) -> WorkspaceManager:
@ -109,7 +108,7 @@ class WorkspaceRegistry():
self._workspaces[wm] = win self._workspaces[wm] = win
return wm return wm
def remove(self, ws: WorkspaceManager | str | None): def remove(self, ws: Optional[WorkspaceManager | str]):
if isinstance(ws, str): if isinstance(ws, str):
ws = self.lookupId(ws) ws = self.lookupId(ws)
@ -120,7 +119,7 @@ class WorkspaceRegistry():
del self._workspaces[ws] del self._workspaces[ws]
workspaces = WorkspaceRegistry()

View file