Text · 6070 bytes Raw Blame History
1 # Lua API (gar)
2
3 tarmac exposes a global `gar` table in the Lua config environment. This is the sole interface for configuring tarmac from `init.lua`.
4
5 ## gar.set(key, value)
6
7 Set a configuration option. Both arguments are strings.
8
9 ```lua
10 gar.set("gap_inner", "8")
11 gar.set("mod_key", "command")
12 gar.set("focus_follows_mouse", "true")
13 ```
14
15 See [Settings Reference](/docs/configuration/settings) for all available keys.
16
17 ## gar.bind(keys, action)
18
19 Register a global hotkey. The `keys` string uses `+` to combine modifiers and a key name. The `action` string specifies what happens when the key is pressed.
20
21 ```lua
22 gar.bind("mod+h", "focus left")
23 gar.bind("mod+shift+q", "close")
24 gar.bind("mod+return", "spawn terminal")
25 ```
26
27 ### Key string format
28
29 Modifiers:
30 - `mod` replaced by the current `mod_key` setting
31 - `shift` Shift key
32 - `ctrl` Control key
33 - `alt` Option key
34 - `fn` Function key
35
36 Key names: `a`-`z`, `0`-`9`, `return`, `space`, `tab`, `escape`, `delete`, `grave`, `minus`, `equal`, `leftbracket`, `rightbracket`, `semicolon`, `quote`, `comma`, `period`, `slash`, `backslash`, `left`, `right`, `up`, `down`, `f1`-`f12`.
37
38 ### Action strings
39
40 | Action | Description |
41 |--------|-------------|
42 | `focus left\|right\|up\|down` | Move focus in a direction |
43 | `swap left\|right\|up\|down` | Swap the focused window with its neighbor |
44 | `resize left\|right\|up\|down` | Adjust the split ratio toward a direction |
45 | `close` | Close the focused window |
46 | `equalize` | Reset all split ratios to 50/50 |
47 | `toggle-floating` | Toggle the focused window between tiled and floating |
48 | `workspace N` | Switch to workspace N (1-10) |
49 | `move-to-workspace N` | Move focused window to workspace N |
50 | `toggle-special NAME` | Toggle a named scratchpad's visibility |
51 | `move-to-special NAME` | Move focused window to a named scratchpad |
52 | `focus-monitor next\|prev` | Focus the next or previous monitor |
53 | `move-to-monitor next\|prev` | Move focused window to the next or previous monitor |
54 | `workspace next\|prev` | Cycle to next or previous workspace |
55 | `spawn terminal` | Run the `terminal` command |
56 | `reload` | Hot reload the config |
57
58 ### Dynamic keybinds with Lua loops
59
60 Since the config is Lua, you can generate repetitive keybinds programmatically:
61
62 ```lua
63 for i = 1, 9 do
64 gar.bind("mod+" .. i, "workspace " .. i)
65 gar.bind("mod+shift+" .. i, "move-to-workspace " .. i)
66 end
67 gar.bind("mod+0", "workspace 10")
68 gar.bind("mod+shift+0", "move-to-workspace 10")
69 ```
70
71 ## gar.rule(match, actions)
72
73 Define a window rule. The first argument is a table of match criteria, the second is a table of actions to apply.
74
75 ```lua
76 gar.rule({ app_name = "Calculator" }, { floating = true })
77 gar.rule({ app_bundle = "com.apple.Safari" }, { workspace = 2 })
78 gar.rule({ app_name = "System Settings" }, { floating = true })
79 gar.rule({ title = "Picture in Picture" }, { floating = true })
80 ```
81
82 ### Match criteria
83
84 | Key | Type | Description |
85 |-----|------|-------------|
86 | `app_name` | string | Match by application name (e.g., `"Firefox"`) |
87 | `app_bundle` | string | Match by bundle identifier (e.g., `"com.apple.Safari"`) |
88 | `title` | string | Match by window title |
89
90 All specified criteria must match (AND logic). If multiple criteria are set, all must be true.
91
92 ### Rule actions
93
94 | Key | Type | Description |
95 |-----|------|-------------|
96 | `floating` | bool | Force window into floating state |
97 | `workspace` | string/number | Assign to workspace: `1`-`10` or `"special:name"` |
98 | `geometry` | table | Initial position and size: `{x, y, width, height}` |
99
100 Geometry example:
101
102 ```lua
103 gar.rule(
104 { app_name = "Music" },
105 { floating = true, geometry = { 100, 100, 800, 600 } }
106 )
107 ```
108
109 See [Window Rules](/docs/window-rules) for more details.
110
111 ## gar.on(event, callback)
112
113 Register a Lua callback for a window manager event. Callbacks receive rich data as Lua tables.
114
115 ```lua
116 gar.on("window_focused", function(info)
117 print("focused: " .. info.app_name .. " - " .. info.title)
118 end)
119
120 gar.on("workspace_changed", function(old, new)
121 gar.exec("echo '" .. new .. "' > /tmp/tarmac-workspace")
122 end)
123
124 gar.on("window_created", function(info)
125 print("new window: " .. info.app_name)
126 end)
127
128 gar.on("layout_changed", function(info)
129 print("workspace " .. info.workspace .. ": " .. info.window_count .. " windows")
130 end)
131
132 gar.on("monitor_changed", function(info)
133 print("monitor " .. info.index)
134 end)
135 ```
136
137 Available events: `workspace_changed`, `window_focused`, `window_created`, `window_closed`, `layout_changed`, `monitor_changed`.
138
139 See [Events & Hooks](/docs/events-hooks) for the full event reference.
140
141 ## gar.exec(command)
142
143 Execute a shell command via `/bin/sh -c`. Runs asynchronously (does not block tarmac).
144
145 ```lua
146 gar.exec("open -a Safari")
147 gar.exec("osascript -e 'display notification \"tarmac reloaded\"'")
148 ```
149
150 ## gar.exec_once(command)
151
152 Like `gar.exec()`, but first checks if a process matching the command is already running. If it is, the command is skipped. Useful for autostart programs that shouldn't spawn duplicates on config reload.
153
154 ```lua
155 gar.exec_once("open -a WezTerm")
156 gar.exec_once("open -a Firefox")
157 ```
158
159 ## gar.special_workspace(name, options)
160
161 Configure a named special workspace (scratchpad). These are overlay workspaces that can be toggled on any monitor.
162
163 ```lua
164 gar.special_workspace("term", {
165 position = "center",
166 width = 0.8,
167 height = 0.8,
168 })
169
170 gar.special_workspace("music", {
171 position = "bottom",
172 width = 1.0,
173 height = 0.4,
174 })
175 ```
176
177 ### Options
178
179 | Key | Type | Default | Description |
180 |-----|------|---------|-------------|
181 | `position` | string | `"center"` | Where to place the overlay: `"center"`, `"top"`, `"bottom"` |
182 | `width` | number | `0.7` | Width as fraction of screen (0.0 - 1.0) |
183 | `height` | number | `0.7` | Height as fraction of screen (0.0 - 1.0) |
184
185 After defining a special workspace, bind a key to toggle it:
186
187 ```lua
188 gar.bind("mod+grave", "toggle-special term")
189 gar.bind("mod+shift+grave", "move-to-special term")
190 ```
191
192 See [Special Workspaces](/docs/workspaces/special-workspaces) for usage details.
193