Skip to content
nobspromptby neg4n.dev
Esc
navigateopen⌘Jpreview
On this page

Opinionated prompt

Read the shipped one-line Zsh prompt, learn how each segment is built from NBSP_DATA, and use the same file as a template for your own layouts.

Initialize the opinionated prompt in ~/.zshrc:

eval "$(nbsp init zsh --autosuggest)"

If another ghost-text plugin is already active, omit --autosuggest.

/U/i/D/p/nobsprompt [main +1 ~2 ?3 ^1] [node:22.14.0] [2.4s] [jobs:2] %

How it is built

nbsp data fills NBSP_DATA; this callback builds PROMPT. Git and Node stay off the foreground path. nbsp init zsh embeds the same file.

# Opinionated one-line prompt - the default shipped by `nbsp init zsh`.
# This is the same file the docs show. Treat it as a real template:
#   1. quote dynamic fields
#   2. build each segment only when it has something useful to say
#   3. assign PROMPT
#   4. register so redraws rebuild after every successful data load
#
# Skip if already installed (double eval of init is a no-op).
if (( ! $+functions[nbsp_opinionated_prompt] )); then

nbsp_opinionated_prompt() {
  emulate -L zsh
  local path= git= node= duration= jobs= end= piece=
  local -i ms=0 secs=0 mins=0 rem=0 tenths=0 whole=0 frac=0

  # Anything from the backend (path, branch, node, …) must be quoted before
  # it enters PROMPT. That keeps % ! and control characters from breaking
  # prompt expansion under PROMPT_PERCENT / PROMPT_BANG / PROMPT_SUBST.
  nbsp_prompt_quote "${NBSP_DATA[path]-}"
  path=$REPLY

  # Path is always drawn when collection succeeded (backend already abbreviated).
  path="%F{default}${path}%f"

  # Git: only when a repo was found and we have a branch (or short detached oid).
  # Counters come from the cache only when it matches the current HEAD (git_valid).
  # Marker order: staged, worktree, untracked, unmerged, ahead, behind, stashes.
  if [[ ${NBSP_DATA[git_present]-} == 1 && -n ${NBSP_DATA[git_branch]-} ]]; then
    nbsp_prompt_quote "${NBSP_DATA[git_branch]}"
    git=" %F{default}[${REPLY}"
    if [[ ${NBSP_DATA[git_valid]-} == 1 ]]; then
      local -a marker_keys=(
        git_staged git_modified git_untracked git_conflicted
        git_ahead git_behind git_stashes
      )
      local -a marker_chars=('+' '~' '?' '!' '^' 'v' '*')
      local -i i
      for (( i = 1; i <= $#marker_keys; i++ )); do
        (( NBSP_DATA[${marker_keys[i]}] )) || continue
        nbsp_prompt_quote "${marker_chars[i]}"
        git+=" ${REPLY}${NBSP_DATA[${marker_keys[i]}]}"
      done
    else
      # Cache is missing or branch moved; keep the label but mark it stale.
      git+=' ...'
    fi
    git+=']%f'
  fi

  # Node version is parsed from NVM_BIN on the C side (no node process).
  if [[ -n ${NBSP_DATA[node_version]-} ]]; then
    nbsp_prompt_quote "[node:${NBSP_DATA[node_version]}]"
    node=" %F{green}${REPLY}%f"
  fi

  # Duration only for slow commands (2 seconds and up), same rules as before.
  ms=${NBSP_DATA[duration_ms]-0}
  if (( ms >= 2000 )); then
    if (( ms < 60000 )); then
      tenths=$(( (ms + 50) / 100 ))
      whole=$(( tenths / 10 ))
      frac=$(( tenths % 10 ))
      piece="[${whole}.${frac}s]"
    else
      secs=$(( ms / 1000 ))
      mins=$(( secs / 60 ))
      rem=$(( secs % 60 ))
      printf -v piece '[%dm%02ds]' mins rem
    fi
    nbsp_prompt_quote "$piece"
    duration=" %F{yellow}${REPLY}%f"
  fi

  if (( NBSP_DATA[jobs]-0 > 0 )); then
    nbsp_prompt_quote "[jobs:${NBSP_DATA[jobs]}]"
    jobs=" %F{yellow}${REPLY}%f"
  fi

  # %# is % for you and # for root. Failures keep the exact exit status in red.
  if (( NBSP_DATA[status]-0 == 0 )); then
    end=' %# '
  else
    end="%F{red}e${NBSP_DATA[status]}%#%f "
  fi

  # Full ownership of PROMPT (no splicing). Add titles/OSC wrappers here if needed.
  PROMPT="${path}${git}${node}${duration}${jobs}${end}"
}

# Rebuild after every successful data frame (precmd and post-refresh).
nbsp_data_update_functions+=(nbsp_opinionated_prompt)
# Soft fallback may set PROMPT only when this flag is set (not for detached).
typeset -g _NBSP_OWNS_PROMPT=1

# First paint before the first prompt: load facts, then the callback runs.
if ! _nbsp_load_data && [[ -z ${NBSP_DATA[path]-} ]]; then
  PROMPT='> '
fi

fi

Segments

Segment When it appears
Path Always after a successful data frame
Git Repository found and a branch label exists
Node NVM_BIN yields a valid label
Duration Previous command ≥ 2 seconds
Jobs Background jobs > 0
Failure Nonzero exit status
Marker Meaning
+ Staged
~ Worktree
? Untracked
! Conflicted
^ Ahead
v Behind
* Stashes

Counters only when git_valid is 1; otherwise the branch shows with ....

Fixed presentation

Colors, markers, the two-second duration threshold, and %# are fixed. The layout assumes promptpercent so %F / %# expand. Use detached mode for a different design.

PATH and _NBSP_BIN

export PATH="$HOME/.local/bin:$PATH"
eval "$(nbsp init zsh --autosuggest)"

PATH must find nbsp for init. The generated script pins _NBSP_BIN so hooks keep working if PATH changes later. Re-run init after moving the install.

Shared shell behavior

Opinionated and detached share timing, jobs, async Git refresh, redraw, and the Alt+E editor widget. The first prompt mode initialized in a shell wins.