From 0e789f4a9fb34db959eefc0a2f40cb5705b0ca5a Mon Sep 17 00:00:00 2001 From: Carlos Cordoba <ccordoba12@gmail.com> Date: Mon, 8 Jul 2024 17:49:30 -0500 Subject: [PATCH] IPython console: Use submenus in envs menu if there are more than 20 That way users will be able to easily go the category for which they want to start an env. --- spyder/plugins/ipythonconsole/api.py | 8 -- .../ipythonconsole/widgets/main_widget.py | 133 ++++++++++++++---- 2 files changed, 109 insertions(+), 32 deletions(-) diff --git a/spyder/plugins/ipythonconsole/api.py b/spyder/plugins/ipythonconsole/api.py index 5e4b4f2407b..ed19744783e 100644 --- a/spyder/plugins/ipythonconsole/api.py +++ b/spyder/plugins/ipythonconsole/api.py @@ -133,11 +133,3 @@ class IPythonConsoleWidgetCornerWidgets: ResetButton = "reset_button" InterruptButton = "interrupt_button" TimeElapsedLabel = "time_elapsed_label" - - -class EnvironmentConsolesMenuSections: - Default = "default_section" - Conda = "conda_section" - Pyenv = "pyenv_section" - Custom = "custom_section" - Other = "other_section" diff --git a/spyder/plugins/ipythonconsole/widgets/main_widget.py b/spyder/plugins/ipythonconsole/widgets/main_widget.py index 2bdbc03474d..6f1e7596454 100644 --- a/spyder/plugins/ipythonconsole/widgets/main_widget.py +++ b/spyder/plugins/ipythonconsole/widgets/main_widget.py @@ -37,7 +37,6 @@ from spyder.config.base import get_home_dir, running_under_pytest from spyder.plugins.ipythonconsole.api import ( ClientContextMenuActions, - EnvironmentConsolesMenuSections, IPythonConsoleWidgetActions, IPythonConsoleWidgetMenus, IPythonConsoleWidgetCornerWidgets, @@ -71,13 +70,27 @@ logger = logging.getLogger(__name__) -# ============================================================================= # ---- Constants -# ============================================================================= +# ----------------------------------------------------------------------------- MAIN_BG_COLOR = SpyderPalette.COLOR_BACKGROUND_1 +# Leaving these enums here because they don't need to be part of the public API +class EnvironmentConsolesSubmenus: + CondaMenu = 'conda_environments_menu' + PyenvMenu = 'pyenv_environment_menu' + CustomMenu = 'custom_environment_menu' -# --- Widgets + +class EnvironmentConsolesMenuSections: + Default = "default_section" + Conda = "conda_section" + Pyenv = "pyenv_section" + Custom = "custom_section" + Other = "other_section" + Submenus = "submenus_section" + + +# ---- Widgets # ---------------------------------------------------------------------------- class IPythonConsoleWidget(PluginMainWidget, CachedKernelMixin): """ @@ -367,7 +380,7 @@ def get_focus_widget(self): return client.get_control() def setup(self): - # --- Main menu + # --- Console environments menu self.console_environment_menu = self.create_menu( IPythonConsoleWidgetMenus.EnvironmentConsoles, _('New console in environment') @@ -381,7 +394,21 @@ def setup(self): self._update_environment_menu ) - # --- Options menu actions + # Submenus + self.conda_envs_menu = self.create_menu( + EnvironmentConsolesSubmenus.CondaMenu, + "Conda", + ) + self.pyenv_envs_menu = self.create_menu( + EnvironmentConsolesSubmenus.PyenvMenu, + "Pyenv", + ) + self.custom_envs_menu = self.create_menu( + EnvironmentConsolesSubmenus.CustomMenu, + _("Custom"), + ) + + # --- Main and options menu actions self.create_client_action = self.create_action( IPythonConsoleWidgetActions.CreateNewClient, text=_("New console (default settings)"), @@ -1132,7 +1159,11 @@ def _create_client_for_kernel(self): def _update_environment_menu(self): """Update submenu with entries for available interpreters.""" + # Clear menu and submenus before rebuilding them self.console_environment_menu.clear_actions() + self.conda_envs_menu.clear_actions() + self.pyenv_envs_menu.clear_actions() + self.custom_envs_menu.clear_actions() internal_action = None conda_actions = [] @@ -1200,37 +1231,91 @@ def _update_environment_menu(self): section=EnvironmentConsolesMenuSections.Default ) - # Add other envs to their respective sections but only if there are two - # or more per category. Otherwise we group them in a single section - # called "Other". We do that because having many menu sections with a - # single entry makes the UI look odd. - for action in conda_actions: + # Add other envs to their respective submenus or sections + max_actions_in_menu = 20 + n_categories = len( + [ + actions + for actions in [conda_actions, pyenv_actions, custom_actions] + if len(actions) > 0 + ] + ) + actions = conda_actions + pyenv_actions + custom_actions + + # We use submenus if there are more envs than we'd like to see + # displayed in the consoles menu, and there are at least two non-empty + # categories. + if len(actions) > max_actions_in_menu and n_categories > 1: + conda_menu = self.conda_envs_menu self.add_item_to_menu( - action, + conda_menu, menu=self.console_environment_menu, - section=EnvironmentConsolesMenuSections.Conda - if len(conda_actions) > 1 - else EnvironmentConsolesMenuSections.Other, + section=EnvironmentConsolesMenuSections.Submenus, ) - for action in pyenv_actions: + pyenv_menu = self.pyenv_envs_menu self.add_item_to_menu( - action, + pyenv_menu, menu=self.console_environment_menu, - section=EnvironmentConsolesMenuSections.Pyenv - if len(pyenv_actions) > 1 - else EnvironmentConsolesMenuSections.Other, + section=EnvironmentConsolesMenuSections.Submenus, ) - for action in custom_actions: + custom_menu = self.custom_envs_menu self.add_item_to_menu( - action, + custom_menu, menu=self.console_environment_menu, - section=EnvironmentConsolesMenuSections.Custom + section=EnvironmentConsolesMenuSections.Submenus, + ) + + # Submenus don't have sections + conda_section = pyenv_section = custom_section = None + else: + # If there are few envs, we add their actions to the consoles menu. + # But we use sections only if there are two or more envs per + # category. Otherwise we group them in a single section called + # "Other". We do that because having many menu sections with a + # single entry makes the UI look odd. + conda_menu = ( + pyenv_menu + ) = custom_menu = self.console_environment_menu + + conda_section = ( + EnvironmentConsolesMenuSections.Conda + if len(conda_actions) > 1 + else EnvironmentConsolesMenuSections.Other + ) + + pyenv_section = ( + EnvironmentConsolesMenuSections.Pyenv + if len(pyenv_actions) > 1 + else EnvironmentConsolesMenuSections.Other + ) + + custom_section = ( + EnvironmentConsolesMenuSections.Custom if len(custom_actions) > 1 - else EnvironmentConsolesMenuSections.Other, + else EnvironmentConsolesMenuSections.Other + ) + + # Add actions to menu or submenus + for action in actions: + if action in conda_actions: + menu = conda_menu + section = conda_section + elif action in pyenv_actions: + menu = pyenv_menu + section = pyenv_section + else: + menu = custom_menu + section = custom_section + + self.add_item_to_menu( + action, + menu=menu, + section=section, ) + # Render consoles menu and submenus self.console_environment_menu.render() def find_connection_file(self, connection_file):