# pyright: reportIncompatibleMethodOverride=false import sublime import sublime_plugin import logging import codemp from .plugin.utils import safe_listener_detach from .plugin.utils import safe_listener_attach 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 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 LOG_LEVEL = logging.DEBUG handler = logging.StreamHandler() handler.setFormatter( logging.Formatter( fmt="<{thread}/{threadName}> {levelname} [{name} :: {funcName}] {message}", style="{", ) ) package_logger = logging.getLogger(__package__) package_logger.setLevel(LOG_LEVEL) package_logger.propagate = False logger = logging.getLogger(__name__) # Initialisation and Deinitialisation ############################################################################## def plugin_loaded(): package_logger.addHandler(handler) logger.debug("plugin loaded") def plugin_unloaded(): logger.debug("unloading") safe_listener_detach(TEXT_LISTENER) package_logger.removeHandler(handler) def kill_all(): for ws in workspaces.lookup(): session.client.leave_workspace(ws.id) workspaces.remove(ws) 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)) try: vbuff = buffers.lookupId(buffid) except KeyError: logger.error("we couldn't find the matching buffer or workspace!") raise ValueError vws = buffers.lookupParent(vbuff) win = workspaces.lookupParent(vws) return win, vws, vbuff class CodempBrowseWorkspaceCommand(sublime_plugin.WindowCommand): def is_enabled(self) -> bool: return session.is_active() def run(self, workspace_id): wks = workspaces.lookupId(workspace_id) buffers = wks.handle.fetch_buffers() QPWorkspaceBrowser(self.window, workspace_id, buffers.wait()).run() class CodempBrowseServerCommand(sublime_plugin.WindowCommand): def is_enabled(self) -> bool: return session.is_active() def run(self): wks = session.get_workspaces() QPServerBrowser(self.window, session.host, wks).run() class CodempReplaceTextCommand(sublime_plugin.TextCommand): def run(self, edit, start, end, content, change_id): # 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) self.view.replace(edit, region, content) class EventListener(sublime_plugin.EventListener): def is_enabled(self): return session.is_active() def on_exit(self): kill_all() # client.disconnect() # if client.driver is not None: # client.driver.stop() def on_pre_close_window(self, window): assert session.client is not None for vws in workspaces.lookup(window): sublime.run_command("codemp_leave_workspace", { "workspace_id": vws.id }) def on_text_command(self, view, command_name, args): if command_name == "codemp_replace_text": logger.info("got a codemp_replace_text command!") def on_post_text_command(self, view, command_name, args): if command_name == "codemp_replace_text": logger.info("got a codemp_replace_text command!") class CodempClientViewEventListener(sublime_plugin.ViewEventListener): @classmethod def is_applicable(cls, settings): return settings.get(g.CODEMP_VIEW_TAG) is not None @classmethod def applies_to_primary_view_only(cls): return False def on_selection_modified_async(self): region = self.view.sel()[0] start = self.view.rowcol(region.begin()) end = self.view.rowcol(region.end()) try: _, vws, vbuff = objects_from_view(self.view) except ValueError: logger.error(f"Could not find buffers associated with the view {self.view}.\ Removig the tag to disable event listener. Reattach.") # delete the tag so we disable this event listener on the view del self.view.settings()[g.CODEMP_VIEW_TAG] return vws.send_cursor(vbuff.id, start, end) logger.debug(f"selection modified! {vws.id}, {vbuff.id} - {start}, {end}") def on_activated(self): global TEXT_LISTENER logger.debug(f"'{self.view}' view activated!") safe_listener_attach(TEXT_LISTENER, self.view.buffer()) # pyright: ignore def on_deactivated(self): global TEXT_LISTENER logger.debug(f"'{self.view}' view deactivated!") safe_listener_detach(TEXT_LISTENER) # pyright: ignore def on_pre_close(self): if self.view == sublime.active_window().active_view(): logger.debug("closing active view") global TEXT_LISTENER safe_listener_detach(TEXT_LISTENER) # pyright: ignore try: _, vws, vbuff = objects_from_view(self.view) buffers.remove(vbuff) except ValueError: return def on_text_command(self, command_name, args): if command_name == "codemp_replace_text": logger.info("got a codemp_replace_text command! but in the view listener") def on_post_text_command(self, command_name, args): if command_name == "codemp_replace_text": logger.info("got a codemp_replace_text command! but in the view listener") # Next TODO: # Server configurations: # - where do we store it? # - TOML? yes probably toml # * Quickpanel for connecting with stuff. # * Quickpanel for browsing the servers # * Move all "server actions" like, create, delete, rename etc. as quickpanel actions. (See SFTP plugin.) # * make panel for notifications! # * make panel for errors and logging! # Proxy Commands ( NOT USED, left just in case we need it again. ) ############################################################################# # class ProxyCodempShareCommand(sublime_plugin.WindowCommand): # # on_window_command, does not trigger when called from the command palette # # See: https://github.com/sublimehq/sublime_text/issues/2234 # def run(self, **kwargs): # self.window.run_command("codemp_share", kwargs) # # def input(self, args): # if 'sublime_buffer' not in args: # return SublimeBufferPathInputHandler() # # def input_description(self): # return 'Share Buffer:'