feat: completely reworked the connection flow. Now profiles can be specified in the

`Codemp.sublime-settings` file. Otherwise we use default endpoint values and ask
for credentials manually. The credentials are then later saved *in memory* for easier subsequent
use.
This commit is contained in:
cschen 2025-02-16 18:36:09 +01:00
parent 34d8a7562c
commit b5ddf71199
4 changed files with 104 additions and 27 deletions

View file

@ -34,9 +34,7 @@
// # See: https://github.com/sublimehq/sublime_text/issues/2234 // # See: https://github.com/sublimehq/sublime_text/issues/2234
"caption": "Codemp: Connect", "caption": "Codemp: Connect",
"command": "codemp_connect", "command": "codemp_connect",
"args": { "args": {}
"server_host": "code.mp"
}
}, },
{ {
"caption": "Codemp: Disconnect Client", "caption": "Codemp: Disconnect Client",

View file

@ -7,45 +7,111 @@ import codemp
from ..core.session import session from ..core.session import session
from ..core.workspace import workspaces from ..core.workspace import workspaces
from ..utils import get_setting
from ..quickpanel.qpbrowser import qpi
from ..quickpanel.qpbrowser import show_qp
from ..input_handlers import SimpleTextInput from ..input_handlers import SimpleTextInput
from ..input_handlers import SimpleListInput from ..input_handlers import SimpleListInput
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def valid_profiles(profiles):
return [p for p in profiles if "name" in p]
def get_profile_index_by_name(profiles, name):
return next((index for (index, d) in enumerate(profiles) if d["name"] == name))
def get_default_profile(profiles):
i = get_profile_index_by_name(profiles, "Default")
return profiles[i]
class CodempConnectCommand(sublime_plugin.WindowCommand): class CodempConnectCommand(sublime_plugin.WindowCommand):
def input(self, args): def __init__(self, window):
_args = { super().__init__(window)
"server_host": "code.mp", self.connprofile = {}
"user_name": "Your username", self.selectedprofile = 0
"password": "Your password"
}
missingargs = [(arg, _args[arg]) for arg in _args.keys() if arg not in args ]
if missingargs: def is_enabled(self) -> bool:
return SimpleTextInput(missingargs) return not session.is_active()
def update_config_and_connect(self):
config = codemp.Config(
username = self.connprofile["username"],
password = self.connprofile["password"],
host = self.connprofile["host"],
port = self.connprofile["port"],
tls = self.connprofile["tls"]
)
def input_description(self): session._config = config
return "Connect:"
def run(self, server_host, user_name, password): # pyright: ignore[reportIncompatibleMethodOverride]
def _(): def _():
try: try:
config = codemp.Config( session.connect()
username = user_name,
password = password,
host = server_host,
port=50053,
tls=False)
session.connect(config)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
sublime.error_message( sublime.error_message(
"Could not connect:\n Make sure the server is up\n\ "Could not connect:\n Make sure the server is up\n\
and your credentials are correct." and your credentials are correct."
) )
# If the connect was successfull, save the credentials in memory for the session:
profiles = get_setting("profiles")
selected_profile_id = get_profile_index_by_name(profiles, self.connprofile["name"])
profiles[selected_profile_id] = self.connprofile # pyright: ignore
sublime.load_settings("Codemp.sublime-settings").set("profiles", profiles)
sublime.set_timeout_async(_) sublime.set_timeout_async(_)
def maybe_get_password(self):
def __(pwd):
self.connprofile["password"] = pwd
self.update_config_and_connect()
panel = self.window.show_input_panel("Password:", "" , __, None, None)
# Very undocumented feature, the input panel if has the setting 'password' set to true
# will hide the input.
panel.settings().set("password", True)
def maybe_get_user(self):
def __(usr):
self.connprofile["username"] = usr
self.maybe_get_password()
panel = self.window.show_input_panel("username:", "" , __, None, None)
panel.settings().set("password", False)
def run(self): # pyright: ignore[reportIncompatibleMethodOverride]
def _run(index):
self.selectedprofile = index
profile = profiles[index]
default_profile = get_default_profile(profiles)
self.connprofile = {**default_profile, **profile}
if self.connprofile["username"] and self.connprofile["password"]:
self.update_config_and_connect()
if not self.connprofile["username"]:
self.maybe_get_user()
if not self.connprofile["password"]:
self.maybe_get_password()
profiles = valid_profiles(get_setting("profiles"))
qplist = []
for p in profiles:
hint = f"host: {p['host']}:{p['port']}"
user = p["username"]
pwd = " : *******" if p["password"] else ""
details = user + pwd
qplist.append(qpi(p["name"], details, letter="P", hint=hint))
show_qp(self.window, qplist, _run, placeholder="Profile")
# Disconnect Command # Disconnect Command
class CodempDisconnectCommand(sublime_plugin.WindowCommand): class CodempDisconnectCommand(sublime_plugin.WindowCommand):
def is_enabled(self): def is_enabled(self):
@ -74,7 +140,7 @@ class CodempJoinWorkspaceCommand(sublime_plugin.WindowCommand):
if "workspace_id" not in args: if "workspace_id" not in args:
wslist = session.get_workspaces() wslist = session.get_workspaces()
return SimpleListInput( return SimpleListInput(
("workspace_id", wslist), [("workspace_id", wslist)],
) )
def run(self, workspace_id): # pyright: ignore[reportIncompatibleMethodOverride] def run(self, workspace_id): # pyright: ignore[reportIncompatibleMethodOverride]

View file

@ -1,6 +1,8 @@
import logging import logging
import codemp import codemp
from typing import Optional
from ..utils import some from ..utils import some
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -10,6 +12,7 @@ class SessionManager():
self._running = False self._running = False
self._driver = None self._driver = None
self._client = None self._client = None
self._config: codemp.Config | None = None
def is_init(self): def is_init(self):
return self._running and self._driver is not None return self._running and self._driver is not None
@ -21,6 +24,10 @@ class SessionManager():
def client(self): def client(self):
return some(self._client) return some(self._client)
@property
def config(self):
return some(self._config)
def get_or_init(self) -> codemp.Driver: def get_or_init(self) -> codemp.Driver:
if self._driver: if self._driver:
return self._driver return self._driver
@ -45,12 +52,15 @@ class SessionManager():
self._running = False self._running = False
self._driver = None self._driver = None
def connect(self, config: codemp.Config) -> codemp.Client: def connect(self, config: Optional[codemp.Config] = None) -> codemp.Client:
if not self.is_init(): if not self.is_init():
self.get_or_init() self.get_or_init()
self._client = codemp.connect(config).wait() if config:
self.config = config self._config = config
self._client = codemp.connect(self.config).wait()
logger.debug(f"Connected to '{self.config.host}' as user {self._client.current_user().name} (id: {self._client.current_user().id})") logger.debug(f"Connected to '{self.config.host}' as user {self._client.current_user().name} (id: {self._client.current_user().id})")
return self._client return self._client

View file

@ -58,7 +58,10 @@ def status_log(msg, popup=False):
print("[codemp] {}".format(msg)) print("[codemp] {}".format(msg))
if popup: if popup:
sublime.error_message(msg) sublime.error_message(msg)
def get_setting(key, default=None):
settings = sublime.load_settings('Codemp.sublime-settings')
return settings.get(key, default)
def rowcol_to_region(view, start, end): def rowcol_to_region(view, start, end):
a = view.text_point(start[0], start[1]) a = view.text_point(start[0], start[1])