diff --git a/main.py b/main.py index 2a4f2bd..d526446 100644 --- a/main.py +++ b/main.py @@ -11,22 +11,9 @@ from .plugin.core.session import session from .plugin.core.workspace import workspaces from .plugin.core.buffers import buffers from .plugin.text_listener import TEXT_LISTENER +from .plugin.input_handlers import SimpleListInput from .plugin import globals as g -# We import these just to showcase the commands available. -from .plugin.commands.client import CodempConnectCommand -from .plugin.commands.client import CodempDisconnectCommand -from .plugin.commands.client import CodempCreateWorkspaceCommand -from .plugin.commands.client import CodempDeleteWorkspaceCommand -from .plugin.commands.client import CodempJoinWorkspaceCommand -from .plugin.commands.client import CodempLeaveWorkspaceCommand -from .plugin.commands.client import CodempInviteToWorkspaceCommand - -from .plugin.commands.workspace import CodempCreateBufferCommand -from .plugin.commands.workspace import CodempDeleteBufferCommand -from .plugin.commands.workspace import CodempJoinBufferCommand -from .plugin.commands.workspace import CodempLeaveBufferCommand - from .plugin.quickpanel.qpbrowser import QPServerBrowser from .plugin.quickpanel.qpbrowser import QPWorkspaceBrowser @@ -55,7 +42,6 @@ def plugin_unloaded(): safe_listener_detach(TEXT_LISTENER) package_logger.removeHandler(handler) - def kill_all(): for ws in workspaces.lookup(): session.client.leave_workspace(ws.id) @@ -63,12 +49,18 @@ def kill_all(): session.stop() -def objects_from_view(view): - assert view.settings().get(g.CODEMP_VIEW_TAG, False) - buffid = str(view.settings().get(g.CODEMP_BUFFER_ID)) +def vbuff_form_view(view): + if not view.settings().get(g.CODEMP_VIEW_TAG, False): + raise ValueError("The view is not a Codemp Buffer.") + buffid = str(view.settings().get(g.CODEMP_BUFFER_ID)) vbuff = buffers.lookupId(buffid) + return vbuff + +def objects_from_view(view): + + vbuff = vbuff_form_view(view) vws = buffers.lookupParent(vbuff) win = workspaces.lookupParent(vws) @@ -83,6 +75,13 @@ class CodempBrowseWorkspaceCommand(sublime_plugin.WindowCommand): buffers = wks.handle.fetch_buffers() QPWorkspaceBrowser(self.window, workspace_id, buffers.wait()).run() + def input(self, args): + if "workspace_id" not in args: + wslist = session.client.active_workspaces() + return SimpleListInput( + ("workspace_id", wslist), + ) + class CodempBrowseServerCommand(sublime_plugin.WindowCommand): def is_enabled(self) -> bool: @@ -104,7 +103,7 @@ class CodempReplaceTextCommand(sublime_plugin.TextCommand): class CodempSyncBuffer(sublime_plugin.TextCommand): def run(self, edit): - buff = buffers.lookupId(self.view.settings().get(g.CODEMP_BUFFER_ID)) + buff = buffers.lookupId(str(self.view.settings().get(g.CODEMP_BUFFER_ID))) buff.sync(TEXT_LISTENER) @@ -114,9 +113,6 @@ class EventListener(sublime_plugin.EventListener): def on_exit(self): kill_all() - # client.disconnect() - # if client.driver is not None: - # client.driver.stop() def on_pre_close_window(self, window): for vws in workspaces.lookup(window): diff --git a/plugin/commands/client.py b/plugin/commands/client.py index be560e4..64b772d 100644 --- a/plugin/commands/client.py +++ b/plugin/commands/client.py @@ -1,5 +1,6 @@ import sublime import sublime_plugin + import logging import random @@ -27,6 +28,7 @@ class CodempConnectCommand(sublime_plugin.WindowCommand): ("password", "password?"), ) + if "password" not in args: return SimpleTextInput( ("password", "password?"), @@ -94,17 +96,16 @@ class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand): except Exception as e: logger.error(f"Could not join workspace '{workspace_id}': {e}") sublime.error_message(f"Could not join workspace '{workspace_id}'") - return + raise e logger.debug("Joined! Adding workspace to registry") - workspaces.add(ws) + workspaces.register(ws) # Leave Workspace Command class CodempLeaveWorkspaceCommand(sublime_plugin.WindowCommand): def is_enabled(self): - return session.is_active() and \ - len(workspaces.lookup(self.window)) > 0 + return session.is_active() and workspaces.hasactive() def input(self, args): if "workspace_id" not in args: @@ -123,7 +124,7 @@ class CodempLeaveWorkspaceCommand(sublime_plugin.WindowCommand): class CodempInviteToWorkspaceCommand(sublime_plugin.WindowCommand): def is_enabled(self) -> bool: - return session.is_active() and len(workspaces.lookup(self.window)) > 0 + return session.is_active() and workspaces.hasactive() > 0 def input(self, args): if "workspace_id" not in args: diff --git a/plugin/commands/workspace.py b/plugin/commands/workspace.py index 1e45924..8ac28fb 100644 --- a/plugin/commands/workspace.py +++ b/plugin/commands/workspace.py @@ -53,18 +53,6 @@ class CodempJoinBufferCommand(sublime_plugin.WindowCommand): except KeyError: pass - # # if doesn't exist in the workspace, ask for creation. - # if vws.handle.get_buffer(buffer_id) is None: - # if sublime.ok_cancel_dialog( - # f"There is no buffer named '{buffer_id}' in the workspace '{workspace_id}'.\n\ - # Do you want to create it?", - # ok_title="yes", title="Create Buffer?", - # ): - # sublime.run_command("codemp_create_buffer", { - # "workspace_id": workspace_id, - # "buffer_id": buffer_id - # }) - # now we can defer the attaching process logger.debug(f"attempting to attach to {buffer_id}...") ctl_promise = vws.handle.attach_buffer(buffer_id) @@ -80,12 +68,12 @@ class CodempJoinBufferCommand(sublime_plugin.WindowCommand): safe_listener_detach(TEXT_LISTENER) content_promise = buff_ctl.content() - vbuff = buffers.add(buff_ctl, vws) + vbuff = buffers.register(buff_ctl, vws) content = content_promise.wait() populate_view(vbuff.view, content) 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()) else: self.window.focus_view(vbuff.view) diff --git a/plugin/core/buffers.py b/plugin/core/buffers.py index 697bc8e..aea1e95 100644 --- a/plugin/core/buffers.py +++ b/plugin/core/buffers.py @@ -25,7 +25,7 @@ def bind_callback(v: sublime.View): multi_tryrecv_lock = threading.Lock() def _callback(bufctl: codemp.BufferController): - def _(): + def _innercb(): try: # change_id = v.change_id() change_id = None @@ -67,7 +67,7 @@ def bind_callback(v: sublime.View): if multi_tryrecv_lock.acquire(blocking=False): logger.debug("acquiring lock") - sublime.set_timeout(_) + sublime.set_timeout(_innercb) return _callback class BufferManager(): @@ -102,8 +102,8 @@ class BufferManager(): def sync(self, text_listener): promise = self.handle.content() def _(): - content = promise.wait() current_contents = get_contents(self.view) + content = promise.wait() if content == current_contents: return @@ -117,6 +117,14 @@ class BufferRegistry(): def __init__(self): self._buffers: bidict[BufferManager, WorkspaceManager] = bidict() + def __contains__(self, item: str): + try: self.lookupId(item) + except KeyError: return False + return True + + def hasactive(self): + return len(self._buffers.keys()) > 0 + def lookup(self, ws: Optional[WorkspaceManager] = None) -> list[BufferManager]: if not ws: return list(self._buffers.keys()) @@ -133,13 +141,16 @@ class BufferRegistry(): if not bfm: raise KeyError return bfm - def add(self, bhandle: codemp.BufferController, wsm: WorkspaceManager): + def register(self, bhandle: codemp.BufferController, wsm: WorkspaceManager): bid = bhandle.path() # tmpfile = os.path.join(wsm.rootdir, bid) # open(tmpfile, "a").close() win = sublime.active_window() view = win.open_file(bid) + while view.is_loading(): + pass # yes spinlock, fite me. + view.set_scratch(True) # view.retarget(tmpfile) view.settings().set(g.CODEMP_VIEW_TAG, True) diff --git a/plugin/core/workspace.py b/plugin/core/workspace.py index 5370b84..810c2c4 100644 --- a/plugin/core/workspace.py +++ b/plugin/core/workspace.py @@ -14,6 +14,8 @@ from codemp import Selection from .. import globals as g from ..utils import draw_cursor_region from ..utils import bidict + +from .session import session from .buffers import buffers logger = logging.getLogger(__name__) @@ -99,6 +101,14 @@ class WorkspaceRegistry(): def __init__(self) -> None: self._workspaces: bidict[WorkspaceManager, sublime.Window] = bidict() + def __contains__(self, item: str): + try: self.lookupId(item) + except KeyError: return False + return True + + def hasactive(self): + return len(session.client.active_workspaces()) > 0 + def lookup(self, w: Optional[sublime.Window] = None) -> list[WorkspaceManager]: if not w: return list(self._workspaces.keys()) @@ -115,7 +125,7 @@ class WorkspaceRegistry(): if not wsm: raise KeyError return wsm - def add(self, wshandle: codemp.Workspace) -> WorkspaceManager: + def register(self, wshandle: codemp.Workspace) -> WorkspaceManager: win = sublime.active_window() # tmpdir = tempfile.mkdtemp(prefix="codemp_") diff --git a/plugin/input_handlers.py b/plugin/input_handlers.py index 0ac57f8..82b4606 100644 --- a/plugin/input_handlers.py +++ b/plugin/input_handlers.py @@ -30,7 +30,7 @@ class SimpleTextInput(sublime_plugin.TextInputHandler): class SimpleListInput(sublime_plugin.ListInputHandler): - def __init__(self, *args: Tuple[str, Union["list[str]", str]]): + def __init__(self, *args: Tuple[str, Union[List[str], str]]): self.input, *self.next_inputs = args self.argname = self.input[0] self.list = self.input[1] diff --git a/plugin/quickpanel/qpbrowser.py b/plugin/quickpanel/qpbrowser.py index 253ad98..05bb080 100644 --- a/plugin/quickpanel/qpbrowser.py +++ b/plugin/quickpanel/qpbrowser.py @@ -17,7 +17,6 @@ def show_qp(window, choices, on_done, placeholder=''): window.show_quick_panel(choices, on_done, flags, placeholder=placeholder) sublime.set_timeout(_, 10) - class QPServerBrowser(): def __init__(self, window, host, raw_input_items): self.window = window @@ -55,36 +54,39 @@ class QPServerBrowser(): self.current_wid_selection = wid # self.select_workspace() def _(): - self.window.run_command( - "codemp_join_workspace", - {"workspace_id": self.current_wid_selection}) + if not wid in workspaces: + try: self.window.run_command( + "codemp_join_workspace", {"workspace_id": wid}) + except Exception as e: + return ws = workspaces.lookupId(wid) buffers = ws.handle.fetch_buffers() + QPWorkspaceBrowser(self.window, wid, buffers.wait()).run() sublime.set_timeout(_) logger.debug("exiting the server_broswer.") - def select_workspace(self): - assert self.current_wid_selection - actions = [ - qpi("Join", details=self.current_wid_selection, color=qpg.QP_COLOR_BLUISH, letter=qpg.QP_FORWARD), - # qpi("Join and open all", - # details="opens all buffer in the workspace", - # color=qpg.QP_COLOR_PINKISH, letter=qpg.QP_DETAILS), - qpi("Back", color=qpg.QP_COLOR_BLUISH, letter=qpg.QP_BACK) - ] - show_qp(self.window, actions, self.select_workspace_actions, self.qp_placeholder()) + # def select_workspace(self): + # assert self.current_wid_selection + # actions = [ + # qpi("Join", details=self.current_wid_selection, color=qpg.QP_COLOR_BLUISH, letter=qpg.QP_FORWARD), + # # qpi("Join and open all", + # # details="opens all buffer in the workspace", + # # color=qpg.QP_COLOR_PINKISH, letter=qpg.QP_DETAILS), + # qpi("Back", color=qpg.QP_COLOR_BLUISH, letter=qpg.QP_BACK) + # ] + # show_qp(self.window, actions, self.select_workspace_actions, self.qp_placeholder()) - def select_workspace_actions(self, index): - if index == -1: - return - elif index == 0: - self.window.run_command( - "codemp_join_workspace", - {"workspace_id": self.current_wid_selection}) - elif index == 1: - self.run() + # def select_workspace_actions(self, index): + # if index == -1: + # return + # elif index == 0: + # self.window.run_command( + # "codemp_join_workspace", + # {"workspace_id": self.current_wid_selection}) + # elif index == 1: + # self.run() def edit_server(self): @@ -168,7 +170,6 @@ class QPWorkspaceBrowser(): "buffer_id": bid }) - def edit_workspace(self): actions = [ qpi("Back", color=qpg.QP_COLOR_CYANISH, letter=qpg.QP_BACK), diff --git a/plugin/utils.py b/plugin/utils.py index 4f8ae27..e2fd018 100644 --- a/plugin/utils.py +++ b/plugin/utils.py @@ -58,7 +58,7 @@ def status_log(msg, popup=False): print("[codemp] {}".format(msg)) if popup: sublime.error_message(msg) - + def rowcol_to_region(view, start, end): a = view.text_point(start[0], start[1])