diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d49d34e..6bf3c961 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@
         * Enables applications to return a non-zero exit code when exiting from ``cmdloop``
     * ``ACHelpFormatter`` now inherits from ``argparse.RawTextHelpFormatter`` to make it easier
     for formatting help/description text
+    * Aliases are now sorted alphabetically
+    * The **set** command now tab-completes settable parameter names
     
 ## 0.9.4 (August 21, 2018)
 * Bug Fixes
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 49ac91a5..8b1cabc9 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -45,7 +45,7 @@ from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, Un
 from . import constants
 from . import utils
 from . import plugin
-from .argparse_completer import AutoCompleter, ACArgumentParser
+from .argparse_completer import AutoCompleter, ACArgumentParser, ACTION_ARG_CHOICES
 from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer
 from .parsing import StatementParser, Statement
 
@@ -2284,6 +2284,9 @@ Usage:  Usage: alias [name] | [<name> <value>]
                 # Set the alias
                 self.aliases[name] = value
                 self.poutput("Alias {!r} created".format(name))
+
+                # Keep aliases in alphabetically sorted order
+                self.aliases = collections.OrderedDict(sorted(self.aliases.items()))
             else:
                 errmsg = "Aliases can not contain: {}".format(invalidchars)
                 self.perror(errmsg, traceback_war=False)
@@ -2541,22 +2544,21 @@ Usage:  Usage: unalias [-a] name [name ...]
         Output redirection and pipes allowed: {}"""
         return read_only_settings.format(str(self.terminators), self.allow_cli_args, self.allow_redirection)
 
-    def show(self, args: argparse.Namespace, parameter: str) -> None:
+    def show(self, args: argparse.Namespace, parameter: str='') -> None:
         """Shows current settings of parameters.
 
         :param args: argparse parsed arguments from the set command
-        :param parameter:
-        :return:
+        :param parameter: optional search parameter
         """
-        param = ''
-        if parameter:
-            param = parameter.strip().lower()
+        param = parameter.strip().lower()
         result = {}
         maxlen = 0
+
         for p in self.settable:
             if (not param) or p.startswith(param):
-                result[p] = '%s: %s' % (p, str(getattr(self, p)))
+                result[p] = '{}: {}'.format(p, str(getattr(self, p)))
                 maxlen = max(maxlen, len(result[p]))
+
         if result:
             for p in sorted(result):
                 if args.long:
@@ -2568,7 +2570,7 @@ Usage:  Usage: unalias [-a] name [name ...]
             if args.all:
                 self.poutput('\nRead only settings:{}'.format(self.cmdenvironment()))
         else:
-            raise LookupError("Parameter '%s' not supported (type 'set' for list of parameters)." % param)
+            raise LookupError("Parameter '{}' not supported (type 'set' for list of parameters).".format(param))
 
     set_description = "Sets a settable parameter or shows current settings of parameters.\n"
     set_description += "\n"
@@ -2578,39 +2580,44 @@ Usage:  Usage: unalias [-a] name [name ...]
     set_parser = ACArgumentParser(description=set_description)
     set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well')
     set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter')
-    set_parser.add_argument('settable', nargs=(0, 2), help='[param_name] [value]')
+    setattr(set_parser.add_argument('param', nargs='?', help='parameter to set or view'),
+            ACTION_ARG_CHOICES, settable)
+    set_parser.add_argument('value', nargs='?', help='the new value for settable')
 
     @with_argparser(set_parser)
     def do_set(self, args: argparse.Namespace) -> None:
         """Sets a settable parameter or shows current settings of parameters"""
-        try:
-            param_name, val = args.settable
-            val = val.strip()
-            param_name = param_name.strip().lower()
-            if param_name not in self.settable:
-                hits = [p for p in self.settable if p.startswith(param_name)]
-                if len(hits) == 1:
-                    param_name = hits[0]
-                else:
-                    return self.show(args, param_name)
-            current_val = getattr(self, param_name)
-            if (val[0] == val[-1]) and val[0] in ("'", '"'):
-                val = val[1:-1]
+
+        # Check if param was passed in
+        if not args.param:
+            return self.show(args)
+        param = args.param.strip().lower()
+
+        # Check if value was passed in
+        if not args.value:
+            return self.show(args, param)
+        value = args.value
+
+        # Check if param points to just one settable
+        if param not in self.settable:
+            hits = [p for p in self.settable if p.startswith(param)]
+            if len(hits) == 1:
+                param = hits[0]
             else:
-                val = utils.cast(current_val, val)
-            setattr(self, param_name, val)
-            self.poutput('%s - was: %s\nnow: %s\n' % (param_name, current_val, val))
-            if current_val != val:
-                try:
-                    onchange_hook = getattr(self, '_onchange_%s' % param_name)
-                    onchange_hook(old=current_val, new=val)
-                except AttributeError:
-                    pass
-        except (ValueError, AttributeError):
-            param = ''
-            if args.settable:
-                param = args.settable[0]
-            self.show(args, param)
+                return self.show(args, param)
+
+        # Update the settable's value
+        current_value = getattr(self, param)
+        value = utils.cast(current_value, value)
+        setattr(self, param, value)
+
+        self.poutput('{} - was: {}\nnow: {}\n'.format(param, current_value, value))
+
+        # See if we need to call a change hook for this settable
+        if current_value != value:
+            onchange_hook = getattr(self, '_onchange_{}'.format(param), None)
+            if onchange_hook is not None:
+                onchange_hook(old=current_value, new=value)
 
     def do_shell(self, statement: Statement) -> None:
         """Execute a command as if at the OS prompt
diff --git a/cmd2/utils.py b/cmd2/utils.py
index 64401895..9d71d061 100644
--- a/cmd2/utils.py
+++ b/cmd2/utils.py
@@ -20,6 +20,28 @@ def strip_ansi(text: str) -> str:
     return constants.ANSI_ESCAPE_RE.sub('', text)
 
 
+def is_quoted(arg: str) -> bool:
+    """
+    Checks if a string is quoted
+    :param arg: the string being checked for quotes
+    :return: True if a string is quoted
+    """
+    return len(arg) > 1 and arg[0] == arg[-1] and arg[0] in constants.QUOTES
+
+
+def quote_string_if_needed(arg: str) -> str:
+    """ Quotes a string if it contains spaces and isn't already quoted """
+    if is_quoted(arg) or ' ' not in arg:
+        return arg
+
+    if '"' in arg:
+        quote = "'"
+    else:
+        quote = '"'
+
+    return quote + arg + quote
+
+
 def strip_quotes(arg: str) -> str:
     """ Strip outer quotes from a string.
 
@@ -28,7 +50,7 @@ def strip_quotes(arg: str) -> str:
     :param arg:  string to strip outer quotes from
     :return: same string with potentially outer quotes stripped
     """
-    if len(arg) > 1 and arg[0] == arg[-1] and arg[0] in constants.QUOTES:
+    if is_quoted(arg):
         arg = arg[1:-1]
     return arg
 
@@ -71,6 +93,8 @@ def cast(current: Any, new: str) -> Any:
     :return: new value with same type as current, or the current value if there was an error casting
     """
     typ = type(current)
+    orig_new = new
+
     if typ == bool:
         try:
             return bool(int(new))
@@ -78,18 +102,18 @@ def cast(current: Any, new: str) -> Any:
             pass
         try:
             new = new.lower()
+            if (new == 'on') or (new[0] in ('y', 't')):
+                return True
+            if (new == 'off') or (new[0] in ('n', 'f')):
+                return False
         except AttributeError:
             pass
-        if (new == 'on') or (new[0] in ('y', 't')):
-            return True
-        if (new == 'off') or (new[0] in ('n', 'f')):
-            return False
     else:
         try:
             return typ(new)
         except (ValueError, TypeError):
             pass
-    print("Problem setting parameter (now %s) to %s; incorrect type?" % (current, new))
+    print("Problem setting parameter (now {}) to {}; incorrect type?".format(current, orig_new))
     return current
 
 

set command should support tab-completion of setting names
It would be helpful if the **set** command support tab-completion of setting names.
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index fdf0f661..1e7e2c3f 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -72,7 +72,7 @@ def test_base_invalid_option(base_app, capsys):
     out = normalize(out)
     err = normalize(err)
     assert 'Error: unrecognized arguments: -z' in err[0]
-    assert out[0] == 'Usage: set settable{0..2} [-h] [-a] [-l]'
+    assert out[0] == 'Usage: set [param] [value] [-h] [-a] [-l]'
 
 def test_base_shortcuts(base_app):
     out = run_cmd(base_app, 'shortcuts')
@@ -1804,6 +1804,24 @@ def test_create_invalid_alias(base_app, alias_name, capsys):
     out, err = capsys.readouterr()
     assert "can not contain" in err
 
+def test_complete_unalias(base_app):
+    text = 'f'
+    line = text
+    endidx = len(line)
+    begidx = endidx - len(text)
+
+    # Validate there are no completions when there are no aliases
+    assert base_app.complete_unalias(text, line, begidx, endidx) == []
+
+    # Create a few aliases - two the start with 'f' and one that doesn't
+    run_cmd(base_app, 'alias fall quit')
+    run_cmd(base_app, 'alias fake pyscript')
+    run_cmd(base_app, 'alias carapace shell')
+
+    # Validate that there are now completions
+    expected = ['fake', 'fall']
+    assert base_app.complete_unalias(text, line, begidx, endidx) == expected
+
 def test_ppaged(base_app):
     msg = 'testing...'
     end = '\n'
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 691abdf8..8c8daa39 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -76,3 +76,38 @@ def test_natural_sort():
     assert cu.natural_sort(my_list) == ['A', 'café', 'micro', 'unity', 'X0', 'x1', 'X2', 'X11', 'x22', 'µ']
     my_list = ['a3', 'a22', 'A2', 'A11', 'a1']
     assert cu.natural_sort(my_list) == ['a1', 'A2', 'a3', 'A11', 'a22']
+
+def test_is_quoted_short():
+    my_str = ''
+    assert not cu.is_quoted(my_str)
+    your_str = '"'
+    assert not cu.is_quoted(your_str)
+
+def test_is_quoted_yes():
+    my_str = '"This is a test"'
+    assert cu.is_quoted(my_str)
+    your_str = "'of the emergengy broadcast system'"
+    assert cu.is_quoted(your_str)
+
+def test_is_quoted_no():
+    my_str = '"This is a test'
+    assert not cu.is_quoted(my_str)
+    your_str = "of the emergengy broadcast system'"
+    assert not cu.is_quoted(your_str)
+    simple_str = "hello world"
+    assert not cu.is_quoted(simple_str)
+
+def test_quote_string_if_needed_yes():
+    my_str = "Hello World"
+    assert cu.quote_string_if_needed(my_str) == '"' + my_str + '"'
+    your_str = '"foo" bar'
+    assert cu.quote_string_if_needed(your_str) == "'" + your_str + "'"
+
+def test_quot_string_if_needed_no():
+    my_str = "HelloWorld"
+    assert cu.quote_string_if_needed(my_str) == my_str
+    your_str = "'Hello World'"
+    assert cu.quote_string_if_needed(your_str) == your_str
+
+
+

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-mock pytest-cov
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@e8bfe314440627ca878f48799ae2b28ccbf0a15f#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==1.2.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
iniconfig==2.1.0
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==24.2
platformdirs==4.3.7
pluggy==1.5.0
pycparser==2.22
Pygments==2.19.1
pylint==3.3.6
pyperclip==1.9.0
pyproject-api==1.9.0
pytest==8.3.5
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
  - 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
  - pip=25.0=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
      - exceptiongroup==1.2.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
      - iniconfig==2.1.0
      - 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==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pycparser==2.22
      - pygments==2.19.1
      - pylint==3.3.6
      - pyperclip==1.9.0
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - 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_cmd2.py::test_base_invalid_option tests/test_cmd2.py::test_complete_unalias tests/test_utils.py::test_is_quoted_short tests/test_utils.py::test_is_quoted_yes tests/test_utils.py::test_is_quoted_no tests/test_utils.py::test_quote_string_if_needed_yes tests/test_utils.py::test_quot_string_if_needed_no
tests/test_cmd2.py::test_which_editor_good
tests/test_cmd2.py::test_version tests/test_cmd2.py::test_empty_statement tests/test_cmd2.py::test_base_help tests/test_cmd2.py::test_base_help_verbose tests/test_cmd2.py::test_base_help_history tests/test_cmd2.py::test_base_argparse_help tests/test_cmd2.py::test_base_shortcuts tests/test_cmd2.py::test_base_show tests/test_cmd2.py::test_base_show_long tests/test_cmd2.py::test_base_show_readonly tests/test_cmd2.py::test_cast tests/test_cmd2.py::test_cast_problems tests/test_cmd2.py::test_base_set tests/test_cmd2.py::test_set_not_supported tests/test_cmd2.py::test_set_quiet tests/test_cmd2.py::test_base_shell tests/test_cmd2.py::test_base_py tests/test_cmd2.py::test_base_run_python_script tests/test_cmd2.py::test_base_run_pyscript tests/test_cmd2.py::test_recursive_pyscript_not_allowed tests/test_cmd2.py::test_pyscript_with_nonexist_file tests/test_cmd2.py::test_pyscript_with_exception tests/test_cmd2.py::test_pyscript_requires_an_argument tests/test_cmd2.py::test_base_error tests/test_cmd2.py::test_history_span tests/test_cmd2.py::test_history_get tests/test_cmd2.py::test_base_history tests/test_cmd2.py::test_history_script_format tests/test_cmd2.py::test_history_with_string_argument tests/test_cmd2.py::test_history_with_integer_argument tests/test_cmd2.py::test_history_with_integer_span tests/test_cmd2.py::test_history_with_span_start tests/test_cmd2.py::test_history_with_span_end tests/test_cmd2.py::test_history_with_span_index_error tests/test_cmd2.py::test_history_output_file tests/test_cmd2.py::test_history_edit tests/test_cmd2.py::test_history_run_all_commands tests/test_cmd2.py::test_history_run_one_command tests/test_cmd2.py::test_history_clear tests/test_cmd2.py::test_base_load tests/test_cmd2.py::test_load_with_empty_args tests/test_cmd2.py::test_load_with_nonexistent_file tests/test_cmd2.py::test_load_with_directory tests/test_cmd2.py::test_load_with_empty_file tests/test_cmd2.py::test_load_with_binary_file tests/test_cmd2.py::test_load_with_utf8_file tests/test_cmd2.py::test_load_nested_loads tests/test_cmd2.py::test_base_runcmds_plus_hooks tests/test_cmd2.py::test_base_relative_load tests/test_cmd2.py::test_relative_load_requires_an_argument tests/test_cmd2.py::test_output_redirection tests/test_cmd2.py::test_output_redirection_to_nonexistent_directory tests/test_cmd2.py::test_output_redirection_to_too_long_filename tests/test_cmd2.py::test_feedback_to_output_true tests/test_cmd2.py::test_feedback_to_output_false tests/test_cmd2.py::test_allow_redirection tests/test_cmd2.py::test_pipe_to_shell tests/test_cmd2.py::test_pipe_to_shell_error tests/test_cmd2.py::test_base_timing tests/test_cmd2.py::test_base_debug tests/test_cmd2.py::test_base_colorize tests/test_cmd2.py::test_edit_no_editor tests/test_cmd2.py::test_edit_file tests/test_cmd2.py::test_edit_file_with_spaces tests/test_cmd2.py::test_edit_blank tests/test_cmd2.py::test_base_py_interactive tests/test_cmd2.py::test_exclude_from_history tests/test_cmd2.py::test_base_cmdloop_with_queue tests/test_cmd2.py::test_base_cmdloop_without_queue tests/test_cmd2.py::test_cmdloop_without_rawinput tests/test_cmd2.py::test_precmd_hook_success tests/test_cmd2.py::test_precmd_hook_failure tests/test_cmd2.py::test_interrupt_quit tests/test_cmd2.py::test_interrupt_noquit tests/test_cmd2.py::test_default_to_shell_unknown tests/test_cmd2.py::test_default_to_shell_good tests/test_cmd2.py::test_default_to_shell_failure tests/test_cmd2.py::test_ansi_prompt_not_esacped tests/test_cmd2.py::test_ansi_prompt_escaped tests/test_cmd2.py::test_custom_command_help tests/test_cmd2.py::test_custom_help_menu tests/test_cmd2.py::test_help_undocumented tests/test_cmd2.py::test_help_overridden_method tests/test_cmd2.py::test_help_cat_base tests/test_cmd2.py::test_help_cat_verbose tests/test_cmd2.py::test_select_options tests/test_cmd2.py::test_select_invalid_option tests/test_cmd2.py::test_select_list_of_strings tests/test_cmd2.py::test_select_list_of_tuples tests/test_cmd2.py::test_select_uneven_list_of_tuples tests/test_cmd2.py::test_help_with_no_docstring tests/test_cmd2.py::test_which_editor_bad tests/test_cmd2.py::test_multiline_complete_empty_statement_raises_exception tests/test_cmd2.py::test_multiline_complete_statement_without_terminator tests/test_cmd2.py::test_multiline_complete_statement_with_unclosed_quotes tests/test_cmd2.py::test_clipboard_failure tests/test_cmd2.py::test_commandresult_truthy tests/test_cmd2.py::test_commandresult_falsy tests/test_cmd2.py::test_is_text_file_bad_input tests/test_cmd2.py::test_eof tests/test_cmd2.py::test_eos tests/test_cmd2.py::test_echo tests/test_cmd2.py::test_pseudo_raw_input_tty_rawinput_true tests/test_cmd2.py::test_pseudo_raw_input_tty_rawinput_false tests/test_cmd2.py::test_pseudo_raw_input_piped_rawinput_true_echo_true tests/test_cmd2.py::test_pseudo_raw_input_piped_rawinput_true_echo_false tests/test_cmd2.py::test_pseudo_raw_input_piped_rawinput_false_echo_true tests/test_cmd2.py::test_pseudo_raw_input_piped_rawinput_false_echo_false tests/test_cmd2.py::test_raw_input tests/test_cmd2.py::test_stdin_input tests/test_cmd2.py::test_empty_stdin_input tests/test_cmd2.py::test_poutput_string tests/test_cmd2.py::test_poutput_zero tests/test_cmd2.py::test_poutput_empty_string tests/test_cmd2.py::test_poutput_none tests/test_cmd2.py::test_alias tests/test_cmd2.py::test_alias_with_quotes tests/test_cmd2.py::test_alias_lookup_invalid_alias tests/test_cmd2.py::test_unalias tests/test_cmd2.py::test_unalias_all tests/test_cmd2.py::test_unalias_non_existing tests/test_cmd2.py::test_create_invalid_alias[">"] tests/test_cmd2.py::test_create_invalid_alias["no>pe"] tests/test_cmd2.py::test_create_invalid_alias["no tests/test_cmd2.py::test_create_invalid_alias["nopipe|"] tests/test_cmd2.py::test_create_invalid_alias["noterm;"] tests/test_cmd2.py::test_create_invalid_alias[noembedded"quotes] tests/test_cmd2.py::test_ppaged tests/test_cmd2.py::test_parseline_empty tests/test_cmd2.py::test_parseline tests/test_cmd2.py::test_readline_remove_history_item tests/test_cmd2.py::test_onecmd_raw_str_continue tests/test_cmd2.py::test_onecmd_raw_str_quit tests/test_cmd2.py::test_existing_history_file tests/test_cmd2.py::test_new_history_file tests/test_cmd2.py::test_bad_history_file_path tests/test_cmd2.py::test_get_all_commands tests/test_cmd2.py::test_get_help_topics tests/test_cmd2.py::test_exit_code_default tests/test_cmd2.py::test_exit_code_nonzero 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 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_utils.py::test_try_int_or_force_to_lower_case tests/test_utils.py::test_natural_keys tests/test_utils.py::test_natural_sort
cmd2/cmd2.py CHANGELOG.md cmd2/utils.py
cmd2/cmd2.py CHANGELOG.md cmd2/utils.py