2024-09-17 22:20:00 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Optional, Tuple
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
2024-09-28 19:55:20 +02:00
|
|
|
import codemp
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
import sublime
|
|
|
|
import shutil
|
|
|
|
import tempfile
|
|
|
|
import logging
|
2024-11-02 18:26:37 +01:00
|
|
|
import gc
|
2024-09-17 22:20:00 +02:00
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
from codemp import Selection
|
2024-09-17 22:20:00 +02:00
|
|
|
from .. import globals as g
|
|
|
|
from ..utils import draw_cursor_region
|
|
|
|
from ..utils import bidict
|
2024-09-28 19:55:20 +02:00
|
|
|
from .buffers import buffers
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
def add_project_folder(w: sublime.Window, folder: str, name: str = ""):
|
2024-11-02 18:26:37 +01:00
|
|
|
proj = w.project_data()
|
|
|
|
if not isinstance(proj, dict):
|
|
|
|
proj = {"folders": []}
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
if name == "":
|
|
|
|
entry = {"path": folder}
|
|
|
|
else:
|
|
|
|
entry = {"name": name, "path": folder}
|
|
|
|
|
|
|
|
proj["folders"].append(entry)
|
|
|
|
|
|
|
|
w.set_project_data(proj)
|
|
|
|
|
|
|
|
def remove_project_folder(w: sublime.Window, filterstr: str):
|
2024-11-02 18:26:37 +01:00
|
|
|
proj: dict = w.project_data() # type:ignore
|
2024-09-17 22:20:00 +02:00
|
|
|
if proj is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
clean_proj_folders = list(
|
|
|
|
filter(
|
|
|
|
lambda f: f.get("name", "") != filterstr,
|
|
|
|
proj["folders"],
|
|
|
|
)
|
|
|
|
)
|
|
|
|
proj["folders"] = clean_proj_folders
|
|
|
|
w.set_project_data(proj)
|
|
|
|
|
2024-09-18 16:57:26 +02:00
|
|
|
|
|
|
|
def cursor_callback(ctl: codemp.CursorController):
|
|
|
|
def _():
|
|
|
|
while event := ctl.try_recv().wait():
|
|
|
|
if event is None: break
|
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
try: bfm = buffers.lookupId(event.sel.buffer)
|
|
|
|
except KeyError: continue
|
|
|
|
|
|
|
|
region_start = (event.sel.start_row, event.sel.start_col)
|
|
|
|
region_end = (event.sel.end_row, event.sel.end_col)
|
2024-09-18 16:57:26 +02:00
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
draw_cursor_region(bfm.view, region_start, region_end, event.user)
|
2024-09-18 16:57:26 +02:00
|
|
|
sublime.set_timeout_async(_)
|
|
|
|
|
2024-09-17 22:20:00 +02:00
|
|
|
class WorkspaceManager():
|
|
|
|
def __init__(self, handle: codemp.Workspace, window: sublime.Window, rootdir: str) -> None:
|
|
|
|
self.handle: codemp.Workspace = handle
|
|
|
|
self.window: sublime.Window = window
|
|
|
|
self.curctl: codemp.CursorController = self.handle.cursor()
|
|
|
|
self.rootdir: str = rootdir
|
2024-09-18 16:57:26 +02:00
|
|
|
self.id: str = self.handle.id()
|
2024-09-28 19:55:20 +02:00
|
|
|
self.curctl.callback(cursor_callback)
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
def __del__(self):
|
2024-09-18 16:57:26 +02:00
|
|
|
logger.debug(f"dropping workspace {self.id}")
|
2024-09-17 22:20:00 +02:00
|
|
|
self.curctl.clear_callback()
|
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
for buff in self.handle.active_buffers():
|
|
|
|
if not self.handle.detach_buffer(buff):
|
2024-09-17 22:20:00 +02:00
|
|
|
logger.warning(
|
|
|
|
f"could not detach from '{buff}' for workspace '{self.id}'."
|
|
|
|
)
|
|
|
|
|
2024-09-28 19:55:20 +02:00
|
|
|
for bfm in buffers.lookup(self):
|
|
|
|
buffers.remove(bfm)
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
# is ok for now with the cursor.
|
2024-11-02 18:26:37 +01:00
|
|
|
sel = Selection(
|
|
|
|
start_row=start[0],
|
|
|
|
start_col=start[1],
|
|
|
|
end_row=end[0],
|
|
|
|
end_col=end[1],
|
|
|
|
buffer=id
|
|
|
|
)
|
|
|
|
self.curctl.send(sel)
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
class WorkspaceRegistry():
|
|
|
|
def __init__(self) -> None:
|
|
|
|
self._workspaces: bidict[WorkspaceManager, sublime.Window] = bidict()
|
|
|
|
|
2024-09-28 19:55:20 +02:00
|
|
|
def lookup(self, w: Optional[sublime.Window] = None) -> list[WorkspaceManager]:
|
2024-09-17 22:20:00 +02:00
|
|
|
if not w:
|
|
|
|
return list(self._workspaces.keys())
|
|
|
|
ws = self._workspaces.inverse.get(w)
|
|
|
|
return ws if ws else []
|
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
def lookupParent(self, ws: WorkspaceManager | str) -> sublime.Window:
|
|
|
|
if isinstance(ws, str):
|
|
|
|
wsm = self.lookupId(ws)
|
|
|
|
return self._workspaces[ws]
|
|
|
|
|
|
|
|
def lookupId(self, wid: str) -> WorkspaceManager:
|
|
|
|
wsm = next((ws for ws in self._workspaces if ws.id == wid), None)
|
|
|
|
if not wsm: raise KeyError
|
|
|
|
return wsm
|
2024-09-17 22:20:00 +02:00
|
|
|
|
2024-09-18 16:57:26 +02:00
|
|
|
def add(self, wshandle: codemp.Workspace) -> WorkspaceManager:
|
2024-09-17 22:20:00 +02:00
|
|
|
win = sublime.active_window()
|
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
# tmpdir = tempfile.mkdtemp(prefix="codemp_")
|
|
|
|
# add_project_folder(win, tmpdir, f"{g.WORKSPACE_FOLDER_PREFIX}{wshandle.id()}")
|
2024-09-17 22:20:00 +02:00
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
tmpdir = "DISABLED"
|
2024-09-17 22:20:00 +02:00
|
|
|
wm = WorkspaceManager(wshandle, win, tmpdir)
|
|
|
|
self._workspaces[wm] = win
|
2024-09-18 16:57:26 +02:00
|
|
|
return wm
|
2024-09-17 22:20:00 +02:00
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
def remove(self, ws: WorkspaceManager | str):
|
2024-09-17 22:20:00 +02:00
|
|
|
if isinstance(ws, str):
|
|
|
|
ws = self.lookupId(ws)
|
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
# remove_project_folder(ws.window, f"{g.WORKSPACE_FOLDER_PREFIX}{ws.id}")
|
|
|
|
# shutil.rmtree(ws.rootdir, ignore_errors=True)
|
2024-09-17 22:20:00 +02:00
|
|
|
del self._workspaces[ws]
|
|
|
|
|
|
|
|
|
2024-11-02 18:26:37 +01:00
|
|
|
|
2024-09-28 19:55:20 +02:00
|
|
|
workspaces = WorkspaceRegistry()
|
2024-09-17 22:20:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|