diff --git a/flake.nix b/flake.nix index 945964b..a7166be 100644 --- a/flake.nix +++ b/flake.nix @@ -19,22 +19,28 @@ fish helix kakoune + nushell ; } ) pkgsFor; apps = eachSystem (system: let - inherit (inputs.self.packages.${system}) fish helix; + inherit (inputs.self.packages.${system}) fish helix nushell; in { - default = { - type = "app"; - program = "${fish}/bin/fish"; - }; + default = inputs.self.apps.${system}.nushell; helix = { type = "app"; program = "${helix}/bin/hx"; }; + nushell = { + type = "app"; + program = "${nushell}/bin/nu"; + }; + fish = { + type = "app"; + program = "${fish}/bin/fish"; + }; }); templates = import ./templates; diff --git a/hosts/hermit/programs.nix b/hosts/hermit/programs.nix index 424f381..bc0b7ea 100644 --- a/hosts/hermit/programs.nix +++ b/hosts/hermit/programs.nix @@ -70,7 +70,6 @@ in { obsidian microfetch nmap - nushell pamixer pwvucontrol pdfarranger diff --git a/modules/other/users.mod.nix b/modules/other/users.mod.nix index 344a3e2..569176f 100644 --- a/modules/other/users.mod.nix +++ b/modules/other/users.mod.nix @@ -49,7 +49,7 @@ in { }; package = mkOption { type = package; - default = pkgs.nushell; + default = self.packages.${pkgs.stdenv.system}.nushell; }; }; }; @@ -69,11 +69,8 @@ in { "nix" "docker" ]; - # shell = self.packages.${pkgs.stdenv.system}.fish; - shell = pkgs.nushell; - # hashedPasswordFile = "/etc/passwords/cr"; + shell = self.packages.${pkgs.stdenv.system}.nushell; }; - # root.hashedPasswordFile = "/persist/passwords/root"; }; }; }; diff --git a/modules/wms/niri/config.kdl b/modules/wms/niri/config.kdl index 3a40986..d3eb85e 100644 --- a/modules/wms/niri/config.kdl +++ b/modules/wms/niri/config.kdl @@ -69,7 +69,7 @@ layout { // xwayland stuff // spawn-at-startup "xwayland-satellite" spawn-at-startup "kwalletd6" -spawn-at-startup "bash" "-c" "quickshell --path ~/repos/projects/nichts/main/modules/style/quickshell/shell" +spawn-at-startup "nu" "-c" "quickshell --path ~/repos/projects/nichts/main/modules/style/quickshell/shell" environment { DISPLAY ":0" } @@ -156,7 +156,7 @@ binds { spawn "brave" } Mod+D { - spawn "bash" "-c" "quickshell --path ~/repos/projects/nichts/main/modules/style/quickshell/shell msg launcher open" + spawn "nu" "-c" "quickshell --path ~/repos/projects/nichts/main/modules/style/quickshell/shell msg launcher open" } Mod+Alt+L { spawn "swaylock" diff --git a/packages/default.nix b/packages/default.nix index 375b3e7..5b24cff 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -6,6 +6,7 @@ helix = pkgs.callPackage ./helix {}; kakoune = pkgs.callPackage ./kakoune.nix {}; fish = pkgs.callPackage ./fish {inherit lib;}; + nushell = pkgs.callPackage ./nushell {}; in { - inherit kakoune fish helix; + inherit kakoune fish helix nushell; } diff --git a/packages/nushell/config.nu b/packages/nushell/config.nu new file mode 100644 index 0000000..cfc7fb2 --- /dev/null +++ b/packages/nushell/config.nu @@ -0,0 +1,328 @@ +#! /usr/bin/env nu + +$env.config = { + bracketed_paste: true + buffer_editor: "hx" + datetime_format: {} + edit_mode: vi + error_style: fancy + float_precision: 2 + footer_mode: 25 + render_right_prompt_on_last_line: false + show_banner: false + use_ansi_coloring: true + use_kitty_protocol: true + + shell_integration: { + osc2: false + osc7: true + osc8: true + osc9_9: false + osc133: true + osc633: true + reset_application_mode: true + } +} + +$env.config.ls = { + clickable_links: true + use_ls_colors: true +} + +$env.config.rm.always_trash = true + +$env.config.table = { + header_on_separator: true + footer_inheritance: true + index_mode: always + mode: compact + missing_value_symbol: kek + padding: {left: 1 right: 1} + show_empty: false + trim: { + methodology: wrapping + truncating_suffix: "..." + wrapping_try_keep_words: true + } +} + +$env.config.explore = { + command_bar_text: {fg: "#C4C9C6"} + highlight: {fg: black bg: yellow} + status: { + error: {fg: white bg: red} + warn: {} + info: {} + } + status_bar_background: {fg: "#1D1F21" bg: "#C4C9C6"} + table: { + split_line: {fg: "#404040"} + selected_cell: {bg: light_blue} + selected_row: {} + selected_column: {} + } +} + +$env.config.history = { + file_format: sqlite + isolation: false + max_size: 100_000 + sync_on_enter: true +} + +$env.config.cursor_shape = { + vi_insert: line + vi_normal: block +} + +$env.config.hooks = { + command_not_found: {|| } + + pre_execution: [ + { + let prompt = commandline | str trim + + if ($prompt | is-empty) { + return + } + + print $"(ansi title)($prompt) — nu(char bel)" + } + ] + + env_change: { + PWD: [ + {|| + if not ($env.PWD | path join .envrc | path exists) { + return + } + if (which direnv | is-empty) { + return + } + + direnv export json | from json | default {} | load-env + $env.PATH = $env.PATH | split row (char env_sep) + } + ] + } +} + +$env.config.menus = [ + { + marker: $"(ansi yellow)╋ " + name: help_menu + only_buffer_difference: true + style: { + description_text: yellow + selected_text: red_reverse + text: yellow + } + type: { + col_padding: 2 + col_width: 20 + columns: 4 + description_rows: 10 + layout: description + selection_rows: 4 + } + } +] + +$env.config.keybindings = [ + { + name: copy_commandline + modifier: alt + keycode: char_c + mode: [vi_normal vi_insert] + event: { + send: executehostcommand + cmd: 'commandline | nu-highlight | $"```ansi\n($in)\n```" | wl-copy $in' + } + } + { + name: escape + modifier: none + keycode: escape + mode: [vi_normal vi_insert] + event: {send: esc} + } + { + name: cancel_command + modifier: control + keycode: char_c + mode: [vi_normal vi_insert] + event: {send: ctrlc} + } + { + name: quit_shell + modifier: control + keycode: char_d + mode: [vi_normal vi_insert] + event: {send: ctrld} + } + { + name: clear_screen + modifier: control + keycode: char_l + mode: [vi_normal vi_insert] + event: {send: clearscreen} + } + { + name: open_command_editor + modifier: control + keycode: char_o + mode: [vi_normal vi_insert] + event: {send: openeditor} + } + { + name: abbr + modifier: control + keycode: space + mode: [vi_normal vi_insert] + event: [ + {send: menu name: abbr_menu} + {edit: insertchar value: " "} + ] + } + { + name: move_down + modifier: none + keycode: down + mode: [vi_normal vi_insert] + event: { + until: [ + {send: menudown} + {send: down} + ] + } + } + { + name: move_left + modifier: none + keycode: left + mode: [vi_normal vi_insert] + event: { + until: [ + {send: menuleft} + {send: left} + ] + } + } + { + name: move_right_or_take_history_hint + modifier: none + keycode: right + mode: [vi_normal vi_insert] + event: { + until: [ + {send: historyhintcomplete} + {send: menuright} + {send: right} + ] + } + } + { + name: move_one_word_left + modifier: control + keycode: left + mode: [vi_normal vi_insert] + event: {edit: movewordleft} + } + { + name: move_one_word_right_or_take_history_hint + modifier: control + keycode: right + mode: [vi_normal vi_insert] + event: { + until: [ + {send: historyhintwordcomplete} + {edit: movewordright} + ] + } + } + { + name: move_to_line_start + modifier: control + keycode: char_a + mode: [vi_normal vi_insert] + event: {edit: movetolinestart} + } + { + name: move_to_line_end_or_take_history_hint + modifier: control + keycode: char_e + mode: [vi_normal vi_insert] + event: { + until: [ + {send: historyhintcomplete} + {edit: movetolineend} + ] + } + } + { + name: delete_one_character_backward + modifier: none + keycode: backspace + mode: vi_insert + event: {edit: backspace} + } + { + name: delete_one_word_backward + modifier: control + keycode: backspace + mode: vi_insert + event: {edit: backspaceword} + } + { + name: newline_or_run_command + modifier: none + keycode: enter + mode: vi_insert + event: {send: enter} + } + { + name: take_history_hint + modifier: control + keycode: char_f + mode: [vi_normal vi_insert] + event: { + until: [ + {send: historyhintcomplete} + ] + } + } +] + +let env_vars_file = '/tmp/nushell-env-vars' +if not ($env_vars_file | path exists) { + open /etc/profile + | lines + | select 11 + | str trim + | split column ' ' del path + | get path.0 + | open $in + | str trim + | lines + | parse 'export {name}="{value}"' + | transpose --header-row --as-record + | tee { load-env $in } + | to nuon + | save --force $env_vars_file +} else { + open $env_vars_file + | from nuon + | load-env $in +} + +# fix sudo by prepending /run/wrappers/bin to the PATH. +$env.PATH = ($env.PATH | split row (char esep) | prepend '/run/wrappers/bin') + +$env.CARAPACE_BRIDGES = 'inshellisense,fish,carapace,clap,bash' +$env.CARAPACE_MATCH = 1 + +# Set environment variables according to the path of the clone +$env.TOPIARY_CONFIG_FILE = ($env.HOME | path join .config | path join topiary languages.ncl) +$env.TOPIARY_LANGUAGE_DIR = ($env.HOME | path join .config | path join topiary languages) +# The prompt indicators are environmental variables that represent +# the state of the prompt. diff --git a/packages/nushell/default.nix b/packages/nushell/default.nix new file mode 100644 index 0000000..b8e29b7 --- /dev/null +++ b/packages/nushell/default.nix @@ -0,0 +1,46 @@ +{pkgs, ...}: let + inherit (pkgs) lib; + inherit (lib.meta) getExe; + + nu-config = + pkgs.writeText "nu-init" + # nu + '' + #!/usr/bin/env nu + source ${./config.nu} + source ${./prompt.nu} + + let autoload_dir = $nu.user-autoload-dirs.0 + mkdir $autoload_dir + + let zoxide_path = $autoload_dir | path join zoxide.nu + if not ($zoxide_path | path exists) { + ${getExe pkgs.zoxide} init nushell --cmd cd | save -f $zoxide_path + } + # Atuin is too slow, sadly. + # let atuin_path = $autoload_dir | path join atuin.nu + # if not ($atuin_path | path exists) { + # ${getExe pkgs.atuin} init nu | save -f $atuin_path + # } + let carapace_path = $autoload_dir | path join carapace.nu + if not ($carapace_path | path exists) { + ${getExe pkgs.carapace} _carapace nushell | save -f $carapace_path + } + ''; + packages = import ./packages.nix pkgs; +in + (pkgs.symlinkJoin { + name = "nushell"; + paths = [pkgs.nushell] ++ packages; + nativeBuildInputs = [pkgs.makeWrapper]; + postBuild = '' + wrapProgram $out/bin/nu --add-flags "\ + --config ${nu-config}" + ''; + }) + .overrideAttrs (_: { + passthru = { + shellPath = "/bin/nu"; + }; + meta.mainProgram = "nu"; + }) diff --git a/packages/nushell/packages.nix b/packages/nushell/packages.nix new file mode 100644 index 0000000..3732db4 --- /dev/null +++ b/packages/nushell/packages.nix @@ -0,0 +1,66 @@ +pkgs: +builtins.attrValues { + inherit + (pkgs) + # better cd + zoxide + # pipe viewer + pv + # hex editor + bvi + #better ls + eza + atuin + # better cat + bat + # clipboard + # yazi + serpl + diff-so-fancy + tig + direnv + sesh + mprocs + curlie + entr + procs + sd + # mult + glow + # dua-cli + dust + kondo + # better grep + ripgrep + # IP stuff + dig + # simply the best fetch tool out there + microfetch + fzf + element + difftastic + hexyl + yazi + gnumake + asciinema + inetutils + tokei + starship + wget + cpufetch + watchman + tealdeer + hyperfine + imagemagick + ffmpeg-full + timg + nmap + fd + jq + rsync + figlet + unzip + zip + ouch + ; +} diff --git a/packages/nushell/prompt.nu b/packages/nushell/prompt.nu new file mode 100644 index 0000000..570ce4a --- /dev/null +++ b/packages/nushell/prompt.nu @@ -0,0 +1,73 @@ +use std null_device + +export-env { + load-env { + PROMPT_COMMAND: {|| + let exit_code = $env.LAST_EXIT_CODE + mut path_segment = $env.PWD | path basename + + let exit_code_segment = if ($exit_code == 0) { + "" + } else { + $"(ansi yellow)━┫(ansi red)($exit_code)(ansi yellow)┣━" + } + + [$"(ansi yellow)┏" $exit_code_segment "━ " $path_segment "\n"] | str join + } + TRANSIENT_PROMPT_COMMAND: {|| + let path_segment = $env.PWD | path basename + + let exit_code_segment = if ($env.LAST_EXIT_CODE == 0) { + "" + } else { + $"(ansi yellow)━┫(ansi red)($env.LAST_EXIT_CODE)(ansi yellow)┣━" + } + + [$"(ansi yellow)━" $exit_code_segment "━ " $path_segment] | str join + } + PROMPT_INDICATOR_VI_INSERT: $"(ansi yellow)┃ " + PROMPT_INDICATOR_VI_NORMAL: $"(ansi yellow)┋ " + PROMPT_MULTILINE_INDICATOR: $"(ansi yellow)┃ " + TRANSIENT_PROMPT_INDICATOR_VI_INSERT: " " + TRANSIENT_PROMPT_INDICATOR_VI_NORMAL: " " + TRANSIENT_PROMPT_MULTILINE_INDICATOR: $"(ansi yellow)┃ " + + config: ( + $env.config? | default {} | merge { + render_right_prompt_on_last_line: true + } + ) + + PROMPT_COMMAND_RIGHT: {|| + let jj_status = try { + jj --quiet --color always --ignore-working-copy log --no-graph --revisions @ --template ' + separate( + " ", + if(empty, label("empty", "(empty)")), + coalesce( + surround( + "\"", + "\"", + if( + description.first_line().substr(0, 24).starts_with(description.first_line()), + description.first_line().substr(0, 24), + description.first_line().substr(0, 23) ++ "…" + ) + ), + label(if(empty, "empty"), description_placeholder) + ), + bookmarks.join(", "), + change_id.shortest(), + commit_id.shortest(), + if(conflict, label("conflict", "(conflict)")), + if(divergent, label("divergent prefix", "(divergent)")), + if(hidden, label("hidden prefix", "(hidden)")), + ) + ' err> $null_device + } catch { + "" + } + $jj_status + } + } +}