✨ ags(runner): add new functions and organize existing
This commit is contained in:
+233
-202
@@ -1,13 +1,77 @@
|
|||||||
import { AstalIO, timeout, Variable } from "astal";
|
import { AstalIO, timeout } from "astal";
|
||||||
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
|
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
|
||||||
import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow";
|
import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow";
|
||||||
import { updateApps } from "../scripts/apps";
|
import { updateApps } from "../scripts/apps";
|
||||||
import { ResultWidget, ResultWidgetProps } from "../widget/runner/ResultWidget";
|
import { ResultWidget, ResultWidgetProps } from "../widget/runner/ResultWidget";
|
||||||
import { Windows } from "../windows";
|
import { Windows } from "../windows";
|
||||||
|
|
||||||
export let runnerInstance: (Gtk.Window|null) = null;
|
export namespace Runner {
|
||||||
|
export type RunnerProps = {
|
||||||
|
halign?: Gtk.Align;
|
||||||
|
valign?: Gtk.Align;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
entryPlaceHolder?: string;
|
||||||
|
initialText?: string;
|
||||||
|
showResultsPlaceHolderOnStartup?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export function startRunnerDefault(initialText?: string) {
|
export interface Plugin {
|
||||||
|
/** prefix to call the plugin. if undefined, will be triggered like applications plugin */
|
||||||
|
readonly prefix?: string;
|
||||||
|
/** name of the plugin. e.g.: websearch, shell */
|
||||||
|
readonly name?: string;
|
||||||
|
/** ran on runner open */
|
||||||
|
readonly init?: () => void;
|
||||||
|
/** handle the user input to return results (does not include plugin's prefix) */
|
||||||
|
readonly handle: (inputText: string) => (ResultWidget|Array<ResultWidget>|null|undefined);
|
||||||
|
/** ran on runner close */
|
||||||
|
readonly onClose?: () => void;
|
||||||
|
/** hide other plugins when using this plugin */
|
||||||
|
prioritize?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let instance: (Widget.Window|null) = null;
|
||||||
|
let gtkEntry: (Widget.Entry|null) = null;
|
||||||
|
const plugins = new Set<Runner.Plugin>();
|
||||||
|
|
||||||
|
export function close() { instance?.close(); }
|
||||||
|
|
||||||
|
export function regExMatch(search: string, item: string): boolean {
|
||||||
|
search = search.replace(/[\\^$.*?()[\]{}|]/g, "\\$&");
|
||||||
|
return new RegExp(`${search.split('').map(c =>
|
||||||
|
`.*(${c.toLowerCase()}|${c.toUpperCase()}).*`).join('')}`
|
||||||
|
).test(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function addPlugin(plugin: Runner.Plugin, force?: boolean) {
|
||||||
|
if(!force && plugin.prefix && plugins.has(plugin))
|
||||||
|
throw new Error(`Runner plugin with prefix ${plugin.prefix} already exists`);
|
||||||
|
|
||||||
|
plugins.delete(plugin);
|
||||||
|
plugins.add(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlugins(): Array<Runner.Plugin> {
|
||||||
|
return [...plugins.values()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a plugin from the runner plugin list
|
||||||
|
* @returns true if plugin was removed or false if plugin wasn't found
|
||||||
|
*/
|
||||||
|
export function removePlugin(plugin: Plugin): boolean {
|
||||||
|
return plugins.delete(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setEntryText(text: string): void {
|
||||||
|
gtkEntry?.set_text(text);
|
||||||
|
gtkEntry?.set_position(gtkEntry.textLength);
|
||||||
|
|
||||||
|
gtkEntry?.grab_focus_without_selecting();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function openDefault(initialText?: string) {
|
||||||
return Runner.openRunner({
|
return Runner.openRunner({
|
||||||
entryPlaceHolder: "Start typing...",
|
entryPlaceHolder: "Start typing...",
|
||||||
showResultsPlaceHolderOnStartup: false,
|
showResultsPlaceHolderOnStartup: false,
|
||||||
@@ -16,222 +80,189 @@ export function startRunnerDefault(initialText?: string) {
|
|||||||
() => [
|
() => [
|
||||||
new ResultWidget({
|
new ResultWidget({
|
||||||
icon: "application-x-executable-symbolic",
|
icon: "application-x-executable-symbolic",
|
||||||
title: "Run your applications",
|
title: "Use your applications",
|
||||||
description: "Type the name of the application to search"
|
description: "Search for any app installed in your computer",
|
||||||
|
closeOnClick: false,
|
||||||
|
onClick: () => gtkEntry?.grab_focus()
|
||||||
} as ResultWidgetProps),
|
} as ResultWidgetProps),
|
||||||
new ResultWidget({
|
new ResultWidget({
|
||||||
icon: "media-playback-start-symbolic",
|
icon: "edit-paste-symbolic",
|
||||||
title: "Control media",
|
title: "See your clipboard history",
|
||||||
description: "Use prefix ':' to run"
|
description: "Start your search with '>' to go through your clipboard history",
|
||||||
|
closeOnClick: false,
|
||||||
|
onClick: () => setEntryText('>')
|
||||||
|
} as ResultWidgetProps),
|
||||||
|
new ResultWidget({
|
||||||
|
icon: "image-x-generic-symbolic",
|
||||||
|
title: "Change your wallpaper",
|
||||||
|
description: "Add '#' at the start to search through the wallpapers folder!",
|
||||||
|
closeOnClick: false,
|
||||||
|
onClick: () => setEntryText('#'),
|
||||||
} as ResultWidgetProps),
|
} as ResultWidgetProps),
|
||||||
new ResultWidget({
|
new ResultWidget({
|
||||||
icon: "utilities-terminal-symbolic",
|
icon: "utilities-terminal-symbolic",
|
||||||
title: "Run shell commands",
|
title: "Run shell commands",
|
||||||
description: "Start typing with '!' prefix to run shell commands"
|
description: "Add '!' before your command to run it (pro tip: add a second '!' to show command output)",
|
||||||
|
closeOnClick: false,
|
||||||
|
onClick: () => setEntryText('!!')
|
||||||
|
} as ResultWidgetProps),
|
||||||
|
new ResultWidget({
|
||||||
|
icon: "media-playback-start-symbolic",
|
||||||
|
title: "Control media",
|
||||||
|
description: "Type ':' to control playing media",
|
||||||
|
closeOnClick: false,
|
||||||
|
onClick: () => setEntryText(':')
|
||||||
} as ResultWidgetProps),
|
} as ResultWidgetProps),
|
||||||
new ResultWidget({
|
new ResultWidget({
|
||||||
icon: "applications-internet-symbolic",
|
icon: "applications-internet-symbolic",
|
||||||
title: "Search the Web",
|
title: "Search the Web",
|
||||||
description: "Start typing with '?' prefix to search the web"
|
description: "Start typing with '?' prefix to search the web",
|
||||||
|
closeOnClick: false,
|
||||||
|
onClick: () => setEntryText('?')
|
||||||
} as ResultWidgetProps)
|
} as ResultWidgetProps)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Runner {
|
export function openRunner(props?: RunnerProps, placeholder?: () => Array<ResultWidget>): Widget.Window {
|
||||||
export type RunnerProps = {
|
let onClickTimeout: (AstalIO.Time|undefined);
|
||||||
halign?: Gtk.Align;
|
|
||||||
valign?: Gtk.Align;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
entryPlaceHolder?: string;
|
|
||||||
initialText?: string;
|
|
||||||
showResultsPlaceHolderOnStartup?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function close() { runnerInstance?.close(); }
|
gtkEntry = new Widget.Entry({
|
||||||
|
className: "search",
|
||||||
const plugins = new Set<Runner.Plugin>([]);
|
placeholderText: props?.entryPlaceHolder || "",
|
||||||
|
onChanged: (self) => {
|
||||||
export interface Plugin {
|
updateResultsList(self.text);
|
||||||
/** prefix to call the plugin. if undefined, will be triggered like applications plugin */
|
resultsList.get_row_at_index(0) &&
|
||||||
readonly prefix?: string;
|
resultsList.select_row(resultsList.get_row_at_index(0));
|
||||||
/** name of the plugin. e.g.: websearch, shell */
|
},
|
||||||
readonly name?: string;
|
onActivate: (entry) => {
|
||||||
/** ran on runner open */
|
const resultWidget = resultsList.get_selected_row()?.get_child();
|
||||||
readonly init?: () => void;
|
if(resultWidget instanceof ResultWidget) {
|
||||||
/** handle the user input to return results (does not include plugin's prefix) */
|
entry.isFocus = false;
|
||||||
readonly handle: (inputText: string) => (ResultWidget|Array<ResultWidget>|null|undefined);
|
resultWidget.onClick();
|
||||||
/** ran on runner close */
|
resultWidget.closeOnClick && Runner.close();
|
||||||
readonly onClose?: () => void;
|
|
||||||
/** hide other plugins when using this plugin **/
|
|
||||||
prioritize?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addPlugin(plugin: Runner.Plugin, force?: boolean) {
|
|
||||||
if(!force && plugin.prefix && plugins.has(plugin))
|
|
||||||
throw new Error(`Runner plugin with prefix ${plugin.prefix} already exists`);
|
|
||||||
|
|
||||||
plugins.delete(plugin);
|
|
||||||
plugins.add(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPlugins(): Array<Runner.Plugin> {
|
|
||||||
return [...plugins.values()];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Removes a plugin from the runner plugin list
|
|
||||||
* @returns true if plugin was removed or false if plugin wasn't found
|
|
||||||
*/
|
|
||||||
export function removePlugin(plugin: Plugin): boolean {
|
|
||||||
return plugins.delete(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function openRunner(props?: RunnerProps, placeholder?: () => Array<ResultWidget>): (Gtk.Window|null) {
|
|
||||||
let subs: Array<() => void> = [];
|
|
||||||
const entryText: Variable<string> = new Variable<string>("");
|
|
||||||
let onClickTimeout: (AstalIO.Time|undefined);
|
|
||||||
|
|
||||||
const searchEntry = new Widget.Entry({
|
|
||||||
className: "search",
|
|
||||||
onChanged: (entry) => entryText.set(entry.text),
|
|
||||||
placeholderText: props?.entryPlaceHolder || "",
|
|
||||||
onActivate: (entry) => {
|
|
||||||
const resultWidget = resultsList.get_selected_row()?.get_child();
|
|
||||||
if(resultWidget instanceof ResultWidget) {
|
|
||||||
entry.isFocus = false;
|
|
||||||
resultWidget.onClick();
|
|
||||||
resultWidget.closeOnClick && Runner.close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
primary_icon_name: "system-search"
|
|
||||||
} as Widget.EntryProps);
|
|
||||||
|
|
||||||
const resultsList: Gtk.ListBox = new Gtk.ListBox({
|
|
||||||
visible: true,
|
|
||||||
expand: true
|
|
||||||
} as Gtk.ListBox.ConstructorProps);
|
|
||||||
|
|
||||||
if(props?.showResultsPlaceHolderOnStartup && placeholder) {
|
|
||||||
const placeholderWidgets = placeholder();
|
|
||||||
placeholderWidgets.map(widget =>
|
|
||||||
resultsList.insert(widget, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanResults() {
|
|
||||||
resultsList.get_children().map((listItem) => {
|
|
||||||
resultsList.remove(listItem);
|
|
||||||
listItem.destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPluginResults(input: string): Array<ResultWidget> {
|
|
||||||
let calledPlugins: Array<Plugin> = getPlugins().filter((plugin) =>
|
|
||||||
plugin.prefix ? (input.startsWith(plugin.prefix) ? true : false) : true
|
|
||||||
).sort((plugin) => plugin.prefix != null ? 0 : 1);
|
|
||||||
|
|
||||||
for(const plugin of calledPlugins) {
|
|
||||||
if(plugin.prioritize) {
|
|
||||||
calledPlugins = [ plugin ];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
primary_icon_name: "system-search"
|
||||||
|
} as Widget.EntryProps);
|
||||||
|
|
||||||
return calledPlugins.map(plugin => plugin.handle(
|
const resultsList: Gtk.ListBox = new Gtk.ListBox({
|
||||||
plugin.prefix ? input.replace(plugin.prefix, "") : input)
|
visible: true,
|
||||||
).filter(value => value !== undefined && value !== null).flat(1);
|
expand: true
|
||||||
}
|
} as Gtk.ListBox.ConstructorProps);
|
||||||
|
|
||||||
function updateResultsList(entryText: string) {
|
if(props?.showResultsPlaceHolderOnStartup && placeholder) {
|
||||||
const widgets: Array<ResultWidget> = [];
|
const placeholderWidgets = placeholder();
|
||||||
|
placeholderWidgets.map(widget =>
|
||||||
// Remove all previous results
|
resultsList.insert(widget, -1));
|
||||||
cleanResults();
|
|
||||||
|
|
||||||
widgets.push(...getPluginResults(entryText))
|
|
||||||
|
|
||||||
// Insert placeholder if there are no results
|
|
||||||
if(placeholder && widgets.length === 0)
|
|
||||||
widgets.push(...placeholder());
|
|
||||||
|
|
||||||
// Insert results inside GtkListBox
|
|
||||||
widgets.map((resultWidget: ResultWidget) => {
|
|
||||||
resultsList.insert(resultWidget, -1);
|
|
||||||
|
|
||||||
resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => {
|
|
||||||
const rWidget = row.get_child();
|
|
||||||
if(rWidget instanceof ResultWidget) {
|
|
||||||
if(onClickTimeout) return;
|
|
||||||
|
|
||||||
// Timeout, so it doesn't fire the event a hundred times :skull:
|
|
||||||
onClickTimeout = timeout(500, () => onClickTimeout = undefined);
|
|
||||||
rWidget.onClick();
|
|
||||||
rWidget.closeOnClick && Runner.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
subs.push(entryText().subscribe((text: string) => {
|
|
||||||
updateResultsList(text.trim());
|
|
||||||
resultsList.select_row(resultsList.get_row_at_index(0));
|
|
||||||
}));
|
|
||||||
|
|
||||||
if(!runnerInstance)
|
|
||||||
runnerInstance = Windows.createWindowForFocusedMonitor((mon: number): (Widget.Window) => PopupWindow({
|
|
||||||
namespace: "runner",
|
|
||||||
monitor: mon,
|
|
||||||
widthRequest: props?.width ?? 750,
|
|
||||||
heightRequest: props?.height ?? 450,
|
|
||||||
marginTop: 240,
|
|
||||||
anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM,
|
|
||||||
setup: () => {
|
|
||||||
// Init plugins
|
|
||||||
plugins.forEach(plugin => plugin.init && plugin.init());
|
|
||||||
if(props?.initialText) {
|
|
||||||
searchEntry.set_text(props.initialText);
|
|
||||||
searchEntry.set_position(searchEntry.textLength);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyPressEvent: (_, event: Gdk.Event) => {
|
|
||||||
const keyVal = event.get_keyval()[1];
|
|
||||||
|
|
||||||
if(!searchEntry.has_focus && keyVal !== Gdk.KEY_F5
|
|
||||||
&& keyVal !== Gdk.KEY_Down && keyVal !== Gdk.KEY_Up
|
|
||||||
&& keyVal !== Gdk.KEY_Return) {
|
|
||||||
searchEntry.grab_focus_without_selecting();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.get_keyval()[1] === Gdk.KEY_F5 &&
|
|
||||||
updateApps();
|
|
||||||
},
|
|
||||||
onDestroy: () => {
|
|
||||||
subs.map(sub => sub());
|
|
||||||
|
|
||||||
[...plugins.values()].map(plugin =>
|
|
||||||
plugin && plugin.onClose && plugin.onClose());
|
|
||||||
runnerInstance = null;
|
|
||||||
},
|
|
||||||
child: new Widget.Box({
|
|
||||||
className: "runner main",
|
|
||||||
orientation: Gtk.Orientation.VERTICAL,
|
|
||||||
expand: false,
|
|
||||||
valign: Gtk.Align.START,
|
|
||||||
children: [
|
|
||||||
searchEntry,
|
|
||||||
new Widget.Scrollable({
|
|
||||||
className: "results-scrollable",
|
|
||||||
vscroll: Gtk.PolicyType.AUTOMATIC,
|
|
||||||
hscroll: Gtk.PolicyType.NEVER,
|
|
||||||
expand: true,
|
|
||||||
propagateNaturalHeight: true,
|
|
||||||
maxContentHeight: props?.height ?? 450,
|
|
||||||
child: resultsList
|
|
||||||
})
|
|
||||||
]
|
|
||||||
} as Widget.BoxProps)
|
|
||||||
} as PopupWindowProps))();
|
|
||||||
|
|
||||||
return runnerInstance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanResults() {
|
||||||
|
resultsList.get_children().map((listItem) => {
|
||||||
|
resultsList.remove(listItem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginResults(input: string): Array<ResultWidget> {
|
||||||
|
let calledPlugins: Array<Plugin> = getPlugins().filter((plugin) =>
|
||||||
|
plugin.prefix ? (input.startsWith(plugin.prefix) ? true : false) : true
|
||||||
|
).sort((plugin) => plugin.prefix != null ? 0 : 1);
|
||||||
|
|
||||||
|
for(const plugin of calledPlugins) {
|
||||||
|
if(plugin.prioritize) {
|
||||||
|
calledPlugins = [ plugin ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return calledPlugins.map(plugin => plugin.handle(
|
||||||
|
plugin.prefix ? input.replace(plugin.prefix, "") : input)
|
||||||
|
).filter(value => value !== undefined && value !== null).flat(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateResultsList(entryText: string) {
|
||||||
|
const widgets: Array<ResultWidget> = [];
|
||||||
|
|
||||||
|
// Remove all previous results
|
||||||
|
cleanResults();
|
||||||
|
|
||||||
|
widgets.push(...getPluginResults(entryText))
|
||||||
|
|
||||||
|
// Insert placeholder if there are no results
|
||||||
|
if(placeholder && widgets.length === 0)
|
||||||
|
widgets.push(...placeholder());
|
||||||
|
|
||||||
|
// Insert results inside GtkListBox
|
||||||
|
widgets.map((resultWidget: ResultWidget) => {
|
||||||
|
resultsList.insert(resultWidget, -1);
|
||||||
|
|
||||||
|
resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => {
|
||||||
|
const rWidget = row.get_child();
|
||||||
|
if(rWidget instanceof ResultWidget) {
|
||||||
|
if(onClickTimeout) return;
|
||||||
|
|
||||||
|
// Timeout, so it doesn't fire the event a hundred times :skull:
|
||||||
|
onClickTimeout = timeout(500, () => onClickTimeout = undefined);
|
||||||
|
rWidget.onClick();
|
||||||
|
rWidget.closeOnClick && Runner.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!instance)
|
||||||
|
instance = Windows.createWindowForFocusedMonitor((mon: number): (Widget.Window) => PopupWindow({
|
||||||
|
namespace: "runner",
|
||||||
|
monitor: mon,
|
||||||
|
widthRequest: props?.width ?? 750,
|
||||||
|
heightRequest: props?.height ?? 450,
|
||||||
|
marginTop: 240,
|
||||||
|
anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM,
|
||||||
|
setup: () => {
|
||||||
|
// Init plugins
|
||||||
|
plugins.forEach(plugin => plugin.init && plugin.init());
|
||||||
|
|
||||||
|
if(props?.initialText)
|
||||||
|
Runner.setEntryText(props.initialText);
|
||||||
|
},
|
||||||
|
onKeyPressEvent: (_, event: Gdk.Event) => {
|
||||||
|
const keyVal = event.get_keyval()[1];
|
||||||
|
|
||||||
|
if(!gtkEntry!.has_focus && keyVal !== Gdk.KEY_F5
|
||||||
|
&& keyVal !== Gdk.KEY_Down && keyVal !== Gdk.KEY_Up
|
||||||
|
&& keyVal !== Gdk.KEY_Return) {
|
||||||
|
gtkEntry!.grab_focus_without_selecting();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.get_keyval()[1] === Gdk.KEY_F5 &&
|
||||||
|
updateApps();
|
||||||
|
},
|
||||||
|
onDestroy: () => {
|
||||||
|
gtkEntry = null;
|
||||||
|
[...plugins.values()].map(plugin =>
|
||||||
|
plugin && plugin.onClose && plugin.onClose());
|
||||||
|
instance = null;
|
||||||
|
},
|
||||||
|
child: new Widget.Box({
|
||||||
|
className: "runner main",
|
||||||
|
orientation: Gtk.Orientation.VERTICAL,
|
||||||
|
expand: false,
|
||||||
|
valign: Gtk.Align.START,
|
||||||
|
children: [
|
||||||
|
gtkEntry,
|
||||||
|
new Widget.Scrollable({
|
||||||
|
className: "results-scrollable",
|
||||||
|
vscroll: Gtk.PolicyType.AUTOMATIC,
|
||||||
|
hscroll: Gtk.PolicyType.NEVER,
|
||||||
|
expand: true,
|
||||||
|
propagateNaturalHeight: true,
|
||||||
|
maxContentHeight: props?.height ?? 450,
|
||||||
|
child: resultsList
|
||||||
|
})
|
||||||
|
]
|
||||||
|
} as Widget.BoxProps)
|
||||||
|
} as PopupWindowProps))();
|
||||||
|
|
||||||
|
return instance!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ export class PluginWallpapers implements Runner.Plugin {
|
|||||||
handle(search: string) {
|
handle(search: string) {
|
||||||
if(this.#files!.length > 0)
|
if(this.#files!.length > 0)
|
||||||
return this.#files!.filter(file => // not the best way to search, but it works
|
return this.#files!.filter(file => // not the best way to search, but it works
|
||||||
new RegExp(`${search.split('').map(c =>
|
Runner.regExMatch(search, file.split('/')[file.split('/').length-1])
|
||||||
`.*(${c.toLowerCase()}|${c.toUpperCase()}).*`).join('')}`
|
|
||||||
).test(file.split('/')[file.split('/').length-1])
|
|
||||||
).map(path => new ResultWidget({
|
).map(path => new ResultWidget({
|
||||||
title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""),
|
title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""),
|
||||||
onClick: () => Wallpaper.getDefault().setWallpaper(path)
|
onClick: () => Wallpaper.getDefault().setWallpaper(path)
|
||||||
|
|||||||
+19
-20
@@ -2,9 +2,9 @@ import { Wireplumber } from "./volume";
|
|||||||
import { Windows } from "../windows";
|
import { Windows } from "../windows";
|
||||||
|
|
||||||
import { restartInstance } from "./reload-handler";
|
import { restartInstance } from "./reload-handler";
|
||||||
import { runnerInstance, startRunnerDefault } from "../runner/Runner";
|
|
||||||
import { showWorkspaceNumbers } from "../widget/bar/Workspaces";
|
import { showWorkspaceNumbers } from "../widget/bar/Workspaces";
|
||||||
import { timeout } from "astal";
|
import { timeout } from "astal";
|
||||||
|
import { Runner } from "../runner/Runner";
|
||||||
|
|
||||||
|
|
||||||
export function handleArguments(request: string): any {
|
export function handleArguments(request: string): any {
|
||||||
@@ -31,9 +31,9 @@ export function handleArguments(request: string): any {
|
|||||||
`${name}: ${Windows.isVisible(name) ? "open" : "closed" }`).join('\n');
|
`${name}: ${Windows.isVisible(name) ? "open" : "closed" }`).join('\n');
|
||||||
|
|
||||||
case "runner":
|
case "runner":
|
||||||
!runnerInstance ?
|
!Runner.instance ?
|
||||||
startRunnerDefault(args[1] || undefined)
|
Runner.openDefault(args[1] || undefined)
|
||||||
: runnerInstance.close();
|
: Runner.close();
|
||||||
return "Opening runner..."
|
return "Opening runner..."
|
||||||
|
|
||||||
case "show-ws-numbers":
|
case "show-ws-numbers":
|
||||||
@@ -154,22 +154,21 @@ Options:
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getHelp(): string {
|
function getHelp(): string {
|
||||||
return `
|
return `Manage Astal Windows and do more stuff. From
|
||||||
Manage Astal Windows and do more stuff. From
|
retrozinndev's Hyprland Dots, using Astal and AGS by Aylur.
|
||||||
retrozinndev's Hyprland Dots, using Astal and AGS by Aylur.
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
open [window_name]: sets specified window's visibility to true.
|
open [window_name]: sets specified window's visibility to true.
|
||||||
close [window_name]: sets specified window's visibility to false.
|
close [window_name]: sets specified window's visibility to false.
|
||||||
toggle [window_name]: toggles visibility of specified window.
|
toggle [window_name]: toggles visibility of specified window.
|
||||||
windows: shows available windows to control.
|
windows: shows available windows to control.
|
||||||
reload: creates a new astal instance and removes this one.
|
reload: creates a new astal instance and removes this one.
|
||||||
volume: wireplumber volume controller, see "volume help".
|
volume: wireplumber volume controller, see "volume help".
|
||||||
runner: open the application runner.
|
runner [initial_text]: open the application runner.
|
||||||
show-ws-numbers: show or hide workspace numbers in bar.
|
show-ws-numbers: show or hide workspace numbers in bar.
|
||||||
h, help: shows this help message.
|
h, help: shows this help message.
|
||||||
|
|
||||||
2025 (c) retrozinndev's Hyprland-Dots, licensed under the MIT License.
|
2025 (c) retrozinndev's Hyprland-Dots, licensed under the MIT License.
|
||||||
https://github.com/retrozinndev/Hyprland-Dots
|
https://github.com/retrozinndev/Hyprland-Dots
|
||||||
`.trim();
|
`.split('\n').map(l => l.replace(/^ {8}/, "")).join('\n');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user