fixed "replace all" bug
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / actions / ExternalPHPParser.java
1 package net.sourceforge.phpeclipse.actions;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.text.MessageFormat;
6 import java.util.Hashtable;
7
8 import net.sourceforge.phpdt.internal.ui.util.StringUtil;
9 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
10 import net.sourceforge.phpeclipse.views.PHPConsole;
11
12 import org.eclipse.core.resources.IFile;
13 import org.eclipse.core.resources.IMarker;
14 import org.eclipse.core.runtime.CoreException;
15 import org.eclipse.jface.dialogs.MessageDialog;
16 import org.eclipse.jface.preference.IPreferenceStore;
17 import org.eclipse.ui.texteditor.MarkerUtilities;
18
19 /**
20  * Calls the external parser and generates problem markers if necessary
21  */
22 public class ExternalPHPParser {
23         private final static String PROBLEM_ID = "net.sourceforge.phpeclipse.problem";
24         // strings for external parser call
25         private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
26         private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
27         public static final int ERROR = 2;
28         public static final int WARNING = 1;
29         public static final int INFO = 0;
30         public static final int TASK = 3;
31         // TODO design error? Analyze why fileToParse must be static ???
32         final protected IFile fFileToParse;
33
34         public ExternalPHPParser(IFile file) {
35                 fFileToParse = file;
36         }
37         /**
38          * Call the php parse command ( php -l -f <filename> ) and create
39          * markers according to the external parser output.
40          * 
41          * @param file
42          *            the file that will be parsed
43          */
44         public void phpExternalParse() {
45                 //IFile file = (IFile) resource;
46                 //  final IPath path = file.getFullPath();
47                 final IPreferenceStore store = PHPeclipsePlugin.getDefault()
48                                 .getPreferenceStore();
49                 final String filename = fFileToParse.getLocation().toString();
50
51                 final String[] arguments = {filename};
52                 final MessageFormat form = new MessageFormat(store
53                                 .getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
54                 final String command = form.format(arguments);
55
56                 final String parserResult = getParserOutput(command,
57                                 "External parser: ");
58
59                 try {
60                         // parse the buffer to find the errors and warnings
61                         createMarkers(parserResult, fFileToParse);
62                 } catch (CoreException e) {
63                 }
64         }
65
66         /**
67          * Create markers according to the external parser output.
68          * 
69          * @param output
70          *            the external parser output
71          * @param file
72          *            the file that was parsed.
73          */
74         protected void createMarkers(final String output, final IFile file)
75                         throws CoreException {
76                 // delete all markers
77                 file.deleteMarkers(PROBLEM_ID, false, 0);
78
79                 int indx = 0;
80                 int brIndx;
81                 boolean flag = true;
82                 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
83                         // newer php error output (tested with 4.2.3)
84                         scanLine(output, file, indx, brIndx);
85                         indx = brIndx + 6;
86                         flag = false;
87                 }
88                 if (flag) {
89                         while ((brIndx = output.indexOf("<br>", indx)) != -1) {
90                                 // older php error output (tested with 4.2.3)
91                                 scanLine(output, file, indx, brIndx);
92                                 indx = brIndx + 4;
93                         }
94                 }
95         }
96
97         private void scanLine(final String output, final IFile file,
98                         final int indx, final int brIndx) throws CoreException {
99                 String current;
100                 //  String outLineNumberString; never used
101                 final StringBuffer lineNumberBuffer = new StringBuffer(10);
102                 char ch;
103                 current = output.substring(indx, brIndx);
104
105                 if (current.indexOf(PARSE_WARNING_STRING) != -1
106                                 || current.indexOf(PARSE_ERROR_STRING) != -1) {
107                         final int onLine = current.indexOf("on line <b>");
108                         if (onLine != -1) {
109                                 lineNumberBuffer.delete(0, lineNumberBuffer.length());
110                                 for (int i = onLine; i < current.length(); i++) {
111                                         ch = current.charAt(i);
112                                         if ('0' <= ch && '9' >= ch) {
113                                                 lineNumberBuffer.append(ch);
114                                         }
115                                 }
116
117                                 final int lineNumber = Integer.parseInt(lineNumberBuffer
118                                                 .toString());
119
120                                 final Hashtable attributes = new Hashtable();
121
122                                 current = StringUtil.replaceAll(current, "\n", "");
123                                 current = StringUtil.replaceAll(current, "<b>", "");
124                                 current = StringUtil.replaceAll(current, "</b>", "");
125                                 MarkerUtilities.setMessage(attributes, current);
126
127                                 if (current.indexOf(PARSE_ERROR_STRING) != -1)
128                                         attributes.put(IMarker.SEVERITY, new Integer(
129                                                         IMarker.SEVERITY_ERROR));
130                                 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
131                                         attributes.put(IMarker.SEVERITY, new Integer(
132                                                         IMarker.SEVERITY_WARNING));
133                                 else
134                                         attributes.put(IMarker.SEVERITY, new Integer(
135                                                         IMarker.SEVERITY_INFO));
136                                 MarkerUtilities.setLineNumber(attributes, lineNumber);
137                                 MarkerUtilities.createMarker(file, attributes, PROBLEM_ID);
138                         }
139                 }
140         }
141
142         /**
143          * This will set a marker.
144          * 
145          * @param file
146          *            the file that generated the marker
147          * @param message
148          *            the message
149          * @param charStart
150          *            the starting character
151          * @param charEnd
152          *            the end character
153          * @param errorLevel
154          *            the error level ({@link ExternalPHPParser#ERROR},
155          *            {@link ExternalPHPParser#INFO},
156          *            {@link ExternalPHPParser#WARNING}),
157          *            {@link ExternalPHPParser#TASK})
158          * @throws CoreException
159          *             an exception throwed by the MarkerUtilities
160          */
161         private void setMarker(final IFile file, final String message,
162                         final int charStart, final int charEnd, final int errorLevel)
163                         throws CoreException {
164                 if (file != null) {
165                         final Hashtable attributes = new Hashtable();
166                         MarkerUtilities.setMessage(attributes, message);
167                         switch (errorLevel) {
168                                 case ERROR :
169                                         attributes.put(IMarker.SEVERITY, new Integer(
170                                                         IMarker.SEVERITY_ERROR));
171                                         break;
172                                 case WARNING :
173                                         attributes.put(IMarker.SEVERITY, new Integer(
174                                                         IMarker.SEVERITY_WARNING));
175                                         break;
176                                 case INFO :
177                                         attributes.put(IMarker.SEVERITY, new Integer(
178                                                         IMarker.SEVERITY_INFO));
179                                         break;
180                                 case TASK :
181                                         attributes.put(IMarker.SEVERITY, new Integer(IMarker.TASK));
182                                         break;
183                         }
184                         MarkerUtilities.setCharStart(attributes, charStart);
185                         MarkerUtilities.setCharEnd(attributes, charEnd);
186                         MarkerUtilities.createMarker(file, attributes, PROBLEM_ID);
187                 }
188         }
189
190         /**
191          * This will set a marker.
192          * 
193          * @param file
194          *            the file that generated the marker
195          * @param message
196          *            the message
197          * @param line
198          *            the line number
199          * @param errorLevel
200          *            the error level ({@link ExternalPHPParser#ERROR},
201          *            {@link ExternalPHPParser#INFO},
202          *            {@link ExternalPHPParser#WARNING})
203          * @throws CoreException
204          *             an exception throwed by the MarkerUtilities
205          */
206         private void setMarker(final IFile file, final String message,
207                         final int line, final int errorLevel, final String location)
208                         throws CoreException {
209                 if (file != null) {
210                         String markerKind = PROBLEM_ID;
211                         final Hashtable attributes = new Hashtable();
212                         MarkerUtilities.setMessage(attributes, message);
213                         switch (errorLevel) {
214                                 case ERROR :
215                                         attributes.put(IMarker.SEVERITY, new Integer(
216                                                         IMarker.SEVERITY_ERROR));
217                                         break;
218                                 case WARNING :
219                                         attributes.put(IMarker.SEVERITY, new Integer(
220                                                         IMarker.SEVERITY_WARNING));
221                                         break;
222                                 case INFO :
223                                         attributes.put(IMarker.SEVERITY, new Integer(
224                                                         IMarker.SEVERITY_INFO));
225                                         break;
226                                 case TASK :
227                                         attributes.put(IMarker.SEVERITY, new Integer(
228                                                         IMarker.SEVERITY_INFO));
229                                         markerKind = IMarker.TASK;
230                                         break;
231                         }
232                         attributes.put(IMarker.LOCATION, location);
233                         MarkerUtilities.setLineNumber(attributes, line);
234                         MarkerUtilities.createMarker(file, attributes, markerKind);
235                 }
236         }
237
238         /**
239          * This will set a marker.
240          * 
241          * @param message
242          *            the message
243          * @param charStart
244          *            the starting character
245          * @param charEnd
246          *            the end character
247          * @param errorLevel
248          *            the error level ({@link ExternalPHPParser#ERROR},
249          *            {@link ExternalPHPParser#INFO},
250          *            {@link ExternalPHPParser#WARNING})
251          * @throws CoreException
252          *             an exception throwed by the MarkerUtilities
253          */
254         private void setMarker(final String message, final int charStart,
255                         final int charEnd, final int errorLevel, final String location)
256                         throws CoreException {
257                 if (fFileToParse != null) {
258                         setMarker(fFileToParse, message, charStart, charEnd, errorLevel,
259                                         location);
260                 }
261         }
262
263         /**
264          * This will set a marker.
265          * 
266          * @param file
267          *            the file that generated the marker
268          * @param message
269          *            the message
270          * @param charStart
271          *            the starting character
272          * @param charEnd
273          *            the end character
274          * @param errorLevel
275          *            the error level ({@link ExternalPHPParser#ERROR},
276          *            {@link ExternalPHPParser#INFO},
277          *            {@link ExternalPHPParser#WARNING})
278          * @param location
279          *            the location of the error
280          * @throws CoreException
281          *             an exception throwed by the MarkerUtilities
282          */
283         private void setMarker(final IFile file, final String message,
284                         final int charStart, final int charEnd, final int errorLevel,
285                         final String location) throws CoreException {
286                 if (file != null) {
287                         final Hashtable attributes = new Hashtable();
288                         MarkerUtilities.setMessage(attributes, message);
289                         switch (errorLevel) {
290                                 case ERROR :
291                                         attributes.put(IMarker.SEVERITY, new Integer(
292                                                         IMarker.SEVERITY_ERROR));
293                                         break;
294                                 case WARNING :
295                                         attributes.put(IMarker.SEVERITY, new Integer(
296                                                         IMarker.SEVERITY_WARNING));
297                                         break;
298                                 case INFO :
299                                         attributes.put(IMarker.SEVERITY, new Integer(
300                                                         IMarker.SEVERITY_INFO));
301                                         break;
302                                 case TASK :
303                                         attributes.put(IMarker.SEVERITY, new Integer(IMarker.TASK));
304                                         break;
305                         }
306                         attributes.put(IMarker.LOCATION, location);
307                         MarkerUtilities.setCharStart(attributes, charStart);
308                         MarkerUtilities.setCharEnd(attributes, charEnd);
309                         MarkerUtilities.createMarker(file, attributes, PROBLEM_ID); //IMarker.PROBLEM);
310                 }
311         }
312
313         private String getParserOutput(String command, String consoleMessage) {
314                 try {
315                         PHPConsole console = null;
316                         try {
317                                 console = PHPConsole.getInstance();
318                                 if (console != null) {
319                                         console.write(consoleMessage + command + "\n");
320                                 }
321                         } catch (Throwable th) {
322
323                         }
324
325                         Runtime runtime = Runtime.getRuntime();
326
327                         // runs the command
328                         Process p = runtime.exec(command);
329
330                         // gets the input stream to have the post-compile-time information
331                         InputStream stream = p.getInputStream();
332
333                         // get the string from Stream
334                         String consoleOutput = PHPConsole.getStringFromStream(stream);
335
336                         // prints out the information
337                         if (console != null) {
338                                 console.write(consoleOutput);
339                         }
340                         return consoleOutput; 
341
342                 } catch (IOException e) {
343                         MessageDialog
344                                         .openInformation(null, "IOException: ", e.getMessage());
345                 }
346                 return "";
347         }
348 }