@pm-2001/shellup 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@pm-2001/shellup",
3
+ "version": "0.1.0",
4
+ "description": "Level up your terminal in 60 seconds — a beautiful prompt, modern tool swaps, and sane defaults, installed by one command and reversible by another.",
5
+ "keywords": [
6
+ "terminal",
7
+ "zsh",
8
+ "prompt",
9
+ "cli",
10
+ "dotfiles",
11
+ "shell",
12
+ "developer-experience",
13
+ "theme",
14
+ "productivity"
15
+ ],
16
+ "homepage": "https://github.com/pm-2001/shell-up#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/pm-2001/shell-up.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/pm-2001/shell-up/issues"
23
+ },
24
+ "license": "MIT",
25
+ "author": "pm-2001",
26
+ "type": "module",
27
+ "bin": {
28
+ "shellup": "dist/cli.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "runtime",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "engines": {
37
+ "node": ">=18"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "typecheck": "tsc --noEmit",
46
+ "prepublishOnly": "npm run typecheck && npm run build"
47
+ },
48
+ "dependencies": {
49
+ "@clack/prompts": "^1.7.0",
50
+ "picocolors": "^1.1.1"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^26.4.0",
54
+ "tsup": "^8.5.1",
55
+ "typescript": "^7.0.2"
56
+ }
57
+ }
@@ -0,0 +1,46 @@
1
+ # shellup — aliases
2
+ # Only aliases that are safe without any extra binary installed. Anything that
3
+ # depends on eza/bat/lazygit lives in generated/tools.zsh behind a guard.
4
+
5
+ [[ -o interactive ]] || return 0
6
+
7
+ # ── Navigation ─────────────────────────────────────────────────────────────
8
+ alias ..='cd ..'
9
+ alias ...='cd ../..'
10
+ alias ....='cd ../../..'
11
+ alias -- -='cd -'
12
+
13
+ # ── Safety rails ───────────────────────────────────────────────────────────
14
+ alias cp='cp -i'
15
+ alias mv='mv -i'
16
+ alias mkdir='mkdir -p'
17
+
18
+ # ── git ────────────────────────────────────────────────────────────────────
19
+ alias g='git'
20
+ alias gs='git status --short --branch'
21
+ alias ga='git add'
22
+ alias gaa='git add --all'
23
+ alias gc='git commit'
24
+ alias gcm='git commit -m'
25
+ alias gca='git commit --amend'
26
+ alias gco='git checkout'
27
+ alias gsw='git switch'
28
+ alias gb='git branch'
29
+ alias gd='git diff'
30
+ alias gds='git diff --staged'
31
+ alias gp='git push'
32
+ alias gpl='git pull'
33
+ alias gf='git fetch --all --prune'
34
+ alias gst='git stash'
35
+ alias gl='git log --oneline --graph --decorate -20'
36
+ alias gll='git log --oneline --graph --decorate --all'
37
+ alias gundo='git reset --soft HEAD~1'
38
+ alias gwip='git add -A && git commit -m "wip" --no-verify'
39
+
40
+ # ── Shell housekeeping ─────────────────────────────────────────────────────
41
+ alias reload='exec zsh'
42
+ alias path='print -l $path'
43
+ alias now='date "+%Y-%m-%d %H:%M:%S"'
44
+ alias week='date +%V'
45
+ alias ports='lsof -iTCP -sTCP:LISTEN -P -n'
46
+ alias myip='curl -s https://api.ipify.org && echo'
@@ -0,0 +1,56 @@
1
+ # shellup — functions
2
+ # The handful of things that are genuinely awkward to type out every time.
3
+
4
+ [[ -o interactive ]] || return 0
5
+
6
+ # Make a directory and step into it.
7
+ mkcd() {
8
+ [[ -z $1 ]] && { print -u2 "usage: mkcd <dir>"; return 2 }
9
+ mkdir -p -- "$1" && builtin cd -- "$1"
10
+ }
11
+
12
+ # One command for every archive format, instead of remembering nine flag sets.
13
+ extract() {
14
+ [[ -z $1 ]] && { print -u2 "usage: extract <archive>"; return 2 }
15
+ [[ -f $1 ]] || { print -u2 "extract: no such file: $1"; return 1 }
16
+ case $1 in
17
+ *.tar.bz2|*.tbz2) tar xjf -- "$1" ;;
18
+ *.tar.gz|*.tgz) tar xzf -- "$1" ;;
19
+ *.tar.xz) tar xJf -- "$1" ;;
20
+ *.tar.zst) tar --zstd -xf -- "$1" ;;
21
+ *.tar) tar xf -- "$1" ;;
22
+ *.bz2) bunzip2 -- "$1" ;;
23
+ *.gz) gunzip -- "$1" ;;
24
+ *.zip) unzip -- "$1" ;;
25
+ *.7z) 7z x "$1" ;;
26
+ *.rar) unrar x "$1" ;;
27
+ *.Z) uncompress -- "$1" ;;
28
+ *) print -u2 "extract: don't know how to open $1"; return 1 ;;
29
+ esac
30
+ }
31
+
32
+ # Serve the current directory over HTTP. `serve 3000` to pick a port.
33
+ serve() {
34
+ local port=${1:-8000}
35
+ print "serving $PWD on http://localhost:$port"
36
+ python3 -m http.server "$port"
37
+ }
38
+
39
+ # What is holding this port, and what do I kill?
40
+ onport() {
41
+ [[ -z $1 ]] && { print -u2 "usage: onport <port>"; return 2 }
42
+ lsof -nP -iTCP:"$1" -sTCP:LISTEN
43
+ }
44
+
45
+ # Timestamped copy, for when you're about to edit something risky.
46
+ bak() {
47
+ [[ -z $1 ]] && { print -u2 "usage: bak <file>"; return 2 }
48
+ cp -a -- "$1" "$1.$(date +%Y%m%d-%H%M%S).bak" && print "backed up $1"
49
+ }
50
+
51
+ # Jump to the root of the current git repo.
52
+ cdr() {
53
+ local root
54
+ root=$(git rev-parse --show-toplevel 2>/dev/null) || { print -u2 "cdr: not in a git repo"; return 1 }
55
+ builtin cd -- "$root"
56
+ }
@@ -0,0 +1,45 @@
1
+ # shellup — keybindings
2
+ # Emacs bindings plus the two things people miss most: prefix-aware history
3
+ # search on the arrow keys, and word-wise movement that works over ssh.
4
+
5
+ [[ -o interactive ]] || return 0
6
+
7
+ bindkey -e
8
+
9
+ # Type a few characters, press Up: cycles only through matching history.
10
+ autoload -U up-line-or-beginning-search down-line-or-beginning-search
11
+ zle -N up-line-or-beginning-search
12
+ zle -N down-line-or-beginning-search
13
+ bindkey '^[[A' up-line-or-beginning-search # Up
14
+ bindkey '^[[B' down-line-or-beginning-search # Down
15
+ bindkey '^[OA' up-line-or-beginning-search # Up (application mode)
16
+ bindkey '^[OB' down-line-or-beginning-search # Down (application mode)
17
+
18
+ bindkey '^[[1;5C' forward-word # Ctrl-Right
19
+ bindkey '^[[1;5D' backward-word # Ctrl-Left
20
+ bindkey '^[[1;3C' forward-word # Alt-Right
21
+ bindkey '^[[1;3D' backward-word # Alt-Left
22
+ bindkey '^[f' forward-word
23
+ bindkey '^[b' backward-word
24
+
25
+ bindkey '^[[H' beginning-of-line # Home
26
+ bindkey '^[[F' end-of-line # End
27
+ bindkey '^[[3~' delete-char # Delete
28
+ bindkey '^[[3;5~' kill-word # Ctrl-Delete
29
+
30
+ bindkey '^U' backward-kill-line # match bash: kill to start, not whole line
31
+ bindkey '^[^?' backward-kill-word # Alt-Backspace
32
+
33
+ # Treat path separators as word boundaries so Ctrl-W deletes one path segment.
34
+ WORDCHARS='*?_-.[]~&;!#$%^(){}<>'
35
+
36
+ # Ctrl-Z again to foreground the job you just suspended.
37
+ _shellup_fg() {
38
+ if [[ $#BUFFER -eq 0 ]]; then
39
+ fg >/dev/null 2>&1 && zle redisplay
40
+ else
41
+ zle push-input
42
+ fi
43
+ }
44
+ zle -N _shellup_fg
45
+ bindkey '^Z' _shellup_fg
@@ -0,0 +1,59 @@
1
+ # shellup — zsh defaults
2
+ # Stock zsh forgets history across panes, re-asks for completions it already
3
+ # knows, and makes you type `cd`. These are the settings most people end up
4
+ # copying from a blog post eventually.
5
+
6
+ [[ -o interactive ]] || return 0
7
+
8
+ # ── History ────────────────────────────────────────────────────────────────
9
+ HISTFILE="${HISTFILE:-$HOME/.zsh_history}"
10
+ HISTSIZE=100000
11
+ SAVEHIST=100000
12
+ setopt append_history # never truncate another shell's writes
13
+ setopt inc_append_history # write as you go, not just on exit
14
+ setopt share_history # new panes see what you just ran
15
+ setopt hist_ignore_dups
16
+ setopt hist_ignore_all_dups
17
+ setopt hist_ignore_space # a leading space keeps it out of history
18
+ setopt hist_reduce_blanks
19
+ setopt hist_verify # expand !! for review instead of running it
20
+ setopt extended_history
21
+
22
+ # ── Navigation ─────────────────────────────────────────────────────────────
23
+ setopt auto_cd # `../..` instead of `cd ../..`
24
+ setopt auto_pushd # every cd builds a stack; `cd -<TAB>` to browse
25
+ setopt pushd_ignore_dups
26
+ setopt pushd_silent
27
+ DIRSTACKSIZE=20
28
+
29
+ # ── Globbing & misc ────────────────────────────────────────────────────────
30
+ setopt extended_glob
31
+ setopt no_case_glob
32
+ setopt interactive_comments # `# note` is legal at the prompt
33
+ setopt no_beep
34
+ setopt no_flow_control # frees Ctrl-S / Ctrl-Q for real bindings
35
+ unsetopt correct_all # autocorrect guesses wrong more than it helps
36
+
37
+ # ── Completion ─────────────────────────────────────────────────────────────
38
+ # compinit rebuilds its cache on every launch unless told otherwise; checking
39
+ # the dump's age once a day keeps startup fast without going stale.
40
+ autoload -Uz compinit
41
+ () {
42
+ local dump="${ZDOTDIR:-$HOME}/.zcompdump"
43
+ if [[ -n ${dump}(#qN.mh+24) ]]; then
44
+ compinit -d "$dump"
45
+ else
46
+ compinit -C -d "$dump"
47
+ fi
48
+ }
49
+
50
+ zstyle ':completion:*' menu select
51
+ zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*'
52
+ zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
53
+ zstyle ':completion:*' group-name ''
54
+ zstyle ':completion:*:descriptions' format '%F{242}%d%f'
55
+ zstyle ':completion:*:warnings' format '%F{red}no matches%f'
56
+ zstyle ':completion:*' use-cache on
57
+ zstyle ':completion:*' cache-path "${XDG_CACHE_HOME:-$HOME/.cache}/zsh/compcache"
58
+ zstyle ':completion:*' special-dirs true
59
+ zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
@@ -0,0 +1,161 @@
1
+ # shellup — prompt engine
2
+ #
3
+ # The expensive part of a git prompt is `git status` in a large repo. Doing that
4
+ # synchronously is what makes themed prompts feel sluggish, so here the only
5
+ # blocking work per prompt is a single `git rev-parse`; counts, divergence and
6
+ # stash state are computed in a background process that repaints the prompt when
7
+ # it lands. Themes never touch any of this — they read the SHELLUP_* variables
8
+ # and define shellup_theme_render to format them.
9
+
10
+ [[ -o interactive ]] || return 0
11
+
12
+ autoload -Uz add-zsh-hook
13
+ setopt prompt_subst
14
+
15
+ # Overridden by whichever theme file loads next. Defined here so a missing or
16
+ # broken theme degrades to a plain prompt instead of erroring on every line.
17
+ shellup_theme_render() { SHELLUP_GIT_PROMPT=""; }
18
+
19
+ typeset -g SHELLUP_GIT_ROOT="" SHELLUP_GIT_BRANCH="" SHELLUP_GIT_ACTION=""
20
+ typeset -gi SHELLUP_GIT_STAGED=0 SHELLUP_GIT_UNSTAGED=0 SHELLUP_GIT_UNTRACKED=0
21
+ typeset -gi SHELLUP_GIT_CONFLICTED=0 SHELLUP_GIT_AHEAD=0 SHELLUP_GIT_BEHIND=0
22
+ typeset -gi SHELLUP_GIT_STASH=0 SHELLUP_GIT_LOADING=0
23
+ typeset -g SHELLUP_GIT_PROMPT="" SHELLUP_DURATION="" SHELLUP_VENV=""
24
+ typeset -gi _shellup_async_fd=0 _shellup_timer=0
25
+
26
+ : ${SHELLUP_SLOW_THRESHOLD:=3}
27
+
28
+ _shellup_git_reset() {
29
+ SHELLUP_GIT_ROOT=""; SHELLUP_GIT_BRANCH=""; SHELLUP_GIT_ACTION=""
30
+ SHELLUP_GIT_STAGED=0; SHELLUP_GIT_UNSTAGED=0; SHELLUP_GIT_UNTRACKED=0
31
+ SHELLUP_GIT_CONFLICTED=0; SHELLUP_GIT_AHEAD=0; SHELLUP_GIT_BEHIND=0
32
+ SHELLUP_GIT_STASH=0; SHELLUP_GIT_LOADING=0; SHELLUP_GIT_PROMPT=""
33
+ }
34
+
35
+ # Runs in a background process. Prints one space-separated line; "-" means empty,
36
+ # so every field stays at a fixed position and the reader needs no parsing rules.
37
+ _shellup_git_worker() {
38
+ builtin cd -q "$1" 2>/dev/null || return
39
+ local line xy branch="-" action="-" rest
40
+ local -i staged=0 unstaged=0 untracked=0 conflicted=0 ahead=0 behind=0 stash=0
41
+
42
+ while IFS= read -r line; do
43
+ case $line in
44
+ '# branch.head '*) branch=${line#'# branch.head '} ;;
45
+ '# branch.ab '*)
46
+ rest=${line#'# branch.ab '}
47
+ ahead=${${rest%% *}#+}
48
+ behind=${${rest##* }#-}
49
+ ;;
50
+ '? '*) (( untracked += 1 )) ;;
51
+ 'u '*) (( conflicted += 1 )) ;;
52
+ [12]' '*)
53
+ xy=${line[3,4]} # porcelain v2: X=index, Y=worktree
54
+ [[ ${xy[1]} != '.' ]] && (( staged += 1 ))
55
+ [[ ${xy[2]} != '.' ]] && (( unstaged += 1 ))
56
+ ;;
57
+ esac
58
+ done < <(command git status --porcelain=v2 --branch --untracked-files=normal 2>/dev/null)
59
+
60
+ stash=$(command git rev-list --walk-reflogs --count refs/stash 2>/dev/null) || stash=0
61
+ [[ -z $stash ]] && stash=0
62
+
63
+ local gitdir
64
+ gitdir=$(command git rev-parse --git-dir 2>/dev/null)
65
+ if [[ -n $gitdir ]]; then
66
+ if [[ -d $gitdir/rebase-merge || -d $gitdir/rebase-apply ]]; then action="rebase"
67
+ elif [[ -f $gitdir/MERGE_HEAD ]]; then action="merge"
68
+ elif [[ -f $gitdir/CHERRY_PICK_HEAD ]]; then action="cherry-pick"
69
+ elif [[ -f $gitdir/REVERT_HEAD ]]; then action="revert"
70
+ elif [[ -f $gitdir/BISECT_LOG ]]; then action="bisect"
71
+ fi
72
+ fi
73
+
74
+ [[ $branch == '(detached)' ]] && branch="@$(command git rev-parse --short HEAD 2>/dev/null)"
75
+ print -r -- "$staged $unstaged $untracked $conflicted $ahead $behind $stash $action $branch"
76
+ }
77
+
78
+ _shellup_async_stop() {
79
+ (( _shellup_async_fd )) || return 0
80
+ zle -F $_shellup_async_fd 2>/dev/null
81
+ exec {_shellup_async_fd}<&- 2>/dev/null
82
+ _shellup_async_fd=0
83
+ }
84
+
85
+ # Fired by zle when the worker has written its line (or hung up).
86
+ _shellup_async_callback() {
87
+ local fd=$1 data
88
+ IFS= read -r data <&$fd
89
+ zle -F $fd 2>/dev/null
90
+ exec {fd}<&- 2>/dev/null
91
+ _shellup_async_fd=0
92
+ SHELLUP_GIT_LOADING=0
93
+
94
+ if [[ -n $data ]]; then
95
+ local -a f=( ${=data} )
96
+ SHELLUP_GIT_STAGED=$f[1]; SHELLUP_GIT_UNSTAGED=$f[2]
97
+ SHELLUP_GIT_UNTRACKED=$f[3]; SHELLUP_GIT_CONFLICTED=$f[4]
98
+ SHELLUP_GIT_AHEAD=$f[5]; SHELLUP_GIT_BEHIND=$f[6]
99
+ SHELLUP_GIT_STASH=$f[7]
100
+ [[ $f[8] != '-' ]] && SHELLUP_GIT_ACTION=$f[8] || SHELLUP_GIT_ACTION=""
101
+ [[ $f[9] != '-' ]] && SHELLUP_GIT_BRANCH=$f[9]
102
+ fi
103
+
104
+ shellup_theme_render
105
+ zle && zle reset-prompt
106
+ }
107
+
108
+ _shellup_preexec() {
109
+ _shellup_timer=$EPOCHSECONDS
110
+ }
111
+
112
+ _shellup_precmd() {
113
+ # Command duration, surfaced only when it was long enough to care about.
114
+ SHELLUP_DURATION=""
115
+ if (( _shellup_timer )); then
116
+ local -i elapsed=$(( EPOCHSECONDS - _shellup_timer ))
117
+ if (( elapsed >= SHELLUP_SLOW_THRESHOLD )); then
118
+ if (( elapsed < 60 )); then SHELLUP_DURATION="${elapsed}s"
119
+ elif (( elapsed < 3600 )); then SHELLUP_DURATION="$(( elapsed / 60 ))m$(( elapsed % 60 ))s"
120
+ else SHELLUP_DURATION="$(( elapsed / 3600 ))h$(( (elapsed % 3600) / 60 ))m"
121
+ fi
122
+ fi
123
+ _shellup_timer=0
124
+ fi
125
+
126
+ SHELLUP_VENV=""
127
+ [[ -n $VIRTUAL_ENV ]] && SHELLUP_VENV=${VIRTUAL_ENV:t}
128
+
129
+ _shellup_async_stop
130
+
131
+ # The one synchronous git call: cheap even in a huge repo.
132
+ local -a info
133
+ info=( ${(f)"$(command git rev-parse --show-toplevel --abbrev-ref HEAD 2>/dev/null)"} )
134
+ if (( ${#info} < 2 )); then
135
+ _shellup_git_reset
136
+ shellup_theme_render
137
+ return
138
+ fi
139
+
140
+ local root=$info[1] branch=$info[2]
141
+ # rev-parse still prints the toplevel on an unborn branch but resolves HEAD to
142
+ # the literal string "HEAD"; a detached checkout does the same. Git forbids a
143
+ # branch actually named HEAD, so this is an unambiguous signal to look closer.
144
+ if [[ $branch == HEAD ]]; then
145
+ branch=$(command git symbolic-ref --short HEAD 2>/dev/null) \
146
+ || branch="@$(command git rev-parse --short HEAD 2>/dev/null)"
147
+ fi
148
+ # Leaving a repo must clear counts, or the old repo's state bleeds into the new prompt.
149
+ [[ $root != $SHELLUP_GIT_ROOT ]] && _shellup_git_reset
150
+ SHELLUP_GIT_ROOT=$root
151
+ SHELLUP_GIT_BRANCH=$branch
152
+ SHELLUP_GIT_LOADING=1
153
+ shellup_theme_render
154
+
155
+ exec {_shellup_async_fd}< <( _shellup_git_worker "$root" )
156
+ zle -F $_shellup_async_fd _shellup_async_callback
157
+ }
158
+
159
+ zmodload zsh/datetime 2>/dev/null
160
+ add-zsh-hook preexec _shellup_preexec
161
+ add-zsh-hook precmd _shellup_precmd
@@ -0,0 +1,29 @@
1
+ # shellup theme: minimal
2
+ # Deliberately glyph-free — every character here exists in any monospace font,
3
+ # so this is the theme that is always safe to fall back to.
4
+
5
+ typeset -g SHELLUP_CTX_PROMPT=""
6
+
7
+ shellup_theme_render() {
8
+ local s=""
9
+ if [[ -n $SHELLUP_GIT_BRANCH ]]; then
10
+ s=" %F{242}on%f %F{magenta}${SHELLUP_GIT_BRANCH}%f"
11
+ (( SHELLUP_GIT_STAGED )) && s+=" %F{green}+${SHELLUP_GIT_STAGED}%f"
12
+ (( SHELLUP_GIT_UNSTAGED )) && s+=" %F{yellow}!${SHELLUP_GIT_UNSTAGED}%f"
13
+ (( SHELLUP_GIT_UNTRACKED )) && s+=" %F{blue}?${SHELLUP_GIT_UNTRACKED}%f"
14
+ (( SHELLUP_GIT_CONFLICTED )) && s+=" %F{red}x${SHELLUP_GIT_CONFLICTED}%f"
15
+ (( SHELLUP_GIT_STASH )) && s+=" %F{cyan}*${SHELLUP_GIT_STASH}%f"
16
+ (( SHELLUP_GIT_AHEAD )) && s+=" %F{cyan}^${SHELLUP_GIT_AHEAD}%f"
17
+ (( SHELLUP_GIT_BEHIND )) && s+=" %F{cyan}v${SHELLUP_GIT_BEHIND}%f"
18
+ [[ -n $SHELLUP_GIT_ACTION ]] && s+=" %F{red}(${SHELLUP_GIT_ACTION})%f"
19
+ fi
20
+ SHELLUP_GIT_PROMPT=$s
21
+
22
+ local ctx=""
23
+ [[ -n $SHELLUP_VENV ]] && ctx=" %F{yellow}(${SHELLUP_VENV})%f"
24
+ SHELLUP_CTX_PROMPT=$ctx
25
+ }
26
+
27
+ PROMPT='%F{39}%(4~|…/%3~|%~)%f${SHELLUP_GIT_PROMPT}${SHELLUP_CTX_PROMPT}
28
+ %(?.%F{green}.%F{red})>%f '
29
+ RPROMPT='%F{242}${SHELLUP_DURATION}%f%(?.. %F{red}[%?]%f)'
@@ -0,0 +1,29 @@
1
+ # shellup theme: neon
2
+ # Bright two-line prompt drawn with box characters and common Unicode arrows —
3
+ # no patched font required, so it works next to minimal on a bare system.
4
+
5
+ typeset -g SHELLUP_CTX_PROMPT=""
6
+
7
+ shellup_theme_render() {
8
+ local s=""
9
+ if [[ -n $SHELLUP_GIT_BRANCH ]]; then
10
+ s=" %F{240}·%f %F{213}⌥ ${SHELLUP_GIT_BRANCH}%f"
11
+ (( SHELLUP_GIT_STAGED )) && s+=" %F{82}●${SHELLUP_GIT_STAGED}%f"
12
+ (( SHELLUP_GIT_UNSTAGED )) && s+=" %F{220}✚${SHELLUP_GIT_UNSTAGED}%f"
13
+ (( SHELLUP_GIT_UNTRACKED )) && s+=" %F{45}◌${SHELLUP_GIT_UNTRACKED}%f"
14
+ (( SHELLUP_GIT_CONFLICTED )) && s+=" %F{196}✖${SHELLUP_GIT_CONFLICTED}%f"
15
+ (( SHELLUP_GIT_STASH )) && s+=" %F{141}⚑${SHELLUP_GIT_STASH}%f"
16
+ (( SHELLUP_GIT_AHEAD )) && s+=" %F{51}⇡${SHELLUP_GIT_AHEAD}%f"
17
+ (( SHELLUP_GIT_BEHIND )) && s+=" %F{51}⇣${SHELLUP_GIT_BEHIND}%f"
18
+ [[ -n $SHELLUP_GIT_ACTION ]] && s+=" %F{196}⚡${SHELLUP_GIT_ACTION}%f"
19
+ fi
20
+ SHELLUP_GIT_PROMPT=$s
21
+
22
+ local ctx=""
23
+ [[ -n $SHELLUP_VENV ]] && ctx=" %F{240}·%f %F{184}🐍${SHELLUP_VENV}%f"
24
+ SHELLUP_CTX_PROMPT=$ctx
25
+ }
26
+
27
+ PROMPT='%F{240}╭─%f %F{51}%(4~|…/%3~|%~)%f${SHELLUP_GIT_PROMPT}${SHELLUP_CTX_PROMPT}
28
+ %F{240}╰─%f%(?.%F{213}.%F{196})❯%f '
29
+ RPROMPT='%F{240}${SHELLUP_DURATION}%f%(?.. %F{196}✖ %?%f)'
@@ -0,0 +1,36 @@
1
+ # shellup theme: powerline
2
+ # Requires a Nerd Font — the separators and icons below are private-use glyphs
3
+ # and render as tofu boxes without one. `shellup doctor` checks for this.
4
+
5
+ typeset -g SHELLUP_CTX_PROMPT=""
6
+
7
+ shellup_theme_render() {
8
+ local s=""
9
+ if [[ -n $SHELLUP_GIT_BRANCH ]]; then
10
+ local body=" ${SHELLUP_GIT_BRANCH}"
11
+ (( SHELLUP_GIT_STAGED )) && body+=" +${SHELLUP_GIT_STAGED}"
12
+ (( SHELLUP_GIT_UNSTAGED )) && body+=" !${SHELLUP_GIT_UNSTAGED}"
13
+ (( SHELLUP_GIT_UNTRACKED )) && body+=" ?${SHELLUP_GIT_UNTRACKED}"
14
+ (( SHELLUP_GIT_CONFLICTED )) && body+=" ${SHELLUP_GIT_CONFLICTED}"
15
+ (( SHELLUP_GIT_STASH )) && body+=" ${SHELLUP_GIT_STASH}"
16
+ (( SHELLUP_GIT_AHEAD )) && body+=" ⇡${SHELLUP_GIT_AHEAD}"
17
+ (( SHELLUP_GIT_BEHIND )) && body+=" ⇣${SHELLUP_GIT_BEHIND}"
18
+ [[ -n $SHELLUP_GIT_ACTION ]] && body+=" ${SHELLUP_GIT_ACTION}"
19
+
20
+ # Dirty tree turns the segment amber; clean stays green.
21
+ local bg=71
22
+ (( SHELLUP_GIT_UNSTAGED + SHELLUP_GIT_UNTRACKED + SHELLUP_GIT_CONFLICTED )) && bg=178
23
+ s="%K{$bg}%F{24}%f%F{233}${body} %f%k%F{$bg}%f"
24
+ else
25
+ s="%F{24}%f"
26
+ fi
27
+ SHELLUP_GIT_PROMPT=$s
28
+
29
+ local ctx=""
30
+ [[ -n $SHELLUP_VENV ]] && ctx=" %F{184} ${SHELLUP_VENV}%f"
31
+ SHELLUP_CTX_PROMPT=$ctx
32
+ }
33
+
34
+ PROMPT='%K{24}%F{233} %(4~|…/%3~|%~) %f%k${SHELLUP_GIT_PROMPT}${SHELLUP_CTX_PROMPT}
35
+ %(?.%F{71}.%F{160})❯%f '
36
+ RPROMPT='%F{240}${SHELLUP_DURATION}%f%(?.. %F{160} %?%f)'