Development Environment Setup
Intuition
Section titled “Intuition”Your digital workshop: A development environment is like a well-organised workshop — the right tools (terminal, editor, shell) make you productive, while poor setup creates friction that slows you down. Investing in your environment pays dividends every day.
Why it matters: The tools you use daily have an outsized impact on your productivity. A fast terminal, a well-configured editor, and efficient shell aliases can save hours per week compared to slow, unconfigured defaults.
The key insight: GPU-accelerated terminals render text faster and support true colour and Unicode — this is not just cosmetic; it enables tools like bat, fzf, and neovim to display syntax highlighting and special characters correctly.
Terminal Emulators
Section titled “Terminal Emulators”GPU-Accelerated Terminals
Section titled “GPU-Accelerated Terminals”Modern terminal emulators use the GPU for rendering, enabling smooth scrolling, proper Unicode Support, and fast image rendering:
| Terminal | Renderer | Platform | Key Features |
|---|---|---|---|
| Alacritty | Vulkan/Metal | Linux, macOS, Windows | Fastest, minimal config (YAML), GPU-first |
| Kitty | OpenGL | Linux, macOS | Image support, tabs, ligatures, layout management |
| WezTerm | WebGL/Metal | Linux, macOS, Windows | Built-in multiplexer, Lua config, image protocol |
| Ghostty | Vulkan/Metal | Linux, macOS | New, fast, system-native font rendering |
| iTerm2 | Metal | macOS | macOS-only, extensive features, splits, tmux integration |
Terminal Configuration
Section titled “Terminal Configuration”Alacritty example configuration (~/.config/alacritty/alacritty.toml):
[window]opacity = 0.95padding = { x = 8, y = 8 }decorations = "none"
[font]normal = { family = "JetBrains Mono", style = "Regular" }size = 13.0
[colors.primary]background = "#1e1e2e"foreground = "#cdd6f4"
[cursor]style = { shape = "Block", blinking = "On" }
[keyboard]bindings = [ { key = "V", mods = "Control|Shift", action = "Paste" }, { key = "C", mods = "Control|Shift", action = "Copy" },]Font Selection
Section titled “Font Selection”A good programming font is critical for long coding sessions:
| Font | Ligatures | Nerd Font | Notes |
|---|---|---|---|
| JetBrains Mono | Yes | Yes | Excellent readability, designed for code |
| Fira Code | Yes | Yes | Popular, good for presentations |
| Cascadia Code | Yes | Yes | Microsoft”s coding font, great for terminals |
| Iosevka | Customizable | Yes | Highly customizable, many variants |
| Monaco | No | No | Classic macOS font, no ligatures |
Install a Nerd Font variant for proper icon rendering in terminal prompts and file managers.
Shells
Section titled “Shells”Shell Comparison
Section titled “Shell Comparison”| Feature | Bash | Zsh | Fish |
|---|---|---|---|
| POSIX compliance | Full | Partial | No |
| Script compatibility | Best | Good (mostly compatible) | Poor (different syntax) |
| Completion | Basic (compgen) | Excellent (zsh-completions) | Excellent (built-in) |
| Prompt customization | PS1/PS2/PROMPT_COMMAND | PROMPT expansion | fish_prompt function |
| Plugin ecosystem | Limited | Oh-My-Zsh, zinit, etc. | Fisher, oh-my-fish |
| Syntax highlighting | No (external: fast-syntax-highlighting for zsh) | Yes (zsh-syntax-highlighting) | Yes (built-in) |
| Autosuggestions | No (external) | Yes (zsh-autosuggestions) | Yes (built-in) |
| Performance | Fast | Moderate (depends on plugins) | Fast |
| Learning curve | Low | Moderate | Low |
Recommendation
Section titled “Recommendation”- Zsh for power users who want maximum customization and compatibility. Pair with a minimal plugin set (zinit or znap) rather than oh-my-zsh for better performance.
- Fish for developers who want a great out-of-the-box experience without configuration. Fish”s built-in autosuggestions and syntax highlighting are excellent.
- Bash for scripting and environments where POSIX compatibility is required. Keep Bash as
/bin/bashfor scripts regardless of your interactive shell choice.
Zsh Configuration
Section titled “Zsh Configuration”Minimal Zsh Setup (Without Oh-My-Zsh)
Section titled “Minimal Zsh Setup (Without Oh-My-Zsh)”Oh-My-Zsh is convenient but adds significant startup latency (100–300 ms). A minimal setup with Hand-picked plugins is faster and more maintainable:
## ~/.zshrc## -- History --HISTFILE=~/.zsh_historyHISTSIZE=50000SAVEHIST=50000setopt HIST_IGNORE_ALL_DUPSsetopt HIST_SAVE_NO_DUPSsetopt SHARE_HISTORYsetopt INC_APPEND_HISTORY
# -- Completion --autoload -Uz compinit && compinitzstyle ':completion:*' menu selectzstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
# -- Key bindings --bindkey -ebindkey '^p' history-search-backwardbindkey '^n' history-search-forward
# -- Plugins (using zinit) --# Install zinit:# bash -c "$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/zdharma-continuum/zinit/HEAD/scripts/install.sh)"
# Source starship prompteval "$(starship init zsh)"Starship Prompt
Section titled “Starship Prompt”Starship is a fast, cross-shell prompt written in Rust:
# Installcurl -sS https://starship.rs/install.sh | sh
# Minimal config (~/.config/starship.toml)add_newline = falsecharacter = { success_symbol = "[>](bold green)", error_symbol = "[>](bold red)" }[directory]truncation_length = 3truncate_to_repo = true[git_branch]symbol = " "[git_status]disabled = falseEssential Zsh Plugins
Section titled “Essential Zsh Plugins”| Plugin | Function | Startup Cost |
|---|---|---|
| zsh-autosuggestions | Gray suggestions from history | ~5 ms |
| zsh-syntax-highlighting | Real-time command syntax coloring | ~10 ms |
| zsh-completions | Additional completion definitions | ~5 ms |
| fzf-tab | Fuzzy completion menus | ~2 ms |
| z | Directory jumping based on frecency | ~1 ms |
Dotfiles Management
Section titled “Dotfiles Management”GNU Stow
Section titled “GNU Stow”GNU Stow manages symlinks from a dotfiles repository to their target locations:
dotfiles/ zsh/ .zshrc .zshenv git/ .gitconfig .gitignore_global nvim/ .config/nvim/init.lua alacritty/ .config/alacritty/alacritty.toml# Stow creates symlinks:stow zsh # ~/.zshrc -> ~/dotfiles/zsh/.zshrcstow git # ~/.gitconfig -> ~/dotfiles/git/.gitconfigstow nvim # ~/.config/nvim/init.lua -> ~/dotfiles/nvim/.config/nvim/init.lua
# Unstow (remove symlinks):stow -D zshChezmoi
Section titled “Chezmoi”Chezmoi is a more feature-rich dotfiles manager that supports templating, encryption, and Cross-platform configuration:
# Installsh -c "$(curl -fsLS get.chezmoi.io)"
# Initialize from a git repochezmoi init https://github.com/yourusername/dotfiles.git
# Applychezmoi apply
# Edit a file (opens in $EDITOR)chezmoi edit ~/.zshrc
# Diff (show changes that would be applied)chezmoi diffChezmoi handles cross-platform differences with templates:
{{ if eq .chezmoi.os "darwin" -}}export PATH="/opt/homebrew/bin:$PATH"{{ else if eq .chezmoi.os "linux" -}}export PATH="/usr/local/bin:$PATH"{{ end -}}Editors
Section titled “Editors”Neovim
Section titled “Neovim”Neovim is the modern successor to Vim, with built-in LSP, Lua scripting, and a thriving plugin Ecosystem:
- LazyVim — Opinionated Neovim distribution with pre-configured LSP, completion, and keybindings. Good starting point.
- AstroNvim — Another opinionated distribution with a GUI-like experience.
- Kickstart.nvim — Minimal Neovim configuration that teaches Neovim configuration from scratch.
VS Code
Section titled “VS Code”VS Code is the most popular editor for good reason: extensive extension ecosystem, integrated Terminal, debugger, and Git integration.
Essential extensions:
| Extension | Function |
|---|---|
| GitLens | Git blame, history, and comparison |
| Error Lens | Inline error/warning display |
| Copilot | AI-assisted code completion |
| Rust Analyzer | Rust language server |
| Python | Python IntelliSense, debugging, linting |
| Go | Go language support |
| C/C++ | C/C++ IntelliSense, debugging |
| Prettier | Code formatting |
| ESLint | JavaScript/TypeScript linting |
Key Bindings Worth Learning
Section titled “Key Bindings Worth Learning”Regardless of editor, these keybindings improve productivity:
| Action | Vim | VS Code | General Benefit |
|---|---|---|---|
| Split pane | :vsp / :sp | Ctrl+\ | Multiple files visible |
| Fuzzy file find | Ctrl-P (fzf) | Ctrl-P | Fast navigation |
| Go to definition | gd | F12 | Code navigation |
| Find references | gr | Shift+F12 | Refactoring |
| Quick fix | :cw | Ctrl+Shift+M | Error navigation |
| Search in files | :Ag / :Rg | Ctrl+Shift+F | Code search |
Terminal Multiplexers
Section titled “Terminal Multiplexers”Tmux provides persistent sessions, window management, and pane splitting:
# Installsudo apt install tmux # Linuxbrew install tmux # macOS
# Essential key bindings (prefix = Ctrl+B)# Sessionstmux new -s work # Create named sessiontmux ls # List sessionstmux attach -t work # Attach to sessionCtrl+B, d # Detach from session
# Windows (tabs)Ctrl+B, c # Create new windowCtrl+B, n # Next windowCtrl+B, p # Previous windowCtrl+B, , # Rename window
# PanesCtrl+B, % # Vertical splitCtrl+B, " # Horizontal splitCtrl+B, arrows # Navigate panesCtrl+B, z # Toggle pane zoomtmux Configuration
Section titled “tmux Configuration”set -g prefix C-aunbind C-bbind C-a send-prefix
set -g base-index 1setw -g pane-base-index 1
set -g mouse onset -g status-position top
set -g default-terminal "screen-256color"set -ga terminal-overrides ",xterm-256color:Tc"
# Vi-style pane navigationbind h select-pane -Lbind j select-pane -Dbind k select-pane -Ubind l select-pane -RVersion Control Setup
Section titled “Version Control Setup”Git Configuration
Section titled “Git Configuration”# Core settingsgit config --global user.name "Your Name"git config --global user.email "you@example.com"git config --global init.defaultBranch maingit config --global pull.rebase truegit config --global fetch.prune true
# GPG commit signinggit config --global user.signingkey YOUR_GPG_KEY_IDgit config --global commit.gpgsign truegit config --global gpg.program gpg
# SSH key signing (alternative to GPG)git config --global gpg.format sshgit config --global user.signingkey ~/.ssh/id_ed25519.pubgit config --global commit.gpgsign true
# Useful aliasesgit config --global alias.co checkoutgit config --global alias.br branchgit config --global alias.ci commitgit config --global alias.st statusgit config --global alias.lg "log --oneline --graph --decorate --all"git config --global alias.last "log -1 HEAD --stat"SSH Keys
Section titled “SSH Keys”# Generate ED25519 key (preferred)ssh-keygen -t ed25519 -C "you@example.com"
# Generate RSA key (for legacy systems)ssh-keygen -t rsa -b 4096 -C "you@example.com"
# Start SSH agent and add keyeval "$(ssh-agent -s)"ssh-add ~/.ssh/id_ed25519
# Copy public key to remote hostssh-copy-id user@remote-hostProductivity CLI Tools
Section titled “Productivity CLI Tools”Modern Coreutils Replacements
Section titled “Modern Coreutils Replacements”| Tool | Replaces | Key Feature |
|---|---|---|
fzf | Ctrl+R``Ctrl+TFile finding | Fuzzy finder with preview |
ripgrep (rg) | grep | Fast regex search, respects .gitignore |
fd | find | Fast file finding, intuitive syntax |
bat | cat | Syntax highlighting, line numbers, git diff |
eza (exa) | ls | Colorized, icons, git status, tree view |
zoxide | cd | Smart directory jumping based on frecency |
delta | diff | Syntax-highlighted diffs with side-by-side |
tldr | man | Simplified, practical man pages |
jq | python -m json.tool | Command-line JSON processor |
httpie | curl | Human-friendly HTTP client |
tokei | cloc | Fast code line counter |
bottom (btm) | htop | Modern system monitor with GPU support |
fzf Integration
Section titled “fzf Integration”# Install# Linux: sudo apt install fzf# macOS: brew install fzf
# fzf integrates with shell history, file finding, and more# Ctrl+R — fuzzy history search# Ctrl+T — fuzzy file finder (inserts path)# Alt+C — fuzzy cd
# Advanced: fzf with previewfzf --preview 'bat --color=always {}'
# Use with ripgrep for project-wide searchrg --color=always --line-number "" | fzf --ansi --delimiter : --preview 'bat --color=always {1} --highlight-line {2}'Containerized Dev Environments
Section titled “Containerized Dev Environments”Devcontainers
Section titled “Devcontainers”Devcontainers provide reproducible development environments defined in code:
{ "name": "My Project", "image": "mcr.microsoft.com/devcontainers/go:1.21", "features": { "ghcr.io/devcontainers/features/docker-in-docker:2": {} }, "customizations": { "vscode": { "extensions": ["golang.go"] } }, "postCreateCommand": "go mod download"}Nix Flakes
Section titled “Nix Flakes”Nix provides reproducible, declarative environments:
# Enter a nix shell with specific toolsnix shell nixpkgs#go nixpkgs#golangci-lint nixpkgs#protobuf
# Use a flake for a project# flake.nix defines the development shellnix develop # Enter the development shellCross-Platform Considerations
Section titled “Cross-Platform Considerations”macOS Specifics
Section titled “macOS Specifics”- Homebrew is the standard package manager:
brew install tmux neovim ripgrep - Xcode Command Line Tools required for many builds:
xcode-select --install - Path differences: Homebrew installs to
/opt/homebrew(Apple Silicon) or/usr/local(Intel) - BSD utilities: macOS ships BSD versions of
sed``grep``awkEtc. Install GNU versions via Homebrew (gsed``ggrep) for compatibility with Linux.
Linux Specifics
Section titled “Linux Specifics”- Package manager varies by distro:
apt(Debian/Ubuntu),dnf(Fedora),pacman(Arch) - Systemd manages services:
systemctl``journalctl - AppArmor/SELinux may restrict terminal and editor capabilities
- Wayland vs X11 affects clipboard integration, screen sharing, and terminal behavior
- Filesystem performance: Linux files in WSL2 are fast; Windows files accessed from WSL2 are slow. Store your code in the WSL2 filesystem (
/home/), not on/mnt/c/. - Docker: Docker Desktop for Windows integrates with WSL2. Alternatively, run Docker directly inside WSL2 for better performance.
- GPU passthrough: WSL2 supports CUDA GPU passthrough for ML workloads.
- Systemd: Modern WSL2 supports systemd. Enable in
/etc/wsl.conf:[boot]systemd=true
Common Pitfalls
Section titled “Common Pitfalls”Over-Engineering Your Dotfiles
Section titled “Over-Engineering Your Dotfiles”Spend time configuring your environment, but do not fall into the trap of endlessly tweaking your Config instead of doing actual work. A good dotfiles setup takes a few hours to set up and then gets Out of your way. If you are spending more time configuring your tools than using them, stop and ship Something.
Not Version-Controlling Dotfiles
Section titled “Not Version-Controlling Dotfiles”Without version control, a machine reinstall or switch means reconfiguring everything from scratch. Use GNU Stow, Chezmoi, or a bare Git repo to manage your dotfiles. Push to a private GitHub Repository for backup and portability.
Ignoring Shell Startup Performance
Section titled “Ignoring Shell Startup Performance”A slow shell startup (more than 100 ms) compounds across every terminal you open. Profile your shell Startup with zprof (Zsh) or time zsh -i -c exit. Oh-My-Zsh with many plugins is a common Culprit. Switch to a minimal plugin manager (zinit, znap) or hand-pick individual plugins.
Using the Wrong Shell for Scripts
Section titled “Using the Wrong Shell for Scripts”Use Bash for scripts (shebang: #!/usr/bin/env bash), even if you use Zsh or Fish as your Interactive shell. Bash scripts are more portable and widely understood. Never assume Zsh or Fish Features are available in a script.
Storing Code on Windows Filesystem in WSL2
Section titled “Storing Code on Windows Filesystem in WSL2”Accessing Windows files (/mnt/c/) from WSL2 has significantly worse I/O performance than accessing Native WSL2 files. This affects build times, file watching (hot reload), and Git operations. Always Store your projects under /home/ or another native WSL2 path.
Cross-Platform Configuration with Chezmoi
Section titled “Cross-Platform Configuration with Chezmoi”Chezmoi Templates
Section titled “Chezmoi Templates”Chezmoi templates allow you to generate different configurations for different systems:
~/.local/share/chezmoi/ dot_zshrc.tmpl # Template for .zshrc dot_gitconfig.tmpl # Template for .gitconfig dot_config/ alacritty/ alacritty.toml.tmpl # Template for Alacritty configExample Template
Section titled “Example Template”{{ if eq .chezmoi.os "darwin" -}}export PATH="/opt/homebrew/bin:$PATH"alias ls="ls -G"{{ else if eq .chezmoi.os "linux" -}}export PATH="/usr/local/bin:$PATH"alias ls="ls --color=auto"{{ end -}}
# Common configurationHISTSIZE=50000SAVEHIST=50000setopt HIST_IGNORE_ALL_DUPSsetopt SHARE_HISTORY
# Prompteval "$(starship init zsh)"Chezmoi Data Files
Section titled “Chezmoi Data Files”{ "email": "you@example.com", "name": "Your Name", "github_username": "yourusername", "workplace": "Company"}Access in templates:
# git config template[user] name = {{ .name }} email = {{ .email }}Development Environment for Specific Languages
Section titled “Development Environment for Specific Languages”Go Development
Section titled “Go Development”# Install Go# macOS: brew install go# Linux: sudo apt install golang-go
# Essential toolsgo install golang.org/x/tools/gopls@latest # Language servergo install github.com/go-delve/delve/cmd/dlv@latest # Debuggergo install github.com/golangci/golangci-lint/cmd/golangci-lint@latest # Lintergo install honnef.co/go/tools/cmd/staticcheck@latest # Static analysis
# VS Code extensions:# - Go (official)# - Go Nightly (experimental features)Rust Development
Section titled “Rust Development”# Install Rustcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Essential toolsrustup component add rust-analyzer clippy rustfmtcargo install cargo-expand cargo-audit cargo-flamegraph
# VS Code extensions:# - rust-analyzer (official)# - CodeLLDB (debugger)# - Even Better TOML# - Crate GraphPython Development
Section titled “Python Development”# Install Python (use pyenv for version management)brew install pyenv # macOSpyenv install 3.12.0pyenv global 3.12.0
# Essential toolspip install black ruff mypy pytest ipython
# VS Code extensions:# - Python (official)# - Ruff (linter + formatter)# - Pylance (type checking)Web Development (TypeScript/JavaScript)
Section titled “Web Development (TypeScript/JavaScript)”# Install Node.js (use fnm or nvm for version management)curl -fsSL https://fnm.vercel.app/install | bashfnm install 22fnm use 22
# Install pnpm (required by this project)corepack enablepnpm --version # should be 10+
# VS Code extensions:# - TypeScript Vue Plugin (Volar) or ES7+ React snippets# - ESLint# - Prettier# - Tailwind CSS IntelliSenseProductivity Workflows
Section titled “Productivity Workflows”Git Workflow for Feature Development
Section titled “Git Workflow for Feature Development”# 1. Create a feature branch from maingit checkout maingit pullgit checkout -b feature/my-feature
# 2. Make changes, commit frequentlygit add -pgit commit -m "Add user authentication endpoint"
# 3. Keep up with maingit fetch origingit rebase origin/main
# 4. Push and create PRgit push -u origin feature/my-featuregh pr create --title "Add user authentication" --body "Description"Tmux Workflow for Development
Section titled “Tmux Workflow for Development”# Session layout for a web development project:# Window 0: Editor (vim/nvim)# Window 1: Terminal (run server, tests)# Window 2: Git (status, log)# Window 3: Monitoring (logs, metrics)
tmux new-session -s dev -d -n editortmux new-window -n terminaltmux new-window -n gittmux new-window -n monitor
# Send commands to specific windowstmux send-keys -t dev:editor "vim" Entertmux send-keys -t dev:terminal "pnpm start" Entertmux send-keys -t dev:git "git status" Enterfzf Integration with zsh
Section titled “fzf Integration with zsh”# Add to ~/.zshrc (after sourcing zinit/plugins):# Ctrl+R — fuzzy history search# Ctrl+T — fuzzy file finder# Alt+C — fuzzy cd
# fzf-tab completion (replaces default tab completion)zinit light zsh-users/zsh-autosuggestionszinit light Aloxaf/fzf-tab
# fzf git integration# Browse git log interactivelygit log --oneline --color=always | fzf --ansi --preview 'git show {1} --stat'Environment Variable Management
Section titled “Environment Variable Management”Using direnv
Section titled “Using direnv”direnv automatically sets environment variables when you enter a project directory:
# Installbrew install direnv # macOSsudo apt install direnv # Linux
# Hook into zsheval "$(direnv hook zsh)"
# Create a per-project .envrc# cd into your project directoryecho 'export DATABASE_URL=postgres://localhost/mydb' > .envrcecho 'export PORT=3000' >> .envrcdirenv allow # Approve the .envrcUsing .env Files
Section titled “Using .env Files”# .env (never commit to git)DATABASE_URL=postgres://localhost/mydbSECRET_KEY=your-secret-keyPORT=3000
# .env.example (commit to git)DATABASE_URL=postgres://localhost/mydbSECRET_KEY=change-mePORT=3000
# Load in shell (for local development)export $(cat .env | xargs)Cross-Platform Scripting
Section titled “Cross-Platform Scripting”Shell Script Portability
Section titled “Shell Script Portability”#!/usr/bin/env bash# Portable shell script that works on macOS, Linux, and WSL2
# Use POSIX-compliant constructs# BAD: arrays (bashism)# GOOD: loops and conditionals
# Portable way to get script directorySCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Portable way to detect OSdetect_os() { case "$(uname -s)" in Darwin*) echo "macOS" ;; Linux*) echo "Linux" ;; *) echo "Unknown" ;; esac}
# Portable way to check if command existsif command -v brew &> /dev/null; then echo "Homebrew installed"fiMakefile for Common Tasks
Section titled “Makefile for Common Tasks”# Makefile for cross-platform development tasks.PHONY: install lint test build clean
install: # macOS @if command -v brew &> /dev/null; then \ brew install fzf ripgrep fd bat eza zoxide; \ elif command -v apt &> /dev/null; then \ sudo apt install fzf ripgrep fd-find bat eza zoxide; \ fi
lint: @if command -v prettier &> /dev/null; then \ prettier --write "**/*.{js,ts,json,md}"; \ fi
test: @if command -v npm &> /dev/null; then \ npm test; \ fi
build: @if command -v npm &> /dev/null; then \ npm run build; \ fiSummary
Section titled “Summary”This topic covers the geographical processes and issues related to development environment setup, including key theories, case studies, and management strategies.
Key concepts include:
- geographical concepts and theories
- case studies and examples
- data analysis and fieldwork techniques
- sustainability and management strategies
- synthesis and evaluation
Using specific case studies and data to support arguments is essential for achieving the highest marks in geography assessments.
Worked Examples
Section titled “Worked Examples”Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.