aboutsummaryrefslogtreecommitdiff
path: root/users/ryan/modules/simple-bar/simple-bar-source/lib/yabai.js
blob: 1a560682b0f624844d8122931a214f7aca449472 (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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import * as Uebersicht from "uebersicht";
import * as Settings from "./settings";
import * as Utils from "./utils";

/**
 * Focuses on the specified space.
 * @param {number} index - The index of the space to focus on.
 */
export async function goToSpace(index) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  await Uebersicht.run(`${yabaiPath} -m space --focus ${index}`);
}

/**
 * Renames the specified space.
 * @param {number} index - The index of the space to rename.
 * @param {string} label - The new label for the space.
 */
export async function renameSpace(index, label) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  await Uebersicht.run(`${yabaiPath} -m space ${index} --label "${label}"`);
}

/**
 * Creates a new space on the specified display.
 * @param {number} displayId - The ID of the display to create the space on.
 */
export async function createSpace(displayId) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  await focusDisplay(displayId);
  await Uebersicht.run(`${yabaiPath} -m space --create`);
  await Utils.softRefresh();
}

/**
 * Removes the specified space from the specified display.
 * @param {number} index - The index of the space to remove.
 * @param {number} displayId - The ID of the display to remove the space from.
 */
export async function removeSpace(index, displayId) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  await focusDisplay(displayId);
  await Uebersicht.run(`${yabaiPath} -m space ${index} --destroy`);
  await Utils.softRefresh();
}

/**
 * Swaps the specified space with the space in the given direction.
 * @param {number} index - The index of the space to swap.
 * @param {string} direction - The direction to swap the space ("left" or "right").
 */
export async function swapSpace(index, direction) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  const action = direction === "left" ? index - 1 : index + 1;
  await Uebersicht.run(`${yabaiPath} -m space ${index} --swap ${action}`);
  await Utils.softRefresh();
}

/**
 * Focuses on the specified window.
 * @param {number} id - The ID of the window to focus on.
 */
export async function focusWindow(id) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  await Uebersicht.run(`${yabaiPath} -m window --focus ${id}`);
}

/**
 * Retrieves the list of spaces.
 * @returns {Promise<Object[]>} A promise that resolves to the list of spaces.
 */
export async function getSpaces() {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  const json = await Uebersicht.run(`${yabaiPath} -m query --spaces`);
  return Utils.parseJson(json);
}

/**
 * Retrieves the list of windows.
 * @returns {Promise<Object[]>} A promise that resolves to the list of windows.
 */
export async function getWindows() {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  const json = await Uebersicht.run(`${yabaiPath} -m query --windows`);
  const cleanedJson = json.replace(/\\\n/g, "").replace(/00000/g, "0");
  return Utils.parseJson(cleanedJson);
}

/**
 * Retrieves the list of displays.
 * @returns {Promise<Object[]>} A promise that resolves to the list of displays.
 */
export async function getDisplays() {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  const json = await Uebersicht.run(`${yabaiPath} -m query --displays`);
  return Utils.parseJson(json);
}

/**
 * Focus the given display.
 *
 * Silently ignores the error thrown when the display is already focused,
 * which is a known and harmless yabai behavior.
 *
 * @param {number|string} displayId - The ID of the display to focus.
 */
async function focusDisplay(displayId) {
  const settings = Settings.get();
  const { yabaiPath = "/opt/homebrew/bin/yabai" } = settings.global;
  try {
    await Uebersicht.run(`${yabaiPath} -m display --focus ${displayId}`);
  } catch (e) {
    const message = e?.toString?.() || "";
    if (!message.includes("cannot focus an already focused display")) {
      // eslint-disable-next-line no-console
      console.warn("Failed to focus display:", message);
    }
  }
}