Code Formatting in Xcode 4

Automatic indentation and cleanup of code seems to have improved in Xcode 4 (Editor menu – Structure – Re-Indent) but it still doesn’t offer full code reformatting or the flexibility of a tool like Uncrustify. If you’re used to having external code formatting in Xcode available you might be disappointed to find the User Scripts menu missing in Xcode 4.

Inputs to Automator Services are more limited than the options available in Xcode 3’s User Scripts. To reformat selected text we can still pass the input from Xcode to a Run Shell Script action.

uncrustify -l OC -q -c ~/.uncrustify/uncrustify_obj_c.cfg

Uncrustify Selected Text

To reformat open files we need to use AppleScript to get the paths to those files so that we can pass them to Uncrustify. I wasn’t able to find a reliable way to select only the currently visible source file so I settled on the following script to reformat all open and modified source files instead.

tell application id &quot;com.apple.dt.Xcode&quot;
repeat with current_document in (source documents whose modified is true)
set current_document_path to path of current_document
set raw_source to text of current_document
set formatted_source to do shell script &quot;uncrustify -l OC -q -c ~/.uncrustify/uncrustify_obj_c.cfg -f &quot; &amp; current_document_path
set text of current_document to formatted_source
end repeat
end tell

Uncrustify Modified Documents

Open Xcode, find the new Services available in the “Xcode” menu. Use the Services Preferences to bind these Services to keyboard shortcuts to your liking.

Services available in Xcode

Enjoy cleaner code.

Feedback

Comments: 14

Juri Pakaste

Good stuff. One addition: it probably makes sense to replace the & current_document_path in the script with & quoted form of current_document_path to make it work with documents with spaces, quotes etc in their paths.

YoungJae

Yanchuan Li

Hello Jonah,
it seemed it doesn’t work at all.
I’ve followed the instructions here and uncrustify also works already in the terminal.
But when I just clicked the service, nothing changed in my xcode4.
Any ideas for this?

Jonah

Sorry to hear that you’re having trouble. If you open the service in Automator you should be able to capture its inputs and outputs to determine where the problem is.

For example you could add a “Get Specified Text” step to the beginning of the “Uncrustify Selected Text” service to send it some known code snippet and inspect the result to make sure the shell script action is correctly passing that text to Uncrustify.
Similarly if you return the raw_source or formatted_source from the “Uncrustify Modified Documents” service’s AppleScript action you should be able to confirm if you got text from Xcode and Uncrustify.

Hopefully that allows you to determine if the Uncrustify shell script calls are incorrect for your machine or if there is some problem with the services interacting with Xcode.

phil

Uncrustify works for me very well on the terminal. As soon as I try to run the script via Automator I’ll get a “Run Shell Script failed – 1 error” message:
/Users/phil/uncrustify_obj_c.cfg:37 Unknown symbol in ‘nl_before_return’
This config file works well when using it directly in terminal.

mC

Anonymous

Thank you very much for the info but there’s several serious problems going on here.

The first issue is minor: the source code is HTML escaped so you have to go in and manually change the quotes and ampersands. Not a big issue for a developer but also something a developer wouldn’t want on their site.

I’m guessing you did some upgrade to your code formatter and don’t have to use escaped code anymore but didn’t change the older posts to reflect this.

The next issue is there is no ~/.uncrustify/ directory so of course there is no uncrustify_obj_c.cfg file. This causes both scripts to crash and burn… but not in a good way.

It’s not immediately clear that we need to read your other article to find the file nor is it clear at all if I do or do not need to also install UniversalIndentGUI to make this all work. I don’t but it’s a bit confusing to someone muddling through.

Next you need to modify the AppleScript line with do shell script so it calls the exact path to the uncrustify app since do shell script doesn’t appear to run the .bashrc file even if you specify /bin/bash in the line. This means it has no idea where uncrustify is at.

This also needs to be done for the selected text script.

While changing the script to the exact path fixes the issue of the shell not knowing where uncrustify is this just gets us to the next problem which is AppleScripts inability to handle the return data from the shell script. Since the return value is non-zero it gets all confused it thinks this is an error.

I got around this by echoing the output to a temp file and putting ; echo 0 at the end of the line. I then load the file with another do shell script where I cat the file.

Here’s the monstrosity I ended up with after all that misery.

tell application id "com.apple.dt.Xcode"
repeat with current_document in (source documents whose modified is true)
set current_document_path to path of current_document
set raw_source to text of current_document
set temp_file to "/tmp/uncrustify_tmp.txt"