-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsillyfetch.py
executable file
·230 lines (160 loc) · 7.37 KB
/
sillyfetch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/usr/bin/env python3
import shutil, sys, os, re, subprocess, fetches
from itertools import zip_longest
from logos import get_logos_values
from colors import get_color, r, color_codes
def ensure_config_exist(config_dir: str):
#Check does config exist, copy default one if no config found
if not os.path.exists(config_dir):
os.makedirs(config_dir)
config_file = os.path.join(config_dir, 'config.py')
current_dir = os.path.dirname(os.path.abspath(__file__))
shutil.copy(os.path.join(current_dir, 'default_config.py'), config_file)
def add_function_marks_wrapper(func):
# Wrapper function for custom user functions, to colorize them while rendering
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
wrapped = "%^^" + str(result) + "^^%"
return wrapped
return wrapper
class ConfigInterlayer:
def __init__(self, settings: dict) -> None:
self._logo_info_whitespace: int = settings["logo_info_whitespace"]
self._colorize_functions: bool = settings["colorize_functions"]
self._functions_color: str | int = settings["functions_color"]
self._custom_fetches: dict = settings["custom_fetches"]
self._text_color: str | int = settings["text_color"]
self._logo_position: str = settings["logo_position"]
self._lstrip_info: bool = settings["lstrip_info"]
self._print_logo: bool = settings["print_logo"]
self._logo: str | dict = settings["logo"]
self._layout: str = settings["layout"]
def get_logo_info_whitespace(self):
return self._logo_info_whitespace
def get_custom_fetches(self):
return self._custom_fetches
def get_lstrip_info(self):
return self._lstrip_info
def get_colorize_functions(self):
return self._colorize_functions
def get_logo_position(self):
if self._logo_position in ['top', 'left', 'bottom', 'right']:
return self._logo_position
raise ValueError(f"Incorrect logo_position: {self._logo_position}")
def get_functions_color(self):
if self.get_colorize_functions():
if self._functions_color == 'logo':
return self.get_logo_main_color()
return get_color(self._functions_color)
return ''
def get_text_color(self):
if self._text_color == 'logo':
return self.get_logo_main_color()
return get_color(self._text_color)
def get_logo(self):
if not self._print_logo:
return ' '
if isinstance(self._logo, dict) and "logo" in self._logo:
return self._logo["logo"]
elif self._logo == "auto":
return get_logos_values()["logo"]
else:
return get_logos_values(key=self._logo)["logo"]
def get_logo_main_color(self):
if isinstance(self._logo, dict) and "logo" in self._logo:
return self._logo["main_color"]
elif self._logo == "auto":
return get_logos_values()["main_color"]
else:
return get_logos_values(key=self._logo)["main_color"]
def get_evaluated_layout(self):
eval_dict = {}
for f in dir(fetches):
if callable(getattr(fetches, f)) and not f.startswith('__'):
eval_dict[f] = getattr(fetches, f)
for key, function in self.get_custom_fetches().items():
self._custom_fetches[key] = add_function_marks_wrapper(function)
eval_dict.update(self._custom_fetches)
eval_dict.update(color_codes)
evaluated_layout: str = eval(f"f'''{self._layout}'''", { "__builtins__" : None }, eval_dict)
lines = evaluated_layout.splitlines()
functions_color = self.get_functions_color()
text_color = self.get_text_color()
formatted_lines = []
for line in lines:
if self.get_lstrip_info():
line = line.lstrip()
# Replace placeholders with respective colors
line = text_color + line.replace("%^^", functions_color).replace("^^%", text_color)
# Check for multi-line split markers
if "%^&" in line:
beginning, rest = line.split("%^&", 1)
items = rest.split("%!&")
multi_lines = [beginning + functions_color + item + text_color for item in items]
formatted_lines.extend(multi_lines)
else:
formatted_lines.append(line)
return "\n".join(formatted_lines)
def strip_ansii(text: str):
pattern = r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])'
ansi_escape = re.compile(pattern)
return ansi_escape.sub('', text)
def get_separator(largest_line: str, main_line: str, whitespace_length: int) -> str:
sep_length = largest_line - len(strip_ansii(main_line.rstrip())) + whitespace_length-1
return " " * sep_length
def get_largest_line(lines: list):
return max(len(strip_ansii(l.rstrip())) for l in lines)
def print_logo_info_line_lef_right(logo_line: str, info_line: str, position: str,
separator: str, logo_main_color: str):
if position == 'left':
print(f"{logo_main_color}{logo_line.rstrip()}{r}" + separator, end=' ')
print(f"{info_line}{r}")
elif position == 'right':
print(f"{info_line.rstrip()}{r}" + separator, end=' ')
print(f"{logo_main_color}{logo_line}{r}")
def print_logo_info_top_bottom(logo_text: str, info_text: str,
postion: str, logo_main_color: str):
if postion == 'top':
print(logo_main_color + logo_text + r)
print(info_text + r)
elif postion == 'bottom':
print(info_text + r)
print(logo_main_color + logo_text + r)
def render(config_object: ConfigInterlayer):
logo_main_color = config_object.get_logo_main_color()
position = config_object.get_logo_position()
# Split logo and info text into lines
logo = config_object.get_logo()
info = config_object.get_evaluated_layout()
whitespace_length = config_object.get_logo_info_whitespace()
# Find the maximum length of logo lines for alignment (ignoring ANSI escape codes) and whitespaces from right
subprocess.run(['setterm', '-linewrap', 'off'])
if position in ['top', 'bottom']:
print_logo_info_top_bottom(logo, info, position, logo_main_color)
return
elif position == 'left':
largest_line = get_largest_line(logo.splitlines())
else:
largest_line = get_largest_line(info.splitlines())
for logo_line, info_line in zip_longest(logo.splitlines(), info.splitlines(), fillvalue=''):
if position == 'left':
main_line = logo_line
else:
main_line = info_line
separator = get_separator(
largest_line, main_line, whitespace_length
)
# Print logo line with the appropriate space and color
print_logo_info_line_lef_right(
logo_line, info_line, position, separator, logo_main_color
)
subprocess.run(['setterm', '-linewrap', 'on'])
def main(config_dir='~/.config/sillyfetch'):
config_dir = os.path.expanduser(config_dir)
sys.path.append(config_dir)
ensure_config_exist(config_dir)
from config import settings
config_object = ConfigInterlayer(settings)
render(config_object)
if __name__ == '__main__':
main()