66import argparse
77import inspect
88import numbers
9+ import sys
910from collections import (
1011 deque ,
1112)
13+ from collections .abc import Sequence
1214from typing import (
1315 IO ,
1416 TYPE_CHECKING ,
1517 cast ,
1618)
1719
18- from .ansi import (
19- style_aware_wcswidth ,
20- widest_line ,
21- )
2220from .constants import (
2321 INFINITY ,
2422)
23+ from .rich_utils import (
24+ Cmd2Console ,
25+ Cmd2Style ,
26+ )
2527
2628if TYPE_CHECKING : # pragma: no cover
2729 from .cmd2 import (
2830 Cmd ,
2931 )
3032
33+
34+ from rich .box import SIMPLE_HEAD
35+ from rich .table import Column , Table
36+
3137from .argparse_custom import (
3238 ChoicesCallable ,
3339 ChoicesProviderFuncWithTokens ,
4046from .exceptions import (
4147 CompletionError ,
4248)
43- from .table_creator import (
44- Column ,
45- HorizontalAlignment ,
46- SimpleTable ,
47- )
4849
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' ,)
5152
5253# Name of the choice/completer function argument that, if present, will be passed a dictionary of
5354# 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]
546547
547548 # Check if there are too many CompletionItems to display as a table
548549 if len (completions ) <= self ._cmd2_app .max_completion_items :
549- four_spaces = 4 * ' '
550-
551550 # If a metavar was defined, use that instead of the dest field
552551 destination = arg_state .action .metavar if arg_state .action .metavar else arg_state .action .dest
553552
@@ -560,39 +559,45 @@ def _format_completions(self, arg_state: _ArgumentState, completions: list[str]
560559 tuple_index = min (len (destination ) - 1 , arg_state .count )
561560 destination = destination [tuple_index ]
562561
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
569565
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 (
584569 Column (
585570 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 ,
589573 )
590574 )
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 )
592595
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 ()
596601
597602 # Return sorted list of completions
598603 return cast (list [str ], completions )
0 commit comments