diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml index 9afbed44b..78b0a9edb 100644 --- a/dots/.config/quickshell/ii/modules/common/Directories.qml +++ b/dots/.config/quickshell/ii/modules/common/Directories.qml @@ -44,6 +44,7 @@ Singleton { property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`) property string defaultAiPrompts: Quickshell.shellPath("defaults/ai/prompts") property string userAiPrompts: FileUtils.trimFileProtocol(`${Directories.shellConfig}/ai/prompts`) + property string userActions: FileUtils.trimFileProtocol(`${Directories.shellConfig}/actions`) property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`) property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`) property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`) @@ -59,6 +60,7 @@ Singleton { Quickshell.execDetached(["bash", "-c", `rm -rf '${latexOutput}'; mkdir -p '${latexOutput}'`]) Quickshell.execDetached(["bash", "-c", `rm -rf '${cliphistDecode}'; mkdir -p '${cliphistDecode}'`]) Quickshell.execDetached(["mkdir", "-p", `${aiChats}`]) + Quickshell.execDetached(["mkdir", "-p", `${userActions}`]) Quickshell.execDetached(["rm", "-rf", `${tempImages}`]) } } diff --git a/dots/.config/quickshell/ii/services/LauncherSearch.qml b/dots/.config/quickshell/ii/services/LauncherSearch.qml index f5a18bec9..52e783e28 100644 --- a/dots/.config/quickshell/ii/services/LauncherSearch.qml +++ b/dots/.config/quickshell/ii/services/LauncherSearch.qml @@ -4,6 +4,7 @@ import qs.modules.common import qs.modules.common.models import qs.modules.common.functions import QtQuick +import Qt.labs.folderlistmodel import Quickshell import Quickshell.Io @@ -31,6 +32,34 @@ Singleton { return acc; }, []).sort() + // Load user action scripts from ~/.config/illogical-impulse/actions/ + // Uses FolderListModel to auto-reload when scripts are added/removed + property var userActionScripts: { + const actions = []; + for (let i = 0; i < userActionsFolder.count; i++) { + const fileName = userActionsFolder.get(i, "fileName"); + const filePath = userActionsFolder.get(i, "filePath"); + if (fileName && filePath) { + const actionName = fileName.replace(/\.[^/.]+$/, ""); // strip extension + actions.push({ + action: actionName, + execute: ((path) => (args) => { + Quickshell.execDetached([path, ...(args ? args.split(" ") : [])]); + })(FileUtils.trimFileProtocol(filePath.toString())) + }); + } + } + return actions; + } + + FolderListModel { + id: userActionsFolder + folder: Qt.resolvedUrl(Directories.userActions) + showDirs: false + showHidden: false + sortField: FolderListModel.Name + } + property var searchActions: [ { action: "accentcolor", @@ -90,6 +119,9 @@ Singleton { }, ] + // Combined built-in and user actions + property var allActions: searchActions.concat(userActionScripts) + property string mathResult: "" property bool clipboardWorkSafetyActive: { const enabled = Config.options.workSafety.enable.clipboard; @@ -273,7 +305,7 @@ Singleton { Qt.openUrlExternally(url); } }); - const launcherActionObjects = root.searchActions.map(action => { + const launcherActionObjects = root.allActions.map(action => { const actionString = `${Config.options.search.prefix.action}${action.action}`; if (actionString.startsWith(root.query) || root.query.startsWith(actionString)) { return resultComp.createObject(null, {