mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-24 01:15:29 +02:00
Bug 249359.
This commit is contained in:
parent
5407d0d337
commit
80abc8bf47
7 changed files with 470 additions and 104 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 <code>null</code> 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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <code>IRangeComparator</code> 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;
|
||||
}
|
||||
}
|
|
@ -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 <code>oldDocument</code>s content
|
||||
* with <code>currentDocument</code>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<IRegion> regions= new ArrayList<IRegion>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
Loading…
Add table
Reference in a new issue