diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java index 9ccdc683849..e2934ce540c 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation * Tianchao Li (tianchao.li@gmail.com) - arbitrary build directory (bug #136136) + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.make.core; @@ -205,11 +206,11 @@ public class MakeBuilder extends ACBuilder { if (last == null) { last = new Integer(100); } - StreamMonitor streamMon = new StreamMonitor(new SubProgressMonitor(monitor, 100), cos, last.intValue()); ErrorParserManager epm = new ErrorParserManager(getProject(), workingDirectoryURI, this, info.getErrorParsers()); - epm.setOutputStream(streamMon); - OutputStream stdout = epm.getOutputStream(); - OutputStream stderr = epm.getOutputStream(); + epm.setOutputStream(cos); + StreamMonitor streamMon = new StreamMonitor(new SubProgressMonitor(monitor, 100), epm, last.intValue()); + OutputStream stdout = streamMon; + OutputStream stderr = streamMon; // Sniff console output for scanner info ConsoleOutputSniffer sniffer = ScannerInfoConsoleParserFactory.getMakeBuilderOutputSniffer( stdout, stderr, getProject(), workingDirectory, null, this, null); @@ -256,7 +257,6 @@ public class MakeBuilder extends ACBuilder { monitor.subTask(MakeMessages.getString("MakeBuilder.Creating_Markers")); //$NON-NLS-1$ consoleOut.close(); consoleErr.close(); - epm.reportProblems(); cos.close(); } } catch (Exception e) { diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java index f39c468f3fa..fad2e606c7e 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Intel Corporation and others. + * Copyright (c) 2007, 2010 Intel Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * Contributors: * Intel Corporation - Initial API and implementation * IBM Corporation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.managedbuilder.internal.core; @@ -1035,7 +1036,6 @@ public class CommonBuilder extends ACBuilder { monitor.subTask(ManagedMakeMessages .getResourceString(MARKERS)); //TODO: addBuilderMarkers(epm); - epm.reportProblems(); bsMngr.setProjectBuildState(currentProject, pBS); } else { @@ -1912,11 +1912,11 @@ public class CommonBuilder extends ACBuilder { if (last == null) { last = new Integer(100); } - StreamMonitor streamMon = new StreamMonitor(new SubProgressMonitor(monitor, 100), cos, last.intValue()); ErrorParserManager epm = new ErrorParserManager(currProject, workingDirectoryURI, this, builder.getErrorParsers()); - epm.setOutputStream(streamMon); - OutputStream stdout = epm.getOutputStream(); - OutputStream stderr = epm.getOutputStream(); + epm.setOutputStream(cos); + StreamMonitor streamMon = new StreamMonitor(new SubProgressMonitor(monitor, 100), epm, last.intValue()); + OutputStream stdout = streamMon; + OutputStream stderr = streamMon; // Sniff console output for scanner info // ICfgScannerConfigBuilderInfo2Set container = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(cfg); // CfgInfoContext context = new CfgInfoContext(cfg); @@ -1980,7 +1980,6 @@ public class CommonBuilder extends ACBuilder { monitor.subTask(ManagedMakeMessages.getResourceString("MakeBuilder.Creating_Markers")); //$NON-NLS-1$ consoleOut.close(); consoleErr.close(); - epm.reportProblems(); cos.close(); } } catch (Exception e) { diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java index 180ad899bfa..551363bca24 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/GeneratedMakefileBuilder.java @@ -1146,7 +1146,6 @@ public class GeneratedMakefileBuilder extends ACBuilder { monitor.subTask(ManagedMakeMessages .getResourceString(MARKERS)); addBuilderMarkers(epm); - epm.reportProblems(); consoleOutStream.close(); } } @@ -1334,10 +1333,8 @@ public class GeneratedMakefileBuilder extends ACBuilder { epmOutputStream.close(); epmOutputStream = null; // Generate any error markers that the build has discovered - monitor.subTask(ManagedMakeMessages - .getResourceString(MARKERS)); + monitor.subTask(ManagedMakeMessages.getResourceString(MARKERS)); addBuilderMarkers(epm); - epm.reportProblems(); } else { buf = new StringBuffer(); buf.append(ManagedMakeMessages.getFormattedString(NOTHING_BUILT, getProject().getName())); @@ -1568,7 +1565,6 @@ public class GeneratedMakefileBuilder extends ACBuilder { // Generate any error markers that the build has discovered addBuilderMarkers(epm); - epm.reportProblems(); consoleOutStream.close(); } catch (Exception e) { StringBuffer buf = new StringBuffer(); diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserEfsFileMatchingTest.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserEfsFileMatchingTest.java index 1e0c3830208..46021b087dd 100644 --- a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserEfsFileMatchingTest.java +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserEfsFileMatchingTest.java @@ -156,7 +156,7 @@ public class ErrorParserEfsFileMatchingTest extends TestCase { line = line + '\n'; epManager.write(line.getBytes(), 0, line.length()); epManager.close(); - epManager.reportProblems(); + epManager.getOutputStream().close(); } /** @@ -175,7 +175,7 @@ public class ErrorParserEfsFileMatchingTest extends TestCase { line = line + '\n'; epManager.write(line.getBytes(), 0, line.length()); epManager.close(); - epManager.reportProblems(); + epManager.getOutputStream().close(); } /** diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserFileMatchingTest.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserFileMatchingTest.java index 157d420d4c7..1850477797b 100644 --- a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserFileMatchingTest.java +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserFileMatchingTest.java @@ -158,7 +158,7 @@ public class ErrorParserFileMatchingTest extends TestCase { line = line + '\n'; epManager.write(line.getBytes(), 0, line.length()); epManager.close(); - epManager.reportProblems(); + epManager.getOutputStream().close(); } /** diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserManagerTest.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserManagerTest.java index 0579e1544cd..ef7766b6be5 100644 --- a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserManagerTest.java +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/ErrorParserManagerTest.java @@ -153,7 +153,7 @@ public class ErrorParserManagerTest extends TestCase { private void end() throws IOException { epManager.getOutputStream(); epManager.close(); - epManager.reportProblems(); + epManager.getOutputStream().close(); } public void testParsersSanity() throws CoreException, IOException { diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/GenericErrorParserTests.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/GenericErrorParserTests.java index 724ebcf8366..1bdd11ffcbd 100644 --- a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/GenericErrorParserTests.java +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/GenericErrorParserTests.java @@ -125,7 +125,7 @@ public abstract class GenericErrorParserTests extends TestCase { transferInputStreamToOutputStream(inputStream, manager.getOutputStream(), 1024); manager.close(); - manager.reportProblems(); + manager.getOutputStream().close(); if (expectedErrorCount >= 0) { assertEquals(expectedErrorCount, markerGenerator.numErrors); diff --git a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/RegexErrorParserTests.java b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/RegexErrorParserTests.java index 8c31ce13f6b..e076eb9f562 100644 --- a/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/RegexErrorParserTests.java +++ b/core/org.eclipse.cdt.core.tests/misc/org/eclipse/cdt/core/internal/errorparsers/tests/RegexErrorParserTests.java @@ -207,7 +207,6 @@ public class RegexErrorParserTests extends TestCase { regexErrorParser.processLine("Variable!Description!10!"+fileName, epManager); errorList.clear(); - epManager.reportProblems(); assertEquals(3, errorList.size()); // Regular @@ -704,7 +703,6 @@ public class RegexErrorParserTests extends TestCase { regexErrorParser.processLine("pattern wrong", epManager); errorList.clear(); - epManager.reportProblems(); assertEquals(0, errorList.size()); } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java index bbf08b37f46..b97f517ce31 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 IBM Corporation and others. + * Copyright (c) 2005, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,7 @@ * Sergey Prigogin (Google) * James Blackburn (Broadcom) - Bug 247838 * Andrew Gvozdev (Quoin Inc) + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.core; @@ -25,6 +26,7 @@ import java.util.Vector; import org.eclipse.cdt.core.errorparsers.ErrorParserNamedWrapper; import org.eclipse.cdt.core.resources.ACBuilder; +import org.eclipse.cdt.internal.core.IErrorMarkeredOutputStream; import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.cdt.internal.errorparsers.ErrorParserExtensionManager; import org.eclipse.cdt.utils.CygPath; @@ -307,7 +309,6 @@ public class ErrorParserManager extends OutputStream { if (fErrorParsers.size() == 0) return; - String lineTrimmed = line.trim(); lineCounter++; @@ -337,6 +338,9 @@ public class ErrorParserManager extends OutputStream { // It should not stop parsing of the rest of output. try { if (curr.processLine(lineToParse, this)) { + ProblemMarkerInfo m = fErrors.size() > 0 ? fErrors.get(0): null; + outputLine(line, m); + fErrors.clear(); return; } } catch (Exception e){ @@ -345,8 +349,29 @@ public class ErrorParserManager extends OutputStream { } } } + outputLine(line, null); } + /** + * Conditionally output line to outputStream. If stream + * supports error markers, use it, otherwise use conventional stream + */ + private void outputLine(String line, ProblemMarkerInfo marker) { + String l = line + "\n"; //$NON-NLS-1$ + if ( outputStream == null ) return; + try { + if ( marker != null && outputStream instanceof IErrorMarkeredOutputStream ) { + IErrorMarkeredOutputStream s = (IErrorMarkeredOutputStream) outputStream; + s.write(l, marker); + } else { + byte[] b = l.getBytes(); + outputStream.write(b, 0, b.length); + } + } catch (IOException e) { + CCorePlugin.log(e); + } + } + /** * @return counter counting processed lines of output * @since 5.2 @@ -500,7 +525,6 @@ public class ErrorParserManager extends OutputStream { /** * Add marker to the list of error markers. - * Markers are actually added in the end of processing in {@link #reportProblems()}. * * @param file - resource to add the new marker. * @param lineNumber - line number of the error. @@ -514,7 +538,6 @@ public class ErrorParserManager extends OutputStream { /** * Add marker to the list of error markers. - * Markers are actually added in the end of processing in {@link #reportProblems()}. * * @param file - resource to add the new marker. * @param lineNumber - line number of the error. @@ -530,6 +553,7 @@ public class ErrorParserManager extends OutputStream { public void generateExternalMarker(IResource file, int lineNumber, String desc, int severity, String varName, IPath externalPath) { ProblemMarkerInfo problemMarkerInfo = new ProblemMarkerInfo(file, lineNumber, desc, severity, varName, externalPath); fErrors.add(problemMarkerInfo); + fMarkerGenerator.addMarker(problemMarkerInfo); if (severity == IMarkerGenerator.SEVERITY_ERROR_RESOURCE) hasErrors = true; } @@ -544,6 +568,8 @@ public class ErrorParserManager extends OutputStream { /** * Method setOutputStream. + * Note: you have to close this stream explicitly + * don't rely on ErrorParserManager.close(). * @param os - output stream */ public void setOutputStream(OutputStream os) { @@ -551,8 +577,9 @@ public class ErrorParserManager extends OutputStream { } /** - * Method getOutputStream. It has a reference count - * the stream must be close the same number of time this method was call. + * Method getOutputStream. + * Note: you have to close this stream explicitly + * don't rely on ErrorParserManager.close(). * @return OutputStream */ public OutputStream getOutputStream() { @@ -562,14 +589,14 @@ public class ErrorParserManager extends OutputStream { /** * @see java.io.OutputStream#close() + * Note: don't rely on this method to close underlying OutputStream, + * close it explicitly */ @Override - public void close() throws IOException { + public synchronized void close() throws IOException { if (nOpens > 0 && --nOpens == 0) { checkLine(true); fDirectoryStack.removeAllElements(); - if (outputStream != null) - outputStream.close(); } } @@ -589,8 +616,6 @@ public class ErrorParserManager extends OutputStream { public synchronized void write(int b) throws IOException { currentLine.append((char) b); checkLine(false); - if (outputStream != null) - outputStream.write(b); } @Override @@ -604,10 +629,12 @@ public class ErrorParserManager extends OutputStream { } currentLine.append(new String(b, 0, len)); checkLine(false); - if (outputStream != null) - outputStream.write(b, off, len); } + // This method examines contents of currentLine buffer + // if it contains whole line this line is checked by error + // parsers (processLine method). + // If flush is true rest of line is checked by error parsers. private void checkLine(boolean flush) { String buffer = currentLine.toString(); int i = 0; @@ -632,7 +659,8 @@ public class ErrorParserManager extends OutputStream { } /** - * Create actual markers from the list of collected problems. + * @deprecated as of 5.2. This method is no longer reporting problems. + * The problem markers are generated after processing each line. * * @return {@code true} if detected a problem indicating that build failed. * The semantics of the return code is inconsistent. As far as build is concerned @@ -640,18 +668,9 @@ public class ErrorParserManager extends OutputStream { * {@link IMarkerGenerator#SEVERITY_ERROR_RESOURCE} and * {@link IMarkerGenerator#SEVERITY_ERROR_BUILD} */ + @Deprecated public boolean reportProblems() { - boolean reset = false; - if (nOpens == 0) { - for (ProblemMarkerInfo problemMarkerInfo : fErrors) { - if (problemMarkerInfo.severity == IMarkerGenerator.SEVERITY_ERROR_BUILD) { - reset = true; - } - fMarkerGenerator.addMarker(problemMarkerInfo); - } - fErrors.clear(); - } - return reset; + return false; } /** diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/IErrorMarkeredOutputStream.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/IErrorMarkeredOutputStream.java new file mode 100644 index 00000000000..096d195f986 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/IErrorMarkeredOutputStream.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2010 CodeSourcery and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Dmitry Kozlov (CodeSourcery) - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core; + +import java.io.IOException; + +import org.eclipse.cdt.core.ProblemMarkerInfo; + +/** + * Output stream for use in build console capable of processing markers info + * attached to the output. + * @since 5.2 + */ +public interface IErrorMarkeredOutputStream { + + public void write(String s, ProblemMarkerInfo marker) throws IOException; + + public void write(byte[] b, int offset, int len) throws IOException; + + public void flush() throws IOException; + + public void close() throws IOException; + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties index 5d27e61217c..29d4771d182 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties @@ -29,6 +29,8 @@ ConsolePreferencePage.outputColor.label=Output text color ConsolePreferencePage.infoColor.label=Information message text color ConsolePreferencePage.errorColor.label=Error message text color ConsolePreferencePage.backgroundColor.label=Background color +ConsolePreferencePage.problemBackgroundColor.label=Background color for build problems +ConsolePreferencePage.problemHighlightedColor.label=Highlighting color for build problems # ------- Project/Prefernces/Wizards COnfiguration blocks ------- diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsole.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsole.java index 59a9cbe92c7..cec4127f567 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsole.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsole.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2007 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation * Red Hat Inc. - Multiple build console support + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -22,16 +23,24 @@ import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.part.IPageBookViewPage; public class BuildConsole extends AbstractConsole { - + + /** + * Menu group identifier for the console view context menu and toolbar, for actions pertaining to + * error navigation (value "errorGroup"). + */ + public static final String ERROR_GROUP = "errorGroup"; //$NON-NLS-1$ + /** * Property constant indicating the color of a stream has changed. */ public static final String P_STREAM_COLOR = CUIPlugin.PLUGIN_ID + ".CONSOLE_P_STREAM_COLOR"; //$NON-NLS-1$ + private static BuildConsolePage fBuildConsolePage; + private IBuildConsoleManager fConsoleManager; private String fConsoleName; private String fConsoleId; - private Color fBackground; + private Color fBackground; public BuildConsole(IBuildConsoleManager manager, String name, String id) { super(name, CPluginImages.DESC_BUILD_CONSOLE); @@ -41,7 +50,12 @@ public class BuildConsole extends AbstractConsole { } public IPageBookViewPage createPage(IConsoleView view) { - return new BuildConsolePage(view, this, fConsoleId); + fBuildConsolePage = new BuildConsolePage(view, this, fConsoleId); + return fBuildConsolePage; + } + + static BuildConsolePage getPage() { + return fBuildConsolePage; } public void setTitle(IProject project) { @@ -53,7 +67,7 @@ public class BuildConsole extends AbstractConsole { } public IBuildConsoleManager getConsoleManager() { - return fConsoleManager; + return fConsoleManager; } public void setBackground(Color background) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleManager.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleManager.java index 0041f034354..33b3f257882 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleManager.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2007 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - initial API and implementation * Red Hat Inc. - multiple build console support + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -53,8 +54,16 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang ListenerList listeners = new ListenerList(); BuildConsole fConsole; private Map fConsoleMap = new HashMap(); - Color infoColor, outputColor, errorColor, backgroundColor; - BuildConsoleStream infoStream, outputStream, errorStream; + Color infoColor, outputColor, errorColor, backgroundColor, problemHighlightedColor, problemBackgroundColor; + public Color getProblemHighlightedColor() { + return problemHighlightedColor; + } + + public Color getProblemBackgroundColor() { + return problemBackgroundColor; + } + + BuildConsoleStreamDecorator infoStream, outputStream, errorStream; String fName, fContextMenuId; static public final int BUILD_STREAM_TYPE_INFO = 0; @@ -159,6 +168,8 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang outputColor.dispose(); errorColor.dispose(); backgroundColor.dispose(); + problemBackgroundColor.dispose(); + problemHighlightedColor.dispose(); } ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new org.eclipse.ui.console.IConsole[]{fConsole}); CUIPlugin.getWorkspace().removeResourceChangeListener(this); @@ -177,9 +188,9 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang } public void startup(String name, String id) { - infoStream = new BuildConsoleStream(); - outputStream = new BuildConsoleStream(); - errorStream = new BuildConsoleStream(); + infoStream = new BuildConsoleStreamDecorator(); + outputStream = new BuildConsoleStreamDecorator(); + errorStream = new BuildConsoleStreamDecorator(); fName = name; fContextMenuId = id; @@ -205,6 +216,8 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang errorStream.setColor(errorColor); backgroundColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_BACKGROUND_COLOR); fConsole.setBackground(backgroundColor); + problemHighlightedColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_HIGHLIGHTED_COLOR); + problemBackgroundColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_BACKGROUND_COLOR); } }); CUIPlugin.getWorkspace().addResourceChangeListener(this); @@ -239,10 +252,33 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang fConsole.setBackground(newColor); backgroundColor.dispose(); backgroundColor = newColor; + } else if (property.equals(BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_HIGHLIGHTED_COLOR)) { + Color newColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_HIGHLIGHTED_COLOR); + problemHighlightedColor.dispose(); + problemHighlightedColor = newColor; + redrawTextViewer(); + } else if (property.equals(BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_BACKGROUND_COLOR)) { + Color newColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_BACKGROUND_COLOR); + problemBackgroundColor.dispose(); + problemBackgroundColor = newColor; + redrawTextViewer(); } } - public BuildConsoleStream getStream(int type) throws CoreException { + private void redrawTextViewer() { + final BuildConsolePage p = BuildConsole.getPage(); + if ( p == null ) return; + final BuildConsoleViewer v = p.getViewer(); + if ( v == null ) return; + Display display = Display.getDefault(); + display.asyncExec(new Runnable() { + public void run() { + v.getTextWidget().redraw(); + } + }); + } + + public BuildConsoleStreamDecorator getStreamDecorator(int type) throws CoreException { switch (type) { case BUILD_STREAM_TYPE_ERROR : return errorStream; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java index 4aeed7874c1..ee2d28dabe6 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2008 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - initial API and implementation * Red Hat Inc. - multiple build console support + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -19,9 +20,12 @@ import java.util.Map; import java.util.ResourceBundle; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; @@ -36,6 +40,7 @@ import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.OpenStrategy; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; @@ -59,6 +64,8 @@ import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.console.IConsoleConstants; @@ -66,15 +73,21 @@ import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.console.actions.ClearOutputAction; import org.eclipse.ui.console.actions.TextViewerAction; import org.eclipse.ui.console.actions.TextViewerGotoLineAction; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.ide.ResourceUtil; import org.eclipse.ui.part.IPageSite; import org.eclipse.ui.part.Page; import org.eclipse.ui.texteditor.FindReplaceAction; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.IUpdate; +import org.eclipse.cdt.core.ProblemMarkerInfo; +import org.eclipse.cdt.core.model.ICModelMarker; +import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.IBuildConsoleEvent; import org.eclipse.cdt.ui.IBuildConsoleListener; +import org.eclipse.cdt.ui.IBuildConsoleManager; import org.eclipse.cdt.internal.ui.preferences.BuildConsolePreferencePage; @@ -86,6 +99,10 @@ public class BuildConsolePage extends Page ITextListener, IAdaptable { + static final int POSITION_NEXT = -1; + static final int POSITION_PREV = -2; + static final int POSITION_FIST = -3; + private BuildConsole fConsole; private IConsoleView fConsoleView; private String fContextMenuId; @@ -109,6 +126,9 @@ public class BuildConsolePage extends Page private Menu fMenu; private ScrollLockAction fScrollLockAction; private boolean fIsLocked; + private NextErrorAction fNextErrorAction; + private PreviousErrorAction fPreviousErrorAction; + private ShowErrorAction fShowErrorAction; /** * @param view @@ -137,7 +157,13 @@ public class BuildConsolePage extends Page protected IDocument setDocument() { IProject project = getProject(); if (project != null) { - getViewer().setDocument(getConsole().getConsoleManager().getConsoleDocument(project)); + IBuildConsoleManager consoleManager = getConsole().getConsoleManager(); + getViewer().setDocument(consoleManager.getConsoleDocument(project)); + IConsole console = consoleManager.getConsole(project); + if ( console instanceof BuildConsolePartitioner) { + BuildConsolePartitioner par = (BuildConsolePartitioner)console; + showError(par, fShowErrorAction.isChecked() ); + } } return null; } @@ -206,6 +232,7 @@ public class BuildConsolePage extends Page setTabs(CUIPlugin.getDefault().getPluginPreferences().getInt(BuildConsolePreferencePage.PREF_BUILDCONSOLE_TAB_WIDTH)); getConsole().addPropertyChangeListener(this); + CUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this); fViewer.addTextListener(this); fViewer.getTextWidget().setBackground(getConsole().getBackground()); @@ -238,8 +265,8 @@ public class BuildConsolePage extends Page final Object source = event.getSource(); final String property = event.getProperty(); - if (BuildConsole.P_STREAM_COLOR.equals(property) && source instanceof BuildConsoleStream) { - BuildConsoleStream stream = (BuildConsoleStream)source; + if (BuildConsole.P_STREAM_COLOR.equals(property) && source instanceof BuildConsoleStreamDecorator) { + BuildConsoleStreamDecorator stream = (BuildConsoleStreamDecorator)source; if (stream.getConsole().equals(getConsole()) && getControl() != null) { Display display = getControl().getDisplay(); display.asyncExec(new Runnable() { @@ -261,6 +288,10 @@ public class BuildConsolePage extends Page protected void createActions() { fClearOutputAction = new ClearOutputAction(getViewer()); fScrollLockAction = new ScrollLockAction(getViewer()); + fNextErrorAction = new NextErrorAction(this); + fPreviousErrorAction = new PreviousErrorAction(this); + fShowErrorAction = new ShowErrorAction(); + fScrollLockAction.setChecked(fIsLocked); getViewer().setAutoScroll(!fIsLocked); // In order for the clipboard actions to accessible via their shortcuts @@ -311,6 +342,11 @@ public class BuildConsolePage extends Page } protected void configureToolBar(IToolBarManager mgr) { + mgr.insertBefore(IConsoleConstants.OUTPUT_GROUP, new GroupMarker(BuildConsole.ERROR_GROUP)); + mgr.appendToGroup(BuildConsole.ERROR_GROUP, fPreviousErrorAction); + mgr.appendToGroup(BuildConsole.ERROR_GROUP, fNextErrorAction); + mgr.appendToGroup(BuildConsole.ERROR_GROUP, fShowErrorAction); + mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, fScrollLockAction); mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, fClearOutputAction); } @@ -506,4 +542,88 @@ public class BuildConsolePage extends Page findReplace.update(); } } + + /** + * Highlight next/previous error or error by console offset + * @param position POSITION_NEXT (-1), POSITION_PREV (-2), or offset + */ + void moveToError(int position) { + IProject project = getProject(); + IBuildConsoleManager consoleManager = CUIPlugin.getDefault().getConsoleManager(); + IConsole console = consoleManager.getConsole(project); + if ( console instanceof BuildConsolePartitioner) { + BuildConsolePartitioner par = (BuildConsolePartitioner)console; + // Move to specified line in the model (BuildConsolePartitioner) + if ( position == POSITION_NEXT ) { + par.fDocumentMarkerManager.moveToNextError(); + } else if ( position == POSITION_PREV ) { + par.fDocumentMarkerManager.moveToPreviousError(); + } else if ( position == POSITION_FIST ) { + par.fDocumentMarkerManager.moveToFirstError(); + } else if ( position >= 0 ) { + if ( ! par.fDocumentMarkerManager.moveToErrorByOffset(position) ) { + // we haven't moved, because offset points to non-error partition + return; + } + } + showError(par, position > 0 || fShowErrorAction.isChecked() ); + } + } + + /** + * Highlight current error and show it in editor + */ + public void showError(BuildConsolePartitioner par, boolean openInEditor) { + // Highlight current error + BuildConsolePartition p = par.fDocumentMarkerManager.getCurrentPartition(); + if ( p == null ) return; + getViewer().selectPartition(par, p); + // Show error in editor if necessary + // (always show when absolute positioning, otherwise depends + // on fShowErrorAction state) + if ( openInEditor ) { + openErrorInEditor(par.fDocumentMarkerManager.getCurrentErrorMarker()); + } + } + + /** + * Open error specified by marker in editor + */ + public static void openErrorInEditor(ProblemMarkerInfo marker) { + IWorkbenchWindow window = CUIPlugin.getActiveWorkbenchWindow(); + + if ( marker == null || marker.file == null || window == null ) return; + + IWorkbenchPage page = window.getActivePage(); + if (page == null) return; + + IEditorPart editor = page.getActiveEditor(); + if (editor != null) { + IEditorInput input = editor.getEditorInput(); + IFile file = ResourceUtil.getFile(input); + if (file != null && file.equals(marker.file) && OpenStrategy.activateOnOpen()) { + page.activate(editor); + } + } + + if ( marker.file instanceof IFile ) { + try { + // Find IMarker corresponding to ProblemMarkerInfo + IMarker mrkrs[] = marker.file.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_ONE); + for (IMarker m: mrkrs) { + if ( marker.lineNumber == ((Integer)m.getAttribute(IMarker.LINE_NUMBER)).intValue() && + marker.description.equals(m.getAttribute(IMarker.MESSAGE)) && + marker.severity == ((Integer)m.getAttribute(IMarker.SEVERITY)).intValue() ) { + IDE.openEditor(page, m, OpenStrategy.activateOnOpen()); + return; + } + } + } catch (PartInitException e) { + CUIPlugin.log(e); + } catch (CoreException e) { + CUIPlugin.log(e); + } + } + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartition.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartition.java index 7e695bbf3cc..051cc58fb29 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartition.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartition.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2006 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,29 +7,39 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; +import org.eclipse.cdt.core.ProblemMarkerInfo; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.jface.text.TypedRegion; public class BuildConsolePartition extends TypedRegion { - /** - * Associated stream - */ - private BuildConsoleStream fStream; + /** Associated stream */ + private BuildConsoleStreamDecorator fStream; + + /** Marker associated with this partition if any */ + private ProblemMarkerInfo fMarker; - /** - * Partition type - */ + /** Partition type */ public static final String CONSOLE_PARTITION_TYPE = CUIPlugin.getPluginId() + ".CONSOLE_PARTITION_TYPE"; //$NON-NLS-1$ - - public BuildConsolePartition(BuildConsoleStream stream, int offset, int length) { - super(offset, length, CONSOLE_PARTITION_TYPE); + + /** Partition type to report errors in console */ + public static final String ERROR_PARTITION_TYPE = CUIPlugin.getPluginId() + ".ERROR_PARTITION_TYPE"; //$NON-NLS-1$ + + public BuildConsolePartition(BuildConsoleStreamDecorator stream, int offset, int length, String type) { + super(offset, length, type); fStream = stream; } + public BuildConsolePartition(BuildConsoleStreamDecorator stream, int offset, int length, String type, ProblemMarkerInfo marker) { + super(offset, length, type); + fStream = stream; + fMarker = marker; + } + /** * @see java.lang.Object#equals(java.lang.Object) */ @@ -54,7 +64,7 @@ public class BuildConsolePartition extends TypedRegion { * * @return this partition's stream */ - public BuildConsoleStream getStream() { + public BuildConsoleStreamDecorator getStream() { return fStream; } @@ -66,6 +76,9 @@ public class BuildConsolePartition extends TypedRegion { * @return boolean */ public boolean canBeCombinedWith(BuildConsolePartition partition) { + // Error partitions never can be combined together + if ( getType() == ERROR_PARTITION_TYPE ) return false; + int start = getOffset(); int end = start + getLength(); int otherStart = partition.getOffset(); @@ -88,18 +101,20 @@ public class BuildConsolePartition extends TypedRegion { int otherEnd = otherStart + partition.getLength(); int theStart = Math.min(start, otherStart); int theEnd = Math.max(end, otherEnd); - return createNewPartition(theStart, theEnd - theStart); + return createNewPartition(theStart, theEnd - theStart, CONSOLE_PARTITION_TYPE); } /** - * Creates a new patition of this type with the given color, offset, and - * length. - * + * Creates a new partition of this type with the given offset, and length. * @param offset * @param length * @return a new partition with the given range */ - public BuildConsolePartition createNewPartition(int offset, int length) { - return new BuildConsolePartition(getStream(), offset, length); + public BuildConsolePartition createNewPartition(int offset, int length, String type) { + return new BuildConsolePartition(getStream(), offset, length, type, getMarker()); + } + + public ProblemMarkerInfo getMarker() { + return fMarker; } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java index 71201ed2765..85869562a1c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2006 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,10 +7,10 @@ * * Contributors: * QNX Software Systems - initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; -import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -32,6 +32,7 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.cdt.core.ConsoleOutputStream; +import org.eclipse.cdt.core.ProblemMarkerInfo; import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.cdt.ui.CUIPlugin; @@ -54,11 +55,13 @@ public class BuildConsolePartitioner /** * The stream that was last appended to */ - BuildConsoleStream fLastStream = null; + BuildConsoleStreamDecorator fLastStream = null; BuildConsoleDocument fDocument; + DocumentMarkerManager fDocumentMarkerManager; boolean killed; BuildConsoleManager fManager; + Boolean outputStreamClosed = new Boolean(false); /** * A queue of stream entries written to standard out and standard err. @@ -72,24 +75,23 @@ public class BuildConsolePartitioner class StreamEntry { - /** - * Identifier of the stream written to. - */ - private BuildConsoleStream fStream; - /** - * The text written - */ - private StringBuffer fText = null; + /** Identifier of the stream written to. */ + private BuildConsoleStreamDecorator fStream; + /** The text written */ + private StringBuffer fText = null; + /** Problem marker corresponding to the line of text */ + private ProblemMarkerInfo fMarker; - StreamEntry(String text, BuildConsoleStream stream) { + StreamEntry(String text, BuildConsoleStreamDecorator stream, ProblemMarkerInfo marker) { fText = new StringBuffer(text); fStream = stream; + fMarker = marker; } /** * Returns the stream identifier */ - public BuildConsoleStream getStream() { + public BuildConsoleStreamDecorator getStream() { return fStream; } @@ -107,6 +109,14 @@ public class BuildConsolePartitioner public String getText() { return fText.toString(); } + + /** + * Returns error marker + */ + public ProblemMarkerInfo getMarker() { + return fMarker; + } + } public BuildConsolePartitioner(BuildConsoleManager manager) { @@ -114,6 +124,7 @@ public class BuildConsolePartitioner fMaxLines = BuildConsolePreferencePage.buildConsoleLines(); fDocument = new BuildConsoleDocument(); fDocument.setDocumentPartitioner(this); + fDocumentMarkerManager = new DocumentMarkerManager(fDocument, this); connect(fDocument); } @@ -125,8 +136,7 @@ public class BuildConsolePartitioner * @param stream * the stream to append to */ - - public void appendToDocument(String text, BuildConsoleStream stream) { + public void appendToDocument(String text, BuildConsoleStreamDecorator stream, ProblemMarkerInfo marker) { boolean addToQueue = true; synchronized (fQueue) { int i = fQueue.size(); @@ -134,13 +144,13 @@ public class BuildConsolePartitioner StreamEntry entry = fQueue.get(i - 1); // if last stream is the same and we have not exceeded our // display write limit, append. - if (entry.getStream() == stream && entry.size() < 10000) { + if (entry.getStream() == stream && entry.size() < 10000 && entry.getMarker() == marker) { entry.appendText(text); addToQueue = false; } } if (addToQueue) { - fQueue.add(new StreamEntry(text, stream)); + fQueue.add(new StreamEntry(text, stream, marker)); } } Runnable r = new Runnable() { @@ -155,12 +165,15 @@ public class BuildConsolePartitioner fLastStream = entry.getStream(); try { warnOfContentChange(fLastStream); - if (fLastStream == null) { - fDocument.set(entry.getText()); - } else { - fDocument.replace(fDocument.getLength(), 0, entry.getText()); - checkOverflow(); + + if ( fLastStream == null ) { + // special case to empty document + fPartitions.clear(); + fDocumentMarkerManager.clear(); + fDocument.set(""); //$NON-NLS-1$ } + addStreamEntryToDocument(entry); + checkOverflow(); } catch (BadLocationException e) { } } @@ -171,7 +184,25 @@ public class BuildConsolePartitioner } } - void warnOfContentChange(BuildConsoleStream stream) { + private void addStreamEntryToDocument(StreamEntry entry) throws BadLocationException { + if ( entry.getMarker() == null ) { + // It is plain unmarkered console output + addPartition(new BuildConsolePartition(fLastStream, + fDocument.getLength(), + entry.getText().length(), + BuildConsolePartition.CONSOLE_PARTITION_TYPE)); + } else { + // this text line in entry is markered with ProblemMarkerInfo, + // create special partition for it. + addPartition(new BuildConsolePartition(fLastStream, + fDocument.getLength(), + entry.getText().length(), + BuildConsolePartition.ERROR_PARTITION_TYPE, entry.getMarker())); + } + fDocument.replace(fDocument.getLength(), 0, entry.getText()); + } + + void warnOfContentChange(BuildConsoleStreamDecorator stream) { if (stream != null) { ConsolePlugin.getDefault().getConsoleManager().warnOfContentChange(stream.getConsole()); } @@ -237,7 +268,8 @@ public class BuildConsolePartitioner ITypedRegion partition = fPartitions.get(i); int partitionStart = partition.getOffset(); int partitionEnd = partitionStart + partition.getLength(); - if ( (offset >= partitionStart && offset <= partitionEnd) || (offset < partitionStart && end >= partitionStart)) { + if ( (offset >= partitionStart && offset <= partitionEnd) || + (offset < partitionStart && end >= partitionStart)) { list.add(partition); } } @@ -266,7 +298,6 @@ public class BuildConsolePartitioner fPartitions.clear(); return new Region(0, 0); } - addPartition(new BuildConsolePartition(fLastStream, event.getOffset(), text.length())); ITypedRegion[] affectedRegions = computePartitioning(event.getOffset(), text.length()); if (affectedRegions.length == 0) { return null; @@ -308,17 +339,19 @@ public class BuildConsolePartitioner int offset = region.getOffset(); if (offset < overflow) { int endOffset = offset + region.getLength(); - if (endOffset < overflow) { - // remove partition + if (endOffset < overflow || + messageConsolePartition.getType() == BuildConsolePartition.ERROR_PARTITION_TYPE ) { + // remove partition, + // partitions with problem markers can't be split - remove them too } else { // split partition int length = endOffset - overflow; - newPartition = messageConsolePartition.createNewPartition(0, length); + newPartition = messageConsolePartition.createNewPartition(0, length, messageConsolePartition.getType()); } } else { - // modify parition offset + // modify partition offset newPartition = messageConsolePartition.createNewPartition(messageConsolePartition.getOffset() - - overflow, messageConsolePartition.getLength()); + - overflow, messageConsolePartition.getLength(), messageConsolePartition.getType()); } if (newPartition != null) { newParitions.add(newPartition); @@ -326,6 +359,7 @@ public class BuildConsolePartitioner } } fPartitions = newParitions; + fDocumentMarkerManager.moveToFirstError(); try { fDocument.replace(0, overflow, ""); //$NON-NLS-1$ @@ -336,8 +370,7 @@ public class BuildConsolePartitioner } /** - * Adds a new colored input partition, combining with the previous partition - * if possible. + * Adds a new partition, combining with the previous partition if possible. */ private BuildConsolePartition addPartition(BuildConsolePartition partition) { if (fPartitions.isEmpty()) { @@ -371,7 +404,6 @@ public class BuildConsolePartitioner Display display = CUIPlugin.getStandardDisplay(); if (display != null) { display.asyncExec(new Runnable() { - public void run() { fManager.startConsoleActivity(project); } @@ -379,43 +411,48 @@ public class BuildConsolePartitioner } if (BuildConsolePreferencePage.isClearBuildConsole()) { - appendToDocument("", null); //$NON-NLS-1$ - } - } - - public class BuildOutputStream extends ConsoleOutputStream { - - final BuildConsoleStream fStream; - - public BuildOutputStream(BuildConsoleStream stream) { - fStream = stream; - } - - @Override - public void flush() throws IOException { - } - - @Override - public void close() throws IOException { - flush(); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - appendToDocument(new String(b, off, len), fStream); + appendToDocument("", null, null); //$NON-NLS-1$ } } public ConsoleOutputStream getOutputStream() throws CoreException { - return new BuildOutputStream(fManager.getStream(BuildConsoleManager.BUILD_STREAM_TYPE_OUTPUT)); + outputStreamClosed = Boolean.FALSE; + return new BuildOutputStream(this, fManager.getStreamDecorator(BuildConsoleManager.BUILD_STREAM_TYPE_OUTPUT)); } public ConsoleOutputStream getInfoStream() throws CoreException { - return new BuildOutputStream(fManager.getStream(BuildConsoleManager.BUILD_STREAM_TYPE_INFO)); + return new BuildOutputStream(this, fManager.getStreamDecorator(BuildConsoleManager.BUILD_STREAM_TYPE_INFO)); } public ConsoleOutputStream getErrorStream() throws CoreException { - return new BuildOutputStream(fManager.getStream(BuildConsoleManager.BUILD_STREAM_TYPE_ERROR)); + return new BuildOutputStream(this, fManager.getStreamDecorator(BuildConsoleManager.BUILD_STREAM_TYPE_ERROR)); + } + + /** This method is useful for future debugging and bugfixing */ + @SuppressWarnings("unused") + private void printDocumentPartitioning() { + System.out.println("Document partitioning: "); //$NON-NLS-1$ + for (ITypedRegion tr : fPartitions) { + BuildConsolePartition p = (BuildConsolePartition) tr; + int start = p.getOffset(); + int end = p.getOffset() + p.getLength(); + String text; + String isError = "U"; //$NON-NLS-1$ + if (p.getType() == BuildConsolePartition.ERROR_PARTITION_TYPE) { + isError = "E"; //$NON-NLS-1$ + } else if (p.getType() == BuildConsolePartition.CONSOLE_PARTITION_TYPE) { + isError = "C"; //$NON-NLS-1$ + } + try { + text = fDocument.get(p.getOffset(), p.getLength()); + } catch (BadLocationException e) { + text = "N/A"; //$NON-NLS-1$ + } + if (text.endsWith("\n")) { //$NON-NLS-1$ + text = text.substring(0, text.length() - 1); + } + System.out.println(" " + isError + " " + start + "-" + end + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ":[" + text + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } } - } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleStream.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleStreamDecorator.java similarity index 87% rename from core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleStream.java rename to core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleStreamDecorator.java index 8fb61eb15b9..363d1d07360 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleStream.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleStreamDecorator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2006 QNX Software Systems and others. + * Copyright (c) 2009, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,13 +7,14 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; import org.eclipse.swt.graphics.Color; -public class BuildConsoleStream { +public class BuildConsoleStreamDecorator { private BuildConsole fConsole = null; private Color fColor = null; @@ -22,7 +23,7 @@ public class BuildConsoleStream { * Constructs a new stream connected to the given console. * */ - public BuildConsoleStream() { + public BuildConsoleStreamDecorator() { } public void setConsole(BuildConsole console) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java index 9d4f922b903..ce5c8ec5b1b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2006 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -17,14 +18,26 @@ import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.TextViewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.LineBackgroundEvent; +import org.eclipse.swt.custom.LineBackgroundListener; import org.eclipse.swt.custom.LineStyleEvent; import org.eclipse.swt.custom.LineStyleListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; -public class BuildConsoleViewer extends TextViewer implements LineStyleListener { +import org.eclipse.cdt.ui.CUIPlugin; + +public class BuildConsoleViewer extends TextViewer + implements LineStyleListener, + LineBackgroundListener, + MouseTrackListener, + MouseListener { protected InternalDocumentListener fInternalDocumentListener = new InternalDocumentListener(); /** @@ -81,13 +94,15 @@ public class BuildConsoleViewer extends TextViewer implements LineStyleListener */ public BuildConsoleViewer(Composite parent) { super(parent, getSWTStyles()); - getTextWidget().setDoubleClickEnabled(true); - getTextWidget().setFont(parent.getFont()); - getTextWidget().addLineStyleListener(this); - getTextWidget().setEditable(false); - getTextWidget().setWordWrap(true); + StyledText styledText = getTextWidget(); + styledText.addLineStyleListener(this); + styledText.addLineBackgroundListener(this); + styledText.addMouseTrackListener(this); + styledText.setFont(parent.getFont()); + styledText.setDoubleClickEnabled(true); + styledText.setEditable(false); + styledText.setWordWrap(true); } - /** * Returns the SWT style flags used when instantiating this viewer @@ -121,7 +136,6 @@ public class BuildConsoleViewer extends TextViewer implements LineStyleListener } } - /* * (non-Javadoc) * @@ -154,21 +168,96 @@ public class BuildConsoleViewer extends TextViewer implements LineStyleListener * * @see org.eclipse.swt.custom.LineStyleListener#lineGetStyle(org.eclipse.swt.custom.LineStyleEvent) */ - public void lineGetStyle(LineStyleEvent event) { + public void lineGetStyle(LineStyleEvent event) { IDocument document = getDocument(); - if (document != null) { - BuildConsolePartitioner partitioner = (BuildConsolePartitioner) document.getDocumentPartitioner(); - if (partitioner != null) { - ITypedRegion[] regions = partitioner.computePartitioning(event.lineOffset, event.lineOffset - + event.lineText.length()); - StyleRange[] styles = new StyleRange[regions.length]; - for (int i = 0; i < regions.length; i++) { - BuildConsolePartition partition = (BuildConsolePartition) regions[i]; - Color color = partition.getStream().getColor(); - styles[i] = new StyleRange(partition.getOffset(), partition.getLength(), color, null); - } - event.styles = styles; + if (document == null) return; + BuildConsolePartitioner partitioner = (BuildConsolePartitioner) document.getDocumentPartitioner(); + if (partitioner == null) return; + + BuildConsolePartition p = partitioner.fDocumentMarkerManager.getCurrentPartition(); + Color problemHighlightedColor = partitioner.fManager.getProblemHighlightedColor(); + + // Note, computePartitioning actually doesn't change anything in partitioning, + // but only computes number of affected regions. + ITypedRegion[] regions = partitioner.computePartitioning(event.lineOffset, event.lineText.length()); + StyleRange[] styles = new StyleRange[regions.length]; + for (int i = 0; i < regions.length; i++) { + BuildConsolePartition partition = (BuildConsolePartition) regions[i]; + Color colorFG = partition.getStream().getColor(); + Color colorBG = null; + + // Highlight current partition + if ( partition == p ) { + colorFG = problemHighlightedColor; } + StyleRange styleRange = new StyleRange(partition.getOffset(), partition.getLength(), colorFG, colorBG); + styles[i] = styleRange; + } + event.styles = styles; + } + + public void selectPartition(BuildConsolePartitioner partitioner, BuildConsolePartition p) { + try { + int start = partitioner.getDocument().getLineOfOffset(p.getOffset()); + int end = partitioner.getDocument().getLineOfOffset(p.getOffset()+p.getLength()-1); + + if ( fAutoScroll ) { + // Check if area around this line is visible, scroll if needed + int top = getTopIndex(); + int bottom = getBottomIndex(); + if ( start < top + 1 ) { + setTopIndex(start - 1 > 0 ? start - 1 : 0); + } else if ( end > bottom -1 ) { + setTopIndex(top + start - bottom + 1); + } + } + + // Select line + StyledText st = getTextWidget(); + st.redrawRange(0, partitioner.getDocument().getLength(), true); + + } catch (BadLocationException e) { + CUIPlugin.log(e); + } + } + + public void mouseEnter(MouseEvent e) { + getTextWidget().addMouseListener(this); + } + + public void mouseExit(MouseEvent e) { + getTextWidget().removeMouseListener(this); + } + + public void mouseHover(MouseEvent e) { + } + + public void mouseDoubleClick(MouseEvent e) { + int offset = -1; + try { + Point p = new Point(e.x, e.y); + offset = getTextWidget().getOffsetAtLocation(p); + BuildConsole.getPage().moveToError(offset); + } catch (IllegalArgumentException ex) { + } + } + + public void mouseDown(MouseEvent e) { + } + + public void mouseUp(MouseEvent e) { + } + + public void lineGetBackground(LineBackgroundEvent event) { + IDocument document = getDocument(); + if (document == null) return; + BuildConsolePartitioner partitioner = (BuildConsolePartitioner) document.getDocumentPartitioner(); + if (partitioner == null) return; + + BuildConsolePartition partition = (BuildConsolePartition) partitioner.getPartition(event.lineOffset); + // Set background for error partitions + if ( partition != null && partition.getType() == BuildConsolePartition.ERROR_PARTITION_TYPE ) { + event.lineBackground = partitioner.fManager.getProblemBackgroundColor(); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java new file mode 100644 index 00000000000..c77a0dfbe7a --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2002, 2010 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.buildconsole; + +import java.io.IOException; + +import org.eclipse.cdt.core.ConsoleOutputStream; +import org.eclipse.cdt.core.ProblemMarkerInfo; + +import org.eclipse.cdt.internal.core.IErrorMarkeredOutputStream; + +/** + * Output stream which put all output to BuildConsolePartitioner + * and informs it when stream is closed + */ +public class BuildOutputStream extends ConsoleOutputStream implements IErrorMarkeredOutputStream { + + final BuildConsoleStreamDecorator fStream; + private BuildConsolePartitioner fPartitioner; + + public BuildOutputStream(BuildConsolePartitioner partitioner, + BuildConsoleStreamDecorator stream) { + fPartitioner = partitioner; + fStream = stream; + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + flush(); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + fPartitioner.appendToDocument(new String(b, off, len), fStream, null); + } + + public void write(String s, ProblemMarkerInfo marker) throws IOException { + fPartitioner.appendToDocument(s, fStream, marker); + + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java index 0401acf5aab..0f5dcfafb62 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2008 QNX Software Systems and others. + * Copyright (c) 2002, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -29,6 +30,9 @@ public final class ConsoleMessages extends NLS { public static String BuildConsolePage_Select__All_Ctrl_A_12; public static String BuildConsolePage_Select_All; public static String ScrollLockAction_Scroll_Lock_1; + public static String PreviousErrorAction_Tooltip; + public static String NextErrorAction_Tooltip; + public static String ShowErrorAction_Tooltip; static { NLS.initializeMessages(BUNDLE_NAME, ConsoleMessages.class); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties index 7de670862d2..a461e0535e1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2003, 2008 QNX Software Systems and others. +# Copyright (c) 2003, 2010 QNX Software Systems and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -20,3 +20,7 @@ BuildConsolePage_Select__All_Ctrl_A_12=Select &All@Ctrl+A BuildConsolePage_Select_All=Select All ScrollLockAction_Scroll_Lock_1=Scroll Lock + +NextErrorAction_Tooltip=&Next Error +PreviousErrorAction_Tooltip=&Previous Error +ShowErrorAction_Tooltip=&Show Error In Editor diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/DocumentMarkerManager.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/DocumentMarkerManager.java new file mode 100644 index 00000000000..6f46c9a2c16 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/DocumentMarkerManager.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2010 CodeSourcery and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Dmitry Kozlov (CodeSourcery) - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.buildconsole; + +import org.eclipse.jface.text.ITypedRegion; + +import org.eclipse.cdt.core.ProblemMarkerInfo; + +/** + * Manages current position of highlighted error in BuildConsole + */ +class DocumentMarkerManager { + + BuildConsoleDocument fDocument; + BuildConsolePartitioner fPartitioner; + + int highlightedPartitionIndex = -1; + + DocumentMarkerManager(BuildConsoleDocument document, BuildConsolePartitioner partitioner) { + fDocument = document; + fPartitioner = partitioner; + } + + /** Increment index */ + void moveToNextError() { + if ( fPartitioner.fPartitions.size() == 0 ) return; + if ( highlightedPartitionIndex == -1 ) { + moveToFirstError(); + return; + } + int i = highlightedPartitionIndex + 1; + do { + if ( i == fPartitioner.fPartitions.size() ) { + i = 0; + } + if ( fPartitioner.fPartitions.get(i).getType() == BuildConsolePartition.ERROR_PARTITION_TYPE ) { + highlightedPartitionIndex = i; + return; + } else { + i++; + } + } while ( highlightedPartitionIndex != i); + } + + /** Decrement index */ + void moveToPreviousError() { + if ( fPartitioner.fPartitions.size() == 0 ) return; + if ( highlightedPartitionIndex == -1 ) { + moveToFirstError(); + return; + } + + int i = highlightedPartitionIndex - 1; + do { + if ( i == -1 ) { + i = fPartitioner.fPartitions.size() - 1; + } + if ( fPartitioner.fPartitions.get(i).getType() == BuildConsolePartition.ERROR_PARTITION_TYPE ) { + highlightedPartitionIndex = i; + return; + } else { + i--; + } + } while ( highlightedPartitionIndex != i); + } + + void moveToFirstError() { + for (int i=0; i