nix/common/terminal.nix
2026-04-08 11:51:33 +10:00

322 lines
9.2 KiB
Nix

{
lib,
pkgs,
inputs,
# getFlakePkg',
config,
mainUser,
...
}:
let
inherit (pkgs) nushell;
cfg = config.programs.inshellah;
nushellWrapped = pkgs.symlinkJoin {
name = "nushell";
paths = [ nushell ];
nativeBuildInputs = [ pkgs.makeWrapper ];
postBuild = ''
wrapProgram $out/bin/nu \
--add-flags "--config ${nuConfig}"
'';
passthru = nushell.passthru or { } // {
shellPath = "/bin/nu";
};
};
theme =
let
pal = config.rice.palette.hex;
ui = config.rice.roles pal;
in
''
let theme = {
separator: "${pal.bright.yellow}"
leading_trailing_space_bg: "${ui.highlight}"
header: "${pal.normal.yellow}"
empty: "${ui.muted}"
bool: "${pal.bright.magenta}"
int: "${pal.bright.magenta}"
filesize: "${pal.bright.magenta}"
duration: "${pal.bright.magenta}"
date: "${pal.bright.cyan}"
range: "${pal.bright.magenta}"
float: "${pal.bright.magenta}"
string: "${pal.normal.green}"
nothing: "${ui.muted}"
binary: "${pal.bright.magenta}"
cell-path: "${pal.bright.blue}"
row_index: "${pal.bright.blue}"
record: "${pal.bright.cyan}"
list: "${pal.bright.cyan}"
block: "${pal.bright.cyan}"
hints: "${ui.hint}"
search_result: "${ui.highlight}"
shape_and: "${pal.normal.red}"
shape_binary: "${pal.bright.magenta}"
shape_block: "${pal.bright.cyan}"
shape_bool: "${pal.bright.magenta}"
shape_custom: "${ui.accent}"
shape_datetime: "${pal.bright.cyan}"
shape_external: "${pal.normal.green}"
shape_externalarg: "${pal.normal.green}"
shape_filepath: "${pal.normal.green}"
shape_flag: "${ui.accent}"
shape_float: "${pal.bright.magenta}"
shape_globpattern: "${pal.normal.green}"
shape_int: "${pal.bright.magenta}"
shape_internalcall: "${pal.normal.green}"
shape_list: "${pal.bright.cyan}"
shape_literal: "${pal.bright.magenta}"
shape_operator: "${pal.bright.magenta}"
shape_option: "${ui.accent}"
shape_range: "${pal.bright.magenta}"
shape_record: "${pal.bright.cyan}"
shape_string: "${pal.normal.green}"
shape_variable: "${pal.bright.blue}"
};
$env.config = ($env.config | upsert color_config $theme)
'';
prompt = ''
do --env {
def prompt-header [
--left-char: string
]: nothing -> string {
let code = $env.LAST_EXIT_CODE
let jj_workspace_root = try {
jj workspace root err>| ignore
} catch {
""
}
let hostname = if ($env.SSH_CONNECTION? | is-not-empty) {
let hostname = try {
hostname
} catch {
"remote"
}
$"(ansi light_green_bold)@($hostname)(ansi reset) "
} else {
""
}
# https://github.com/nushell/nushell/issues/16205
#
# Case insensitive filesystems strike again!
let pwd = pwd | path expand
let body = if ($jj_workspace_root | is-not-empty) {
let subpath = $pwd | path relative-to $jj_workspace_root
let subpath = if ($subpath | is-not-empty) {
$"(ansi magenta_bold) (ansi reset)(ansi blue)($subpath)"
}
$"($hostname)(ansi light_yellow_bold)($jj_workspace_root | path basename)($subpath)(ansi reset)"
} else {
let pwd = if ($pwd | str starts-with $env.HOME) {
"~" | path join ($pwd | path relative-to $env.HOME)
} else {
$pwd
}
$"($hostname)(ansi cyan)($pwd)(ansi reset)"
}
let command_duration = ($env.CMD_DURATION_MS | into int) * 1ms
let command_duration = if $command_duration <= 2sec {
""
} else {
$"(ansi light_magenta_bold)($command_duration)(ansi light_yellow_bold)"
}
let exit_code = if $code == 0 {
""
} else {
$"(ansi light_red_bold)($code)(ansi light_yellow_bold)"
}
let middle = if $command_duration == "" and $exit_code == "" {
""
} else {
""
}
$"(ansi light_yellow_bold)($left_char)($exit_code)($middle)($command_duration)(ansi reset) ($body)(char newline)"
}
$env.PROMPT_INDICATOR = $"(ansi light_yellow_bold)(ansi reset) "
$env.PROMPT_INDICATOR_VI_NORMAL = $env.PROMPT_INDICATOR
$env.PROMPT_INDICATOR_VI_INSERT = $env.PROMPT_INDICATOR
$env.PROMPT_MULTILINE_INDICATOR = $env.PROMPT_INDICATOR
$env.PROMPT_COMMAND = {||
prompt-header --left-char ""
}
$env.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>| ignore
} catch {
""
}
$jj_status
}
}
'';
aliases = {
"l" = "ls";
"la" = "ls -a";
"gco" = "git checkout";
"gcb" = "git checkout -b";
"gp" = "git push";
"gpf" = "git push --force";
"gl" = "git pull";
"ga" = "git add";
"gcam" = "git commit -am";
"gcl" = "git clone";
"gcd" = "git clone --depth 1";
"lg" = "lazygit";
":q" = "exit";
"fg" = "job unfreeze";
"jobs" = "job list";
};
nuScriptsPath = "${pkgs.nu_scripts}/share/nu_scripts";
nuConfig = pkgs.writeText "config.nu" ''
use std/config *
${lib.mapAttrsToList (n: v: "alias ${n} = ${v}") aliases |> lib.concatStringsSep "\n"}
$env.NU_LIB_DIRS = ( $env.NU_LIB_DIRS | append "${nuScriptsPath}")
use ${nuScriptsPath}/modules/capture-foreign-env
source ${nuScriptsPath}/modules/formats/from-env.nu
let nixos_env = ('source /etc/set-environment' | capture-foreign-env --shell bash)
if ($nixos_env | describe | str starts-with "record") { $nixos_env | load-env }
source ${(pkgs.runCommand "zoxide.nu" { } ''${pkgs.zoxide}/bin/zoxide init nushell >> "$out"'')}
$env.config.buffer_editor = "${lib.getExe config.apps.editor}"
# aliases
#
def fresh [] {
clear
${./rice/header.sh}
echo
}
def gap [] {
git commit -a --amend --no-edit
git push --force
}
# direnv
$env.config = ($env.config? | default {})
$env.config.hooks = ($env.config.hooks? | default {})
$env.config.hooks.pre_prompt = (
$env.config.hooks.pre_prompt?
| default []
| append {||
${pkgs.direnv}/bin/direnv export json
| from json --strict
| default {}
| items {|key, value|
let value = do (
{
"PATH": {
from_string: {|s| $s | split row (char esep) | path expand --no-symlink }
to_string: {|v| $v | path expand --no-symlink | str join (char esep) }
}
}
| merge ($env.ENV_CONVERSIONS? | default {})
| get ([[value, optional, insensitive]; [$key, true, true] [from_string, true, false]] | into cell-path)
| if ($in | is-empty) { {|x| $x} } else { $in }
) $value
return [ $key $value ]
}
| into record
| load-env
}
)
# $cmd doesn't carry its args ?
# $env.config.hooks.command_not_found = { |cmd| , $cmd; echo }
$env.config.table.mode = "none";
$env.config.edit_mode = "vi";
$env.config.completions.algorithm = "fuzzy";
${prompt}
${cfg.snippet}
${theme}
$env.config.show_banner = false
fresh
'';
in
{
imports = [ inputs.inshellah.nixosModules.default ];
programs.inshellah = {
enable = true;
helpOnlyCommands = [ "nh" ];
};
programs.command-not-found.enable = false;
programs.zoxide.enable = true;
environment.shellAliases = {
};
environment.systemPackages = [
nushellWrapped
];
environment.shells = [
nushellWrapped
];
users.defaultUserShell = nushellWrapped;
console.font = "Lat2-Terminus16";
environment.variables = {
EDITOR = "hx";
};
}