Skip to content

Commit 5ea6525

Browse files
committed
Added matches_sort_key member to cmd2
1 parent 559983d commit 5ea6525

File tree

3 files changed

+32
-16
lines changed

3 files changed

+32
-16
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 0.9.11 (TBD, 2019)
22
* Enhancements
33
* Simplified examples that illustrate ``argparse`` tab completion via ``AutoCompleter``
4+
* Added ``matches_sort_key`` to override the default way tab completion matches are sorted
45
* Deprecations
56
* Deprecated support for bash completion since this feature had slow performance. Also it relied on
67
``AutoCompleter`` which has since developed a dependency on ``cmd2`` methods.
@@ -9,7 +10,7 @@
910
requires that it can't be ``None``.
1011
* ``AutoCompleter`` no longer assumes ``CompletionItem`` results are sorted. Therefore you should follow the
1112
``cmd2`` convention of setting ``self.matches_sorted`` to True before returning the results if you have already
12-
sorted the ``CompletionItem`` list. Otherwise ``cmd2`` will just sort them alphabetically.
13+
sorted the ``CompletionItem`` list. Otherwise it will be sorted using ``self.matches_sort_key``.
1314

1415
## 0.9.10 (February 22, 2019)
1516
* Bug Fixes

cmd2/argparse_completer.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,19 @@ def my_completer(text: str, line: str, begidx: int, endidx:int, extra_param: str
6161
"""
6262

6363
import argparse
64-
from colorama import Fore
6564
import os
65+
import re as _re
6666
import sys
67-
from typing import List, Dict, Tuple, Callable, Union
68-
6967

7068
# imports copied from argparse to support our customized argparse functions
7169
from argparse import ZERO_OR_MORE, ONE_OR_MORE, ArgumentError, _, _get_action_name, SUPPRESS
70+
from typing import List, Dict, Tuple, Callable, Union
7271

73-
import re as _re
74-
72+
from colorama import Fore
73+
from wcwidth import wcswidth
7574

7675
from .rl_utils import rl_force_redisplay
7776

78-
7977
# attribute that can optionally added to an argparse argument (called an Action) to
8078
# define the completion choices for the argument. You may provide a Collection or a Function.
8179
ACTION_ARG_CHOICES = 'arg_choices'
@@ -588,12 +586,19 @@ def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._Argu
588586

589587
def _format_completions(self, action, completions: List[Union[str, CompletionItem]]) -> List[str]:
590588
if completions and len(completions) > 1 and isinstance(completions[0], CompletionItem):
591-
token_width = len(action.dest)
589+
590+
# If the user has not already sorted the CompletionItems, then do that now
591+
if not self._cmd2_app.matches_sorted:
592+
completions.sort(key=self._cmd2_app.matches_sort_key)
593+
self._cmd2_app.matches_sorted = True
594+
595+
token_width = wcswidth(action.dest)
592596
completions_with_desc = []
593597

594598
for item in completions:
595-
if len(item) > token_width:
596-
token_width = len(item)
599+
item_width = wcswidth(item)
600+
if item_width > token_width:
601+
token_width = item_width
597602

598603
term_size = os.get_terminal_size()
599604
fill_width = int(term_size.columns * .6) - (token_width + 2)

cmd2/cmd2.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ def __subclasshook__(cls, C):
129129
# All help functions start with this
130130
HELP_FUNC_PREFIX = 'help_'
131131

132+
# Sorting keys for strings
133+
ALPHABETICAL_SORT_KEY = utils.norm_fold
134+
NATURAL_SORT_KEY = utils.natural_keys
135+
132136

133137
def categorize(func: Union[Callable, Iterable], category: str) -> None:
134138
"""Categorize a function.
@@ -492,6 +496,12 @@ def __init__(self, completekey: str='tab', stdin=None, stdout=None, persistent_h
492496
if os.path.exists(startup_script) and os.path.getsize(startup_script) > 0:
493497
self.cmdqueue.append("load '{}'".format(startup_script))
494498

499+
# The default key for sorting tab completion matches. This only applies when the matches are not
500+
# already marked as sorted by setting self.matches_sorted to True. Its default value performs a
501+
# case-insensitive alphabetical sort. If natural sorting preferred, then set this to NATURAL_SORT_KEY.
502+
# Otherwise it can be set to any custom key to meet your needs.
503+
self.matches_sort_key = ALPHABETICAL_SORT_KEY
504+
495505
############################################################################################################
496506
# The following variables are used by tab-completion functions. They are reset each time complete() is run
497507
# in reset_completion_defaults() and it is up to completer functions to set them before returning results.
@@ -520,7 +530,7 @@ def __init__(self, completekey: str='tab', stdin=None, stdout=None, persistent_h
520530
self.matches_delimited = False
521531

522532
# Set to True before returning matches to complete() in cases where matches are sorted with custom ordering.
523-
# If False, then complete() will sort the matches alphabetically before they are displayed.
533+
# If False, then complete() will sort the matches using self.matches_sort_key before they are displayed.
524534
self.matches_sorted = False
525535

526536
# Set the pager(s) for use with the ppaged() method for displaying output using a pager
@@ -1119,8 +1129,8 @@ def complete_users() -> List[str]:
11191129
self.allow_appended_space = False
11201130
self.allow_closing_quote = False
11211131

1122-
# Sort the matches alphabetically before any trailing slashes are added
1123-
matches.sort(key=utils.norm_fold)
1132+
# Sort the matches before any trailing slashes are added
1133+
matches.sort(key=self.matches_sort_key)
11241134
self.matches_sorted = True
11251135

11261136
# Build display_matches and add a slash to directories
@@ -1560,10 +1570,10 @@ def complete(self, text: str, state: int) -> Optional[str]:
15601570

15611571
self.completion_matches[0] += str_to_append
15621572

1563-
# Sort matches alphabetically if they haven't already been sorted
1573+
# Sort matches if they haven't already been sorted
15641574
if not self.matches_sorted:
1565-
self.completion_matches.sort(key=utils.norm_fold)
1566-
self.display_matches.sort(key=utils.norm_fold)
1575+
self.completion_matches.sort(key=self.matches_sort_key)
1576+
self.display_matches.sort(key=self.matches_sort_key)
15671577
self.matches_sorted = True
15681578

15691579
try:

0 commit comments

Comments
 (0)