diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2bda144e..fcc394f8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,9 +2,10 @@
 * Bug Fixes
     * Fixed bug where ``preparse`` wasn't getting called
 * Enhancements
-    * Improved implementation of lifecycle hooks to to support a plugin
+    * Improved implementation of lifecycle hooks to support a plugin
       framework, see ``docs/hooks.rst`` for details.
     * New dependency on ``attrs`` third party module
+    * Added ``matches_sorted`` member to support custom sorting of tab-completion matches
 * Deprecations
     * Deprecated the following hook methods, see ``hooks.rst`` for full details:
        * ``cmd2.Cmd.preparse()`` - equivilent functionality available
@@ -14,6 +15,10 @@
        * ``cmd2.Cmd.postparsing_postcmd()`` - equivilent functionality available
          via ``cmd2.Cmd.register_postcmd_hook()``
 
+## 0.8.9 (August TBD, 2018)
+* Bug Fixes
+    * Fixed extra slash that could print when tab completing users on Windows
+
 ## 0.9.3 (July 12, 2018)
 * Bug Fixes
     * Fixed bug when StatementParser ``__init__()`` was called with ``terminators`` equal to ``None``
diff --git a/README.md b/README.md
index a60f0a18..b2eb314c 100755
--- a/README.md
+++ b/README.md
@@ -34,7 +34,6 @@ Main Features
 - Ability to load commands at startup from an initialization script
 - Settable environment parameters
 - Parsing commands with arguments using `argparse`, including support for sub-commands
-- Sub-menu support via the ``AddSubmenu`` decorator
 - Unicode character support
 - Good tab-completion of commands, sub-commands, file system paths, and shell commands
 - Support for Python 3.4+ on Windows, macOS, and Linux
@@ -58,7 +57,7 @@ pip install -U cmd2
 ```
 
 cmd2 works with Python 3.4+ on Windows, macOS, and Linux. It is pure Python code with
-the only 3rd-party dependencies being on [attrs](https://github.com/python-attrs/attrs), 
+the only 3rd-party dependencies being on [attrs](https://github.com/python-attrs/attrs),
 [colorama](https://github.com/tartley/colorama), and [pyperclip](https://github.com/asweigart/pyperclip).
 Windows has an additional dependency on [pyreadline](https://pypi.python.org/pypi/pyreadline). Non-Windows platforms
 have an additional dependency on [wcwidth](https://pypi.python.org/pypi/wcwidth). Finally, Python
diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py
index 60af25de..1479a6bf 100755
--- a/cmd2/argparse_completer.py
+++ b/cmd2/argparse_completer.py
@@ -492,6 +492,7 @@ class AutoCompleter(object):
 
             self._cmd2_app.completion_header = header
             self._cmd2_app.display_matches = completions_with_desc
+            self._cmd2_app.matches_sorted = True
 
         return completions
 
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index d34e7161..7273286b 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -369,7 +369,7 @@ class Cmd(cmd.Cmd):
             except AttributeError:
                 pass
 
-		# initialize plugin system
+        # initialize plugin system
         # needs to be done before we call __init__(0)
         self._initialize_plugin_system()
 
@@ -482,11 +482,11 @@ class Cmd(cmd.Cmd):
         # in reset_completion_defaults() and it is up to completer functions to set them before returning results.
         ############################################################################################################
 
-        # If true and a single match is returned to complete(), then a space will be appended
+        # If True and a single match is returned to complete(), then a space will be appended
         # if the match appears at the end of the line
         self.allow_appended_space = True
 
-        # If true and a single match is returned to complete(), then a closing quote
+        # If True and a single match is returned to complete(), then a closing quote
         # will be added if there is an unmatched opening quote
         self.allow_closing_quote = True
 
@@ -504,6 +504,10 @@ class Cmd(cmd.Cmd):
         # quote matches that are completed in a delimited fashion
         self.matches_delimited = False
 
+        # Set to True before returning matches to complete() in cases where matches are sorted with custom ordering.
+        # If False, then complete() will sort the matches alphabetically before they are displayed.
+        self.matches_sorted = False
+
         # Set the pager(s) for use with the ppaged() method for displaying output using a pager
         if sys.platform.startswith('win'):
             self.pager = self.pager_chop = 'more'
@@ -678,6 +682,7 @@ class Cmd(cmd.Cmd):
         self.completion_header = ''
         self.display_matches = []
         self.matches_delimited = False
+        self.matches_sorted = False
 
         if rl_type == RlType.GNU:
             readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
@@ -994,12 +999,15 @@ class Cmd(cmd.Cmd):
             users = []
 
             # Windows lacks the pwd module so we can't get a list of users.
-            # Instead we will add a slash once the user enters text that
+            # Instead we will return a result once the user enters text that
             # resolves to an existing home directory.
             if sys.platform.startswith('win'):
                 expanded_path = os.path.expanduser(text)
                 if os.path.isdir(expanded_path):
-                    users.append(text + os.path.sep)
+                    user = text
+                    if add_trailing_sep_if_dir:
+                        user += os.path.sep
+                    users.append(user)
             else:
                 import pwd
 
@@ -1083,6 +1091,10 @@ class Cmd(cmd.Cmd):
             self.allow_appended_space = False
             self.allow_closing_quote = False
 
+        # Sort the matches before any trailing slashes are added
+        matches = utils.alphabetical_sort(matches)
+        self.matches_sorted = True
+
         # Build display_matches and add a slash to directories
         for index, cur_match in enumerate(matches):
 
@@ -1446,11 +1458,8 @@ class Cmd(cmd.Cmd):
                 if self.completion_matches:
 
                     # Eliminate duplicates
-                    matches_set = set(self.completion_matches)
-                    self.completion_matches = list(matches_set)
-
-                    display_matches_set = set(self.display_matches)
-                    self.display_matches = list(display_matches_set)
+                    self.completion_matches = utils.remove_duplicates(self.completion_matches)
+                    self.display_matches = utils.remove_duplicates(self.display_matches)
 
                     if not self.display_matches:
                         # Since self.display_matches is empty, set it to self.completion_matches
@@ -1521,10 +1530,11 @@ class Cmd(cmd.Cmd):
 
                 self.completion_matches[0] += str_to_append
 
-            # Otherwise sort matches
-            elif self.completion_matches:
-                self.completion_matches.sort()
-                self.display_matches.sort()
+            # Sort matches alphabetically if they haven't already been sorted
+            if not self.matches_sorted:
+                self.completion_matches = utils.alphabetical_sort(self.completion_matches)
+                self.display_matches = utils.alphabetical_sort(self.display_matches)
+                self.matches_sorted = True
 
         try:
             return self.completion_matches[state]
@@ -2270,7 +2280,7 @@ Usage:  Usage: unalias [-a] name [name ...]
 
         else:
             # Get rid of duplicates
-            arglist = list(set(arglist))
+            arglist = utils.remove_duplicates(arglist)
 
             for cur_arg in arglist:
                 if cur_arg in self.aliases:
@@ -2315,12 +2325,10 @@ Usage:  Usage: unalias [-a] name [name ...]
         """Show a list of commands which help can be displayed for.
         """
         # Get a sorted list of help topics
-        help_topics = self.get_help_topics()
-        help_topics.sort()
+        help_topics = utils.alphabetical_sort(self.get_help_topics())
 
         # Get a sorted list of visible command names
-        visible_commands = self.get_visible_commands()
-        visible_commands.sort()
+        visible_commands = utils.alphabetical_sort(self.get_visible_commands())
 
         cmds_doc = []
         cmds_undoc = []
diff --git a/cmd2/utils.py b/cmd2/utils.py
index d03e7f6f..02956f6b 100644
--- a/cmd2/utils.py
+++ b/cmd2/utils.py
@@ -5,6 +5,7 @@
 import collections
 import os
 from typing import Any, List, Optional, Union
+import unicodedata
 
 from . import constants
 
@@ -110,7 +111,7 @@ def which(editor: str) -> Optional[str]:
 
 
 def is_text_file(file_path: str) -> bool:
-    """Returns if a file contains only ASCII or UTF-8 encoded text
+    """Returns if a file contains only ASCII or UTF-8 encoded text.
 
     :param file_path: path to the file being checked
     :return: True if the file is a text file, False if it is binary.
@@ -144,3 +145,34 @@ def is_text_file(file_path: str) -> bool:
             pass
 
     return valid_text_file
+
+
+def remove_duplicates(list_to_prune: List) -> List:
+    """Removes duplicates from a list while preserving order of the items.
+
+    :param list_to_prune: the list being pruned of duplicates
+    :return: The pruned list
+    """
+    temp_dict = collections.OrderedDict()
+    for item in list_to_prune:
+        temp_dict[item] = None
+
+    return list(temp_dict.keys())
+
+
+def norm_fold(astr: str) -> str:
+    """Normalize and casefold Unicode strings for saner comparisons.
+
+    :param astr: input unicode string
+    :return: a normalized and case-folded version of the input string
+    """
+    return unicodedata.normalize('NFC', astr).casefold()
+
+
+def alphabetical_sort(list_to_sort: List[str]) -> List[str]:
+    """Sorts a list of strings alphabetically.
+
+    :param list_to_sort: the list being sorted
+    :return: the sorted list
+    """
+    return sorted(list_to_sort, key=norm_fold)
diff --git a/examples/tab_autocompletion.py b/examples/tab_autocompletion.py
index 342cfff5..38972358 100755
--- a/examples/tab_autocompletion.py
+++ b/examples/tab_autocompletion.py
@@ -38,7 +38,7 @@ class TabCompleteExample(cmd2.Cmd):
     static_list_directors = ['J. J. Abrams', 'Irvin Kershner', 'George Lucas', 'Richard Marquand',
                              'Rian Johnson', 'Gareth Edwards']
     USER_MOVIE_LIBRARY = ['ROGUE1', 'SW_EP04', 'SW_EP05']
-    MOVIE_DATABASE_IDS = ['SW_EP01', 'SW_EP02', 'SW_EP03', 'ROGUE1', 'SW_EP04',
+    MOVIE_DATABASE_IDS = ['SW_EP1', 'SW_EP02', 'SW_EP03', 'ROGUE1', 'SW_EP04',
                           'SW_EP05', 'SW_EP06', 'SW_EP07', 'SW_EP08', 'SW_EP09']
     MOVIE_DATABASE = {'SW_EP04': {'title': 'Star Wars: Episode IV - A New Hope',
                                   'rating': 'PG',
@@ -52,13 +52,13 @@ class TabCompleteExample(cmd2.Cmd):
                                   'actor': ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher',
                                             'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels']
                                   },
-                      'SW_EP06': {'title': 'Star Wars: Episode IV - A New Hope',
+                      'SW_EP06': {'title': 'Star Wars: Episode VI - Return of the Jedi',
                                   'rating': 'PG',
                                   'director': ['Richard Marquand'],
                                   'actor': ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher',
                                             'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels']
                                   },
-                      'SW_EP01': {'title': 'Star Wars: Episode I - The Phantom Menace',
+                      'SW_EP1': {'title': 'Star Wars: Episode I - The Phantom Menace',
                                   'rating': 'PG',
                                   'director': ['George Lucas'],
                                   'actor': ['Liam Neeson', 'Ewan McGregor', 'Natalie Portman', 'Jake Lloyd']
@@ -113,8 +113,10 @@ class TabCompleteExample(cmd2.Cmd):
         """Demonstrates showing tabular hinting of tab completion information"""
         completions_with_desc = []
 
-        for movie_id, movie_entry in self.MOVIE_DATABASE.items():
-            completions_with_desc.append(argparse_completer.CompletionItem(movie_id, movie_entry['title']))
+        for movie_id in self.MOVIE_DATABASE_IDS:
+            if movie_id in self.MOVIE_DATABASE:
+                movie_entry = self.MOVIE_DATABASE[movie_id]
+                completions_with_desc.append(argparse_completer.CompletionItem(movie_id, movie_entry['title']))
 
         return completions_with_desc
 

Add ability to custom sort tab-completion matches
Currently the `complete()` method sorts tab-completion matches in all cases where there is more than one match. There are cases where a user has a custom sort order and already returns the matches to `complete()` in that preferred order. Add a flag like `self.matches_already_sorted` that overrides the sorting in `complete()`.
diff --git a/tests/test_completion.py b/tests/test_completion.py
index 2faa4a08..00a120cc 100644
--- a/tests/test_completion.py
+++ b/tests/test_completion.py
@@ -14,6 +14,7 @@ import sys
 
 import pytest
 import cmd2
+from cmd2 import utils
 from .conftest import complete_tester, StdOut
 from examples.subcommands import SubcommandsExample
 
@@ -251,7 +252,7 @@ def test_path_completion_multiple(cmd2_app, request):
     endidx = len(line)
     begidx = endidx - len(text)
 
-    matches = sorted(cmd2_app.path_complete(text, line, begidx, endidx))
+    matches = cmd2_app.path_complete(text, line, begidx, endidx)
     expected = [text + 'cript.py', text + 'cript.txt', text + 'cripts' + os.path.sep]
     assert matches == expected
 
@@ -408,9 +409,8 @@ def test_delimiter_completion(cmd2_app):
     cmd2_app.delimiter_complete(text, line, begidx, endidx, delimited_strs, '/')
 
     # Remove duplicates from display_matches and sort it. This is typically done in complete().
-    display_set = set(cmd2_app.display_matches)
-    display_list = list(display_set)
-    display_list.sort()
+    display_list = utils.remove_duplicates(cmd2_app.display_matches)
+    display_list = utils.alphabetical_sort(display_list)
 
     assert display_list == ['other user', 'user']
 
diff --git a/tests/test_utils.py b/tests/test_utils.py
new file mode 100644
index 00000000..61fd8373
--- /dev/null
+++ b/tests/test_utils.py
@@ -0,0 +1,52 @@
+# coding=utf-8
+"""
+Unit testing for cmd2/utils.py module.
+
+Copyright 2018 Todd Leonhardt <todd.leonhardt@gmail.com>
+Released under MIT license, see LICENSE file
+"""
+from colorama import Fore
+import cmd2.utils as cu
+
+HELLO_WORLD = 'Hello, world!'
+
+
+def test_strip_ansi():
+    base_str = HELLO_WORLD
+    ansi_str =  Fore.GREEN + base_str + Fore.RESET
+    assert base_str != ansi_str
+    assert base_str == cu.strip_ansi(ansi_str)
+
+def test_strip_quotes_no_quotes():
+    base_str = HELLO_WORLD
+    stripped = cu.strip_quotes(base_str)
+    assert base_str == stripped
+
+def test_strip_quotes_with_quotes():
+    base_str = '"' + HELLO_WORLD + '"'
+    stripped = cu.strip_quotes(base_str)
+    assert stripped == HELLO_WORLD
+
+def test_remove_duplicates_no_duplicates():
+    no_dups = [5, 4, 3, 2, 1]
+    assert cu.remove_duplicates(no_dups) == no_dups
+
+def test_remove_duplicates_with_duplicates():
+    duplicates = [1, 1, 2, 3, 9, 9, 7, 8]
+    assert cu.remove_duplicates(duplicates) == [1, 2, 3, 9, 7, 8]
+
+def test_unicode_normalization():
+    s1 = 'café'
+    s2 = 'cafe\u0301'
+    assert s1 != s2
+    assert cu.norm_fold(s1) == cu.norm_fold(s2)
+
+def test_unicode_casefold():
+    micro = 'µ'
+    micro_cf = micro.casefold()
+    assert micro != micro_cf
+    assert cu.norm_fold(micro) == cu.norm_fold(micro_cf)
+
+def test_alphabetical_sort():
+    my_list = ['café', 'µ', 'A' , 'micro', 'unity', 'cafeteria']
+    assert cu.alphabetical_sort(my_list) == ['A', 'cafeteria', 'café', 'micro', 'unity', 'µ']

pip install -e .[dev]
parse_log_pytest
pytest
pytest pytest-cov pytest-mock
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
anyio==4.9.0
astroid==3.3.9
attrs==25.3.0
babel==2.17.0
backports.tarfile==1.2.0
cachetools==5.5.2
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
click==8.1.8
-e git+https://github.com/python-cmd2/cmd2.git@bc559df2afcc51d1804e5d068d7e2c57bc4f72af#egg=cmd2
codecov==2.1.13
colorama==0.4.6
coverage==7.8.0
cryptography==44.0.2
dill==0.3.9
distlib==0.3.9
docutils==0.21.2
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
filelock==3.18.0
h11==0.14.0
id==1.5.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
invoke==2.2.0
isort==6.0.1
jaraco.classes==3.4.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jeepney==0.9.0
Jinja2==3.1.6
keyring==25.6.0
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mccabe==0.7.0
mdurl==0.1.2
more-itertools==10.6.0
nh3==0.2.21
packaging @ file:///croot/packaging_1734472117206/work
platformdirs==4.3.7
pluggy @ file:///croot/pluggy_1733169602837/work
pycparser==2.22
Pygments==2.19.1
pylint==3.3.6
pyperclip==1.9.0
pyproject-api==1.9.0
pytest @ file:///croot/pytest_1738938843180/work
pytest-cov==6.0.0
pytest-mock==3.14.0
readme_renderer==44.0
requests==2.32.3
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==14.0.0
SecretStorage==3.3.3
sniffio==1.3.1
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-autobuild==2024.10.3
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
starlette==0.46.1
tomli==2.2.1
tomlkit==0.13.2
tox==4.25.0
twine==6.1.0
typing_extensions==4.13.0
urllib3==2.3.0
uvicorn==0.34.0
virtualenv==20.29.3
watchfiles==1.0.4
wcwidth==0.2.13
websockets==15.0.1
zipp==3.21.0

name: cmd2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - anyio==4.9.0
      - astroid==3.3.9
      - attrs==25.3.0
      - babel==2.17.0
      - backports-tarfile==1.2.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cffi==1.17.1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - codecov==2.1.13
      - colorama==0.4.6
      - coverage==7.8.0
      - cryptography==44.0.2
      - dill==0.3.9
      - distlib==0.3.9
      - docutils==0.21.2
      - filelock==3.18.0
      - h11==0.14.0
      - id==1.5.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - invoke==2.2.0
      - isort==6.0.1
      - jaraco-classes==3.4.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jeepney==0.9.0
      - jinja2==3.1.6
      - keyring==25.6.0
      - markdown-it-py==3.0.0
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - mdurl==0.1.2
      - more-itertools==10.6.0
      - nh3==0.2.21
      - platformdirs==4.3.7
      - pycparser==2.22
      - pygments==2.19.1
      - pylint==3.3.6
      - pyperclip==1.9.0
      - pyproject-api==1.9.0
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - readme-renderer==44.0
      - requests==2.32.3
      - requests-toolbelt==1.0.0
      - rfc3986==2.0.0
      - rich==14.0.0
      - secretstorage==3.3.3
      - sniffio==1.3.1
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-autobuild==2024.10.3
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - starlette==0.46.1
      - tomli==2.2.1
      - tomlkit==0.13.2
      - tox==4.25.0
      - twine==6.1.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - uvicorn==0.34.0
      - virtualenv==20.29.3
      - watchfiles==1.0.4
      - wcwidth==0.2.13
      - websockets==15.0.1
      - zipp==3.21.0
prefix: /opt/conda/envs/cmd2

tests/test_completion.py::test_path_completion_multiple tests/test_completion.py::test_delimiter_completion tests/test_utils.py::test_remove_duplicates_no_duplicates tests/test_utils.py::test_remove_duplicates_with_duplicates tests/test_utils.py::test_unicode_normalization tests/test_utils.py::test_unicode_casefold tests/test_utils.py::test_alphabetical_sort
tests/test_completion.py::test_cmd2_command_completion_single tests/test_completion.py::test_complete_command_single tests/test_completion.py::test_complete_empty_arg tests/test_completion.py::test_complete_bogus_command tests/test_completion.py::test_cmd2_command_completion_multiple tests/test_completion.py::test_cmd2_command_completion_nomatch tests/test_completion.py::test_cmd2_help_completion_single tests/test_completion.py::test_cmd2_help_completion_multiple tests/test_completion.py::test_cmd2_help_completion_nomatch tests/test_completion.py::test_shell_command_completion_shortcut tests/test_completion.py::test_shell_command_completion_doesnt_match_wildcards tests/test_completion.py::test_shell_command_completion_multiple tests/test_completion.py::test_shell_command_completion_nomatch tests/test_completion.py::test_shell_command_completion_doesnt_complete_when_just_shell tests/test_completion.py::test_shell_command_completion_does_path_completion_when_after_command tests/test_completion.py::test_path_completion_single_end tests/test_completion.py::test_path_completion_nomatch tests/test_completion.py::test_default_to_shell_completion tests/test_completion.py::test_path_completion_cwd tests/test_completion.py::test_path_completion_doesnt_match_wildcards tests/test_completion.py::test_path_completion_complete_user tests/test_completion.py::test_path_completion_user_path_expansion tests/test_completion.py::test_path_completion_directories_only tests/test_completion.py::test_basic_completion_single tests/test_completion.py::test_basic_completion_multiple tests/test_completion.py::test_basic_completion_nomatch tests/test_completion.py::test_flag_based_completion_single tests/test_completion.py::test_flag_based_completion_multiple tests/test_completion.py::test_flag_based_completion_nomatch tests/test_completion.py::test_flag_based_default_completer tests/test_completion.py::test_flag_based_callable_completer tests/test_completion.py::test_index_based_completion_single tests/test_completion.py::test_index_based_completion_multiple tests/test_completion.py::test_index_based_completion_nomatch tests/test_completion.py::test_index_based_default_completer tests/test_completion.py::test_index_based_callable_completer tests/test_completion.py::test_tokens_for_completion_quoted tests/test_completion.py::test_tokens_for_completion_unclosed_quote tests/test_completion.py::test_tokens_for_completion_redirect tests/test_completion.py::test_tokens_for_completion_quoted_redirect tests/test_completion.py::test_tokens_for_completion_redirect_off tests/test_completion.py::test_add_opening_quote_basic_no_text tests/test_completion.py::test_add_opening_quote_basic_nothing_added tests/test_completion.py::test_add_opening_quote_basic_quote_added tests/test_completion.py::test_add_opening_quote_basic_text_is_common_prefix tests/test_completion.py::test_add_opening_quote_delimited_no_text tests/test_completion.py::test_add_opening_quote_delimited_nothing_added tests/test_completion.py::test_add_opening_quote_delimited_quote_added tests/test_completion.py::test_add_opening_quote_delimited_text_is_common_prefix tests/test_completion.py::test_add_opening_quote_delimited_space_in_prefix tests/test_completion.py::test_cmd2_subcommand_completion_single_end tests/test_completion.py::test_cmd2_subcommand_completion_multiple tests/test_completion.py::test_cmd2_subcommand_completion_nomatch tests/test_completion.py::test_cmd2_help_subcommand_completion_single tests/test_completion.py::test_cmd2_help_subcommand_completion_multiple tests/test_completion.py::test_cmd2_help_subcommand_completion_nomatch tests/test_completion.py::test_subcommand_tab_completion tests/test_completion.py::test_subcommand_tab_completion_with_no_completer tests/test_completion.py::test_subcommand_tab_completion_space_in_text tests/test_completion.py::test_cmd2_subcmd_with_unknown_completion_single_end tests/test_completion.py::test_cmd2_subcmd_with_unknown_completion_multiple tests/test_completion.py::test_cmd2_subcmd_with_unknown_completion_nomatch tests/test_completion.py::test_cmd2_help_subcommand_completion_single_scu tests/test_completion.py::test_cmd2_help_subcommand_completion_multiple_scu tests/test_completion.py::test_cmd2_help_subcommand_completion_nomatch_scu tests/test_completion.py::test_subcommand_tab_completion_scu tests/test_completion.py::test_subcommand_tab_completion_with_no_completer_scu tests/test_completion.py::test_subcommand_tab_completion_space_in_text_scu tests/test_utils.py::test_strip_ansi tests/test_utils.py::test_strip_quotes_no_quotes tests/test_utils.py::test_strip_quotes_with_quotes
cmd2/cmd2.py examples/tab_autocompletion.py CHANGELOG.md README.md cmd2/argparse_completer.py cmd2/utils.py
cmd2/cmd2.py examples/tab_autocompletion.py CHANGELOG.md README.md cmd2/argparse_completer.py cmd2/utils.py