Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save MaximBazarov/7d8d48c968ff415c1a063776aeeccba6 to your computer and use it in GitHub Desktop.
Save MaximBazarov/7d8d48c968ff415c1a063776aeeccba6 to your computer and use it in GitHub Desktop.
Xcode invocation tool - xed

Xcode invocation tool - xed

xed is a command-line tool that launches the Xcode application and opens the given documents (xcodeproj, xcworkspace, etc.), or opens a new document, optionally with the contents of standard input.

If you work from the command line, this tool is a better option than open (which can open Xcode projects as well). Why?

  • xed knows about the current selected Xcode version (open behaves unpredictably if you have multiple Xcode installed)
  • You can use it open all files from a specific commit (with a little help explained below). It is useful on code-reviews or when you want to explore significant changes in the repository
  • You can use it as a "quick open" helper. Helps with monorepo phenomena, when you have hundreds of projects in the repository (I will show you an example below)

Note about the current selected Xcode version

The current selected Xcode is controlled by xcode-select tool. You can check the current selected version with xcode-select -p (or xcode-select --print-path) and change it with sudo xcode-select -s PATH_TO_XCODE (or sudo xcode-select --switch PATH_TO_XCODE).

Tips & Tricks: There is a trick to get the current selected Xcode version without the tool. But your command line has to have full disk access. In some cases, it can be useful, but I recommend to use xcode-select if you have no additional requirements. To check the current selected Xcode version without xcode-select, execute the following command:

$ readlink /private/var/db/xcode_select_link
/Volumes/Extended/Archive/Xcode_11.5.app/Contents/Developer

Base commands

xed --launch
# or
xed -x

Launches the current selected Xcode.

xed Client.xcodeproj
# or
xed Client.xcworkspace

Will open the project with the current selected Xcode and terminate (the process that invoked xed remains in control).

xed SourceFile.swift AnotherExample.swift

Will open the files. There are two possible outcomes:

  • Xcode will navigate to these file within the project if the project that contains these files is already opened
  • Xcode will open the files as separate units

There are more options, like --wait or --line. Please, consult the man page for xed.

Tips & Tricks: If you are browsing this article on macOS, you can click on the Man page for xed link, and it will show you the man page for the command in Terminal.app. There is a special scheme - x-man-page - than can open man pages for any available commands on macOS. For example, the URL for xed looks like x-man-page://xed.

Open all files with changes

You can browse the git history directly in Xcode, and this is a convenient way to navigate the history. But I am not too fond of the Xcode Code Review tool because of the layout (when they show the original source and the version side-by-side), and there is no option to open all the files in the editor. Sometimes it is useful to open all files changed by the commit as regular source files and navigate them one by one.

To do so, you need a hash of the commit you want to browse. The following command will list all the files in the commit and open them in Xcode:

xed $(git diff-tree --no-commit-id --name-only -r COMMIT_HASH)

You can use the command as an alias for your Bash or zsh configurations.

Note: if the Xcode project for these files is already opened then Xcode will open them in the context of the project. Otherwise, it will open each file in a separate window.

Quick search and open projects

You need a quick way to search and open projects when you have hundreds of them in your git repository. In my case, I work with two monorepos daily, and I have a significant number of different projects in my "projects" folder. To be able to navigate and open them as quickly as possible, I developed a script that scans the current folder for all .xcodeproj files, produces a list of them according to the provided search term and then open a specific project with the xed tool.

Let's take the Firefox iOS project as a simple example. The project contains 65 .xcodeproj files in the repository (most of them are third-party Carthage dependencies). Imagine that I work with the repository every day and have to switch between these projects (check demos, run tests, apply fixes, etc.). To help myself, I am using the following script:

#!/usr/bin/env bash

set -euo pipefail
declare -a PROJECTS=()

function XcodeProjectsInCurrentDirectory() {
    TEMP_FILE=$(mktemp)
    SEARCH_PATTERN="*${1}*.xcodeproj"
    find . -iname "$SEARCH_PATTERN" -type d -print0 | sort -z > "$TEMP_FILE"
    while IFS=  read -r -d $'\0'; do
        PROJECTS+=("$REPLY")
    done <"$TEMP_FILE"
    rm -f "$TEMP_FILE"
}

function ListProjects() {
    echo "Collecting .xcodeproj..."
    XcodeProjectsInCurrentDirectory "$1"
    if [ "${#PROJECTS[@]}" -eq 0 ]; then
        echo "The project not found."
        exit 0
    elif [ "${#PROJECTS[@]}" -eq 1 ]; then
        echo "Opening ${PROJECTS[0]}..."
        xed "${PROJECTS[0]}"
    else 
        echo "Please select a project:"
        select d in "${PROJECTS[@]}"; do test -n "$d" && break; echo ">>> Invalid Selection"; done
        echo "Opening ${d}..."
        xed "$d"
    fi
}

ListProjects "${1-}"

unset XcodeProjectsInCurrentDirectory;
unset ListProjects;

The script will produce the full list of projects when you run it in the Firefox iOS project and ask you to provide a number to select a project to open:

$ sh pxed.sh
...
60) ./Carthage/Checkouts/sentry-cocoa/Sentry.xcodeproj
61) ./Carthage/Checkouts/swift-protobuf/SwiftProtobuf.xcodeproj
62) ./Carthage/Checkouts/telemetry-ios/Telemetry.xcodeproj
63) ./Client.xcodeproj
64) ./FxA/FxA.xcodeproj
65) ./ThirdParty/Deferred/Deferred.xcodeproj
#?

If you run it with a search term, "demo" for example, the list will be limited to projects with the keyword in the name:

$ sh pxed.sh demo
Collecting .xcodeproj...
Please select a project:
1) ./Carthage/Checkouts/Fuzi/FuziDemo/FuziDemo.xcodeproj
2) ./Carthage/Checkouts/SDWebImage/Examples/SDWebImage Demo.xcodeproj
3) ./Carthage/Checkouts/XCGLogger/DemoApps/iOSDemo/iOSDemo.xcodeproj
4) ./Carthage/Checkouts/XCGLogger/DemoApps/macOSDemo/macOSDemo.xcodeproj
5) ./Carthage/Checkouts/XCGLogger/DemoApps/tvOSDemo/tvOSDemo.xcodeproj
6) ./Carthage/Checkouts/onepassword-app-extension/Demos/App Demo for iOS Swift/App Demo for iOS Swift.xcodeproj
7) ./Carthage/Checkouts/onepassword-app-extension/Demos/App Demo for iOS/App Demo for iOS.xcodeproj
8) ./Carthage/Checkouts/onepassword-app-extension/Demos/WebView Demo for iOS Swift/WebView Demo for iOS Swift.xcodeproj
9) ./Carthage/Checkouts/onepassword-app-extension/Demos/WebView Demo for iOS/WebView Demo for iOS.xcodeproj
#?

And, finally, the script will open the project straight away if there is only one search result for the keyword:

$ sh pxed.sh sent
Collecting .xcodeproj...
Opening ./Carthage/Checkouts/sentry-cocoa/Sentry.xcodeproj...

Thanks for reading

Let me know if you have questions or want to discuss something. Feel free to comment the script on GitHub as well.

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