fix: fixed the logger, spawning multiple instances.

Former-commit-id: 926b222cad75a036095ab23e5d11c439e0810b21
This commit is contained in:
cschen 2024-08-09 14:22:12 +02:00
parent 73e8e9c061
commit e334323304
3 changed files with 134 additions and 93 deletions

222
plugin.py
View file

@ -9,8 +9,7 @@ import random
# import importlib.util # import importlib.util
from .src.TaskManager import tm from .src.TaskManager import tm
from .src.client import client, VirtualClient from .src.client import logger, client, VirtualClient
from .src.client import CodempLogger
from .src.utils import status_log from .src.utils import status_log
from .src.utils import safe_listener_detach from .src.utils import safe_listener_detach
from .src.utils import safe_listener_attach from .src.utils import safe_listener_attach
@ -29,9 +28,6 @@ def plugin_loaded():
# instantiate and start a global asyncio event loop. # instantiate and start a global asyncio event loop.
# pass in the exit_handler coroutine that will be called upon relasing the event loop. # pass in the exit_handler coroutine that will be called upon relasing the event loop.
tm.acquire(disconnect_client) tm.acquire(disconnect_client)
logger = CodempLogger()
tm.dispatch(logger.log(), "codemp-logger") tm.dispatch(logger.log(), "codemp-logger")
TEXT_LISTENER = CodempClientTextChangeListener() TEXT_LISTENER = CodempClientTextChangeListener()
@ -50,6 +46,8 @@ async def disconnect_client():
for vws in client.workspaces.values(): for vws in client.workspaces.values():
vws.cleanup() vws.cleanup()
client.handle = None # drop
def plugin_unloaded(): def plugin_unloaded():
# releasing the runtime, runs the disconnect callback defined when acquiring the event loop. # releasing the runtime, runs the disconnect callback defined when acquiring the event loop.
@ -67,6 +65,7 @@ class EventListener(sublime_plugin.EventListener):
if client.active_workspace is None: if client.active_workspace is None:
return # nothing to do return # nothing to do
# deactivate all workspaces
client.make_active(None) client.make_active(None)
s = window.settings() s = window.settings()
@ -172,6 +171,9 @@ class CodempConnectCommand(sublime_plugin.WindowCommand):
def run(self, server_host, user_name, password="lmaodefaultpassword"): def run(self, server_host, user_name, password="lmaodefaultpassword"):
client.connect(server_host, user_name, password) client.connect(server_host, user_name, password)
def is_enabled(self) -> bool:
return client.handle is None
def input(self, args): def input(self, args):
if "server_host" not in args: if "server_host" not in args:
return ConnectServerHost() return ConnectServerHost()
@ -189,10 +191,13 @@ class ConnectServerHost(sublime_plugin.TextInputHandler):
def next_input(self, args): def next_input(self, args):
if "user_name" not in args: if "user_name" not in args:
return ConnectUserName() return ConnectUserName(args)
class ConnectUserName(sublime_plugin.TextInputHandler): class ConnectUserName(sublime_plugin.TextInputHandler):
def __init__(self, args):
self.host = args["server_host"]
def name(self): def name(self):
return "user_name" return "user_name"
@ -200,49 +205,95 @@ class ConnectUserName(sublime_plugin.TextInputHandler):
return f"user-{random.random()}" return f"user-{random.random()}"
# Separate the join command into two join workspace and join buffer commands that get called back to back
# Generic Join Command # Generic Join Command
############################################################################# #############################################################################
async def JoinCommand(client: VirtualClient, workspace_id: str, buffer_id: str): async def JoinCommand(client: VirtualClient, workspace_id: str, buffer_id: str):
if workspace_id is None: if workspace_id == "":
return return
vws = client.workspaces.get(workspace_id)
if vws is None:
vws = await client.join_workspace(workspace_id) vws = await client.join_workspace(workspace_id)
if buffer_id is None: vws.materialize()
return
if vws is not None: if buffer_id != "":
await vws.attach(buffer_id) await vws.attach(buffer_id)
class CodempJoinCommand(sublime_plugin.WindowCommand): class CodempJoinCommand(sublime_plugin.WindowCommand):
def run(self, workspace_id, buffer_id): def run(self, workspace_id, buffer_id):
print(workspace_id, buffer_id)
if buffer_id == "* Don't Join Any":
buffer_id = ""
tm.dispatch(JoinCommand(client, workspace_id, buffer_id)) tm.dispatch(JoinCommand(client, workspace_id, buffer_id))
def is_enabled(self) -> bool:
return client.handle is not None
def input_description(self): def input_description(self):
return "Join:" return "Join:"
def input(self, args): def input(self, args):
if "workspace_id" not in args: if "workspace_id" not in args:
return WorkspaceIdAndFollowup() return JoinWorkspaceIdList()
class WorkspaceIdAndFollowup(sublime_plugin.ListInputHandler): class JoinWorkspaceIdList(sublime_plugin.ListInputHandler):
# To allow for having a selection and choosing non existing workspaces
# we do a little dance: We pass this list input handler to a TextInputHandler
# when we select "Create New..." which adds his result to the list of possible
# workspaces and pop itself off the stack to go back to the list handler.
def __init__(self):
self.list = client.active_workspaces()
self.list.sort()
self.list.append("* Create New...")
self.preselected = None
def name(self): def name(self):
return "workspace_id" return "workspace_id"
def placeholder(self): def placeholder(self):
return "Workspace Id" return "Workspace"
def list_items(self): def list_items(self):
return client.active_workspaces() if self.preselected is not None:
return (self.list, self.preselected)
else:
return self.list
def next_input(self, args): def next_input(self, args):
if "buffer_id" not in args: if args["workspace_id"] == "* Create New...":
return ListBufferId() return AddListEntryName(self)
wid = args["workspace_id"]
if wid != "":
vws = tm.sync(client.join_workspace(wid))
else:
vws = None
try:
return ListBufferId(vws)
except Exception:
return TextBufferId()
class TextBufferId(sublime_plugin.TextInputHandler):
def name(self):
return "buffer_id"
class ListBufferId(sublime_plugin.ListInputHandler): class ListBufferId(sublime_plugin.ListInputHandler):
def __init__(self, vws):
self.ws = vws
self.list = vws.handle.filetree()
self.list.sort()
self.list.append("* Create New...")
self.list.append("* Don't Join Any")
self.preselected = None
def name(self): def name(self):
return "buffer_id" return "buffer_id"
@ -250,54 +301,39 @@ class ListBufferId(sublime_plugin.ListInputHandler):
return "Buffer Id" return "Buffer Id"
def list_items(self): def list_items(self):
return client.active_workspace.handle.filetree() if self.preselected is not None:
return (self.list, self.preselected)
# Join Workspace Command
#############################################################################
class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
def run(self, workspace_id): # pyright: ignore
tm.dispatch(client.join_workspace(workspace_id))
def input_description(self):
return "Join specific workspace"
def input(self, args):
if "workspace_id" not in args:
return RawWorkspaceId()
# Join Buffer Command
#############################################################################
class CodempJoinBufferCommand(sublime_plugin.WindowCommand):
def run(self, buffer_id): # pyright: ignore
if client.active_workspace is None:
sublime.error_message(
"You haven't joined any worksapce yet. \
use `Codemp: Join Workspace` or `Codemp: Join`"
)
return
tm.dispatch(client.active_workspace.attach(buffer_id))
def input_description(self):
return "Join buffer in the active workspace"
# This is awful, fix it
def input(self, args):
if client.active_workspace is None:
sublime.error_message(
"You haven't joined any worksapce yet. \
use `Codemp: Join Workspace` or `Codemp: Join`"
)
return
if "buffer_id" not in args:
existing_buffers = client.active_workspace.handle.filetree()
if len(existing_buffers) == 0:
return RawBufferId()
else: else:
return ListBufferId2() return self.list
def cancel(self):
client.leave_workspace(self.ws.id)
def next_input(self, args):
if args["buffer_id"] == "* Create New...":
return AddListEntryName(self)
if args["buffer_id"] == "* Dont' Join Any":
return None
class AddListEntryName(sublime_plugin.TextInputHandler):
def __init__(self, list_handler):
self.parent = list_handler
def name(self):
return None
def validate(self, text: str) -> bool:
return not len(text) == 0
def confirm(self, text: str):
self.parent.list.pop() # removes the "Create New..."
self.parent.list.insert(0, text)
self.parent.preselected = 0
def next_input(self, args):
return sublime_plugin.BackInputHandler()
# Text Change Command # Text Change Command
@ -309,39 +345,6 @@ class CodempReplaceTextCommand(sublime_plugin.TextCommand):
self.view.replace(edit, region, content) self.view.replace(edit, region, content)
# Input Handlers
##############################################################################
class ListBufferId2(sublime_plugin.ListInputHandler):
def name(self):
return "buffer_id"
def list_items(self):
assert client.active_workspace is not None
return client.active_workspace
def next_input(self, args):
if "buffer_id" not in args:
return RawBufferId()
class RawWorkspaceId(sublime_plugin.TextInputHandler):
def name(self):
return "workspace_id"
def placeholder(self):
return "Workspace Id"
class RawBufferId(sublime_plugin.TextInputHandler):
def name(self):
return "buffer_id"
def placeholder(self):
return "Buffer Id"
# Share Command # Share Command
# ############################################################################# # #############################################################################
# class CodempShareCommand(sublime_plugin.WindowCommand): # class CodempShareCommand(sublime_plugin.WindowCommand):
@ -359,10 +362,37 @@ class RawBufferId(sublime_plugin.TextInputHandler):
# Disconnect Command # Disconnect Command
############################################################################# #############################################################################
class CodempDisconnectCommand(sublime_plugin.WindowCommand): class CodempDisconnectCommand(sublime_plugin.WindowCommand):
def is_enabled(self) -> bool:
if client.handle is not None:
return True
else:
return False
def run(self): def run(self):
tm.sync(disconnect_client()) tm.sync(disconnect_client())
# Leave Workspace Command
class CodempLeaveWorkspaceCommand(sublime_plugin.WindowCommand):
def is_enabled(self) -> bool:
return client.handle is not None and len(client.workspaces.keys()) > 0
def run(self, id: str):
client.leave_workspace(id)
def input(self, args):
if "id" not in args:
return LeaveWorkspaceIdList()
class LeaveWorkspaceIdList(sublime_plugin.ListInputHandler):
def name(self):
return "id"
def list_items(self):
return client.active_workspaces()
# Proxy Commands ( NOT USED, left just in case we need it again. ) # Proxy Commands ( NOT USED, left just in case we need it again. )
############################################################################# #############################################################################
# class ProxyCodempShareCommand(sublime_plugin.WindowCommand): # class ProxyCodempShareCommand(sublime_plugin.WindowCommand):

View file

@ -18,12 +18,13 @@ class TaskManager:
def release(self, at_exit): def release(self, at_exit):
self.runtime.release(at_exit=at_exit, exit_handler_id=self.exit_handler_id) self.runtime.release(at_exit=at_exit, exit_handler_id=self.exit_handler_id)
self.exit_handler_id = None
def dispatch(self, coro, name=None): def dispatch(self, coro, name=None):
self.runtime.dispatch(coro, self.store_named_lambda(name)) self.runtime.dispatch(coro, self.store_named_lambda(name))
def sync(self, coro): def sync(self, coro):
self.runtime.sync(coro) return self.runtime.sync(coro)
def remove_stopped(self): def remove_stopped(self):
self.tasks = list(filter(lambda T: not T.cancelled(), self.tasks)) self.tasks = list(filter(lambda T: not T.cancelled(), self.tasks))

View file

@ -22,18 +22,25 @@ from ..src.utils import status_log, rowcol_to_region
class CodempLogger: class CodempLogger:
def __init__(self, debug: bool = False): def __init__(self, debug: bool = False):
self.handle = None
self.started = False
try: try:
self.handle = PyLogger(debug) self.handle = PyLogger(debug)
except Exception: except Exception:
pass pass
async def log(self): async def log(self):
if self.started:
return
self.started = True
status_log("spinning up the logger...") status_log("spinning up the logger...")
try: try:
while msg := await self.handle.listen(): while msg := await self.handle.listen():
print(msg) print(msg)
except asyncio.CancelledError: except asyncio.CancelledError:
status_log("stopping logger") status_log("stopping logger")
self.started = False
raise raise
except Exception as e: except Exception as e:
status_log(f"logger crashed unexpectedly:\n{e}") status_log(f"logger crashed unexpectedly:\n{e}")
@ -460,4 +467,7 @@ class VirtualClient:
self.active_workspace = ws self.active_workspace = ws
DEBUG = False
logger = CodempLogger(DEBUG)
logger.log()
client = VirtualClient() client = VirtualClient()