Files
TerminalPolyjuice/nushell/modules/pj_prompt.nu
T

550 lines
16 KiB
Nu
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
def _pj_detect_os_key [] {
let host_name = (((sys host | get name?) | default ($nu.os-info.name? | default "")) | into string)
if ($host_name == "Darwin") {
return "Macos"
}
if ($host_name =~ "Windows") {
return "Windows"
}
if ($host_name != "Linux") {
return "Unknown"
}
let os_release = if ("/etc/os-release" | path exists) {
"/etc/os-release"
} else if ("/usr/lib/os-release" | path exists) {
"/usr/lib/os-release"
} else {
""
}
if ($os_release != "") {
let id_line = (open $os_release | lines | where {|l| $l | str starts-with "ID=" } | get 0?)
let id = if ($id_line == null) { "" } else { (($id_line | str replace "ID=" "") | str trim -c '"') }
match ($id | str downcase) {
"alpine" => "Alpine"
"alma" => "AlmaLinux"
"almalinux" => "AlmaLinux"
"amzn" => "Amazon"
"arch" => "Arch"
"artix" => "Artix"
"centos" => "CentOS"
"debian" => "Debian"
"endeavouros" => "EndeavourOS"
"fedora" => "Fedora"
"garuda" => "Garuda"
"gentoo" => "Gentoo"
"kali" => "Kali"
"linuxmint" => "Mint"
"manjaro" => "Manjaro"
"mariner" => "Mariner"
"nixos" => "NixOS"
"nobara" => "Nobara"
"opensuse" => "openSUSE"
"opensuse-leap" => "openSUSE"
"opensuse-tumbleweed" => "openSUSE"
"ol" => "OracleLinux"
"pop" => "Pop"
"raspbian" => "Raspbian"
"rhel" => "RedHatEnterprise"
"rocky" => "RockyLinux"
"solus" => "Solus"
"sles" => "SUSE"
"opensuse-slowroll" => "openSUSE"
"ubuntu" => "Ubuntu"
"void" => "Void"
_ => "Linux"
}
} else {
"Linux"
}
}
def _pj_os_symbol_from_key [key: string] {
match $key {
"Alpaquita" => " "
"Alpine" => " "
"AlmaLinux" => " "
"Amazon" => " "
"Android" => " "
"Arch" => " "
"Artix" => " "
"CachyOS" => " "
"CentOS" => " "
"Debian" => " "
"DragonFly" => " "
"Emscripten" => " "
"EndeavourOS" => " "
"Fedora" => " "
"FreeBSD" => " "
"Garuda" => "󰛓 "
"Gentoo" => " "
"HardenedBSD" => "󰞌 "
"Illumos" => "󰈸 "
"Kali" => " "
"Linux" => " "
"Mabox" => " "
"Macos" => " "
"Manjaro" => " "
"Mariner" => " "
"MidnightBSD" => " "
"Mint" => " "
"NetBSD" => " "
"NixOS" => " "
"Nobara" => " "
"OpenBSD" => "󰈺 "
"openSUSE" => " "
"OracleLinux" => "󰌷 "
"Pop" => " "
"Raspbian" => " "
"Redhat" => " "
"RedHatEnterprise" => " "
"RockyLinux" => " "
"Redox" => "󰀘 "
"Solus" => "󰠳 "
"SUSE" => " "
"Ubuntu" => " "
"Unknown" => " "
"Void" => " "
"Windows" => "󰍲 "
_ => " "
}
}
def _pj_os_symbol [] {
let key = ($env.PJ_OS_KEY? | default (_pj_detect_os_key))
_pj_os_symbol_from_key $key
}
def _pj_first_version [text: string] {
let parsed = ($text | parse -r '(?<ver>\d+(?:\.\d+)+)')
if (($parsed | length) > 0) {
($parsed | get ver.0)
} else {
""
}
}
def _pj_cmd_duration_ms [] {
let raw = ($env.CMD_DURATION_MS? | default 0)
let kind = ($raw | describe)
if ($kind == "int") {
return $raw
}
if ($kind == "duration") {
return (($raw | into int) / 1_000_000)
}
let s = ($raw | into string | str trim)
let parsed = ($s | parse -r '^(?<n>\d+)')
if (($parsed | length) > 0) {
(($parsed | get n.0) | into int)
} else {
0
}
}
def _pj_truncate_pwd [pwd: string, length: int = 4] {
let home = ($env.HOME? | default "")
let normalized_pwd = (($pwd | into string) | str replace -a "\\" "/")
let normalized_home = (($home | into string) | str replace -a "\\" "/")
let shown = if ($normalized_home != "" and ($normalized_pwd | str starts-with $normalized_home)) {
let rest = ($normalized_pwd | str substring ($normalized_home | str length)..)
if ($rest == "") { "~" } else { $"~($rest)" }
} else {
$normalized_pwd
}
if ($shown == "~") {
return "~"
}
let parts = if ($shown | str starts-with "~/") {
($shown | str substring 2.. | split row "/" | where {|it| $it != "" })
} else if ($shown | str starts-with "/") {
($shown | str substring 1.. | split row "/" | where {|it| $it != "" })
} else if ($shown =~ '^[A-Za-z]:/') {
($shown | str substring 3.. | split row "/" | where {|it| $it != "" })
} else {
($shown | split row "/" | where {|it| $it != "" })
}
let prefix = if ($shown | str starts-with "~/") {
"~/"
} else if ($shown | str starts-with "/") {
"/"
} else if ($shown =~ '^[A-Za-z]:/') {
let drive = ($shown | str substring 0..1)
$"($drive)/"
} else {
""
}
if (($parts | length) <= $length) {
if ($prefix == "") { ($parts | str join "/") } else { $"($prefix)($parts | str join '/')" }
} else {
let tail = ($parts | last $length | str join "/")
$"($prefix)…/($tail)"
}
}
def _pj_git_info [] {
if (which ^git | is-empty) {
return {
branch: ""
changed: 0
untracked: 0
stashed: 0
ahead: 0
behind: 0
}
}
let repo_check = (^git rev-parse --is-inside-work-tree | complete)
if ($repo_check.exit_code != 0 or (($repo_check.stdout | str trim) != "true")) {
return {
branch: ""
changed: 0
untracked: 0
stashed: 0
ahead: 0
behind: 0
}
}
let branch_result = (^git branch --show-current | complete)
let branch = ($branch_result.stdout | str trim)
let branch_text = if ($branch != "") {
$branch
} else {
let head_result = (^git rev-parse --short HEAD | complete)
if ($head_result.exit_code == 0) {
($head_result.stdout | str trim)
} else {
""
}
}
let status = (^git status --porcelain=2 --branch | complete)
if ($status.exit_code != 0) {
return {
branch: $branch_text
changed: 0
untracked: 0
stashed: 0
ahead: 0
behind: 0
}
}
let lines = ($status.stdout | lines)
let changed = ($lines | where {|l| ($l | str starts-with "1 ") or ($l | str starts-with "2 ") or ($l | str starts-with "u ") } | length)
let untracked = ($lines | where {|l| $l | str starts-with "? " } | length)
let stashed = ((^git stash list | complete).stdout | lines | length)
let ab = ($lines | where {|l| $l | str starts-with "# branch.ab " } | get 0?)
let ahead = if ($ab == null) {
0
} else {
let m = (($ab | parse -r '# branch.ab \+(?<a>\d+) -(?<b>\d+)') | get 0?)
if ($m == null) { 0 } else { (($m | get a) | into int) }
}
let behind = if ($ab == null) {
0
} else {
let m = (($ab | parse -r '# branch.ab \+(?<a>\d+) -(?<b>\d+)') | get 0?)
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
untracked: $untracked
stashed: $stashed
ahead: $ahead
behind: $behind
}
}
def _pj_git_branch_module [] {
let c_git = (ansi '#4ca47b')
let c_alert = (ansi '#c2295b')
let reset = (ansi reset)
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)")
}
if (($git.untracked | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_alert)?($git.untracked)($reset)")
}
if (($git.stashed | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_alert)\$($git.stashed)($reset)")
}
if (($git.ahead | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_git)($git.ahead)($reset)")
}
if (($git.behind | default 0) > 0) {
$status_parts = ($status_parts | append $"($c_git)($git.behind)($reset)")
}
let git_status = if (($status_parts | length) > 0) {
$" (($status_parts | str join ' '))"
} else {
""
}
if ($branch == "") {
""
} else {
$"($c_git)on  ($branch)($git_status) ($reset)"
}
}
def _pj_has_glob [pattern: string] {
((glob $pattern | length) > 0)
}
def _pj_c_version [] {
if (which ^cc | is-empty) {
return ""
}
let out = (^cc --version | complete)
_pj_first_version (($out.stdout | str trim) + " " + ($out.stderr | str trim))
}
def _pj_cpp_version [] {
if (which ^'c++' | is-empty) {
return ""
}
let out = (^'c++' --version | complete)
_pj_first_version (($out.stdout | str trim) + " " + ($out.stderr | str trim))
}
def _pj_rust_version [] {
if (which ^rustc | is-empty) {
return ""
}
let out = (^rustc --version | complete)
_pj_first_version (($out.stdout | str trim) + " " + ($out.stderr | str trim))
}
def _pj_zig_version [] {
if (which ^zig | is-empty) {
return ""
}
let out = (^zig version | complete)
_pj_first_version (($out.stdout | str trim) + " " + ($out.stderr | str trim))
}
def _pj_python_version [] {
if (which ^python | is-not-empty) {
let out = (^python --version | complete)
return (_pj_first_version (($out.stdout | str trim) + " " + ($out.stderr | str trim)))
}
if (which ^python3 | is-not-empty) {
let out = (^python3 --version | complete)
return (_pj_first_version (($out.stdout | str trim) + " " + ($out.stderr | str trim)))
}
""
}
def _pj_python_venv [] {
let venv = ($env.VIRTUAL_ENV? | default "")
if ($venv != "") {
return ($venv | path basename)
}
($env.CONDA_DEFAULT_ENV? | default "")
}
def _pj_lang_segments [] {
let has_c = ((_pj_has_glob "*.c") or (_pj_has_glob "*.h"))
let has_cpp = ((_pj_has_glob "*.cpp") or (_pj_has_glob "*.cc") or (_pj_has_glob "*.cxx") or (_pj_has_glob "*.hpp") or (_pj_has_glob "*.hh") or (_pj_has_glob "*.hxx"))
let has_rust = (("Cargo.toml" | path exists) or (_pj_has_glob "*.rs"))
let has_zig = (("build.zig" | path exists) or (_pj_has_glob "*.zig"))
let has_python = (("pyproject.toml" | path exists) or ("requirements.txt" | path exists) or (".python-version" | path exists) or (_pj_has_glob "*.py"))
mut out = []
if $has_c {
let v = (_pj_c_version)
if ($v != "") {
$out = ($out | append $" v($v)")
} else {
$out = ($out | append "")
}
}
if $has_cpp {
let v = (_pj_cpp_version)
if ($v != "") {
$out = ($out | append $" v($v)")
} else {
$out = ($out | append "")
}
}
if $has_rust {
let v = (_pj_rust_version)
if ($v != "") {
$out = ($out | append $"󱘗 v($v)")
} else {
$out = ($out | append "󱘗")
}
}
if $has_zig {
let v = (_pj_zig_version)
if ($v != "") {
$out = ($out | append $" v($v)")
} else {
$out = ($out | append "")
}
}
if $has_python {
let pyver = (_pj_python_version)
let venv = (_pj_python_venv)
let py_base = if ($pyver != "") { $" v($pyver)" } else { "" }
if ($venv != "") {
$out = ($out | append $"($py_base) \(($venv)\)")
} else {
$out = ($out | append $py_base)
}
}
$out
}
def _pj_shell_module [] {
let reset = (ansi reset)
$"(ansi cyan_bold) nu ($reset)"
}
def _pj_time_module [] {
let c_time = (ansi '#a6356f')
let reset = (ansi reset)
let now = (date now | format date "%R")
$"($c_time)($now) ($reset)"
}
def _pj_duration_module [] {
let c_duration = (ansi '#a6356f')
let reset = (ansi reset)
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)"
}
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 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 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)"
} else {
""
}
let shell_part = (_pj_shell_module)
let dir = (_pj_truncate_pwd $env.PWD 4)
let git_part = (_pj_git_branch_module)
let langs = (_pj_lang_segments)
let lang_parts = ($langs | each {|seg|
if ($seg | str starts-with "") {
$"($c_python)via ($seg) ($reset)"
} else if ($seg | str starts-with "󱘗") {
$"($c_rust)via ($seg) ($reset)"
} else if ($seg | str starts-with "") {
$"($c_cpp)via ($seg) ($reset)"
} else if ($seg | str starts-with "") {
$"($c_c)via ($seg) ($reset)"
} else if ($seg | str starts-with "") {
$"($c_zig)via ($seg) ($reset)"
} else {
$seg
}
})
let time_part = (_pj_time_module)
let duration_part = (_pj_duration_module)
mut out = ""
$out = $"($out)($c_os)(_pj_os_symbol)($reset)"
$out = $"($out)($user_color)($user)($reset)"
if ($host_part != "") { $out = $"($out)($host_part)" }
$out = $"($out)($shell_part)"
$out = $"($out)($c_dir) ($dir) ($reset)"
if ($git_part != "") { $out = $"($out)($git_part)" }
for m in $lang_parts {
$out = $"($out)($m)"
}
$out = $"($out)($time_part)($duration_part)"
$out
}
def _pj_prompt_indicator [] {
if (($env.LAST_EXIT_CODE? | default 0) == 0) {
$"(ansi green_bold)(ansi reset) "
} else {
$"(ansi red_bold)(ansi reset) "
}
}
def _pj_prompt_content [] {
$"(_pj_left_prompt)\n(_pj_prompt_indicator)"
}
export-env {
load-env {
PJ_OS_KEY: (_pj_detect_os_key)
PROMPT_MULTILINE_INDICATOR: ""
PROMPT_INDICATOR: ""
PROMPT_INDICATOR_VI_INSERT: ""
PROMPT_INDICATOR_VI_NORMAL: ""
PROMPT_COMMAND: {||
(_pj_prompt_content)
}
PROMPT_COMMAND_RIGHT: {||
""
}
config: ($env.config? | default {} | merge {
render_right_prompt_on_last_line: false
})
}
}