aboutsummarylogtreecommitdiffstats
path: root/i3-kblayout-switch.ts
blob: eceafe873f597a034d34dba7c31e21482f1315f0 (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
83
84
85
86
87
88
89
90
#!/usr/bin/env bun
import { $, spawn } from 'bun';

type Workspace = {
    workspaceId: number;
    language: string;
};

let savedWorkspaces: Array<Workspace> = [];
setInitialWorkspaceData();

updateConfigOnLanguageChange();

const availableLanguages = (await $`setxkbmap -query  | grep layout | awk '{print $2}'`.text()).split(',');

const i3Socket = (await Bun.$`sh -c 'ls /run/user/1000/i3/ipc-socket.*'`.text()).trim();
const { stdout } = spawn(['i3-msg', '-m', `--socket=${i3Socket}`, '-t', 'subscribe', '[ "workspace" ]']);

for await (const data of stdout.pipeThrough(new TextDecoderStream())) {
    for (const dataLine of data.split('\n')) {
        if (!dataLine) continue;
        const workspaceData = JSON.parse(dataLine);
        const event = workspaceData.change;
        if (event !== "focus") continue;
        await switchLanguageOnWorkspaceChange(workspaceData.current.num);
    }
}

async function updateConfigOnLanguageChange() {
    const { stdout } = spawn(['xkb-switch', '-W']);

    for await (const data of stdout.pipeThrough(new TextDecoderStream())) {
        const currentLanguage = data.trim();
        const currentWorkspace = await getWorkspace();

        const existing = tryGetSavedWorkspace(currentWorkspace);
        if (!!existing) {
            setSavedWorkspace(currentWorkspace, currentLanguage);
        } else {
            savedWorkspaces.push({ workspaceId: currentWorkspace, language: currentLanguage });
        }
    }
}

async function setInitialWorkspaceData() {
    savedWorkspaces.push({ workspaceId: await getWorkspace(), language: await getLanguage() });
}

async function getWorkspace() {
    const json = await $`i3-msg -t get_workspaces`.json();
    const focused = json.find((w: any) => w.focused);
    return focused.num;
}

function tryGetSavedWorkspace(workspaceId: number) {
    return savedWorkspaces.find((w: Workspace) => w.workspaceId === workspaceId);
}

function setSavedWorkspace(workspaceId: number, language: string) {
    const workspace = tryGetSavedWorkspace(workspaceId);
    if (workspace) {
        workspace.language = language;
    } else {
        savedWorkspaces.push({ workspaceId, language });
    }
}

async function getLanguage() {
    return await $`xkblayout-state print %s`.text();
}

async function setLanguage(language: string) {
    await $`xkblayout-state set ${availableLanguages.indexOf(language)}`;
}

async function switchLanguageOnWorkspaceChange(focusedWorkspaceId: number) {
    let currentLayout = await getLanguage();

    let savedWorkspace = tryGetSavedWorkspace(focusedWorkspaceId);

    if (!tryGetSavedWorkspace(focusedWorkspaceId)) {
        savedWorkspaces.push({ workspaceId: focusedWorkspaceId, language: currentLayout });
        savedWorkspace = tryGetSavedWorkspace(focusedWorkspaceId);
    }

    if (savedWorkspace.language !== currentLayout) {
        await setLanguage(savedWorkspace.language);
    }
}