notes/config/nushell/env.nu

567 lines
14 KiB
Plaintext
Raw Permalink 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.

# Nushell Environment Config File
def create_left_prompt [] {
let path_segment = ($env.PWD)
$path_segment
}
def display_time [] {
let time_segment = ([
(ansi { fg: "#d33682"})
(date now | date format '[%Y-%m-%d %H:%M:%S]')
] | str collect)
$time_segment
}
def create_right_prompt [] {
''
}
def indicator [] {
let code = $env.LAST_EXIT_CODE
let indicator = (
if $code == 0 {[
(ansi {fg: '#2aa198'})
(" ")
] | str collect
} else {[
# if LAST_EXIT_CODE is not 0, then display the code
(ansi { fg: '#b58900' })
( "C:" )
(ansi { fg: '#dc322f' })
( $code )
(ansi { fg: '#dc322f' })
(" ")
] | str collect
}
)
$indicator
}
# Use nushell functions to define your right and left prompt
let-env PROMPT_COMMAND = { simpleline-git }
let-env PROMPT_COMMAND_RIGHT = { create_right_prompt }
# The prompt indicators are environmental variables that represent
# the state of the prompt
let-env PROMPT_INDICATOR = { indicator }
# let-env PROMPT_INDICATOR = { " " }
let-env PROMPT_INDICATOR_VI_INSERT = { ": " }
let-env PROMPT_INDICATOR_VI_NORMAL = { " " }
let-env PROMPT_MULTILINE_INDICATOR = { "::: " }
# Specifies how environment variables are:
# - converted from a string to a value on Nushell startup (from_string)
# - converted from a value back to a string when running external commands (to_string)
# Note: The conversions happen *after* config.nu is loaded
let-env ENV_CONVERSIONS = {
"PATH": {
from_string: { |s| $s | split row (char esep) }
to_string: { |v| $v | str collect (char esep) }
}
"Path": {
from_string: { |s| $s | split row (char esep) }
to_string: { |v| $v | str collect (char esep) }
}
}
# Directories to search for scripts when calling source or use
#
# By default, <nushell-config-dir>/scripts is added
let-env NU_LIB_DIRS = [
($nu.config-path | path dirname | path join 'scripts')
]
# Directories to search for plugin binaries when calling register
#
# By default, <nushell-config-dir>/plugins is added
let-env NU_PLUGIN_DIRS = [
($nu.config-path | path dirname | path join 'plugins')
]
# To add entries to PATH (on Windows you might use Path), you can use the following pattern:
# let-env PATH = ($env.PATH | prepend '/some/path')
# Inspired by panache-git: https://github.com/ehdevries/panache-git
module simpleline {
# Get the current directory with home abbreviated
export def simpleline_dir [] {
let current-dir = ($env.PWD)
let current-dir-relative-to-home = (
do --ignore-errors { $current-dir | path relative-to $nu.home-path } | str collect
)
let in-sub-dir-of-home = ($current-dir-relative-to-home | empty? | nope)
let current-dir-abbreviated = (if $in-sub-dir-of-home {
$'~(char separator)($current-dir-relative-to-home)'
} else if $current-dir == $nu.home-path {
'~'
} else {
$current-dir
})
$'(ansi { fg: "#859900" })($current-dir-abbreviated)'
}
# Get repository status as structured data
export def simpleline_structured [] {
let in-git-repo = (do --ignore-errors { git rev-parse --abbrev-ref HEAD } | empty? | nope)
let status = (if $in-git-repo {
git --no-optional-locks status --porcelain=2 --branch | lines
} else {
[]
})
let on-named-branch = (if $in-git-repo {
$status
| where ($it | str starts-with '# branch.head')
| first
| str contains '(detached)'
| nope
} else {
false
})
let branch-name = (if $on-named-branch {
$status
| where ($it | str starts-with '# branch.head')
| split column ' ' col1 col2 branch
| get branch
| first
} else {
''
})
let commit-hash = (if $in-git-repo {
$status
| where ($it | str starts-with '# branch.oid')
| split column ' ' col1 col2 full_hash
| get full_hash
| first
| str substring [0 7]
} else {
''
})
let tracking-upstream-branch = (if $in-git-repo {
$status
| where ($it | str starts-with '# branch.upstream')
| str collect
| empty?
| nope
} else {
false
})
let upstream-exists-on-remote = (if $in-git-repo {
$status
| where ($it | str starts-with '# branch.ab')
| str collect
| empty?
| nope
} else {
false
})
let ahead-behind-table = (if $upstream-exists-on-remote {
$status
| where ($it | str starts-with '# branch.ab')
| split column ' ' col1 col2 ahead behind
} else {
[[]]
})
let commits-ahead = (if $upstream-exists-on-remote {
$ahead-behind-table
| get ahead
| first
| into int
} else {
0
})
let commits-behind = (if $upstream-exists-on-remote {
$ahead-behind-table
| get behind
| first
| into int
| math abs
} else {
0
})
let has-staging-or-worktree-changes = (if $in-git-repo {
$status
| where ($it | str starts-with '1') || ($it | str starts-with '2')
| str collect
| empty?
| nope
} else {
false
})
let has-untracked-files = (if $in-git-repo {
$status
| where ($it | str starts-with '?')
| str collect
| empty?
| nope
} else {
false
})
let has-unresolved-merge-conflicts = (if $in-git-repo {
$status
| where ($it | str starts-with 'u')
| str collect
| empty?
| nope
} else {
false
})
let staging-worktree-table = (if $has-staging-or-worktree-changes {
$status
| where ($it | str starts-with '1') || ($it | str starts-with '2')
| split column ' '
| get column2
| split column '' staging worktree --collapse-empty
} else {
[[]]
})
let staging-added-count = (if $has-staging-or-worktree-changes {
$staging-worktree-table
| where staging == 'A'
| length
} else {
0
})
let staging-modified-count = (if $has-staging-or-worktree-changes {
$staging-worktree-table
| where staging in ['M', 'R']
| length
} else {
0
})
let staging-deleted-count = (if $has-staging-or-worktree-changes {
$staging-worktree-table
| where staging == 'D'
| length
} else {
0
})
let stashed-count = (if $in-git-repo {
git stash list | split row "\n" | length
} else {
0
})
let untracked-count = (if $has-untracked-files {
$status
| where ($it | str starts-with '?')
| length
} else {
0
})
let worktree-modified-count = (
if $has-staging-or-worktree-changes {
$staging-worktree-table
| where worktree in ['M', 'R']
| length
} else {
0
})
let worktree-deleted-count = (if $has-staging-or-worktree-changes {
$staging-worktree-table
| where worktree == 'D'
| length
} else {
0
})
let merge-conflict-count = (if $has-unresolved-merge-conflicts {
$status
| where ($it | str starts-with 'u')
| length
} else {
0
})
{
in_git_repo: $in-git-repo,
on_named_branch: $on-named-branch,
branch_name: $branch-name,
commit_hash: $commit-hash,
tracking_upstream_branch: $tracking-upstream-branch,
upstream_exists_on_remote: $upstream-exists-on-remote,
commits_ahead: $commits-ahead,
commits_behind: $commits-behind,
staging_added_count: $staging-added-count,
staging_modified_count: $staging-modified-count,
staging_deleted_count: $staging-deleted-count,
stashed_count: $stashed-count,
untracked_count: $untracked-count,
worktree_modified_count: $worktree-modified-count,
worktree_deleted_count: $worktree-deleted-count,
merge_conflict_count: $merge-conflict-count
}
}
# Get repository status as a styled string
export def simpleline_styled [] {
let status = (simpleline_structured)
let is-local-only = ($status.tracking_upstream_branch != true)
let upstream-deleted = (
$status.tracking_upstream_branch &&
$status.upstream_exists_on_remote != true
)
let is-up-to-date = (
$status.upstream_exists_on_remote &&
$status.commits_ahead == 0 &&
$status.commits_behind == 0
)
let is-ahead = (
$status.upstream_exists_on_remote &&
$status.commits_ahead > 0 &&
$status.commits_behind == 0
)
let is-behind = (
$status.upstream_exists_on_remote &&
$status.commits_ahead == 0 &&
$status.commits_behind > 0
)
let is-ahead-and-behind = (
$status.upstream_exists_on_remote &&
$status.commits_ahead > 0 &&
$status.commits_behind > 0
)
let branch-name = (if $status.in_git_repo {
(if $status.on_named_branch {
$status.branch_name
} else {
['(' $status.commit_hash '...)'] | str collect
})
} else {
''
})
let branch-styled = (if $status.in_git_repo {
(if $is-local-only {
(branch-local-only $branch-name)
} else if $is-up-to-date {
(branch-up-to-date $branch-name)
} else if $is-ahead {
(branch-ahead $branch-name $status.commits_ahead)
} else if $is-behind {
(branch-behind $branch-name $status.commits_behind)
} else if $is-ahead-and-behind {
(branch-ahead-and-behind $branch-name $status.commits_ahead $status.commits_behind)
} else if $upstream-deleted {
(branch-upstream-deleted $branch-name)
} else {
$branch-name
})
} else {
''
})
let has-staging-changes = (
$status.staging_added_count > 0 ||
$status.staging_modified_count > 0 ||
$status.staging_deleted_count > 0
)
let has-worktree-changes = (
$status.untracked_count > 0 ||
$status.worktree_modified_count > 0 ||
$status.worktree_deleted_count > 0 ||
$status.merge_conflict_count > 0
)
let has-stashed-changes = (
$status.stashed_count > 0
)
let has-merge-conflicts = $status.merge_conflict_count > 0
let staging-summary = (if $has-staging-changes {
(staging-changes $status.staging_added_count $status.staging_modified_count $status.staging_deleted_count)
} else {
''
})
let worktree-summary = (if $has-worktree-changes {
(worktree-changes $status.untracked_count $status.worktree_modified_count $status.worktree_deleted_count)
} else {
''
})
let stash-summary = (if $has-stashed-changes {
(stashed-changes $status.stashed_count)
} else {
''
})
let merge-conflict-summary = (if $has-merge-conflicts {
(unresolved-conflicts $status.merge_conflict_count)
} else {
''
})
let delimiter = (if ($has-staging-changes && $has-worktree-changes) {
('|' | bright-yellow)
} else {
''
})
let local-summary = (
$'($staging-summary) ($delimiter) ($worktree-summary) ($stash-summary) ($merge-conflict-summary)' | str trim
)
let local-indicator = (if $status.in_git_repo {
(if $has-worktree-changes {
('!' | red)
} else if $has-staging-changes {
('~' | bright-cyan)
} else if $has-stashed-changes {
('▣' | green)
} else {
''
})
} else {
''
})
let repo-summary = (
$'($branch-styled) ($local-summary) ($local-indicator)' | str trim
)
let left-bracket = ('[' | bright-yellow)
let right-bracket = (']' | bright-yellow)
(if $status.in_git_repo {
$'($left-bracket)($repo-summary)($right-bracket)'
} else {
''
})
}
# Helper commands to encapsulate style and make everything else more readable
def nope [] {
each { |it| $it == false }
}
def bright-cyan [] {
each { |it| $"(ansi -e '96m')($it)(ansi reset)" }
}
def bright-green [] {
each { |it| $"(ansi -e '92m')($it)(ansi reset)" }
}
def bright-red [] {
each { |it| $"(ansi -e '91m')($it)(ansi reset)" }
}
def bright-yellow [] {
each { |it| $"(ansi -e '93m')($it)(ansi reset)" }
}
def green [] {
each { |it| $"(ansi green)($it)(ansi reset)" }
}
def red [] {
each { |it| $"(ansi red)($it)(ansi reset)" }
}
def branch-local-only [
branch: string
] {
$branch | bright-cyan
}
def branch-upstream-deleted [
branch: string
] {
$'($branch) (char failed)' | bright-cyan
}
def branch-up-to-date [
branch: string
] {
$'($branch) (char identical_to)' | bright-cyan
}
def branch-ahead [
branch: string
ahead: int
] {
$'($branch) (char branch_ahead)($ahead)' | bright-green
}
def branch-behind [
branch: string
behind: int
] {
$'($branch) (char branch_behind)($behind)' | bright-red
}
def branch-ahead-and-behind [
branch: string
ahead: int
behind: int
] {
$'($branch) (char branch_behind)($behind) (char branch_ahead)($ahead)' | bright-yellow
}
def staging-changes [
added: int
modified: int
deleted: int
] {
$'+($added) ~($modified) -($deleted)' | green
}
def worktree-changes [
added: int
modified: int
deleted: int
] {
$'+($added) ~($modified) -($deleted)' | red
}
def stashed-changes [ num: int ] {
$'▣($num)' | bright-cyan
}
def unresolved-conflicts [
conflicts: int
] {
$'!($conflicts)' | red
}
}
# An opinionated Git prompt for Nushell, styled after posh-git
def simpleline-git [] {
use simpleline *
let prompt = ($'(display_time) (simpleline_dir) (simpleline_styled)' | str trim )
$'($prompt)'
}