feat: added leave buffer command.

feat: new generic input handler for sequence of text inputs with defaults.
chore: minor fixes and improvements

Former-commit-id: 73ea017903fd717d894092871b7b62f827df4ff2
This commit is contained in:
cschen 2024-08-24 18:45:42 +02:00
parent 37b67aa1ea
commit 77ca8ab93d
4 changed files with 148 additions and 130 deletions

View file

@ -28,6 +28,11 @@
// "server_host": "http://[::1]:50051" // "server_host": "http://[::1]:50051"
} }
}, },
{
"caption": "Codemp: Disconnect Client",
"command": "codemp_disconnect",
"arg": {}
},
{ {
"caption": "Codemp: Join Workspace", "caption": "Codemp: Join Workspace",
"command": "codemp_join_workspace", "command": "codemp_join_workspace",
@ -36,6 +41,13 @@
// 'buffer_id': 'test' // 'buffer_id': 'test'
}, },
}, },
{
"caption": "Codemp: Leave Workspace",
"command": "codemp_leave_workspace",
"arg": {
// "id": 'lmaaaao'
}
},
{ {
"caption": "Codemp: Join Buffer", "caption": "Codemp: Join Buffer",
"command": "codemp_join_buffer", "command": "codemp_join_buffer",
@ -45,23 +57,11 @@
}, },
}, },
{ {
"caption": "Codemp: Share", "caption": "Codemp: Leave Buffer",
"command": "codemp_share", "command": "codemp_leave_buffer",
"arg": { "arg": {
// 'sublime_buffer' : /path/to/buffer/to/share // 'workspace_id': 'asd'
// 'server_id' : 'how to call the buffer on the server' // 'buffer_id': 'test'
} }
}, },
{
"caption": "Codemp: Leave Workspace",
"command": "codemp_leave_workspace",
"arg": {
// "id": 'lmaaaao'
}
},
{
"caption": "Codemp: Disconnect Client",
"command": "codemp_disconnect",
"arg": {}
},
] ]

238
plugin.py
View file

@ -3,6 +3,7 @@ import sublime
import sublime_plugin import sublime_plugin
import logging import logging
import random import random
from typing import List, Tuple
import codemp import codemp
from Codemp.src.client import client from Codemp.src.client import client
@ -114,7 +115,7 @@ class CodempClientViewEventListener(sublime_plugin.ViewEventListener):
if vws is None or vbuff is None: if vws is None or vbuff is None:
raise raise
vws.uninstall_buffer(vbuff.id) vws.uninstall_buffer(vbuff)
def on_text_command(self, command_name, args): def on_text_command(self, command_name, args):
if command_name == "codemp_replace_text": if command_name == "codemp_replace_text":
@ -146,23 +147,26 @@ class CodempClientTextChangeListener(sublime_plugin.TextChangeListener):
sublime.set_timeout(lambda: vbuff.send_buffer_change(changes)) sublime.set_timeout(lambda: vbuff.send_buffer_change(changes))
# Commands: # Client Commands:
# codemp_connect: connect to a server. # codemp_connect: connect to a server.
# codemp_join: shortcut command if you already know both workspace id
# and buffer id
# codemp_join_workspace: joins a specific workspace, without joining also a buffer
# codemp_join_buffer: joins a specific buffer within the current active workspace
# codemp_share: ??? todo!()
# codemp_disconnect: manually call the disconnection, triggering the cleanup and dropping # codemp_disconnect: manually call the disconnection, triggering the cleanup and dropping
# the connection # the connection
# # codemp_join_workspace: joins a specific workspace, without joining also a buffer
# codemp_leave_workspace:
# Workspace Commands:
# codemp_join_buffer: joins a specific buffer within the current active workspace
# codemp_leave_buffer:
# codemp_create_buffer:
# codemp_delete_buffer:
# Internal commands: # Internal commands:
# replace_text: swaps the content of a view with the given text. # replace_text: swaps the content of a view with the given text.
#
# Connect Command
# Client Commands
############################################################################# #############################################################################
# Connect Command
class CodempConnectCommand(sublime_plugin.WindowCommand): class CodempConnectCommand(sublime_plugin.WindowCommand):
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
return client.codemp is None return client.codemp is None
@ -182,42 +186,27 @@ class CodempConnectCommand(sublime_plugin.WindowCommand):
sublime.set_timeout_async(try_connect) sublime.set_timeout_async(try_connect)
def input(self, args):
if "server_host" not in args:
return ConnectServerHost()
def input_description(self): def input_description(self):
return "Server host:" return "Server host:"
def input(self, args):
class ConnectServerHost(sublime_plugin.TextInputHandler): if "server_host" not in args:
def name(self): return SimpleTextInput(
return "server_host" ("server_host", "http://127.0.0.1:50051"),
("user_name", f"user-{random.random()}"),
def initial_text(self): )
return "http://127.0.0.1:50051"
def next_input(self, args):
if "user_name" not in args:
return ConnectUserName(args)
class ConnectUserName(sublime_plugin.TextInputHandler): # Disconnect Command
def __init__(self, args): class CodempDisconnectCommand(sublime_plugin.WindowCommand):
self.host = args["server_host"] def is_enabled(self):
return client.codemp is not None
def name(self): def run(self):
return "user_name" client.disconnect()
def initial_text(self):
return f"user-{random.random()}"
# Separate the join command into two join workspace and join buffer commands that get called back to back # Join Workspace Command
# Generic Join Workspace Command
#############################################################################
class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand): class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
return client.codemp is not None return client.codemp is not None
@ -252,11 +241,6 @@ class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
return WorkspaceIdText() return WorkspaceIdText()
class WorkspaceIdText(sublime_plugin.TextInputHandler):
def name(self):
return "workspace_id"
# To allow for having a selection and choosing non existing workspaces # 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 # 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 # when we select "Create New..." which adds his result to the list of possible
@ -291,6 +275,25 @@ class WorkspaceIdText(sublime_plugin.TextInputHandler):
# return AddListEntry(self) # return AddListEntry(self)
# Leave Workspace Command
class CodempLeaveWorkspaceCommand(sublime_plugin.WindowCommand):
def is_enabled(self):
return client.codemp is not None and len(client.all_workspaces(self.window)) > 0
def run(self, workspace_id: str):
# client.leave_workspace(id)
pass
def input(self, args):
if "id" not in args:
return ActiveWorkspacesIdList()
# WORKSPACE COMMANDS
#############################################################################
# Join Buffer Command
class CodempJoinBufferCommand(sublime_plugin.WindowCommand): class CodempJoinBufferCommand(sublime_plugin.WindowCommand):
def is_enabled(self): def is_enabled(self):
available_workspaces = client.all_workspaces(self.window) available_workspaces = client.all_workspaces(self.window)
@ -343,8 +346,6 @@ class CodempJoinBufferCommand(sublime_plugin.WindowCommand):
return "Attach: " return "Attach: "
def input(self, args): def input(self, args):
# if we have only a workspace in the window, then
# skip to the buffer choice
if "workspace_id" not in args: if "workspace_id" not in args:
return ActiveWorkspacesIdList(self.window, get_buffer=True) return ActiveWorkspacesIdList(self.window, get_buffer=True)
@ -352,6 +353,86 @@ class CodempJoinBufferCommand(sublime_plugin.WindowCommand):
return BufferIdList(args["workspace_id"]) return BufferIdList(args["workspace_id"])
# Leave Buffer Comand
class CodempLeaveBufferCommand(sublime_plugin.WindowCommand):
def is_enabled(self):
return len(client.all_buffers()) > 0
def run(self, workspace_id, buffer_id):
vbuff = client.buffer_from_id(buffer_id)
vws = client.workspace_from_id(workspace_id)
if vbuff is None or vws is None:
return
def defer_detach():
if vws.codemp.detach(buffer_id):
vws.uninstall_buffer(vbuff)
sublime.set_timeout_async(defer_detach)
def input_description(self) -> str:
return "Leave: "
def input(self, args):
if "workspace_id" not in args:
return ActiveWorkspacesIdList(self.window, get_buffer=True)
if "buffer_id" not in args:
return BufferIdList(args["workspace_id"])
# Text Change Command
#############################################################################
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)
# Input handlers
############################################################
class SimpleTextInput(sublime_plugin.TextInputHandler):
def __init__(self, *args: Tuple[str, str]):
assert len(args) > 0
self.argname = args[0][0]
self.default = args[0][1]
self.next_inputs = args[1:]
def initial_text(self):
return self.default
def name(self):
return self.argname
def next_input(self, args):
if len(self.next_inputs) > 0:
if self.next_inputs[0][0] not in args:
return SimpleTextInput(*self.next_inputs)
class WorkspaceIdText(sublime_plugin.TextInputHandler):
def name(self):
return "workspace_id"
class ActiveWorkspacesIdList(sublime_plugin.ListInputHandler):
def __init__(self, window=None, get_buffer=False):
self.window = window
self.get_buffer = get_buffer
def name(self):
return "workspace_id"
def list_items(self):
return [vws.id for vws in client.all_workspaces(self.window)]
def next_input(self, args):
if self.get_buffer:
return BufferIdList(args["workspace_id"])
class BufferIdList(sublime_plugin.ListInputHandler): class BufferIdList(sublime_plugin.ListInputHandler):
def __init__(self, workspace_id): def __init__(self, workspace_id):
self.add_entry_text = "* create new..." self.add_entry_text = "* create new..."
@ -377,69 +458,6 @@ class BufferIdList(sublime_plugin.ListInputHandler):
return AddListEntry(self) return AddListEntry(self)
# Text Change Command
#############################################################################
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)
# Share Command
# #############################################################################
# class CodempShareCommand(sublime_plugin.WindowCommand):
# def run(self, sublime_buffer_path, server_id):
# sublime_asyncio.dispatch(share_buffer_command(sublime_buffer_path, server_id))
# def input(self, args):
# if "sublime_buffer" not in args:
# return SublimeBufferPathInputHandler()
# def input_description(self):
# return "Share Buffer:"
# Disconnect Command
#############################################################################
class CodempDisconnectCommand(sublime_plugin.WindowCommand):
def is_enabled(self):
return client.codemp is not None
def run(self):
client.disconnect()
# Leave Workspace Command
class CodempLeaveWorkspaceCommand(sublime_plugin.WindowCommand):
def is_enabled(self):
return client.codemp is not None and len(client.all_workspaces(self.window)) > 0
def run(self, workspace_id: str):
# client.leave_workspace(id)
pass
def input(self, args):
if "id" not in args:
return ActiveWorkspacesIdList()
class ActiveWorkspacesIdList(sublime_plugin.ListInputHandler):
def __init__(self, window=None, get_buffer=False):
self.window = window
self.get_buffer = get_buffer
def name(self):
return "workspace_id"
def list_items(self):
return [vws.id for vws in client.all_workspaces(self.window)]
def next_input(self, args):
if self.get_buffer:
return BufferIdList(args["workspace_id"])
class AddListEntry(sublime_plugin.TextInputHandler): class AddListEntry(sublime_plugin.TextInputHandler):
# this class works when the list input handler # this class works when the list input handler
# added appended a new element to it's list that will need to be # added appended a new element to it's list that will need to be

View file

@ -1,5 +1,5 @@
from __future__ import annotations from __future__ import annotations
from typing import Optional, Dict from typing import Optional
import sublime import sublime
@ -50,7 +50,7 @@ class VirtualClient:
if window is None: if window is None:
return list(self.__workspace2window.keys()) return list(self.__workspace2window.keys())
else: else:
return self.__workspace2window.inverse[window] return self.__workspace2window.inverse.get(window, [])
def workspace_from_view(self, view: sublime.View) -> Optional[VirtualWorkspace]: def workspace_from_view(self, view: sublime.View) -> Optional[VirtualWorkspace]:
buff = self.__view2buff.get(view, None) buff = self.__view2buff.get(view, None)
@ -70,7 +70,7 @@ class VirtualClient:
else: else:
if isinstance(workspace, str): if isinstance(workspace, str):
workspace = client.__id2workspace[workspace] workspace = client.__id2workspace[workspace]
return self.__buff2workspace.inverse[workspace] return self.__buff2workspace.inverse.get(workspace, [])
def buffer_from_view(self, view: sublime.View) -> Optional[VirtualBuffer]: def buffer_from_view(self, view: sublime.View) -> Optional[VirtualBuffer]:
return self.__view2buff.get(view) return self.__view2buff.get(view)

View file

@ -47,7 +47,7 @@ class VirtualWorkspace:
all(id in self.__id2buff for id in attached_buffers) all(id in self.__id2buff for id in attached_buffers)
# TODO! # TODO!
def valid_bufffer(self, buff: VirtualBuffer | str): def valid_buffer(self, buff: VirtualBuffer | str):
if isinstance(buff, str): if isinstance(buff, str):
return self.buff_by_id(buff) is not None return self.buff_by_id(buff) is not None