View | Details | Raw Unified | Return to bug 75333 | Differences between
and this patch

Collapse All | Expand All

(-)plugin.xml (+11 lines)
Lines 209-212 Link Here
209
   <initializer class="org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer"/>
209
   <initializer class="org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer"/>
210
</extension>
210
</extension>
211
211
212
<!-- =================================================================================== -->
213
<!-- Extension: Java Code Formatter                                                      -->
214
<!-- =================================================================================== -->
215
<extension
216
      id="JavaCodeFormatter"
217
      point="org.eclipse.core.runtime.applications">
218
      	<application>
219
      		<run class="org.eclipse.jdt.core.formatter.CodeFormatterApplication" />
220
		</application>
221
</extension>
222
212
</plugin>
223
</plugin>
(-)formatter/org/eclipse/jdt/core/formatter/CodeFormatter.java (-1 / +1 lines)
Lines 62-68 Link Here
62
	 *      level of zero or below has no effect.
62
	 *      level of zero or below has no effect.
63
	 * @param lineSeparator the line separator to use in formatted source,
63
	 * @param lineSeparator the line separator to use in formatted source,
64
	 *     if set to <code>null</code>, then the platform default one will be used.
64
	 *     if set to <code>null</code>, then the platform default one will be used.
65
	 * @return the text edit
65
	 * @return the text edit or <code>null</code> if the given string cannot be formatted.
66
	 * @throws IllegalArgumentException if offset is lower than 0, length is lower than 0 or
66
	 * @throws IllegalArgumentException if offset is lower than 0, length is lower than 0 or
67
	 * length is greater than source length.
67
	 * length is greater than source length.
68
	 */
68
	 */
(-)formatter/org/eclipse/jdt/core/formatter/CodeFormatterApplication.java (+435 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004 Ben Konrath <ben@bagu.org>
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     Ben Konrath <ben@bagu.org> - initial implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.core.formatter;
13
14
import java.io.BufferedReader;
15
import java.io.BufferedWriter;
16
import java.io.File;
17
import java.io.FileInputStream;
18
import java.io.FileReader;
19
import java.io.FileWriter;
20
import java.io.IOException;
21
import java.io.Writer;
22
import java.text.MessageFormat;
23
import java.util.ArrayList;
24
import java.util.HashMap;
25
import java.util.Map;
26
import java.util.MissingResourceException;
27
import java.util.ResourceBundle;
28
29
import javax.xml.parsers.ParserConfigurationException;
30
import javax.xml.parsers.SAXParser;
31
import javax.xml.parsers.SAXParserFactory;
32
33
import org.eclipse.core.runtime.IPlatformRunnable;
34
import org.eclipse.core.runtime.Platform;
35
import org.eclipse.jdt.core.ToolFactory;
36
import org.eclipse.jdt.internal.core.util.Util;
37
import org.eclipse.jface.text.BadLocationException;
38
import org.eclipse.jface.text.Document;
39
import org.eclipse.jface.text.IDocument;
40
import org.eclipse.text.edits.TextEdit;
41
import org.xml.sax.Attributes;
42
import org.xml.sax.InputSource;
43
import org.xml.sax.SAXException;
44
import org.xml.sax.helpers.DefaultHandler;
45
46
/**
47
 * Class that handles the org.eclipse.jdt.core.JavaCodeFormatter the
48
 * application. The map file reading code is based on code in ProfileStore.java
49
 * (org.eclipse.jdf.ui).
50
 * 
51
 * There are a couple improvments that could be made:
52
 * 1. Add an import clean up option (requires stuff from org.eclipse.jdt.ui).
53
 * 2. Make a list of all the files first and then format. You could then 
54
 *    remove duplicate files. 
55
 * 
56
 * @author Ben Konrath <ben@bagu.org>
57
 * @since 3.1
58
 */
59
public class CodeFormatterApplication implements IPlatformRunnable {
60
61
    /**
62
     * A SAX event handler to parse the config xml.
63
     */
64
    private final static class ConfigHandler extends DefaultHandler {
65
66
        /**
67
         * Identifiers for the XML file.
68
         */
69
        private final String XML_NODE_ROOT = "profiles"; //$NON-NLS-1$
70
71
        private final String XML_NODE_PROFILE = "profile"; //$NON-NLS-1$
72
73
        private final String XML_NODE_SETTING = "setting"; //$NON-NLS-1$
74
75
        private final String XML_ATTRIBUTE_VERSION = "version"; //$NON-NLS-1$
76
77
        private final String XML_ATTRIBUTE_ID = "id"; //$NON-NLS-1$
78
79
        private final String XML_ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
80
81
        private final String XML_ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$
82
83
        private int fVersion;
84
85
        private String fName;
86
87
        private Map fSettings;
88
89
        public void startElement(String uri, String localName, String qName,
90
                Attributes attributes) throws SAXException {
91
92
            if (qName.equals(XML_NODE_SETTING)) {
93
94
                final String key = attributes.getValue(XML_ATTRIBUTE_ID);
95
                final String value = attributes.getValue(XML_ATTRIBUTE_VALUE);
96
                fSettings.put(key, value);
97
98
            } else if (qName.equals(XML_NODE_PROFILE)) {
99
100
                fName = attributes.getValue(XML_ATTRIBUTE_NAME);
101
                fSettings = new HashMap(200);
102
103
            } else if (qName.equals(XML_NODE_ROOT)) {
104
105
                try {
106
                    fVersion = Integer.parseInt(attributes
107
                            .getValue(XML_ATTRIBUTE_VERSION));
108
                } catch (NumberFormatException ex) {
109
                    throw new SAXException(ex);
110
                }
111
112
            }
113
        }
114
115
        public Map getSettings() {
116
            return fSettings;
117
        }
118
119
        public int getVersion() {
120
            return fVersion;
121
        }
122
123
        public String getName() {
124
            return fName;
125
        }
126
127
    }
128
129
    /**
130
     * Deals with the messages in the properties file (cut n' pasted from a
131
     * generated class).
132
     */
133
    private final static class FormatterAppMessages {
134
        private static final String BUNDLE_NAME = "org.eclipse.jdt.core.formatter.FormatterAppMessages";//$NON-NLS-1$
135
136
        private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
137
                .getBundle(BUNDLE_NAME);
138
139
        public static String getString(String key) {
140
            try {
141
                return RESOURCE_BUNDLE.getString(key);
142
            } catch (MissingResourceException e) {
143
                return '!' + key + '!';
144
            }
145
        }
146
147
        public static String getFormattedString(String key, String arg) {
148
            return getFormattedString(key, new String[] { arg });
149
        }
150
151
        public static String getFormattedString(String key, String[] args) {
152
            return MessageFormat.format(getString(key), args);
153
        }
154
    }
155
    
156
    /*
157
     * FIXME This value should come from ProfileVersioner.CURRENT_VERSION, however
158
     * this class cannot be included here because it is internal to
159
     * org.eclipse.jdt.ui and becuase this plugin (org.eclipse.jdt.core) does
160
     * not require org.eclipse.jdt.ui (nor should it). Refactoring this to make
161
     * it an external class of org.eclipse.jdt.core would solve these problems.
162
     */
163
    int CURRENT_VERSION = 6;
164
165
    /**
166
     * Read the xml config file and return a Map representing the options that
167
     * are in the specified config file.
168
     */
169
    public Map readConfig(String filename) {
170
171
        try {
172
            final FileInputStream reader = new FileInputStream(new File(
173
                    filename));
174
            final ConfigHandler handler = new ConfigHandler();
175
176
            try {
177
                InputSource inputSource = new InputSource(reader);
178
                final SAXParserFactory factory = SAXParserFactory.newInstance();
179
                final SAXParser parser = factory.newSAXParser();
180
                parser.parse(inputSource, handler);
181
                if (handler.getVersion() != CURRENT_VERSION)
182
                    return null;
183
                configName = handler.getName();
184
                return handler.getSettings();
185
186
            } finally {
187
                try { reader.close(); } catch (IOException e) { /* ignore */ }
188
            }
189
190
        } catch (IOException e) {
191
            Util.log(e, FormatterAppMessages
192
                    .getString("ConfigFile.reading.error")); //$NON-NLS-1$
193
        } catch (SAXException e) {
194
            Util.log(e, FormatterAppMessages
195
                    .getString("ConfigFile.reading.error")); //$NON-NLS-1$
196
        } catch (ParserConfigurationException e) {
197
            Util.log(e, FormatterAppMessages
198
                    .getString("ConfigFile.reading.error")); //$NON-NLS-1$
199
        }
200
        return null;
201
    }
202
    
203
	/*
204
	 * Allow the formatter to run in a stand-alone mode.
205
	 */
206
	public static void main(String[] args) throws Exception {
207
		new CodeFormatterApplication().run(args);
208
	}
209
	
210
    /**
211
     * Runs the Java code formatter application
212
     */
213
    public Object run(Object args) throws Exception {
214
        
215
        ArrayList fileList = processCommandLine((String[]) args);
216
        
217
        // nothing to do
218
        if (fileList == null || fileList.isEmpty())
219
        	return EXIT_OK;
220
       
221
        if (!quiet) {
222
        	if (configName != null)
223
        		System.out.println(FormatterAppMessages.getFormattedString("CommandLine.config.file", configName)); //$NON-NLS-1$
224
            System.out.println(FormatterAppMessages.getString("CommandLine.start")); //$NON-NLS-1$
225
        }
226
        
227
        // format the list of files and/or directories
228
        while (!fileList.isEmpty()) {
229
        	File file = (File) fileList.remove(0);
230
        		
231
            if (file.isDirectory())
232
                formatDirTree(file);
233
            else
234
                formatFile(file);    
235
        }
236
        
237
        if (!quiet) {
238
            System.out.println(FormatterAppMessages.getString("CommandLine.done")); //$NON-NLS-1$
239
        }
240
        
241
        return EXIT_OK;
242
    }
243
244
    private void displayHelp(String message) {
245
        System.err.println(message);
246
        System.out.println(""); //$NON-NLS-1$
247
        displayHelp();
248
    }
249
250
    private String configName;
251
    
252
    /*
253
     * The output will look like this:
254
     * 
255
     * "Usage: eclipse -application org.eclipse.jdt.core.JavaCodeFormatter [ OPTIONS ] <files>
256
     *     <files>		Java source files and/or directories to format.
257
     *					Only files ending with .java will be formatted in the given directory.
258
     *  OPTIONS:
259
     *	   -config <file>		Use the formatting style from the specified config file.
260
     *							This file must be an xml file that has been exported by Eclipse 3.0.
261
     *     -help				Display this message.
262
     *     -quiet				Only print error messages.
263
     *	   -verbose				Be verbose about the formatting job.   
264
     */
265
    private void displayHelp() {
266
        String binaryName = "eclipse"; //$NON-NLS-1$ 
267
268
        // this is UG-LY. is there a way to make this look nicer?
269
        System.out.println(FormatterAppMessages.getFormattedString("CommandLine.usage", //$NON-NLS-1$
270
        		binaryName + " -application org.eclipse.jdt.core.JavaCodeFormatter")); //$NON-NLS-1$
271
        System.out.println(""); //$NON-NLS-1$
272
        
273
        System.out.println("   " + FormatterAppMessages.getString("CommandLine.files") //$NON-NLS-1$ //$NON-NLS-2$
274
                + "\t" + FormatterAppMessages.getString("CommandLine.files.msg1")); //$NON-NLS-1$ //$NON-NLS-2$
275
        System.out.println("\t\t" //$NON-NLS-1$
276
        		+ FormatterAppMessages.getFormattedString("CommandLine.files.msg2", ".java")); //$NON-NLS-1$ //$NON-NLS-2$ 
277
        
278
        System.out.println(FormatterAppMessages.getString("CommandLine.options")); //$NON-NLS-1$
279
        System.out.println("   " + FormatterAppMessages.getFormattedString("CommandLine.config", ARG_CONFIG) //$NON-NLS-1$ //$NON-NLS-2$ 
280
        		+ "\t" + FormatterAppMessages.getString("CommandLine.config.msg1")); //$NON-NLS-1$ //$NON-NLS-2$
281
        System.out.println("\t\t\t" + FormatterAppMessages.getString("CommandLine.config.msg2")); //$NON-NLS-1$ //$NON-NLS-2$
282
        System.out.println("   " + ARG_HELP + "\t\t" + FormatterAppMessages.getString("CommandLine.help")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
283
        System.out.println("   " + ARG_QUIET + "\t\t" + FormatterAppMessages.getString("CommandLine.quiet")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
284
        System.out.println("   " + ARG_VERBOSE +"\t\t" + FormatterAppMessages.getString("CommandLine.verbose")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
285
    }
286
    
287
    private final String ARG_HELP =    "-help"; //$NON-NLS-1$
288
    private final String ARG_CONFIG =  "-config"; //$NON-NLS-1$
289
    private final String ARG_VERBOSE = "-verbose"; //$NON-NLS-1$
290
    private final String ARG_QUIET = "-quiet"; //$NON-NLS-1$
291
    private boolean verbose = false;
292
    private boolean quiet = false;
293
    
294
    private ArrayList processCommandLine(String[] argsArray) {
295
296
        ArrayList args = new ArrayList();
297
        for (int i = 0; i < argsArray.length; i++) {
298
			args.add(argsArray[i]);
299
		}
300
        
301
        // look for flag-like args
302
        if (args.remove(ARG_HELP)) {
303
            displayHelp();
304
            return null;
305
        }
306
        if (args.remove(ARG_VERBOSE))
307
            verbose = true;
308
        if (args.remove(ARG_QUIET)) 
309
        	quiet = true;
310
        
311
        if (quiet && verbose) {
312
        	displayHelp(FormatterAppMessages.getFormattedString
313
        			("CommandLineError.quiet.verbose", new String[] {ARG_QUIET, ARG_VERBOSE})); //$NON-NLS-1$
314
        	return null;
315
        }
316
        args.remove("-pdelaunch"); //$NON-NLS-1$
317
318
        // look for flag/param args
319
        int index = args.indexOf(ARG_CONFIG);
320
        if (index >= 0) {
321
            args.remove(index);
322
            String configFile = (String) args.remove(index);
323
            options = readConfig(configFile);
324
            if (options == null) {
325
                displayHelp(FormatterAppMessages
326
                        .getFormattedString("CommandLineError.config", configFile)); //$NON-NLS-1$
327
                return null;
328
            }
329
        }
330
331
        // only the files and directories should remain
332
        ArrayList fileList = new ArrayList();
333
        while (!args.isEmpty()) {
334
			String fileName = (String) args.remove(0);
335
			File file = new File(fileName);
336
			if (file.exists()) {
337
				fileList.add(file);
338
			} else {
339
				displayHelp(FormatterAppMessages
340
					.getFormattedString("CommandLineError.file", fileName)); //$NON-NLS-1$
341
				return null;
342
			}
343
		}
344
        
345
        if (fileList.isEmpty())
346
        	displayHelp(FormatterAppMessages.getString("CommandLineError.file.dir")); //$NON-NLS-1$
347
        	
348
        return fileList;
349
    }
350
351
    /**
352
     * Recursively format the Java source code that is contained in the
353
     * directory rooted at dir.
354
     */
355
    private void formatDirTree(File dir) {
356
357
        File[] files = dir.listFiles();
358
        if (files == null)
359
            return;
360
361
        for (int i = 0; i < files.length; i++) {
362
            File file = files[i];
363
            if (file.isDirectory()) {
364
                formatDirTree(file);
365
            } else if (file.getPath().endsWith(".java")) { //$NON-NLS-1$
366
                formatFile(file);
367
            }
368
        }
369
    }
370
371
    // internal representation of configuration options in the xml file
372
    private Map options = null;
373
374
    /**
375
     * Format the given Java source file.
376
     */
377
    private void formatFile(File file) {
378
        
379
        IDocument doc = new Document();
380
        try {
381
            // read the file
382
            final BufferedReader in = new BufferedReader(new FileReader(file));
383
            if (verbose) {           
384
                System.out.println(FormatterAppMessages.getFormattedString
385
                		("CommandLine.formatting", file.getName())); //$NON-NLS-1$
386
            }
387
            String line;
388
            String contents = ""; //$NON-NLS-1$
389
            try {
390
                while ((line = in.readLine()) != null)
391
                    contents = contents
392
                            + System.getProperty("line.separator") + line; //$NON-NLS-1$
393
            } finally {
394
                try { in.close(); } catch (IOException e) { /* ignore */  }
395
            }
396
          
397
            // format the file (the meat and potatoes)
398
            doc.set(contents);
399
            TextEdit edit = ToolFactory.createCodeFormatter(options).format(
400
                    CodeFormatter.K_COMPILATION_UNIT, doc.get(), 0,
401
                    doc.getLength(), 0, null);
402
            if (edit != null) {
403
                edit.apply(doc);
404
            } else {            	
405
                System.err.println
406
                	(FormatterAppMessages.getFormattedString("Edit.problem", file.getName())); //$NON-NLS-1$
407
                return;
408
            }
409
        
410
            // write the file
411
            final Writer out = new BufferedWriter(new FileWriter(file, false));
412
            try {
413
                out.write(doc.get());
414
                out.flush();
415
            } finally {
416
                try { out.close(); } catch (IOException e) { /* ignore */ }
417
            }
418
            
419
        } catch (IOException e) {
420
            String errorMessage = FormatterAppMessages.getString("Exception.io") + " " //$NON-NLS-1$ //$NON-NLS-2$
421
            	+ e.getLocalizedMessage();
422
            Util.log(e, errorMessage);
423
            System.err.println(errorMessage); 
424
            System.err.println(FormatterAppMessages.getString("Exception.skip")); //$NON-NLS-1$
425
            
426
        }  catch (BadLocationException e) {
427
            String errorMessage = FormatterAppMessages.getString("Exception.bad.location") + " " //$NON-NLS-1$ //$NON-NLS-2$
428
    			+ e.getLocalizedMessage();
429
            Util.log(e, errorMessage);
430
            System.err.println(errorMessage); 
431
            System.err.println(FormatterAppMessages.getString("Exception.skip")); //$NON-NLS-1$
432
        }
433
    }
434
435
}
(-)formatter/org/eclipse/jdt/core/formatter/FormatterAppMessages.properties (+47 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004 Ben Konrath <ben@bagu.org>
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     Ben Konrath <ben@bagu.org> - initial implementation
10
 *******************************************************************************/
11
12
CommandLine.start=Starting format job ...
13
CommandLine.done=Done.
14
CommandLine.config.file=Configuration Name: {0}
15
CommandLine.formatting=Formatting: {0}
16
17
CommandLine.usage=Usage: {0} [ OPTIONS ] <files>
18
19
CommandLine.files=<files>
20
CommandLine.files.msg1=Java source files and/or directories to format.
21
CommandLine.files.msg2=Only files ending with {0} will be formatted in the given directory.
22
23
CommandLine.options=OPTIONS:
24
CommandLine.config={0} <file>
25
CommandLine.config.msg1=Use the formatting style from the specified config file.
26
CommandLine.config.msg2=This file must be an xml file that has been exported by Eclipse 3.0.
27
CommandLine.help=Display this message.
28
CommandLine.quiet=Only print error messages.
29
CommandLine.verbose=Be verbose about the formatting job.
30
31
32
CommandLineError.file={0} does not exsit. Please specify only valid Java Source files.
33
CommandLineError.config=There was problem reading the config file, {0}.
34
CommandLineError.file.dir=You must specify at least one file or dirctory to format.
35
CommandLineError.quiet.verbose=You cannot use the options {0} and {1} together.
36
37
38
Exception.io=Caught IOExecption:
39
Exception.bad.location=Caught BadLocationException:  
40
Exception.skip=Skipping File.
41
42
43
ConfigFile.reading.error=Error Reading config file.
44
45
46
Edit.problem=The Eclipse formatter had a problem {0}, Skipping.
47

Return to bug 75333