diff options
author | Anton Leherbauer | 2008-02-08 12:30:10 +0000 |
---|---|---|
committer | Anton Leherbauer | 2008-02-08 12:30:10 +0000 |
commit | 00091c99cbc7b0bc051c3005da3cbc280878a876 (patch) | |
tree | 782eb510e1bcd1c0fb2288153a2f4892838d282d | |
parent | 4c7161361eb522edadc9016cec6c589db4c3753e (diff) | |
download | org.eclipse.cdt-00091c99cbc7b0bc051c3005da3cbc280878a876.tar.gz org.eclipse.cdt-00091c99cbc7b0bc051c3005da3cbc280878a876.tar.xz org.eclipse.cdt-00091c99cbc7b0bc051c3005da3cbc280878a876.zip |
Fix for 216437: [Formatter] Shift left/right incorrect in Mixed tab policy/indentation mode
7 files changed, 408 insertions, 49 deletions
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/ShiftActionTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/ShiftActionTest.java new file mode 100644 index 00000000000..70e91f7b9d5 --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/ShiftActionTest.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, 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: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.ui.tests.text; + +import java.util.ListResourceBundle; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.ui.texteditor.ShiftAction; + +import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.testplugin.CProjectHelper; +import org.eclipse.cdt.ui.tests.BaseUITestCase; +import org.eclipse.cdt.ui.tests.text.MarkOccurrenceTest.MarkOccurrenceTestSetup; + +import org.eclipse.cdt.internal.ui.editor.CEditor; + +/** + * Test the Shift left/right actions. + * + * @since 5.0 + */ +public class ShiftActionTest extends BaseUITestCase { + private static final String PROJECT= "ShiftTests"; + private static final String FILE = "shiftTest.c"; + + private static final class EmptyBundle extends ListResourceBundle { + protected Object[][] getContents() { + return new Object[0][]; + } + } + + protected static class ShiftTestSetup extends TestSetup { + + private ICProject fCProject; + + public ShiftTestSetup(Test test) { + super(test); + } + + protected void setUp() throws Exception { + super.setUp(); + + fCProject= CProjectHelper.createCProject(PROJECT, null); + fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, DefaultCodeFormatterConstants.MIXED); + fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, String.valueOf(8)); + fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE, String.valueOf(4)); + IFile file= EditorTestHelper.createFile(fCProject.getProject(), FILE, "", new NullProgressMonitor()); + } + + protected void tearDown () throws Exception { + EditorTestHelper.closeAllEditors(); + if (fCProject != null) { + CProjectHelper.delete(fCProject); + } + super.tearDown(); + } + } + + private static final Class THIS= ShiftActionTest.class; + public static Test suite() { + return new ShiftTestSetup(new TestSuite(THIS)); + } + + private CEditor fEditor; + private SourceViewer fSourceViewer; + private IDocument fDocument; + private MarkOccurrenceTestSetup fProjectSetup; + + /* + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + if (!ResourcesPlugin.getWorkspace().getRoot().exists(new Path(PROJECT))) { + fProjectSetup= new MarkOccurrenceTestSetup(this); + fProjectSetup.setUp(); + } + fEditor= (CEditor) EditorTestHelper.openInEditor(ResourceTestHelper.findFile(PROJECT + '/' + FILE), true); + fSourceViewer= EditorTestHelper.getSourceViewer(fEditor); + fDocument= fSourceViewer.getDocument(); + super.setUp(); + } + + /* + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (fProjectSetup != null) { + fProjectSetup.tearDown(); + } + super.tearDown(); + } + + private void shiftLeft() throws Exception { + new ShiftAction(new EmptyBundle(), "prefix", fEditor, SourceViewer.SHIFT_LEFT).run(); + } + + private void shiftRight() throws Exception { + new ShiftAction(new EmptyBundle(), "prefix", fEditor, SourceViewer.SHIFT_RIGHT).run(); + } + + private void selectAll() { + fSourceViewer.setSelectedRange(0, fDocument.getLength()); + } + + //void f() { + // for(;;) { + //} + + // void f() { + // for(;;) { + // } + public void testShiftRight() throws Exception { + StringBuffer[] contents= getContentsForTest(2); + String before= contents[0].toString(); + String after= contents[1].toString(); + fDocument.set(before); + selectAll(); + shiftRight(); + assertEquals(after, fDocument.get()); + } + + // void f() { + // for(;;) { + // } + + //void f() { + // for(;;) { + //} + public void testShiftLeft() throws Exception { + StringBuffer[] contents= getContentsForTest(2); + String before= contents[0].toString(); + String after= contents[1].toString(); + fDocument.set(before); + selectAll(); + shiftLeft(); + assertEquals(after, fDocument.get()); + } + +} diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java index d794ea94819..e19bb822035 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java @@ -33,6 +33,7 @@ public class TextTestSuite extends TestSuite { addTest(BracketInserterTest.suite()); addTest(IndentActionTest.suite()); addTest(FormatActionTest.suite()); + addTest(ShiftActionTest.suite()); addTest(CodeFormatterTest.suite()); addTest(CIndenterTest.suite()); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/IndentAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/IndentAction.java index e1d414ba23a..547bb9437ac 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/IndentAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/IndentAction.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 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 @@ -269,11 +269,12 @@ public class IndentAction extends TextEditorAction { String currentIndent= document.get(offset, length); // if we are right before the text start / line end, and already after the insertion point - // then just insert a tab. + // then just shift to the right if (fIsTabAction && caret == end && whiteSpaceLength(currentIndent) >= whiteSpaceLength(indent)) { - String tab= getTabEquivalent(); - document.replace(caret, 0, tab); - fCaretOffset= caret + tab.length(); + int indentWidth= whiteSpaceLength(currentIndent) + getIndentSize(); + String replacement= IndentUtil.changePrefix(currentIndent.trim(), indentWidth, getTabSize(), useSpaces()); + document.replace(offset, length, replacement); + fCaretOffset= offset + replacement.length(); return true; } @@ -329,36 +330,17 @@ public class IndentAction extends TextEditorAction { private int whiteSpaceLength(String indent) { if (indent == null) return 0; - else { - int size= 0; - int l= indent.length(); - int tabSize= getTabSize(); - - for (int i= 0; i < l; i++) - size += indent.charAt(i) == '\t' ? tabSize : 1; - return size; - } + return IndentUtil.computeVisualLength(indent, getTabSize()); } /** - * Returns a tab equivalent, either as a tab character or as spaces, depending on the editor and + * Returns whether spaces should be used exclusively for indentation, depending on the editor and * formatter preferences. * - * @return a string representing one tab in the editor, never <code>null</code> + * @return <code>true</code> if only spaces should be used */ - private String getTabEquivalent() { - String tab; - if (CCorePlugin.SPACE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) { - int size= getTabSize(); - StringBuffer buf= new StringBuffer(); - for (int i= 0; i< size; i++) - buf.append(' '); - tab= buf.toString(); - } else { - tab= "\t"; //$NON-NLS-1$ - } - - return tab; + private boolean useSpaces() { + return CCorePlugin.SPACE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)); } /** @@ -372,6 +354,16 @@ public class IndentAction extends TextEditorAction { } /** + * Returns the indent size used by the editor, which is deduced from the + * formatter preferences. + * + * @return the indent size as defined in the current formatter preferences + */ + private int getIndentSize() { + return getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE, 4); + } + + /** * Returns <code>true</code> if empty lines should be indented, <code>false</code> otherwise. * * @return <code>true</code> if empty lines should be indented, <code>false</code> otherwise diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java index 5de7312cb03..133c728683e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java @@ -175,6 +175,7 @@ import org.eclipse.cdt.ui.text.ICPartitions; import org.eclipse.cdt.ui.text.folding.ICFoldingStructureProvider; import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; +import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil; import org.eclipse.cdt.internal.ui.CPluginImages; import org.eclipse.cdt.internal.ui.ICHelpContextIds; @@ -1093,8 +1094,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC public static final String INACTIVE_CODE_ENABLE = "inactiveCodeEnable"; //$NON-NLS-1$ /** Preference key for inactive code painter color */ public static final String INACTIVE_CODE_COLOR = "inactiveCodeColor"; //$NON-NLS-1$ - /** Preference key for inserting spaces rather than tabs */ - public final static String SPACES_FOR_TABS = DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR; /** Preference key for automatically closing strings */ private final static String CLOSE_STRINGS = PreferenceConstants.EDITOR_CLOSE_STRINGS; /** Preference key for automatically closing brackets and parenthesis */ @@ -1211,6 +1210,13 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC if (fCEditorErrorTickUpdater != null) { fCEditorErrorTickUpdater.updateEditorImage(getInputCElement()); } + + ICElement element= getInputCElement(); + if (element instanceof ITranslationUnit) { + fBracketMatcher.configure(((ITranslationUnit)element).getLanguage()); + } else { + fBracketMatcher.configure(null); + } } /** @@ -1342,14 +1348,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC return; } - if (SPACES_FOR_TABS.equals(property)) { - if (isTabsToSpacesConversionEnabled()) - installTabsToSpacesConverter(); - else - uninstallTabsToSpacesConverter(); - return; - } - if (PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS.equals(property)) updateHoverBehavior(); @@ -1392,7 +1390,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC uninstallTabsToSpacesConverter(); installTabsToSpacesConverter(); } else { - updateIndentPrefixes(); + updateIndentationMode(); } return; } @@ -1723,8 +1721,21 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC } else tabToSpacesConverter.setLineTracker(new DefaultLineTracker()); ((ITextViewerExtension7)sourceViewer).setTabsToSpacesConverter(tabToSpacesConverter); - updateIndentPrefixes(); + updateIndentationMode(); + } + } + + private void updateIndentationMode() { + ISourceViewer sourceViewer= getSourceViewer(); + if (sourceViewer instanceof CSourceViewer) { + CSourceViewer cSourceVieer= (CSourceViewer) sourceViewer; + ICElement element= getInputCElement(); + ICProject project= element == null ? null : element.getCProject(); + final int indentWidth= CodeFormatterUtil.getIndentWidth(project); + final boolean useSpaces= isTabsToSpacesConversionEnabled(); + cSourceVieer.configureIndentation(indentWidth, useSpaces); } + super.updateIndentPrefixes(); } /* @@ -1736,9 +1747,9 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC ICProject project= element == null ? null : element.getCProject(); String option; if (project == null) - option= CCorePlugin.getOption(SPACES_FOR_TABS); + option= CCorePlugin.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); else - option= project.getOption(SPACES_FOR_TABS, true); + option= project.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, true); return CCorePlugin.SPACE.equals(option); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CSourceViewer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CSourceViewer.java index 2ee2a2b5c44..006f736fc70 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CSourceViewer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CSourceViewer.java @@ -18,7 +18,11 @@ import java.util.ArrayList; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentRewriteSession; +import org.eclipse.jface.text.DocumentRewriteSessionType; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextPresentationListener; import org.eclipse.jface.text.Region; @@ -35,6 +39,7 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; @@ -51,11 +56,11 @@ import org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration; public class CSourceViewer extends ProjectionViewer implements IPropertyChangeListener { /** Show outline operation id. */ - public static final int SHOW_OUTLINE = 101; + public static final int SHOW_OUTLINE= 101; /** Show type hierarchy operation id. */ - public static final int SHOW_HIERARCHY = 102; + public static final int SHOW_HIERARCHY= 102; /** Show macro explorer operation id. */ - public static final int SHOW_MACRO_EXPLORER = 103; + public static final int SHOW_MACRO_EXPLORER= 103; /** Presents outline. */ private IInformationPresenter fOutlinePresenter; @@ -111,6 +116,15 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=195808 */ private boolean fWasProjectionMode; + + /** + * The configured indent width. + */ + private int fIndentWidth= 4; + /** + * Flag indicating whether to use spaces exclusively for indentation. + */ + private boolean fUseSpaces; /** * Creates new source viewer. @@ -152,6 +166,7 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi } super.configure(configuration); + if (configuration instanceof CSourceViewerConfiguration) { CSourceViewerConfiguration cConfiguration= (CSourceViewerConfiguration)configuration; fOutlinePresenter= cConfiguration.getOutlinePresenter(this); @@ -164,6 +179,12 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi if (fMacroExplorationPresenter != null) { fMacroExplorationPresenter.install(this); } + String[] defaultIndentPrefixes= (String[])fIndentChars.get(IDocument.DEFAULT_CONTENT_TYPE); + if (defaultIndentPrefixes != null && defaultIndentPrefixes.length > 0) { + final int indentWidth= cConfiguration.getIndentWidth(this); + final boolean useSpaces= cConfiguration.useSpacesOnly(this); + configureIndentation(indentWidth, useSpaces); + } } if (fPreferenceStore != null) { fPreferenceStore.addPropertyChangeListener(this); @@ -290,7 +311,7 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { - String property = event.getProperty(); + String property= event.getProperty(); if (AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND.equals(property) || AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT.equals(property) || AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND.equals(property) @@ -468,4 +489,114 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi enableProjection(); } } + + + /** + * Configure the indentation mode for this viewer. + * + * @param indentWidth the indentation width + * @param useSpaces if <code>true</code>, only spaces are used for indentation + */ + public void configureIndentation(int indentWidth, boolean useSpaces) { + fIndentWidth= indentWidth; + fUseSpaces= useSpaces; + } + + /* + * @see org.eclipse.jface.text.TextViewer#shift(boolean, boolean, boolean) + */ + protected void shift(boolean useDefaultPrefixes, boolean right, boolean ignoreWhitespace) { + if (!useDefaultPrefixes) { + // simple shift case + adjustIndent(right, fIndentWidth, fUseSpaces); + return; + } + super.shift(useDefaultPrefixes, right, ignoreWhitespace); + } + + /** + * Increase/decrease indentation of current selection. + * + * @param increase if <code>true</code>, indent is increased by one unit + * @param shiftWidth width in spaces of one indent unit + * @param useSpaces if <code>true</code>, only spaces are used for indentation + */ + protected void adjustIndent(boolean increase, int shiftWidth, boolean useSpaces) { + if (fUndoManager != null) { + fUndoManager.beginCompoundChange(); + } + IDocument d= getDocument(); + DocumentRewriteSession rewriteSession= null; + try { + if (d instanceof IDocumentExtension4) { + IDocumentExtension4 extension= (IDocumentExtension4) d; + rewriteSession= extension.startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL); + } + + Point selection= getSelectedRange(); + + // perform the adjustment + int tabWidth= getTextWidget().getTabs(); + int startLine= d.getLineOfOffset(selection.x); + int endLine= selection.y == 0 ? startLine : d.getLineOfOffset(selection.x + selection.y - 1); + for (int line= startLine; line <= endLine; ++line) { + IRegion lineRegion= d.getLineInformation(line); + String indent= IndentUtil.getCurrentIndent(d, line, false); + int indentWidth= IndentUtil.computeVisualLength(indent, tabWidth); + int newIndentWidth= Math.max(0, indentWidth + (increase ? shiftWidth : -shiftWidth)); + String newIndent= IndentUtil.changePrefix(indent.trim(), newIndentWidth, tabWidth, useSpaces); + int commonLen= getCommonPrefixLength(indent, newIndent); + if (commonLen < Math.max(indent.length(), newIndent.length())) { + if (commonLen > 0) { + indent= indent.substring(commonLen); + newIndent= newIndent.substring(commonLen); + } + final int offset= lineRegion.getOffset() + commonLen; + if (!increase && newIndent.length() > indent.length() && indent.length() > 0) { + d.replace(offset, indent.length(), ""); //$NON-NLS-1$ + d.replace(offset, 0, newIndent); + } else { + d.replace(offset, indent.length(), newIndent); + } + } + } + + } catch (BadLocationException x) { + // ignored + } finally { + if (rewriteSession != null) { + ((IDocumentExtension4)d).stopRewriteSession(rewriteSession); + } + if (fUndoManager != null) { + fUndoManager.endCompoundChange(); + } + } + } + + /** + * Compute the length of the common prefix of two strings. + * + * @param s1 + * @param s2 + * @return the length of the common prefix + */ + private static int getCommonPrefixLength(String s1, String s2) { + final int l1= s1.length(); + final int l2= s2.length(); + int i= 0; + while (i < l1 && i < l2 && s1.charAt(i) == s2.charAt(i)) { + ++i; + } + return i; + } + + /* + * work around for memory leak in TextViewer$WidgetCommand + */ + protected void updateTextListeners(WidgetCommand cmd) { + super.updateTextListeners(cmd); + cmd.preservedText= null; + cmd.event= null; + cmd.text= null; + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java index d2093314ae4..75f44c92906 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 2008 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 @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Sergey Prigogin, Google + * Anton Leherbauer (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.ui.editor; @@ -618,4 +619,46 @@ public final class IndentUtil { return computed.toString(); } + /** + * Extends the string with whitespace to match displayed width. + * @param prefix add to this string + * @param displayedWidth the desired display width + * @param tabWidth the configured tab width + * @param useSpaces whether to use spaces only + */ + public static String changePrefix(String prefix, int displayedWidth, int tabWidth, boolean useSpaces) { + int column = computeVisualLength(prefix, tabWidth); + if (column > displayedWidth) { + return prefix; + } + final StringBuffer buffer = new StringBuffer(prefix); + appendIndent(buffer, displayedWidth, tabWidth, useSpaces, column); + return buffer.toString(); + } + + /** + * Appends whitespace to given buffer such that its visual length equals the given width. + * @param buffer the buffer to add whitespace to + * @param width the desired visual indent width + * @param tabWidth the configured tab width + * @param useSpaces whether tabs should be substituted by spaces + * @param startColumn the column where to start measurement + * @return StringBuffer + */ + private static StringBuffer appendIndent(StringBuffer buffer, int width, int tabWidth, boolean useSpaces, int startColumn) { + assert tabWidth > 0; + int tabStop = startColumn - startColumn % tabWidth; + int tabs = useSpaces ? 0 : (width-tabStop) / tabWidth; + for (int i = 0; i < tabs; ++i) { + buffer.append('\t'); + tabStop += tabWidth; + startColumn = tabStop; + } + int spaces = width - startColumn; + for (int i = 0; i < spaces; ++i) { + buffer.append(' '); + } + return buffer; + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java index fd83c63a055..7f0a8ca7f5f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java @@ -531,6 +531,31 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration { } /** + * Returns the configured indent width for this viewer. + * @param sourceViewer + * @return the indent width + */ + public int getIndentWidth(ISourceViewer sourceViewer) { + return CodeFormatterUtil.getIndentWidth(getProject()); + } + + /** + * Returns whether spaces should be used exclusively for indentation. + * + * @param sourceViewer + * @return <code>true</code> if spaces should be used for indentation + */ + public boolean useSpacesOnly(ISourceViewer sourceViewer) { + ICProject project= getProject(); + String option; + if (project == null) + option= CCorePlugin.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); + else + option= project.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, true); + return CCorePlugin.SPACE.equals(option); + } + + /** * @see SourceViewerConfiguration#getAnnotationHover(ISourceViewer) */ public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { @@ -874,5 +899,4 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration { return conrolCreator; } - } |