aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/user/User.js
blob: dc48209b044d564c7610db7a347ba32228f4d52a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

.pragma library

// Pure helpers for the user page, tested by test_user.js under node.

// `userctl get` output into an object.
function parse(text) {
    const out = {};
    for (const line of text.split("\n")) {
        const i = line.indexOf("=");
        if (i > 0) out[line.slice(0, i)] = line.slice(i + 1);
    }
    return out;
}

// `userctl keys` output into [{fpr, uid}].
function keys(text) {
    return text.split("\n").filter(l => l.includes("\t"))
        .map(l => ({ fpr: l.slice(0, l.indexOf("\t")), uid: l.slice(l.indexOf("\t") + 1) }));
}

// `locale -a` prints it_IT.utf8; AccountsService stores it_IT.UTF-8.
function locales(text) {
    return text.split("\n")
        .filter(l => /\.utf-?8$/i.test(l) && !/^C\./.test(l))
        .map(l => l.replace(/\.utf-?8$/i, ".UTF-8"))
        .sort();
}

// The name git gets, for the page's preview. ponytail: duplicates userctl's
// gitname; both tests pin the same cases, keep them in step.
function gitName(name) {
    const w = name.trim().split(/\s+/).filter(s => s !== "");
    if (w.length < 2) return w.join(" ");
    return w.slice(0, -1).join(" ") + " " + Array.from(w[w.length - 1])[0] + ".";
}

// Nominatim jsonv2 search results as location labels, "place, region,
// country", deduplicated. Anything that is not a JSON array (an error page,
// a rate-limit notice) is no suggestions rather than an error.
function places(text) {
    let rows;
    try { rows = JSON.parse(text); } catch (e) { return []; }
    if (!Array.isArray(rows)) return [];
    const out = [];
    for (const r of rows) {
        const a = r.address || {};
        const parts = [a.city || a.town || a.village || a.hamlet || a.municipality || r.name,
                       a.state, a.country].filter(p => p);
        const label = parts.filter((p, i) => parts.indexOf(p) === i).join(", ");
        if (label && !out.includes(label)) out.push(label);
    }
    return out;
}

// The drawer's greeting, from ~/.config/quickshell/greetings: one per line,
// {user} for the login name, blank lines and # comments skipped. A missing or
// empty file is the built-in set. The row is rebuilt on every drawer open, so
// the last pick lives here, in the shared library, to never show the same one
// twice running.
const defaultGreetings = ["Hello {user}", "Hi {user}", "Welcome back, {user}",
    "Hey there, {user}", "Good to see you, {user}"];
let lastGreeting = -1;
function greeting(text, user, random) {
    const lines = text.split("\n").map(l => l.trim()).filter(l => l && !l.startsWith("#"));
    const all = lines.length ? lines : defaultGreetings;
    const skip = all.length > 1 && lastGreeting >= 0 && lastGreeting < all.length;
    let i = Math.floor((random ?? Math.random()) * (all.length - skip));
    if (skip && i >= lastGreeting) i++;
    lastGreeting = i;
    return all[i].replace(/\{user\}/g, user);
}