diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d839827 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,68 @@ +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# .editorconfig — cross-editor formatting baseline +# ============================================================================= +# Supported by VS Code (EditorConfig extension), Vim, Neovim, Emacs, Sublime, +# WebStorm, and many others. Reference: https://editorconfig.org +# ============================================================================= + +# root = true + +# ---- Defaults for all files ------------------------------------------------ +# [*] +# charset = utf-8 +# end_of_line = lf +# indent_style = space +# indent_size = 2 +# trim_trailing_whitespace = true +# insert_final_newline = true + +# ---- JavaScript / TypeScript ----------------------------------------------- +# [*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}] +# indent_style = space +# indent_size = 2 + +# ---- JSON ------------------------------------------------------------------ +# [*.{json,jsonc,json5}] +# indent_style = space +# indent_size = 2 + +# ---- YAML ------------------------------------------------------------------ +# [*.{yml,yaml}] +# indent_style = space +# indent_size = 2 + +# ---- HTML / CSS / SCSS ----------------------------------------------------- +# [*.{html,css,scss,sass,less}] +# indent_style = space +# indent_size = 2 + +# ---- Markdown -------------------------------------------------------------- +# [*.{md,mdx}] +# trim_trailing_whitespace = false # trailing spaces are meaningful in Markdown +# indent_size = 2 + +# ---- Python (PEP 8 uses 4 spaces) ------------------------------------------ +# [*.py] +# indent_size = 4 + +# ---- Go (uses tabs) -------------------------------------------------------- +# [*.go] +# indent_style = tab + +# ---- Rust ------------------------------------------------------------------ +# [*.rs] +# indent_size = 4 + +# ---- Shell scripts --------------------------------------------------------- +# [*.{sh,bash,zsh}] +# indent_size = 2 + +# ---- Makefiles (require tabs) ---------------------------------------------- +# [Makefile] +# indent_style = tab + +# ---- Package lock files (auto-generated; don't reformat) ------------------ +# [{package-lock.json,yarn.lock,pnpm-lock.yaml}] +# indent_size = unset +# insert_final_newline = unset diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..62e92b8 --- /dev/null +++ b/.gitconfig @@ -0,0 +1,206 @@ +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# ~/.gitconfig — global Git configuration +# ============================================================================= +# This file is managed by dotfiles. Machine-specific overrides go in +# ~/.gitconfig.local (included at the bottom of this file). +# +# Run `git config --list --show-origin` to see the current resolved config. +# ============================================================================= + +[user] + # Set your name and email here — or override in ~/.gitconfig.local + # name = Your Name + # email = you@example.com + + # GPG signing (uncomment after setting up a key) + # signingkey = + +[core] + # Sensible cross-platform line ending handling + # autocrlf = input # convert CRLF → LF on commit; leave LF alone + # safecrlf = warn + # whitespace = fix,-indent-with-non-tab,trailing-space,cr-at-eol + + # Faster status/diff on large repos + # fsmonitor = true + # untrackedCache = true + + # Pager — plain less by default; delta below is much nicer + # pager = less -FRX + + # Editor for commit messages + # editor = code --wait + + # Global gitignore (path below is set by install.sh) + # excludesfile = ~/.gitignore_global + + # Avoid "dubious ownership" warnings when repo owner ≠ current user + # trustctime = false + +[init] + # defaultBranch = main + +[pull] + # rebase = false # merge by default; change to `true` or `ff-only` if preferred + +[push] + # default = current # push current branch to same-name remote branch + # autoSetupRemote = true # automatically set upstream on first push + +[fetch] + # prune = true # remove remote-tracking branches that no longer exist + +[merge] + # tool = vscode + # conflictstyle = zdiff3 # shows the common ancestor in conflict markers + +# [mergetool "vscode"] +# cmd = code --wait $MERGED + +[diff] + # tool = vscode + # algorithm = histogram # better diff for moved code + # colorMoved = default + +# [difftool "vscode"] +# cmd = code --wait --diff $LOCAL $REMOTE + +[rebase] + # autosquash = true # automatically apply fixup!/squash! prefixes + # autostash = true # stash/pop dirty working tree around rebase + # updateRefs = true # update intermediate refs when rebasing a stack + +[branch] + # sort = -committerdate # show most recently committed branches first + +[tag] + # sort = -version:refname # sort tags by version descending + +[status] + # showUntrackedFiles = all # show individual files in untracked dirs + +[log] + # date = relative + +[color] + # ui = auto + # branch = auto + # diff = auto + # status = auto + +# [color "branch"] +# current = yellow bold +# local = green bold +# remote = cyan bold + +# [color "diff"] +# meta = yellow bold +# frag = magenta bold +# old = red bold +# new = green bold +# whitespace = red reverse + +# [color "status"] +# added = green bold +# changed = yellow bold +# untracked = red bold + +[credential] + # helper = osxkeychain # macOS; change to `manager` on Windows, `store` on Linux + +# ============================================================================= +# ALIASES — git shortcuts +# ============================================================================= + +[alias] + # Basics + s = status -sb + a = add + aa = add --all + c = commit + cm = commit -m + ca = commit --amend + can = commit --amend --no-edit + + # Branches + co = checkout + sw = switch + swc = switch -c # create and switch + b = branch + ba = branch -a + bd = branch -d + + # Stash + st = stash + stp = stash pop + stl = stash list + + # Diff / log + d = diff + ds = diff --staged + dc = diff --cached + lg = log --oneline --graph --decorate --all + lgg = log --graph --pretty=format:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' + last = log -1 HEAD --stat + + # Remote + p = push + pf = push --force-with-lease + pu = pull + f = fetch --all --prune + + # Convenience + unstage = restore --staged + discard = restore + aliases = config --get-regexp alias + ignored = ls-files --others --ignored --exclude-standard + root = rev-parse --show-toplevel + + # Find the commit that introduced a string + find = log -S + # List contributors by commit count + contributors = shortlog -sn --no-merges + + # Undo last commit (keep changes staged) + uncommit = reset --soft HEAD~1 + + # Create a throwaway "wip" commit + wip = "!git add -A && git commit -m 'WIP'" + unwip = "!git log -n 1 | grep -q -c WIP && git reset HEAD~1" + + +# ============================================================================= +# DELTA — a better diff pager (https://github.com/dandavison/delta) +# ============================================================================= +# Install: brew install git-delta +# Uncomment the block below to enable it. +# +# [core] +# pager = delta +# +# [interactive] +# diffFilter = delta --color-only +# +# [delta] +# navigate = true # n/N to move between diff sections +# side-by-side = true +# line-numbers = true +# syntax-theme = Dracula +# +# [merge] +# conflictstyle = zdiff3 + + +# ============================================================================= +# GITHUB CLI / gh — https://cli.github.com +# ============================================================================= +# [url "git@github.com:"] +# insteadOf = https://github.com/ # use SSH for GitHub repos + + +# ============================================================================= +# LOCAL OVERRIDES — user.name, user.email, work configs, etc. +# ============================================================================= +[include] + path = ~/.gitconfig.local diff --git a/.gitignore_global b/.gitignore_global new file mode 100644 index 0000000..da16e83 --- /dev/null +++ b/.gitignore_global @@ -0,0 +1,164 @@ +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# ~/.gitignore_global — patterns ignored in ALL your git repositories +# ============================================================================= +# Referenced by ~/.gitconfig → [core] excludesfile +# +# Only put things here that you NEVER want to commit anywhere (OS files, +# editor files, your own tooling). Project-specific ignores belong in +# the repo's own .gitignore. +# ============================================================================= + + +# ----------------------------------------------------------------------------- +# macOS +# ----------------------------------------------------------------------------- + +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +.AppleDouble +.LSOverride +Icon? + +# Thumbnails +ehthumbs.db +Thumbs.db + + +# ----------------------------------------------------------------------------- +# Linux desktop +# ----------------------------------------------------------------------------- + +*~ +.directory +.Trash-* + + +# ----------------------------------------------------------------------------- +# Windows +# ----------------------------------------------------------------------------- + +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ +*.lnk + + +# ----------------------------------------------------------------------------- +# Editors & IDEs +# ----------------------------------------------------------------------------- + +# VS Code +.vscode/ +!.vscode/settings.json # feel free to commit these if you want +!.vscode/extensions.json +!.vscode/launch.json +!.vscode/tasks.json +*.code-workspace + +# JetBrains (WebStorm, IntelliJ, …) +.idea/ +*.iml +*.iws +*.ipr +out/ + +# Vim / Neovim +*.swp +*.swo +*~ +.netrwhist +Session.vim +.nvimrc.local + +# Emacs +*# +.#* +\#*# +*.elc +auto-save-list +tramp + +# Sublime Text +*.sublime-project +*.sublime-workspace + + +# ----------------------------------------------------------------------------- +# Node.js / TypeScript +# ----------------------------------------------------------------------------- + +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +.npm/ +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.js +.pnp.cjs + +# Build output +dist/ +build/ +out/ +.next/ +.nuxt/ +.svelte-kit/ +.output/ + +# TypeScript +*.tsbuildinfo + +# Coverage +coverage/ +*.lcov +.nyc_output/ + +# Misc +*.env.local +*.env.*.local + + +# ----------------------------------------------------------------------------- +# Environment / secrets — never commit these +# ----------------------------------------------------------------------------- + +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +*.pem +*.key +*.p12 +*.pfx +secrets/ +.secrets + + +# ----------------------------------------------------------------------------- +# Logs & temp files +# ----------------------------------------------------------------------------- + +*.log +logs/ +tmp/ +temp/ +.cache/ + + +# ----------------------------------------------------------------------------- +# Package manager lock files (decide per-project, not globally) +# ----------------------------------------------------------------------------- +# Uncomment if you NEVER want to commit lock files (unusual; not recommended): +# package-lock.json +# yarn.lock +# pnpm-lock.yaml diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..74cdf0e --- /dev/null +++ b/.npmrc @@ -0,0 +1,41 @@ +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# ~/.npmrc — npm configuration +# ============================================================================= +# Reference: https://docs.npmjs.com/cli/v10/configuring-npm/npmrc +# Run `npm config list` to see the current resolved config. +# ============================================================================= + +# Store global packages in ~/.npm-global instead of /usr/local (avoids sudo) +# After setting this, add ~/.npm-global/bin to your PATH in .zshenv +# prefix=~/.npm-global + +# Save exact versions by default (avoids unexpected minor/patch upgrades) +# Tradeoff: lock files are more important; keep this off if you prefer ranges. +# save-exact=true + +# Default to saving dependencies (not devDependencies) when running `npm install pkg` +# save=true + +# Initialise new packages with sane defaults so you don't get prompted every time +# init-author-name= +# init-license=MIT +# init-version=0.1.0 + +# Engine strict mode — fail if the package requires a different Node version +# engine-strict=true + +# Audit level — fail `npm install` if vulnerabilities of this severity or above exist +# audit-level=high + +# Progress bar (disable for cleaner CI output — set per CI env instead) +# progress=false + +# Log level: silent, error, warn, notice, http, timing, info, verbose, silly +# loglevel=warn + +# Use a faster registry mirror (e.g. Verdaccio, Nexus, GitHub Packages) +# registry=https://registry.npmjs.org/ # default + +# Cache directory (defaults to ~/.npm) +# cache=~/.npm diff --git a/.zshenv b/.zshenv new file mode 100644 index 0000000..9186e77 --- /dev/null +++ b/.zshenv @@ -0,0 +1,94 @@ +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# ~/.zshenv — sourced by ALL zsh instances (login, interactive, scripts) +# ============================================================================= +# Keep this file lean and fast. Only put things here that genuinely need to +# be available in every shell context (e.g. $PATH, $EDITOR, $LANG). +# +# For interactive-shell-only settings, use ~/.zshrc instead. +# For login-shell-only settings, use ~/.zprofile instead. +# ============================================================================= + + +# ----------------------------------------------------------------------------- +# LANGUAGE / LOCALE +# ----------------------------------------------------------------------------- + +export LANG='en_US.UTF-8' +export LC_ALL='en_US.UTF-8' + + +# ----------------------------------------------------------------------------- +# XDG BASE DIRECTORIES (https://specifications.freedesktop.org/basedir-spec/) +# Keeps your $HOME tidy — many modern tools respect these. +# ----------------------------------------------------------------------------- + +export XDG_CONFIG_HOME="${HOME}/.config" +export XDG_DATA_HOME="${HOME}/.local/share" +export XDG_CACHE_HOME="${HOME}/.cache" +export XDG_STATE_HOME="${HOME}/.local/state" + + +# ----------------------------------------------------------------------------- +# PATH — add your own bins before the system ones +# ----------------------------------------------------------------------------- + +# Local user binaries (scripts you want available everywhere) +export PATH="${HOME}/.local/bin:${PATH}" + +# Homebrew (uncomment whichever applies) +# export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:${PATH}" # Apple Silicon +# export PATH="/usr/local/bin:/usr/local/sbin:${PATH}" # Intel Mac + +# Global npm binaries (fallback if a version manager isn't managing PATH) +# export PATH="${HOME}/.npm-global/bin:${PATH}" + + +# ----------------------------------------------------------------------------- +# DOTFILES LOCATION — used by the `dotfiles` alias in .zshrc +# ----------------------------------------------------------------------------- + +export DOTFILES_DIR="${HOME}/.dotfiles" + + +# ----------------------------------------------------------------------------- +# EDITOR / PAGER +# ----------------------------------------------------------------------------- + +export EDITOR='code --wait' +export VISUAL="${EDITOR}" +export PAGER='less' + +# Less options: case-insensitive search, quit if short, use colour, show % +export LESS='-iRFX --use-color' + +# Use bat as a colourised pager for man pages (requires bat to be installed) +# export MANPAGER='sh -c "col -bx | bat -l man -p"' + + +# ----------------------------------------------------------------------------- +# DEVELOPMENT TOOLS +# ----------------------------------------------------------------------------- + +# Node / npm +export NPM_CONFIG_PREFIX="${HOME}/.npm-global" # global npm install location + +# TypeScript / ts-node +# export TS_NODE_PROJECT='tsconfig.json' + +# Go (if you ever dabble) +# export GOPATH="${HOME}/go" +# export PATH="${GOPATH}/bin:${PATH}" + +# Rust / Cargo +# export PATH="${HOME}/.cargo/bin:${PATH}" + +# Python (pyenv) +# export PYENV_ROOT="${HOME}/.pyenv" +# export PATH="${PYENV_ROOT}/bin:${PATH}" + + +# ----------------------------------------------------------------------------- +# LOCAL OVERRIDES — machine-specific env vars (not committed to git) +# ----------------------------------------------------------------------------- +[[ -f "${HOME}/.zshenv.local" ]] && source "${HOME}/.zshenv.local" diff --git a/.zshrc b/.zshrc new file mode 100644 index 0000000..1808189 --- /dev/null +++ b/.zshrc @@ -0,0 +1,472 @@ +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# ~/.zshrc — zsh interactive shell configuration +# ============================================================================= +# Optimised for TypeScript / Node.js development. Fast by default; the many +# commented-out sections are a tutorial you can read with Copilot and +# enable a piece at a time. +# +# References: +# https://dotfiles.github.io/ +# https://zsh.sourceforge.io/Doc/Release/zsh_toc.html +# ============================================================================= + + +# ----------------------------------------------------------------------------- +# 0. PROFILING (uncomment to find what's slow) +# ----------------------------------------------------------------------------- +# zmodload zsh/zprof # start profiling — pair with `zprof` at bottom of file + + +# ============================================================================= +# 1. HISTORY — the single most impactful setting for command recall +# ============================================================================= + +HISTFILE="${HOME}/.zsh_history" +HISTSIZE=100000 # lines kept in memory +SAVEHIST=100000 # lines written to HISTFILE + +setopt HIST_IGNORE_DUPS # skip consecutive duplicates +setopt HIST_IGNORE_ALL_DUPS # remove older duplicate entry from history +setopt HIST_FIND_NO_DUPS # don't show duplicates when searching +setopt HIST_IGNORE_SPACE # don't record commands starting with a space +setopt HIST_REDUCE_BLANKS # strip extra blanks +setopt HIST_VERIFY # show substituted history line before running it +setopt SHARE_HISTORY # share history across all open shells in real time +setopt INC_APPEND_HISTORY # write immediately, not on shell exit +setopt EXTENDED_HISTORY # record timestamp with each command + + +# ============================================================================= +# 2. COMPLETION — fast native zsh completion (no plugins needed) +# ============================================================================= + +autoload -Uz compinit + +# Only rebuild the completion cache once per day (keeps startup snappy) +if [[ -n "${ZDOTDIR:-$HOME}/.zcompdump"(#qN.mh+20) ]]; then + compinit +else + compinit -C +fi + +setopt COMPLETE_IN_WORD # complete from both ends of a word +setopt AUTO_MENU # show completion menu on second tab press +setopt LIST_PACKED # compact the completion list + +# Case-insensitive completion +zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*' + +# Coloured completion menu +zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" + +# Group completions by type (files, commands, etc.) +zstyle ':completion:*' group-name '' +zstyle ':completion:*:descriptions' format '%F{yellow}-- %d --%f' + + +# ============================================================================= +# 3. PROMPT — git-aware, single-line, no external dependencies +# ============================================================================= +# Shows: user@host current/dir [branch] $ +# Async git info keeps the prompt instant even in big repos. +# See the "ALTERNATIVE PROMPTS" section below for Starship, Pure, etc. + +autoload -Uz vcs_info +precmd_functions+=(vcs_info) + +zstyle ':vcs_info:git:*' formats ' %F{cyan}(%b)%f' +zstyle ':vcs_info:git:*' actionformats ' %F{red}(%b|%a)%f' +zstyle ':vcs_info:*' enable git + +# Prompt format: user@host ~/path (branch) $ +setopt PROMPT_SUBST +PROMPT='%F{green}%n@%m%f %F{blue}%~%f${vcs_info_msg_0_} %# ' + +# Right-side prompt: last command exit status (hidden when 0) +RPROMPT='%(?..%F{red}✘ %?%f)' + +# --- ALTERNATIVE PROMPTS (pick one; comment out the block above) ----------- +# +# --- Starship (https://starship.rs) — cross-shell, feature-rich, fast ----- +# Install: curl -sS https://starship.rs/install.sh | sh +# eval "$(starship init zsh)" +# +# --- Pure (https://github.com/sindresorhus/pure) — minimal, async --------- +# Install: npm install --global pure-prompt +# autoload -U promptinit; promptinit; prompt pure +# +# --- Oh My Posh (https://ohmyposh.dev) — highly themeable ----------------- +# eval "$(oh-my-posh init zsh)" +# --------------------------------------------------------------------------- + + +# ============================================================================= +# 4. KEY BINDINGS — make history search intuitive +# ============================================================================= + +bindkey -e # Emacs mode (default, plays well with readline apps) +# bindkey -v # Uncomment for Vi mode + +# Up/Down arrows search history by prefix already typed +autoload -Uz up-line-or-beginning-search down-line-or-beginning-search +zle -N up-line-or-beginning-search +zle -N down-line-or-beginning-search +bindkey '^[[A' up-line-or-beginning-search +bindkey '^[[B' down-line-or-beginning-search +bindkey '^[OA' up-line-or-beginning-search # tmux / some terminals +bindkey '^[OB' down-line-or-beginning-search + +# Ctrl+R — incremental history search (built-in) +bindkey '^R' history-incremental-search-backward + +# --- fzf-powered history search (HIGHLY RECOMMENDED) ---------------------- +# fzf gives you a fuzzy-searchable history popup — game-changing for recall. +# Install: brew install fzf && $(brew --prefix)/opt/fzf/install +# or: git clone --depth 1 https://github.com/junegunn/fzf ~/.fzf && ~/.fzf/install +# +# Once installed, sourcing the key bindings file is all you need: +# [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh +# --------------------------------------------------------------------------- + +# Home / End +bindkey '^[[H' beginning-of-line +bindkey '^[[F' end-of-line +bindkey '^[[1~' beginning-of-line +bindkey '^[[4~' end-of-line + +# Ctrl+Left / Ctrl+Right — jump words +bindkey '^[[1;5D' backward-word +bindkey '^[[1;5C' forward-word + +# Ctrl+Backspace / Ctrl+Delete +bindkey '^H' backward-kill-word +bindkey '^[[3;5~' kill-word + + +# ============================================================================= +# 5. DIRECTORY NAVIGATION +# ============================================================================= + +setopt AUTO_CD # type a directory name to cd into it +setopt AUTO_PUSHD # cd pushes old directory onto stack +setopt PUSHD_IGNORE_DUPS # no duplicates in directory stack +setopt PUSHD_SILENT # don't print the stack on each pushd/popd + +alias ..='cd ..' +alias ...='cd ../..' +alias ....='cd ../../..' +alias -- -='cd -' # cd to previous directory + +# --- zoxide (smarter cd — learns your most-visited dirs) ------------------ +# Install: brew install zoxide or cargo install zoxide +# eval "$(zoxide init zsh)" +# After a while: `z proj` jumps straight to ~/work/my-project +# --------------------------------------------------------------------------- + + +# ============================================================================= +# 6. NODE.JS / TYPESCRIPT TOOLCHAIN +# ============================================================================= + +# --- Node version manager: choose ONE of the options below ---------------- +# +# Option A: fnm (fast, written in Rust — RECOMMENDED for speed) +# Install: curl -fsSL https://fnm.vercel.app/install | bash +# or: brew install fnm +if command -v fnm &>/dev/null; then + eval "$(fnm env --use-on-cd)" +fi +# +# Option B: nvm (most popular, but adds ~100 ms to every shell startup) +# Install: https://github.com/nvm-sh/nvm#install--update-script +# export NVM_DIR="${HOME}/.nvm" +# [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" +# [ -s "${NVM_DIR}/bash_completion" ] && \. "${NVM_DIR}/bash_completion" +# # Lazy-load nvm to keep startup fast (loads on first `nvm`, `node`, or `npm` call) +# # See: https://www.reddit.com/r/node/comments/4tg5jg/lazy_load_nvm_for_faster_shell_start/ +# +# Option C: volta (pin per-project, zero-config) +# Install: curl https://get.volta.sh | bash +# export VOLTA_HOME="${HOME}/.volta" +# export PATH="${VOLTA_HOME}/bin:${PATH}" +# +# Option D: asdf (polyglot version manager — Node, Ruby, Python, Go, …) +# Install: https://asdf-vm.com/guide/getting-started.html +# . "${HOME}/.asdf/asdf.sh" +# . "${HOME}/.asdf/completions/asdf.bash" +# --------------------------------------------------------------------------- + +# pnpm +export PNPM_HOME="${HOME}/.local/share/pnpm" +case ":${PATH}:" in + *":${PNPM_HOME}:"*) ;; + *) export PATH="${PNPM_HOME}:${PATH}" ;; +esac + +# Corepack / Yarn (comes bundled with Node ≥ 16.9) +# corepack enable # uncomment to manage yarn/pnpm versions via package.json#packageManager + + +# ============================================================================= +# 7. ALIASES — Node / TypeScript / everyday +# ============================================================================= + +# --- npm --- +alias ni='npm install' +alias nid='npm install --save-dev' +alias nig='npm install -g' +alias nu='npm update' +alias nr='npm run' +alias nrb='npm run build' +alias nrd='npm run dev' +alias nrt='npm run test' +alias nrl='npm run lint' +alias nrw='npm run watch' +alias nlg='npm list -g --depth=0' + +# --- pnpm (uncomment if you prefer pnpm) --- +# alias pi='pnpm install' +# alias pid='pnpm add -D' +# alias pig='pnpm add -g' +# alias pr='pnpm run' +# alias prb='pnpm run build' +# alias prd='pnpm run dev' +# alias prt='pnpm run test' +# alias prl='pnpm run lint' + +# --- TypeScript --- +alias tsc='npx tsc' +alias tsw='npx tsc --watch' +alias tsx='npx tsx' # run TS files without compiling first + +# --- git (short but readable) --- +alias g='git' +alias gs='git status -sb' +alias ga='git add' +alias gaa='git add --all' +alias gc='git commit' +alias gcm='git commit -m' +alias gca='git commit --amend' +alias gco='git checkout' +alias gsw='git switch' +alias gb='git branch' +alias gba='git branch -a' +alias gbd='git branch -d' +alias gd='git diff' +alias gds='git diff --staged' +alias gl='git log --oneline --graph --decorate --all' +alias gll='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset"' +alias gp='git push' +alias gpf='git push --force-with-lease' # safer than --force +alias gu='git pull' +alias gst='git stash' +alias gstp='git stash pop' +alias gcp='git cherry-pick' +alias grb='git rebase' +alias gri='git rebase -i' +alias grc='git rebase --continue' + +# --- ls / file listing --- +alias ls='ls --color=auto' +alias ll='ls -lAh --color=auto' +alias la='ls -A --color=auto' +# Modern alternatives (install with brew install eza): +# alias ls='eza' +# alias ll='eza -lah --git' +# alias lt='eza --tree --level=2' + +# --- safer defaults --- +alias rm='rm -i' +alias cp='cp -i' +alias mv='mv -i' +alias mkdir='mkdir -pv' + +# --- utilities --- +alias grep='grep --color=auto' +alias df='df -h' +alias du='du -sh' +alias ports='lsof -i -P -n | grep LISTEN' # show listening ports +alias path='echo -e ${PATH//:/\\n}' # print PATH one entry per line +alias reload='source ~/.zshrc' # reload this config +alias dotfiles='cd ${DOTFILES_DIR:-~/.dotfiles}' + + +# ============================================================================= +# 8. FUNCTIONS — useful one-liners +# ============================================================================= + +# Create a directory and immediately cd into it +mkcd() { mkdir -p "$1" && cd "$1"; } + +# Quick git clone and cd +gclone() { git clone "$1" && cd "$(basename "$1" .git)"; } + +# Find and kill a process on a given port +killport() { + local pid + pid=$(lsof -ti :"$1") && kill -9 "$pid" && echo "Killed PID ${pid} on port $1" \ + || echo "Nothing listening on port $1" +} + +# Show the 10 most-used commands (great for finding alias candidates) +topcmds() { + history 1 | awk '{print $2}' | sort | uniq -c | sort -rn | head -10 +} + +# Extract any archive format +extract() { + case "$1" in + *.tar.bz2) tar xjf "$1" ;; + *.tar.gz) tar xzf "$1" ;; + *.tar.xz) tar xJf "$1" ;; + *.bz2) bunzip2 "$1" ;; + *.gz) gunzip "$1" ;; + *.tar) tar xf "$1" ;; + *.tbz2) tar xjf "$1" ;; + *.tgz) tar xzf "$1" ;; + *.zip) unzip "$1" ;; + *.Z) uncompress "$1";; + *.7z) 7z x "$1" ;; + *) echo "'$1' cannot be extracted via extract()" ;; + esac +} + +# Open GitHub repo page for the current directory +ghopen() { + local url + url=$(git remote get-url origin 2>/dev/null \ + | sed 's|git@github.com:|https://github.com/|' \ + | sed 's|\.git$||') + [[ -n "$url" ]] && open "$url" || echo "No GitHub remote found" +} + + +# ============================================================================= +# 9. EDITOR +# ============================================================================= + +export EDITOR='code --wait' # VS Code; change to nvim/vim/nano as preferred +export VISUAL="${EDITOR}" + +# --- Neovim alternatives --- +# export EDITOR='nvim' +# export VISUAL='nvim' + + +# ============================================================================= +# 10. MISCELLANEOUS OPTIONS +# ============================================================================= + +setopt NO_BEEP # silence audible bell +setopt INTERACTIVE_COMMENTS # allow # comments in interactive shell +setopt CORRECT # suggest corrections for mistyped commands +setopt GLOB_DOTS # include dotfiles in glob patterns (but not .. /) + +# Colour support +export CLICOLOR=1 +export LSCOLORS='ExFxBxDxCxegedabagacad' # macOS ls colours + + +# ============================================================================= +# 11. TOOL INTEGRATIONS (commented-out; install tools then uncomment) +# ============================================================================= + +# --- Homebrew (macOS / Linux) --------------------------------------------- +# eval "$(/opt/homebrew/bin/brew shellenv)" # Apple Silicon +# eval "$(/usr/local/bin/brew shellenv)" # Intel Mac + +# --- direnv — per-directory .envrc files --------------------------------- +# Great for project-specific env vars without a plugin manager. +# Install: brew install direnv +# eval "$(direnv hook zsh)" + +# --- pyenv — Python version management ------------------------------------ +# Install: brew install pyenv +# export PYENV_ROOT="${HOME}/.pyenv" +# export PATH="${PYENV_ROOT}/bin:${PATH}" +# eval "$(pyenv init -)" + +# --- rbenv — Ruby version management -------------------------------------- +# eval "$(rbenv init - zsh)" + +# --- GitHub CLI completions ----------------------------------------------- +# brew install gh → then: +# eval "$(gh completion -s zsh)" + +# --- Docker --- +# export DOCKER_BUILDKIT=1 # faster builds + +# --- bat (better cat) — https://github.com/sharkdp/bat ------------------- +# Install: brew install bat +# export BAT_THEME="TwoDark" +# alias cat='bat' +# alias man='batman' # colourised man pages via bat-extras + +# --- ripgrep (faster grep) ------------------------------------------------ +# Install: brew install ripgrep +# export RIPGREP_CONFIG_PATH="${HOME}/.ripgreprc" + +# --- atuin — magic shell history database --------------------------------- +# Syncs/searches history across machines; replaces Ctrl+R +# Install: bash <(curl https://raw.githubusercontent.com/atuinsh/atuin/main/install.sh) +# eval "$(atuin init zsh)" + +# --- 1Password SSH agent -------------------------------------------------- +# export SSH_AUTH_SOCK=~/.1password/agent.sock + + +# ============================================================================= +# 12. PLUGIN MANAGER OPTIONS (all disabled by default for speed) +# ============================================================================= +# These are the main options — read, pick one, enjoy. +# +# --- Oh My Zsh (most popular, most plugins, slowest) ---------------------- +# Docs: https://ohmyz.sh +# Install: sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" +# export ZSH="${HOME}/.oh-my-zsh" +# ZSH_THEME="robbyrussell" +# plugins=(git node npm yarn typescript vscode fzf) +# source "${ZSH}/oh-my-zsh.sh" +# +# --- Prezto (leaner than OMZ, good defaults) ------------------------------ +# Docs: https://github.com/sorin-ionescu/prezto +# source "${ZDOTDIR:-${HOME}}/.zprezto/init.zsh" +# +# --- Zinit (fastest, plugin manager with turbo mode) ---------------------- +# Docs: https://github.com/zdharma-continuum/zinit +# Install: bash -c "$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/zdharma-continuum/zinit/HEAD/scripts/install.sh)" +# source "${HOME}/.local/share/zinit/zinit.git/zinit.zsh" +# zinit ice wait lucid; zinit light zsh-users/zsh-autosuggestions +# zinit ice wait lucid; zinit light zsh-users/zsh-syntax-highlighting +# zinit ice wait lucid; zinit light zsh-users/zsh-completions +# +# --- Antidote (successor to antibody, no daemon) -------------------------- +# Docs: https://getantidote.github.io +# source "$(brew --prefix)/opt/antidote/share/antidote/antidote.zsh" +# antidote load +# +# --- Sheldon (TOML config, fast) ------------------------------------------ +# Docs: https://sheldon.cli.rs +# eval "$(sheldon source)" +# +# --- Manual (no manager; clone repos, source files) ----------------------- +# zsh-autosuggestions (Fish-like suggestions): https://github.com/zsh-users/zsh-autosuggestions +# source "${HOME}/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh" +# ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8' +# bindkey '^ ' autosuggest-accept # Ctrl+Space to accept suggestion +# +# zsh-syntax-highlighting: https://github.com/zsh-users/zsh-syntax-highlighting +# source "${HOME}/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" +# (must be sourced LAST) + + +# ============================================================================= +# 13. LOCAL OVERRIDES — machine-specific settings go here +# ============================================================================= +# Keep work/personal secrets and machine-specific paths out of version control. +[[ -f "${HOME}/.zshrc.local" ]] && source "${HOME}/.zshrc.local" + + +# --- Profiling results (uncomment if you uncommented zmodload above) ------ +# zprof diff --git a/README.md b/README.md index 27ef622..b488412 100644 --- a/README.md +++ b/README.md @@ -1 +1,106 @@ -# dotfiles \ No newline at end of file +# dotfiles + +**GUID: `4e079e8c-dadd-47fc-9582-0914483981ea`** — grep for this string to locate any installed dotfile on any machine. + +Personal dotfiles for a TypeScript / Node.js developer. Optimised for a **fast, +git-aware shell** with plenty of commented-out tutorial sections you can browse +with Copilot and enable a piece at a time. + +Inspired by / further reading: + +--- + +## What's included + +| File | Purpose | +|---|---| +| `.zshrc` | Interactive shell: prompt, history, completion, aliases, functions, tool integrations | +| `.zshenv` | Environment variables loaded by all zsh sessions (PATH, EDITOR, XDG dirs) | +| `.gitconfig` | Git aliases, delta diff, sane defaults | +| `.gitignore_global` | Global ignore patterns (macOS, editors, Node/TS artefacts) | +| `.npmrc` | npm defaults (global prefix, init values) | +| `.editorconfig` | Cross-editor formatting baseline | +| `bootstrap.sh` | Symlinks every file above into `$HOME` | + +--- + +## Quick start + +```bash +# 1. Clone +git clone https://github.com/markfields/dotfiles.git ~/.dotfiles +cd ~/.dotfiles + +# 2. Dry run — see what would change +./bootstrap.sh + +# 3. Apply +./bootstrap.sh --apply + +# 4. Reload +source ~/.zshrc +``` + +--- + +## Shell highlights + +### Prompt +A single-line prompt built on zsh's native `vcs_info` — no external tools +required. Shows `user@host ~/path (branch) $` with the exit-status in red on +the right when a command fails. + +Alternative prompts are commented in `.zshrc` (Starship, Pure, Oh My Posh). + +### History +- 100 000-line history shared across all open terminals in real time +- Prefix-search with ↑ / ↓ +- `Ctrl+R` for incremental reverse search (or install fzf for a fuzzy popup) + +### Node version management +`fnm` is enabled by default (fast, written in Rust). Alternatives — `nvm`, +`volta`, `asdf` — are all documented and commented in `.zshrc`. + +### Key aliases +``` +gs git status -sb nr npm run +ga git add nrb npm run build +gcm git commit -m nrd npm run dev +gl git log (pretty graph) nrt npm run test +gp git push +``` + +--- + +## Extending / customising + +### Machine-specific overrides +Create `~/.zshrc.local` and/or `~/.gitconfig.local` — they're sourced +automatically and are never committed to git. + +### Enabling a commented section +Most of the interesting stuff in `.zshrc` is commented out as a tutorial. +Search for a section (e.g. `fzf`, `Starship`, `nvm`) and follow the install +instructions in the comment, then un-comment the relevant lines. + +### Recommended additions (not installed by default) +| Tool | Install | What it does | +|---|---|---| +| [fzf](https://github.com/junegunn/fzf) | `brew install fzf` | Fuzzy history/file search via `Ctrl+R` | +| [fnm](https://github.com/Schniz/fnm) | `brew install fnm` | Fast Node version manager | +| [git-delta](https://github.com/dandavison/delta) | `brew install git-delta` | Beautiful diffs | +| [eza](https://github.com/eza-community/eza) | `brew install eza` | Modern `ls` with git info | +| [bat](https://github.com/sharkdp/bat) | `brew install bat` | Syntax-highlighted `cat` | +| [ripgrep](https://github.com/BurntSushi/ripgrep) | `brew install ripgrep` | Fast `grep` | +| [zoxide](https://github.com/ajeetdsouza/zoxide) | `brew install zoxide` | Smart `cd` | +| [Starship](https://starship.rs) | `brew install starship` | Cross-shell prompt | + +--- + +## Further reading + +- — community dotfiles tutorials & links +- — comprehensive dotfiles guide +- — popular reference dotfiles +- — Zach Holman's dotfiles (topic-based) +- — thoughtbot's dotfiles diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..cc26c56 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# dotfiles-guid: 4e079e8c-dadd-47fc-9582-0914483981ea +# ============================================================================= +# bootstrap.sh — bootstrap dotfiles by symlinking them into $HOME +# ============================================================================= +# Usage: +# ./bootstrap.sh # dry run (shows what would happen) +# ./bootstrap.sh --apply # actually create symlinks +# +# What it does: +# • Symlinks every file listed in FILES below from this repo into $HOME +# • Backs up any existing files to .backup. +# • Is idempotent — safe to run multiple times +# +# Alternative tools to consider for managing dotfiles: +# • GNU Stow — https://www.gnu.org/software/stow/ (simple, symlink-based) +# • chezmoi — https://www.chezmoi.io/ (templates, encryption) +# • YADM — https://yadm.io/ (git wrapper) +# • Dotbot — https://github.com/anishathalye/dotbot (YAML config) +# • Mackup — https://github.com/lra/mackup (syncs app settings too) +# ============================================================================= + +set -euo pipefail + +DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BACKUP_SUFFIX=".backup.$(date +%Y%m%d_%H%M%S)" +APPLY=false + +# Colour helpers +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' +CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m' + +info() { echo -e "${CYAN} →${RESET} $*"; } +success() { echo -e "${GREEN} ✓${RESET} $*"; } +warning() { echo -e "${YELLOW} !${RESET} $*"; } +error() { echo -e "${RED} ✗${RESET} $*" >&2; } + +# Parse args +for arg in "$@"; do + case "$arg" in + --apply|-a) APPLY=true ;; + --help|-h) + echo "Usage: $(basename "$0") [--apply]" + echo " Without --apply, performs a dry run." + exit 0 + ;; + *) error "Unknown argument: $arg"; exit 1 ;; + esac +done + +# ============================================================================= +# FILES TO SYMLINK (source path relative to DOTFILES_DIR → target in $HOME) +# ============================================================================= +declare -A FILES=( + [".zshrc"]=".zshrc" + [".zshenv"]=".zshenv" + [".gitconfig"]=".gitconfig" + [".gitignore_global"]=".gitignore_global" + [".npmrc"]=".npmrc" + [".editorconfig"]=".editorconfig" +) + +# ============================================================================= +# MAIN +# ============================================================================= + +echo +echo -e "${BOLD}dotfiles installer${RESET} — ${DOTFILES_DIR}" +if [[ "${APPLY}" == false ]]; then + echo -e "${YELLOW}DRY RUN — pass --apply to make changes${RESET}" +fi +echo + +link_file() { + local src="${DOTFILES_DIR}/${1}" + local dst="${HOME}/${2}" + + if [[ ! -e "$src" ]]; then + error "Source not found: $src" + return + fi + + # Already correctly linked + if [[ -L "$dst" && "$(readlink "$dst")" == "$src" ]]; then + success "${dst} → already linked" + return + fi + + # Backup existing file/symlink + if [[ -e "$dst" || -L "$dst" ]]; then + warning "Backing up ${dst} → ${dst}${BACKUP_SUFFIX}" + if [[ "${APPLY}" == true ]]; then + mv "$dst" "${dst}${BACKUP_SUFFIX}" + fi + fi + + info "Linking ${dst} → ${src}" + if [[ "${APPLY}" == true ]]; then + ln -sf "$src" "$dst" + fi +} + +for src in "${!FILES[@]}"; do + link_file "$src" "${FILES[$src]}" +done + +echo +if [[ "${APPLY}" == true ]]; then + echo -e "${GREEN}${BOLD}Done!${RESET} Dotfiles installed." + echo " Reload your shell: source ~/.zshrc" +else + echo -e "Run ${BOLD}./bootstrap.sh --apply${RESET} to apply the above changes." +fi +echo