Dienstag, 18. Oktober 2011

Xtext Objective C Formatter/Beautifier

This post shows how I integrated uncrustify into Xtext. At the end of this post you will be able to package uncrustify with your language UI plugin and run uncrustify as part of a MWE2 workflow (the described approach was tested with Xtext 2.0 on Mac OS X 10.7).

First, you have to get uncrustify. Unpack it, run ./configure and then make. The binary is located in the src/ folder and is named uncrustify - what a surprise. Create a folder formatting/ in your language's UI plugin. Copy the binary into this folder. To tell uncrustify how to format the code we have to supply it with a config file. A config file for objective c can be found here. Download this file and put it into the formatting/ folder. Besides the binary and a config file we need a shell script that runs uncrustify. Create a file formatSource.sh in formatting/. The shell script looks like this:
#! /bin/sh

touch files.txt
find . -name "*.[hm]" > files.txt

while read line; do
./uncrustify_osx -l OC -c ./uncrustify_obj_c.cfg --no-backup $line
done < files.txt  
rm files.txt 
This script will look for *.h and *.m files recursively down from its location, run over them, and format them without creating a backup copy.

Now that we have the necessary files for running uncrustify ... oh well ... we must be able to run uncrustify from within java. For executing shell scripts from within a java process - welcome platform dependency - check out my ShellCommandExecutor. This class is also used for making the shell script formatSource.sh executable after copying it to a language project:
private void copyFormattingFiles(final IProject project){
 Bundle bundle = SystemDslActivator.getInstance().getBundle();
 IPath scriptPath = copyFile("formatting/formatSource.sh"     , "formatSource.sh",      project, bundle);
 IPath binaryPath = copyFile("formatting/uncrustify_osx",       "uncrustify_osx",       project, bundle);

 copyFile("formatting/uncrustify_obj_c.cfg", "uncrustify_obj_c.cfg", project, bundle);

 //make script and binary executable
 try {
  ShellCommandExecutor.execute("chmod", "+x", scriptPath.toString());
  ShellCommandExecutor.execute("chmod", "+x", binaryPath.toString());
 } catch (Exception e) {
  //TODO: write to error log
 }
}
The above method can be found in this class. The execution of formatSource.sh in a MWE2 workflow component looks like this:
public class ObjectiveCFormatter extends org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent2{

private static final String SCRIPT_PATH = "./formatSource.sh";

@Override
protected void invokeInternal(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) {
try{
 CommandResult cr = ShellCommandExecutor.execute(SCRIPT_PATH, new String[]{});

 if (cr.success){
  System.out.println("Formatting complete!");
 } else{
  issues.addError(cr.output);
 }
}catch (Exception e){
 issues.addError(e.getMessage());
}
}
}
If you add this component after your objective c generator in your workflow all *.h and *.m files will be formatted as described by the uncrustify objective c config file.

regards,

steven

Keine Kommentare: