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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
# IDE integration
YASL includes Zed debugger profiles for stepping from example applications into
the library's display and window creation code. Open the repository root (the
directory containing `meson.build`) as your Zed project. The shared configuration
uses `build/` for the build directory on Linux and macOS.
## Prerequisites
Install Zed, a C23 compiler, Meson 1.6 or newer, Ninja, pkg-config, and Python 3.
A C++ compiler enables the optional public-header compatibility test. Install
the backend development dependencies described in
[Getting started](docs/getting-started.md#build-and-run): at least one of Wayland
or X11 on Linux, or the macOS 14+ SDK on macOS. Running windows on macOS also
requires a Metal-capable device.
[Zed's C support](https://zed.dev/docs/languages/c) includes clangd for code
completion, diagnostics, and navigation, and CodeLLDB for debugging. Allow Zed
to obtain these tools when prompted, or configure your existing installations
in your personal Zed settings. Use a recent clangd with C23 support.
Make sure `meson`, `ninja`, your compiler, `pkg-config`, and `python3` are on the
PATH visible to Zed's terminal. You can open the project from an initialized
terminal with `zed .` when Zed's CLI is installed. On macOS, if your toolchain
defaults to an older deployment target, launch from a terminal with
`MACOSX_DEPLOYMENT_TARGET=14.0` (or newer) exported before configuring.
## Start debugging window creation
1. Save your changes and open `examples/hello.c`.
2. Set gutter breakpoints on the calls to `yasl_display_open()` and
`yasl_surface_create_toplevel()` in `main()`.
3. Open the command palette (`Ctrl+Shift+P` on Linux, `Cmd+Shift+P` on macOS),
run `debugger: start`, and choose **YASL: debug hello**.
4. The debugger prepares the build and pauses on entry. Continue to the display
creation breakpoint, then use **Step Into** to enter YASL's implementation in
`src/common/backend.c`. Continue to the surface creation breakpoint and step
into `yasl_surface_create_toplevel()` and `yasl_create_toplevel()`.
5. Step into `d->ops->surface_create_toplevel(...)` to reach native window
creation. Inspect `spec`, `d`, local variables, and the call stack in Zed's
debug panel. Use **Step Over** for calls you want to execute without entering.
Every debug profile runs **YASL: build for debugger** before launching. This
task creates or reconfigures `build/` with debug symbols, optimization disabled,
and LTO disabled, then builds the library and examples. It explicitly sets
`buildtype=debug`, `debug=true`, `optimization=0`, and `b_lto=false`, including
when `build/` was previously a release or customized build. Other Meson options,
including backend selection, are preserved. Both the example and YASL have
source-level debug information; the shared-library examples load the library
from the Meson build tree.
Profiles pause on entry through CodeLLDB's `stopOnEntry` setting, so initialization
does not run before you can inspect the session. To launch directly to your
breakpoints instead, set `"stopOnEntry": false` in the desired profile. See
[CodeLLDB's launch settings](https://github.com/vadimcn/codelldb/blob/master/MANUAL.md#launching-a-new-process).
Native creation follows the backend selected at runtime:
| Backend | Window creation implementation |
| --- | --- |
| Wayland | `wayland_surface_create_toplevel()` in `src/platform/wayland/surface.c` |
| X11 | `create_toplevel()` in `src/platform/x11/window.c` |
| Cocoa | `cocoa_surface_create_toplevel()` in `src/platform/cocoa/window.m` |
You can also put a source breakpoint directly in these functions before
launching. A breakpoint in a backend that is disabled or not selected will not
be hit. In the notepad and game examples, `yasl_run()` opens the display before
calling the example's initialization callback; set a breakpoint in `yasl_run()`
in `src/common/app.c` to follow that path.
## Configure and build without launching
1. Open the command palette (`Ctrl+Shift+P` on Linux, `Cmd+Shift+P` on macOS).
2. Run `task: spawn`, then select **YASL: configure debug build**.
3. Run **YASL: build** from the same task picker.
4. Open `examples/hello.c` or a file in `src/` to use completion and navigation.
The configure task runs:
```sh
meson setup build --backend=ninja --buildtype=debug
```
Meson's Ninja backend writes `build/compile_commands.json`. The root
[.clangd](.clangd) points clangd at that directory, so it uses Meson's actual
include paths, C standard, and enabled-backend definitions. Keep the generated
database in the ignored build directory; no root-level copy or symlink is
needed. The same configuration works with other clangd-based editors. See
[clangd's compilation database setting](https://clangd.llvm.org/config#compilationdatabase).
If `build/` is already configured, the configure task leaves its existing
options in place. To change an existing build to debug, run this in Zed's
terminal:
```sh
meson configure build -Dbuildtype=debug
```
Save edited files before building, running, or debugging. Use **YASL:
reconfigure** to rerun Meson configuration and refresh its metadata. Meson also
regenerates the build automatically when build definitions change.
## Tasks and examples
The project tasks live in [.zed/tasks.json](.zed/tasks.json). Select them with
`task: spawn`; `task: rerun` repeats the last task. See
[Zed's task documentation](https://zed.dev/docs/tasks) for personal keybindings.
| Task | Behavior |
| --- | --- |
| YASL: configure debug build | Set up `build/` with Ninja and debug symbols. |
| YASL: reconfigure | Reconfigure an existing `build/`, preserving its options. |
| YASL: build | Compile the library, examples, and enabled tests. |
| YASL: build for debugger | Configure symbols and disable optimization/LTO, then build. |
| YASL: test | Build as needed and run enabled tests, printing failure logs. |
| YASL: benchmark | Build as needed and run Meson's registered benchmarks. |
| YASL: run hello | Build and launch `yasl-hello`. |
| YASL: run simple window | Build and launch `yasl-example`. |
| YASL: run tablet | Build and launch `yasl-tablet`. |
| YASL: run notepad | Build and launch `yasl-notepad`. |
| YASL: run game | Build and launch `yasl-game`. |
Each run task builds its executable before launching and stops if compilation
fails. Run tasks explicitly use `sh` for their compound command. All tasks use
the repository root as their working directory, including when a nested source
file is active.
Examples need a desktop connection. On Linux, run Zed in your desktop session
so the launched program inherits `WAYLAND_DISPLAY`/`DISPLAY` and
`XDG_RUNTIME_DIR` as appropriate. Most tests can run without a display, but the
currently registered `app-runner` test opens a window even in a default build.
`app-input-destroy` also needs a Wayland compositor when `WAYLAND_DISPLAY` is
set. Run the full suite in a desktop session with the corresponding backend
enabled; additional tests retain their configured requirements.
## Debugging
The profiles in [.zed/debug.json](.zed/debug.json) use CodeLLDB. Run
`debugger: start` from the command palette and select an example. Profiles cover
hello, simple window, tablet, notepad, game, and the lifecycle test
(`build/tests/yasl-test`), which needs no display. Each profile builds through
**YASL: build for debugger** and pauses on entry.
See [Zed's debugger documentation](https://zed.dev/docs/debugger).
To debug another test, copy the lifecycle profile and change its `label` and
`program` to the executable under `build/tests/`. To pass example arguments,
add an `args` array to a debug profile; for example, the tablet profile accepts
`"args": ["--backend", "x11"]` when that backend is enabled.
## Backend options and additional builds
Linux backend selection defaults to automatic dependency detection. To require
X11 and disable Wayland in the IDE build, run:
```sh
meson configure build -Dx11=enabled -Dwayland=disabled
meson compile -C build
```
Restore automatic selection with `-Dx11=auto -Dwayland=auto`. Integration tests
are opt-in through `-Dintegration_tests=true`; their server dependencies and
desktop requirements are documented in [Testing](docs/testing.md).
For sanitizers or a different compiler, prefer a separate build directory:
```sh
meson setup build-sanitize -Db_sanitize=address,undefined
meson test -C build-sanitize --print-errorlogs
```
The checked-in Zed tasks and profiles continue to target `build/`. To use a
different directory throughout the IDE, update the tasks' build arguments and
run commands, debugger program paths, and `.clangd`'s `CompilationDatabase`
together. Ignore additional build directories locally (for example through
`.git/info/exclude`) and keep machine-specific tool paths out of shared files.
## Troubleshooting
- **Missing headers or incorrect backend diagnostics:** confirm that
`build/compile_commands.json` exists, build successfully, then run
`editor: restart language server`. clangd analyzes the backend configuration
in that database; disabled native backends may lack their SDK headers.
- **C23 syntax errors in the editor:** update clangd; the compiler used by Meson
and the clangd used by Zed are separate tools.
- **A task cannot find Meson or a compiler:** check `command -v meson ninja cc`
in Zed's terminal and fix the PATH used by Zed and its task shell.
- **No window opens:** check the desktop environment and enabled backends.
Use the lifecycle debug profile to check debugging without a display.
- **`app-runner` or `app-input-destroy` fails at startup:** check that the test
can connect to the inherited desktop session. For a headless check of the
lifecycle test alone, run `meson test -C build basic --print-errorlogs`.
- **Breakpoints do not bind:** use a **YASL: debug ...** profile so the debugger
build task runs, and confirm the executable and library come from `build/`.
Shared-library breakpoints may remain pending until the library loads. Check
that a native backend breakpoint belongs to the enabled, selected backend.
- **Configuration fails on macOS:** check the SDK and deployment target against
[Getting started](docs/getting-started.md#build-and-run). Compiler or SDK
changes may require a fresh build directory.
|