Formatted logs
This commit is contained in:
@@ -11,9 +11,9 @@ class Console:
|
||||
_next_line = 0
|
||||
|
||||
class Line:
|
||||
def __init__(self, name):
|
||||
def __init__(self, name: Optional[str]=None):
|
||||
"""Initialize a new managed line"""
|
||||
self.name = name
|
||||
self.name = name or f"line_{Console._next_line}"
|
||||
self._reserve_line()
|
||||
|
||||
def update(self, message, icon="⏳"):
|
||||
@@ -25,7 +25,10 @@ class Console:
|
||||
if lines_up > 0:
|
||||
sys.stdout.write(f"\033[{lines_up}F")
|
||||
# Clear line and write status
|
||||
sys.stdout.write(f"\r\033[K{icon} {message}")
|
||||
if icon.strip() == "":
|
||||
sys.stdout.write(f"\r\033[K{message}")
|
||||
else:
|
||||
sys.stdout.write(f"\r\033[K{icon} {message}")
|
||||
# Move the cursor back down
|
||||
if lines_up > 0:
|
||||
sys.stdout.write(f"\033[{lines_up}E")
|
||||
@@ -78,8 +81,8 @@ class Color(Enum):
|
||||
GRAY = '\033[90m'
|
||||
|
||||
@classmethod
|
||||
def get(cls, color: str) -> Optional['Color']:
|
||||
return getattr(cls, color.upper(), None)
|
||||
def get(cls, color: str, default: Optional['Color']=None) -> Optional['Color']:
|
||||
return getattr(cls, color.upper(), default)
|
||||
|
||||
|
||||
class Format(Enum):
|
||||
|
||||
+38
-14
@@ -1,10 +1,15 @@
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from scripts import config
|
||||
from scripts.utils.console import Console, Format, Color
|
||||
from scripts.utils.parse_folder import parse_folder
|
||||
|
||||
|
||||
def gnome_version() -> str | None:
|
||||
"""
|
||||
Get gnome-shell version
|
||||
"""
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(['gnome-shell', '--version'], text=True).strip()
|
||||
return output.split(' ')[2]
|
||||
@@ -13,21 +18,40 @@ def gnome_version() -> str | None:
|
||||
|
||||
def apply_gnome_theme(theme=None) -> bool:
|
||||
"""
|
||||
Apply gnome-shell theme
|
||||
:param theme: theme name
|
||||
Applies the theme in user theme extension if it is Marble and extension installed.
|
||||
"""
|
||||
|
||||
try:
|
||||
if theme is None:
|
||||
current_theme = subprocess.check_output(['dconf', 'read', '/org/gnome/shell/extensions/user-theme/name'], text=True).strip().strip("'")
|
||||
if current_theme.startswith("Marble"):
|
||||
theme = current_theme
|
||||
else:
|
||||
return False
|
||||
theme = get_current_theme()
|
||||
|
||||
subprocess.run(['dconf', 'reset', '/org/gnome/shell/extensions/user-theme/name'], check=True)
|
||||
subprocess.run(['dconf', 'write', '/org/gnome/shell/extensions/user-theme/name', f"'{theme}'"], check=True)
|
||||
print(f"Theme '{theme}' applied.")
|
||||
except subprocess.CalledProcessError:
|
||||
line = Console.Line("apply_gnome_theme")
|
||||
(color, _) = parse_folder(theme)
|
||||
formatted_theme = Console.format(theme, color=Color.get(color, Color.GRAY), format_type=Format.BOLD)
|
||||
|
||||
line.update(f"Applying {formatted_theme} theme...")
|
||||
time.sleep(0.1) # applying the theme may freeze, so we need to wait a bit
|
||||
apply_user_theme(theme)
|
||||
line.success(f"Theme {formatted_theme} applied.")
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
|
||||
|
||||
def get_current_theme() -> str:
|
||||
"""
|
||||
Throws an error if theme is not Marble.
|
||||
"""
|
||||
try:
|
||||
output = subprocess.check_output(['dconf', 'read', config.user_themes_extension], text=True)
|
||||
output = output.strip().strip("'")
|
||||
|
||||
if not output.startswith("Marble"):
|
||||
raise Exception(f"Theme {output} doesn't appear to be a Marble theme")
|
||||
return output
|
||||
except subprocess.CalledProcessError:
|
||||
raise Exception("User theme extension not found.")
|
||||
|
||||
|
||||
def apply_user_theme(theme_name: str):
|
||||
subprocess.run(['dconf', 'reset', config.user_themes_extension], check=True)
|
||||
subprocess.run(['dconf', 'write', config.user_themes_extension, f"'{theme_name}'"], check=True)
|
||||
@@ -0,0 +1,11 @@
|
||||
def parse_folder(folder: str) -> tuple[str, str] | None:
|
||||
"""Parse a folder name into color and mode"""
|
||||
folder_arr = folder.split("-")
|
||||
|
||||
if len(folder_arr) < 2 or folder_arr[0] != "Marble":
|
||||
return None
|
||||
|
||||
color = "-".join(folder_arr[1:-1])
|
||||
mode = folder_arr[-1]
|
||||
|
||||
return color, mode
|
||||
@@ -7,10 +7,12 @@ import shutil
|
||||
from collections import defaultdict
|
||||
from typing import Any
|
||||
|
||||
from .console import Console, Color, Format
|
||||
from .parse_folder import parse_folder
|
||||
from .. import config
|
||||
import os
|
||||
|
||||
def remove_files(args: argparse.Namespace, colors: dict[str, Any]):
|
||||
def remove_files(args: argparse.Namespace, formatted_colors: dict[str, Any]):
|
||||
"""Delete already installed Marble theme"""
|
||||
themes = detect_themes(config.themes_folder)
|
||||
|
||||
@@ -20,23 +22,26 @@ def remove_files(args: argparse.Namespace, colors: dict[str, Any]):
|
||||
filtered_themes = themes
|
||||
if not args.all:
|
||||
args_dict = vars(args)
|
||||
arguments = [color for color in colors.keys() if args_dict.get(color)]
|
||||
arguments = [color for color in formatted_colors.keys() if args_dict.get(color)]
|
||||
filtered_themes = themes.filter(arguments)
|
||||
|
||||
if not filtered_themes:
|
||||
print("No matching themes found.")
|
||||
Console.Line().error("No matching themes found.")
|
||||
return
|
||||
|
||||
colors = [color for (color, modes) in filtered_themes]
|
||||
print(f"The following themes will be deleted: {', '.join(colors)}.")
|
||||
formatted_colors = [
|
||||
Console.format(color, color=Color.get(color), format_type=Format.BOLD)
|
||||
for (color, modes) in filtered_themes
|
||||
]
|
||||
Console.Line().warn(f"The following themes will be deleted: {', '.join(formatted_colors)}.")
|
||||
if args.mode:
|
||||
print(f"Theme modes to be deleted: {args.mode}.")
|
||||
Console.Line().warn(f"Theme modes to be deleted: {args.mode}.")
|
||||
|
||||
if input(f"Proceed? (y/N) ").lower() == "y":
|
||||
if proceed_input().lower() == "y":
|
||||
filtered_themes.remove(args.mode)
|
||||
print("Themes deleted successfully.")
|
||||
Console.Line().success("Themes deleted successfully.")
|
||||
else:
|
||||
print("Operation cancelled.")
|
||||
Console.Line().error("Operation cancelled.")
|
||||
|
||||
|
||||
def detect_themes(path: str) -> 'Themes':
|
||||
@@ -59,41 +64,12 @@ def detect_themes(path: str) -> 'Themes':
|
||||
return themes
|
||||
|
||||
|
||||
def parse_folder(folder: str) -> tuple[str, str] | None:
|
||||
"""Parse a folder name into color and mode"""
|
||||
folder_arr = folder.split("-")
|
||||
|
||||
if len(folder_arr) < 2 or folder_arr[0] != "Marble":
|
||||
return None
|
||||
|
||||
color = "-".join(folder_arr[1:-1])
|
||||
mode = folder_arr[-1]
|
||||
|
||||
return color, mode
|
||||
|
||||
|
||||
class ThemeMode:
|
||||
"""Concrete theme with mode and path"""
|
||||
mode: str
|
||||
path: str
|
||||
|
||||
def __init__(self, mode: str, path: str):
|
||||
self.mode = mode
|
||||
self.path = path
|
||||
|
||||
def remove(self):
|
||||
try:
|
||||
shutil.rmtree(self.path)
|
||||
except Exception as e:
|
||||
print(f"Error deleting {self.path}: {e}")
|
||||
|
||||
|
||||
class Themes:
|
||||
"""Collection of themes grouped by color"""
|
||||
def __init__(self):
|
||||
self.by_color: dict[str, list[ThemeMode]] = defaultdict(list) # color: list[ThemeMode]
|
||||
|
||||
def add_theme(self, color: str, theme_mode: ThemeMode):
|
||||
def add_theme(self, color: str, theme_mode: 'ThemeMode'):
|
||||
self.by_color[color].append(theme_mode)
|
||||
|
||||
def filter(self, colors: list[str]):
|
||||
@@ -121,3 +97,26 @@ class Themes:
|
||||
def __iter__(self):
|
||||
for color, modes in self.by_color.items():
|
||||
yield color, modes
|
||||
|
||||
|
||||
class ThemeMode:
|
||||
"""Concrete theme with mode and path"""
|
||||
mode: str
|
||||
path: str
|
||||
|
||||
def __init__(self, mode: str, path: str):
|
||||
self.mode = mode
|
||||
self.path = path
|
||||
|
||||
def remove(self):
|
||||
try:
|
||||
shutil.rmtree(self.path)
|
||||
except Exception as e:
|
||||
print(f"Error deleting {self.path}: {e}")
|
||||
|
||||
|
||||
def proceed_input():
|
||||
formatted_agree = Console.format("y", color=Color.GREEN, format_type=Format.BOLD)
|
||||
formatted_disagree = Console.format("N", color=Color.RED, format_type=Format.BOLD)
|
||||
formatted_proceed = Console.format("Proceed?", format_type=Format.BOLD)
|
||||
return input(f"{formatted_proceed} ({formatted_agree}/{formatted_disagree}) ")
|
||||
Reference in New Issue
Block a user