diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java
index e38b908983e..60ea298142f 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java
@@ -11,15 +11,15 @@
package org.eclipse.cdt.internal.ui;
/**
- * Defines status codes relevant to the Java UI plug-in. When a
+ * Defines status codes relevant to the CDT UI plug-in. When a
* Core exception is thrown, it contain a status object describing
* the cause of the exception. The status objects originating from the
- * Java UI plug-in use the codes defined in this interface.
+ * CDT UI plug-in use the codes defined in this interface.
*/
public interface ICStatusConstants {
// C UI status constants start at 10000 to make sure that we don't
- // collide with resource and java model constants.
+ // collide with resource and c model constants.
public static final int INTERNAL_ERROR= 10001;
@@ -46,4 +46,12 @@ public interface ICStatusConstants {
* parsing template file.
*/
public static final int TEMPLATE_PARSE_EXCEPTION = 10005;
- }
+
+ /**
+ * Status constant indication that a problem occurred while calculating
+ * the changed region during a save.
+ *
+ * @since 5.1
+ */
+ public static final int EDITOR_CHANGED_REGION_CALCULATION= 10006;
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java
index bf52c685781..8b78e3dc68f 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java
@@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
@@ -26,7 +27,11 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
@@ -46,6 +51,10 @@ import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.text.edits.DeleteEdit;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.text.edits.MalformedTreeException;
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.ForwardingDocumentProvider;
@@ -71,6 +80,7 @@ import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.ui.text.ICPartitions;
+import org.eclipse.cdt.internal.core.model.CommitWorkingCopyOperation;
import org.eclipse.cdt.internal.core.model.IBufferFactory;
import org.eclipse.cdt.internal.core.model.TranslationUnit;
@@ -313,7 +323,6 @@ public class CDocumentProvider extends TextFileDocumentProvider {
}
return true;
}
-
}
/**
@@ -926,28 +935,69 @@ public class CDocumentProvider extends TextFileDocumentProvider {
super.disposeFileInfo(element, info);
}
- protected void commitWorkingCopy(IProgressMonitor monitor, Object element, TranslationUnitInfo info, boolean overwrite)
- throws CoreException {
+ /**
+ * Creates and returns a new sub-progress monitor for the
+ * given parent monitor.
+ *
+ * @param monitor the parent progress monitor
+ * @param ticks the number of work ticks allocated from the parent monitor
+ * @return the new sub-progress monitor
+ */
+ private IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) {
+ if (monitor != null)
+ return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
- IDocument document= info.fTextFileBuffer.getDocument();
- IResource resource= info.fCopy.getResource();
-
- if (resource instanceof IFile && !resource.exists()) {
- // underlying resource has been deleted, just recreate file, ignore the rest
- createFileFromDocument(monitor, (IFile) resource, document);
- return;
- }
+ return new NullProgressMonitor();
+ }
+
+ protected void commitWorkingCopy(IProgressMonitor monitor, Object element, TranslationUnitInfo info,
+ boolean overwrite) throws CoreException {
+ if (monitor == null)
+ monitor= new NullProgressMonitor();
+
+ monitor.beginTask("", 100); //$NON-NLS-1$
try {
- commitFileBuffer(monitor, info, overwrite);
- } catch (CoreException x) {
- // inform about the failure
- fireElementStateChangeFailed(element);
- throw x;
- } catch (RuntimeException x) {
- // inform about the failure
- fireElementStateChangeFailed(element);
- throw x;
+ IDocument document= info.fTextFileBuffer.getDocument();
+ IResource resource= info.fCopy.getResource();
+
+ boolean isSynchronized= resource.isSynchronized(IResource.DEPTH_ZERO);
+
+ // Make sure file gets save in commit() if the underlying file has been deleted
+ if (!isSynchronized && isDeleted(element))
+ info.fTextFileBuffer.setDirty(true);
+
+ if (resource instanceof IFile && !resource.exists()) {
+ // Underlying resource has been deleted, just recreate file, ignore the rest
+ createFileFromDocument(monitor, (IFile) resource, document);
+ return;
+ }
+
+ try {
+ CoreException saveActionException= null;
+ try {
+ performSaveActions(info.fTextFileBuffer, getSubProgressMonitor(monitor, 20));
+ } catch (CoreException e) {
+ saveActionException = e;
+ }
+
+ CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(info.fCopy, isSynchronized || overwrite);
+ op.runOperation(getSubProgressMonitor(monitor, 80));
+
+ if (saveActionException != null) {
+ throw saveActionException;
+ }
+ } catch (CoreException x) {
+ // inform about the failure
+ fireElementStateChangeFailed(element);
+ throw x;
+ } catch (RuntimeException x) {
+ // inform about the failure
+ fireElementStateChangeFailed(element);
+ throw x;
+ }
+ } finally {
+ monitor.done();
}
}
@@ -955,14 +1005,8 @@ public class CDocumentProvider extends TextFileDocumentProvider {
* @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createSaveOperation(java.lang.Object, org.eclipse.jface.text.IDocument, boolean)
*/
@Override
- protected DocumentProviderOperation createSaveOperation(final Object element, final IDocument document, final boolean overwrite) throws CoreException {
- try {
- performSaveActions(document);
- } catch (Exception exc) {
- // log any exeption, but perform save anyway
- CUIPlugin.log(exc);
- }
-
+ protected DocumentProviderOperation createSaveOperation(final Object element, final IDocument document,
+ final boolean overwrite) throws CoreException {
final FileInfo info= getFileInfo(element);
if (info instanceof TranslationUnitInfo) {
return new DocumentProviderOperation() {
@@ -993,66 +1037,117 @@ public class CDocumentProvider extends TextFileDocumentProvider {
}
/**
- * Perform configured document manipulations before save.
- *
- * @param document
+ * Removes trailing whitespaces from changed lines and adds newline at the end of the file,
+ * if the last line of the file was changed.
* @throws BadLocationException
*/
- private void performSaveActions(final IDocument document) throws BadLocationException {
- //add a newline to the end of the document (if it is not already present)
- //-----------------------------------------------------------------------
- //for people who do not want auto-modification of their files,
- //this flag will prevent addition of a newline unless the user
- //explicitly sets the preference thru Window -> Preferences -> C/C++ -> Editor
- // -> Appearance Tab -> Ensure newline end of file when saving
- if (PreferenceConstants.getPreferenceStore().getBoolean(
- PreferenceConstants.ENSURE_NEWLINE_AT_EOF)) {
- // even if the document is empty, there will be at least one line in
- // it (the 0th one)
- int lastLineIndex = document.getNumberOfLines() - 1;
-
- // we have to ensure that the length of the last line is 0.
- // this will also take care of empty files. empty files have
- // only one line in them and the length of this one and only
- // line is 0.
- // Thus we do not need to append an extra line separator to
- // empty files.
- int lastLineLength = document.getLineLength(lastLineIndex);
- if (lastLineLength != 0) {
- document.replace(document.getLength(), 0,
- TextUtilities.getDefaultLineDelimiter(document));
- }
- }
-
- // Remove trailing whitespace when saving. Triggered by the flag
- // in Preferences -> C/C++ -> Editor
- if (PreferenceConstants.getPreferenceStore().getBoolean(
- PreferenceConstants.REMOVE_TRAILING_WHITESPACE)) {
-
- int lineCount= document.getNumberOfLines();
- for (int i= 0; i < lineCount; i++) {
-
- IRegion region= document.getLineInformation(i);
- if (region.getLength() == 0)
- continue;
-
- int lineStart= region.getOffset();
- int lineExclusiveEnd= lineStart + region.getLength();
-
- // Find the rightmost none-whitespace character
- int charPos= lineExclusiveEnd - 1;
- while (charPos >= lineStart && Character.isWhitespace(document.getChar(charPos)))
- charPos--;
-
- charPos++;
- if (charPos < lineExclusiveEnd) {
- DeleteEdit edit= new DeleteEdit(charPos, lineExclusiveEnd - charPos);
+ private void performSaveActions(ITextFileBuffer buffer, IProgressMonitor monitor) throws CoreException {
+ if (shouldRemoveTrailingWhitespace() || shouldAddNewlineAtEof()) {
+ IRegion[] changedRegions= EditorUtility.calculateChangedLineRegions(buffer, getSubProgressMonitor(monitor, 20));
+ IDocument document = buffer.getDocument();
+ TextEdit edit = createSaveActionEdit(document, changedRegions);
+ if (edit != null) {
+ try {
edit.apply(document);
+ } catch (MalformedTreeException e) {
+ String message= e.getMessage();
+ if (message == null)
+ message= "MalformedTreeException"; //$NON-NLS-1$
+ throw new CoreException(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, message, e));
+ } catch (BadLocationException e) {
+ String message= e.getMessage();
+ if (message == null)
+ message= "BadLocationException"; //$NON-NLS-1$
+ throw new CoreException(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, message, e));
}
}
}
}
+ private static boolean shouldAddNewlineAtEof() {
+ return PreferenceConstants.getPreferenceStore().getBoolean(
+ PreferenceConstants.ENSURE_NEWLINE_AT_EOF);
+ }
+
+ private static boolean shouldRemoveTrailingWhitespace() {
+ return PreferenceConstants.getPreferenceStore().getBoolean(
+ PreferenceConstants.REMOVE_TRAILING_WHITESPACE);
+ }
+
+ /**
+ * Creates a text edit for the save actions.
+ * @return a text edit, or null
if the save actions leave the file intact.
+ */
+ private TextEdit createSaveActionEdit(IDocument document, IRegion[] changedRegions) {
+ TextEdit rootEdit = null;
+ try {
+ if (shouldRemoveTrailingWhitespace()) {
+ // Remove trailing whitespace from changed lines.
+ for (IRegion region : changedRegions) {
+ int firstLine = document.getLineOfOffset(region.getOffset());
+ int lastLine = document.getLineOfOffset(region.getOffset() + region.getLength());
+ for (int line = firstLine; line <= lastLine; line++) {
+ IRegion lineRegion = document.getLineInformation(line);
+ if (lineRegion.getLength() == 0) {
+ continue;
+ }
+ int lineStart = lineRegion.getOffset();
+ int lineEnd = lineStart + lineRegion.getLength();
+
+ // Find the rightmost none-whitespace character
+ int charPos = lineEnd - 1;
+ while (charPos >= lineStart && Character.isWhitespace(document.getChar(charPos)))
+ charPos--;
+
+ charPos++;
+ if (charPos < lineEnd) {
+ TextEdit edit= new DeleteEdit(charPos, lineEnd - charPos);
+ if (rootEdit == null) {
+ rootEdit = new MultiTextEdit();
+ }
+ rootEdit.addChild(edit);
+ }
+ }
+ }
+ }
+ if (shouldAddNewlineAtEof()) {
+ // Add newline at the end of the file.
+ int endOffset = document.getLength();
+ IRegion lastLineRegion = document.getLineInformationOfOffset(endOffset);
+ if (lastLineRegion.getLength() != 0) {
+ for (IRegion region : changedRegions) {
+ if (region.getOffset() + region.getLength() >= lastLineRegion.getOffset()) {
+ // Last line has changed
+ if (!shouldRemoveTrailingWhitespace() || !isWhitespaceRegion(document, lastLineRegion)) {
+ TextEdit edit = new InsertEdit(endOffset,
+ TextUtilities.getDefaultLineDelimiter(document));
+ if (rootEdit == null) {
+ rootEdit = edit;
+ } else {
+ rootEdit.addChild(edit);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ } catch (BadLocationException e) {
+ CUIPlugin.log(e);
+ }
+ return rootEdit;
+ }
+
+ private static boolean isWhitespaceRegion(IDocument document, IRegion region) throws BadLocationException {
+ int end = region.getOffset() + region.getLength();
+ for (int i = region.getOffset(); i < end; i++) {
+ if (!Character.isWhitespace(document.getChar(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Returns the preference whether handling temporary problems is enabled.
*/
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties
index c0204575571..5518298716f 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties
@@ -85,8 +85,8 @@ CEditorColoringConfigurationBlock_underline=&Underline
CEditorColoringConfigurationBlock_strikethrough=&Strikethrough
CEditorPreferencePage_colorPage_systemDefault=S&ystem Default
-CEditorPreferencePage_behaviorPage_removeTrailingWhitespace=Remove trailing &whitespace
-CEditorPreferencePage_behaviorPage_ensureNewline=Ensure &newline at end of file
+CEditorPreferencePage_behaviorPage_removeTrailingWhitespace=Remove trailing &whitespace in edited lines
+CEditorPreferencePage_behaviorPage_ensureNewline=Ensure &newline at the end of file
CEditorPreferencePage_behaviorPage_matchingBrackets=Highlight &matching brackets
CEditorPreferencePage_behaviorPage_subWordNavigation=Smart &caret positioning in identifiers
CEditorPreferencePage_behaviorPage_inactiveCode=Highlight &inactive code
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/LineComparator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/LineComparator.java
new file mode 100644
index 00000000000..eba6c92998d
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/LineComparator.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Prigogin (Google)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text;
+
+import org.eclipse.compare.rangedifferencer.IRangeComparator;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+
+import org.eclipse.cdt.ui.CUIPlugin;
+
+
+/**
+ * This implementation of IRangeComparator
compares lines of a document.
+ * The lines are compared using a DJB hash function.
+ *
+ * @since 5.1
+ */
+public class LineComparator implements IRangeComparator {
+ private static final long UNKNOWN_HASH = Long.MIN_VALUE;
+ private final IDocument fDocument;
+ private final long[] fHashes;
+
+ /**
+ * Create a line comparator for the given document.
+ *
+ * @param document
+ */
+ public LineComparator(IDocument document) {
+ fDocument= document;
+
+ fHashes= new long[fDocument.getNumberOfLines()];
+ for (int i = 0; i < fHashes.length; i++) {
+ fHashes[i] = UNKNOWN_HASH;
+ }
+ }
+
+ /*
+ * @see org.eclipse.compare.rangedifferencer.IRangeComparator#getRangeCount()
+ */
+ public int getRangeCount() {
+ return fDocument.getNumberOfLines();
+ }
+
+ /*
+ * @see org.eclipse.compare.rangedifferencer.IRangeComparator#rangesEqual(int, org.eclipse.compare.rangedifferencer.IRangeComparator, int)
+ */
+ public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) {
+ try {
+ return getHash(thisIndex) == ((LineComparator) other).getHash(otherIndex);
+ } catch (BadLocationException e) {
+ CUIPlugin.log(e);
+ return false;
+ }
+ }
+
+ /*
+ * @see org.eclipse.compare.rangedifferencer.IRangeComparator#skipRangeComparison(int, int, org.eclipse.compare.rangedifferencer.IRangeComparator)
+ */
+ public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) {
+ return false;
+ }
+
+ /**
+ * @param line the number of the line in the document to get the hash for
+ * @return the hash of the line
+ * @throws BadLocationException if the line number is invalid
+ */
+ private int getHash(int line) throws BadLocationException {
+ long hash= fHashes[line];
+ if (hash == UNKNOWN_HASH) {
+ IRegion lineRegion= fDocument.getLineInformation(line);
+ String lineContents= fDocument.get(lineRegion.getOffset(), lineRegion.getLength());
+ hash= computeDJBHash(lineContents);
+ fHashes[line] = hash;
+ }
+
+ return (int) hash;
+ }
+
+ /**
+ * Compute a hash using the DJB hash algorithm
+ *
+ * @param string the string for which to compute a hash
+ * @return the DJB hash value of the string
+ */
+ private int computeDJBHash(String string) {
+ int hash= 5381;
+ int len= string.length();
+ for (int i= 0; i < len; i++) {
+ char ch= string.charAt(i);
+ hash= (hash << 5) + hash + ch;
+ }
+
+ return hash;
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java
index e2d50a9a9cd..3ac5ff58128 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java
@@ -18,8 +18,16 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
import com.ibm.icu.text.MessageFormat;
+import org.eclipse.compare.rangedifferencer.IRangeComparator;
+import org.eclipse.compare.rangedifferencer.RangeDifference;
+import org.eclipse.compare.rangedifferencer.RangeDifferencer;
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
@@ -33,10 +41,21 @@ import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.action.Action;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
@@ -71,9 +90,11 @@ import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
+import org.eclipse.cdt.internal.ui.ICStatusConstants;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
import org.eclipse.cdt.internal.ui.editor.ITranslationUnitEditorInput;
+import org.eclipse.cdt.internal.ui.text.LineComparator;
public class EditorUtility {
@@ -726,4 +747,128 @@ public class EditorUtility {
}
return cProject;
}
+
+ /**
+ * Return the regions of all lines which have changed in the given buffer since the
+ * last save occurred. Each region in the result spans over the size of at least one line.
+ * If successive lines have changed a region spans over the size of all successive lines.
+ * The regions include line delimiters.
+ *
+ * @param buffer the buffer to compare contents from
+ * @param monitor to report progress to
+ * @return the regions of the changed lines
+ * @throws CoreException
+ * @since 5.1
+ */
+ public static IRegion[] calculateChangedLineRegions(final ITextFileBuffer buffer, final IProgressMonitor monitor) throws CoreException {
+ final IRegion[][] result= new IRegion[1][];
+ final IStatus[] errorStatus= new IStatus[] { Status.OK_STATUS };
+
+ try {
+ SafeRunner.run(new ISafeRunnable() {
+ /*
+ * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
+ */
+ public void handleException(Throwable exception) {
+ CUIPlugin.log(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, ICStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, exception.getLocalizedMessage(), exception));
+ String msg= Messages.EditorUtility_error_calculatingChangedRegions;
+ errorStatus[0]= new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, ICStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, msg, exception);
+ result[0]= null;
+ }
+
+ /*
+ * @see org.eclipse.core.runtime.ISafeRunnable#run()
+ */
+ public void run() throws Exception {
+ monitor.beginTask(Messages.EditorUtility_calculatingChangedRegions_message, 20);
+ IFileStore fileStore= buffer.getFileStore();
+
+ ITextFileBufferManager fileBufferManager= FileBuffers.createTextFileBufferManager();
+ fileBufferManager.connectFileStore(fileStore, getSubProgressMonitor(monitor, 15));
+ try {
+ IDocument currentDocument= buffer.getDocument();
+ IDocument oldDocument= ((ITextFileBuffer) fileBufferManager.getFileStoreFileBuffer(fileStore)).getDocument();
+
+ result[0]= getChangedLineRegions(oldDocument, currentDocument);
+ } finally {
+ fileBufferManager.disconnectFileStore(fileStore, getSubProgressMonitor(monitor, 5));
+ monitor.done();
+ }
+ }
+
+ /**
+ * Return regions of all lines which differ comparing oldDocument
s content
+ * with currentDocument
s content. Successive lines are merged into one region.
+ *
+ * @param oldDocument a document containing the old content
+ * @param currentDocument a document containing the current content
+ * @return the changed regions
+ * @throws BadLocationException
+ */
+ private IRegion[] getChangedLineRegions(IDocument oldDocument, IDocument currentDocument) throws BadLocationException {
+ /*
+ * Do not change the type of those local variables. We use Object
+ * here in order to prevent loading of the Compare plug-in at load
+ * time of this class.
+ */
+ Object leftSide= new LineComparator(oldDocument);
+ Object rightSide= new LineComparator(currentDocument);
+
+ RangeDifference[] differences= RangeDifferencer.findDifferences((IRangeComparator) leftSide, (IRangeComparator) rightSide);
+
+ // It holds that:
+ // 1. Ranges are sorted:
+ // forAll r1,r2 element differences: indexOf(r1) < indexOf(r2) -> r1.rightStart() < r2.rightStart();
+ // 2. Successive changed lines are merged into on RangeDifference
+ // forAll r1,r2 element differences: r1.rightStart() < r2.rightStart() -> r1.rightEnd() < r2.rightStart
+
+ List regions= new ArrayList();
+ for (int i= 0; i < differences.length; i++) {
+ RangeDifference curr= differences[i];
+ if (curr.kind() == RangeDifference.CHANGE) {
+ int startLine= curr.rightStart();
+ int endLine= curr.rightEnd() - 1;
+
+ IRegion startLineRegion= currentDocument.getLineInformation(startLine);
+ if (startLine >= endLine) {
+ // startLine > endLine indicates a deletion of one or more lines.
+ // Deletions are ignored except at the end of the document.
+ if (startLine == endLine ||
+ startLineRegion.getOffset() + startLineRegion.getLength() == currentDocument.getLength()) {
+ regions.add(startLineRegion);
+ }
+ } else {
+ IRegion endLineRegion= currentDocument.getLineInformation(endLine);
+ int startOffset= startLineRegion.getOffset();
+ int endOffset= endLineRegion.getOffset() + endLineRegion.getLength();
+ regions.add(new Region(startOffset, endOffset - startOffset));
+ }
+ }
+ }
+
+ return regions.toArray(new IRegion[regions.size()]);
+ }
+ });
+ } finally {
+ if (!errorStatus[0].isOK())
+ throw new CoreException(errorStatus[0]);
+ }
+
+ return result[0];
+ }
+
+ /**
+ * Creates and returns a new sub-progress monitor for
+ * the given parent monitor.
+ *
+ * @param monitor the parent progress monitor
+ * @param ticks the number of work ticks allocated from the parent monitor
+ * @return the new sub-progress monitor
+ */
+ private static IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) {
+ if (monitor != null)
+ return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+
+ return new NullProgressMonitor();
+ }
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java
index fd5d024cba2..0b90c85d7a6 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java
@@ -7,30 +7,29 @@
*
* Contributors:
* Markus Schorn - initial API and implementation
+ * Sergey Prigogin (Google)
*******************************************************************************/
-
package org.eclipse.cdt.internal.ui.util;
import com.ibm.icu.text.MessageFormat;
-public class Messages {
- public static String format(String pattern, Object[] args) {
- return MessageFormat.format(pattern, args);
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME= Messages.class.getName();
+
+ public static String EditorUtility_calculatingChangedRegions_message;
+ public static String EditorUtility_error_calculatingChangedRegions;
+
+ public static String format(String pattern, Object... arguments) {
+ return MessageFormat.format(pattern, arguments);
}
- public static String format(String pattern, Object arg0) {
- return format(pattern, new Object[] {arg0});
- }
+ private Messages() {
+ // Do not instantiate
+ }
- public static String format(String pattern, Object arg0, Object arg1) {
- return format(pattern, new Object[] {arg0, arg1});
- }
-
- public static String format(String pattern, Object arg0, Object arg1, Object arg2) {
- return format(pattern, new Object[] {arg0, arg1, arg2});
- }
-
- public static String format(String pattern, Object arg0, Object arg1, Object arg2, Object arg3) {
- return format(pattern, new Object[] {arg0, arg1, arg2, arg3});
- }
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.properties
new file mode 100644
index 00000000000..6805d5fb139
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2009 Google, Inc 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:
+# Sergey Prigogin (Google) - initial API and implementation
+###############################################################################
+
+EditorUtility_calculatingChangedRegions_message=Calculating changed regions
+EditorUtility_error_calculatingChangedRegions=An error occurred while calculating the changed regions. See error log for details.