Zed: Difference between revisions
Niklas Korz (talk | contribs) Mention home-manager remote server option |
Remote Server: setup clarification, simplification, and pro/cons. |
||
Line 30: | Line 30: | ||
== Remote Server == | == Remote Server == | ||
When connecting to a remote server running NixOS, Zed will automatically | When connecting to a remote server running NixOS, Zed will either automatically download a static server binary matching its version from the upstream Zed website onto the remote host, or will locally obtain then upload a static server binary (if <code>"upload_binary_over_ssh": true</code>) to the remote host, before connecting to it : | ||
:<syntaxhighlight lang="console"> | :<syntaxhighlight lang="console"> | ||
Line 41: | Line 41: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
In either case, the binary is placed in the <code>~/.zed_server</code> folder on the remote system, and must match the client Zed version exactly or the connection will fail. This same <code>~/.zed_server</code> location on the client system is also where locally downloaded binaries are stored before being uploaded via SSH to a remote system. | |||
While the default prebuilt binaries from the upstream Zed website work fine with the default nixpkgs definition of <code>zed-editor</code>, you may want to provide your own, whether for reasons related to custom patching or purely mistrust of prebuilt upstream binaries. | |||
The <code>zed-editor</code> provides an additional output, <code>remote_server</code>, for the server binary matching the client version. To make use of it you need the binary in <code>"${pkgs.zed-editor.remote_server}/bin"</code> placed/symlinked into your <code>~/.zed_server</code> folder (and <code>"upload_binary_over_ssh": true</code> included in the Zed client settings that specify each remote system). | |||
In a simple case, this can be setup with home-manager as follows: | |||
:<syntaxhighlight lang="nix"> | :<syntaxhighlight lang="nix"> | ||
{ pkgs, ... }: | { pkgs, ... }: | ||
{ | { | ||
home.file.".zed_server | home.file.".zed_server" = { | ||
source = "${pkgs.zed-editor.remote_server}/bin"; | |||
# keeps the folder writable, but symlinks the binaries into it | |||
recursive = true; | |||
}; | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Because the <code>~/.zed_server</code> folder is also used for external clients connecting to the current system as a remote, it's necessary to use the <code>recursive = true;</code> setting so only individual binaries are symlinked from the nix store into the folder, and the folder itself remains writable. When a client connects using a version that doesn't already have a matching server binary available, it will use its configured method to add the missing server binary. This same configuration may be set more easily via home-manager if you're managing your entire Zed config thru home-manager by setting <code>programs.zed-editor.installRemoteServer = true;</code> (the <code>programs.zed-editor.enable = true</code> must also be enabled for this to take effect, see below for further details about using the home-manager <code>programs.zed-editor</code>). | |||
</ | |||
If you want to prohibit clients from managing the Zed server binaries on your system when connecting to it as a remote, you can make the whole <code>~/.zed_server</code> folder read-only by symlinking the whole folder to the nix store. This will restrict clients to only be able to use one Zed server binary provided from your nixpkgs <code>zed-editor</code>, which has the indirect effect of also limiting to a single Zed client version that's allowed to connect. To do this, simply remove the <code>recursive = true;</code> or explicitly set it to <code>recursive = false;</code> (the default when not specified) on <code>home.file.".zed_server"</code>. | |||
Be aware however that Zed will refuse to connect to a remote if there is no remote server binary matching the exact Zed client version and it's unable to populate a matching one! | |||
== Home manager support == | == Home manager support == | ||
Line 86: | Line 70: | ||
'''userSettings''' option will be translated directly to '''json''' file. | '''userSettings''' option will be translated directly to '''json''' file. | ||
Note that home-manager configuration produces a '''read only <code>settings.json</code>'''. Zed assumes the <code>settings.json</code> is writable, and modifies it for all settings changed directly or indirectly from the GUI. Using a read-only version will prevent changing features like the current working model of the AI engine, or switching between AI engines. | |||
You can see an example of the home-manager configuration: | |||
:<syntaxhighlight lang="nix"> | :<syntaxhighlight lang="nix"> | ||
Line 96: | Line 80: | ||
programs.zed-editor = { | programs.zed-editor = { | ||
enable = true; | enable = true; | ||
## This populates the userSettings "auto_install_extensions" which is a very odd optional Zed setting. | |||
## It is not automatically populated or updated by Zed itself, and is only used at Zed startup to verify | |||
## these are present in the set of installed extensions. Other extensions may have been installed from the | |||
## GUI and Zed will do nothing to change those. Removing an extension from this list will NOT remove it from | |||
## Zed, that must be done manually from the GUI for every Zed instance using this config. | |||
extensions = ["nix" "toml" "elixir" "make"]; | extensions = ["nix" "toml" "elixir" "make"]; | ||
Revision as of 22:40, 13 May 2025
Zed is a graphical text editor focusing on speed and collaborative editing.
Its Linux support is fairly recent, the NixOS support even more so.
Installation
The package zed-editor is available only from channel 24.11 onward.
CLI support is installed and aliased to zeditor
LSP Support
By default, Zed will try to download pre-built LSP servers in ~/.local/share/zed/languages/
. This does not work for NixOS.
There's sadly no way to inject those from $PATH
for now. Worse, the way to point to the language server is language-specific, there is no global configuration flag for now.
The following sections contain some language-specific setup working on NixOS.
rust-analyzer
Here, we'll assume rust-analyzer is globally installed in your system profile at /run/current-system/sw/bin/rust-analyzer
. You may want to adapt this path in the following code snippet to something more relevant to your use case.
Add the following snippet to your zed configuration file:
"lsp": {
"rust-analyzer": {
"binary": {
"path": "/run/current-system/sw/bin/rust-analyzer",
},
}
}
Remote Server
When connecting to a remote server running NixOS, Zed will either automatically download a static server binary matching its version from the upstream Zed website onto the remote host, or will locally obtain then upload a static server binary (if "upload_binary_over_ssh": true
) to the remote host, before connecting to it :
➜ ~ ls .zed_server zed-remote-server-stable-0.169.2 ➜ ~ file .zed_server/zed-remote-server-stable-0.169.2 .zed_server/zed-remote-server-stable-0.169.2: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=b1ac2c83127e7a9a072840cd7c24d7d125c1b655, not stripped ➜ ~ ldd .zed_server/zed-remote-server-stable-0.169.2 statically linked
In either case, the binary is placed in the ~/.zed_server
folder on the remote system, and must match the client Zed version exactly or the connection will fail. This same ~/.zed_server
location on the client system is also where locally downloaded binaries are stored before being uploaded via SSH to a remote system.
While the default prebuilt binaries from the upstream Zed website work fine with the default nixpkgs definition of zed-editor
, you may want to provide your own, whether for reasons related to custom patching or purely mistrust of prebuilt upstream binaries.
The zed-editor
provides an additional output, remote_server
, for the server binary matching the client version. To make use of it you need the binary in "${pkgs.zed-editor.remote_server}/bin"
placed/symlinked into your ~/.zed_server
folder (and "upload_binary_over_ssh": true
included in the Zed client settings that specify each remote system).
In a simple case, this can be setup with home-manager as follows:
{ pkgs, ... }: { home.file.".zed_server" = { source = "${pkgs.zed-editor.remote_server}/bin"; # keeps the folder writable, but symlinks the binaries into it recursive = true; }; }
Because the ~/.zed_server
folder is also used for external clients connecting to the current system as a remote, it's necessary to use the recursive = true;
setting so only individual binaries are symlinked from the nix store into the folder, and the folder itself remains writable. When a client connects using a version that doesn't already have a matching server binary available, it will use its configured method to add the missing server binary. This same configuration may be set more easily via home-manager if you're managing your entire Zed config thru home-manager by setting programs.zed-editor.installRemoteServer = true;
(the programs.zed-editor.enable = true
must also be enabled for this to take effect, see below for further details about using the home-manager programs.zed-editor
).
If you want to prohibit clients from managing the Zed server binaries on your system when connecting to it as a remote, you can make the whole ~/.zed_server
folder read-only by symlinking the whole folder to the nix store. This will restrict clients to only be able to use one Zed server binary provided from your nixpkgs zed-editor
, which has the indirect effect of also limiting to a single Zed client version that's allowed to connect. To do this, simply remove the recursive = true;
or explicitly set it to recursive = false;
(the default when not specified) on home.file.".zed_server"
.
Be aware however that Zed will refuse to connect to a remote if there is no remote server binary matching the exact Zed client version and it's unable to populate a matching one!
Home manager support
Zed is supported by home-manager, this way you are able to make a reproducible Zed setup.
userSettings option will be translated directly to json file.
Note that home-manager configuration produces a read only settings.json
. Zed assumes the settings.json
is writable, and modifies it for all settings changed directly or indirectly from the GUI. Using a read-only version will prevent changing features like the current working model of the AI engine, or switching between AI engines.
You can see an example of the home-manager configuration:
{pkgs, lib, ... }: { programs.zed-editor = { enable = true; ## This populates the userSettings "auto_install_extensions" which is a very odd optional Zed setting. ## It is not automatically populated or updated by Zed itself, and is only used at Zed startup to verify ## these are present in the set of installed extensions. Other extensions may have been installed from the ## GUI and Zed will do nothing to change those. Removing an extension from this list will NOT remove it from ## Zed, that must be done manually from the GUI for every Zed instance using this config. extensions = ["nix" "toml" "elixir" "make"]; ## everything inside of these brackets are Zed options. userSettings = { assistant = { enabled = true; version = "2"; default_open_ai_model = null; ### PROVIDER OPTIONS ### zed.dev models { claude-3-5-sonnet-latest } requires github connected ### anthropic models { claude-3-5-sonnet-latest claude-3-haiku-latest claude-3-opus-latest } requires API_KEY ### copilot_chat models { gpt-4o gpt-4 gpt-3.5-turbo o1-preview } requires github connected default_model = { provider = "zed.dev"; model = "claude-3-5-sonnet-latest"; }; # inline_alternatives = [ # { # provider = "copilot_chat"; # model = "gpt-3.5-turbo"; # } # ]; }; node = { path = lib.getExe pkgs.nodejs; npm_path = lib.getExe' pkgs.nodejs "npm"; }; hour_format = "hour24"; auto_update = false; terminal = { alternate_scroll = "off"; blinking = "off"; copy_on_select = false; dock = "bottom"; detect_venv = { on = { directories = [".env" "env" ".venv" "venv"]; activate_script = "default"; }; }; env = { TERM = "alacritty"; }; font_family = "FiraCode Nerd Font"; font_features = null; font_size = null; line_height = "comfortable"; option_as_meta = false; button = false; shell = "system"; #{ # program = "zsh"; #}; toolbar = { title = true; }; working_directory = "current_project_directory"; }; lsp = { rust-analyzer = { binary = { # path = lib.getExe pkgs.rust-analyzer; path_lookup = true; }; }; nix = { binary = { path_lookup = true; }; }; elixir-ls = { binary = { path_lookup = true; }; settings = { dialyzerEnabled = true; }; }; }; languages = { "Elixir" = { language_servers = ["!lexical" "elixir-ls" "!next-ls"]; format_on_save = { external = { command = "mix"; arguments = ["format" "--stdin-filename" "{buffer_path}" "-"]; }; }; }; "HEEX" = { language_servers = ["!lexical" "elixir-ls" "!next-ls"]; format_on_save = { external = { command = "mix"; arguments = ["format" "--stdin-filename" "{buffer_path}" "-"]; }; }; }; }; vim_mode = true; ## tell zed to use direnv and direnv can use a flake.nix enviroment. load_direnv = "shell_hook"; base_keymap = "VSCode"; theme = { mode = "system"; light = "One Light"; dark = "One Dark"; }; show_whitespaces = "all" ; ui_font_size = 16; buffer_font_size = 16; }; }; }