As developer, I constantly like to try new tools, and code editors are no exception. Over the past few months, I’ve found myself hopping between VSCode, Cursor, and most recently Windsurf. Each editor has its strengths, and sometimes you want to give one a proper test drive as your primary editor. (And no, I’m not just chasing the latest vibe coding trends… okay, maybe a little.)1
The problem? Every time I switch editors, I have to manually update file associations for dozens of file types. Right-clicking on every .js, .ts, .py, etc. file and changing “Open with…” gets old fast. There had to be a better way.
Enter duti - The macOS File Association Manager
After some research, I discovered duti, a command-line utility for managing default applications on macOS. It’s exactly what I needed: a way to programmatically set file associations in bulk.
You can install it via Homebrew:
brew install duti
The Script
Here’s the script I created to handle editor switching:
#!/bin/bash
# Replace this with your verified editor bundle ID
# CURSOR_ID="com.todesktop.230313mzl4w4u92" # Cursor
# VSCODE_ID="com.microsoft.VSCode" # VSCode
EDITOR_ID="com.exafunction.windsurf" # Windsurf
# Array of file extensions
EXTENSIONS=(
# Web development
".html" ".css" ".js" ".jsx" ".ts" ".tsx"
".vue" ".svelte" ".scss" ".sass" ".less"
# Python
".py" ".ipynb"
# Ruby
".rb" ".erb"
# Java/Kotlin
".java" ".kt"
# C/C++
".c" ".cpp" ".h" ".hpp"
# Go
".go"
# Rust
".rs"
# PHP
".php" ".phtml"
# Swift/Dart
".swift" ".dart"
# Data/Database
".sql" ".graphql" ".gql" ".r" ".R"
# Config files
".json" ".yml" ".yaml" ".toml" ".xml" ".md"
".txt" ".ini" ".env" ".properties" ".conf"
".gitignore" ".editorconfig" ".prettierrc"
# Infrastructure
".hcl" ".tf" ".lua"
# Shell scripts
".sh" ".bash" ".zsh"
)
# Set each file association
for ext in "${EXTENSIONS[@]}"; do
echo "Setting $ext to open with editor..."
duti -s "$EDITOR_ID" "$ext" all
done
echo "Done! Editor should now be set as the default for all development files."
Finding Bundle IDs
The tricky part is finding the correct bundle ID for each application. Here are a few ways to get them:
Method 1: Using osascript
osascript -e 'id of app "Windsurf"'
Method 2: Using mdls
mdls -name kMDItemCFBundleIdentifier -r /Applications/Windsurf.app
Method 3: Check the app’s Info.plist
/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" /Applications/Windsurf.app/Contents/Info.plist
Making It Flexible
To make the script more flexible, I keep the bundle IDs for different editors commented out at the top. When I want to switch editors, I just uncomment the one I want and update the EDITOR_ID variable.
You could also make it more sophisticated with command-line arguments:
#!/bin/bash
case "$1" in
"vscode")
EDITOR_ID="com.microsoft.VSCode"
EDITOR_NAME="VSCode"
;;
"cursor")
EDITOR_ID="com.todesktop.230313mzl4w4u92"
EDITOR_NAME="Cursor"
;;
"windsurf")
EDITOR_ID="com.exafunction.windsurf"
EDITOR_NAME="Windsurf"
;;
*)
echo "Usage: $0 {vscode|cursor|windsurf}"
exit 1
;;
esac
echo "Setting default editor to $EDITOR_NAME..."
# ... rest of the script
Then you can run it like:
./setup-editor.sh windsurf
The Dotfiles Connection
This script fits nicely into my dotfiles setup philosophy. I’ve added it to my dotfiles repository so that whenever I set up a new machine or want to standardise my editor choice across multiple machines, it’s just a single command away.
Footnotes
-
I should probably write something about my current (and always evolving) relationship with AI-powered coding tools, but that’s another story. ↩