From 93f3e38c75a11c6b2310643cd84315eefd133f63 Mon Sep 17 00:00:00 2001 From: cschen Date: Sun, 3 Nov 2024 17:57:31 +0100 Subject: [PATCH] feat(WIP): added quick panel browsing for server and workspace! --- Codemp.sublime-commands | 36 +++-- main.py | 40 ++++++ plugin/quickpanel/qp_globals.py | 24 ++++ plugin/quickpanel/qpbrowser.py | 224 ++++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+), 11 deletions(-) create mode 100644 plugin/quickpanel/qp_globals.py create mode 100644 plugin/quickpanel/qpbrowser.py diff --git a/Codemp.sublime-commands b/Codemp.sublime-commands index f7037bf..b467cf9 100644 --- a/Codemp.sublime-commands +++ b/Codemp.sublime-commands @@ -19,24 +19,38 @@ "file": "${packages}/CodempClient/README.md" } }, + { + "caption": "Codemp: Browse Server", + "command": "codemp_browse_server", + "args": {} + }, + { + "caption": "Codemp: Browse Workspace", + "command": "codemp_browse_workspace", + "args": { + + } + }, { // # on_window_command, does not trigger when called from the command palette // # See: https://github.com/sublimehq/sublime_text/issues/2234 "caption": "Codemp: Connect", "command": "codemp_connect", "args": { - "server_host": "http://code.mp:50053", + "server_host": "code.mp", + "user_name" : "cschen@codemp.dev", + "password" : "***REMOVED***" } }, { "caption": "Codemp: Disconnect Client", "command": "codemp_disconnect", - "arg": {} + "args": {} }, { "caption": "Codemp: Join Workspace", "command": "codemp_join_workspace", - "arg": { + "args": { // 'workspace_id': 'asd' // 'buffer_id': 'test' }, @@ -44,14 +58,14 @@ { "caption": "Codemp: Leave Workspace", "command": "codemp_leave_workspace", - "arg": { + "args": { // "id": 'lmaaaao' } }, { "caption": "Codemp: Invite To Workspace", "command": "codemp_invite_to_workspace", - "arg": { + "args": { // "id": 'lmaaaao' // "user": 'lupo' } @@ -59,21 +73,21 @@ { "caption": "Codemp: Create Workspace", "command": "codemp_create_workspace", - "arg": { + "args": { // "id": 'lmaaaao' } }, { "caption": "Codemp: Delete Workspace", "command": "codemp_delete_workspace", - "arg": { + "args": { // "id": 'lmaaaao' } }, { "caption": "Codemp: Join Buffer", "command": "codemp_join_buffer", - "arg": { + "args": { // 'workspace_id': 'asd' // 'buffer_id': 'test' }, @@ -81,7 +95,7 @@ { "caption": "Codemp: Leave Buffer", "command": "codemp_leave_buffer", - "arg": { + "args": { // 'workspace_id': 'asd' // 'buffer_id': 'test' } @@ -89,7 +103,7 @@ { "caption": "Codemp: Create Buffer", "command": "codemp_create_buffer", - "arg": { + "args": { // 'workspace_id': 'asd' // 'buffer_id': 'test' } @@ -97,7 +111,7 @@ { "caption": "Codemp: Delete Buffer", "command": "codemp_delete_buffer", - "arg": { + "args": { // 'workspace_id': 'asd' // 'buffer_id': 'test' } diff --git a/main.py b/main.py index 1924f10..892a173 100644 --- a/main.py +++ b/main.py @@ -5,10 +5,14 @@ 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 @@ -22,6 +26,10 @@ 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( @@ -54,6 +62,38 @@ 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)) + + 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): diff --git a/plugin/quickpanel/qp_globals.py b/plugin/quickpanel/qp_globals.py new file mode 100644 index 0000000..f4785a8 --- /dev/null +++ b/plugin/quickpanel/qp_globals.py @@ -0,0 +1,24 @@ +import sublime + +QP_COLOR_NONE = sublime.KIND_ID_AMBIGUOUS +QP_COLOR_REDISH = sublime.KIND_ID_COLOR_REDISH +QP_COLOR_ORANGISH = sublime.KIND_ID_COLOR_ORANGISH +QP_COLOR_YELLOWISH = sublime.KIND_ID_COLOR_YELLOWISH +QP_COLOR_GREENISH = sublime.KIND_ID_COLOR_GREENISH +QP_COLOR_CYANISH = sublime.KIND_ID_COLOR_CYANISH +QP_COLOR_BLUISH = sublime.KIND_ID_COLOR_BLUISH +QP_COLOR_PURPLISH = sublime.KIND_ID_COLOR_PURPLISH +QP_COLOR_PINKISH = sublime.KIND_ID_COLOR_PINKISH +QP_COLOR_DARK = sublime.KIND_ID_COLOR_DARK +QP_COLOR_LIGHT = sublime.KIND_ID_COLOR_LIGHT + +QP_YES = "✓" +QP_NO = "✗" +QP_ADD = "+" +QP_FORWARD = "❯" +QP_BACK = "❮" +QP_DETAILS = "⋯" +QP_RENAME = "*" +QP_CHMOD = "7" +QP_DOWNLOAD = "⏬" +QP_EDIT = "a" diff --git a/plugin/quickpanel/qpbrowser.py b/plugin/quickpanel/qpbrowser.py new file mode 100644 index 0000000..859062e --- /dev/null +++ b/plugin/quickpanel/qpbrowser.py @@ -0,0 +1,224 @@ +import sublime +import logging + +from . import qp_globals as qpg + +from ..core.workspace import workspaces +from ..core.buffers import buffers + +logger = logging.getLogger(__name__) + +def qpi(text, details="", color=qpg.QP_COLOR_NONE, letter="", name="", hint="", prefix=""): + return sublime.QuickPanelItem(text, details, annotation=hint, kind=(color, letter, name)) + +def show_qp(window, choices, on_done, placeholder=''): + def _(): + flags = sublime.KEEP_OPEN_ON_FOCUS_LOST + 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 + self.host = host + self.raw_input_items = raw_input_items + + def make_entry(self, wsid): + return qpi(wsid, letter="w", color=qpg.QP_COLOR_BLUISH, hint="Workspace", prefix=" ") + + def qp_placeholder(self): + return f"Browsing workspaces on host: {self.host}" + + def run(self): + self.current_wid_selection = None + self.entries = [] + for item in self.raw_input_items: + self.entries.append(self.make_entry(item)) + + self.entries.insert(0, qpi("Server Actions", + color=qpg.QP_COLOR_CYANISH, + letter=qpg.QP_DETAILS, + hint="Submenu", + prefix=" • ")) + + show_qp(self.window, self.entries, self.server_actions, self.qp_placeholder()) + + def server_actions(self, index): + if index == -1: + return + elif index == 0: + self.edit_server() + return + + wid = self.entries[index].trigger + self.current_wid_selection = wid + # self.select_workspace() + def _(): + self.window.run_command( + "codemp_join_workspace", + { + "workspace_id": self.current_wid_selection, + "sync": True + }) + + 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_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): + actions = [ + qpi("Back", color=qpg.QP_COLOR_CYANISH, letter=qpg.QP_BACK), + qpi("New Workspace", color=qpg.QP_COLOR_GREENISH, letter=qpg.QP_ADD), + qpi("Delete Workspace", color=qpg.QP_COLOR_REDISH, letter=qpg.QP_NO) + ] + show_qp(self.window, actions, self.edit_server_actions, self.qp_placeholder()) + + def edit_server_actions(self, index): + if index == -1: + return + + if index == 0: + self.run() + + if index == 1: + def create_workspace(name): + self.window.run_command( + "codemp_create_workspace", + {"workspace_id": name}) + self.window.show_input_panel("New Workspace Name", "", create_workspace, None, self.edit_server) + + if index == 2: + def delete_workspace(index): + if index == -1 or index == 0: + self.edit_server() + # we must be careful here. here with index 1 we are selecting the correct + # workspace, because the index zero in the entries is the workspace action submenu. + # which is occupied by the back action. + # if we add extra non workspace entries, then we must shift the index accordingly. + # Do this differently? + selected = self.entries[index] + self.window.run_command( + "codemp_delete_workspace", + {"workspace_id": selected.trigger}) + + + show_qp(self.window, self.entries, delete_workspace, self.qp_placeholder()) + + +class QPWorkspaceBrowser(): + def __init__(self, window, workspace_id, raw_input_items): + self.window = window + self.workspace_id = workspace_id + self.raw_input_items = raw_input_items + + def qp_placeholder(self): + return f"Browsing buffers in {self.workspace_id}" + + def make_entry(self, item): + return qpi(item, letter="b", color=qpg.QP_COLOR_BLUISH, hint="Buffer", prefix=" ") + + def run(self): + self.entries = [] + for buffer in self.raw_input_items: + self.entries.append(self.make_entry(buffer)) + + self.entries.insert(0, qpi("Workspace Actions", + color=qpg.QP_COLOR_CYANISH, + letter=qpg.QP_DETAILS, + hint="Submenu", + prefix=" • ")) + + show_qp(self.window, self.entries, self.workspace_actions, self.qp_placeholder()) + + def workspace_actions(self, index): + if index == -1: + return + elif index == 0: + self.edit_workspace() + return + + bid = self.entries[index].trigger + + self.window.run_command( + "codemp_join_buffer", + { + "workspace_id": self.workspace_id, + "buffer_id": bid + }) + + + def edit_workspace(self): + actions = [ + qpi("Back", color=qpg.QP_COLOR_CYANISH, letter=qpg.QP_BACK), + qpi("Leave Workspace", color=qpg.QP_COLOR_ORANGISH, letter=qpg.QP_BACK), + qpi("Invite User", color=qpg.QP_COLOR_PINKISH, letter=qpg.QP_FORWARD), + qpi("Create Buffer", color=qpg.QP_COLOR_GREENISH, letter=qpg.QP_ADD), + qpi("Delete Buffer", color=qpg.QP_COLOR_REDISH, letter=qpg.QP_NO), + qpi("Rename Buffer", color=qpg.QP_COLOR_ORANGISH, letter=qpg.QP_RENAME), + ] + show_qp(self.window, actions, self.edit_workspace_actions, self.qp_placeholder()) + + def edit_workspace_actions(self, index): + if index == -1 or index == 0: + self.edit_workspace() + elif index == 1: + self.window.run_command( + "codemp_leave_workspace", + {"workspace_id": self.workspace_id}) + self.window.run_command( + "codemp_browse_server", {}) + elif index == 2: + self.window.run_command( + "codemp_invite_to_workspace", + {"workspace_id": self.workspace_id}) + elif index == 3: + def create_buffer(name): + self.window.run_command( + "codemp_create_workspace", + { + "workspace_id": self.workspace_id, + "buffer_id": name + }) + self.window.show_input_panel("New Workspace Name", "", create_buffer, None, self.edit_workspace) + elif index == 4: + def delete_buffer(index): + if index == -1 or index == 0: + self.edit_workspace() + + # same warning as the server browser. Check your indexed 3 times + selected = self.entries[index] + self.window.run_command( + "codemp_delete_buffer", + { + "workspace_id": self.workspace_id, + "buffer_id": selected.trigger + }) + show_qp(self.window, self.entries, delete_buffer, self.qp_placeholder()) + elif index == 5: + sublime.message_dialog("renaming is not yet implemented.") + self.edit_workspace() \ No newline at end of file