codemp-sublime/main.py
2024-11-19 19:46:44 +01:00

219 lines
7.5 KiB
Python

# 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.utils import some
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))
vbuff = buffers.lookupId(buffid)
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.config.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 CodempSyncBuffer(sublime_plugin.TextCommand):
def run(self, edit):
buff = buffers.lookupId(self.view.settings().get(g.CODEMP_BUFFER_ID))
buff.sync(TEXT_LISTENER)
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):
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 KeyError:
logger.error(f"Could not find buffers associated with the view {self.view}.\
Removing 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):
logger.debug(f"'{self.view}' view activated!")
safe_listener_attach(TEXT_LISTENER, self.view.buffer()) # pyright: ignore
def on_deactivated(self):
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")
safe_listener_detach(TEXT_LISTENER) # pyright: ignore
try:
bid = str(self.view.settings().get(g.CODEMP_BUFFER_ID))
vws = buffers.lookupParent(bid)
some(self.view.window()).run_command(
"codemp_leave_buffer",
{"workspace_id": vws.id, "buffer_id": bid})
except KeyError:
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:'