Configuring VSCode with Nix on macOS

Nov 24 2024
4 minutes

Welcome back to the Nix on Mac series! By the end of this post, you’ll be able to fully configure VSCode through your Nix flake via home-manager, which we set up in part 2. This includes:

  • Custom keybindings and settings
  • Installing themes and extensions from nixpkgs and directly from the VSCode Marketplace
  • Properly aliasing VSCode and other macOS applications to /Applications for Spotlight

Without further ado, let’s dive in!

Installing VSCode

Nix won’t install non-free software like VSCode without you opting in. Add this line to your nix-darwin configuration module:

configuration = { pkgs, ... }: {
    # ...
    
    nixpkgs.config.allowUnfree = true;
    
    # ...
};

After that, installing VSCode is just one line of code in our home-manager config:

homeconfig = { pkgs, ... }: {
    programs.vscode = {
        enable = true;
    };
};

I’m sure many of you who are following along are using VSCode to edit your flake.nix file. I should note that installing VSCode through home-manager will likely blow away your existing settings when you call switch. Now would be a good time to back up your existing settings and extension list so you can replicate your setup from within Nix.

VSCode will be installed in /Users/$USER/Applications/Home Manager Apps/Notably, this isn’t inside the normal /Applications folder since home-manager can only install programs under your home directory. Even stranger, Spotlight can’t pick up our alias! We’ll come back and fix this at the end of the post. after running switch.

If you’ve previously installed VSCode, go ahead and dump the copy from /Applications in the trash. Where we’re going, we don’t need roads globally installed programs!

Editor Settings and Keybindings

You can add user settings and keybindings pretty easily:

programs.vscode = {
    enable = true;

    userSettings = {
        # This property will be used to generate settings.json:
        # https://code.visualstudio.com/docs/getstarted/settings#_settingsjson
        "editor.formatOnSave" = true;
    };
    keybindings = [
        # See https://code.visualstudio.com/docs/getstarted/keybindings#_advanced-customization
        {
            key = "shift+cmd+j";
            command = "workbench.action.focusActiveEditorGroup";
            when = "terminalFocus";
        }
    ];
};

It almost looks like JSON! And in fact, converting Nix types to and from JSON is part of the Nix standard library.

Extensions

A huge part of VSCode is the bountiful extension ecosystem. home-manager lets you install many extensions from nixpkgs directly and also gives you a way to install any other ones from the marketplace directly.

From nixpkgs

You can search for the vscode-extensions package set on nixpkgs search to find out what’s available. We’ll start off with an extension (the Nix extension, obvously) and a theme (Dracula):

programs.vscode {
    # ...
    
    userSettings = {
        # ...
        "workbench.colorTheme" = "Dracula";
    };
    
    # ...

    extensions = with pkgs.vscode-extensions; [
        bbenoist.nix
        dracula-theme.theme-dracula
    ]
}

Some extensions require you to reload VSCode after installing. Unlike VSCode’s normall installation flow, VSCode will not tell you to reload after switch is called. In general I recommend just always restarting VSCode after running switch if you adjusted the extensions list.

From the VSCode Marketplace

Not every extension has been pre-built for Nix. Nixpkgs also exposes a function to download and build any extension directly from the VSCode Marketplace.

We’ll be installing nixpkgs-fmt, which will let us auto-format our Nix code when we save a .nix file. The extension also requires the binary nixpkgs-fmt to be in our PATH. We’ll add nixpkgs-fmt to both the VSCode extensions list and the home-manager package list:

homeconfig = { pkgs, ... }: {
    # ...

    home.packages = with pkgs; [ nixpkgs-fmt ];
    
    # ...

    programs.vscode {
        # ...

        extensions = with pkgs.vscode-extensions; [
            bbenoist.nix
            dracula-theme.theme-dracula
            vscodevim.vim
        ] ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
            {
              name = "nixpkgs-fmt";
              publisher = "b4dm4n";
              version = "0.0.1";
              sha256 = "bf3da4537e81d7190b722d90c0ba65fd204485f49696d203275afb4a8ac772bf";
            }
        ]
    }
}

Run switch again, restart VSCode, and your nix.flake should format itself nicely whenever you save.

Computing extension checksums

Whoa, where did that hash come from? It’s a checksum of one of the extension’s metadata files. We can download that file from vsassets.io and grab its checksum:

$ curl https://b4dm4n.gallery.vsassets.io/_apis/public/gallery/publisher/b4dm4n/extension/nixpkgs-fmt/0.0.1/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage | sha256sum
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3889  100  3889    0     0  10803      0 --:--:-- --:--:-- --:--:-- 10832
bf3da4537e81d7190b722d90c0ba65fd204485f49696d203275afb4a8ac772bf  -

It would be pretty gross if you needed to remember this every time. We can add it as a shell function to our zsh config:


home.packages = with pkgs; [
    nixpkgs-fmt
    coreutils-full # for sha256sum
];

# ...

programs.zsh = {
    # ...

    envExtra = ''
        function vscode-hash() {
            if [ "$#" -ne 3 ]; then
            echo "Error: This function requires exactly 3 arguments"
            echo "Usage: $0 <PUBLISHER> <NAME> <VERSION>"
            return 1
            fi
            publisher=$1
            name=$2
            version=$3
            url="https://$publisher.gallery.vsassets.io/_apis/public/gallery/publisher/$publisher/extension/$name/$version/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"
            curl $url | sha256sum
    }'';
};

Easy peasy!

Playing nice with Spotlight

You might have noticed that the version of VSCode that Nix installs doesn’t show up in Spotlight. Why is that? It’s unfortunately pretty simple: All artifacts that Nix and home-manager add to your system are symbolic links, and Spotlight won’t index symlinks. There’s a very long thread about this on GitHub if you’re interested in reading. From the various options discussed there, mac-app-util is the easiest way to get Spotlight working as expected.

We can add it as another input at the top of our flake and then modify our flake output to load mac-app-util in both nix-darwin and home-manager:

{
    description = "My system configuration";
    inputs = {
        # ...
        mac-app-util.url = "github:hraban/mac-app-util";
    };

    # ...

    in
    {
      darwinConfigurations."$HOSTNAME" = nix-darwin.lib.darwinSystem {
        modules = [
          # ...
          mac-app-util.darwinModules.default
          home-manager.darwinModules.home-manager
          {
            # ...
            home-manager.sharedModules = [
                mac-app-util.homeManagerModules.default
            ];
            # ...
          }
        ];
      };
    }
}

After running switch, VSCode should be properly copied to /Users/$USER/Applications/Home Manager Trampolines and should be available the next time Spotlight refreshes.

Stepping Back

We just included someone’s third-party Nix utility in our flake to do some custom behavior when Nix installs macOS GUI apps. You probably didn’t notice that mac-app-util is written in Common Lisp. I’ve never written Common Lisp, and my guess is you haven’t either. Even so, with fewer than five lines of code we were able make use of some code that someone wrote in their favorite niche programming language without needing to figure out how to build or run that code. Nix handled it all for us! I, for one, think that’s pretty amazing.

Conclusion

Our Nix config is now able to fully configure and manage VSCode, including installing extensions and themes. home-manager has just as deep an integration with many other utilities. If you haven’t already definitely go through and check out home-manager’s config options to find out what you can do with your favorite program.

You can find the full flake.nix for this installment on GitHub here. See you in the next one!

nix vscode nix-on-mac editors