Skip to content

Commit 7b506ba

Browse files
authored
Add colorless menu
1 parent 0bf3845 commit 7b506ba

File tree

3 files changed

+23
-101
lines changed

3 files changed

+23
-101
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,13 @@ export _GIT_BRANCH="master"
309309
310310
### Color Themes
311311
312-
You can change to the legacy color scheme by toggling the variable
313-
`_MENU_THEME` between `default` and `legacy`
312+
You can change to the legacy color scheme by toggling the variable `_MENU_THEME` between `default` and `legacy`.
313+
You can completely disable the color theme by setting the `_MENU_THEME` variable to `none`.
314314
315315
```bash
316316
export _MENU_THEME="legacy"
317+
# or
318+
export _MENU_THEME="none"
317319
```
318320
319321
## Contributing

git_py_stats/menu.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def interactive_menu(config: Dict[str, Union[str, int]]) -> str:
2424
WHITE = "\033[37m"
2525
CYAN = "\033[36m"
2626

27-
# Handle default and legacy menu
27+
# Handle default, legacy, and colorless menu
2828
theme = config.get("menu_theme", "")
2929

3030
if theme == "legacy":
@@ -33,6 +33,13 @@ def interactive_menu(config: Dict[str, Union[str, int]]) -> str:
3333
NUMS = f"{BOLD}{YELLOW}"
3434
HELP_TXT = f"{NORMAL}{YELLOW}"
3535
EXIT_TXT = f"{BOLD}{RED}"
36+
elif theme == "none":
37+
TITLES = BOLD
38+
TEXT = ""
39+
NUMS = BOLD
40+
HELP_TXT = ""
41+
EXIT_TXT = BOLD
42+
NORMAL = ""
3643
else:
3744
TITLES = f"{BOLD}{CYAN}"
3845
TEXT = f"{NORMAL}{WHITE}"

git_py_stats/tests/test_menu.py

Lines changed: 11 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def setUp(self):
2525
# Mock configurations for testing
2626
self.config_default = {} # Default theme
2727
self.config_legacy = {"menu_theme": "legacy"} # Legacy theme
28+
self.config_none = {"menu_theme": "none"} # Alternate colorless theme alias
2829

2930
@patch("builtins.input", return_value="1")
3031
@patch("sys.stdout", new_callable=StringIO)
@@ -88,107 +89,19 @@ def test_legacy_theme_option_1(self, mock_stdout, mock_input):
8889
self.assertIn("Generate:", output)
8990
self.assertIn("1) Contribution stats (by author)", output)
9091

91-
@patch("builtins.input", return_value="2")
92+
@patch("builtins.input", return_value="3")
9293
@patch("sys.stdout", new_callable=StringIO)
93-
def test_legacy_theme_option_2(self, mock_stdout, mock_input):
94+
def test_none_theme_option_3(self, mock_stdout, mock_input):
9495
"""
95-
Test the interactive_menu with legacy theme and user selects option '2'.
96+
Test the interactive_menu with 'none' theme (alias for colorless) and user selects option '3'.
9697
"""
97-
choice = interactive_menu(self.config_legacy)
98-
self.assertEqual(choice, "2")
99-
output = strip_ansi_codes(mock_stdout.getvalue())
100-
self.assertIn("2) Contribution stats (by author) on a specific branch", output)
101-
102-
@patch("builtins.input", return_value="")
103-
@patch("sys.stdout", new_callable=StringIO)
104-
def test_legacy_theme_exit(self, mock_stdout, mock_input):
105-
"""
106-
Test the interactive_menu with legacy theme and user presses Enter to exit.
107-
"""
108-
choice = interactive_menu(self.config_legacy)
109-
self.assertEqual(choice, "")
110-
output = strip_ansi_codes(mock_stdout.getvalue())
111-
self.assertIn("press Enter to exit", output)
112-
113-
@patch("builtins.input", return_value="invalid")
114-
@patch("sys.stdout", new_callable=StringIO)
115-
def test_legacy_theme_invalid_input(self, mock_stdout, mock_input):
116-
"""
117-
Test the interactive_menu with legacy theme and user enters an invalid option.
118-
"""
119-
choice = interactive_menu(self.config_legacy)
120-
self.assertEqual(choice, "invalid")
121-
output = strip_ansi_codes(mock_stdout.getvalue())
122-
self.assertIn("Generate:", output)
123-
124-
@patch("builtins.input", side_effect=["1", ""])
125-
@patch("sys.stdout", new_callable=StringIO)
126-
def test_multiple_inputs(self, mock_stdout, mock_input):
127-
"""
128-
Test the interactive_menu with multiple inputs in sequence.
129-
"""
130-
choice1 = interactive_menu(self.config_default)
131-
choice2 = interactive_menu(self.config_default)
132-
self.assertEqual(choice1, "1")
133-
self.assertEqual(choice2, "")
134-
output = strip_ansi_codes(mock_stdout.getvalue())
135-
self.assertIn("Generate:", output)
136-
137-
@patch("builtins.input", return_value=" 5 ")
138-
@patch("sys.stdout", new_callable=StringIO)
139-
def test_input_with_whitespace(self, mock_stdout, mock_input):
140-
"""
141-
Test the interactive_menu with input that includes leading/trailing whitespace.
142-
"""
143-
choice = interactive_menu(self.config_default)
144-
self.assertEqual(choice, "5")
145-
output = strip_ansi_codes(mock_stdout.getvalue())
146-
self.assertIn("5) My daily status", output)
147-
148-
@patch("builtins.input", return_value="QUIT")
149-
@patch("sys.stdout", new_callable=StringIO)
150-
def test_input_quit(self, mock_stdout, mock_input):
151-
"""
152-
Test the interactive_menu with input 'QUIT' to simulate exit.
153-
"""
154-
choice = interactive_menu(self.config_default)
155-
self.assertEqual(choice, "QUIT")
156-
output = strip_ansi_codes(mock_stdout.getvalue())
157-
self.assertIn("Generate:", output)
158-
159-
@patch("builtins.input", return_value="EXIT")
160-
@patch("sys.stdout", new_callable=StringIO)
161-
def test_input_exit(self, mock_stdout, mock_input):
162-
"""
163-
Test the interactive_menu with input 'EXIT' to simulate exit.
164-
"""
165-
choice = interactive_menu(self.config_default)
166-
self.assertEqual(choice, "EXIT")
167-
output = strip_ansi_codes(mock_stdout.getvalue())
168-
self.assertIn("Generate:", output)
169-
170-
@patch("builtins.input", return_value=" ")
171-
@patch("sys.stdout", new_callable=StringIO)
172-
def test_input_only_whitespace(self, mock_stdout, mock_input):
173-
"""
174-
Test the interactive_menu with input that is only whitespace.
175-
"""
176-
choice = interactive_menu(self.config_default)
177-
self.assertEqual(choice, "")
178-
output = strip_ansi_codes(mock_stdout.getvalue())
179-
self.assertIn("press Enter to exit", output)
180-
181-
@patch("builtins.input", side_effect=KeyboardInterrupt)
182-
@patch("sys.stdout", new_callable=StringIO)
183-
def test_keyboard_interrupt(self, mock_stdout, mock_input):
184-
"""
185-
Test the interactive_menu handles KeyboardInterrupt (Ctrl+C).
186-
"""
187-
with self.assertRaises(KeyboardInterrupt):
188-
interactive_menu(self.config_default)
189-
output = strip_ansi_codes(mock_stdout.getvalue())
190-
self.assertIn("Generate:", output)
191-
98+
choice = interactive_menu(self.config_none)
99+
self.assertEqual(choice, "3")
100+
output = mock_stdout.getvalue()
101+
self.assertNotIn("\033[31m", output) # No RED
102+
self.assertNotIn("\033[33m", output) # No YELLOW
103+
self.assertNotIn("\033[36m", output) # No CYAN
104+
self.assertIn("\033[1m", output) # BOLD allowed
192105

193106
if __name__ == "__main__":
194107
unittest.main()

0 commit comments

Comments
 (0)