mirror of
https://github.com/hexedtech/codemp-sublime.git
synced 2024-11-22 06:44:48 +01:00
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:
parent
89df99b850
commit
74f386e819
8 changed files with 39 additions and 148 deletions
6
main.py
6
main.py
|
@ -3,11 +3,11 @@ import sublime
|
|||
import sublime_plugin
|
||||
import logging
|
||||
|
||||
from lib import codemp
|
||||
import codemp
|
||||
from .plugin.utils import safe_listener_detach
|
||||
from .plugin.core.session import session
|
||||
from .plugin.core.registry import workspaces
|
||||
from .plugin.core.registry import buffers
|
||||
from .plugin.core.workspace import workspaces
|
||||
from .plugin.core.buffers import buffers
|
||||
|
||||
from .plugin.commands.client import CodempConnectCommand
|
||||
from .plugin.commands.client import CodempDisconnectCommand
|
||||
|
|
|
@ -3,10 +3,10 @@ import sublime_plugin
|
|||
import logging
|
||||
import random
|
||||
|
||||
from ...lib import codemp
|
||||
import codemp
|
||||
from ..core.session import session
|
||||
from ..core.registry import workspaces
|
||||
from ..core.registry import buffers
|
||||
from ..core.workspace import workspaces
|
||||
from ..core.buffers import buffers
|
||||
|
||||
from input_handlers import SimpleTextInput
|
||||
from input_handlers import SimpleListInput
|
||||
|
@ -14,14 +14,13 @@ from input_handlers import SimpleListInput
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CodempConnectCommand(sublime_plugin.WindowCommand):
|
||||
|
||||
def run(self, server_host, user_name, password): # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
def _():
|
||||
try:
|
||||
config = codemp.get_default_config()
|
||||
config.host = server_host
|
||||
config.username = user_name
|
||||
config.password = password
|
||||
config = codemp.Config(
|
||||
username = user_name,
|
||||
password = password,
|
||||
host = server_host)
|
||||
session.connect(config)
|
||||
except Exception as e:
|
||||
sublime.error_message(
|
||||
|
@ -72,15 +71,14 @@ class CodempDisconnectCommand(sublime_plugin.WindowCommand):
|
|||
# Join Workspace Command
|
||||
class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
|
||||
def is_enabled(self) -> bool:
|
||||
return client.codemp is not None
|
||||
return session.is_active()
|
||||
|
||||
def run(self, workspace_id): # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
assert client.codemp is not None
|
||||
if workspace_id is None:
|
||||
return
|
||||
|
||||
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()
|
||||
|
||||
def _():
|
||||
|
@ -92,19 +90,15 @@ class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
|
|||
)
|
||||
sublime.error_message(f"Could not join workspace '{workspace_id}'")
|
||||
return
|
||||
client.install_workspace(workspace, active_window)
|
||||
|
||||
workspaces.add(workspace)
|
||||
sublime.set_timeout_async(_)
|
||||
# the else shouldn't really happen, and if it does, it should already be instantiated.
|
||||
# ignore.
|
||||
|
||||
def input_description(self):
|
||||
return "Join:"
|
||||
|
||||
def input(self, args):
|
||||
assert client.codemp is not None
|
||||
if "workspace_id" not in args:
|
||||
list = client.codemp.list_workspaces(True, True)
|
||||
list = session.client.list_workspaces(True, True)
|
||||
return SimpleListInput(
|
||||
("workspace_id", list.wait()),
|
||||
)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from .workspace import WorkspaceManager
|
||||
from ...lib import codemp
|
||||
import codemp
|
||||
|
||||
import sublime
|
||||
import os
|
||||
|
@ -16,10 +16,10 @@ from ..utils import bidict
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def bind_buffer_manager(buff: BufferManager):
|
||||
def text_callback(bufctl: codemp.BufferController):
|
||||
def bind_callback(v: sublime.View):
|
||||
def _callback(bufctl: codemp.BufferController):
|
||||
def _():
|
||||
change_id = buff.view.change_id()
|
||||
change_id = v.change_id()
|
||||
while change := bufctl.try_recv().wait():
|
||||
logger.debug("received remote buffer change!")
|
||||
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.
|
||||
# We are not listening on it. Otherwise, interrupt the listening
|
||||
# to avoid echoing back the change just received.
|
||||
if buff.view.id() == g.ACTIVE_CODEMP_VIEW:
|
||||
buff.view.settings()[g.CODEMP_IGNORE_NEXT_TEXT_CHANGE] = True
|
||||
if v.id() == g.ACTIVE_CODEMP_VIEW:
|
||||
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.
|
||||
buff.view.run_command(
|
||||
v.run_command(
|
||||
"codemp_replace_text",
|
||||
{
|
||||
"start": change.start,
|
||||
|
@ -48,7 +48,7 @@ def bind_buffer_manager(buff: BufferManager):
|
|||
}, # pyright: ignore
|
||||
)
|
||||
sublime.set_timeout(_)
|
||||
return text_callback
|
||||
return _callback
|
||||
|
||||
class BufferManager():
|
||||
def __init__(self, handle: codemp.BufferController, v: sublime.View, filename: str):
|
||||
|
@ -56,6 +56,7 @@ class BufferManager():
|
|||
self.view: sublime.View = v
|
||||
self.id = self.handle.path()
|
||||
self.filename = filename
|
||||
self.handle.callback(bind_callback(self.view))
|
||||
|
||||
def __del__(self):
|
||||
logger.debug(f"dropping buffer {self.id}")
|
||||
|
@ -80,7 +81,6 @@ class BufferManager():
|
|||
|
||||
def sync(self, text_listener):
|
||||
promise = self.handle.content()
|
||||
|
||||
def _():
|
||||
content = promise.wait()
|
||||
safe_listener_detach(text_listener)
|
||||
|
@ -92,13 +92,13 @@ class BufferRegistry():
|
|||
def __init__(self):
|
||||
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:
|
||||
return list(self._buffers.keys())
|
||||
bf = self._buffers.inverse.get(ws)
|
||||
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)
|
||||
|
||||
def add(self, bhandle: codemp.BufferController, wsm: WorkspaceManager):
|
||||
|
@ -115,17 +115,17 @@ class BufferRegistry():
|
|||
view.set_status(g.SUBLIME_STATUS_ID, "[Codemp]")
|
||||
|
||||
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):
|
||||
bf = self.lookupId(bf)
|
||||
|
||||
if not bf: return
|
||||
|
||||
del self._buffers[bf]
|
||||
bf.view.close()
|
||||
|
||||
|
||||
buffers = BufferRegistry()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -1,5 +0,0 @@
|
|||
from .workspace import WorkspaceRegistry
|
||||
from .buffers import BufferRegistry
|
||||
|
||||
workspaces = WorkspaceRegistry()
|
||||
buffers = BufferRegistry()
|
|
@ -1,5 +1,5 @@
|
|||
import logging
|
||||
from ...lib import codemp
|
||||
import codemp
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -54,5 +54,4 @@ class SessionManager():
|
|||
def drop_client(self):
|
||||
self._client = None
|
||||
|
||||
|
||||
session = SessionManager()
|
|
@ -3,7 +3,7 @@ from typing import Optional, Tuple
|
|||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ...main import CodempClientTextChangeListener
|
||||
from ...lib import codemp
|
||||
import codemp
|
||||
|
||||
import sublime
|
||||
import shutil
|
||||
|
@ -13,7 +13,7 @@ import logging
|
|||
from .. import globals as g
|
||||
from ..utils import draw_cursor_region
|
||||
from ..utils import bidict
|
||||
from ..core.registry import buffers
|
||||
from .buffers import buffers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -64,11 +64,11 @@ class WorkspaceManager():
|
|||
self.curctl: codemp.CursorController = self.handle.cursor()
|
||||
self.rootdir: str = rootdir
|
||||
self.id: str = self.handle.id()
|
||||
self.curctl.callback(cursor_callback)
|
||||
|
||||
def __del__(self):
|
||||
logger.debug(f"dropping workspace {self.id}")
|
||||
self.curctl.clear_callback()
|
||||
self.curctl.stop()
|
||||
|
||||
for buff in self.handle.buffer_list():
|
||||
if not self.handle.detach(buff):
|
||||
|
@ -76,9 +76,8 @@ class WorkspaceManager():
|
|||
f"could not detach from '{buff}' for workspace '{self.id}'."
|
||||
)
|
||||
|
||||
bfm = buffers.lookupId(buff)
|
||||
if bfm:
|
||||
buffers.remove(bfm)
|
||||
for bfm in buffers.lookup(self):
|
||||
buffers.remove(bfm)
|
||||
|
||||
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
|
||||
|
@ -89,13 +88,13 @@ class WorkspaceRegistry():
|
|||
def __init__(self) -> None:
|
||||
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:
|
||||
return list(self._workspaces.keys())
|
||||
ws = self._workspaces.inverse.get(w)
|
||||
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)
|
||||
|
||||
def add(self, wshandle: codemp.Workspace) -> WorkspaceManager:
|
||||
|
@ -109,7 +108,7 @@ class WorkspaceRegistry():
|
|||
self._workspaces[wm] = win
|
||||
return wm
|
||||
|
||||
def remove(self, ws: WorkspaceManager | str | None):
|
||||
def remove(self, ws: Optional[WorkspaceManager | str]):
|
||||
if isinstance(ws, str):
|
||||
ws = self.lookupId(ws)
|
||||
|
||||
|
@ -120,7 +119,7 @@ class WorkspaceRegistry():
|
|||
del self._workspaces[ws]
|
||||
|
||||
|
||||
|
||||
workspaces = WorkspaceRegistry()
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue