@domicile-desktop/system-apps 0.0.0-alpha-0bb6b376cd01 → 0.0.0-alpha-8d9d380ea456
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +2 -2
- package/src/describe-apps.ts +36 -14
- package/src/fake-system.ts +25 -2
package/README.md
CHANGED
|
@@ -29,13 +29,13 @@ const editors = findApps(apps, "edit", 50);
|
|
|
29
29
|
| `./installed` | Every desktop entry under them; an earlier directory hides a later one's ID. |
|
|
30
30
|
| `./desktop-entry` | One entry parsed: name, comment, argv, icon and `X-Domicile-Preview`. |
|
|
31
31
|
| `./find-apps`, `./bookmark` | The launcher's matching and ranking; bookmarks and their Zod schema. |
|
|
32
|
-
| `./describe-apps` | Application IDs named and drawn by their entries, for a shell to say who asks. |
|
|
32
|
+
| `./describe-apps` | Application IDs named and drawn by their entries, in the config's icon theme, for a shell to say who asks. |
|
|
33
33
|
| `./mime-apps` | A content type's default applications from every `mimeapps.list`, the desktop's own (`domicile-mimeapps.list`) first. |
|
|
34
34
|
| `./openers` | The applications that open a file, its default first, and the argv each opens it with. The type comes from shared-mime-info's `mime/globs2`, by name. |
|
|
35
35
|
| `./omit` | Desktop file IDs left out, as globs. |
|
|
36
36
|
| `./app-icons` | Icon names resolved to `data:` URLs (PNG, SVG, 128 KiB at most) by the icon theme spec: a theme, its `Inherits`, `hicolor`, then `pixmaps`, at the size asked for, in `apps` or the contexts given. `themedIcons` falls back to `<name>-symbolic` and says which icons are symbolic. Pass the theme `readIconTheme` reads. |
|
|
37
37
|
| `./favicon`, `./curl`, `./favicons` | A bookmark's icon: picked from the page, fetched with `curl`, kept and retried. |
|
|
38
|
-
| `./fake-system` | A `System` over an in-memory tree, for tests. |
|
|
38
|
+
| `./fake-system` | A `System` over an in-memory tree, for tests. Its Settings portal serves the icon theme it is given. |
|
|
39
39
|
|
|
40
40
|
- Calls resolve `Result`s with the SDK's `SystemError`; a missing or
|
|
41
41
|
unreadable file or directory is skipped, as the specs say.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"@cprussin/option-result": "^2.0.1",
|
|
4
|
-
"@domicile-desktop/sdk": "0.0.0-alpha-
|
|
4
|
+
"@domicile-desktop/sdk": "0.0.0-alpha-8d9d380ea456",
|
|
5
5
|
"zod": "^4.5.4"
|
|
6
6
|
},
|
|
7
7
|
"description": "Installed applications and bookmarks for a Domicile shell's launcher, read through @domicile-desktop/sdk/system.",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"test:unit": "bun test"
|
|
49
49
|
},
|
|
50
50
|
"type": "module",
|
|
51
|
-
"version": "0.0.0-alpha-
|
|
51
|
+
"version": "0.0.0-alpha-8d9d380ea456"
|
|
52
52
|
}
|
package/src/describe-apps.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import type { Option } from "@cprussin/option-result";
|
|
5
5
|
import { None, Ok, Result } from "@cprussin/option-result";
|
|
6
|
+
import { readIconTheme } from "@domicile-desktop/sdk/icon-theme";
|
|
6
7
|
import type { System, SystemError } from "@domicile-desktop/sdk/system";
|
|
7
8
|
|
|
8
9
|
import type { IconLookup } from "./app-icons";
|
|
@@ -21,24 +22,45 @@ export type DescribedApp = {
|
|
|
21
22
|
icon: string | undefined;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Each of `ids`, in order, described by its installed desktop entry, with its
|
|
27
|
+
* icon from the config's icon theme.
|
|
28
|
+
*/
|
|
25
29
|
export const describeApps = async (
|
|
26
30
|
system: System,
|
|
27
31
|
ids: readonly string[],
|
|
32
|
+
): Promise<Result<DescribedApp[], SystemError>> => {
|
|
33
|
+
const [dirs, theme] = await Promise.all([
|
|
34
|
+
dataDirs(system),
|
|
35
|
+
readIconTheme(system),
|
|
36
|
+
]);
|
|
37
|
+
return dirs.andThenAsync((found) =>
|
|
38
|
+
theme.andThenAsync((named) =>
|
|
39
|
+
describedIn(
|
|
40
|
+
system,
|
|
41
|
+
found,
|
|
42
|
+
appIcons(system, found, ["apps"], {
|
|
43
|
+
theme: named.match({ None: () => undefined, Some: (name) => name }),
|
|
44
|
+
}),
|
|
45
|
+
ids,
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Each of `ids` described by its entry under `dirs`, drawn by `icons`. */
|
|
52
|
+
const describedIn = async (
|
|
53
|
+
system: System,
|
|
54
|
+
dirs: readonly string[],
|
|
55
|
+
icons: IconLookup,
|
|
56
|
+
ids: readonly string[],
|
|
28
57
|
): Promise<Result<DescribedApp[], SystemError>> =>
|
|
29
|
-
(await
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
);
|
|
36
|
-
return Result.collect(
|
|
37
|
-
await Promise.all(
|
|
38
|
-
ids.map((id) => described(icons, id, entries.get(id))),
|
|
39
|
-
),
|
|
40
|
-
);
|
|
41
|
-
},
|
|
58
|
+
(await installedApps(system, dirs)).andThenAsync(async (installed) => {
|
|
59
|
+
const entries = new Map(
|
|
60
|
+
installed.map((entry) => [entry.id.replace(/\.desktop$/, ""), entry]),
|
|
61
|
+
);
|
|
62
|
+
return Result.collect(
|
|
63
|
+
await Promise.all(ids.map((id) => described(icons, id, entries.get(id)))),
|
|
42
64
|
);
|
|
43
65
|
});
|
|
44
66
|
|
package/src/fake-system.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type { Result } from "@cprussin/option-result";
|
|
4
4
|
import { Err, Ok } from "@cprussin/option-result";
|
|
5
5
|
import type {
|
|
6
|
+
DbusBody,
|
|
6
7
|
DirEntry,
|
|
7
8
|
Ran,
|
|
8
9
|
Stat,
|
|
@@ -36,13 +37,18 @@ export type FakeSystem = System & {
|
|
|
36
37
|
|
|
37
38
|
type Tree = Readonly<Record<string, Node>>;
|
|
38
39
|
|
|
40
|
+
/** The Settings portal interface `readIconTheme` reads. */
|
|
41
|
+
const SETTINGS = "org.freedesktop.impl.portal.Settings";
|
|
42
|
+
|
|
39
43
|
/**
|
|
40
44
|
* A system whose files are `tree`, keyed by path, with the directories
|
|
41
|
-
* between them implied. `spawned` answers `spawn` and `run`.
|
|
45
|
+
* between them implied. `spawned` answers `spawn` and `run`. Its Settings
|
|
46
|
+
* portal serves `iconTheme`, or no icon theme when `undefined`.
|
|
42
47
|
*/
|
|
43
48
|
export const fakeSystem = (
|
|
44
49
|
tree: Tree,
|
|
45
50
|
spawned: (argv: readonly string[]) => Spawned = unexpected,
|
|
51
|
+
iconTheme: string | undefined = undefined,
|
|
46
52
|
): FakeSystem => {
|
|
47
53
|
const touched: string[] = [];
|
|
48
54
|
const at = (path: string): Result<Found, SystemError> => {
|
|
@@ -56,7 +62,10 @@ export const fakeSystem = (
|
|
|
56
62
|
: Err({ kind: SystemErrorKind.IsADirectory, message: path }),
|
|
57
63
|
);
|
|
58
64
|
return {
|
|
59
|
-
dbusCall:
|
|
65
|
+
dbusCall: (call) =>
|
|
66
|
+
call.interface === SETTINGS && call.member === "ReadAll"
|
|
67
|
+
? Promise.resolve(Ok(settings(iconTheme)))
|
|
68
|
+
: unexpected(),
|
|
60
69
|
dbusMatch: unexpected,
|
|
61
70
|
readDir: (path) =>
|
|
62
71
|
Promise.resolve(
|
|
@@ -107,6 +116,20 @@ export const fakeSystem = (
|
|
|
107
116
|
};
|
|
108
117
|
};
|
|
109
118
|
|
|
119
|
+
/** `ReadAll`'s answer for `org.gnome.desktop.interface`. */
|
|
120
|
+
const settings = (iconTheme: string | undefined): DbusBody => ({
|
|
121
|
+
body: [
|
|
122
|
+
iconTheme === undefined
|
|
123
|
+
? {}
|
|
124
|
+
: {
|
|
125
|
+
"org.gnome.desktop.interface": {
|
|
126
|
+
"icon-theme": { signature: "s", value: iconTheme },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
signature: "a{sa{sv}}",
|
|
131
|
+
});
|
|
132
|
+
|
|
110
133
|
/** A file's contents, or the directory a path resolved to. */
|
|
111
134
|
type Found = string | Uint8Array | { directory: string };
|
|
112
135
|
|