diff --git a/Bin/colors-apply.sh b/Bin/colors-apply.sh index 447203a4..3febd53f 100755 --- a/Bin/colors-apply.sh +++ b/Bin/colors-apply.sh @@ -5,7 +5,7 @@ if [ "$#" -ne 1 ]; then # Print usage information to standard error. echo "Error: No application specified." >&2 - echo "Usage: $0 {kitty|ghostty|foot|fuzzell|pywalfox}" >&2 + echo "Usage: $0 {kitty|ghostty|foot|fuzzel|pywalfox}" >&2 exit 1 fi @@ -50,8 +50,8 @@ case "$APP_NAME" in fi ;; - fuzzell) - echo "🎨 Applying 'noctalia' theme to fuzzell..." + fuzzel) + echo "🎨 Applying 'noctalia' theme to fuzzel..." CONFIG_FILE="$HOME/.config/fuzzel/fuzzel.ini" # Check if the config file exists. @@ -61,7 +61,7 @@ case "$APP_NAME" in # Add the new theme include line. echo "include=~/.config/fuzzel/themes/noctalia" >> "$CONFIG_FILE" else - echo "Error: fuzzell config file not found at $CONFIG_FILE" >&2 + echo "Error: fuzzel config file not found at $CONFIG_FILE" >&2 exit 1 fi ;; @@ -78,6 +78,4 @@ case "$APP_NAME" in ;; esac -echo "✅ Command sent for $APP_NAME." - - # lines.push("post_hook = \"grep -q '^theme *= *' ~/.config/ghostty/config; and sed -i 's/^theme *= *.*/theme = noctalia/' ~/.config/ghostty/config; or echo 'theme = noctalia' >> ~/.config/ghostty/config; and pkill -SIGUSR2 ghostty\"") \ No newline at end of file +echo "✅ Command sent for $APP_NAME." \ No newline at end of file diff --git a/Services/MatugenService.qml b/Services/MatugenService.qml index fd200071..60bf4a58 100644 --- a/Services/MatugenService.qml +++ b/Services/MatugenService.qml @@ -46,6 +46,7 @@ Singleton { // Generate colors using current wallpaper and settings function generateFromWallpaper() { Logger.log("Matugen", "Generating from wallpaper on screen:", Screen.name) + var wp = WallpaperService.getWallpaper(Screen.name).replace(/'/g, "'\\''") if (wp === "") { Logger.error("Matugen", "No wallpaper was found") @@ -55,26 +56,47 @@ Singleton { var content = MatugenTemplates.buildConfigToml() var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light" var pathEsc = dynamicConfigPath.replace(/'/g, "'\\''") - var extraRepo = (Quickshell.shellDir + "/Assets/Matugen/extra").replace(/'/g, "'\\''") - var extraUser = (Settings.configDir + "matugen.d").replace(/'/g, "'\\''") // Build the main script - var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n" + "for d in '" + extraRepo + "' '" + extraUser + "'; do\n" + " if [ -d \"$d\" ]; then\n" + " for f in \"$d\"/*.toml; do\n" + " [ -f \"$f\" ] && { echo; echo \"# extra: $f\"; cat \"$f\"; } >> '" + pathEsc + "'\n" + " done\n" + " fi\n" - + "done\n" + "matugen image '" + wp + "' --config '" + pathEsc + "' --mode " + mode + " --type " + Settings.data.colorSchemes.matugenSchemeType + var script = buildMatugenScript(content, pathEsc, wp, mode) - // Add user config execution if enabled - if (Settings.data.templates.enableUserTemplates) { - var userConfigDir = (Quickshell.env("HOME") + "/.config/matugen/").replace(/'/g, "'\\''") - script += "\n# Execute user config if it exists\nif [ -f '" + userConfigDir + "config.toml' ]; then\n" - script += " matugen image '" + wp + "' --config '" + userConfigDir + "config.toml' --mode " + mode + " --type " + Settings.data.colorSchemes.matugenSchemeType + "\n" - script += "fi" - } - - script += "\n" generateProcess.command = ["bash", "-lc", script] generateProcess.running = true } + // -------------------------------- + function buildMatugenScript(content, pathEsc, wallpaper, mode) { + var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n" + + // Main matugen command + script += "matugen image '" + wallpaper + "' --config '" + pathEsc + "' --mode " + mode + " --type " + Settings.data.colorSchemes.matugenSchemeType + + // Add user template execution if enabled + script += addUserTemplateExecution(wallpaper, mode) + + return script + "\n" + } + + // -------------------------------- + function addUserTemplateExecution(input, mode) { + if (!Settings.data.templates.enableUserTemplates) { + return "" + } + + var userConfigPath = getUserConfigPath() + var script = "\n# Execute user config if it exists\n" + script += "if [ -f '" + userConfigPath + "' ]; then\n" + script += " matugen image '" + input + "' --config '" + userConfigPath + "' --mode " + mode + " --type " + Settings.data.colorSchemes.matugenSchemeType + "\n" + script += "fi" + + return script + } + + // -------------------------------- + function getUserConfigPath() { + return (Quickshell.env("HOME") + "/.config/matugen/config.toml").replace(/'/g, "'\\''") + } + // -------------------------------- function selectVibrantColor(schemeData, mode) { var colors = [] @@ -106,63 +128,67 @@ Singleton { var content = MatugenTemplates.buildConfigToml() var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light" var pathEsc = dynamicConfigPath.replace(/'/g, "'\\''") - var extraRepo = (Quickshell.shellDir + "/Assets/Matugen/extra").replace(/'/g, "'\\''") - var extraUser = (Settings.configDir + "matugen.d").replace(/'/g, "'\\''") const color = selectVibrantColor(schemeData, mode) // Build the script - var script = "" - script += "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n\n" - // script += "for d in '" + extraRepo + "' '" + extraUser + "'; do\n" - // script += " if [ -d \"$d\" ]; then\n" - // script += " for f in \"$d\"/*.toml; do\n" - // script += " [ -f \"$f\" ] && { echo; echo \"# extra: $f\"; cat \"$f\"; } >> '" + pathEsc + "'\n" - // script += " done\n" - // script += " fi\n" - // script += "done\n\n" - script += "matugen color hex '" + color + "' --config '" + pathEsc + "' --mode " + mode + var script = buildPredefinedSchemeScript(content, pathEsc, color, mode) - console.log(script) - - // // Add user config execution if enabled - // if (Settings.data.templates.enableUserTemplates) { - // var userConfigDir = (Quickshell.env("HOME") + "/.config/matugen/").replace(/'/g, "'\\''") - // script += "\n# Execute user config if it exists\nif [ -f '" + userConfigDir + "config.toml' ]; then\n" - // script += " matugen color hex " + color + " --config '" + userConfigDir + "config.toml' --mode " + mode - // script += "fi" - // } - - script += "\n" generateProcess.command = ["bash", "-lc", script] generateProcess.running = true - // ----- + // Handle terminal theme copying for predefined schemes + handleTerminalThemes() + } + + // -------------------------------- + function buildPredefinedSchemeScript(content, pathEsc, color, mode) { + var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n\n" + script += "matugen color hex '" + color + "' --config '" + pathEsc + "' --mode " + mode + "\n" + + // Add user template execution if enabled + script += addUserTemplateExecutionForColor(color, mode) + + return script + } + + // -------------------------------- + function addUserTemplateExecutionForColor(color, mode) { + if (!Settings.data.templates.enableUserTemplates) { + return "" + } + + var userConfigPath = getUserConfigPath() + var script = "\n# Execute user config if it exists\n" + script += "if [ -f '" + userConfigPath + "' ]; then\n" + script += " matugen color hex '" + color + "' --config '" + userConfigPath + "' --mode " + mode + "\n" + script += "fi" + + return script + } + + // -------------------------------- + function handleTerminalThemes() { var terminals = { foot: "~/.config/foot/themes/noctalia", - ghostty: "/.config/ghostty/themes/noctalia", + ghostty: "~/.config/ghostty/themes/noctalia", kitty: "~/.config/kitty/themes/noctalia.conf", } var copyCmd = Object.entries(terminals) .filter(([terminal, colorsPath]) => Settings.data.templates[terminal]) .map(([terminal, colorsPath]) => { - // regex matches everything after last '/' in a string var colorsPathParent = colorsPath.replace(/[^\/]*$/, "") var terminalColorsTemplate = getTerminalColorsTemplate(terminal) return [ - // make sure intermediate theme directories are present `mkdir -p ${colorsPathParent}`, - // copy theme file to terminal config directory `cp -f ${terminalColorsTemplate} ${colorsPath}`, - // apply theme config `${colorsApplyScript} ${terminal}`, ] }) - .reduce((arr1, arr2) => arr1.concat(arr2), []) // can't use .flatMap in Qt's environment + .reduce((arr1, arr2) => arr1.concat(arr2), []) .join("; ") if (copyCmd !== "") { - //console.log(copyCmd) copyProcess.command = ["bash", "-lc", copyCmd] copyProcess.running = true } @@ -174,14 +200,13 @@ Singleton { const darkLight = Settings.data.colorSchemes.darkMode ? 'dark' : 'light' // Convert display names back to folder names - if (colorScheme === "Noctalia (default)") { - colorScheme = "Noctalia-default" - } else if (colorScheme === "Noctalia (legacy)") { - colorScheme = "Noctalia-legacy" - } else if (colorScheme === "Tokyo Night") { - colorScheme = "Tokyo-Night" + var schemeMap = { + "Noctalia (default)": "Noctalia-default", + "Noctalia (legacy)": "Noctalia-legacy", + "Tokyo Night": "Tokyo-Night" } - + + colorScheme = schemeMap[colorScheme] || colorScheme var extension = terminal === 'kitty' ? ".conf" : "" return `${Quickshell.shellDir}/Assets/ColorScheme/${colorScheme}/terminal/${terminal}/${colorScheme}-${darkLight}${extension}` diff --git a/Services/MatugenTemplates.qml b/Services/MatugenTemplates.qml index 8f091f8d..30feea22 100644 --- a/Services/MatugenTemplates.qml +++ b/Services/MatugenTemplates.qml @@ -6,8 +6,11 @@ import qs.Commons // Central place to define which templates we generate and where they write. // Users can extend it by dropping additional templates into: -// - Assets/MatugenTemplates/ -// - ~/.config/matugen/ (when enableUserTemplates is true) +// - Assets/MatugenTemplates/ (built-in templates) +// - ~/.config/matugen/ (user-defined templates when enableUserTemplates is true) +// +// User templates are automatically executed after the main matugen command +// if enableUserTemplates is enabled in settings. Singleton { id: root @@ -15,81 +18,97 @@ Singleton { function buildConfigToml() { var lines = [] var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light" + lines.push("[config]") if (Settings.data.colorSchemes.useWallpaperColors) { - // Only generate colors for Noctalia if the colors are wallpaper based - // or this will conflict with our predefined colors - lines.push("[templates.noctalia]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/noctalia.json"') - lines.push('output_path = "' + Settings.configDir + 'colors.json"') - - // Only generate colors for terminalk if the colors are wallpaper based - // predefined color schemes use a different approach for better result - if (Settings.data.templates.foot) { - lines.push("\n[templates.foot]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/Terminal/foot"') - lines.push('output_path = "~/.config/foot/themes/noctalia"') - lines.push(`post_hook = "${MatugenService.colorsApplyScript} foot"`) - } - - if (Settings.data.templates.ghostty) { - lines.push("\n[templates.ghostty]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/Terminal/ghostty"') - lines.push('output_path = "~/.config/ghostty/themes/noctalia"') - lines.push(`post_hook = "${MatugenService.colorsApplyScript} ghostty"`) - } - - if (Settings.data.templates.kitty) { - lines.push("\n[templates.kitty]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/Terminal/kitty.conf"') - lines.push('output_path = "~/.config/kitty/themes/noctalia.conf"') - lines.push(`post_hook = "${MatugenService.colorsApplyScript} kitty"`) - } - } - - if (Settings.data.templates.gtk) { - lines.push("\n[templates.gtk3]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/gtk.css"') - lines.push('output_path = "~/.config/gtk-3.0/gtk.css"') - lines.push("post_hook = 'gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + "'") - - lines.push("\n[templates.gtk4]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/gtk.css"') - lines.push('output_path = "~/.config/gtk-4.0/gtk.css"') - lines.push("post_hook = 'gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + "'") - } - - if (Settings.data.templates.qt) { - lines.push("\n[templates.qt5]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/qtct.conf"') - lines.push('output_path = "~/.config/qt5ct/colors/noctalia.conf"') - - lines.push("\n[templates.qt6]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/qtct.conf"') - lines.push('output_path = "~/.config/qt6ct/colors/noctalia.conf"') - } - - if (Settings.data.templates.fuzzel) { - lines.push("\n[templates.fuzzel]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/fuzzel.conf"') - lines.push('output_path = "~/.config/fuzzel/themes/noctalia"') - lines.push(`post_hook = "${MatugenService.colorsApplyScript} fuzzel"`) - } - - if (Settings.data.templates.pywalfox) { - lines.push("\n[templates.pywalfox]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/pywalfox.json"') - lines.push('output_path = "~/.cache/wal/colors.json"') - lines.push(`post_hook = "${MatugenService.colorsApplyScript} pywalfox"`) - } - - if (Settings.data.templates.vesktop) { - lines.push("\n[templates.vesktop]") - lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/vesktop.css"') - lines.push('output_path = "~/.config/vesktop/themes/noctalia.theme.css"') + addWallpaperBasedTemplates(lines, mode) } + addApplicationTemplates(lines, mode) + return lines.join("\n") + "\n" } + + // -------------------------------- + function addWallpaperBasedTemplates(lines, mode) { + // Noctalia colors + lines.push("[templates.noctalia]") + lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/noctalia.json"') + lines.push('output_path = "' + Settings.configDir + 'colors.json"') + + // Terminal templates (only for wallpaper-based colors) + addTerminalTemplates(lines) + } + + // -------------------------------- + function addTerminalTemplates(lines) { + var terminals = [ + { name: "foot", path: "Terminal/foot", output: "~/.config/foot/themes/noctalia" }, + { name: "ghostty", path: "Terminal/ghostty", output: "~/.config/ghostty/themes/noctalia" }, + { name: "kitty", path: "Terminal/kitty.conf", output: "~/.config/kitty/themes/noctalia.conf" } + ] + + terminals.forEach(function(terminal) { + if (Settings.data.templates[terminal.name]) { + lines.push("\n[templates." + terminal.name + "]") + lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/' + terminal.path + '"') + lines.push('output_path = "' + terminal.output + '"') + lines.push('post_hook = "' + MatugenService.colorsApplyScript + " " + terminal.name + '"') + } + }) + } + + // -------------------------------- + function addApplicationTemplates(lines, mode) { + var applications = [ + { + name: "gtk", + templates: [ + { version: "gtk3", output: "~/.config/gtk-3.0/gtk.css" }, + { version: "gtk4", output: "~/.config/gtk-4.0/gtk.css" } + ], + input: "gtk.css", + postHook: "gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + }, + { + name: "qt", + templates: [ + { version: "qt5", output: "~/.config/qt5ct/colors/noctalia.conf" }, + { version: "qt6", output: "~/.config/qt6ct/colors/noctalia.conf" } + ], + input: "qtct.conf" + }, + { + name: "fuzzel", + templates: [{ version: "fuzzel", output: "~/.config/fuzzel/themes/noctalia" }], + input: "fuzzel.conf", + postHook: MatugenService.colorsApplyScript + " fuzzel" + }, + { + name: "pywalfox", + templates: [{ version: "pywalfox", output: "~/.cache/wal/colors.json" }], + input: "pywalfox.json", + postHook: MatugenService.colorsApplyScript + " pywalfox" + }, + { + name: "vesktop", + templates: [{ version: "vesktop", output: "~/.config/vesktop/themes/noctalia.theme.css" }], + input: "vesktop.css" + } + ] + + applications.forEach(function(app) { + if (Settings.data.templates[app.name]) { + app.templates.forEach(function(template) { + lines.push("\n[templates." + template.version + "]") + lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/' + app.input + '"') + lines.push('output_path = "' + template.output + '"') + if (app.postHook) { + lines.push('post_hook = "' + app.postHook + '"') + } + }) + } + }) + } }