at main 553 lines 16 kB view raw
1{ 2 lib, 3 pkgs, 4 inputs', 5 self', 6 config, 7 ... 8}: 9let 10 jj-patch = pkgs.fetchurl { 11 url = "https://patch-diff.githubusercontent.com/raw/helix-editor/helix/pull/14519.patch"; 12 hash = "sha256-L+dcrYNApgNdMH5iWDhgGnmmtmKG2s/DnxOa7Ug/dsw="; 13 }; 14 helix = inputs'.helix.packages.default.overrideAttrs (_: { 15 patches = jj-patch; 16 }); 17 global-tools = with pkgs; [ 18 nixfmt 19 biome 20 golangci-lint 21 gotools 22 gopls 23 sql-formatter 24 nodePackages.prettier 25 ]; 26in 27lib.mkIf config.dev.editor.enable { 28 home.packages = global-tools; 29 programs.helix = { 30 enable = true; 31 defaultEditor = true; 32 package = helix; 33 extraPackages = 34 with pkgs; 35 [ 36 golangci-lint-langserver 37 nixd 38 marksman 39 nodePackages.typescript-language-server 40 vscode-langservers-extracted 41 yaml-language-server 42 typos-lsp 43 nil 44 ] 45 ++ global-tools; 46 47 ignores = [ 48 ".zig-cache" 49 "node_modules" 50 ".direnv" 51 "!/notes" 52 ]; 53 54 settings = { 55 keys = 56 let 57 plusMenu = { 58 g = '' 59 :sh ${pkgs.nushell}/bin/nu -c ' 60 let line = ("%{selection_line_start}" | default "%{cursor_line}") 61 let line_end = (if ("%{selection_line_end}" | is-not-empty) {$"-L%{selection_line_end}"} else "") 62 let root = (${pkgs.jujutsu}/bin/jj workspace root | str trim) 63 let rel_path = ("%{file_path_absolute}" | path relative-to $root) 64 let ref = (${pkgs.jujutsu}/bin/jj log -r "heads(::@ & bookmarks())" -n 1 --no-graph -T "commit_id") 65 let remote_url = (${pkgs.jujutsu}/bin/jj git remote list | parse "{remote} {url}" | where remote == origin | get url.0 | if ($in | str contains '://') {$in} else $"https://($in | str replace ':' '/')" | url parse) 66 let url = $"https://($remote_url.host)($remote_url.path | str replace ".git" "")/blob/($ref)/($rel_path)#L($line)($line_end)" 67 $url | ${pkgs.wl-clipboard}/bin/wl-copy 68 ' 69 ''; 70 b = ":echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}"; 71 p = ":sh echo %{buffer_name} | ${pkgs.wl-clipboard}/bin/wl-copy"; 72 }; 73 goMenu = { 74 "8" = [ 75 "move_prev_word_start" 76 "move_next_word_end" 77 ]; 78 "c" = caseMenu; 79 }; 80 caseMenu = { 81 p = ":pipe ${lib.getExe pkgs.sttr} pascal"; 82 c = ":pipe ${lib.getExe pkgs.sttr} camel"; 83 k = ":pipe ${lib.getExe pkgs.sttr} kebab"; 84 K = ":pipe ${lib.getExe pkgs.sttr} kebab | ${lib.getExe pkgs.sttr} upper"; 85 s = ":pipe ${lib.getExe pkgs.sttr} snake"; 86 S = ":pipe ${lib.getExe pkgs.sttr} snake | ${lib.getExe pkgs.sttr} upper"; 87 t = ":pipe ${lib.getExe pkgs.sttr} title"; 88 }; 89 runMenu = { 90 f = [ 91 ":sh golangci-lint run --issues-exit-code=0 --fix %{buffer_name}" 92 ":reload" 93 ]; 94 }; 95 scrollFast = { 96 "C-j" = lib.replicate 5 "move_visual_line_down"; 97 "C-k" = lib.replicate 5 "move_visual_line_up"; 98 }; 99 in 100 { 101 normal = { 102 "+" = plusMenu; 103 "-" = runMenu; 104 "g" = goMenu; 105 } 106 // scrollFast; 107 select = { 108 "+" = plusMenu; 109 "-" = runMenu; 110 "." = goMenu; 111 } 112 // scrollFast; 113 }; 114 115 editor = { 116 scrolloff = 10; 117 text-width = 120; 118 rulers = [ 120 ]; 119 bufferline = "multiple"; 120 color-modes = true; 121 auto-format = true; 122 auto-save = true; 123 lsp = { 124 snippets = true; 125 display-color-swatches = true; 126 display-messages = true; 127 }; 128 soft-wrap = { 129 enable = true; 130 }; 131 statusline = { 132 left = [ 133 "mode" 134 "spacer" 135 "diagnostics" 136 "read-only-indicator" 137 "file-modification-indicator" 138 "spinner" 139 ]; 140 center = [ 141 "version-control" 142 "spacer" 143 "file-name" 144 ]; 145 right = [ 146 "file-encoding" 147 "file-type" 148 "selections" 149 "position" 150 ]; 151 }; 152 gutters = [ 153 "line-numbers" 154 "diagnostics" 155 "diff" 156 ]; 157 end-of-line-diagnostics = "hint"; 158 inline-diagnostics = { 159 cursor-line = "warning"; # show warnings and errors on the cursorline inline 160 }; 161 cursor-shape = { 162 insert = "bar"; 163 normal = "block"; 164 select = "underline"; 165 }; 166 whitespace.render.tab = "all"; 167 indent-guides = { 168 render = true; 169 character = ""; 170 skip-levels = 1; 171 }; 172 }; 173 }; 174 175 languages = { 176 language-server = { 177 biome = { 178 command = "biome"; 179 args = [ "lsp-proxy" ]; 180 }; 181 nu-lsp = { 182 command = "nu"; 183 args = [ 184 "--lsp" 185 "--no-config-file" 186 ]; 187 }; 188 typos = { 189 command = "typos-lsp"; 190 config = { 191 diagnosticSeverity = "Warning"; 192 }; 193 }; 194 yaml-language-server = { 195 config = { 196 enabled = true; 197 enabledForFilesGlob = "*.{yaml,yml}"; 198 diagnosticsLimit = 50; 199 showDiagnosticsDirectly = false; 200 config = { 201 schemas = { 202 kubernetes = "templates/**"; 203 }; 204 completion = true; 205 hover = true; 206 }; 207 }; 208 }; 209 golangci-lint-lsp = { 210 command = "golangci-lint-langserver"; 211 config = { 212 command = [ 213 "nu" 214 "-c" 215 '' 216 let args = [ 217 --output.json.path=stdout 218 --path-mode=abs 219 --issues-exit-code=1 220 --show-stats=false 221 ] 222 223 if ($env.GOLANGCI_LINT_CONFIG? | is-not-empty) { 224 golangci-lint run --config $env.GOLANGCI_LINT_CONFIG ...$args 225 } else { 226 golangci-lint run ...$args 227 } 228 '' 229 ]; 230 }; 231 }; 232 rubocop = { 233 command = "rubocop"; 234 args = [ "--lsp" ]; 235 }; 236 ruby-lsp = { 237 command = "ruby-lsp"; 238 config = { 239 diagnostics = true; 240 formatting = true; 241 config = { 242 initializationOptions = { 243 enabledFeatures = { 244 codeActions = true; 245 codeLens = true; 246 completion = true; 247 definition = true; 248 diagnostics = true; 249 documentHighlights = true; 250 documentLink = true; 251 documentSymbols = true; 252 foldingRanges = true; 253 formatting = true; 254 hover = true; 255 inlayHint = true; 256 onTypeFormatting = true; 257 selectionRanges = true; 258 semanticHighlighting = true; 259 signatureHelp = true; 260 typeHierarchy = true; 261 workspaceSymbol = true; 262 }; 263 featuresConfiguration = { 264 inlayHint = { 265 implicitHashValue = true; 266 implicitRescue = true; 267 }; 268 }; 269 }; 270 }; 271 }; 272 }; 273 thriftls = { 274 command = "thriftls"; 275 except-features = [ "format" ]; 276 }; 277 }; 278 279 language = 280 let 281 defaults = [ "typos" ]; 282 in 283 map 284 (lang: lang // { language-servers = if lang ? language-servers then lang.language-servers ++ defaults else defaults; }) 285 ( 286 [ 287 { 288 name = "nix"; 289 language-servers = [ 290 "nixd" 291 "nil" 292 ]; 293 formatter = { 294 command = "nixfmt"; 295 args = [ 296 "-s" 297 "-w" 298 "120" 299 ]; 300 }; 301 auto-format = true; 302 } 303 { 304 name = "go"; 305 language-servers = [ 306 "gopls" 307 "golangci-lint-lsp" 308 ]; 309 formatter = { 310 command = "goimports"; 311 }; 312 auto-format = true; 313 } 314 { 315 name = "ruby"; 316 language-servers = [ 317 "ruby-lsp" 318 "rubocop" 319 ]; 320 auto-format = true; 321 } 322 { 323 name = "html"; 324 language-servers = [ "vscode-html-language-server" ]; 325 formatter = { 326 command = "prettier"; 327 args = [ 328 "--stdin-filepath" 329 "file.html" 330 ]; 331 }; 332 auto-format = true; 333 } 334 { 335 name = "javascript"; 336 language-servers = [ 337 { 338 name = "typescript-language-server"; 339 except-features = [ "format" ]; 340 } 341 "biome" 342 ]; 343 auto-format = true; 344 } 345 { 346 name = "json"; 347 language-servers = [ 348 { 349 name = "vscode-json-language-server"; 350 except-features = [ "format" ]; 351 } 352 "biome" 353 ]; 354 formatter = { 355 command = "biome"; 356 args = [ 357 "format" 358 "--stdin-file-path" 359 "file.json" 360 ]; 361 }; 362 auto-format = true; 363 } 364 { 365 name = "graphql"; 366 formatter = { 367 command = "biome"; 368 args = [ 369 "format" 370 "--stdin-file-path" 371 "file.gql" 372 ]; 373 }; 374 auto-format = true; 375 } 376 { 377 name = "jsonc"; 378 language-servers = [ 379 { 380 name = "vscode-json-language-server"; 381 except-features = [ "format" ]; 382 } 383 "biome" 384 ]; 385 formatter = { 386 command = "biome"; 387 args = [ 388 "format" 389 "--stdin-file-path" 390 "file.jsonc" 391 ]; 392 }; 393 file-types = [ 394 "jsonc" 395 "hujson" 396 ]; 397 auto-format = true; 398 } 399 { 400 name = "jsx"; 401 language-servers = [ 402 { 403 name = "typescript-language-server"; 404 except-features = [ "format" ]; 405 } 406 "biome" 407 ]; 408 formatter = { 409 command = "biome"; 410 args = [ 411 "format" 412 "--stdin-file-path" 413 "file.jsx" 414 ]; 415 }; 416 auto-format = true; 417 } 418 { 419 name = "tsx"; 420 language-servers = [ 421 { 422 name = "typescript-language-server"; 423 except-features = [ "format" ]; 424 } 425 "biome" 426 ]; 427 formatter = { 428 command = "biome"; 429 args = [ 430 "format" 431 "--stdin-file-path" 432 "file.tsx" 433 ]; 434 }; 435 auto-format = true; 436 } 437 { 438 name = "typescript"; 439 language-servers = [ 440 { 441 name = "typescript-language-server"; 442 except-features = [ "format" ]; 443 } 444 "biome" 445 ]; 446 formatter = { 447 command = "biome"; 448 args = [ 449 "format" 450 "--stdin-file-path" 451 "file.ts" 452 ]; 453 }; 454 auto-format = true; 455 } 456 { 457 name = "yaml"; 458 language-servers = [ "yaml-language-server" ]; 459 formatter = { 460 command = "prettier"; 461 args = [ 462 "--stdin-filepath" 463 "file.yaml" 464 ]; 465 }; 466 auto-format = true; 467 } 468 { 469 name = "helm"; 470 language-servers = [ "helm_ls" ]; 471 } 472 { 473 name = "typst"; 474 language-servers = [ "tinymist" ]; 475 } 476 { 477 name = "markdown"; 478 language-servers = [ 479 "marksman" 480 # "vale-ls" 481 ]; 482 text-width = 100; 483 rulers = [ 100 ]; 484 soft-wrap = { 485 enable = true; 486 wrap-at-text-width = true; 487 }; 488 formatter = { 489 command = "prettier"; 490 args = [ 491 "--stdin-filepath" 492 "file.md" 493 ]; 494 }; 495 auto-format = true; 496 } 497 { 498 name = "sql"; 499 formatter = { 500 command = "sql-formatter"; 501 args = [ 502 "-c" 503 (builtins.toJSON { 504 keywordCase = "upper"; 505 functionCase = "upper"; 506 dataTypeCase = "upper"; 507 identifierCase = "lower"; 508 language = "postgresql"; 509 expressionWidth = 80; 510 tabWidth = 2; 511 }) 512 ]; 513 }; 514 auto-format = false; 515 } 516 { 517 name = "nu"; 518 language-servers = [ "nu-lsp" ]; 519 formatter = { 520 command = "${lib.getExe self'.packages.topiary-nu}"; 521 args = [ 522 "format" 523 "--language" 524 "nu" 525 ]; 526 }; 527 auto-format = true; 528 } 529 { 530 name = "thrift"; 531 language-servers = [ "thriftls" ]; 532 formatter = { 533 command = "thriftls"; 534 args = [ 535 "format" 536 "-indent" 537 "2space" 538 ]; 539 }; 540 auto-format = true; 541 } 542 ] 543 ++ map (lang: { name = lang; }) [ 544 "git-attributes" 545 "git-commit" 546 "git-config" 547 "git-ignore" 548 "git-rebase" 549 ] 550 ); 551 }; 552 }; 553}