# 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.