@@ -635,11 +635,14 @@ def _(event: Any) -> None: # pragma: no cover
635635 self ._in_prompt = False
636636 self ._in_prompt_lock = threading .Lock ()
637637
638- # Commands that have been disabled from use. This is to support commands that are only available
639- # during specific states of the application. This dictionary's keys are the command names and its
640- # values are DisabledCommand objects.
638+ # Commands disabled during specific application states
639+ # Key: Command name | Value: DisabledCommand object
641640 self .disabled_commands : dict [str , DisabledCommand ] = {}
642641
642+ # Categories of commands to be disabled
643+ # Key: Category name | Value: Message to display
644+ self .disabled_categories : dict [str , str ] = {}
645+
643646 # The default key for sorting string results. Its default value performs a case-insensitive alphabetical sort.
644647 # If natural sorting is preferred, then set this to NATURAL_SORT_KEY.
645648 # cmd2 uses this key for sorting:
@@ -830,6 +833,12 @@ def register_command_set(self, cmdset: CommandSet) -> None:
830833 if default_category and not hasattr (command_method , constants .CMD_ATTR_HELP_CATEGORY ):
831834 utils .categorize (command_method , default_category )
832835
836+ # If this command is in a disabled category, then disable it
837+ command_category = getattr (command_method , constants .CMD_ATTR_HELP_CATEGORY , None )
838+ if command_category in self .disabled_categories :
839+ message_to_print = self .disabled_categories [command_category ]
840+ self .disable_command (command , message_to_print )
841+
833842 self ._installed_command_sets .add (cmdset )
834843
835844 self ._register_subcommands (cmdset )
@@ -1876,31 +1885,45 @@ def delimiter_complete(
18761885 :return: a list of possible tab completions
18771886 """
18781887 matches = self .basic_complete (text , line , begidx , endidx , match_against )
1888+ if not matches :
1889+ return []
18791890
1880- # Display only the portion of the match that's being completed based on delimiter
1881- if matches :
1882- # Set this to True for proper quoting of matches with spaces
1883- self .matches_delimited = True
1891+ # Set this to True for proper quoting of matches with spaces
1892+ self .matches_delimited = True
18841893
1885- # Get the common beginning for the matches
1886- common_prefix = os .path .commonprefix (matches )
1887- prefix_tokens = common_prefix .split (delimiter )
1894+ # Get the common beginning for the matches
1895+ common_prefix = os .path .commonprefix (matches )
1896+ prefix_tokens = common_prefix .split (delimiter )
18881897
1889- # Calculate what portion of the match we are completing
1890- display_token_index = 0
1891- if prefix_tokens :
1892- display_token_index = len (prefix_tokens ) - 1
1898+ # Calculate what portion of the match we are completing
1899+ display_token_index = 0
1900+ if prefix_tokens :
1901+ display_token_index = len (prefix_tokens ) - 1
18931902
1894- # Get this portion for each match and store them in self.display_matches
1895- for cur_match in matches :
1896- match_tokens = cur_match .split (delimiter )
1897- display_token = match_tokens [display_token_index ]
1903+ # Remove from each match everything after where the user is completing.
1904+ # This approach can result in duplicates so we will filter those out.
1905+ unique_results : dict [str , str ] = {}
18981906
1899- if not display_token :
1900- display_token = delimiter
1901- self .display_matches .append (display_token )
1907+ for cur_match in matches :
1908+ match_tokens = cur_match .split (delimiter )
19021909
1903- return matches
1910+ filtered_match = delimiter .join (match_tokens [: display_token_index + 1 ])
1911+ display_match = match_tokens [display_token_index ]
1912+
1913+ # If there are more tokens, then we aren't done completing a full item
1914+ if len (match_tokens ) > display_token_index + 1 :
1915+ filtered_match += delimiter
1916+ display_match += delimiter
1917+ self .allow_appended_space = False
1918+ self .allow_closing_quote = False
1919+
1920+ if filtered_match not in unique_results :
1921+ unique_results [filtered_match ] = display_match
1922+
1923+ filtered_matches = list (unique_results .keys ())
1924+ self .display_matches = list (unique_results .values ())
1925+
1926+ return filtered_matches
19041927
19051928 def flag_based_complete (
19061929 self ,
@@ -5620,7 +5643,7 @@ def enable_command(self, command: str) -> None:
56205643
56215644 :param command: the command being enabled
56225645 """
5623- # If the commands is already enabled, then return
5646+ # If the command is already enabled, then return
56245647 if command not in self .disabled_commands :
56255648 return
56265649
@@ -5652,11 +5675,17 @@ def enable_category(self, category: str) -> None:
56525675
56535676 :param category: the category to enable
56545677 """
5678+ # If the category is already enabled, then return
5679+ if category not in self .disabled_categories :
5680+ return
5681+
56555682 for cmd_name in list (self .disabled_commands ):
56565683 func = self .disabled_commands [cmd_name ].command_function
56575684 if getattr (func , constants .CMD_ATTR_HELP_CATEGORY , None ) == category :
56585685 self .enable_command (cmd_name )
56595686
5687+ del self .disabled_categories [category ]
5688+
56605689 def disable_command (self , command : str , message_to_print : str ) -> None :
56615690 """Disable a command and overwrite its functions.
56625691
@@ -5667,7 +5696,7 @@ def disable_command(self, command: str, message_to_print: str) -> None:
56675696 command being disabled.
56685697 ex: message_to_print = f"{cmd2.COMMAND_NAME} is currently disabled"
56695698 """
5670- # If the commands is already disabled, then return
5699+ # If the command is already disabled, then return
56715700 if command in self .disabled_commands :
56725701 return
56735702
@@ -5706,13 +5735,19 @@ def disable_category(self, category: str, message_to_print: str) -> None:
57065735 of the command being disabled.
57075736 ex: message_to_print = f"{cmd2.COMMAND_NAME} is currently disabled"
57085737 """
5738+ # If the category is already disabled, then return
5739+ if category in self .disabled_categories :
5740+ return
5741+
57095742 all_commands = self .get_all_commands ()
57105743
57115744 for cmd_name in all_commands :
57125745 func = self .cmd_func (cmd_name )
57135746 if getattr (func , constants .CMD_ATTR_HELP_CATEGORY , None ) == category :
57145747 self .disable_command (cmd_name , message_to_print )
57155748
5749+ self .disabled_categories [category ] = message_to_print
5750+
57165751 def _report_disabled_command_usage (self , * _args : Any , message_to_print : str , ** _kwargs : Any ) -> None :
57175752 """Report when a disabled command has been run or had help called on it.
57185753
0 commit comments