Compare commits

..
Author SHA1 Message Date
Jonny Barnes
7b40ed544c
Trying out a new font 2026-04-01 21:18:23 +01:00
Jonny Barnes
f9e4c65001
Add claude statusline to my dotfiles 2026-03-28 16:51:14 +00:00
Jonny Barnes
2d18961ebc
Stay in tmux of there are other windows when quitting 2026-03-28 16:50:34 +00:00
4 changed files with 166 additions and 8 deletions

View file

@ -41,6 +41,10 @@ test -L $HOME/.config/nvim/init.lua || ln -f -s $BASEDIR/neovim/init.lua $HOME/.
test -d $HOME/.config/nvim/lsp || mkdir -p $HOME/.config/nvim/lsp test -d $HOME/.config/nvim/lsp || mkdir -p $HOME/.config/nvim/lsp
test -L $HOME/.config/nvim/lsp/phpactor.lua || ln -f -s $BASEDIR/neovim/lsp/phpactor.lua $HOME/.config/nvim/lsp/phpactor.lua test -L $HOME/.config/nvim/lsp/phpactor.lua || ln -f -s $BASEDIR/neovim/lsp/phpactor.lua $HOME/.config/nvim/lsp/phpactor.lua
# Claude Code statusline
test -d $HOME/.claude || mkdir $HOME/.claude
test -L $HOME/.claude/statusline.sh || ln -f -s $BASEDIR/claude/statusline.sh $HOME/.claude/statusline.sh
# .gitconfig gets edited by .extra so we won't symlink it, but copy it # .gitconfig gets edited by .extra so we won't symlink it, but copy it
echo "For compatibility we shall copy the global gitconfig" echo "For compatibility we shall copy the global gitconfig"
cp $BASEDIR/gitconfig $HOME/.gitconfig cp $BASEDIR/gitconfig $HOME/.gitconfig

150
claude/statusline.sh Executable file
View file

@ -0,0 +1,150 @@
#!/bin/bash
# Status line command for Claude Code
# Two-line display:
# Line 1: [Opus 4.6] 📁 project-name | 🌿 branch
# Line 2: █████░░░░░ 42% | 19.8k tok | ✅ Max | ⏱️ 7m 3s (API thinking time, not wall-clock)
# Read JSON input from Claude Code
input=$(cat)
# Debug mode: set CLAUDE_STATUSLINE_DEBUG=1 to dump JSON input
if [ -n "$CLAUDE_STATUSLINE_DEBUG" ]; then
echo "$input" | jq '.' > /tmp/claude-statusline-debug.json 2>/dev/null
fi
# Extract data from JSON (single jq call for performance)
eval "$(echo "$input" | jq -r '
@sh "cwd=\(.workspace.current_dir)",
@sh "model_display=\(.model.display_name)",
@sh "model_id=\(.model.id)",
@sh "used_pct_raw=\(.context_window.used_percentage // 0)",
@sh "total_input=\(.context_window.total_input_tokens // 0)",
@sh "total_output=\(.context_window.total_output_tokens // 0)",
@sh "duration_ms=\(.cost.total_api_duration_ms // 0)",
@sh "total_cost=\(.cost.total_cost_usd // 0)"
')"
dir_name=$(basename "$cwd")
# Truncate percentage to integer
used_pct=${used_pct_raw%%.*}
: "${used_pct:=0}"
# Use display_name directly — it already includes the version (e.g. "Opus 4.6")
# Only extract from model_id as fallback if display_name has no version
if [[ "$model_display" =~ [0-9] ]]; then
model_full="$model_display"
else
version=""
if [[ "$model_id" =~ claude-[a-z]+-([0-9]+)-([0-9]+) ]]; then
version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
fi
if [ -n "$version" ]; then
model_full="$model_display $version"
else
model_full="$model_display"
fi
fi
# Git branch with caching (5 second TTL)
git_branch=""
cache_dir="/tmp/claude-statusline"
cache_file="${cache_dir}/git-branch-$(echo "$cwd" | md5 -q)"
cache_ttl=5
if git -C "$cwd" rev-parse --git-dir > /dev/null 2>&1; then
now=$(date +%s)
file_mtime=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null || echo 0)
cache_age=$((now - file_mtime))
if [ -f "$cache_file" ] && [ "$cache_age" -lt "$cache_ttl" ]; then
git_branch=$(cat "$cache_file")
else
git_branch=$(git -C "$cwd" branch --show-current 2>/dev/null || echo 'detached')
mkdir -p "$cache_dir" && echo "$git_branch" > "$cache_file"
fi
fi
# Format tokens (pure bash integer math)
total_tokens=$(( ${total_input%%.*} + ${total_output%%.*} ))
if [ "$total_tokens" -ge 1000000 ]; then
whole=$((total_tokens / 1000000))
frac=$(( (total_tokens % 1000000) / 100000 ))
token_display="${whole}.${frac}M tok"
elif [ "$total_tokens" -ge 1000 ]; then
whole=$((total_tokens / 1000))
frac=$(( (total_tokens % 1000) / 100 ))
if [ "$whole" -ge 100 ]; then
token_display="${whole}k tok"
else
token_display="${whole}.${frac}k tok"
fi
else
token_display="${total_tokens} tok"
fi
# Billing mode detection (cached 60s)
billing_cache="/tmp/.claude-statusline-billing-cache"
billing_ttl=60
billing_mode=""
now_bill=$(date +%s)
bill_mtime=$(stat -c %Y "$billing_cache" 2>/dev/null || stat -f %m "$billing_cache" 2>/dev/null || echo 0)
bill_age=$((now_bill - bill_mtime))
if [ -f "$billing_cache" ] && [ "$bill_age" -lt "$billing_ttl" ]; then
billing_mode=$(cat "$billing_cache")
else
if security find-generic-password -s "Claude Code-credentials" >/dev/null 2>&1; then
billing_mode="max"
elif [ -n "$ANTHROPIC_API_KEY" ]; then
billing_mode="api"
else
billing_mode="unknown"
fi
echo "$billing_mode" > "$billing_cache"
fi
if [ "$billing_mode" = "max" ]; then
billing_display='\e[32m✅ Max\e[0m'
elif [ "$billing_mode" = "api" ]; then
billing_display='\e[1;31m⚠ API\e[0m'
else
billing_display='\e[33m? Auth\e[0m'
fi
# Format cost
cost_display=$(printf '$%.2f' "$total_cost")
# Format duration from milliseconds
duration_sec=$((${duration_ms%%.*} / 1000))
duration_min=$((duration_sec / 60))
duration_rem=$((duration_sec % 60))
# Build progress bar (10 chars wide)
filled=$((used_pct * 10 / 100))
empty=$((10 - filled))
# Color-code based on usage
if [ "$used_pct" -lt 70 ]; then
bar_color='\e[32m' # Green
elif [ "$used_pct" -lt 90 ]; then
bar_color='\e[33m' # Yellow
else
bar_color='\e[31m' # Red
fi
bar=""
for ((i=0; i<filled; i++)); do bar="${bar}"; done
for ((i=0; i<empty; i++)); do bar="${bar}"; done
# Line 1: [Opus 4.6] 📁 project-name | 🌿 branch
printf '\e[36m[%s]\e[0m 📁 %s' "$model_full" "$dir_name"
if [ -n "$git_branch" ]; then
printf ' \e[2m|\e[0m 🌿 %s' "$git_branch"
fi
printf '\n'
# Line 2: █████░░░░░ 42% | 19.8k tok | $1.23 | ✅ Max | ⏱️ 7m 3s
printf '%b%s\e[0m %d%% \e[2m|\e[0m \e[36m%s\e[0m \e[2m|\e[0m \e[33m%s\e[0m \e[2m|\e[0m %b \e[2m|\e[0m ⏱️ %dm %ds' \
"$bar_color" "$bar" "$used_pct" "$token_display" "$cost_display" "$billing_display" "$duration_min" "$duration_rem"

View file

@ -6,7 +6,7 @@ command = zsh
# Font configuration # Font configuration
font-size = 18 font-size = 18
font-family = MonaspiceKr NFM ont-family = Hack Nerd Font Mono
font-thicken = true font-thicken = true
# Set the theme # Set the theme

18
tmux
View file

@ -1,6 +1,6 @@
# remap prefix from 'C-b' to 'C-a' # add C-a as primary prefix, keep C-b as secondary
unbind C-b
set-option -g prefix C-a set-option -g prefix C-a
set-option -g prefix2 C-b
bind-key C-a send-prefix bind-key C-a send-prefix
# start with window 1 (instead of 0) # start with window 1 (instead of 0)
@ -11,6 +11,9 @@ setw -g pane-base-index 1
# renumber windows sequentially after closing any of them # renumber windows sequentially after closing any of them
set -g renumber-windows on set -g renumber-windows on
# don't detach when closing a window if other windows remain
set -g detach-on-destroy off
# reload config file (change file location to your the tmux.conf you want to use) # reload config file (change file location to your the tmux.conf you want to use)
unbind r unbind r
bind r source-file ~/.tmux.conf bind r source-file ~/.tmux.conf
@ -18,17 +21,18 @@ bind r source-file ~/.tmux.conf
# Enable mouse mode (tmux 2.1 and above) # Enable mouse mode (tmux 2.1 and above)
set -g mouse on set -g mouse on
# Track focus events
#set-option -g focus-events on
# don't rename windows automatically # don't rename windows automatically
set-option -g allow-rename off set-option -g allow-rename off
# Set terminal
set -g default-terminal "$TERM"
# Allow OSC 8 links # Allow OSC 8 links
set -ga terminal-features "*:hyperlinks" set -ga terminal-features "*:hyperlinks"
# Get 256 colour support
set -g default-terminal "screen-256color"
# tell Tmux that outside terminal supports true color
set -as terminal-features ",xterm-256color:RGB"
# Tweak status bar styles # Tweak status bar styles
set -g status-style bg=default,fg='#fdfdd9' set -g status-style bg=default,fg='#fdfdd9'