From 57554fa1fbd8e6278a74e7180f386597c7b8e28b Mon Sep 17 00:00:00 2001 From: David Stosik Date: Mon, 2 Mar 2026 15:48:43 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20zsh=20=E2=80=94=20structured=20conf?= =?UTF-8?q?ig=20with=20aliases=20and=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorganized zsh configuration from single flat file into: - zsh/zshrc — main config (history, prompt, completions, tool integrations) - zsh/aliases.zsh — consolidated aliases from v1-v4 (git, navigation, safety, ruby) - zsh/functions.zsh — shell functions (mkcd from v3, vpn-fix from v4) New in this version: - fzf integration (was in v3 but missing from v4) - Case-insensitive completion - Support for ~/.zshrc.local overrides - Better organized tool integrations (mise, fzf, op, gt) Preserved from v4: - Git-aware prompt with staged/unstaged indicators - Auto-attach to tmux session - EDITOR=nvim, emacs keybindings in shell - Shared history between panes Restored from older branches: - mkcd function (v3) - ls color aliases for macOS + Linux (v1) - Safety aliases: rm -i, cp -i, mv -i (v1) - Ruby/Rails aliases: be, r, rb (wip-20241205) - Navigation aliases: .., ..., .... (new) - Git shortcut aliases: gs, gd, gdc, gl, etc. (new) --- zsh/aliases.zsh | 51 +++++++++++++++++++++++++++ zsh/functions.zsh | 29 ++++++++++++++++ zsh/zshrc | 87 +++++++++++++++++++++++++++++++++++++++++++++++ zshrc | 74 ---------------------------------------- 4 files changed, 167 insertions(+), 74 deletions(-) create mode 100644 zsh/aliases.zsh create mode 100644 zsh/functions.zsh create mode 100644 zsh/zshrc delete mode 100644 zshrc diff --git a/zsh/aliases.zsh b/zsh/aliases.zsh new file mode 100644 index 0000000..3944a6c --- /dev/null +++ b/zsh/aliases.zsh @@ -0,0 +1,51 @@ +# Aliases — sourced from zshrc + +# --- Git --- +alias g='git' +alias ga='git addp' +alias gc='git ci' +alias gco='git co' +alias gd='git diff' +alias gdc='git diffc' +alias gl='git lol' +alias gla='git lol --all' +alias gp='git push' +alias gpf='git pushf' +alias gs='git st' + +# --- Navigation --- +alias ..='cd ..' +alias ...='cd ../..' +alias ....='cd ../../..' + +# --- Listing --- +alias l='ls' +alias ll='ls -alF' +alias la='ls -A' + +# Use colors for ls (macOS vs Linux) +if [[ "$OSTYPE" == "darwin"* ]]; then + alias ls='ls -hFG' +else + alias ls='ls -hF --color=auto' +fi + +# --- Safety --- +alias rm='rm -i' +alias cp='cp -i' +alias mv='mv -i' + +# --- Grep --- +alias grep='grep --color=auto' + +# --- History --- +alias hist='fc -lt "%F %T"' + +# --- Ruby/Rails --- +alias be='bundle exec' +alias r='rails' +alias rb='ruby' + +# --- Misc --- +alias vim='nvim' +alias vi='nvim' diff --git a/zsh/functions.zsh b/zsh/functions.zsh new file mode 100644 index 0000000..ea58437 --- /dev/null +++ b/zsh/functions.zsh @@ -0,0 +1,29 @@ +# Functions — sourced from zshrc + +# Create a directory and cd into it +mkcd() { mkdir -p "$@" && cd "$_" } + +# Fix route to devices behind VPN when there's a subnet conflict (macOS) +vpn-fix() { + if [[ "$OSTYPE" != "darwin"* ]]; then + echo "vpn-fix is macOS only" + return 1 + fi + + local iface + iface=$(ifconfig | awk '/^utun/{iface=$1} /10\.10\.10\./{gsub(/:$/,"",iface); print iface}') + + if [[ -z "$iface" ]]; then + echo "WireGuard interface not found — is VPN connected?" + return 1 + fi + + if netstat -rn | grep -q "192.168.1 \+${iface}"; then + echo "Route already set (192.168.1.0/24 → $iface)" + return 0 + fi + + sudo -v -p "sudo password required to add route: " && \ + sudo route add 192.168.1.0/24 -interface "$iface" &>/dev/null && \ + echo "✓ Route added: 192.168.1.0/24 → $iface" +} diff --git a/zsh/zshrc b/zsh/zshrc new file mode 100644 index 0000000..82e5ab8 --- /dev/null +++ b/zsh/zshrc @@ -0,0 +1,87 @@ +# ~/.zshrc — David Stosik's zsh configuration +# Managed by: https://github.com/davidstosik/dotfiles + +# --- History --- +HISTFILE="${HOME}/.zsh_history" +HISTSIZE=50000 +SAVEHIST=50000 +setopt SHARE_HISTORY +setopt INC_APPEND_HISTORY +setopt HIST_IGNORE_DUPS +setopt HIST_IGNORE_ALL_DUPS +setopt HIST_REDUCE_BLANKS +setopt HIST_VERIFY + +# --- General options --- +setopt AUTO_CD +setopt INTERACTIVE_COMMENTS +setopt PROMPT_SUBST + +# --- Keybindings --- +bindkey -e # Emacs keybindings in shell (despite EDITOR=nvim) +bindkey "^[[3~" delete-char # Fix Delete key (tmux/ghostty) + +# --- Environment --- +export EDITOR=nvim +export VISUAL=nvim +export LANG="${LANG:-en_US.UTF-8}" +export PATH="${HOME}/.local/bin:${HOME}/bin:${PATH}" + +# --- Completions --- +autoload -Uz compinit && compinit +zstyle ':completion:*' menu select +zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' # Case-insensitive completion + +# --- Colors & VCS Info --- +autoload -U colors && colors +autoload -Uz vcs_info + +precmd_update_vcs_info() { vcs_info } +precmd_functions+=(precmd_update_vcs_info) + +default_vcs_info_color=$fg[blue] +zstyle ':vcs_info:*' enable git +zstyle ':vcs_info:git:*' formats "%{$default_vcs_info_color%}(%b%u%c)%{$reset_color%}" +zstyle ':vcs_info:git:*' actionformats "%{$default_vcs_info_color%}(%b|%{$fg_bold[magenta]%}%a%{$default_vcs_info_color%}%u%c)%{$reset_color%}" +zstyle ':vcs_info:git:*' check-for-changes true +zstyle ':vcs_info:git:*' unstagedstr "%{$fg_bold[yellow]%}*%{$default_vcs_info_color%}" +zstyle ':vcs_info:git:*' stagedstr "%{$fg_bold[green]%}!%{$default_vcs_info_color%}" + +# --- Prompt --- +PROMPT=$'\n''%{$fg[green]%}%~%{$reset_color%} ${vcs_info_msg_0_}'$'\n''%{$fg[white]%}%{$dim%}%(!.#.$)%{$reset_color%} ' +RPROMPT='' + +# --- Source aliases & functions --- +DOTFILES_DIR="${${(%):-%x}:A:h:h}" +[[ -f "${DOTFILES_DIR}/zsh/aliases.zsh" ]] && source "${DOTFILES_DIR}/zsh/aliases.zsh" +[[ -f "${DOTFILES_DIR}/zsh/functions.zsh" ]] && source "${DOTFILES_DIR}/zsh/functions.zsh" + +# --- Tool integrations --- + +# mise (polyglot version manager — replaces rbenv, nvm, etc.) +if command -v mise &> /dev/null; then + eval "$(mise activate zsh)" +fi + +# fzf (fuzzy finder) +if command -v fzf &> /dev/null; then + source <(fzf --zsh 2>/dev/null) || true +fi + +# 1Password CLI completions +if command -v op &> /dev/null; then + eval "$(op completion zsh)" ; compdef _op op +fi + +# Graphite CLI completions +if command -v gt &> /dev/null; then + eval "$(gt completion)" +fi + +# --- Auto-attach tmux --- +if command -v tmux &> /dev/null && [[ -z "$TMUX" ]]; then + tmux new-session -A -s "${USER}" +fi + +# --- Local overrides (not tracked) --- +[[ -f "${HOME}/.zshrc.local" ]] && source "${HOME}/.zshrc.local" diff --git a/zshrc b/zshrc deleted file mode 100644 index f569fd2..0000000 --- a/zshrc +++ /dev/null @@ -1,74 +0,0 @@ -# Sync command history between panes -setopt SHARE_HISTORY -setopt INC_APPEND_HISTORY -setopt HIST_IGNORE_DUPS -setopt HIST_IGNORE_ALL_DUPS -HISTSIZE=10000 -SAVEHIST=10000 - -export EDITOR=vim -bindkey -e # for emacs keys in shell despite EDITOR -bindkey "^[[3~" delete-char # restore Delete key in tmux - -alias g=git -alias hist='fc -lt "%F %T"' - -autoload -U colors && colors -autoload -Uz vcs_info -autoload -Uz compinit && compinit - -if command -v op &> /dev/null; then - eval "$(op completion zsh)" ; compdef _op op -fi - -# FIXME: should probably be in .zprofile on Mac -if command -v gt &> /dev/null; then - eval "$(gt completion)" -fi - -if command -v mise &> /dev/null; then - eval "$(mise activate zsh)" -fi - -precmd_update_vcs_info() { - vcs_info -} -precmd_functions+=(precmd_update_vcs_info) - -setopt prompt_subst - -default_vcs_info_color=$fg[blue] -zstyle ':vcs_info:*' enable git -zstyle ':vcs_info:git:*' formats "%{$default_vcs_info_color%}(%b%u%c)%{$reset_color%}" -zstyle ':vcs_info:git:*' actionformats "%{$default_vcs_info_color%}(%b|%{$fg_bold[magenta]%}%a%{$default_vcs_info_color%}%u%c)%{$reset_color%}" -zstyle ':vcs_info:git:*' check-for-changes true -zstyle ':vcs_info:git:*' unstagedstr "%{$fg_bold[yellow]%}*%{$default_vcs_info_color%}" -zstyle ':vcs_info:git:*' stagedstr "%{$fg_bold[green]%}!%{$default_vcs_info_color%}" - -PROMPT=$'\n''%{$fg[green]%}%~%{$reset_color%} ${vcs_info_msg_0_}'$'\n''%{$fg[white]%}%{$dim%}%(!.#.$)%{$reset_color%} ' -RPROMPT='' # '%{$fg[cyan]%}%T%{$reset_color%}' - -if command -v tmux &> /dev/null && [[ -z "$TMUX" ]]; then - tmux new-session -A -s "$USER" -fi - -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm -[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion -export PATH="$HOME/.local/bin:$PATH" - - -vpn-fix() { - local iface=$(ifconfig | awk '/^utun/{iface=$1} /10\.10\.10\./{gsub(/:$/,"",iface); print iface}') - if [[ -z "$iface" ]]; then - echo "WireGuard interface not found — is VPN connected?" - return 1 - fi - if netstat -rn | grep -q "192.168.1 \+${iface}"; then - echo "Route already set (192.168.1.0/24 → $iface)" - return 0 - fi - sudo -v -p "sudo password required to add route: " && \ - sudo route add 192.168.1.0/24 -interface "$iface" &>/dev/null && \ - echo "✓ Route added: 192.168.1.0/24 → $iface" -} From cd23acf1e4f1974c2160023c9268f584d15f8a9d Mon Sep 17 00:00:00 2001 From: David Stosik Date: Mon, 2 Mar 2026 15:48:56 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20git=20=E2=80=94=20consolidate=20con?= =?UTF-8?q?fig=20from=20all=20branches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved git configuration to git/ directory: - git/gitconfig — comprehensive config merging best of v1-v4 - git/gitignore — global gitignore with .claude, tags Preserved from v4 (modern git best practices): - histogram diff algorithm - zdiff3 merge conflict style - autoSquash, autoStash, updateRefs for rebase - fsmonitor + untrackedCache for performance - push.autoSetupRemote, fetch.prune - rerere enabled - Detailed color configuration for status and diff - column.ui = auto, help.autocorrect = prompt Restored from older branches: - lola alias (lol --all --graph) from v1-v3 - lolg alias (lol --graph) from wip-20241205 - addu alias (add -u) from v1-v3 - cp (cherry-pick), br (branch), up (pull) shortcuts from v1-v3 - copr alias for checking out PRs by number from v2-v3 - find-merge alias from v4 Consolidated aliases (kept best version of each): - pushf uses --force-with-lease (v4, safer than v-wip's --force) - lol uses --date=auto:human (v4, better than v1's --date=local) - recent for listing branches by recent commit Added: - Support for ~/.gitconfig.local (machine-specific overrides) - /tags in gitignore (from v3) --- gitconfig => git/gitconfig | 46 ++++++++++++++++++++++++++++++-------- git/gitignore | 16 +++++++++++++ gitignore | 11 --------- 3 files changed, 53 insertions(+), 20 deletions(-) rename gitconfig => git/gitconfig (78%) create mode 100644 git/gitignore delete mode 100644 gitignore diff --git a/gitconfig b/git/gitconfig similarity index 78% rename from gitconfig rename to git/gitconfig index 44ba892..c0aa8b1 100644 --- a/gitconfig +++ b/git/gitconfig @@ -14,27 +14,52 @@ defaultBranch = main [alias] - addp = add --patch + # Shortcuts + co = checkout + cob = checkout -b ci = commit --verbose + cim = commit --verbose --message cia = commit --amend --no-edit ciam = commit --amend - cim = commit --verbose --message - co = checkout - cob = checkout -b + st = status + br = branch + cp = cherry-pick + up = pull + + # Staging + addp = add --patch + addu = add -u + unstage = reset HEAD + + # Diff diffc = diff --cached - find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'" + + # Log lol = log --decorate --pretty=format:'%C(yellow)%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cd) %C(bold blue)<%an>%Creset' --abbrev-commit --date=auto:human + lolg = lol --graph + lola = lol --all --graph + + # Push pushf = push --force-with-lease + + # Branch management recent = branch --sort=-committerdate --format=\"%(committerdate:relative)%09%(refname:short)\" - st = status - unstage = reset HEAD + + # Stash + sstash = stash save -u + + # Find the merge commit for a given commit + find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'" + + # Checkout a PR by number: git copr 123 branch-name + copr = "!copr() { git fetch origin pull/$1/head:$2 && git checkout $2; }; copr" [column] ui = auto [color "status"] header = white dim - added = green bold # or updated + added = green bold changed = yellow bold untracked = red bold dim branch = magenta bold @@ -46,7 +71,6 @@ [color "diff"] meta = yellow context = white dim - whitespace = red reverse frag = magenta bold old = red new = green @@ -96,3 +120,7 @@ [feature] experimental = true + +# Local overrides (not tracked) — machine-specific settings, work configs, etc. +[include] + path = ~/.gitconfig.local diff --git a/git/gitignore b/git/gitignore new file mode 100644 index 0000000..6e0b777 --- /dev/null +++ b/git/gitignore @@ -0,0 +1,16 @@ +# macOS +*.DS_Store + +# Vim / Neovim +*.swp +*.swo +*~ + +# Logs +*.log + +# Claude / AI tools +.claude + +# Tags (ctags) +/tags diff --git a/gitignore b/gitignore deleted file mode 100644 index 597f4f6..0000000 --- a/gitignore +++ /dev/null @@ -1,11 +0,0 @@ -*.DS_Store - -# Vim -*.swp -*.swo - -*~ - -*.log - -.claude \ No newline at end of file From 1dab97a9108ea847fec06bef08c3bfd0afdb44af Mon Sep 17 00:00:00 2001 From: David Stosik Date: Mon, 2 Mar 2026 15:49:05 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20tmux=20=E2=80=94=20reorganize=20and?= =?UTF-8?q?=20cherry-pick=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved tmux config to tmux/ directory: - tmux/tmux.conf — main config - tmux/tmux.mac.conf — macOS-specific (pbcopy integration) Preserved from v4: - Tokyo Night theme with datetime and battery plugins - vim-style pane navigation (hjkl) - Intuitive split bindings (\ and -) - tmux-resurrect for session persistence - tmux-sessionx for session switching (C-o) - Mouse support - Inactive pane dimming (Tokyo Night colors) - VI copy mode, emacs command prompt Cherry-picked from older branches: - renumber-windows (v1) — auto-renumber when closing windows - synchronize-panes toggle: prefix+y (v3) — useful for multi-server work Removed (intentionally): - tmux-sensible (v1-v3) — ported needed settings directly - tmux-pain-control (v1-v3) — replaced by explicit bindings - tmux-continuum (v1) — resurrect alone is sufficient --- tmux.conf => tmux/tmux.conf | 103 ++++++++++++++-------------- tmux.mac.conf => tmux/tmux.mac.conf | 6 +- 2 files changed, 53 insertions(+), 56 deletions(-) rename tmux.conf => tmux/tmux.conf (51%) rename tmux.mac.conf => tmux/tmux.mac.conf (59%) diff --git a/tmux.conf b/tmux/tmux.conf similarity index 51% rename from tmux.conf rename to tmux/tmux.conf index b81808c..3c3df51 100644 --- a/tmux.conf +++ b/tmux/tmux.conf @@ -1,108 +1,105 @@ -# TPM plugin manager +# tmux configuration — David Stosik +# Requires: TPM (auto-installed by install.sh) + +# --- Plugins --- set -g @plugin 'tmux-plugins/tpm' -#set -g @plugin 'tmux-plugins/tmux-sensible' # I've ported what I need from this plugin to this file set -g @plugin 'tmux-plugins/tmux-resurrect' -#set -g @plugin 'tmux-plugins/tmux-sessionist' -#set -g @plugin 'tmux-plugins/tmux-pain-control' # Unnecessary? set -g @plugin 'omerxx/tmux-sessionx' -# Tokyo Night theme and config +# Tokyo Night theme set -g @plugin 'fabioluciano/tmux-tokyo-night' set -g @theme_variation 'night' set -g @theme_plugins 'datetime,battery' set -g @theme_transparent_status_bar 'true' -set -g @theme_left_separator '' -set -g @theme_right_separator '' -set -g @theme_transparent_left_separator_inverse '' -set -g @theme_transparent_right_separator_inverse '' +set -g @theme_left_separator '' +set -g @theme_right_separator '' +set -g @theme_transparent_left_separator_inverse '' +set -g @theme_transparent_right_separator_inverse '' set -g @theme_plugin_datetime_format '%m-%d %a | %H:%M' -# set -g status-justify centre # doesn't go well with the Tokyo Night theme - -# sessionx bindings -unbind C-o -set -g @sessionx-bind 'C-o' -bind-key -r O rotate-window - -# Unnecessary in modern systems -# set -s default-terminal "screen-256color" - +# --- General --- set-option -g display-time 1000 - -# Delay between prefix and command in ms (don't use 0) set -s escape-time 50 - -# refresh status more often set-option -g status-interval 5 - -setw -g monitor-activity on -#set -g visual-activity on - -set-option -g focus-events on - -# VI keys in Copy mode -setw -g mode-keys vi - -# emacs keys in command prompt (tmux-sensible) -set -g status-keys emacs - -# increase scrollback buffer size set-option -g history-limit 50000 - +set-option -g focus-events on set-window-option -g aggressive-resize on +setw -g monitor-activity on -# Prefix +# --- Keybindings --- + +# Prefix: Ctrl-A set -g prefix C-a unbind C-b bind C-a send-prefix -# Number windows and panes from 1 -set -g base-index 1 -setw -g pane-base-index 1 +# VI keys in copy mode, emacs keys in command prompt +setw -g mode-keys vi +set -g status-keys emacs +# Reload config bind r source-file ~/.tmux.conf \; display -d500 "Reloaded!" -bind c new-window -c "#{pane_current_path}" # Creates new windows in same directory -bind C new-window -c "~" # Creates new windows in home dir +# Windows +bind c new-window -c "#{pane_current_path}" +bind C new-window -c "~" +# Splits (intuitive: \ for vertical, - for horizontal) bind \\ split-window -h -c "#{pane_current_path}" bind - split-window -v -c "#{pane_current_path}" bind | split-window -h bind _ split-window -v - unbind % unbind '"' +# Pane navigation (vim-style) bind -r h select-pane -L bind -r j select-pane -D bind -r k select-pane -U bind -r l select-pane -R - unbind Left unbind Down unbind Up unbind Right +# Window navigation bind -r C-h select-window -t :- bind -r C-l select-window -t :+ +# Pane resizing bind -r H resize-pane -L 5 bind -r J resize-pane -D 5 bind -r K resize-pane -U 5 bind -r L resize-pane -R 5 -set -g mouse on - -# Distinguish inactive panes only, let theme handle active ones -setw -g window-style "bg=#16161e,fg=#787c99" # Darker background, dimmed text for inactive -setw -g window-active-style "bg=terminal,fg=terminal" # Let terminal/theme colors show through - +# Copy mode bind Escape copy-mode bind-key -T copy-mode-vi v send -X begin-selection bind-key -T copy-mode-vi y send -X copy-selection -# load macOS-specific settings +# Session switching (sessionx) +unbind C-o +set -g @sessionx-bind 'C-o' +bind-key -r O rotate-window + +# Toggle sync panes (from v3 — useful for multi-server work) +bind y set synchronize-panes\; display 'synchronize-panes #{?synchronize-panes,on,off}' + +# --- Numbering --- +set -g base-index 1 +setw -g pane-base-index 1 +set -g renumber-windows on + +# --- Mouse --- +set -g mouse on + +# --- Appearance --- +# Dim inactive panes (active pane uses terminal/theme colors) +setw -g window-style "bg=#16161e,fg=#787c99" +setw -g window-active-style "bg=terminal,fg=terminal" + +# --- Platform-specific --- if-shell "uname | grep -q Darwin" "source-file ~/.tmux.mac.conf" -# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) +# --- Initialize TPM (must be last line) --- run '~/.tmux/plugins/tpm/tpm' diff --git a/tmux.mac.conf b/tmux/tmux.mac.conf similarity index 59% rename from tmux.mac.conf rename to tmux/tmux.mac.conf index 031123d..02a1de3 100644 --- a/tmux.mac.conf +++ b/tmux/tmux.mac.conf @@ -1,5 +1,5 @@ +# macOS-specific tmux settings + +# Use pbcopy for copy-mode yanking unbind -T copy-mode-vi y bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy" - -#unbind p -#bind p paste-buffer From f648f0def6bd1f0726bd6e15195dede21b72a227 Mon Sep 17 00:00:00 2001 From: David Stosik Date: Mon, 2 Mar 2026 15:49:11 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20ghostty=20=E2=80=94=20move=20to=20X?= =?UTF-8?q?DG-standard=20config=20location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved Ghostty config from flat file to config/ghostty/config. Install.sh links to the correct platform-specific location: - macOS: ~/Library/Application Support/com.mitchellh.ghostty/config - Linux: ~/.config/ghostty/config No changes to the config itself — preserves v4 settings: - Tokyo Night theme (light/dark auto-switching) - Monaspace Argon font with all ligature features - 90% background opacity - Shift+Enter for newline --- ghostty.config => config/ghostty/config | 2 -- 1 file changed, 2 deletions(-) rename ghostty.config => config/ghostty/config (98%) diff --git a/ghostty.config b/config/ghostty/config similarity index 98% rename from ghostty.config rename to config/ghostty/config index 143f95c..57cb482 100644 --- a/ghostty.config +++ b/config/ghostty/config @@ -13,8 +13,6 @@ font-feature = ss08 font-feature = ss09 font-variation = wght=300 -# fi fl - window-inherit-font-size = false font-size = 13 From f0f8042d7563fd9c484c644c8c1b68c769e2c8ab Mon Sep 17 00:00:00 2001 From: David Stosik Date: Mon, 2 Mar 2026 15:49:36 +0900 Subject: [PATCH 5/5] feat: add install.sh and README install.sh: - Idempotent symlink installer (safe to re-run) - Backs up existing files before overwriting - Auto-installs TPM (tmux plugin manager) if missing - Handles Ghostty config path differences (macOS vs Linux) - Clear post-install instructions - Colored output for readability README.md: - What's included (tools and their config locations) - Prerequisites - Install instructions - Post-install steps - Local override files explanation - Full directory structure - Neovim plugin list - Design decisions and rationale --- README.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ install.sh | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 README.md create mode 100755 install.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7d237f --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# dotfiles + +My personal dotfiles. macOS primary, Linux compatible. + +## What's included + +| Tool | Config | Notes | +|------|--------|-------| +| **zsh** | `zsh/` | Prompt with git info, history, aliases, functions | +| **git** | `git/` | Modern defaults, useful aliases, pretty log | +| **tmux** | `tmux/` | C-a prefix, vim-style nav, Tokyo Night theme, TPM | +| **Ghostty** | `config/ghostty/` | Tokyo Night, Monaspace font, transparency | + +## Bootstrap + +Install tools first, then link dotfiles: + +```bash +git clone https://github.com/davidstosik/dotfiles ~/.dotfiles +cd ~/.dotfiles + +# 1. Install packages (neovim, gh, tmux, mise, ripgrep, fzf) +./mitamae/bootstrap.sh + +# 2. Link dotfiles +./install.sh +``` + +`mitamae/bootstrap.sh` downloads the [mitamae](https://github.com/itamae-kitchen/mitamae) binary for your platform and runs the recipe. mitamae's `package` resource auto-detects the package manager (Homebrew on macOS, apt on Linux), so the same recipe works everywhere. + +## Post-install + +1. **Restart your shell** (or `source ~/.zshrc`) +2. **tmux:** Press `C-a I` to install tmux plugins via TPM + +## Local overrides + +Machine-specific config goes in local files (not tracked by git): + +- **`~/.zshrc.local`** — extra shell config, env vars, work-specific paths +- **`~/.gitconfig.local`** — work email, signing keys, conditional includes + +Example `~/.gitconfig.local`: + +```gitconfig +[user] + email = david@work.com + +[includeIf "gitdir:~/work/"] + path = ~/work.gitconfig +``` + +## Structure + +``` +dotfiles/ +├── install.sh # Symlink installer +├── README.md +├── mitamae/ +│ ├── bootstrap.sh # Download mitamae + run recipe +│ └── recipe.rb # Package installation recipe +├── zsh/ +│ ├── zshrc # Main shell config +│ ├── aliases.zsh # Aliases (git, navigation, safety, ruby) +│ └── functions.zsh # Shell functions (mkcd, vpn-fix) +├── git/ +│ ├── gitconfig # Git configuration +│ └── gitignore # Global gitignore +├── tmux/ +│ ├── tmux.conf # tmux configuration +│ └── tmux.mac.conf # macOS-specific (pbcopy integration) +└── config/ + └── ghostty/ + └── config # Ghostty terminal config +``` + +## Design decisions + +- **mitamae for package installation** — single static binary (mruby compiled in), no Ruby/RubyGems needed. Chef-like DSL with `package` resource that auto-detects the package manager. One recipe works on macOS (Homebrew) and Linux (apt). Cross-platform from day one. +- **install.sh for symlinking** — plain symlinks, idempotent, zero dependencies beyond git and zsh. mitamae handles packages, install.sh handles links — clean separation of concerns. +- **No dotfiles framework** — chezmoi, yadm, etc. are overkill for this setup. mitamae + install.sh covers packages and links with minimal complexity. +- **mise over rbenv/nvm** — single tool for all language versions. +- **Local override files** — machine-specific config stays out of the repo. +- **macOS + Linux** — platform conditionals where needed (ls colors, vpn-fix, tmux copy). diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..5d6909b --- /dev/null +++ b/install.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env zsh +# install.sh — dotfiles installer +# Idempotent: safe to run multiple times. +# Usage: ./install.sh + +set -e + +DOTFILES_DIR="${0:a:h}" + +# --- Colors --- +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +info() { echo "${BLUE}→${NC} $1" } +ok() { echo "${GREEN}✓${NC} $1" } +warn() { echo "${YELLOW}!${NC} $1" } +err() { echo "${RED}✗${NC} $1" } + +# --- Helpers --- +link_file() { + local src="$1" + local dst="$2" + + if [[ -L "$dst" ]] && [[ "$(readlink "$dst")" == "$src" ]]; then + ok "Already linked: $dst" + return + fi + + if [[ -e "$dst" ]] || [[ -L "$dst" ]]; then + local backup="${dst}.backup.$(date +%Y%m%d%H%M%S)" + warn "Backing up existing $dst → $backup" + mv "$dst" "$backup" + fi + + mkdir -p "$(dirname "$dst")" + ln -sf "$src" "$dst" + ok "Linked: $dst → $src" +} + +# --- Main --- +echo "" +echo " ${BLUE}dotfiles installer${NC}" +echo " ${BLUE}==================${NC}" +echo "" + +# Shell +info "Linking zsh config..." +link_file "${DOTFILES_DIR}/zsh/zshrc" "${HOME}/.zshrc" + +# Git +info "Linking git config..." +link_file "${DOTFILES_DIR}/git/gitconfig" "${HOME}/.gitconfig" +link_file "${DOTFILES_DIR}/git/gitignore" "${HOME}/.gitignore" + +# tmux +info "Linking tmux config..." +link_file "${DOTFILES_DIR}/tmux/tmux.conf" "${HOME}/.tmux.conf" +link_file "${DOTFILES_DIR}/tmux/tmux.mac.conf" "${HOME}/.tmux.mac.conf" + +# Ghostty +info "Linking Ghostty config..." +if [[ "$OSTYPE" == "darwin"* ]]; then + ghostty_dir="${HOME}/Library/Application Support/com.mitchellh.ghostty" +else + ghostty_dir="${HOME}/.config/ghostty" +fi +link_file "${DOTFILES_DIR}/config/ghostty/config" "${ghostty_dir}/config" + +# TPM (tmux plugin manager) +if [[ ! -d "${HOME}/.tmux/plugins/tpm" ]]; then + info "Installing TPM (tmux plugin manager)..." + git clone https://github.com/tmux-plugins/tpm "${HOME}/.tmux/plugins/tpm" + ok "TPM installed" +else + ok "TPM already installed" +fi + +echo "" +echo " ${GREEN}Done!${NC}" +echo "" +echo " Next steps:" +echo " 1. Restart your shell (or: source ~/.zshrc)" +echo " 2. Open tmux and press ${YELLOW}prefix + I${NC} to install tmux plugins" +echo "" +echo " Optional:" +echo " • Create ${YELLOW}~/.zshrc.local${NC} for machine-specific shell config" +echo " • Create ${YELLOW}~/.gitconfig.local${NC} for machine-specific git config" +echo ""