# Neovim setup for Zig

Zig is an open-source, statically-typed programming language designed with a focus on simplicity, performance, and safety. Created by Andrew Kelley, Zig aims to provide a modern alternative to existing programming languages, offering low-level control without sacrificing developer convenience.

I first learned about Zig just a few months ago. However, with the recent surge of languages attempting to replace C/C++, such as Rust, Carbon, Nim, and others, I initially held a degree of skepticism toward yet another contender. It seemed like another attempt to replace the longstanding C/C++. Nevertheless, as I observed Zig gaining traction in the indie game development scene, my curiosity was piqued, prompting me to explore it further. The more I delve into its features, the more I find myself drawn to it. This growing affinity led me to take the step of setting up a development environment on Windows, eager to give Zig a chance and test how it feels to program in this language.

# Zig installation

First, we are going to install manually Zig by downloading a release for Windows from the official website:

1. Go to [Download ⚡ Zig Programming Language (ziglang.org)](https://ziglang.org/download/)
    
2. Download the release for Windows (e.g.: zig-windows-x86\_64-0.12.0-dev.1819+5c1428ea9.zip)
    
3. Unzip the file in the folder that you want (e.g.: C:\\Users\\&lt;username&gt;\\zig)
    

After that, we need to add the path of the unzipped folder (i.e.: C:\\Users\\&lt;username&gt;\\zig\\zig-windows-x86\_64-0.12.0-dev.1819+5c1428ea9) to the **PATH** environment variable, so that we can run Zig from any location.

## Test installation

Now that we have Zig installed, we can check if it works properly. The **zig init** command sets up the basic structure and configuration files needed for a Zig project. Open a Terminal and type the following commands:

```powershell
mkdir zig_hello_world
cd zig_hello_world
zig init
```

This command creates an example program containing a basic main function that prints a message, and a unit test.

```c
const std = @import("std");

pub fn main() !void {
    // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
    std.debug.print("All your {s} are belong to us.\n", .{"codebase"});

    // stdout is for the actual output of your application, for example if you
    // are implementing gzip, then only the compressed bytes should be sent to
    // stdout, not any debugging messages.
    const stdout_file = std.io.getStdOut().writer();
    var bw = std.io.bufferedWriter(stdout_file);
    const stdout = bw.writer();

    try stdout.print("Run `zig build test` to run the tests.\n", .{});

    try bw.flush(); // don't forget to flush!
}

test "simple test" {
    var list = std.ArrayList(i32).init(std.testing.allocator);
    defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
    try list.append(42);
    try std.testing.expectEqual(@as(i32, 42), list.pop());
}
```

We can execute the main function by running the command **zig build run**:

```powershell
zig build run
All your codebase are belong to us.
Run `zig build test` to run the tests.
```

To run the unit test, we just have to run the command **zig build test**, which will not print anything. But we can check that it works properly by modifying the value to be expected in the unit test.

```powershell
zig build test
```

# Neovim

## Language Server

To install the Zig Language Server we can download the Windows version from the following website:

* [Zig Language Server](https://github.com/zigtools/zls/wiki/Installation#install-zls)
    

After downloading it, we have to copy the **zls.exe** file to the **path** where we have installed Zig (i.e.: C:\\Users\\&lt;username&gt;\\zig\\zig-windows-x86\_64-0.12.0-dev.1819+5c1428ea9).

Then, we have to configure the language server in our Neovim configuration file. I prefer to use a local configuration file (i.e.: **.nvim.lua**), instead of the global Neovim configuration files as I explain in my [book about Neovim](https://t.co/CSEJEmUrU2).

[![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765790582088/ca3a4ab5-125b-4383-a8ec-3c0b524d23ff.png align="center")](https://www.amazon.com/dp/B0CCW8PGKV)

There I also explain how to configure the main actions of **lspconfig** in Neovim.

```c
require 'lspconfig'.zls.setup{}
```

We can check that it works properly by opening the **main.zig** function, and showing the details of a function.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702853862760/93b59dba-339b-479e-9ccd-f53ffe02d868.png align="center")

## Debugger

### LLVM

To debug Zig code we will use **LLDB**, which is included in the LLVM installation. We can download the LLVM version for Windows (e.g.: LLVM-16.0.6-win64.exe) from the following website:

* [LLVM](https://github.com/llvm/llvm-project/releases)
    

### Python

Once we have LLVM installed, we need to install the Python version required by that LLVM version. We can check that by running LLDB from a terminal. It will show an error dialog complaining of the missing Python DLL (e.g.: python310.dll not found). For the LLVM-16.0.6 version, we need to install the Python version 3.10.x (e.g.: python-3.10.10-amd64.exe). We can download it from the website:

* [Python](https://www.python.org/downloads/windows/)
    

Finally, we need to define the following **environment variable**:

```powershell
LLDB_USE_NATIVE_PDB_READER="yes"
```

After that, we can check **lldb** from a terminal and debug the executable coming out from the example program:

```c
PS C:\Users\<username>\zig_hello_world> lldb.exe .\zig-out\bin\zig_hello_world.exe
(lldb) target create ".\\zig-out\\bin\\hello_world.exe"
Current executable set to 'C:\Users\<username>\zig_hello_world\zig-out\bin\zig_hello_world.exe' (x86_64).
(lldb) (lldb) b main
Breakpoint 1: where = zig_hello_world.exe`main + 26 at main.zig:5, address = 0x00000001400013fa
(lldb) r
(lldb) Process 28096 launched: 'C:\Users\<username>\zig_hello_world\zig-out\bin\zig_hello_world.exe' (x86_64)
Process 28096 stopped
* thread #1, stop reason = breakpoint 1.1
    frame #0: 0x00007ff7d46b13fa zig_hello_world.exe`main at main.zig:5
   2
   3    pub fn main() !void {
   4        // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
-> 5        std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
   6
   7        // stdout is for the actual output of your application, for example if you
   8        // are implementing gzip, then only the compressed bytes should be sent to
(lldb)
```

As Neovim supports the Debug Adapter Protocol (**DAP**), we can debug directly from Neovim. To configure Zig debugging in Neovim we can use the **nvim-dap** plugin. The required configuration for Zig that we need to add to our local Neovim configuration files (i.e.: **.nvim.lua**) is the following:

```c
local dap = require('dap')
dap.adapters.lldb = {
  type = 'executable',
  command = 'C:\\Program Files\\LLVM\\bin\\lldb-vscode.exe', -- adjust as needed, must be absolute path
  name = 'lldb'
}

dap.configurations.zig = {
  {
    name = 'Launch',
    type = 'lldb',
    request = 'launch',
    program = '${workspaceFolder}/zig-out/bin/zig_hello_world.exe',
    cwd = '${workspaceFolder}',
    stopOnEntry = false,
    args = {},
  },
}
```

Then, you can start a debugging session from Neovim, and move around the source code while inspecting the execution flow of the program.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702903975549/61004b79-2d3d-46ab-89d1-572e35ff1374.png align="center")

# Bonus: VScode setup

If you don't feel comfortable working with a text editor like Neovim, I'm going to give you the instructions to configure VScode to work with Zig as VScode is one of the most commonly used IDEs nowadays. To add support for Zig, you just need to install the **Zig extension** from the VScode marketplace.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702852119229/feaee2be-0aab-4253-af3f-ae1934b867a3.png align="center")

Now that we have the Zig extension installed, we can open the folder of the example project that we created previously (i.e.: zig\_hello\_world) from VScode. When we open the **main.zig** file, VScode will ask us to install **Zig** and the **Zig Language Server**. It will install them under the **local** VScode directory (e.g.: c:\\Users\\&lt;username&gt;\\AppData\\Roaming\\Code\\User\\globalStorage\\ziglang.vscode-zig\\zig\_install\\zig.exe).

Once we have the Zig Language Server installed, we can test it by opening the **main.zig** file and placing the cursor over one of the functions (e.g.: std.debug.print). It will pop up a dialog showing details about the selected function.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702852734571/8c89a5bb-9340-4974-8ad4-538edb81a4d8.png align="center")

Lastly, we can configure the **debugger** for Zig by creating the following **launch.json** file:

```json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/zig-out/bin/zig_hello_world.exe",
            "cwd": "${workspaceFolder}",
        },
    ]
}
```

After that, if we place a breakpoint on one of the lines of the **main.zig** file and press **F5** to start a debugging session, we will see how the program execution stops at the breakpoint:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702852966590/1186fc92-49fb-436b-b99c-abbebc5219ec.png align="center")

And that's all. I hope this post helps you set up a development environment for Zig so that you can give this language a try. It is promising, especially for game development, where I've seen several indie games and engines already implemented using Zig. In the case of Linux, the setup is pretty similar to this one. You just need to pick the versions corresponding to Linux for each product, but the steps would be pretty much the same.

See you in the next post!
