6
6
import argparse
7
7
import inspect
8
8
import numbers
9
+ import sys
9
10
from collections import (
10
11
deque ,
11
12
)
13
+ from collections .abc import Sequence
12
14
from typing import (
13
15
IO ,
14
16
TYPE_CHECKING ,
15
17
cast ,
16
18
)
17
19
18
- from .ansi import (
19
- style_aware_wcswidth ,
20
- widest_line ,
21
- )
22
20
from .constants import (
23
21
INFINITY ,
24
22
)
23
+ from .rich_utils import (
24
+ Cmd2Console ,
25
+ Cmd2Style ,
26
+ )
25
27
26
28
if TYPE_CHECKING : # pragma: no cover
27
29
from .cmd2 import (
28
30
Cmd ,
29
31
)
30
32
33
+
34
+ from rich .box import SIMPLE_HEAD
35
+ from rich .table import Column , Table
36
+
31
37
from .argparse_custom import (
32
38
ChoicesCallable ,
33
39
ChoicesProviderFuncWithTokens ,
40
46
from .exceptions import (
41
47
CompletionError ,
42
48
)
43
- from .table_creator import (
44
- Column ,
45
- HorizontalAlignment ,
46
- SimpleTable ,
47
- )
48
49
49
- # If no descriptive header is supplied, then this will be used instead
50
- DEFAULT_DESCRIPTIVE_HEADER = 'Description'
50
+ # If no descriptive headers are supplied, then this will be used instead
51
+ DEFAULT_DESCRIPTIVE_HEADERS : Sequence [ str | Column ] = ( 'Description' ,)
51
52
52
53
# Name of the choice/completer function argument that, if present, will be passed a dictionary of
53
54
# command line tokens up through the token being completed mapped to their argparse destination name.
@@ -546,8 +547,6 @@ def _format_completions(self, arg_state: _ArgumentState, completions: list[str]
546
547
547
548
# Check if there are too many CompletionItems to display as a table
548
549
if len (completions ) <= self ._cmd2_app .max_completion_items :
549
- four_spaces = 4 * ' '
550
-
551
550
# If a metavar was defined, use that instead of the dest field
552
551
destination = arg_state .action .metavar if arg_state .action .metavar else arg_state .action .dest
553
552
@@ -560,39 +559,45 @@ def _format_completions(self, arg_state: _ArgumentState, completions: list[str]
560
559
tuple_index = min (len (destination ) - 1 , arg_state .count )
561
560
destination = destination [tuple_index ]
562
561
563
- desc_header = arg_state .action .get_descriptive_header () # type: ignore[attr-defined]
564
- if desc_header is None :
565
- desc_header = DEFAULT_DESCRIPTIVE_HEADER
566
-
567
- # Replace tabs with 4 spaces so we can calculate width
568
- desc_header = desc_header .replace ('\t ' , four_spaces )
562
+ desc_headers = cast (Sequence [str | Column ] | None , arg_state .action .get_descriptive_headers ()) # type: ignore[attr-defined]
563
+ if desc_headers is None :
564
+ desc_headers = DEFAULT_DESCRIPTIVE_HEADERS
569
565
570
- # Calculate needed widths for the token and description columns of the table
571
- token_width = style_aware_wcswidth (destination )
572
- desc_width = widest_line (desc_header )
573
-
574
- for item in completion_items :
575
- token_width = max (style_aware_wcswidth (item ), token_width )
576
-
577
- # Replace tabs with 4 spaces so we can calculate width
578
- item .description = item .description .replace ('\t ' , four_spaces )
579
- desc_width = max (widest_line (item .description ), desc_width )
580
-
581
- cols = []
582
- dest_alignment = HorizontalAlignment .RIGHT if all_nums else HorizontalAlignment .LEFT
583
- cols .append (
566
+ # Build all headers for the hint table
567
+ headers : list [Column ] = []
568
+ headers .append (
584
569
Column (
585
570
destination .upper (),
586
- width = token_width ,
587
- header_horiz_align = dest_alignment ,
588
- data_horiz_align = dest_alignment ,
571
+ justify = "right" if all_nums else "left" ,
572
+ no_wrap = True ,
589
573
)
590
574
)
591
- cols .append (Column (desc_header , width = desc_width ))
575
+ for desc_header in desc_headers :
576
+ header = (
577
+ desc_header
578
+ if isinstance (desc_header , Column )
579
+ else Column (
580
+ desc_header ,
581
+ overflow = "fold" ,
582
+ )
583
+ )
584
+ headers .append (header )
585
+
586
+ # Build the hint table
587
+ hint_table = Table (
588
+ * headers ,
589
+ box = SIMPLE_HEAD ,
590
+ show_edge = False ,
591
+ border_style = Cmd2Style .RULE_LINE ,
592
+ )
593
+ for item in completion_items :
594
+ hint_table .add_row (item , * item .descriptive_data )
592
595
593
- hint_table = SimpleTable (cols , divider_char = self ._cmd2_app .ruler )
594
- table_data = [[item , item .description ] for item in completion_items ]
595
- self ._cmd2_app .formatted_completions = hint_table .generate_table (table_data , row_spacing = 0 )
596
+ # Generate the hint table string
597
+ console = Cmd2Console (sys .stdout )
598
+ with console .capture () as capture :
599
+ console .print (hint_table )
600
+ self ._cmd2_app .formatted_completions = capture .get ()
596
601
597
602
# Return sorted list of completions
598
603
return cast (list [str ], completions )
0 commit comments