diff --git a/README.md b/README.md index d7ae8a5..c11e82f 100644 --- a/README.md +++ b/README.md @@ -254,12 +254,19 @@ print(s) ### Format String -A format string may be used to format an `AnsiString` or `AnsiStr` before printing. The format specification string must be in the format `"[string_format[:ansi_format]]"` where `string_format` is an extension of the standard string format specifier and `ansi_format` contains 0 or more ANSI directives separated by semicolons (;). The ANSI directives may be any of the same string values that can be passed to the `AnsiString` constructor. If no `string_format` is desired, then it can be set to an empty string. +A format string may be used to format an `AnsiString` or `AnsiStr` before printing. The format specification string must be in the format `"[string_format[:ansi_format]]"` where: +- `string_format` is an extension of the standard string format specifier: `.?[+-]?[<>^]?[0-9]*` + - The first character is optional and is the fill character used (default: space) + - An optional + or - char may be specified after the first fill character to enable or disable formatting of the fill character (enabled by default) + - A `^`, `<`, or `>` character specified center, left, or right justification (left by default) + - An integer specifies the total width (0 by default) +- `ansi_format` contains 0 or more ansi directives separated by semicolons (;). The ANSI directives may be any of the same string values that can be passed to the `AnsiString` constructor. If no `string_format` is desired, then it can be set to an empty string. Examples: ```py ansi_str = AnsiString("This is an ANSI string") + # Right justify with width of 100, formatted with underline and colored red. # By default, all fill characters will take on the first character's formatting. print("{:>100:underline;red}".format(ansi_str)) diff --git a/src/ansi_string/ansi_string.py b/src/ansi_string/ansi_string.py index c913d27..f9077f3 100644 --- a/src/ansi_string/ansi_string.py +++ b/src/ansi_string/ansi_string.py @@ -638,7 +638,7 @@ def _apply_string_format(self, string_format:str, settings:Union[AnsiFormat, Ans (start, end) values where accompanying formats should be applied ''' extend_formatting = True - match = re.search(r'^(.?)([+-]?)<([0-9]*)$', string_format) + match = re.search(r'^(.?)([+-]?)<([0-9]*)$', string_format) or re.search(r'^()()([0-9]*)$', string_format) if match: # Left justify num = match.group(3) @@ -689,11 +689,11 @@ def _apply_string_format(self, string_format:str, settings:Union[AnsiFormat, Ans self.apply_formatting(settings) return - match = re.search(r'^[<>\^]?[+-]?[0-9]*$', string_format) + match = re.search(r'^[<>\^]?[+-][0-9]*$', string_format) if match: raise ValueError('Sign not allowed in string format specifier') - match = re.search(r'^[<>\^]?[ ]?[0-9]*$', string_format) + match = re.search(r'^[<>\^]?[ ][0-9]*$', string_format) if match: raise ValueError('Space not allowed in string format specifier') @@ -731,12 +731,13 @@ def to_str(self, format_spec:str=None, optimize:bool=True, reset_start:bool=Fals ''' Returns an ANSI format string with both internal and given formatting spec set. Parameters: - format_spec - must be in the format "[string_format[:ansi_format]]" where string_format is an extension of - the standard string format specifier and ansi_format contains 0 or more ansi directives - separated by semicolons (;) - ex: ">10:bold;red" to make output right justify with width of 10, bold and red formatting - No formatting should be applied as part of the justification, add a '-' after the fillchar. - ex: " ->10:bold;red" to not not apply formatting to justification characters + format_spec - must be in the format "[string_format[:ansi_format]]" where: + - string_format is an extension of the standard string format specifier: .?[+-]?[<>^]?[0-9]* + An optional + or - char may be specified after the first fill character to enable or disable + formatting of the fill character (enabled by default) + - ansi_format contains 0 or more ansi directives separated by semicolons (;) + ex: ">10:underline;red" for right justify, width of 10, underline and red formatting + ex: " ->10:underline;red" to do the same but don't extend underline across fill characters optimize - optimization selects the shortest setting string based on the situation. If this is False, then the RESET directive (0) will always used when settings change mid-string. reset_start - when True, the output string will always start with the RESET directive (0) @@ -851,12 +852,13 @@ def __format__(self, __format_spec:str) -> str: ''' Returns an ANSI format string with both internal and given formatting spec set. Parameters: - __format_spec - must be in the format "[string_format[:ansi_format]]" where string_format is an extension of - the standard string format specifier and ansi_format contains 0 or more ansi directives - separated by semicolons (;) - ex: ">10:bold;red" to make output right justify with width of 10, bold and red formatting - No formatting should be applied as part of the justification, add a '-' after the fillchar. - ex: " ->10:bold;red" to not not apply formatting to justification characters + __format_spec - must be in the format "[string_format[:ansi_format]]" where: + - string_format is an extension of the standard string format specifier: .?[+-]?[<>^]?[0-9]* + An optional + or - char may be specified after the first fill character to enable or disable + formatting of the fill character (enabled by default) + - ansi_format contains 0 or more ansi directives separated by semicolons (;) + ex: ">10:underline;red" for right justify, width of 10, underline and red formatting + ex: " ->10:underline;red" to do the same but don't extend underline across fill characters ''' return self.to_str(__format_spec) diff --git a/tests/test_ansi_string.py b/tests/test_ansi_string.py index 7556947..55042f5 100755 --- a/tests/test_ansi_string.py +++ b/tests/test_ansi_string.py @@ -262,6 +262,13 @@ def test_format_left_justify_and_strings(self): '\x1b[1;31mThis string will be formatted bold and red++++++++++++++++++++++++++++++++++++++++++++++++\x1b[m' ) + def test_format_default_left_justify_and_strings(self): + s = AnsiString('This string will be formatted bold and red', 'bold') + self.assertEqual( + '{:90:fg_red}'.format(s), + '\x1b[1;31mThis string will be formatted bold and red \x1b[m' + ) + def test_format_left_justify_no_extend_and_strings(self): s = AnsiString('This string will be formatted bold and red', 'bold') self.assertEqual(