diff --git a/modules/capabilities/helix.nix b/modules/capabilities/helix.nix new file mode 100644 index 0000000..fa7e8ce --- /dev/null +++ b/modules/capabilities/helix.nix @@ -0,0 +1,470 @@ +{ config, ... }: +let + account = config.facts.account; +in +{ + flake.modules.homeManager.helix = + { + lib, + osConfig, + pkgs, + ... + }: + let + indent = { + tab-width = 2; + unit = " "; + }; + + oxfmt = { + name = "oxfmt"; + only-features = [ "format" ]; + }; + + oxlint = { + name = "oxlint"; + only-features = [ + "code-action" + "diagnostics" + ]; + }; + + webLanguageServers = [ + oxfmt + "vtsls" + oxlint + "tailwindcss-ls" + ]; + + markupLanguageServers = primary: [ + oxfmt + primary + "tailwindcss-ls" + "emmet-ls" + ]; + + ruffFormatter = pkgs.writeShellApplication { + name = "helix-ruff-format"; + runtimeInputs = [ pkgs.ruff ]; + text = '' + if (( $# != 1 )); then + echo "usage: helix-ruff-format " >&2 + exit 2 + fi + + filename=$1 + ruff check \ + --fix \ + --force-exclude \ + --exit-zero \ + --no-cache \ + --stdin-filename "$filename" \ + - \ + | ruff format \ + --force-exclude \ + --stdin-filename "$filename" \ + - \ + | ruff check \ + --fix \ + --force-exclude \ + --select=I001 \ + --exit-zero \ + --no-cache \ + --stdin-filename "$filename" \ + - + ''; + }; + in + { + programs.helix = { + enable = true; + + extraPackages = with pkgs; [ + ripgrep + fd + wl-clipboard + stylua + taplo + yamlfmt + lua-language-server + nixd + nixfmt + dafny + vscode-langservers-extracted + tailwindcss-language-server + rust-analyzer + rustfmt + astro-language-server + tinymist + typstyle + ty + ruff + vtsls + pkgs.oxlint + pkgs.oxfmt + emmet-language-server + svelte-language-server + ]; + + settings = { + theme = "lux-kanagawa"; + + editor = { + scrolloff = 10; + default-yank-register = "+"; + cursorline = true; + completion-timeout = 5; + color-modes = true; + popup-border = "all"; + + file-picker.hidden = false; + + indent-guides.render = true; + + inline-diagnostics.cursor-line = "hint"; + + lsp.display-inlay-hints = true; + + soft-wrap.enable = true; + + statusline = { + left = [ + "mode" + "spinner" + "version-control" + "file-name" + "read-only-indicator" + "file-modification-indicator" + ]; + right = [ + "diagnostics" + "selections" + "position-percentage" + "position" + "file-type" + ]; + separator = ""; + mode = { + normal = "NORMAL"; + insert = "INSERT"; + select = "SELECT"; + }; + diagnostics = [ + "error" + "warning" + "info" + "hint" + ]; + workspace-diagnostics = [ + "error" + "warning" + "info" + "hint" + ]; + }; + + whitespace = { + render = { + tab = "all"; + nbsp = "all"; + nnbsp = "all"; + }; + characters = { + tab = "»"; + nbsp = "␣"; + }; + }; + }; + + keys = { + insert."C-g" = "signature_help"; + + normal = { + esc = [ + "collapse_selection" + "keep_primary_selection" + ]; + + "C-h" = "jump_view_left"; + "C-j" = "jump_view_down"; + "C-k" = "jump_view_up"; + "C-l" = "jump_view_right"; + + "[".h = "goto_prev_change"; + "]".h = "goto_next_change"; + + g.I = "goto_implementation"; + + space = { + space = "buffer_picker"; + f = ":format"; + q = "diagnostics_picker"; + "/" = "search"; + + b.d = ":buffer-close"; + c.a = "code_action"; + d.s = "symbol_picker"; + h.r = ":reset-diff-change"; + r.n = "rename_symbol"; + t.h = ":toggle lsp.display-inlay-hints"; + + s = { + f = "file_picker"; + g = "global_search"; + d = "diagnostics_picker"; + r = "last_picker"; + "/" = "global_search"; + }; + }; + }; + }; + }; + + themes.lux-kanagawa = { + inherits = "kanagawa"; + "ui.gutter" = { + fg = "sumiInk6"; + }; + }; + + languages = { + language-server = { + dafny = { + command = "dafny"; + args = [ "server" ]; + }; + + emmet-ls = { + command = "emmet-language-server"; + args = [ "--stdio" ]; + }; + + lua-language-server = { + config.Lua = { + runtime.version = "LuaJIT"; + signatureHelp.enable = true; + diagnostics.globals = [ "vim" ]; + telemetry.enable = false; + completion.callSnippet = "Replace"; + hint.enable = true; + }; + }; + + nixd = { + config.nixd = { + nixpkgs.expr = "import ${pkgs.path} {}"; + options = { + nixos.expr = ''(builtins.getFlake "path://${account.nixosConfigurationPath}").nixosConfigurations.${osConfig.facts.machine.name}.options''; + home-manager.expr = ''(builtins.getFlake "path://${account.nixosConfigurationPath}").nixosConfigurations.${osConfig.facts.machine.name}.options.home-manager.users.type.getSubOptions []''; + }; + formatting.command = [ "nixfmt" ]; + }; + }; + + oxfmt = { + command = "oxfmt"; + args = [ "--lsp" ]; + required-root-patterns = [ + ".oxfmtrc.json" + ".oxfmtrc.jsonc" + "oxfmt.config.ts" + "package.json" + "vite.config.ts" + ]; + }; + + oxlint = { + command = "oxlint"; + args = [ "--lsp" ]; + required-root-patterns = [ + ".oxlintrc.json" + ".oxlintrc.jsonc" + "oxlint.config.ts" + "package.json" + "vite.config.ts" + ]; + }; + + tinymist = { + config.formatterMode = "typstyle"; + }; + + vtsls = { + command = "vtsls"; + args = [ "--stdio" ]; + config.vtsls.autoUseWorkspaceTsdk = true; + }; + }; + + language = [ + { + name = "lua"; + auto-format = true; + formatter = { + command = "stylua"; + args = [ + "--indent-type" + "Spaces" + "--indent-width" + "2" + "--search-parent-directories" + "--respect-ignores" + "--stdin-filepath" + "%{buffer_name}" + "-" + ]; + }; + } + { + name = "nix"; + auto-format = true; + language-servers = [ "nixd" ]; + } + { + name = "dafny"; + scope = "source.dafny"; + injection-regex = "dafny"; + file-types = [ + "dfy" + "dafny" + ]; + roots = [ ".git" ]; + comment-token = "//"; + block-comment-tokens = { + start = "/*"; + end = "*/"; + }; + inherit indent; + auto-format = true; + language-servers = [ "dafny" ]; + } + { + name = "json"; + language-servers = [ + oxfmt + "vscode-json-language-server" + ]; + } + { + name = "jsonc"; + language-servers = [ + oxfmt + "vscode-json-language-server" + ]; + } + { + name = "javascript"; + auto-format = true; + language-servers = webLanguageServers; + } + { + name = "jsx"; + auto-format = true; + language-servers = webLanguageServers ++ [ "emmet-ls" ]; + } + { + name = "typescript"; + auto-format = true; + language-servers = webLanguageServers; + } + { + name = "tsx"; + auto-format = true; + language-servers = webLanguageServers ++ [ "emmet-ls" ]; + } + { + name = "css"; + language-servers = markupLanguageServers "vscode-css-language-server"; + } + { + name = "scss"; + language-servers = markupLanguageServers "vscode-css-language-server"; + } + { + name = "less"; + scope = "source.css.less"; + injection-regex = "less"; + file-types = [ "less" ]; + grammar = "css"; + block-comment-tokens = { + start = "/*"; + end = "*/"; + }; + inherit indent; + auto-format = true; + language-servers = markupLanguageServers "vscode-css-language-server"; + } + { + name = "html"; + language-servers = markupLanguageServers "vscode-html-language-server"; + } + { + name = "rust"; + inherit indent; + } + { + name = "python"; + inherit indent; + auto-format = true; + language-servers = [ + "ty" + "ruff" + ]; + formatter = { + command = lib.getExe ruffFormatter; + args = [ "%{buffer_name}" ]; + }; + } + { + name = "astro"; + auto-format = true; + language-servers = [ + "astro-ls" + oxlint + "tailwindcss-ls" + "emmet-ls" + ]; + } + { + name = "svelte"; + auto-format = true; + language-servers = [ + oxfmt + "svelteserver" + oxlint + "tailwindcss-ls" + "emmet-ls" + ]; + } + { + name = "typst"; + auto-format = true; + } + { + name = "toml"; + auto-format = true; + language-servers = [ "taplo" ]; + formatter = { + command = "taplo"; + args = [ + "format" + "--stdin-filepath" + "%{buffer_name}" + "-" + ]; + }; + } + { + name = "yaml"; + auto-format = true; + language-servers = [ ]; + formatter = { + command = "yamlfmt"; + args = [ "-" ]; + }; + } + ]; + }; + }; + }; +} diff --git a/modules/profiles/host-base.nix b/modules/profiles/host-base.nix index 57ac844..6c52843 100644 --- a/modules/profiles/host-base.nix +++ b/modules/profiles/host-base.nix @@ -25,6 +25,7 @@ in hmModules.facts hmModules.syncthing hmModules.shell + hmModules.helix hmModules.neovim ]; };