Skip to content

Instantly share code, notes, and snippets.

@crstnmac
Last active March 22, 2025 10:48
Show Gist options
  • Save crstnmac/1afafc0470df374bb8e0e7b2936b3039 to your computer and use it in GitHub Desktop.
Save crstnmac/1afafc0470df374bb8e0e7b2936b3039 to your computer and use it in GitHub Desktop.
#!/bin/bash
# macOS Fullstack Developer Setup Script
# This script sets up a macOS environment for fullstack development with zsh completions
# Enhanced with senior developer tooling and configurations
# Exit on error
set -e
echo "🚀 Starting macOS Fullstack Developer Setup..."
# Check if Homebrew is installed, if not install it
if ! command -v brew &> /dev/null; then
echo "🍺 Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Add Homebrew to PATH for the current session
if [[ $(uname -m) == "arm64" ]]; then
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
else
echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/usr/local/bin/brew shellenv)"
fi
else
echo "🍺 Homebrew already installed, updating..."
brew update
fi
# Install Git
echo "📦 Installing Git..."
brew install git
# Install Oh My Zsh if not already installed
if [ ! -d "$HOME/.oh-my-zsh" ]; then
echo "🔧 Installing Oh My Zsh..."
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
else
echo "✅ Oh My Zsh already installed"
fi
# IMPROVED: Function to safely install or update a zsh plugin
install_or_update_plugin() {
local plugin_name=$1
local plugin_url=$2
local plugin_dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/$plugin_name"
if [ -d "$plugin_dir" ]; then
echo "🔄 Updating $plugin_name..."
cd "$plugin_dir" && git pull origin master
else
echo "🔧 Installing $plugin_name..."
git clone "$plugin_url" "$plugin_dir"
fi
}
# IMPROVED: Install or update zsh plugins
echo "🔧 Setting up zsh plugins..."
install_or_update_plugin "zsh-syntax-highlighting" "https://github.com/zsh-users/zsh-syntax-highlighting.git"
install_or_update_plugin "zsh-autosuggestions" "https://github.com/zsh-users/zsh-autosuggestions.git"
install_or_update_plugin "fzf-tab" "https://github.com/Aloxaf/fzf-tab.git"
install_or_update_plugin "zsh-nvm" "https://github.com/lukechilds/zsh-nvm.git"
# IMPROVED: Install or update Powerlevel10k theme
POWERLEVEL10K_DIR="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k"
if [ -d "$POWERLEVEL10K_DIR" ]; then
echo "🔄 Updating Powerlevel10k theme..."
cd "$POWERLEVEL10K_DIR" && git pull
else
echo "🔧 Installing Powerlevel10k theme..."
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$POWERLEVEL10K_DIR"
fi
# IMPROVED: Install Node.js version manager (nvm) if not installed
export NVM_DIR="$HOME/.nvm"
if [ ! -d "$NVM_DIR" ]; then
echo "🟢 Installing Node Version Manager (nvm)..."
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
else
echo "✅ nvm already installed"
fi
# Load nvm if installed
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# Check if Node.js LTS is installed, if not install it
if ! command -v node &> /dev/null || [ "$(node --version)" != "$(nvm version 'lts/*')" ]; then
echo "🟢 Installing Node.js LTS..."
nvm install --lts
nvm use --lts
nvm alias default 'lts/*'
else
echo "✅ Node.js LTS already installed: $(node --version)"
fi
# Install global npm packages
echo "📦 Installing global npm packages..."
npm install -g yarn typescript ts-node nodemon serve http-server pnpm nx @nestjs/cli vite turbo next vercel netlify-cli prisma
# IMPROVED: Install Python via pyenv if not installed
if ! command -v pyenv &> /dev/null; then
echo "🐍 Installing Python via pyenv..."
brew install pyenv
# Set up pyenv in profile files if not already there
if ! grep -q "PYENV_ROOT" ~/.zprofile; then
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile
echo 'eval "$(pyenv init -)"' >> ~/.zprofile
fi
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
# Install Python if not installed
if ! pyenv versions | grep -q "3.11"; then
pyenv install 3.11
pyenv global 3.11
fi
else
echo "✅ pyenv already installed"
# Check if Python 3.11 is installed
if ! pyenv versions | grep -q "3.11"; then
echo "🐍 Installing Python 3.11..."
pyenv install 3.11
pyenv global 3.11
else
echo "✅ Python 3.11 already installed"
fi
fi
# Install pip packages
echo "📦 Installing pip packages..."
pip install --upgrade pip
pip install pipenv virtualenv poetry black flake8 pylint mypy pytest python-dotenv fastapi django flask sqlalchemy alembic jupyterlab
# IMPROVED: Install applications via brew only if not already installed
brew_install() {
if ! brew list "$1" &>/dev/null; then
echo "📦 Installing $1..."
brew install "$@"
else
echo "✅ $1 already installed"
fi
}
brew_install_cask() {
# Normalize app name for checking (handle spaces in app names)
local app_name=$(brew info --cask "$1" | grep -m 1 "$(brew --prefix)/Caskroom" | awk -F'/' '{print $NF}' | sed 's/.*\///' 2>/dev/null)
# If we couldn't get the app name from brew info, use the cask name
if [ -z "$app_name" ]; then
app_name="$1"
fi
# Check if the app is already installed by looking for its .app bundle
if ! [ -d "/Applications/${app_name}.app" ] && ! [ -d "/Applications/ ${app_name}.app" ]; then
echo "📦 Installing $1..."
brew install --cask "$@"
else
echo "✅ $1 already installed"
fi
}
# Install database tools
echo "📊 Installing database tools..."
brew_install postgresql
brew_install mysql
brew_install sqlite
brew_install redis
brew_install mongodb-atlas
brew_install cockroachdb/tap/cockroach
brew_install_cask pgadmin4
brew_install_cask mongodb-compass
brew_install_cask dbeaver-community
# Install Docker
echo "🐳 Installing Docker..."
brew_install_cask docker
# Install Visual Studio Code
echo "💻 Installing Visual Studio Code..."
brew_install_cask visual-studio-code
# Install other useful dev tools
echo "🧰 Installing additional development tools..."
TOOLS="jq wget curl htop tree cmake grep gnu-sed tmux gh ripgrep fd bat fzf lazygit lazydocker neovim starship delta tldr xh helm kubectl kubectx stern k9s dive rbenv"
for tool in $TOOLS; do
brew_install $tool
done
# Configure zsh
echo "⚙️ Configuring zsh..."
ZSH_RC_FILE="$HOME/.zshrc"
# Backup existing .zshrc
if [ -f "$ZSH_RC_FILE" ]; then
echo "📄 Backing up existing .zshrc to .zshrc.backup.$(date +%s)"
cp "$ZSH_RC_FILE" "$ZSH_RC_FILE.backup.$(date +%s)"
fi
# Configure zsh plugins
cat > "$ZSH_RC_FILE" <<EOL
# Path to your oh-my-zsh installation
export ZSH="\$HOME/.oh-my-zsh"
# Set theme to Powerlevel10k
ZSH_THEME="powerlevel10k/powerlevel10k"
# Configure plugins
plugins=(
git
docker
docker-compose
npm
yarn
node
python
pip
macos
vscode
zsh-syntax-highlighting
zsh-autosuggestions
fzf-tab
zsh-nvm
kubectl
helm
kubectx
rust
golang
brew
gh
tmux
aws
terraform
extract
copypath
dirhistory
history-substring-search
colored-man-pages
)
source \$ZSH/oh-my-zsh.sh
# User configuration
export LANG=en_US.UTF-8
# NVM setup
export NVM_DIR="\$HOME/.nvm"
[ -s "\$NVM_DIR/nvm.sh" ] && \. "\$NVM_DIR/nvm.sh"
[ -s "\$NVM_DIR/bash_completion" ] && \. "\$NVM_DIR/bash_completion"
# Python pyenv setup
export PYENV_ROOT="\$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="\$PYENV_ROOT/bin:\$PATH"
eval "\$(pyenv init -)"
# Load additional completions
autoload -Uz compinit && compinit
# Useful aliases
alias ll="ls -la"
alias gs="git status"
alias gc="git commit"
alias gp="git push"
alias gl="git pull"
alias gd="git diff"
alias dev="cd ~/Development"
# Custom functions
mkcd() {
mkdir -p "\$1" && cd "\$1"
}
# Auto suggestions configuration
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=240'
# FZF configuration
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="\$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND="fd --type d --hidden --follow --exclude .git"
export FZF_DEFAULT_OPTS="--height 40% --layout=reverse --border --preview 'bat --color=always {}'"
# Starship prompt (uncomment to use instead of Powerlevel10k)
# eval "\$(starship init zsh)"
# Use exa instead of ls
if command -v exa &> /dev/null; then
alias ls="exa --icons --group-directories-first"
alias ll="exa --icons --group-directories-first -l"
alias la="exa --icons --group-directories-first -la"
alias lt="exa --icons --group-directories-first -T"
alias lta="exa --icons --group-directories-first -Ta"
fi
# Use bat instead of cat
if command -v bat &> /dev/null; then
alias cat="bat --paging=never"
fi
# Advanced git aliases
alias glog="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
alias gco="git checkout"
alias gca="git commit -a"
alias gcam="git commit -am"
alias gst="git status -sb"
alias gdf="git diff --color | diff-so-fancy"
alias gprune="git branch --merged | grep -v '\*\|master\|main\|develop' | xargs -n 1 git branch -d"
# Docker aliases
alias dps="docker ps"
alias dls="docker container ls"
alias dcup="docker-compose up -d"
alias dcdown="docker-compose down"
alias dclogs="docker-compose logs -f"
# Kubernetes aliases
alias k="kubectl"
alias kgp="kubectl get pods"
alias kgs="kubectl get services"
alias kgd="kubectl get deployments"
alias kns="kubens"
alias kctx="kubectx"
# Development directory shortcuts
alias projects="cd ~/Development/projects"
alias work="cd ~/Development/work"
alias personal="cd ~/Development/personal"
alias opensource="cd ~/Development/opensource"
# Terminal productivity
alias zshconfig="code ~/.zshrc"
alias ohmyzsh="code ~/.oh-my-zsh"
alias reload="source ~/.zshrc"
alias c="clear"
alias h="history"
alias path='echo \$PATH | tr ":" "\n"'
# Advanced functions
function clone() {
git clone "\$1" && cd "\$(basename "\$1" .git)"
}
function httpserver() {
local port="\${1:-8000}"
python -m http.server "\$port"
}
function extract() {
if [ -f \$1 ] ; then
case \$1 in
*.tar.bz2) tar xjf \$1 ;;
*.tar.gz) tar xzf \$1 ;;
*.bz2) bunzip2 \$1 ;;
*.rar) unrar e \$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
else
echo "'\$1' is not a valid file"
fi
}
# NVM lazy loading to improve shell startup time
nvm() {
unset -f nvm
export NVM_DIR="\$HOME/.nvm"
[ -s "\$NVM_DIR/nvm.sh" ] && \. "\$NVM_DIR/nvm.sh"
nvm "\$@"
}
# Directory jumping with z
[ -f \$(brew --prefix)/etc/profile.d/z.sh ] && source \$(brew --prefix)/etc/profile.d/z.sh
EOL
# Set up Development folder
echo "📁 Creating Development folder..."
mkdir -p ~/Development
# IMPROVED: Setup git configuration if not already configured
echo "⚙️ Setting up Git configuration..."
if [ -z "$(git config --global user.name)" ]; then
read -p "Enter your Git user name: " git_username
git config --global user.name "$git_username"
else
echo "✅ Git username already configured: $(git config --global user.name)"
fi
if [ -z "$(git config --global user.email)" ]; then
read -p "Enter your Git email: " git_email
git config --global user.email "$git_email"
else
echo "✅ Git email already configured: $(git config --global user.email)"
fi
# Set some sensible Git defaults if not already set
git config --global init.defaultBranch main
git config --global core.editor "code --wait"
git config --global pull.rebase false
# Function to install VS Code extensions if not already installed
install_vscode_extension() {
if ! code --list-extensions | grep -q "$1"; then
echo "🧩 Installing VS Code extension: $1"
code --install-extension "$1"
else
echo "✅ VS Code extension already installed: $1"
fi
}
# Set up VS Code extensions
echo "🧩 Installing VS Code extensions..."
# JavaScript/TypeScript Development
install_vscode_extension dbaeumer.vscode-eslint
install_vscode_extension esbenp.prettier-vscode
install_vscode_extension ms-vscode.vscode-typescript-next
install_vscode_extension dsznajder.es7-react-js-snippets
install_vscode_extension bradlc.vscode-tailwindcss
install_vscode_extension styled-components.vscode-styled-components
install_vscode_extension svelte.svelte-vscode
install_vscode_extension chakrounanas.turbo-console-log
install_vscode_extension jock.svg
install_vscode_extension wix.vscode-import-cost
install_vscode_extension xabikos.JavaScriptSnippets
install_vscode_extension rvest.vs-code-prettier-eslint
# Python Development
install_vscode_extension ms-python.python
install_vscode_extension ms-python.vscode-pylance
install_vscode_extension ms-python.black-formatter
install_vscode_extension ms-toolsai.jupyter
install_vscode_extension njpwerner.autodocstring
# General Web Development
install_vscode_extension ritwickdey.LiveServer
install_vscode_extension formulahendry.auto-rename-tag
install_vscode_extension mikestead.dotenv
install_vscode_extension firefox-devtools.vscode-firefox-debug
# DevOps & Cloud
install_vscode_extension ms-azuretools.vscode-docker
install_vscode_extension ms-kubernetes-tools.vscode-kubernetes-tools
install_vscode_extension redhat.vscode-yaml
install_vscode_extension HashiCorp.terraform
install_vscode_extension ms-vscode-remote.remote-containers
install_vscode_extension ms-vscode-remote.remote-ssh
# Database
install_vscode_extension mtxr.sqltools
install_vscode_extension cweijan.vscode-mysql-client2
install_vscode_extension mongodb.mongodb-vscode
# Git Integration
install_vscode_extension eamodio.gitlens
install_vscode_extension mhutchie.git-graph
install_vscode_extension donjayamanne.githistory
# AI Assistants
install_vscode_extension GitHub.copilot
install_vscode_extension GitHub.copilot-chat
# Productivity & UI
install_vscode_extension vscodevim.vim
install_vscode_extension wayou.vscode-todo-highlight
install_vscode_extension usernamehw.errorlens
install_vscode_extension streetsidesoftware.code-spell-checker
install_vscode_extension aaron-bond.better-comments
install_vscode_extension yzhang.markdown-all-in-one
install_vscode_extension bierner.markdown-preview-github-styles
install_vscode_extension PKief.material-icon-theme
install_vscode_extension sdras.night-owl
# Testing
install_vscode_extension orta.vscode-jest
install_vscode_extension rangav.vscode-thunder-client
install_vscode_extension ms-playwright.playwright
# Advanced Languages & Frameworks
install_vscode_extension golang.go
install_vscode_extension rust-lang.rust-analyzer
install_vscode_extension redhat.java
install_vscode_extension graphql.vscode-graphql
# Performance & Code Quality
install_vscode_extension wmaurer.change-case
install_vscode_extension christian-kohler.path-intellisense
install_vscode_extension naumovs.color-highlight
install_vscode_extension VisualStudioExptTeam.vscodeintellicode
install_vscode_extension SonarSource.sonarlint-vscode
# IMPROVED: Skip setting macOS preferences if already set
echo "⚙️ Setting macOS preferences..."
if [ "$(defaults read com.apple.finder AppleShowAllFiles)" != "YES" ]; then
# Show hidden files
defaults write com.apple.finder AppleShowAllFiles YES
echo "✅ Set Finder to show hidden files"
else
echo "✅ Finder already configured to show hidden files"
fi
if [ "$(defaults read com.apple.finder ShowPathbar)" != "1" ]; then
# Show path bar in Finder
defaults write com.apple.finder ShowPathbar -bool true
echo "✅ Set Finder to show path bar"
else
echo "✅ Finder already configured to show path bar"
fi
if [ "$(defaults read com.apple.finder ShowStatusBar)" != "1" ]; then
# Show status bar in Finder
defaults write com.apple.finder ShowStatusBar -bool true
echo "✅ Set Finder to show status bar"
else
echo "✅ Finder already configured to show status bar"
fi
if [ "$(defaults read com.apple.desktopservices DSDontWriteNetworkStores)" != "1" ]; then
# Avoid creating .DS_Store files on network volumes
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
echo "✅ Configured to avoid creating .DS_Store files on network volumes"
else
echo "✅ Already configured to avoid creating .DS_Store files on network volumes"
fi
# Restart Finder to apply changes
killall Finder &> /dev/null || true
# IMPROVED: Install Rust if not installed
if ! command -v rustc &> /dev/null; then
echo "🦀 Installing Rust..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
else
echo "✅ Rust already installed"
fi
# IMPROVED: Install Go if not installed
if ! command -v go &> /dev/null; then
echo "🐹 Installing Go..."
brew install go
mkdir -p $HOME/go/{bin,src,pkg}
if ! grep -q "GOPATH" ~/.zprofile; then
echo 'export GOPATH=$HOME/go' >> ~/.zprofile
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.zprofile
fi
else
echo "✅ Go already installed"
fi
# IMPROVED: Install AWS CLI if not installed
if ! command -v aws &> /dev/null; then
echo "☁️ Installing AWS CLI..."
brew install awscli
else
echo "✅ AWS CLI already installed"
fi
# IMPROVED: Install Terraform if not installed
if ! command -v terraform &> /dev/null; then
echo "🏗️ Installing Terraform..."
brew install terraform
else
echo "✅ Terraform already installed"
fi
# IMPROVED: Install language servers for better code intelligence
echo "📚 Installing language servers for better code intelligence..."
npm list -g typescript-language-server &> /dev/null || npm install -g typescript-language-server typescript
npm list -g @angular/language-server &> /dev/null || npm install -g @angular/language-server
npm list -g vscode-langservers-extracted &> /dev/null || npm install -g vscode-langservers-extracted
npm list -g graphql-language-service-cli &> /dev/null || npm install -g graphql-language-service-cli
# Check if gopls is installed
if ! command -v gopls &> /dev/null; then
if command -v go &> /dev/null; then
go install golang.org/x/tools/gopls@latest
fi
fi
# Check if rust-analyzer is installed
if command -v cargo &> /dev/null; then
if ! command -v rust-analyzer &> /dev/null; then
cargo install rust-analyzer
fi
fi
# IMPROVED: Install tmux configuration if not exists
echo "🧩 Setting up tmux configuration..."
if [ ! -f "$HOME/.tmux.conf" ]; then
cat > "$HOME/.tmux.conf" <<EOL
# Improve colors
set -g default-terminal "screen-256color"
set -ga terminal-overrides ",*256col*:Tc"
# Set prefix to Ctrl+Space
unbind C-b
set -g prefix C-Space
bind Space send-prefix
# Start window numbering at 1
set -g base-index 1
set -g pane-base-index 1
# Reload config file
bind r source-file ~/.tmux.conf \; display "Config reloaded!"
# Split panes using | and -
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# Switch panes using Alt-arrow without prefix
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
# Enable mouse mode
set -g mouse on
# Don't rename windows automatically
set-option -g allow-rename off
# Increase history limit
set-option -g history-limit 50000
# Enable vi mode
setw -g mode-keys vi
# Setup 'v' to begin selection as in Vim
bind-key -T copy-mode-vi v send -X begin-selection
bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel "pbcopy"
# Status bar
set -g status-position bottom
set -g status-justify left
set -g status-style 'bg=colour234 fg=colour137'
set -g status-left '#[fg=colour233,bg=colour245] #S #[bg=colour234] '
set -g status-right '#[fg=colour233,bg=colour245] %d/%m #[fg=colour233,bg=colour245] %H:%M:%S '
set -g status-right-length 50
set -g status-left-length 20
EOL
echo "✅ Created new tmux configuration"
else
echo "✅ tmux configuration already exists"
fi
# IMPROVED: Install Neovim configuration if not exists
echo "📝 Setting up Neovim configuration..."
NVIM_CONFIG_DIR="$HOME/.config/nvim"
if [ ! -f "$NVIM_CONFIG_DIR/init.vim" ]; then
mkdir -p "$NVIM_CONFIG_DIR"
cat > "$NVIM_CONFIG_DIR/init.vim" <<EOL
" General Settings
set number relativenumber
set expandtab
set tabstop=2
set shiftwidth=2
set softtabstop=2
set smartindent
set autoindent
set wrap
set linebreak
set incsearch
set ignorecase
set smartcase
set showmatch
set hlsearch
set wildmenu
set wildmode=list:longest
set cursorline
set mouse=a
set clipboard=unnamed
set backspace=indent,eol,start
set hidden
set nobackup
set nowritebackup
set cmdheight=2
set updatetime=300
set shortmess+=c
set signcolumn=yes
set termguicolors
set scrolloff=8
set noshowmode
set completeopt=menuone,noinsert,noselect
set splitbelow
set splitright
" Key Mappings
let mapleader = " "
nnoremap <leader>ff <cmd>Telescope find_files<cr>
nnoremap <leader>fg <cmd>Telescope live_grep<cr>
nnoremap <leader>fb <cmd>Telescope buffers<cr>
nnoremap <leader>fh <cmd>Telescope help_tags<cr>
nnoremap <leader>e :NvimTreeToggle<CR>
nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
nnoremap <leader>h :noh<CR>
nnoremap <leader>sv :source $MYVIMRC<CR>
" Auto install vim-plug
let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim'
if empty(glob(data_dir . '/autoload/plug.vim'))
silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
" Plugins
call plug#begin('~/.vim/plugged')
Plug 'neovim/nvim-lspconfig'
Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-telescope/telescope.nvim'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
Plug 'kyazdani42/nvim-web-devicons'
Plug 'kyazdani42/nvim-tree.lua'
Plug 'folke/tokyonight.nvim'
Plug 'tpope/vim-fugitive'
Plug 'hrsh7th/nvim-cmp'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-path'
Plug 'hrsh7th/cmp-cmdline'
Plug 'saadparwaiz1/cmp_luasnip'
Plug 'L3MON4D3/LuaSnip'
Plug 'windwp/nvim-autopairs'
Plug 'lewis6991/gitsigns.nvim'
Plug 'hoob3rt/lualine.nvim'
Plug 'folke/which-key.nvim'
call plug#end()
" Theme settings
colorscheme tokyonight
" Auto-install missing plugins
autocmd VimEnter *
\ if len(filter(values(g:plugs), '!isdirectory(v:val.dir)'))
\| PlugInstall --sync | q
\| endif
EOL
echo "✅ Created new Neovim configuration"
else
echo "✅ Neovim configuration already exists"
fi
# IMPROVED: Set up global Git hooks template if not exists
HOOKS_DIR="$HOME/.git-templates/hooks"
if [ ! -d "$HOOKS_DIR" ]; then
echo "🔧 Setting up Git hooks template..."
mkdir -p "$HOOKS_DIR"
# Create pre-commit hook template
cat > "$HOOKS_DIR/pre-commit" <<EOL
#!/bin/sh
# Check for trailing whitespace
if git diff --cached --name-only | xargs grep --with-filename -n '[[:space:]] > /tmp/whitespace.txt 2>&1; then
echo "Error: Trailing whitespace found in the following files:"
cat /tmp/whitespace.txt
echo "Please remove trailing whitespace before committing."
exit 1
fi
# Check for large files
MAX_SIZE=5000000 # 5MB
for file in $(git diff --cached --name-only); do
size=$(git cat-file -s :$file 2>/dev/null)
if [ "$size" -gt "$MAX_SIZE" ]; then
echo "Error: $file is $size bytes, which exceeds the $MAX_SIZE byte limit."
echo "Consider using Git LFS for large files."
exit 1
fi
done
exit 0
EOL
chmod +x "$HOOKS_DIR/pre-commit"
# Set up the global git hooks template
git config --global init.templatedir '~/.git-templates'
git config --global core.hooksPath '~/.git-templates/hooks'
echo "✅ Git hooks template created"
else
echo "✅ Git hooks template already exists"
fi
# IMPROVED: Setup global .gitignore if not exists
GITIGNORE_GLOBAL="$HOME/.gitignore_global"
if [ ! -f "$GITIGNORE_GLOBAL" ]; then
echo "🔧 Setting up global .gitignore..."
cat > "$GITIGNORE_GLOBAL" <<EOL
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# IDE and editor files
.idea/
.vscode/
*.sublime-project
*.sublime-workspace
.vs/
*.swp
*.swo
*~
.project
.settings/
.classpath
.factorypath
# Node.js
node_modules/
npm-debug.log
yarn-error.log
.pnp/
.pnp.js
.npm/
.yarn/
.yarnrc
.yarn-integrity
# Python
__pycache__/
*.py[cod]
*$py.class
.Python
env/
venv/
ENV/
.env
.venv
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Java
*.class
.mtj.tmp/
*.jar
*.war
*.ear
hs_err_pid*
# Logs and databases
*.log
*.sqlite
*.sqlite3
*.db
# Build outputs
/build/
/dist/
/out/
/target/
.coverage
coverage/
.nyc_output/
# Local configuration files
.env.local
.env.development.local
.env.test.local
.env.production.local
EOL
git config --global core.excludesfile "$GITIGNORE_GLOBAL"
echo "✅ Global .gitignore created"
else
echo "✅ Global .gitignore already exists"
fi
# IMPROVED: Create a powerlevel10k configuration if not exists
P10K_CONFIG="$HOME/.p10k.zsh"
if [ ! -f "$P10K_CONFIG" ]; then
echo "🔧 Setting up Powerlevel10k configuration..."
cat > "$P10K_CONFIG" <<EOL
# Powerlevel10k configuration
# For customization, run \`p10k configure\` or edit this file.
# See: https://github.com/romkatv/powerlevel10k
'builtin' 'local' '-a' 'p10k_config_opts'
[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases')
[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob')
[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand')
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
() {
emulate -L zsh -o extended_glob
unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR'
# Prompt type
typeset -g POWERLEVEL9K_MODE=nerdfont-complete
# Left/right prompt segments
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
os_icon # OS identifier
dir # Current directory
vcs # Git status
prompt_char # Prompt symbol
)
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(
status # Exit code
command_execution_time # Command execution time
background_jobs # Jobs running in the background
direnv # direnv status
node_version # Node.js version
go_version # Go version
rust_version # Rust version
python_version # Python version
time # Current time
)
# Basic style options
typeset -g POWERLEVEL9K_BACKGROUND= # Transparent background
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='❯'
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='❮'
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_FOREGROUND=76
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_FOREGROUND=76
# Configure directory element
typeset -g POWERLEVEL9K_DIR_FOREGROUND=31
typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=103
typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=39
typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=40
typeset -g POWERLEVEL9K_DIR_WRITABLE_FORBIDDEN_FOREGROUND=203
# Time format
typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}'
# Command execution time
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=3
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=2
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=248
# VCS configuration
typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND=76
typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND=178
typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND=39
# Status indicators
typeset -g POWERLEVEL9K_STATUS_OK=false
typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND=196
# Truncate segments
typeset -g POWERLEVEL9K_TRUNCATE_PROMPT=true
# Icon settings
typeset -g POWERLEVEL9K_VISUAL_IDENTIFIER_EXPANSION='${P9K_VISUAL_IDENTIFIER}'
}
# Source the theme (this should be at the END of .zshrc)
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
EOL
echo "✅ Powerlevel10k configuration created"
else
echo "✅ Powerlevel10k configuration already exists"
fi
# IMPROVED: Setup SSH key for GitHub only if needed
echo "🔑 Setting up SSH key for GitHub..."
if [ ! -f "$HOME/.ssh/github_ed25519" ]; then
read -p "Enter email for GitHub SSH key (or press Enter to skip): " github_email
if [ -n "$github_email" ]; then
ssh-keygen -t ed25519 -C "$github_email" -f ~/.ssh/github_ed25519 -N ""
eval "$(ssh-agent -s)"
# Create or update SSH config
SSH_CONFIG="$HOME/.ssh/config"
mkdir -p "$HOME/.ssh"
touch "$SSH_CONFIG"
if ! grep -q "github.com" "$SSH_CONFIG"; then
echo "Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/github_ed25519" >> "$SSH_CONFIG"
fi
ssh-add -K ~/.ssh/github_ed25519 2>/dev/null || ssh-add ~/.ssh/github_ed25519
echo "✅ SSH key generated. Add this public key to your GitHub account:"
cat ~/.ssh/github_ed25519.pub
echo "Would you like to copy this to your clipboard? (y/n)"
read copy_to_clipboard
if [[ $copy_to_clipboard =~ ^[Yy]$ ]]; then
pbcopy < ~/.ssh/github_ed25519.pub
echo "✅ Public key copied to clipboard"
fi
else
echo "⏩ GitHub SSH key setup skipped"
fi
else
echo "✅ GitHub SSH key already exists"
fi
# IMPROVED: Install applications with checks
echo "🛠️ Installing development applications..."
# Docker Desktop
if ! [ -d "/Applications/Docker.app" ]; then
echo "🐳 Installing Docker Desktop..."
brew_install_cask docker
else
echo "✅ Docker Desktop already installed"
fi
# Postman
if ! [ -d "/Applications/Postman.app" ]; then
echo "📮 Installing Postman..."
brew_install_cask postman
else
echo "✅ Postman already installed"
fi
# Insomnia
if ! [ -d "/Applications/Insomnia.app" ]; then
echo "🔄 Installing Insomnia API Client..."
brew_install_cask insomnia
else
echo "✅ Insomnia already installed"
fi
# Install Minikube for local Kubernetes
if ! command -v minikube &> /dev/null; then
echo "☸️ Installing Minikube..."
brew_install minikube
else
echo "✅ Minikube already installed"
fi
# Install Cloud CLI tools
echo "☁️ Installing Cloud CLI tools..."
brew_install azure-cli
brew tap heroku/brew &> /dev/null || true
brew_install heroku
brew_install google-cloud-sdk
# Install Vagrant for VM management
if ! command -v vagrant &> /dev/null; then
echo "📦 Installing Vagrant..."
brew_install_cask vagrant vagrant-manager
else
echo "✅ Vagrant already installed"
fi
# Install mkcert for local HTTPS development
if ! command -v mkcert &> /dev/null; then
echo "🔒 Installing mkcert for local HTTPS development..."
brew_install mkcert nss
mkcert -install
else
echo "✅ mkcert already installed"
fi
# Install Xcode command line tools if not already installed
if ! xcode-select -p &> /dev/null; then
echo "🛠 Installing Xcode command line tools..."
xcode-select --install
else
echo "✅ Xcode command line tools already installed"
fi
# Install additional programming languages
echo "🌐 Installing additional programming languages..."
# Install Java via SDKMan if not installed
if ! command -v sdk &> /dev/null; then
echo "☕ Installing Java via SDKMan..."
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java
else
echo "✅ SDKMan already installed"
# Ensure Java is installed
source "$HOME/.sdkman/bin/sdkman-init.sh" &> /dev/null || true
if ! command -v java &> /dev/null; then
sdk install java
else
echo "✅ Java already installed: $(java -version 2>&1 | head -n 1)"
fi
fi
# Install Ruby via rbenv if not already the correct version
if ! command -v rbenv &> /dev/null; then
echo "💎 Installing rbenv for Ruby version management..."
brew_install rbenv
eval "$(rbenv init -)"
rbenv install 3.2.2
rbenv global 3.2.2
else
echo "✅ rbenv already installed"
# Check if Ruby 3.2.2 is installed
if ! rbenv versions | grep -q "3.2.2"; then
echo "💎 Installing Ruby 3.2.2..."
rbenv install 3.2.2
rbenv global 3.2.2
else
echo "✅ Ruby 3.2.2 already installed"
fi
fi
# Install common Ruby gems
if command -v rbenv &> /dev/null; then
echo "💎 Installing common Ruby gems..."
# Ensure rbenv is initialized and we're using the rbenv Ruby
eval "$(rbenv init -)"
# Verify we're using rbenv Ruby and not system Ruby
if [[ $(which ruby) == *".rbenv"* ]]; then
gem list | grep -q "bundler" || gem install bundler
gem list | grep -q "solargraph" || gem install solargraph
gem list | grep -q "rubocop" || gem install rubocop
gem list | grep -q "rails" || gem install rails
gem list | grep -q "foreman" || gem install foreman
else
echo "⚠️ Not using rbenv Ruby. Skipping gem installations to avoid permission issues."
echo " After the script completes, run: rbenv init && gem install bundler solargraph rubocop rails foreman"
fi
else
echo "⚠️ rbenv not found, skipping gem installations"
fi
# Install Elixir
if ! command -v elixir &> /dev/null; then
echo "💧 Installing Elixir..."
brew_install elixir
else
echo "✅ Elixir already installed"
fi
# Install Lua
if ! command -v lua &> /dev/null; then
echo "🌙 Installing Lua..."
brew_install lua luarocks
else
echo "✅ Lua already installed"
fi
# Install Kotlin
if ! command -v kotlin &> /dev/null; then
echo "🏝️ Installing Kotlin..."
brew_install kotlin
else
echo "✅ Kotlin already installed"
fi
# Setup direnv for environment management
if ! command -v direnv &> /dev/null; then
echo "🔧 Installing direnv for environment management..."
brew_install direnv
if ! grep -q "direnv hook zsh" ~/.zshrc; then
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
fi
else
echo "✅ direnv already installed"
fi
# Install iTerm2 with a nice color scheme
if ! [ -d "/Applications/iTerm.app" ]; then
echo "💻 Installing iTerm2..."
brew_install_cask iterm2
else
echo "✅ iTerm2 already installed"
fi
# Download and install nice programming fonts
echo "🔤 Installing programming fonts..."
brew tap homebrew/cask-fonts &>/dev/null || true
brew_install_cask font-fira-code-nerd-font
brew_install_cask font-jetbrains-mono-nerd-font
brew_install_cask font-hack-nerd-font
# Setup GPG for signed commits
if ! command -v gpg &> /dev/null; then
echo "🔏 Setting up GPG for signed commits..."
brew_install gnupg pinentry-mac
mkdir -p ~/.gnupg
echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" > ~/.gnupg/gpg-agent.conf
chmod 700 ~/.gnupg
if ! grep -q "GPG_TTY" ~/.zshrc; then
echo 'export GPG_TTY=$(tty)' >> ~/.zshrc
fi
else
echo "✅ GPG already installed"
fi
# Install browser development tools
echo "🌐 Installing development browsers..."
brew_install_cask firefox
brew_install_cask firefox@developer-edition
brew_install_cask google-chrome@canary
brew_install_cask brave-browser
# Install Responsively App for responsive web development
if ! [ -d "/Applications/ResponsivelyApp.app" ]; then
echo "📱 Installing Responsively App..."
brew_install_cask responsively
else
echo "✅ Responsively App already installed"
fi
# Install ngrok for exposing localhost to the internet
if ! command -v ngrok &> /dev/null; then
echo "🌍 Installing ngrok..."
brew_install ngrok
else
echo "✅ ngrok already installed"
fi
# Install GitHub CLI extensions
if command -v gh &> /dev/null; then
# Check if authenticated with GitHub CLI
if gh auth status &>/dev/null; then
echo "🔄 Installing GitHub CLI extensions..."
gh extension list | grep -q "gh-copilot" || gh extension install github/gh-copilot
gh extension list | grep -q "gh-dash" || gh extension install dlvhdr/gh-dash
else
echo "⚠️ GitHub CLI not authenticated. Skipping extensions."
echo " To authenticate later, run: gh auth login"
echo " Then install extensions with: gh extension install github/gh-copilot dlvhdr/gh-dash"
fi
else
echo "⚠️ GitHub CLI not installed, skipping extensions"
fi
# Install Terraform helper tools
echo "🏗️ Installing Terraform helper tools..."
if brew list terraform &>/dev/null; then
echo "⚠️ terraform is already installed directly. Unlinking before installing tfenv..."
brew unlink terraform
fi
brew_install tfenv
brew_install terragrunt
brew_install tflint
# Install productivity tools
echo "⚡ Installing productivity tools..."
brew_install_cask raycast
brew_install_cask rectangle
brew_install_cask alt-tab
brew_install_cask notion
brew_install_cask obsidian
# Install Media Tools
echo "🎨 Installing media tools..."
brew_install_cask figma
brew_install_cask shottr
brew_install_cask kap
# Install frontend development tools
echo "🎨 Installing frontend development tools..."
npm list -g storybook &> /dev/null || npm install -g storybook
npm list -g lighthouse &> /dev/null || npm install -g lighthouse
npm list -g stylelint &> /dev/null || npm install -g stylelint
npm list -g svgo &> /dev/null || npm install -g svgo
npm list -g @testing-library/dom &> /dev/null || npm install -g @testing-library/dom
# Install database migration tools
echo "🗃️ Installing database migration tools..."
npm list -g prisma &> /dev/null || npm install -g prisma
pip list | grep -q "alembic" || pip install alembic
# Install GraphQL tools
echo "🔄 Installing GraphQL tools..."
npm list -g graphql-cli &> /dev/null || npm install -g graphql-cli
# Setup work and personal development directories
mkdir -p ~/Development/{work,personal,opensource,experiments,learning}
# Add a reminder to install Rosetta 2 for Apple Silicon Macs if needed
if [[ $(uname -m) == "arm64" ]]; then
echo "🍎 Note: If you need to run Intel-based applications, install Rosetta 2:"
echo "softwareupdate --install-rosetta"
fi
# Final touches and cleanup
brew cleanup
echo "
🎉 Setup complete! Your Mac is now configured with a senior developer environment!
What was installed:
- Advanced shell setup with Powerlevel10k theme and plugins
- Extensive VS Code extensions for all aspects of development
- Advanced Git configuration with templates and global ignore
- Docker, Kubernetes, and cloud tools
- Multiple programming languages and environments
- Database tools and migration utilities
- Advanced terminal configurations (tmux, Neovim)
- SSH and GPG for secure development
- Developer fonts and productivity tools
Next steps:
1. Restart your terminal or run 'source ~/.zshrc'
2. Run 'p10k configure' for a guided Powerlevel10k setup
3. If you added a GitHub SSH key, add it to your GitHub account
4. Consider running 'nvim' and then ':PlugInstall' to set up Neovim plugins
5. For Apple Silicon Macs, run 'softwareupdate --install-rosetta' if needed
Enjoy your new development environment! 🚀
"
@crstnmac
Copy link
Author

crstnmac commented Mar 2, 2025

To use the script:

Save it to a file (e.g., setup.sh)
Make it executable: chmod +x setup.sh
Run it: ./setup.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment