Files
z-bar-qt/Modules/Launcher/Services/Files.qml
T
zach dfecaf9cbc
C++ / fmt (pull_request) Successful in 6s
C++ / build (pull_request) Failing after 2m2s
C++ / clang-tidy (pull_request) Failing after 2m0s
JS/TS / fmt (pull_request) Failing after 11s
JS/TS / lint (pull_request) Successful in 9s
Python / static (pull_request) Successful in 27s
Rust / build (pull_request) Successful in 50s
Python / verify (pull_request) Successful in 1m32s
Rust / fmt (pull_request) Successful in 27s
Rust / clippy (pull_request) Successful in 48s
cache text during chat sidebar anim + file search with plocate
2026-09-02 19:31:54 +02:00

195 lines
4.4 KiB
QML

// qs/Services/Files.qml
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import ZShell.Config
Singleton {
id: root
property list<var> results: []
property string _pendingQuery: ""
property int _generation: 0
readonly property var _imageExts: ({
"png": true,
"jpg": true,
"jpeg": true,
"gif": true,
"bmp": true,
"webp": true,
"svg": true,
"tiff": true,
"tif": true,
"ico": true,
"heic": true,
"avif": true
})
// freedesktop mimetype-icon names; extend as needed
readonly property var _extIcons: ({
// images
"png": "image-x-generic",
"jpg": "image-x-generic",
"jpeg": "image-x-generic",
"gif": "image-x-generic",
"bmp": "image-x-generic",
"webp": "image-x-generic",
"svg": "image-x-generic",
"tiff": "image-x-generic",
"tif": "image-x-generic",
"ico": "image-x-generic",
"heic": "image-x-generic",
"avif": "image-x-generic",
// documents
"pdf": "application-pdf",
"doc": "x-office-document",
"docx": "x-office-document",
"odt": "x-office-document",
"txt": "text-x-generic",
"md": "text-x-generic",
"xls": "x-office-spreadsheet",
"xlsx": "x-office-spreadsheet",
"ods": "x-office-spreadsheet",
"ppt": "x-office-presentation",
"pptx": "x-office-presentation",
"odp": "x-office-presentation",
// archives
"zip": "package-x-generic",
"tar": "package-x-generic",
"gz": "package-x-generic",
"xz": "package-x-generic",
"7z": "package-x-generic",
"rar": "package-x-generic",
// audio/video
"mp3": "audio-x-generic",
"flac": "audio-x-generic",
"wav": "audio-x-generic",
"ogg": "audio-x-generic",
"mp4": "video-x-generic",
"mkv": "video-x-generic",
"webm": "video-x-generic",
"avi": "video-x-generic",
"mov": "video-x-generic",
// code
"js": "text-x-script",
"ts": "text-x-script",
"py": "text-x-script",
"sh": "text-x-script",
"qml": "text-x-script",
"cpp": "text-x-c++src",
"c": "text-x-csrc",
"h": "text-x-chdr",
"json": "application-json",
"html": "text-html",
"css": "text-css"
})
function showInFolder(path: string): void {
const explorer = Config.general.apps.explorer;
let args = [];
if (explorer.includes("dolphin"))
args = [...explorer, "--select", path];
else
args = [...explorer, path];
if (Config.launcher.uwsm)
Quickshell.execDetached(["app2unit", "--", ...args]);
else
Quickshell.execDetached([...args]);
}
function launch(command: list<string>): void {
if (Config.launcher.uwsm)
Quickshell.execDetached(["app2unit", "--"].concat(command));
else
Quickshell.execDetached(command);
}
function transformSearch(search: string): string {
return search.slice(Config.launcher.actionPrefix.length + "files ".length);
}
function query(search: string): list<var> {
search = transformSearch(search);
if (search !== _pendingQuery) {
_pendingQuery = search;
debounceTimer.restart();
}
return results;
}
function _extOf(name: string): string {
const i = name.lastIndexOf(".");
// no dot, or dotfile with no real extension (".bashrc" -> treat as no ext)
if (i <= 0)
return "";
return name.slice(i + 1).toLowerCase();
}
function _iconFor(name: string, isDir: bool): string {
if (isDir)
return "folder";
const ext = _extOf(name);
return _extIcons[ext] ?? "text-x-generic";
}
function _buildEntry(path: string): var {
const name = path.split("/").pop();
const ext = _extOf(name);
// trailing slash from plocate's directory output (if -d/dir results ever appear)
const isDir = path.endsWith("/");
return {
path: path,
name: name,
icon: _iconFor(name, isDir),
isImage: !isDir && (_imageExts[ext] ?? false)
};
}
Timer {
id: debounceTimer
interval: 120
onTriggered: root._runQuery(root._pendingQuery)
}
function _runQuery(search: string): void {
_generation++;
if (!search) {
proc.running = false;
results = [];
return;
}
if (proc.running)
proc.running = false;
proc.buffer = [];
proc.myGeneration = _generation;
proc.command = ["plocate", "-i", "-b", "--limit", "50", search];
proc.running = true;
}
Process {
id: proc
property var buffer: []
property int myGeneration: 0
stdout: SplitParser {
onRead: line => proc.buffer.push(root._buildEntry(line))
}
onRunningChanged: {
if (!running && myGeneration === root._generation)
root.results = buffer;
}
}
}