Auto-sync from catchthesethighs
This commit is contained in:
81
CHANGELOG.md
81
CHANGELOG.md
@@ -5,6 +5,64 @@ All notable changes to this dotfiles project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.0] - 2025-12-16
|
||||
|
||||
### Added
|
||||
|
||||
#### Shell Startup Optimization
|
||||
- **Deferred Loading** - Heavy plugins and functions load after first prompt displays
|
||||
- **Cached Command Checks** - `_has_cmd()` function caches `command -v` results for faster lookups
|
||||
- **Lazy kubectl** - kubectl completions only load when first used (saves ~200-500ms)
|
||||
- **Background Tasks** - Dotfiles sync check runs fully async with `&!`
|
||||
- **Compile Script** (`dotfiles-compile.sh`) - Pre-compile zsh files to `.zwc` bytecode for 20-50ms speedup
|
||||
|
||||
#### Smart Path Resolution
|
||||
- **`_df_run()` Helper** - All aliases use full path with fallback to PATH
|
||||
- Fixes "command not found" errors on fresh installs
|
||||
- Scripts work even before symlinks are created or PATH is set
|
||||
|
||||
#### New Aliases
|
||||
- `dfcompile` - Compile zsh files for faster startup
|
||||
- `dfcd` - Navigate to dotfiles directory (replaces `df` to avoid disk utility conflict)
|
||||
|
||||
### Changed
|
||||
|
||||
#### Script Reorganization
|
||||
- Renamed `bin/shell-stats.sh` → `bin/dotfiles-stats.sh`
|
||||
- Renamed `bin/vault.sh` → `bin/dotfiles-vault.sh`
|
||||
- Renamed `bin/update-dotfiles.sh` → `bin/dotfiles-update.sh`
|
||||
- Moved `bin/setup-wizard.sh` → `setup/setup-wizard.sh`
|
||||
- Moved `bin/setup-espanso.sh` → `setup/setup-espanso.sh`
|
||||
- Removed deprecated `bin/deploy-zshtheme-systemwide.sh`
|
||||
|
||||
#### Alias System Overhaul
|
||||
- All command aliases now use `_df_run()` function wrapper
|
||||
- Uses full path `$_df_dir/bin/script.sh` with fallback to PATH lookup
|
||||
- Better error messages when scripts not found
|
||||
- Removed `df` alias (conflicts with disk free utility)
|
||||
|
||||
#### .zshrc Optimizations
|
||||
- Reduced default plugins (removed `docker`, `docker-compose`, `kubectl` from immediate load)
|
||||
- Disabled oh-my-zsh auto-update check on every load (`DISABLE_AUTO_UPDATE="true"`)
|
||||
- Tool aliases (eza, bat) now set up in deferred loading
|
||||
- FZF configuration deferred until after prompt
|
||||
- Vault secrets loaded with full path to avoid command_not_found issues
|
||||
- Background sync check uses full script path
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Fresh Install Bug** - "Command not found: dotfiles-sync.sh" error on new user accounts
|
||||
- **Path Resolution** - Scripts now work before `~/.local/bin` is in PATH
|
||||
- **Smart Suggest Conflicts** - Background tasks no longer trigger `command_not_found_handler`
|
||||
|
||||
### Removed
|
||||
|
||||
- `df` alias (conflicted with `df` disk utility)
|
||||
- Heavy plugins from default load (now lazy-loaded)
|
||||
- `bin/deploy-zshtheme-systemwide.sh` (redundant with installer)
|
||||
|
||||
---
|
||||
|
||||
## [1.0.0] - 2025-12-15
|
||||
|
||||
### Added
|
||||
@@ -14,8 +72,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- **Dynamic MOTD** (`motd.zsh`) - Compact system info on shell start (uptime, CPU, memory, docker, git status)
|
||||
- **Command Palette** (`command-palette.zsh`) - Raycast-style fuzzy launcher triggered by Ctrl+Space or Ctrl+P
|
||||
- **Smart Suggestions** (`smart-suggest.zsh`) - Typo correction for 100+ common mistakes + alias recommendations
|
||||
- **Shell Analytics** (`shell-stats.sh`) - Dashboard showing command usage, suggestions, and activity heatmap
|
||||
- **Secrets Vault** (`vault.sh`) - Encrypted storage for API keys using age/gpg
|
||||
- **Shell Analytics** (`dotfiles-stats.sh`) - Dashboard showing command usage, suggestions, and activity heatmap
|
||||
- **Secrets Vault** (`dotfiles-vault.sh`) - Encrypted storage for API keys using age/gpg
|
||||
- **Password Manager Integration** (`password-manager.zsh`) - Unified CLI for 1Password, LastPass, Bitwarden
|
||||
- **Dotfiles Sync** (`dotfiles-sync.sh`) - Multi-machine synchronization with watch mode
|
||||
- **Dotfiles Doctor** (`dotfiles-doctor.sh`) - Health checker with auto-fix capability
|
||||
@@ -86,35 +144,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Checking Your Version
|
||||
|
||||
```bash
|
||||
dfv
|
||||
# or
|
||||
dotfiles-version.sh
|
||||
```
|
||||
|
||||
### Updating
|
||||
|
||||
```bash
|
||||
cd ~/.dotfiles
|
||||
git pull origin main
|
||||
./install.sh --skip-deps
|
||||
```
|
||||
|
||||
Or use:
|
||||
|
||||
```bash
|
||||
update-dotfiles.sh
|
||||
dfu
|
||||
# or
|
||||
dotfiles-update.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Planned for 1.1.0
|
||||
### Planned for 1.2.0
|
||||
- [ ] Multiple theme support with live preview
|
||||
- [ ] Project scaffolding templates
|
||||
- [ ] SSH key generation helper
|
||||
- [ ] Machine profiles (work, personal, server)
|
||||
|
||||
### Planned for 1.2.0
|
||||
- [ ] Dynamic MOTD/welcome screen
|
||||
### Planned for 1.3.0
|
||||
- [ ] Remote machine bootstrap script
|
||||
- [ ] Neovim configuration support
|
||||
|
||||
|
||||
@@ -357,9 +357,11 @@ All dotfiles commands have convenient aliases:
|
||||
| `dfu` | `dotfiles-update.sh` | Update dotfiles |
|
||||
| `dfv` | `dotfiles-version.sh` | Version info |
|
||||
| `dfstats` | `dotfiles-stats.sh` | Shell analytics |
|
||||
| `dfcompile` | `dotfiles-compile.sh` | Compile zsh for speed |
|
||||
| `vault` | `dotfiles-vault.sh` | Secrets manager |
|
||||
| `reload` | `source ~/.zshrc` | Reload shell |
|
||||
| `dfc` | `dotfiles-cli` | CLI with subcommands |
|
||||
| `dotfiles` | `cd ~/.dotfiles` | Go to dotfiles dir |
|
||||
|
||||
## 🗑️ Uninstalling
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ All dotfiles commands have convenient aliases defined in `~/.dotfiles/zsh/aliase
|
||||
|
||||
| Alias | Full Command | Description |
|
||||
|-------|--------------|-------------|
|
||||
| `dotfiles` / `df` | `cd ~/.dotfiles` | Go to dotfiles directory |
|
||||
| `dotfiles` / `dfcd` | `cd ~/.dotfiles` | Go to dotfiles directory |
|
||||
| `dfd` / `doctor` | `dotfiles-doctor.sh` | Run health check |
|
||||
| `dffix` | `dotfiles-doctor.sh --fix` | Auto-fix issues |
|
||||
| `dfs` / `dfsync` | `dotfiles-sync.sh` | Interactive sync |
|
||||
@@ -421,6 +421,7 @@ All dotfiles commands have convenient aliases defined in `~/.dotfiles/zsh/aliase
|
||||
| `dfstats` / `stats` | `dotfiles-stats.sh` | Shell analytics |
|
||||
| `tophist` | `dotfiles-stats.sh --top` | Top commands |
|
||||
| `suggest` | `dotfiles-stats.sh --suggest` | Alias suggestions |
|
||||
| `dfcompile` | `dotfiles-compile.sh` | Compile zsh for speed |
|
||||
|
||||
### Vault Commands
|
||||
|
||||
@@ -451,6 +452,7 @@ dfc update # Update dotfiles
|
||||
dfc version # Show version
|
||||
dfc stats # Shell analytics
|
||||
dfc vault # Secrets manager
|
||||
dfc compile # Compile zsh for speed
|
||||
dfc edit # Open in editor
|
||||
dfc cd # Go to dotfiles dir
|
||||
dfc help # Show help
|
||||
@@ -458,6 +460,61 @@ dfc help # Show help
|
||||
|
||||
---
|
||||
|
||||
## Shell Optimization
|
||||
|
||||
The `.zshrc` is optimized for fast startup while maintaining full functionality.
|
||||
|
||||
### Measuring Startup Time
|
||||
|
||||
```bash
|
||||
# Quick measurement
|
||||
time zsh -i -c exit
|
||||
|
||||
# More accurate (requires hyperfine)
|
||||
hyperfine 'zsh -i -c exit'
|
||||
```
|
||||
|
||||
### Compile Zsh Files
|
||||
|
||||
Pre-compile `.zsh` files to bytecode for 20-50ms speedup:
|
||||
|
||||
```bash
|
||||
dfcompile # Compile all zsh files
|
||||
dfcompile --clean # Remove compiled files
|
||||
```
|
||||
|
||||
### Loading Strategy
|
||||
|
||||
| Phase | What Loads | Timing |
|
||||
|-------|------------|--------|
|
||||
| **Immediate** | PATH, history, oh-my-zsh, basic aliases, keybindings | Blocks prompt |
|
||||
| **Deferred** | Tool aliases (eza, bat), FZF, smart-suggest, snapper, vault | After first prompt |
|
||||
| **Background** | Dotfiles sync check | Fully async |
|
||||
| **Lazy** | NVM, kubectl, virtualenvwrapper | When first used |
|
||||
|
||||
### Profiling
|
||||
|
||||
To debug slow startup, edit `~/.zshrc`:
|
||||
|
||||
```zsh
|
||||
# Uncomment at the TOP of file:
|
||||
zmodload zsh/zprof
|
||||
|
||||
# Uncomment at the BOTTOM of file:
|
||||
zprof
|
||||
```
|
||||
|
||||
Then run `zsh -i -c exit` to see timing breakdown.
|
||||
|
||||
### Tips for Fast Startup
|
||||
|
||||
1. **Run `dfcompile`** after installation
|
||||
2. **Avoid adding** `command -v` checks in `.zshrc` (use `_has_cmd` cache instead)
|
||||
3. **Use lazy loading** for heavy tools (NVM, kubectl already lazy-loaded)
|
||||
4. **Keep `.zshrc.local`** minimal
|
||||
|
||||
---
|
||||
|
||||
## Customization
|
||||
|
||||
### Adding Aliases
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# ============================================================================
|
||||
|
||||
# --- Version ---
|
||||
DOTFILES_VERSION="1.0.0"
|
||||
DOTFILES_VERSION="1.1.0"
|
||||
|
||||
# --- GitHub Settings ---
|
||||
DOTFILES_GITHUB_USER="adlee-was-taken"
|
||||
|
||||
29
install.sh
29
install.sh
@@ -26,6 +26,7 @@ SKIP_DEPS=false
|
||||
DEPS_ONLY=false
|
||||
UNINSTALL=false
|
||||
UNINSTALL_PURGE=false
|
||||
RUN_WIZARD=false
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
@@ -41,10 +42,14 @@ for arg in "$@"; do
|
||||
--purge)
|
||||
UNINSTALL_PURGE=true
|
||||
;;
|
||||
--wizard)
|
||||
RUN_WIZARD=true
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " --wizard Run interactive setup wizard (recommended)"
|
||||
echo " --skip-deps Skip dependency installation (useful for re-runs)"
|
||||
echo " --deps-only Only install dependencies, then exit"
|
||||
echo " --uninstall Remove symlinks and restore backups"
|
||||
@@ -57,6 +62,7 @@ for arg in "$@"; do
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " ./install.sh # Full install"
|
||||
echo " ./install.sh --wizard # Interactive wizard"
|
||||
echo " ./install.sh --skip-deps # Re-run without checking deps"
|
||||
echo " ./install.sh --uninstall # Remove symlinks"
|
||||
echo " ./install.sh --uninstall --purge # Remove everything"
|
||||
@@ -800,6 +806,28 @@ main() {
|
||||
do_uninstall
|
||||
fi
|
||||
|
||||
# Handle wizard mode
|
||||
if [[ "$RUN_WIZARD" == true ]]; then
|
||||
load_config
|
||||
local wizard_script="$DOTFILES_DIR/setup/setup-wizard.sh"
|
||||
|
||||
# If dotfiles not yet cloned, clone first
|
||||
if [[ ! -f "$wizard_script" ]]; then
|
||||
detect_os
|
||||
install_dependencies
|
||||
clone_or_update_dotfiles
|
||||
load_config
|
||||
wizard_script="$DOTFILES_DIR/setup/setup-wizard.sh"
|
||||
fi
|
||||
|
||||
if [[ -f "$wizard_script" ]]; then
|
||||
exec bash "$wizard_script"
|
||||
else
|
||||
print_error "Wizard script not found: $wizard_script"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
print_header
|
||||
|
||||
detect_os
|
||||
@@ -844,6 +872,7 @@ main() {
|
||||
echo " dfs / dfsync - Sync dotfiles"
|
||||
echo " dfu / dfupdate - Update dotfiles"
|
||||
echo " dfstats / stats - Shell analytics"
|
||||
echo " dfcompile - Compile zsh for speed"
|
||||
echo " vault - Secrets manager"
|
||||
echo
|
||||
echo -e "${BLUE}To uninstall:${NC}"
|
||||
|
||||
@@ -25,39 +25,45 @@ _df_run() {
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Core Dotfiles Commands ---
|
||||
alias dotfiles='cd ~/.dotfiles'
|
||||
alias dfcd='cd ~/.dotfiles'
|
||||
# Note: 'df' not aliased to avoid conflict with disk free utility
|
||||
|
||||
# Doctor - health check
|
||||
function dfd() { _df_run dotfiles-doctor.sh "$@"; }
|
||||
function doctor() { _df_run dotfiles-doctor.sh "$@"; }
|
||||
function dffix() { _df_run dotfiles-doctor.sh --fix "$@"; }
|
||||
dfd() { _df_run dotfiles-doctor.sh "$@"; }
|
||||
doctor() { _df_run dotfiles-doctor.sh "$@"; }
|
||||
dffix() { _df_run dotfiles-doctor.sh --fix "$@"; }
|
||||
|
||||
# Sync - multi-machine synchronization
|
||||
function dfs() { _df_run dotfiles-sync.sh "$@"; }
|
||||
function dfsync() { _df_run dotfiles-sync.sh "$@"; }
|
||||
function dfpush() { _df_run dotfiles-sync.sh --push "$@"; }
|
||||
function dfpull() { _df_run dotfiles-sync.sh --pull "$@"; }
|
||||
function dfstatus() { _df_run dotfiles-sync.sh --status "$@"; }
|
||||
dfs() { _df_run dotfiles-sync.sh "$@"; }
|
||||
dfsync() { _df_run dotfiles-sync.sh "$@"; }
|
||||
dfpush() { _df_run dotfiles-sync.sh --push "$@"; }
|
||||
dfpull() { _df_run dotfiles-sync.sh --pull "$@"; }
|
||||
dfstatus() { _df_run dotfiles-sync.sh --status "$@"; }
|
||||
|
||||
# Update - pull latest and reinstall
|
||||
function dfu() { _df_run dotfiles-update.sh "$@"; }
|
||||
function dfupdate() { _df_run dotfiles-update.sh "$@"; }
|
||||
dfu() { _df_run dotfiles-update.sh "$@"; }
|
||||
dfupdate() { _df_run dotfiles-update.sh "$@"; }
|
||||
|
||||
# Version - check version info
|
||||
function dfv() { _df_run dotfiles-version.sh "$@"; }
|
||||
function dfversion() { _df_run dotfiles-version.sh "$@"; }
|
||||
dfv() { _df_run dotfiles-version.sh "$@"; }
|
||||
dfversion() { _df_run dotfiles-version.sh "$@"; }
|
||||
|
||||
# Stats - shell analytics
|
||||
function dfstats() { _df_run dotfiles-stats.sh "$@"; }
|
||||
function tophist() { _df_run dotfiles-stats.sh --top "$@"; }
|
||||
function suggest() { _df_run dotfiles-stats.sh --suggest "$@"; }
|
||||
dfstats() { _df_run dotfiles-stats.sh "$@"; }
|
||||
stats() { _df_run dotfiles-stats.sh "$@"; }
|
||||
tophist() { _df_run dotfiles-stats.sh --top "$@"; }
|
||||
suggest() { _df_run dotfiles-stats.sh --suggest "$@"; }
|
||||
|
||||
# Vault - secrets management
|
||||
function vault() { _df_run dotfiles-vault.sh "$@"; }
|
||||
function vls() { _df_run dotfiles-vault.sh list "$@"; }
|
||||
function vget() { _df_run dotfiles-vault.sh get "$@"; }
|
||||
function vset() { _df_run dotfiles-vault.sh set "$@"; }
|
||||
vault() { _df_run dotfiles-vault.sh "$@"; }
|
||||
vls() { _df_run dotfiles-vault.sh list "$@"; }
|
||||
vget() { _df_run dotfiles-vault.sh get "$@"; }
|
||||
vset() { _df_run dotfiles-vault.sh set "$@"; }
|
||||
|
||||
# Compile - compile zsh files for speed
|
||||
function dfcompile() { _df_run dotfiles-compile.sh "$@"; }
|
||||
dfcompile() { _df_run dotfiles-compile.sh "$@"; }
|
||||
|
||||
# --- Quick Edit Aliases ---
|
||||
alias zshrc='${EDITOR:-vim} ~/.zshrc'
|
||||
|
||||
@@ -127,10 +127,11 @@ _palette_get_actions() {
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_EDIT" "action" "Edit .zshrc" "${EDITOR:-vim} ~/.zshrc"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_EDIT" "action" "Edit dotfiles.conf" "${EDITOR:-vim} $DOTFILES_DIR/dotfiles.conf"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_EDIT" "action" "Edit theme" "${EDITOR:-vim} $DOTFILES_DIR/zsh/themes/adlee.zsh-theme"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Dotfiles doctor" "dotfiles-doctor.sh"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Dotfiles sync" "dotfiles-sync.sh"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Shell stats" "shell-stats.sh"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Vault list" "vault.sh list"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Dotfiles doctor" "dfd"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Dotfiles sync" "dfs"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Shell stats" "dfstats"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Compile zsh" "dfcompile"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Vault list" "vault list"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_ACTION" "action" "Clear screen" "clear"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "action" "Home" "cd ~"
|
||||
printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "action" "Dotfiles" "cd $DOTFILES_DIR"
|
||||
|
||||
@@ -1,102 +1,157 @@
|
||||
#!/usr/bin/env zsh
|
||||
# ============================================================================
|
||||
# MOTD — Width-Safe, Color-Safe, Reload-Safe
|
||||
# MOTD (Message of the Day) - Dynamic System Info
|
||||
# ============================================================================
|
||||
# Displays system information on shell startup
|
||||
#
|
||||
# Functions:
|
||||
# show_motd - Compact box format
|
||||
# show_motd_mini - Single line format
|
||||
# ============================================================================
|
||||
|
||||
# ---------------------------- Guards -----------------------------------------
|
||||
# Only run in interactive shells
|
||||
[[ -o interactive ]] || return 0
|
||||
|
||||
[[ -o interactive ]] || return
|
||||
[[ -n $__MOTD_SHOWN ]] && return
|
||||
typeset -g __MOTD_SHOWN=1
|
||||
# ============================================================================
|
||||
# Colors (ANSI escape codes)
|
||||
# ============================================================================
|
||||
|
||||
# ---------------------------- Configuration ----------------------------------
|
||||
_M_RESET=$'\033[0m'
|
||||
_M_BOLD=$'\033[1m'
|
||||
_M_DIM=$'\033[2m'
|
||||
_M_BLUE=$'\033[38;5;39m'
|
||||
_M_CYAN=$'\033[38;5;51m'
|
||||
_M_GREEN=$'\033[38;5;82m'
|
||||
_M_YELLOW=$'\033[38;5;220m'
|
||||
_M_GREY=$'\033[38;5;242m'
|
||||
|
||||
BOX_WIDTH=78 # total width INCLUDING borders
|
||||
INNER_WIDTH=$(( BOX_WIDTH - 2 ))
|
||||
LABEL_WIDTH=12
|
||||
# ============================================================================
|
||||
# Info Gathering
|
||||
# ============================================================================
|
||||
|
||||
# ---------------------------- Colors -----------------------------------------
|
||||
|
||||
autoload -Uz colors && colors
|
||||
|
||||
C_DIM="%F{242}"
|
||||
C_HEAD="%B%F{39}"
|
||||
C_LABEL="%F{51}"
|
||||
C_OK="%F{82}"
|
||||
C_RESET="%f%b"
|
||||
|
||||
# ---------------------------- Low-level helpers ------------------------------
|
||||
|
||||
repeat_char() {
|
||||
local ch="$1" n="$2"
|
||||
printf '%*s' "$n" '' | tr ' ' "$ch"
|
||||
_motd_uptime() {
|
||||
local up=$(uptime 2>/dev/null)
|
||||
if [[ "$up" =~ "up "([^,]+) ]]; then
|
||||
echo "${match[1]}" | sed 's/^ *//'
|
||||
else
|
||||
echo "?"
|
||||
fi
|
||||
}
|
||||
|
||||
pad_right() {
|
||||
local s="$1" w="$2"
|
||||
printf '%-*s' "$w" "$s"
|
||||
_motd_load() {
|
||||
if [[ -f /proc/loadavg ]]; then
|
||||
awk '{print $1}' /proc/loadavg
|
||||
else
|
||||
uptime | awk -F'load average:' '{print $2}' | awk -F, '{print $1}' | xargs
|
||||
fi
|
||||
}
|
||||
|
||||
center_text() {
|
||||
local s="$1" w="$2"
|
||||
local len=${#s}
|
||||
(( len >= w )) && { print "${s[1,w]}"; return }
|
||||
local pad=$(( (w - len) / 2 ))
|
||||
printf '%*s%s%*s' "$pad" '' "$s" "$(( w - len - pad ))" ''
|
||||
_motd_mem() {
|
||||
free -h 2>/dev/null | awk '/^Mem:/ {print $3 "/" $2}' || echo "N/A"
|
||||
}
|
||||
|
||||
# ---------------------------- Box primitives ---------------------------------
|
||||
|
||||
box_top() {
|
||||
print "${C_DIM}┌$(repeat_char '─' $INNER_WIDTH)┐${C_RESET}"
|
||||
_motd_disk() {
|
||||
df -h / 2>/dev/null | awk 'NR==2 {print $4 " free"}' || echo "N/A"
|
||||
}
|
||||
|
||||
box_bottom() {
|
||||
print "${C_DIM}└$(repeat_char '─' $INNER_WIDTH)┘${C_RESET}"
|
||||
# ============================================================================
|
||||
# Box Drawing - Fixed Width
|
||||
# ============================================================================
|
||||
|
||||
# Fixed box width
|
||||
_M_WIDTH=62
|
||||
|
||||
_motd_line() {
|
||||
local char="$1"
|
||||
local i
|
||||
local line=""
|
||||
for ((i=0; i<_M_WIDTH; i++)); do
|
||||
line+="$char"
|
||||
done
|
||||
echo "$line"
|
||||
}
|
||||
|
||||
box_blank() {
|
||||
print "${C_DIM}│$(repeat_char ' ' $INNER_WIDTH)│${C_RESET}"
|
||||
_motd_pad() {
|
||||
# Pad a plain string to exact width
|
||||
local str="$1"
|
||||
local width="$2"
|
||||
local len=${#str}
|
||||
if (( len >= width )); then
|
||||
echo "${str:0:$width}"
|
||||
else
|
||||
printf "%-${width}s" "$str"
|
||||
fi
|
||||
}
|
||||
|
||||
box_line() {
|
||||
local content="$1"
|
||||
content="$(pad_right "$content" "$INNER_WIDTH")"
|
||||
print "${C_DIM}│${C_RESET}${content}${C_DIM}│${C_RESET}"
|
||||
# ============================================================================
|
||||
# Main Display Function
|
||||
# ============================================================================
|
||||
|
||||
show_motd() {
|
||||
[[ -n "$_MOTD_SHOWN" && "$1" != "--force" ]] && return 0
|
||||
typeset -g _MOTD_SHOWN=1
|
||||
|
||||
local hostname="${HOST:-$(hostname -s 2>/dev/null)}"
|
||||
local datetime=$(date '+%a %b %d %H:%M')
|
||||
local uptime=$(_motd_uptime)
|
||||
local load=$(_motd_load)
|
||||
local mem=$(_motd_mem)
|
||||
local disk=$(_motd_disk)
|
||||
|
||||
local hline=$(_motd_line '─')
|
||||
local inner=$((_M_WIDTH - 2))
|
||||
|
||||
echo ""
|
||||
|
||||
# Top border
|
||||
echo "${_M_GREY}┌${hline}┐${_M_RESET}"
|
||||
|
||||
# Header: hostname + datetime
|
||||
local h_left="✦ ${hostname}"
|
||||
local h_right="${datetime}"
|
||||
local h_pad=$((inner - ${#h_left} - ${#h_right}))
|
||||
local h_spaces=""
|
||||
for ((i=0; i<h_pad; i++)); do h_spaces+=" "; done
|
||||
echo "${_M_GREY}│${_M_RESET} ${_M_BOLD}${_M_BLUE}✦${_M_RESET} ${_M_BOLD}${hostname}${_M_RESET}${h_spaces}${_M_DIM}${datetime}${_M_RESET} ${_M_GREY}│${_M_RESET}"
|
||||
|
||||
# Separator
|
||||
echo "${_M_GREY}├${hline}┤${_M_RESET}"
|
||||
|
||||
# Stats line - build with exact spacing
|
||||
local s1="▲up:${uptime}"
|
||||
local s2="◆load:${load}"
|
||||
local s3="◇mem:${mem}"
|
||||
local s4="⊡${disk}"
|
||||
local stats_content="${s1} ${s2} ${s3} ${s4}"
|
||||
local stats_pad=$((inner - ${#stats_content} - 1))
|
||||
local stats_spaces=""
|
||||
for ((i=0; i<stats_pad; i++)); do stats_spaces+=" "; done
|
||||
echo "${_M_GREY}│${_M_RESET} ${_M_DIM}▲${_M_RESET}up:${uptime} ${_M_DIM}◆${_M_RESET}load:${load} ${_M_DIM}◇${_M_RESET}mem:${mem} ${_M_DIM}⊡${_M_RESET}${disk}${stats_spaces}${_M_GREY} │${_M_RESET}"
|
||||
|
||||
# Bottom border
|
||||
echo "${_M_GREY}└${hline}┘${_M_RESET}"
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ---------------------------- Content builders -------------------------------
|
||||
# ============================================================================
|
||||
# Mini Format (Single Line)
|
||||
# ============================================================================
|
||||
|
||||
header_line() {
|
||||
local text="$1"
|
||||
box_line "$(center_text "$text" "$INNER_WIDTH")"
|
||||
show_motd_mini() {
|
||||
[[ -n "$_MOTD_SHOWN" && "$1" != "--force" ]] && return 0
|
||||
typeset -g _MOTD_SHOWN=1
|
||||
|
||||
local hostname="${HOST:-$(hostname -s 2>/dev/null)}"
|
||||
local uptime=$(_motd_uptime)
|
||||
local mem=$(_motd_mem)
|
||||
|
||||
echo "${_M_DIM}──${_M_RESET} ${_M_BOLD}${hostname}${_M_RESET} ${_M_DIM}│${_M_RESET} up:${uptime} ${_M_DIM}│${_M_RESET} mem:${mem} ${_M_DIM}──${_M_RESET}"
|
||||
}
|
||||
|
||||
row_line() {
|
||||
local label="$1" value="$2"
|
||||
local left="$(pad_right "$label" "$LABEL_WIDTH")"
|
||||
box_line " ${left} ${value}"
|
||||
}
|
||||
|
||||
# ---------------------------- Info providers ---------------------------------
|
||||
|
||||
get_os() { uname -sr }
|
||||
get_uptime() { uptime | sed 's/.*up *//' | cut -d',' -f1 }
|
||||
get_load() { uptime | awk -F'load average:' '{print $2}' | xargs }
|
||||
get_mem() { free -h | awk '/Mem:/ {print $3 "/" $2}' }
|
||||
get_disk() { df -h / | awk 'NR==2 {print $3 "/" $2 " (" $5 ")"}' }
|
||||
|
||||
# ---------------------------- Render -----------------------------------------
|
||||
|
||||
box_top
|
||||
header_line "${C_HEAD}$(hostname)${C_RESET} - ${C_DIM}$(get_os)${C_RESET}"
|
||||
box_blank
|
||||
row_line "${C_LABEL}Uptime${C_RESET}" "$(get_uptime)"
|
||||
row_line "${C_LABEL}Load${C_RESET}" "$(get_load)"
|
||||
row_line "${C_LABEL}Memory${C_RESET}" "$(get_mem)"
|
||||
row_line "${C_LABEL}Disk${C_RESET}" "$(get_disk)"
|
||||
box_blank
|
||||
box_line " ${C_OK}System up to date${C_RESET}"
|
||||
box_bottom
|
||||
print
|
||||
# ============================================================================
|
||||
# Aliases
|
||||
# ============================================================================
|
||||
|
||||
alias motd='show_motd --force'
|
||||
alias motd-mini='show_motd_mini --force'
|
||||
|
||||
Reference in New Issue
Block a user