🔧 chore: start new cli development, use pnpm's built-in github repo feature for gnim-utils

This commit is contained in:
retrozinndev
2025-10-07 10:04:09 -03:00
parent 1996ab88b8
commit 14a3855df8
12 changed files with 335 additions and 36 deletions
+160
View File
@@ -0,0 +1,160 @@
import { Scope } from "ags";
import { createScopedConnection, encoder } from "../modules/utils";
import windows from "./modules/windows";
import volume from "./modules/volume";
import devel from "./modules/devel";
import media from "./modules/media";
import Gio from "gi://Gio?version=2.0";
import GLib from "gi://GLib?version=2.0";
export namespace Cli {
let rootScope: Scope;
let service: Gio.SocketService;
let initialized: boolean = false;
const modules: Array<Module> = [
// main module, no need for prefix
{
help: "manage colorshell windows and do more cool stuff.",
commands: [
...windows,
// others
{
name: "runner",
onCalled: (_, data) => {
return {
content: `Opening runner${data ? ` with "${data}"` : ""}...`,
type: "out"
};
}
}
],
arguments: [
{
name: "version",
alias: "v",
help: "print the current colorshell version",
onCalled: () => `colorshell by retrozinndev, version ${COLORSHELL_VERSION
}${DEVEL ? "(devel)" : ""}`
}
]
},
volume,
media
];
export type Output = {
type: "err"|"out";
content: string|Uint8Array;
} | string;
/** argument passed to the command / module.
* output of onCalled is passed to */
export type Argument = {
/** kebab-cased name for the argument(without the `--` prefix)
* @example help (turns into `--help` internally)*/
name: string;
/** alias for the name (without the `-` prefix).
* @example help -> h */
alias?: string;
/** whether the argument needs a value attribute.
* @example --file ~/a_nice_home_file.txt */
hasValue?: boolean;
/** runtime-set value for the argument(if enabled) */
value?: string;
/** help message for the argument */
help?: string;
onCalled: (value?: string) => void;
};
export type Command = {
/** the command name to be called.
* @example `colorshell ${prefix?} ${command.name}`*/
name: string;
help?: string;
/** data passed to the command. (only works when arguments are disabled) */
data?: string;
arguments?: Array<Argument>;
onCalled: (args: Array<string>, data?: string) => Output;
};
export type Module = {
/** command to come after the cli call.
* @example `colorshell ${prefix?} ${command}`*/
prefix?: string;
commands?: Array<Command>;
arguments?: Array<Argument>;
help?: string;
/** called everytime the prefix is used, even when using module commands */
onPrefixCalled?: () => void;
};
/** initialize the cli */
export function init(scope: Scope, socketService: Gio.SocketService): void {
if(initialized) return;
initialized = true;
rootScope = scope;
service = socketService;
DEVEL && modules.push(devel);
scope.run(() => {
createScopedConnection(
service, "incoming", (conn) => {
try {
return handleIncoming(conn);
} catch(_) {}
return false;
}
);
});
}
/** handle incoming socket calls */
function handleIncoming(conn: Gio.SocketConnection): void {
const inputStream = Gio.DataInputStream.new(conn.inputStream);
inputStream.read_upto_async('\x00', -1, GLib.PRIORITY_DEFAULT, null, (_, res) => {
const [args, len] = inputStream.read_upto_finish(res);
inputStream.close(null);
conn.inputStream.close(null);
if(len < 1) {
console.error(`Colorshell: No args provided via socket call`);
return;
}
try {
const [success, parsedArgs] = GLib.shell_parse_argv(`colorshell ${args}`);
parsedArgs?.splice(0, 1); // remove the unnecessary `colorshell` part
if(success) {
handleArgs(parsedArgs!);
conn.outputStream.flush(null);
conn.close(null);
return;
}
conn.outputStream.write_bytes(
encoder.encode("Error: Unexpected syntax error occurred"),
null
);
conn.outputStream.flush(null);
conn.close(null);
} catch(_e) {
const e = _e as Error;
console.error(`Colorshell: An error occurred while writing to socket output. Stderr:\n${
e.message}\n${e.stack}`);
}
});
}
/** translate app arguments to modules/commands */
function handleArgs(args: Array<string>): void {
let mod: Module;
}
}
+16
View File
@@ -0,0 +1,16 @@
import { Gtk } from "ags/gtk4";
import { Cli } from "..";
export default {
prefix: "dev",
help: "development tools to help debugging colorshell",
commands: [{
name: "inspector",
help: "open the gtk's visual inspector",
onCalled: () => {
Gtk.Window.set_interactive_debugging(true);
return "Opening GTK Inspector..."
}
}]
} satisfies Cli.Module;
+46
View File
@@ -0,0 +1,46 @@
import { Cli } from "..";
export default {
prefix: "media",
help: "manage colorshell's active player",
commands: [
{
name: "play",
help: "resume/start active player's media",
onCalled: () => "TODO"
}, {
name: "pause",
help: "pause the active player",
onCalled: () => "TODO"
}, {
name: "play-pause",
help: "toggle pause/resume the active player",
onCalled: () => "TODO"
}, {
name: "stop",
help: "stop the active player (if compatible)",
onCalled: () => "TODO"
}, {
name: "previous",
help: "go back to previous media in the active player",
onCalled: () => "TODO"
}, {
name: "next",
help: "jump to the next media in active player",
onCalled: () => "TODO"
}, {
name: "bus-name",
help: "retrieve the active player's mpris bus name",
onCalled: () => "TODO"
}, {
name: "list",
help: "list available players implementing mpris",
onCalled: () => "TODO"
}, {
name: "select",
help: "resume/start active player's media",
onCalled: (_, busName) => "TODO"
}
]
} satisfies Cli.Module;
+27
View File
@@ -0,0 +1,27 @@
import { Cli } from "..";
export default {
prefix: "volume",
help: "manage audio device volume/sensitivity. available devices are sink(speaker) and source(microphone).\
example usage: `colorshell volume increase sink 5%`",
commands: [
{
name: "increase",
help: "increase volume/sensitivity of a sink/source",
onCalled: () => "TODO"
}, {
name: "decrease",
help: "decrease volume/sensitivity of a sink/source",
onCalled: () => "TODO"
}, {
name: "set",
help: "set the volume/sensitivity of a sink/source",
onCalled: () => "TODO"
}, {
name: "mute",
help: "toggle-mute a sink/source's audio",
onCalled: () => "TODO"
}
]
} satisfies Cli.Module;
+46
View File
@@ -0,0 +1,46 @@
import { Cli } from "..";
export default [
{
name: "open",
onCalled: (_, data) => {
return {
type: "out",
content: "TODO"
}
}
}, {
name: "toggle",
onCalled: (_, data) => {
return {
type: "out",
content: "TODO"
}
}
}, {
name: "close",
onCalled: (_, data) => {
return {
type: "out",
content: "TODO"
}
}
}, {
name: "windows",
onCalled: () => {
return {
type: "out",
content: "TODO"
}
}
}, {
name: "reopen",
onCalled: () => {
return {
type: "out",
content: "TODO"
}
}
}
] satisfies Array<Cli.Command>;