{ config, lib, pkgs, pkgs-unstable, ... }: let cfg = config.programs.zed-editor; ameba-ls = pkgs.stdenv.mkDerivation rec { pname = "ameba-ls"; version = "0.1.0"; src = let selectSystem = attrs: attrs.${pkgs.stdenv.hostPlatform.system} or (throw "Unsupported system: ${pkgs.stdenv.hostPlatform.system}"); in pkgs.fetchurl (selectSystem { x86_64-linux = { url = "https://github.com/crystal-lang-tools/ameba-ls/releases/download/v${version}/ameba-ls-${version}-x86_64-linux-musl.tar.gz"; hash = "sha256-NtqR8NHytuHT1XIhRVvnp7Lo4Ed9UGbISbTn/BfLGA8="; }; aarch64-linux = { url = "https://github.com/crystal-lang-tools/ameba-ls/releases/download/v${version}/ameba-ls-${version}-aarch64-linux-musl.tar.gz"; hash = "sha256-77iqdaI+Mqivk0/9jkNdGpluDbz297vsY9wzuipcPOU="; }; aarch64-darwin = { url = "https://github.com/crystal-lang-tools/ameba-ls/releases/download/v${version}/ameba-ls-${version}-aarch64-apple-darwin.tar.gz"; hash = "sha256-tDB+ZjgjlGjNg3DjX09z1dJnqTv9h/1sXiauBj7uHNc="; }; }); sourceRoot = "."; installPhase = '' runHook preInstall mkdir -p $out/bin cp ameba-ls $out/bin/ chmod +x $out/bin/ameba-ls runHook postInstall ''; meta = with lib; { description = "Language server for the Ameba linter for Crystal lang"; homepage = "https://github.com/crystal-lang-tools/ameba-ls"; license = licenses.mit; platforms = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ]; mainProgram = "ameba-ls"; }; }; in { options.programs.zed-editor = { defaultEditor = lib.mkOption { type = lib.types.bool; default = false; }; }; config = lib.mkIf cfg.enable { programs.zed-editor = { package = pkgs-unstable.zed-editor; extensions = [ "ruby" "crystal" "nix" "svelte" ]; userSettings = { node = { path = lib.getExe pkgs.nodejs_latest; npm_path = lib.getExe' pkgs.nodejs_latest "npm"; }; agent = { enabled = true; default_model = { provider = "openai"; model = "kimi-k2.5"; }; }; auto_update = false; telemetry = { diagnostics = false; metrics = false; }; vim_mode = true; languages = { Ruby = { language_servers = [ "ruby-lsp" "rubocop" "!solargraph" ]; formatter.external = { command = pkgs.writeShellScript "rufo" '' bundle exec rufo "$@" if [ $? -eq 1 ]; then exit 1 fi ''; arguments = [ "--filename" "{buffer_path}" ]; }; }; Nix = { formatter.external = { command = lib.getExe pkgs.nixfmt-rfc-style; arguments = [ "-q" ]; }; }; Rust = { formatter.external = { command = lib.getExe pkgs.rustfmt; arguments = [ "--edition" "2018" ]; }; }; Crystal = { language_servers = [ "crystalline" "ameba-ls" ]; formatter.external = { command = lib.getExe pkgs.crystal; arguments = [ "tool" "format" "--no-color" "-" ]; }; }; }; lsp = with pkgs; { nixd.binary.path = lib.getExe nixd; nil.binary.path = lib.getExe nil; ruby-lsp = { initialization_options = { enabledFeatures = { codeActions = true; codeLens = true; completion = true; definition = true; diagnostics = true; documentHighlights = true; documentLink = true; documentSymbols = true; foldingRanges = true; formatting = false; hover = true; inlayHint = true; onTypeFormatting = true; selectionRanges = true; semanticHighlighting = true; signatureHelp = true; typeHierarchy = true; workspaceSymbol = true; }; linters = [ "standard" ]; }; settings.use_bundler = true; }; rubocop.binary = { path = "bundle"; arguments = [ "exec" "rubocop" "--lsp" ]; }; yaml-language-server.binary = { path = lib.getExe yaml-language-server; arguments = [ "--stdio" ]; }; json-language-server.binary = { path = lib.getExe nodePackages.vscode-json-languageserver; arguments = [ "--stdio" ]; }; package-version-server.binary.path = lib.getExe pkgs-unstable.package-version-server; eslint.settings.onIgnoredFiles = "off"; crystalline.binary.path = lib.getExe crystalline; ameba-ls.binary.path = lib.getExe ameba-ls; rust-analyzer.binary.path = lib.getExe rust-analyzer; }; load_direnv = "shell_hook"; theme = { mode = "system"; light = "One Light"; dark = "One Dark"; }; terminal = { line_height = "standard"; font_family = "IosevkaTerm Nerd Font"; }; edit_predictions = { enabled = true; mode = "eager"; provider = "copilot"; }; buffer_font_family = "Iosevka Nerd Font"; buffer_font_size = 16; ui_font_size = 17; relative_line_numbers = "enabled"; file_types = { JSONC = [ "tsconfig.json" "tsconfig.*.json" ]; }; language_models = { openai = { api_url = "https://opencode.ai/zen/v1"; available_models = [ # Claude models { name = "claude-opus-4-6"; display_name = "OpenCode Zen - Claude Opus 4.6"; max_tokens = 1048576; } { name = "claude-opus-4-5"; display_name = "OpenCode Zen - Claude Opus 4.5"; max_tokens = 200000; } { name = "claude-opus-4-1"; display_name = "OpenCode Zen - Claude Opus 4.1"; max_tokens = 200000; } { name = "claude-sonnet-4"; display_name = "OpenCode Zen - Claude Sonnet 4"; max_tokens = 1048576; } { name = "claude-sonnet-4-5"; display_name = "OpenCode Zen - Claude Sonnet 4.5"; max_tokens = 1048576; } { name = "claude-3-5-haiku"; display_name = "OpenCode Zen - Claude 3.5 Haiku"; max_tokens = 200000; } { name = "claude-haiku-4-5"; display_name = "OpenCode Zen - Claude Haiku 4.5"; max_tokens = 200000; } # GPT models { name = "gpt-5.2"; display_name = "OpenCode Zen - GPT 5.2"; max_tokens = 400000; } { name = "gpt-5.2-codex"; display_name = "OpenCode Zen - GPT 5.2 Codex"; max_tokens = 400000; } { name = "gpt-5.1"; display_name = "OpenCode Zen - GPT 5.1"; max_tokens = 400000; } { name = "gpt-5.1-codex-max"; display_name = "OpenCode Zen - GPT 5.1 Codex Max"; max_tokens = 400000; } { name = "gpt-5.1-codex"; display_name = "OpenCode Zen - GPT 5.1 Codex"; max_tokens = 400000; } { name = "gpt-5.1-codex-mini"; display_name = "OpenCode Zen - GPT 5.1 Codex Mini"; max_tokens = 400000; } { name = "gpt-5"; display_name = "OpenCode Zen - GPT 5"; max_tokens = 400000; } { name = "gpt-5-codex"; display_name = "OpenCode Zen - GPT 5 Codex"; max_tokens = 400000; } { name = "gpt-5-nano"; display_name = "OpenCode Zen - GPT 5 Nano"; max_tokens = 400000; } # Gemini models { name = "gemini-3-pro"; display_name = "OpenCode Zen - Gemini 3 Pro"; max_tokens = 1048576; } { name = "gemini-3-flash"; display_name = "OpenCode Zen - Gemini 3 Flash"; max_tokens = 1048576; } # GLM models { name = "glm-4.7"; display_name = "OpenCode Zen - GLM 4.7"; max_tokens = 205000; } { name = "glm-4.6"; display_name = "OpenCode Zen - GLM 4.6"; max_tokens = 205000; } { name = "glm-4.7-free"; display_name = "OpenCode Zen - GLM 4.7 Free"; max_tokens = 205000; } # Kimi models { name = "kimi-k2.5"; display_name = "OpenCode Zen - Kimi K2.5"; max_tokens = 262000; } { name = "kimi-k2.5-free"; display_name = "OpenCode Zen - Kimi K2.5 Free"; max_tokens = 262000; } { name = "kimi-k2"; display_name = "OpenCode Zen - Kimi K2"; max_tokens = 262000; } { name = "kimi-k2-thinking"; display_name = "OpenCode Zen - Kimi K2 Thinking"; max_tokens = 262000; } # MiniMax models { name = "minimax-m2.1"; display_name = "OpenCode Zen - MiniMax M2.1"; max_tokens = 205000; } { name = "minimax-m2.5-free"; display_name = "OpenCode Zen - MiniMax M2.5 Free"; max_tokens = 205000; } { name = "minimax-m2.1-free"; display_name = "OpenCode Zen - MiniMax M2.1 Free"; max_tokens = 205000; } # Other models { name = "trinity-large-preview-free"; display_name = "OpenCode Zen - Trinity Large Preview Free"; max_tokens = 131000; } { name = "big-pickle"; display_name = "OpenCode Zen - Big Pickle"; max_tokens = 200000; } { name = "alpha-g5"; display_name = "OpenCode Zen - Alpha G5"; max_tokens = 200000; } ]; }; }; }; userKeymaps = [ { context = "VimControl && !menu"; bindings = { "space g" = [ "task::Spawn" { task_name = "lazygit"; reveal_target = "center"; } ]; "space r" = "pane::DeploySearch"; "space f" = [ "file_finder::Toggle" { separate_history = true; } ]; "space :" = "task::Spawn"; "g R" = "editor::FindAllReferences"; }; } { context = "Dock || Pane || Editor"; bindings = { "ctrl-h" = "workspace::ActivatePaneLeft"; "ctrl-j" = "workspace::ActivatePaneDown"; "ctrl-k" = "workspace::ActivatePaneUp"; "ctrl-l" = "workspace::ActivatePaneRight"; }; } { context = "Terminal"; bindings = { "ctrl-p" = [ "terminal::SendKeystroke" "ctrl-p" ]; }; } ]; userTasks = [ { label = "lazygit"; command = lib.getExe config.programs.lazygit.package; env = { EDITOR = lib.getExe cfg.package; }; args = [ "-p" "$ZED_WORKTREE_ROOT" ]; reveal = "always"; allow_concurrent_runs = true; use_new_terminal = false; hide = "on_success"; } ]; }; home.sessionVariables = lib.mkIf cfg.defaultEditor { EDITOR = "${lib.getExe cfg.package} -w"; }; }; }