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 (+427 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
 */
58
public class CodeFormatterApplication implements IPlatformRunnable {
59
60
    /**
61
     * A SAX event handler to parse the config xml.
62
     */
63
    private final static class ConfigHandler extends DefaultHandler {
64
65
        /**
66
         * Identifiers for the XML file.
67
         */
68
        private final String XML_NODE_ROOT = "profiles"; //$NON-NLS-1$
69
70
        private final String XML_NODE_PROFILE = "profile"; //$NON-NLS-1$
71
72
        private final String XML_NODE_SETTING = "setting"; //$NON-NLS-1$
73
74
        private final String XML_ATTRIBUTE_VERSION = "version"; //$NON-NLS-1$
75
76
        private final String XML_ATTRIBUTE_ID = "id"; //$NON-NLS-1$
77
78
        private final String XML_ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
79
80
        private final String XML_ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$
81
82
        private int fVersion;
83
84
        private String fName;
85
86
        private Map fSettings;
87
88
        public void startElement(String uri, String localName, String qName,
89
                Attributes attributes) throws SAXException {
90
91
            if (qName.equals(XML_NODE_SETTING)) {
92
93
                final String key = attributes.getValue(XML_ATTRIBUTE_ID);
94
                final String value = attributes.getValue(XML_ATTRIBUTE_VALUE);
95
                fSettings.put(key, value);
96
97
            } else if (qName.equals(XML_NODE_PROFILE)) {
98
99
                fName = attributes.getValue(XML_ATTRIBUTE_NAME);
100
                fSettings = new HashMap(200);
101
102
            } else if (qName.equals(XML_NODE_ROOT)) {
103
104
                try {
105
                    fVersion = Integer.parseInt(attributes
106
                            .getValue(XML_ATTRIBUTE_VERSION));
107
                } catch (NumberFormatException ex) {
108
                    throw new SAXException(ex);
109
                }
110
111
            }
112
        }
113
114
        public Map getSettings() {
115
            return fSettings;
116
        }
117
118
        public int getVersion() {
119
            return fVersion;
120
        }
121
122
        public String getName() {
123
            return fName;
124
        }
125
126
    }
127
128
    /**
129
     * Deals with the messages in the properties file (cut n' pasted from a
130
     * generated class).
131
     */
132
    private final static class FormatterAppMessages {
133
        private static final String BUNDLE_NAME = "org.eclipse.jdt.core.formatter.FormatterAppMessages";//$NON-NLS-1$
134
135
        private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
136
                .getBundle(BUNDLE_NAME);
137
138
        public static String getString(String key) {
139
            try {
140
                return RESOURCE_BUNDLE.getString(key);
141
            } catch (MissingResourceException e) {
142
                return '!' + key + '!';
143
            }
144
        }
145
146
        public static String getFormattedString(String key, String arg) {
147
            return getFormattedString(key, new String[] { arg });
148
        }
149
150
        public static String getFormattedString(String key, String[] args) {
151
            return MessageFormat.format(getString(key), args);
152
        }
153
    }
154
    
155
    /*
156
     * FIXME This value should come from ProfileVersioner.CURRENT_VERSION, however
157
     * this class cannot be included here because it is internal to
158
     * org.eclipse.jdt.ui and becuase this plugin (org.eclipse.jdt.core) does
159
     * not require org.eclipse.jdt.ui (nor should it). Refactoring this to make
160
     * it an external class of org.eclipse.jdt.core would solve these problems.
161
     */
162
    int CURRENT_VERSION = 6;
163
164
    /**
165
     * Read the xml config file and return a Map representing the options that
166
     * are in the specified config file.
167
     */
168
    public Map readConfig(String filename) {
169
170
        try {
171
            final FileInputStream reader = new FileInputStream(new File(
172
                    filename));
173
            final ConfigHandler handler = new ConfigHandler();
174
175
            try {
176
                InputSource inputSource = new InputSource(reader);
177
                final SAXParserFactory factory = SAXParserFactory.newInstance();
178
                final SAXParser parser = factory.newSAXParser();
179
                parser.parse(inputSource, handler);
180
                if (handler.getVersion() != CURRENT_VERSION)
181
                    return null;
182
                configName = handler.getName();
183
                return handler.getSettings();
184
185
            } finally {
186
                try { reader.close(); } catch (IOException e) { /* ignore */ }
187
            }
188
189
        } catch (IOException e) {
190
            Util.log(e, FormatterAppMessages
191
                    .getString("ConfigFile.reading.error")); //$NON-NLS-1$
192
        } catch (SAXException e) {
193
            Util.log(e, FormatterAppMessages
194
                    .getString("ConfigFile.reading.error")); //$NON-NLS-1$
195
        } catch (ParserConfigurationException e) {
196
            Util.log(e, FormatterAppMessages
197
                    .getString("ConfigFile.reading.error")); //$NON-NLS-1$
198
        }
199
        return null;
200
    }
201
    
202
    /**
203
     * Runs the Java code formatter application
204
     */
205
    public Object run(Object args) throws Exception {
206
        
207
        ArrayList fileList = processCommandLine((String[]) args);
208
        
209
        // nothing to do
210
        if (fileList == null || fileList.isEmpty())
211
        	return EXIT_OK;
212
       
213
        if (!quiet) {
214
        	if (configName != null)
215
        		System.out.println(FormatterAppMessages.getFormattedString("CommandLine.config.file", configName)); //$NON-NLS-1$
216
            System.out.println(FormatterAppMessages.getString("CommandLine.start")); //$NON-NLS-1$
217
        }
218
        
219
        // format the list of files and/or directories
220
        while (!fileList.isEmpty()) {
221
        	File file = (File) fileList.remove(0);
222
        		
223
            if (file.isDirectory())
224
                formatDirTree(file);
225
            else
226
                formatFile(file);    
227
        }
228
        
229
        if (!quiet) {
230
            System.out.println(FormatterAppMessages.getString("CommandLine.done")); //$NON-NLS-1$
231
        }
232
        
233
        return EXIT_OK;
234
    }
235
236
    private void displayHelp(String message) {
237
        System.err.println(message);
238
        System.out.println(""); //$NON-NLS-1$
239
        displayHelp();
240
    }
241
242
    private String configName;
243
    
244
    /*
245
     * The output will look like this:
246
     * 
247
     * "Usage: eclipse -application org.eclipse.jdt.core.JavaCodeFormatter [ OPTIONS ] <files>
248
     *     <files>		Java source files and/or directories to format.
249
     *					Only files ending with .java will be formatted in the given directory.
250
     *  OPTIONS:
251
     *	   -config <file>		Use the formatting style from the specified config file.
252
     *							This file must be an xml file that has been exported by Eclipse 3.0.
253
     *     -help				Display this message.
254
     *     -quiet				Only print error messages.
255
     *	   -verbose				Be verbose about the formatting job.   
256
     */
257
    private void displayHelp() {
258
        String binaryName = Platform.getOS().equals(Platform.OS_WIN32) ? "eclipse.exe" : "eclipse"; //$NON-NLS-1$ //$NON-NLS-2$
259
260
        // this is UG-LY. is there a way to make this look nicer?
261
        System.out.println(FormatterAppMessages.getFormattedString("CommandLine.usage", //$NON-NLS-1$
262
        		binaryName + " -application org.eclipse.jdt.core.JavaCodeFormatter")); //$NON-NLS-1$
263
        System.out.println(""); //$NON-NLS-1$
264
        
265
        System.out.println("   " + FormatterAppMessages.getString("CommandLine.files") //$NON-NLS-1$ //$NON-NLS-2$
266
                + "\t" + FormatterAppMessages.getString("CommandLine.files.msg1")); //$NON-NLS-1$ //$NON-NLS-2$
267
        System.out.println("\t\t" //$NON-NLS-1$
268
        		+ FormatterAppMessages.getFormattedString("CommandLine.files.msg2", ".java")); //$NON-NLS-1$ //$NON-NLS-2$ 
269
        
270
        System.out.println(FormatterAppMessages.getString("CommandLine.options")); //$NON-NLS-1$
271
        System.out.println("   " + FormatterAppMessages.getFormattedString("CommandLine.config", ARG_CONFIG) //$NON-NLS-1$ //$NON-NLS-2$ 
272
        		+ "\t" + FormatterAppMessages.getString("CommandLine.config.msg1")); //$NON-NLS-1$ //$NON-NLS-2$
273
        System.out.println("\t\t\t" + FormatterAppMessages.getString("CommandLine.config.msg2")); //$NON-NLS-1$ //$NON-NLS-2$
274
        System.out.println("   " + ARG_HELP + "\t\t" + FormatterAppMessages.getString("CommandLine.help")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
275
        System.out.println("   " + ARG_QUIET + "\t\t" + FormatterAppMessages.getString("CommandLine.quiet")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
276
        System.out.println("   " + ARG_VERBOSE +"\t\t" + FormatterAppMessages.getString("CommandLine.verbose")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
277
    }
278
    
279
    private final String ARG_HELP =    "-help"; //$NON-NLS-1$
280
    private final String ARG_CONFIG =  "-config"; //$NON-NLS-1$
281
    private final String ARG_VERBOSE = "-verbose"; //$NON-NLS-1$
282
    private final String ARG_QUIET = "-quiet"; //$NON-NLS-1$
283
    private boolean verbose = false;
284
    private boolean quiet = false;
285
    
286
    private ArrayList processCommandLine(String[] argsArray) {
287
288
        ArrayList args = new ArrayList();
289
        for (int i = 0; i < argsArray.length; i++) {
290
			args.add(argsArray[i]);
291
		}
292
        
293
        // look for flag-like args
294
        if (args.remove(ARG_HELP)) {
295
            displayHelp();
296
            return null;
297
        }
298
        if (args.remove(ARG_VERBOSE))
299
            verbose = true;
300
        if (args.remove(ARG_QUIET)) 
301
        	quiet = true;
302
        
303
        if (quiet && verbose) {
304
        	displayHelp(FormatterAppMessages.getFormattedString
305
        			("CommandLineError.quiet.verbose", new String[] {ARG_QUIET, ARG_VERBOSE})); //$NON-NLS-1$
306
        	return null;
307
        }
308
        args.remove("-pdelaunch"); //$NON-NLS-1$
309
310
        // look for flag/param args
311
        int index = args.indexOf(ARG_CONFIG);
312
        if (index >= 0) {
313
            args.remove(index);
314
            String configFile = (String) args.remove(index);
315
            options = readConfig(configFile);
316
            if (options == null) {
317
                displayHelp(FormatterAppMessages
318
                        .getFormattedString("CommandLineError.config", configFile)); //$NON-NLS-1$
319
                return null;
320
            }
321
        }
322
323
        // only the files and directories should remain
324
        ArrayList fileList = new ArrayList();
325
        while (!args.isEmpty()) {
326
			String fileName = (String) args.remove(0);
327
			File file = new File(fileName);
328
			if (file.exists()) {
329
				fileList.add(file);
330
			} else {
331
				displayHelp(FormatterAppMessages
332
					.getFormattedString("CommandLineError.file", fileName)); //$NON-NLS-1$
333
				return null;
334
			}
335
		}
336
        
337
        if (fileList.isEmpty())
338
        	displayHelp(FormatterAppMessages.getString("CommandLineError.file.dir")); //$NON-NLS-1$
339
        	
340
        return fileList;
341
    }
342
343
    /**
344
     * Recursively format the Java source code that is contained in the
345
     * directory rooted at dir.
346
     */
347
    private void formatDirTree(File dir) {
348
349
        File[] files = dir.listFiles();
350
        if (files == null)
351
            return;
352
353
        for (int i = 0; i < files.length; i++) {
354
            File file = files[i];
355
            if (file.isDirectory()) {
356
                formatDirTree(file);
357
            } else if (file.getPath().endsWith(".java")) { //$NON-NLS-1$
358
                formatFile(file);
359
            }
360
        }
361
    }
362
363
    // internal representation of configuration options in the xml file
364
    private Map options = null;
365
366
    /**
367
     * Format the given Java source file.
368
     */
369
    private void formatFile(File file) {
370
        
371
        IDocument doc = new Document();
372
        try {
373
            // read the file
374
            final BufferedReader in = new BufferedReader(new FileReader(file));
375
            if (verbose) {           
376
                System.out.println(FormatterAppMessages.getFormattedString
377
                		("CommandLine.formatting", file.getName())); //$NON-NLS-1$
378
            }
379
            String line;
380
            String contents = ""; //$NON-NLS-1$
381
            try {
382
                while ((line = in.readLine()) != null)
383
                    contents = contents
384
                            + System.getProperty("line.separator") + line; //$NON-NLS-1$
385
            } finally {
386
                try { in.close(); } catch (IOException e) { /* ignore */  }
387
            }
388
          
389
            // format the file (the meat and potatoes)
390
            doc.set(contents);
391
            TextEdit edit = ToolFactory.createCodeFormatter(options).format(
392
                    CodeFormatter.K_COMPILATION_UNIT, doc.get(), 0,
393
                    doc.getLength(), 0, null);
394
            if (edit != null) {
395
                edit.apply(doc);
396
            } else {            	
397
                System.err.println
398
                	(FormatterAppMessages.getFormattedString("Edit.problem", file.getName())); //$NON-NLS-1$
399
                return;
400
            }
401
        
402
            // write the file
403
            final Writer out = new BufferedWriter(new FileWriter(file, false));
404
            try {
405
                out.write(doc.get());
406
                out.flush();
407
            } finally {
408
                try { out.close(); } catch (IOException e) { /* ignore */ }
409
            }
410
            
411
        } catch (IOException e) {
412
            String errorMessage = FormatterAppMessages.getString("Exception.io") + " " //$NON-NLS-1$ //$NON-NLS-2$
413
            	+ e.getLocalizedMessage();
414
            Util.log(e, errorMessage);
415
            System.err.println(errorMessage); 
416
            System.err.println(FormatterAppMessages.getString("Exception.skip")); //$NON-NLS-1$
417
            
418
        }  catch (BadLocationException e) {
419
            String errorMessage = FormatterAppMessages.getString("Exception.bad.location") + " " //$NON-NLS-1$ //$NON-NLS-2$
420
    			+ e.getLocalizedMessage();
421
            Util.log(e, errorMessage);
422
            System.err.println(errorMessage); 
423
            System.err.println(FormatterAppMessages.getString("Exception.skip")); //$NON-NLS-1$
424
        }
425
    }
426
427
}
(-)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