77import pytest
88
99import cmd2
10+ import cmd2 .string_utils as su
1011from cmd2 import (
1112 Cmd2ArgumentParser ,
1213 CompletionError ,
1516 argparse_custom ,
1617 with_argparser ,
1718)
19+ from cmd2 import rich_utils as ru
1820
1921from .conftest import (
2022 complete_tester ,
2123 normalize ,
2224 run_cmd ,
25+ with_ansi_style ,
2326)
2427
2528# Data and functions for testing standalone choice_provider and completer
@@ -109,12 +112,18 @@ def do_pos_and_flag(self, args: argparse.Namespace) -> None:
109112 static_choices_list = ('static' , 'choices' , 'stop' , 'here' )
110113 choices_from_provider = ('choices' , 'provider' , 'probably' , 'improved' )
111114 completion_item_choices = (
112- CompletionItem ('choice_1' , ['A description' ]),
113- CompletionItem ('choice_2' , ['Another description' ]),
115+ CompletionItem ('choice_1' , ['Description 1' ]),
116+ # Make this the longest description so we can test display width.
117+ CompletionItem ('choice_2' , [su .stylize ("String with style" , style = cmd2 .Color .BLUE )]),
118+ CompletionItem ('choice_3' , [su .stylize ("Text with style" , style = cmd2 .Color .RED )]),
114119 )
115120
116121 # This tests that CompletionItems created with numerical values are sorted as numbers.
117- num_completion_items = (CompletionItem (5 , ["Five" ]), CompletionItem (1.5 , ["One.Five" ]), CompletionItem (2 , ["Five" ]))
122+ num_completion_items = (
123+ CompletionItem (5 , ["Five" ]),
124+ CompletionItem (1.5 , ["One.Five" ]),
125+ CompletionItem (2 , ["Five" ]),
126+ )
118127
119128 def choices_provider (self ) -> tuple [str ]:
120129 """Method that provides choices"""
@@ -704,6 +713,7 @@ def test_autocomp_blank_token(ac_app) -> None:
704713 assert sorted (completions ) == sorted (ArgparseCompleterTester .completions_for_pos_2 )
705714
706715
716+ @with_ansi_style (ru .AllowStyle .ALWAYS )
707717def test_completion_items (ac_app ) -> None :
708718 # First test CompletionItems created from strings
709719 text = ''
@@ -716,16 +726,20 @@ def test_completion_items(ac_app) -> None:
716726 assert len (ac_app .completion_matches ) == len (ac_app .completion_item_choices )
717727 assert len (ac_app .display_matches ) == len (ac_app .completion_item_choices )
718728
719- # Look for both the value and description in the hint table
720- line_found = False
721- for line in ac_app .formatted_completions .splitlines ():
722- # Since the CompletionItems were created from strings, the left-most column is left-aligned.
723- # Therefore choice_1 will begin the line (with 1 space for padding).
724- if line .startswith (' choice_1' ) and 'A description' in line :
725- line_found = True
726- break
729+ lines = ac_app .formatted_completions .splitlines ()
730+
731+ # Since the CompletionItems were created from strings, the left-most column is left-aligned.
732+ # Therefore choice_1 will begin the line (with 1 space for padding).
733+ assert lines [2 ].startswith (' choice_1' )
734+ assert lines [2 ].strip ().endswith ('Description 1' )
735+
736+ # Verify that the styled string was converted to a Rich Text object so that
737+ # Rich could correctly calculate its display width. Since it was the longest
738+ # description in the table, we should only see one space of padding after it.
739+ assert lines [3 ].endswith ("\x1b [34mString with style\x1b [0m " )
727740
728- assert line_found
741+ # Verify that the styled Rich Text also rendered.
742+ assert lines [4 ].endswith ("\x1b [31mText with style\x1b [0m " )
729743
730744 # Now test CompletionItems created from numbers
731745 text = ''
@@ -738,16 +752,12 @@ def test_completion_items(ac_app) -> None:
738752 assert len (ac_app .completion_matches ) == len (ac_app .num_completion_items )
739753 assert len (ac_app .display_matches ) == len (ac_app .num_completion_items )
740754
741- # Look for both the value and description in the hint table
742- line_found = False
743- for line in ac_app .formatted_completions .splitlines ():
744- # Since the CompletionItems were created from numbers, the left-most column is right-aligned.
745- # Therefore 1.5 will be right-aligned.
746- if line .startswith (" 1.5" ) and "One.Five" in line :
747- line_found = True
748- break
755+ lines = ac_app .formatted_completions .splitlines ()
749756
750- assert line_found
757+ # Since the CompletionItems were created from numbers, the left-most column is right-aligned.
758+ # Therefore 1.5 will be right-aligned.
759+ assert lines [2 ].startswith (" 1.5" )
760+ assert lines [2 ].strip ().endswith ('One.Five' )
751761
752762
753763@pytest .mark .parametrize (
0 commit comments