11from dataclasses import dataclass
22from enum import Enum , auto
33from re import compile
4- from typing import TYPE_CHECKING , TextIO
4+ from typing import TYPE_CHECKING , TextIO , Optional
55from commented_config import CommentsHolder , get_comments_holder
66from file_tracker import DataFileSyncer , Syncable
77
@@ -15,6 +15,12 @@ class LookForTitle(Enum):
1515 ROOT = auto ()
1616
1717
18+ class RuleType (Enum ):
19+ INCLUDE = auto ()
20+ EXCLUDE = auto ()
21+ IGNORE = auto ()
22+
23+
1824@dataclass
1925class InversionRule :
2026 """
@@ -58,11 +64,13 @@ class InversionRule:
5864 \t { LookForTitle .CURRENT .name } - Current window (or text element)
5965 """ , LookForTitle .ANY .name ), locals ())
6066
61- exclude : bool = None
62- _comments_ .add (__comment_base .format ("""
63- If this rule is active,
64- then no inversion needed
65- """ , "false" ), locals ())
67+ type : RuleType = None
68+ _comments_ .add (__comment_base .format (f"""
69+ Type of rule: { ' | ' .join (e .name for e in RuleType )}
70+ \t { RuleType .INCLUDE .name } - if this rule is active, then inversion needed
71+ \t { RuleType .EXCLUDE .name } - if this rule is active, then no inversion needed
72+ \t { RuleType .IGNORE .name } - if this rule is active, then do nothing
73+ """ , RuleType .INCLUDE .name ), locals ())
6674
6775 remember_processes : bool = None
6876 _comments_ .add (__comment_base .format ("""
@@ -74,7 +82,9 @@ def __post_init__(self):
7482 if self .remember_processes :
7583 self ._pids = set ()
7684
77- self .exclude = self .exclude or None
85+ self ._type = self .type or RuleType .INCLUDE
86+ if self .type == RuleType .INCLUDE :
87+ self .type = None
7888
7989 if self .path is not None :
8090 self .path_regex = None
@@ -91,6 +101,9 @@ def __post_init__(self):
91101 self ._title_regex = try_compile (self .title_regex )
92102 self ._path_regex = try_compile (self .path_regex )
93103
104+ def get_type (self ):
105+ return self ._type
106+
94107 def is_active (self , info : 'WindowInfo' ) -> bool :
95108 active = (self .check_path (info )
96109 and self .check_title (info ))
@@ -134,12 +147,15 @@ class InversionRulesController(Syncable):
134147 if no active rules found or
135148 if there are some excluded active rules
136149 Recommends to turn filter off, otherwise: on
150+ if there are some ignored active rules
151+ Recommends to do nothing
137152 """
138153
139154 def __init__ (self ):
140155 self .rules : RULES = dict ()
141156 self .included : RULES = dict ()
142157 self .excluded : RULES = dict ()
158+ self .ignored : RULES = dict ()
143159 super ().__init__ (RulesSyncer ("inversion_rules" , self .rules , RULES ))
144160 self ._syncer .on_file_reloaded = lambda : self .load_rules (self ._syncer .data )
145161
@@ -149,7 +165,7 @@ def setup(self):
149165
150166 def load_rules (self , rules : RULES ):
151167 self .rules = rules
152- self .included , self .excluded = dict (), dict ()
168+ self .included , self .excluded , self . ignored = dict (), dict (), dict ()
153169 for name , rule in rules .items ():
154170 self ._detect_accessory (rule )[name ] = rule
155171 self .on_rules_changed ()
@@ -170,11 +186,16 @@ def remove_rules(self, names: set[str]):
170186 self ._syncer .save_file ()
171187 self .on_rules_changed ()
172188
173- def is_inversion_required (self , info : 'WindowInfo' ):
174- return (
175- self .has_active_rules (info , self .included ) and
176- not self .has_active_rules (info , self .excluded )
189+ def is_inversion_required (self , info : 'WindowInfo' ) -> Optional [bool ]:
190+ possibilities = (
191+ (self .ignored , None ),
192+ (self .excluded , False ),
193+ (self .included , True ),
177194 )
195+ for rules , result in possibilities :
196+ if self .has_active_rules (info , rules ):
197+ return result
198+ return False
178199
179200 def has_active_rules (self , info : 'WindowInfo' , rules : RULES = None ):
180201 if rules is None :
@@ -187,9 +208,11 @@ def get_active_rules(info: 'WindowInfo', rules: RULES):
187208 if rules [name ].is_active (info ))
188209
189210 def _detect_accessory (self , rule : InversionRule ):
190- if rule .exclude :
191- return self .excluded
192- return self .included
211+ return {
212+ RuleType .INCLUDE : self .included ,
213+ RuleType .EXCLUDE : self .excluded ,
214+ RuleType .IGNORE : self .ignored ,
215+ }.get (rule .get_type ())
193216
194217 def on_rules_changed (self ):
195218 pass
0 commit comments