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