feat(Nushell): improve prompt rendering

This commit is contained in:
2026-05-29 22:08:41 +08:00
parent 2241e10f47
commit fdacaab656
+127 -81
View File
@@ -1,14 +1,11 @@
def _pj_detect_os_key [] {
let host_name = (((sys host | get name?) | default ($nu.os-info.name? | default "")) | into string)
if ($host_name == "Darwin") {
let host_name = (((sys host | get name?) | default ($nu.os-info.name? | default "")) | into string | str downcase)
if ($host_name | str contains "darwin") {
return "Macos"
}
if ($host_name =~ "Windows") {
if ($host_name | str contains "windows") {
return "Windows"
}
if ($host_name != "Linux") {
return "Unknown"
}
let os_release = if ("/etc/os-release" | path exists) {
"/etc/os-release"
@@ -56,7 +53,11 @@ def _pj_detect_os_key [] {
_ => "Linux"
}
} else {
if ($host_name | str contains "linux") {
"Linux"
} else {
"Unknown"
}
}
}
@@ -116,6 +117,50 @@ def _pj_os_symbol [] {
_pj_os_symbol_from_key $key
}
def _pj_palette_default [] {
{
c_reset: (ansi reset)
c_os: (ansi '#6b6b6b')
c_user: (ansi '#4ca47b')
c_root: (ansi '#c2295b')
c_host: (ansi '#4ca47b')
c_ssh: (ansi '#d65d0e')
c_dir: (ansi '#9d8fbe')
c_c: (ansi '#306898')
c_cpp: (ansi '#306898')
c_rust: (ansi '#000000')
c_zig: (ansi '#306898')
c_python: (ansi '#4685b7')
c_git: (ansi '#4ca47b')
c_alert: (ansi '#c2295b')
c_time: (ansi '#a6356f')
c_duration: (ansi '#a6356f')
c_shell: (ansi cyan_bold)
c_indicator_ok: (ansi green_bold)
c_indicator_err: (ansi red_bold)
c_right_error: (ansi red_bold)
}
}
def _pj_palette [] {
($env.PJ_PROMPT_PALETTE? | default (_pj_palette_default))
}
def _pj_runtime_default [] {
let user = ($env.USER? | default ($env.USERNAME? | default "user"))
let host = (sys host | get hostname? | default "")
{
user: $user
is_root: ($user == "root")
host: $host
in_ssh: (($env.SSH_CONNECTION? | default "") != "" or ($env.SSH_TTY? | default "") != "")
}
}
def _pj_runtime [] {
(_pj_runtime_default)
}
def _pj_first_version [text: string] {
let parsed = ($text | parse -r '(?<ver>\d+(?:\.\d+)+)')
if (($parsed | length) > 0) {
@@ -144,6 +189,32 @@ def _pj_cmd_duration_ms [] {
}
}
def _pj_format_duration [ms: int] {
if ($ms < 1000) {
return $"($ms)ms"
}
let ms_part = ($ms mod 1000)
if ($ms < 60_000) {
let s = ($ms // 1000)
return $"($s)s ($ms_part)ms"
}
if ($ms < 3_600_000) {
let total_s = ($ms // 1000)
let s = ($total_s mod 60)
let m = ($total_s // 60)
return $"($m)m ($s)s ($ms_part)ms"
}
let total_s = ($ms // 1000)
let s = ($total_s mod 60)
let total_m = ($total_s // 60)
let m = ($total_m mod 60)
let h = ($total_m // 60)
$"($h)h ($m)m ($s)s ($ms_part)ms"
}
def _pj_truncate_pwd [pwd: string, length: int = 4] {
let home = ($env.HOME? | default "")
let normalized_pwd = (($pwd | into string) | str replace -a "\\" "/")
@@ -258,13 +329,6 @@ def _pj_git_info [] {
if ($m == null) { 0 } else { (($m | get b) | into int) }
}
mut parts = []
if ($changed > 0) { $parts = ($parts | append $"!($changed)") }
if ($untracked > 0) { $parts = ($parts | append $"?($untracked)") }
if ($stashed > 0) { $parts = ($parts | append $"\$($stashed)") }
if ($ahead > 0) { $parts = ($parts | append $"($ahead)") }
if ($behind > 0) { $parts = ($parts | append $"($behind)") }
{
branch: $branch_text
changed: $changed
@@ -275,28 +339,25 @@ def _pj_git_info [] {
}
}
def _pj_git_branch_module [] {
let c_git = (ansi '#4ca47b')
let c_alert = (ansi '#c2295b')
let reset = (ansi reset)
def _pj_git_branch_module [p: record] {
let git = (_pj_git_info)
let branch = ($git.branch | default "")
mut status_parts = []
if (($git.changed | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_alert)!($git.changed)($reset)")
$status_parts = ($status_parts | append $"($p.c_alert)!($git.changed)($p.c_reset)")
}
if (($git.untracked | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_alert)?($git.untracked)($reset)")
$status_parts = ($status_parts | append $"($p.c_alert)?($git.untracked)($p.c_reset)")
}
if (($git.stashed | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_alert)\$($git.stashed)($reset)")
$status_parts = ($status_parts | append $"($p.c_alert)\$($git.stashed)($p.c_reset)")
}
if (($git.ahead | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_git)($git.ahead)($reset)")
$status_parts = ($status_parts | append $"($p.c_git)($git.ahead)($p.c_reset)")
}
if (($git.behind | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_git)($git.behind)($reset)")
$status_parts = ($status_parts | append $"($p.c_git)($git.behind)($p.c_reset)")
}
let git_status = if (($status_parts | length) > 0) {
@@ -308,7 +369,7 @@ def _pj_git_branch_module [] {
if ($branch == "") {
""
} else {
$"($c_git)on  ($branch)($git_status) ($reset)"
$"($p.c_git)on  ($branch)($git_status) ($p.c_reset)"
}
}
@@ -428,122 +489,107 @@ def _pj_lang_segments [] {
$out
}
def _pj_shell_module [] {
let reset = (ansi reset)
$"(ansi cyan_bold) nu ($reset)"
def _pj_shell_module [p: record] {
$"($p.c_shell) nu ($p.c_reset)"
}
def _pj_time_module [] {
let c_time = (ansi '#a6356f')
let reset = (ansi reset)
def _pj_time_module [p: record] {
let now = (date now | format date "%R")
$"($c_time)($now) ($reset)"
$"($p.c_time)($now) ($p.c_reset)"
}
def _pj_duration_module [] {
let c_duration = (ansi '#a6356f')
let reset = (ansi reset)
def _pj_duration_module [p: record] {
let ms = (_pj_cmd_duration_ms)
let duration_text = if ($ms >= 1000) {
let s = (($ms / 1000) | into int)
$"($s)s"
} else {
$"($ms)ms"
}
$"($c_duration) 󱫑 ($duration_text) ($reset)"
let duration_text = (_pj_format_duration $ms)
$"($p.c_duration) 󱫑 ($duration_text) ($p.c_reset)"
}
def _pj_left_prompt [] {
let c_os = (ansi '#6b6b6b')
let c_user = (ansi '#4ca47b')
let c_root = (ansi '#c2295b')
let c_host = (ansi '#4ca47b')
let c_ssh = (ansi '#d65d0e')
let c_dir = (ansi '#9d8fbe')
let c_c = (ansi '#306898')
let c_cpp = (ansi '#306898')
let c_rust = (ansi '#000000')
let c_zig = (ansi '#306898')
let c_python = (ansi '#4685b7')
let reset = (ansi reset)
let p = (_pj_palette)
let runtime = (_pj_runtime)
let user = ($env.USER? | default ($env.USERNAME? | default "user"))
let is_root = ($user == "root")
let user_color = if $is_root { $c_root } else { $c_user }
let user_color = if ($runtime.is_root | default false) { $p.c_root } else { $p.c_user }
let host = (sys host | get hostname? | default "")
let in_ssh = (($env.SSH_CONNECTION? | default "") != "" or ($env.SSH_TTY? | default "") != "")
let host_part = if $in_ssh {
$"($c_host)@($host)($reset)($c_ssh)  󰬚󰬚󰬏 ($reset)"
let host_part = if ($runtime.in_ssh | default false) {
$"($p.c_host)@($runtime.host)($p.c_reset)($p.c_ssh)  󰬚󰬚󰬏 ($p.c_reset)"
} else {
""
}
let shell_part = (_pj_shell_module)
let shell_part = (_pj_shell_module $p)
let dir = (_pj_truncate_pwd $env.PWD 4)
let git_part = (_pj_git_branch_module)
let git_part = (_pj_git_branch_module $p)
let langs = (_pj_lang_segments)
let lang_parts = ($langs | each {|seg|
if ($seg | str starts-with "") {
$"($c_python)via ($seg) ($reset)"
$"($p.c_python)via ($seg) ($p.c_reset)"
} else if ($seg | str starts-with "󱘗") {
$"($c_rust)via ($seg) ($reset)"
$"($p.c_rust)via ($seg) ($p.c_reset)"
} else if ($seg | str starts-with "") {
$"($c_cpp)via ($seg) ($reset)"
$"($p.c_cpp)via ($seg) ($p.c_reset)"
} else if ($seg | str starts-with "") {
$"($c_c)via ($seg) ($reset)"
$"($p.c_c)via ($seg) ($p.c_reset)"
} else if ($seg | str starts-with "") {
$"($c_zig)via ($seg) ($reset)"
$"($p.c_zig)via ($seg) ($p.c_reset)"
} else {
$seg
}
})
let time_part = (_pj_time_module)
let duration_part = (_pj_duration_module)
let time_part = (_pj_time_module $p)
let duration_part = (_pj_duration_module $p)
mut out = ""
$out = $"($out)($c_os)(_pj_os_symbol)($reset)"
$out = $"($out)($user_color)($user)($reset)"
$out = $"($out)($p.c_os)(_pj_os_symbol)($p.c_reset)"
$out = $"($out)($user_color)($runtime.user)($p.c_reset)"
if ($host_part != "") { $out = $"($out)($host_part)" }
$out = $"($out)($shell_part)"
$out = $"($out)($c_dir) ($dir) ($reset)"
$out = $"($out)($p.c_dir) ($dir) ($p.c_reset)"
if ($git_part != "") { $out = $"($out)($git_part)" }
for m in $lang_parts {
$out = $"($out)($m)"
}
$out = $"($out)($time_part)($duration_part)"
$out = $"\n($out)($time_part)($duration_part)\n"
$out
}
def _pj_prompt_indicator [] {
let p = (_pj_palette)
if (($env.LAST_EXIT_CODE? | default 0) == 0) {
$"(ansi green_bold)(ansi reset) "
$"($p.c_indicator_ok)($p.c_reset) "
} else {
$"(ansi red_bold)(ansi reset) "
$"($p.c_indicator_err)($p.c_reset) "
}
}
def _pj_prompt_content [] {
$"(_pj_left_prompt)\n(_pj_prompt_indicator)"
def _pj_right_prompt [] {
let p = (_pj_palette)
if (($env.LAST_EXIT_CODE? | default 0) != 0) {
$"($p.c_right_error)Exit code: ($env.LAST_EXIT_CODE)($p.c_reset)"
} else {
$""
}
}
export-env {
load-env {
PJ_PROMPT_PALETTE: (_pj_palette_default)
PJ_OS_KEY: (_pj_detect_os_key)
PROMPT_MULTILINE_INDICATOR: ""
PROMPT_INDICATOR: ""
PROMPT_MULTILINE_INDICATOR: ":"
PROMPT_INDICATOR: {||
_pj_prompt_indicator
}
PROMPT_INDICATOR_VI_INSERT: ""
PROMPT_INDICATOR_VI_NORMAL: ""
PROMPT_COMMAND: {||
(_pj_prompt_content)
_pj_left_prompt
}
PROMPT_COMMAND_RIGHT: {||
""
_pj_right_prompt
}
config: ($env.config? | default {} | merge {
render_right_prompt_on_last_line: false
render_right_prompt_on_last_line: true
})
}
}