From d6c48415c3e50707e934b56e39b796bbd4ae29f5 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Mon, 3 May 2010 04:53:27 +0000 Subject: [PATCH] Sort Lines command. --- .../cdt/ui/tests/text/SortLinesTest.java | 190 ++++++++++ .../cdt/ui/tests/text/TextTestSuite.java | 5 +- core/org.eclipse.cdt.ui/plugin.properties | 9 +- core/org.eclipse.cdt.ui/plugin.xml | 18 + .../cdt/internal/corext/util/Strings.java | 31 +- .../cdt/internal/ui/editor/CEditor.java | 8 +- .../ui/editor/CEditorActionContributor.java | 1 + .../ConstructedCEditorMessages.properties | 4 + .../editor/ICEditorActionDefinitionIds.java | 8 +- .../internal/ui/editor/SortLinesAction.java | 329 ++++++++++++++++++ .../cdt/internal/ui/util/EditorUtility.java | 4 +- .../cdt/ui/actions/CdtActionConstants.java | 13 +- .../cdt/ui/actions/GenerateActionGroup.java | 9 +- 13 files changed, 614 insertions(+), 15 deletions(-) create mode 100644 core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java new file mode 100644 index 00000000000..33654a027af --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +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.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.SourceViewer; + +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.testplugin.EditorTestHelper; +import org.eclipse.cdt.ui.testplugin.ResourceTestHelper; +import org.eclipse.cdt.ui.tests.BaseUITestCase; +import org.eclipse.cdt.internal.ui.editor.CEditor; +import org.eclipse.cdt.internal.ui.editor.SortLinesAction; + +/** + * Tests for the SortLinesAction. + * + * @since 5.2 + */ +public class SortLinesTest extends BaseUITestCase { + private static final String PROJECT = "SortLinesTest"; + private static final String FILE = "test.cpp"; + + private static final class EmptyBundle extends ListResourceBundle { + @Override + protected Object[][] getContents() { + return new Object[0][]; + } + } + + protected static class SortLinesTestSetup extends TestSetup { + private ICProject fCProject; + + public SortLinesTestSetup(Test test) { + super(test); + } + + @Override + 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()); + } + + @Override + protected void tearDown () throws Exception { + EditorTestHelper.closeAllEditors(); + if (fCProject != null) { + CProjectHelper.delete(fCProject); + } + super.tearDown(); + } + } + + private static final Class THIS= SortLinesTest.class; + public static Test suite() { + return new SortLinesTestSetup(new TestSuite(THIS)); + } + + private CEditor fEditor; + private SourceViewer fSourceViewer; + private IDocument fDocument; + private SortLinesTestSetup fProjectSetup; + + /* + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + if (!ResourcesPlugin.getWorkspace().getRoot().exists(new Path(PROJECT))) { + fProjectSetup= new SortLinesTestSetup(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() + */ + @Override + protected void tearDown() throws Exception { + if (fProjectSetup != null) { + fProjectSetup.tearDown(); + } + super.tearDown(); + } + + private void sortLines() throws Exception { + new SortLinesAction(fEditor).run(); + } + + /** + * Selects part of the document. + * + * @param startLine First line of the selection. Zero based. + * @param startPosition Start position of the selection in startLine. Zero based. + * @param endLine Last line of the selection. Zero based. + * @param endPosition Position after the end of the selection in endLine. Zero based. + */ + private void select(int startLine, int startPosition, int endLine, int endPosition) + throws BadLocationException { + int offset = fDocument.getLineOffset(startLine) + startPosition; + fSourceViewer.setSelectedRange(offset, fDocument.getLineOffset(endLine) + endPosition - offset); + } + + /** + * Selects the whole document. + */ + private void selectAll() { + fSourceViewer.setSelectedRange(0, fDocument.getLength()); + } + + // // e.h + // #include "e.h" + // #include "bbb.h" + // #include "dd.h" + // /* + // * ccccc.h + // */ + // #include "ccccc.h" + // #include "aaaa.h" + + // #include "aaaa.h" + // #include "bbb.h" + // /* + // * ccccc.h + // */ + // #include "ccccc.h" + // #include "dd.h" + // // e.h + // #include "e.h" + public void testSortLinesMixed() throws Exception { + StringBuffer[] contents= getContentsForTest(2); + String before= contents[0].toString(); + String after= contents[1].toString(); + fDocument.set(before); + selectAll(); + sortLines(); + assertEquals(after, fDocument.get()); + } + + // /* + // * Ganymede + // * Europa + // * Callisto + // */ + + // /* + // * Europa + // * Ganymede + // * Callisto + // */ + public void testSortLinesCommentsOnly() throws Exception { + StringBuffer[] contents= getContentsForTest(2); + String before= contents[0].toString(); + String after= contents[1].toString(); + fDocument.set(before); + select(1, 0, 3, 0); + sortLines(); + 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 03a27cbcc00..4a99d7ecc16 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 @@ -72,10 +72,11 @@ public class TextTestSuite extends TestSuite { // compare tests addTest(CStructureCreatorTest.suite()); - // block comment tests + // source manipulation tests addTest(AddBlockCommentTest.suite()); addTest(RemoveBlockCommentTest.suite()); - + addTest(SortLinesTest.suite()); + // add include addTest(AddIncludeTest.suite()); } diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index 021fb4e8407..e8c297ed06e 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -170,7 +170,7 @@ Refactoring.extractLocalVariable.label=Extract &Local Variable Refactoring.extractFunction.label=Extract &Function... Refactoring.hideMethod.label=Hide Method... Refactoring.implementMethod.label=Impl&ement Method... -Refactoring.gettersAndSetters.label=Generate Getters and Setters... +Refactoring.gettersAndSetters.label=Gene&rate Getters and Setters... Source.menu.label = &Source @@ -253,10 +253,14 @@ OpenTypeAction.tooltip= Open Element ActionDefinition.openType.name= Open Element ActionDefinition.openType.description= Open an element in an Editor -#Add include +#Add Include ActionDefinition.addInclude.name= Add Include ActionDefinition.addInclude.description= Create include statement on selection +#Sort Lines +ActionDefinition.sortLines.name= Sort Lines +ActionDefinition.sortLines.description= Sort selected lines alphabetically + #Show outline dialog ActionDefinition.showOutline.name= Show outline ActionDefinition.showOutline.description= Shows outline @@ -555,6 +559,7 @@ renameParticipant.name = Source Folder Rename FormatAction.label= &Format IndentAction.label= Correct &Indentation AddIncludeAction.label= A&dd Include +SortLinesAction.label= Sor&t Lines CommentAction.label= Co&mment UncommentAction.label= &Uncomment ToggleCommentAction.label= Togg&le Comment diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index 3fdbbe83795..dabfc933d4e 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -1334,6 +1334,13 @@ retarget="true"> + + + + + = 0;) + for (int i = c.length; --i >= 0;) { if (s.charAt(i) != c[i]) return false; + } return true; } @@ -421,7 +421,32 @@ public class Strings { else return text.substring(0, end); } - + + /** + * Converts tabs to spaces in a line of text. + * @param line The line of text. + * @param tabWidth Tabulation size. + * @return The line with tab characters replaced by spaces. + */ + public static String convertTabsToSpaces(String line, int tabWidth) { + StringBuilder buf = null; + for (int i = 0; i < line.length(); i++) { + char c = line.charAt(i); + if (c == '\t') { + if (buf == null) { + buf = new StringBuilder(line.length() * tabWidth); + buf.append(line.subSequence(0, i)); + } + for (int k = tabWidth - i % tabWidth; --k >= 0;) { + buf.append(' '); + } + } else if (buf != null) { + buf.append(c); + } + } + return buf != null ? buf.toString() : line; + } + public static String removeMnemonicIndicator(String string) { return LegacyActionTools.removeMnemonics(string); } 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 c2adf580ac6..33de676f576 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 @@ -2191,6 +2191,12 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC setAction("Format", action); //$NON-NLS-1$ markAsStateDependentAction("Format", true); //$NON-NLS-1$ + action = new SortLinesAction(this); + action.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_LINES); + setAction("SortLines", action); //$NON-NLS-1$ + markAsStateDependentAction("SortLines", true); //$NON-NLS-1$ + markAsSelectionDependentAction("SortLines", true); //$NON-NLS-1$ + action = new ContentAssistAction(bundle, "ContentAssistProposal.", this); //$NON-NLS-1$ action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); setAction("ContentAssistProposal", action); //$NON-NLS-1$ @@ -2225,7 +2231,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC action.setActionDefinitionId(ICEditorActionDefinitionIds.OPEN_QUICK_MACRO_EXPLORER); setAction("OpenMacroExplorer", action); //$NON-NLS-1$*/ - //Assorted action groupings + // Assorted action groupings fSelectionSearchGroup = createSelectionSearchGroup(); fTextSearchGroup= new TextSearchGroup(this); fRefactoringActionGroup= new CRefactoringActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java index 165f843fa7c..b933b8297f8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java @@ -196,6 +196,7 @@ public class CEditorActionContributor extends TextEditorActionContributor { bars.setGlobalActionHandler(CdtActionConstants.REMOVE_BLOCK_COMMENT, getAction(textEditor, "RemoveBlockComment")); //$NON-NLS-1$ bars.setGlobalActionHandler(CdtActionConstants.INDENT, getAction(textEditor, "Indent")); //$NON-NLS-1$ bars.setGlobalActionHandler(CdtActionConstants.ADD_INCLUDE, getAction(textEditor, "AddIncludeOnSelection")); //$NON-NLS-1$ + bars.setGlobalActionHandler(CdtActionConstants.SORT_LINES, getAction(textEditor, "SortLines")); //$NON-NLS-1$ IAction action= getAction(textEditor, ITextEditorActionConstants.REFRESH); bars.setGlobalActionHandler(ITextEditorActionConstants.REFRESH, action); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties index 2cd6a8ba026..fc747605b87 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties @@ -17,6 +17,10 @@ AddIncludeOnSelection.description=Add include statement for selected name AddIncludeOnSelection.label=Add Include AddIncludeOnSelection.tooltip=Add Include Statement for Selected Name +SortLines.description=Sort selected lines alphabetically +SortLines.label=Sort Lines +SortLines.tooltip=Sort Selected Lines Alphabetically + OpenOutline.label= Quick Out&line OpenOutline.tooltip= Shows the Quick Outline of Editor Input OpenOutline.description= Shows the quick outline for the editor input diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java index 8cba4ff6a2b..8c7b4a2643f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java @@ -235,11 +235,17 @@ public interface ICEditorActionDefinitionIds extends ITextEditorActionDefinition */ public static final String TOGGLE_MARK_OCCURRENCES= "org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences"; //$NON-NLS-1$ - /** * Action definition ID of the open macro explorer quick view action * (value "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"). * @since 5.0 */ public static final String OPEN_QUICK_MACRO_EXPLORER = "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"; //$NON-NLS-1$ + + /** + * Action definition id of sort lines action. + * (value: "org.eclipse.cdt.ui.edit.text.c.sort.lines"). + * @since 5.2 + */ + public static final String SORT_LINES = "org.eclipse.cdt.ui.edit.text.c.sort.lines"; //$NON-NLS-1$ } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java new file mode 100644 index 00000000000..db12b664fd4 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright (c) 2010 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 + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.editor; + +import java.util.Arrays; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.text.TextUtilities; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.text.undo.DocumentUndoManagerRegistry; +import org.eclipse.text.undo.IDocumentUndoManager; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.TextEditorAction; + +import com.ibm.icu.text.Collator; + +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.text.ICPartitions; + +import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil; +import org.eclipse.cdt.internal.corext.util.Strings; + +import org.eclipse.cdt.internal.ui.util.EditorUtility; + +/** + * Sorts selected lines in alphabetical order. If both, comment and non-comment lines + * are selected, the non-comment lines are sorted, and the comments are moved together + * with the non-comment lines they precede. + * + * @since 5.2 + */ +public final class SortLinesAction extends TextEditorAction { + + public SortLinesAction(ITextEditor editor) { + super(CEditorMessages.getBundleForConstructedKeys(), "SortLines.", editor); //$NON-NLS-1$ + } + + /** + * Sorts selected lines. + */ + @Override + public void run() { + ITextEditor editor= getTextEditor(); + if (editor == null) + return; + + ISelection selection = editor.getSelectionProvider().getSelection(); + if (!(selection instanceof ITextSelection)) + return; + + ITextSelection textSelection= (ITextSelection) selection; + if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0) + return; + + IEditorInput editorInput = editor.getEditorInput(); + ICProject cProject = EditorUtility.getCProject(editorInput); + IDocument document= editor.getDocumentProvider().getDocument(editorInput); + try { + IRegion block= getTextBlockFromSelection(textSelection, document); + SortElement[] elements = createSortElements(block, document, + CodeFormatterUtil.getTabWidth(cProject)); + if (elements.length <= 1) + return; + if (!validateEditorInputState()) + return; + + Arrays.sort(elements); + StringBuilder buf = new StringBuilder(); + for (SortElement element : elements) { + buf.append(document.get(element.getOffset(), element.getLength())); + if (!isLastLineTerminated(element, document)) { + buf.append(TextUtilities.getDefaultLineDelimiter(document)); + } + } + ReplaceEdit edit = new ReplaceEdit(block.getOffset(), block.getLength(), buf.toString()); + IDocumentUndoManager manager= DocumentUndoManagerRegistry.getDocumentUndoManager(document); + manager.beginCompoundChange(); + edit.apply(document); + editor.getSelectionProvider().setSelection(new TextSelection(block.getOffset(), buf.length())); + manager.endCompoundChange(); + } catch (BadLocationException e) { + CUIPlugin.log(e); + } + } + + /** + * Creates a region describing the text block (something that consists of full lines) + * completely containing the current selection. + * + * @param selection The selection to use + * @param document The document + * @return the region describing the text block comprising the given selection + */ + private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) { + try { + IRegion firstLine= document.getLineInformationOfOffset(selection.getOffset()); + int selectionEnd = selection.getOffset() + selection.getLength(); + IRegion lastLine= document.getLineInformationOfOffset(selectionEnd); + int length = lastLine.getOffset() - firstLine.getOffset(); + if (selectionEnd > lastLine.getOffset()) { + // Last line is included with the line delimiter. + length += document.getLineLength(document.getLineOfOffset(selectionEnd)); + } + return new Region(firstLine.getOffset(), length); + } catch (BadLocationException e) { + CUIPlugin.log(e); // Should not happen + } + return null; + } + + private SortElement[] createSortElements(IRegion block, IDocument document, int tabWidth) + throws BadLocationException { + ITypedRegion[] regions= TextUtilities.computePartitioning(document, ICPartitions.C_PARTITIONING, + block.getOffset(), block.getLength(), false); + + int numLines = document.getNumberOfLines(block.getOffset(), block.getLength()); + if (endOf(block) <= document.getLineInformationOfOffset(endOf(block)).getOffset()) { + numLines--; // Last line is excluded + } + LineInfo[] lineDescriptors = new LineInfo[numLines]; + int numNonCommentLines = 0; + int i = 0; + int k = 0; + int line = document.getLineOfOffset(block.getOffset()); + int endLine = line + numLines; + for (; line < endLine; line++) { + LineInfo lineInfo = new LineInfo(document, line); + lineDescriptors[k++] = lineInfo; + while (i < regions.length && endOf(regions[i]) <= lineInfo.getTrimmedOffset()) + i++; + for (; i < regions.length && regions[i].getOffset() < lineInfo.getTrimmedEndOffset(); i++) { + ITypedRegion region = regions[i]; + if (region.getType() != ICPartitions.C_MULTI_LINE_COMMENT && + region.getType() != ICPartitions.C_MULTI_LINE_DOC_COMMENT && + region.getType() != ICPartitions.C_SINGLE_LINE_COMMENT && + region.getType() != ICPartitions.C_SINGLE_LINE_DOC_COMMENT) { + lineInfo.nonComment = true; + break; + } + } + if (lineInfo.nonComment) { + numNonCommentLines++; + } + } + SortElement[] elements; + if (numNonCommentLines > 1) { + elements = new SortElement[numNonCommentLines]; + k = 0; + int offset = block.getOffset(); + for (int j = 0; j < lineDescriptors.length; j++) { + LineInfo lineInfo = lineDescriptors[j]; + if (lineInfo.nonComment) { + int endOffset = k < numNonCommentLines - 1 ? + lineInfo.getEndOffset() : block.getOffset() + block.getLength(); + elements[k++] = new SortElement(new Region(offset, endOffset - offset), lineInfo, + document, tabWidth); + offset = lineInfo.getEndOffset(); + } + } + } else { + elements = new SortElement[numLines]; + for (int j = 0; j < lineDescriptors.length; j++) { + LineInfo lineInfo = lineDescriptors[j]; + elements[j] = new SortElement(lineInfo, lineInfo, document, tabWidth); + } + } + return elements; + } + + /** + * Returns end offset of a region. + */ + private int endOf(IRegion region) { + return region.getOffset() + region.getLength(); + } + + /** + * Returns true if the given region is terminated by a line delimiter. + */ + private static boolean isLastLineTerminated(IRegion region, IDocument document) throws BadLocationException { + int offset = region.getOffset() + region.getLength(); + IRegion nextLine = document.getLineInformationOfOffset(offset); + return nextLine.getOffset() == offset; + } + + @Override + public void update() { + if (!canModifyEditor()) { + setEnabled(false); + return; + } + + // Enable if two or more lines are selected. + boolean enabled = false; + ITextEditor editor = getTextEditor(); + if (editor != null) { + ISelection selection = editor.getSelectionProvider().getSelection(); + if (selection instanceof ITextSelection) { + ITextSelection textSelection= (ITextSelection) selection; + int startLine = textSelection.getStartLine(); + int endLine = textSelection.getEndLine(); + if (startLine >= 0 && endLine > startLine) { + if (endLine == startLine + 1) { + IDocument document= editor.getDocumentProvider().getDocument(editor.getEditorInput()); + try { + if (textSelection.getOffset() + textSelection.getLength() > document.getLineOffset(endLine)) { + enabled = true; + } + } catch (BadLocationException e) { + CUIPlugin.log(e); + } + } else { + enabled = true; + } + } + } + } + setEnabled(enabled); + } + + /* + * @see TextEditorAction#setEditor(ITextEditor) + */ + @Override + public void setEditor(ITextEditor editor) { + super.setEditor(editor); + } + + private static class SortElement implements Comparable, IRegion { + private static final Collator collator = Collator.getInstance(); + private final IRegion region; + private final String collationKey; + + public SortElement(IRegion region, IRegion collationLine, IDocument document, int tabWidth) + throws BadLocationException { + super(); + this.region = region; + this.collationKey = Strings.convertTabsToSpaces(Strings.trimTrailingTabsAndSpaces( + document.get(collationLine.getOffset(), collationLine.getLength())), tabWidth); + } + + public int compareTo(SortElement other) { + return collator.compare(collationKey, other.collationKey); + } + + public int getOffset() { + return region.getOffset(); + } + + public int getLength() { + return region.getLength(); + } + } + + private static class LineInfo implements IRegion { + final int offset; + final int length; + final int trimmedOffset; + final int trimmedEndOffset; + boolean nonComment; + + LineInfo(IDocument document, int line) throws BadLocationException { + offset = document.getLineOffset(line); + length = document.getLineLength(line); + int begin = offset; + int end = offset + length; + while (--end >= begin && Character.isWhitespace(document.getChar(end))) { + } + end++; + while (begin < end && Character.isWhitespace(document.getChar(begin))) { + begin++; + } + trimmedOffset = begin; + trimmedEndOffset = end; + } + + /** + * Offset of the line in the document. + */ + public int getOffset() { + return offset; + } + + /** + * Length of the line including line delimiter. + */ + public int getLength() { + return length; + } + + /** + * End offset of the line including line delimiter. + */ + public int getEndOffset() { + return offset + length; + } + + /** + * Document offset of the first non-whitespace character of the line. + */ + public int getTrimmedOffset() { + return trimmedOffset; + } + + /** + * Document offset after the last non-whitespace character of the line. + */ + public int getTrimmedEndOffset() { + return trimmedEndOffset; + } + } +} 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 36eb72bbb15..c7cd47ece82 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 @@ -733,14 +733,14 @@ public class EditorUtility { public static ICProject getCProject(IEditorInput input) { ICProject cProject= null; if (input instanceof IFileEditorInput) { - IProject project= ((IFileEditorInput)input).getFile().getProject(); + IProject project= ((IFileEditorInput) input).getFile().getProject(); if (project != null) { cProject= CoreModel.getDefault().create(project); if (!cProject.exists()) cProject= null; } } else if (input instanceof ITranslationUnitEditorInput) { - final ITranslationUnit tu= ((ITranslationUnitEditorInput)input).getTranslationUnit(); + final ITranslationUnit tu= ((ITranslationUnitEditorInput) input).getTranslationUnit(); if (tu != null) { cProject= tu.getCProject(); } else if (input instanceof ExternalEditorInput) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java index 581802495de..03eb44c09b4 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java @@ -132,19 +132,26 @@ public class CdtActionConstants { * (value "org.eclipse.cdt.ui.actions.Format"). */ public static final String FORMAT= "org.eclipse.cdt.ui.actions.Format"; //$NON-NLS-1$ - + /** * Source menu: name of standard Add Include global action * (value "org.eclipse.cdt.ui.actions.AddInclude"). */ public static final String ADD_INCLUDE= "org.eclipse.cdt.ui.actions.AddInclude"; //$NON-NLS-1$ - + + /** + * Source menu: name of standard Sort Lines global action + * (value "org.eclipse.cdt.ui.actions.SortLines"). + * @since 5.2 + */ + public static final String SORT_LINES= "org.eclipse.cdt.ui.actions.SortLines"; //$NON-NLS-1$ + /** * Source menu: name of standard Sort Members global action (value * "org.eclipse.cdt.ui.actions.SortMembers"). */ public static final String SORT_MEMBERS= "org.eclipse.cdt.ui.actions.SortMembers"; //$NON-NLS-1$ - + /** * Source menu: name of standard Surround with try/catch block global action * (value "org.eclipse.cdt.ui.actions.SurroundWithTryCatch"). diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java index 274e1d50ff3..e7c61a1766e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java @@ -52,6 +52,7 @@ import org.eclipse.cdt.internal.ui.actions.CDTQuickMenuCreator; import org.eclipse.cdt.internal.ui.editor.AddIncludeOnSelectionAction; import org.eclipse.cdt.internal.ui.editor.CEditor; import org.eclipse.cdt.internal.ui.editor.ICEditorActionDefinitionIds; +import org.eclipse.cdt.internal.ui.editor.SortLinesAction; /** * Action group that adds the source and generate actions to a part's context @@ -129,6 +130,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange // // private OrganizeIncludesAction fOrganizeIncludes; // private SortMembersAction fSortMembers; + private SortLinesAction fSortLines; // private FormatAllAction fFormatAll; // private CopyQualifiedNameAction fCopyQualifiedNameAction; // @@ -161,7 +163,11 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange // fSortMembers= new SortMembersAction(editor); // fSortMembers.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_MEMBERS); // editor.setAction("SortMembers", fSortMembers); //$NON-NLS-1$ -// + + fSortLines= new SortLinesAction(editor); + fSortLines.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_LINES); + editor.setAction("SortLines", fSortLines); //$NON-NLS-1$ + // IAction pastAction= editor.getAction(ITextEditorActionConstants.PASTE);//IWorkbenchActionDefinitionIds.PASTE); // fCopyQualifiedNameAction= new CopyQualifiedNameAction(editor, null, pastAction); // fCopyQualifiedNameAction.setActionDefinitionId(CopyQualifiedNameAction.JAVA_EDITOR_ACTION_DEFINITIONS_ID); @@ -412,6 +418,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange added+= addAction(source, fAddInclude); // added+= addAction(source, fOrganizeIncludes); // added+= addAction(source, fSortMembers); + added+= addAction(source, fSortLines); // added+= addAction(source, fCleanUp); source.add(new Separator(GROUP_GENERATE)); // added+= addAction(source, fOverrideMethods);