1010# #
1111# ############################################################################ #
1212
13+ from __future__ import annotations
1314
1415import re
15- from enum import Enum
16+ import typing
1617
17- from c_formatter_42 .formatters import helper
18+ if typing .TYPE_CHECKING :
19+ from typing import Literal
1820
21+ from c_formatter_42 .formatters import helper
1922
20- class Scope (Enum ):
21- LOCAL = 0
22- GLOBAL = 1
23+ TYPEDECL_OPEN_REGEX = re .compile (
24+ r"""^(?P<prefix>\s*(typedef\s+)? # Maybe a typedef
25+ (struct|enum|union)) # Followed by a struct, enum or union
26+ \s*(?P<suffix>[a-zA-Z_]\w+)?$ # Name of the type declaration
27+ """ ,
28+ re .X ,
29+ )
30+ TYPEDECL_CLOSE_REGEX = re .compile (
31+ r"""^(?P<prefix>\})\s* # Closing } followed by any amount of spaces
32+ (?P<suffix>([a-zA-Z_]\w+)?;)$ # Name of the type (if typedef used)
33+ """ ,
34+ re .X ,
35+ )
2336
2437
25- def align_scope (content : str , scope : Scope ) -> str :
38+ def align_scope (content : str , scope : Literal [ "local" , "global" ] ) -> str :
2639 """Align content
2740 scope can be either local or global
2841 local: for variable declarations in function
2942 global: for function prototypes
3043 """
3144
3245 lines = content .split ("\n " )
33- aligned = []
3446 # select regex according to scope
35- if scope is Scope . LOCAL :
47+ if scope == "local" :
3648 align_regex = "^\t " r"(?P<prefix>{type})\s+" r"(?P<suffix>\**{decl};)$"
37- elif scope is Scope . GLOBAL :
49+ elif scope == "global" :
3850 align_regex = (
3951 r"^(?P<prefix>{type})\s+"
4052 r"(?P<suffix>({name}\(.*\)?;?)|({decl}(;|(\s+=\s+.*))))$"
4153 )
4254 align_regex = align_regex .format (
4355 type = helper .REGEX_TYPE , name = helper .REGEX_NAME , decl = helper .REGEX_DECL_NAME
4456 )
45- # get the lines to be aligned
46- matches = [re .match (align_regex , line ) for line in lines ]
57+ lines_to_be_aligned = [re .match (align_regex , line ) for line in lines ]
4758 aligned = [
4859 (i , match .group ("prefix" ), match .group ("suffix" ))
49- for i , match in enumerate (matches )
60+ for i , match in enumerate (lines_to_be_aligned )
5061 if match is not None
5162 and match .group ("prefix" ) not in ["struct" , "union" , "enum" ]
5263 ]
5364
54- # global type declaration (struct/union/enum)
55- if scope is Scope .GLOBAL :
56- typedecl_open_regex = (
57- r"^(?P<prefix>\s*(typedef\s+)?(struct|enum|union))"
58- r"\s*(?P<suffix>[a-zA-Z_]\w+)?$"
59- )
60- typedecl_close_regex = r"^(?P<prefix>\})\s*(?P<suffix>([a-zA-Z_]\w+)?;)$"
65+ # Global type declaration (struct/union/enum)
66+ if scope == "global" :
6167 in_type_scope = False
6268 for i , line in enumerate (lines ):
63- m = re .match (typedecl_open_regex , line )
69+ m = TYPEDECL_OPEN_REGEX .match (line )
6470 if m is not None :
6571 in_type_scope = True
6672 if m .group ("suffix" ) is not None and "typedef" not in m .group ("prefix" ):
6773 aligned .append ((i , m .group ("prefix" ), m .group ("suffix" )))
6874 continue
69- m = re .match (typedecl_close_regex , line )
75+ m = TYPEDECL_CLOSE_REGEX .match (line )
7076 if m is not None :
7177 in_type_scope = False
7278 if line != "};" :
@@ -83,27 +89,28 @@ def align_scope(content: str, scope: Scope) -> str:
8389 if m is not None :
8490 aligned .append ((i , m .group ("prefix" ), m .group ("suffix" )))
8591
86- # get the minimum alignment required for each line
92+ # Minimum alignment required for each line
8793 min_alignment = max (
88- (len (prefix .replace ("\t " , " " * 4 )) // 4 + 1 for _ , prefix , _ in aligned ),
89- default = 1 ,
94+ (len (prefix .expandtabs (4 )) // 4 + 1 for _ , prefix , _ in aligned ), default = 1
9095 )
9196 for i , prefix , suffix in aligned :
92- alignment = len (prefix .replace ( " \t " , " " * 4 )) // 4
97+ alignment = len (prefix .expandtabs ( 4 )) // 4
9398 lines [i ] = prefix + "\t " * (min_alignment - alignment ) + suffix
94- if scope is Scope .LOCAL :
95- lines [i ] = "\t " + lines [i ]
99+ if scope == "local" :
100+ lines [i ] = (
101+ "\t " + lines [i ]
102+ ) # Adding one more indent for inside the type declaration
96103 return "\n " .join (lines )
97104
98105
99106@helper .locally_scoped
100107def align_local (content : str ) -> str :
101108 """Wrapper for align_scope to use local_scope decorator"""
102- return align_scope (content , scope = Scope . LOCAL )
109+ return align_scope (content , scope = "local" )
103110
104111
105112def align (content : str ) -> str :
106113 """Align the content in global and local scopes"""
107- content = align_scope (content , scope = Scope . GLOBAL )
114+ content = align_scope (content , scope = "global" )
108115 content = align_local (content )
109116 return content
0 commit comments