X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java index 0ca710d..506df17 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java @@ -8,9 +8,10 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ - package net.sourceforge.phpeclipse.phpeditor; +import java.util.HashMap; +import java.util.Map; import java.util.ResourceBundle; import net.sourceforge.phpeclipse.PHPeclipsePlugin; @@ -18,8 +19,14 @@ import net.sourceforge.phpeclipse.PHPeclipsePlugin; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextUtilities; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.widgets.Display; @@ -31,7 +38,7 @@ import org.eclipse.ui.texteditor.TextEditorAction; /** - * An action which toggles the single line comment prefixes on the selected lines. + * An action which toggles comment prefixes on the selected lines. * * @since 3.0 */ @@ -39,8 +46,10 @@ public final class ToggleCommentAction extends TextEditorAction { /** The text operation target */ private ITextOperationTarget fOperationTarget; + /** The document partitioning */ + private String fDocumentPartitioning; /** The comment prefixes */ - private String[] fCommentPrefixes; + private Map fPrefixesMap; /** * Creates and initializes the action for the given text editor. The action @@ -51,23 +60,22 @@ public final class ToggleCommentAction extends TextEditorAction { * (described in ResourceAction constructor), or * null if none * @param editor the text editor - * @see ResourceAction#ResourceAction + * @see ResourceAction#ResourceAction(ResourceBundle, String, int) */ - public ToggleCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor, String[] commentPrefixes) { + public ToggleCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor) { super(bundle, prefix, editor); - fCommentPrefixes= commentPrefixes; } /** * Implementation of the IAction prototype. Checks if the selected - * lines are all commented or not and uncomment/comments them respectively. + * lines are all commented or not and uncomments/comments them respectively. */ public void run() { - if (fOperationTarget == null) + if (fOperationTarget == null || fDocumentPartitioning == null || fPrefixesMap == null) return; ITextEditor editor= getTextEditor(); - if (!(editor instanceof PHPEditor)) + if (editor == null) return; if (!validateEditorInputState()) @@ -101,37 +109,153 @@ public final class ToggleCommentAction extends TextEditorAction { * Is the given selection single-line commented? * * @param selection Selection to check - * @return true iff all selected lines are single-line commented + * @return true iff all selected lines are commented */ private boolean isSelectionCommented(ISelection selection) { if (!(selection instanceof ITextSelection)) return false; - ITextSelection ts= (ITextSelection) selection; - if (ts.getStartLine() < 0 || ts.getEndLine() < 0) + ITextSelection textSelection= (ITextSelection) selection; + if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0) return false; IDocument document= getTextEditor().getDocumentProvider().getDocument(getTextEditor().getEditorInput()); - OUTER: for (int i= ts.getStartLine(); i <= ts.getEndLine(); i++) { - for (int j= 0; j < fCommentPrefixes.length; j++) { - try { - if (fCommentPrefixes[j].length() == 0) - continue; - String s= document.get(document.getLineOffset(i), document.getLineLength(i)); - int index= s.indexOf(fCommentPrefixes[j]); - if (index >= 0 && s.substring(0, index).trim().length() == 0) - continue OUTER; - } catch (BadLocationException e) { - // should not happen - PHPeclipsePlugin.log(e); - } + + try { + + IRegion block= getTextBlockFromSelection(textSelection, document); + ITypedRegion[] regions= TextUtilities.computePartitioning(document, fDocumentPartitioning, block.getOffset(), block.getLength(), false); + + int lineCount= 0; + int[] lines= new int[regions.length * 2]; // [startline, endline, startline, endline, ...] + for (int i= 0, j= 0; i < regions.length; i++, j+= 2) { + // start line of region + lines[j]= getFirstCompleteLineOfRegion(regions[i], document); + // end line of region + int length= regions[i].getLength(); + int offset= regions[i].getOffset() + length; + if (length > 0) + offset--; + lines[j + 1]= (lines[j] == -1 ? -1 : document.getLineOfOffset(offset)); + lineCount += lines[j + 1] - lines[j] + 1; } - return false; + + // Perform the check + for (int i= 0, j= 0; i < regions.length; i++, j += 2) { + String[] prefixes= (String[]) fPrefixesMap.get(regions[i].getType()); + if (prefixes != null && prefixes.length > 0 && lines[j] >= 0 && lines[j + 1] >= 0) + if (!isBlockCommented(lines[j], lines[j + 1], prefixes, document)) + return false; + } + + return true; + + } catch (BadLocationException x) { + // should not happen + PHPeclipsePlugin.log(x); } - return true; + + return false; } /** + * Creates a region describing the text block (something that starts at + * the beginning of a line) 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 line= document.getLineInformationOfOffset(selection.getOffset()); + int length= selection.getLength() == 0 ? line.getLength() : selection.getLength() + (selection.getOffset() - line.getOffset()); + return new Region(line.getOffset(), length); + + } catch (BadLocationException x) { + // should not happen + PHPeclipsePlugin.log(x); + } + + return null; + } + + /** + * Returns the index of the first line whose start offset is in the given text range. + * + * @param region the text range in characters where to find the line + * @param document The document + * @return the first line whose start index is in the given range, -1 if there is no such line + */ + private int getFirstCompleteLineOfRegion(IRegion region, IDocument document) { + + try { + + int startLine= document.getLineOfOffset(region.getOffset()); + + int offset= document.getLineOffset(startLine); + if (offset >= region.getOffset()) + return startLine; + + offset= document.getLineOffset(startLine + 1); + return (offset > region.getOffset() + region.getLength() ? -1 : startLine + 1); + + } catch (BadLocationException x) { + // should not happen + PHPeclipsePlugin.log(x); + } + + return -1; + } + + /** + * Determines whether each line is prefixed by one of the prefixes. + * + * @param startLine Start line in document + * @param endLine End line in document + * @param prefixes Possible comment prefixes + * @param document The document + * @return true iff each line from startLine + * to and including endLine is prepended by one + * of the prefixes, ignoring whitespace at the + * begin of line + */ + private boolean isBlockCommented(int startLine, int endLine, String[] prefixes, IDocument document) { + + try { + + // check for occurrences of prefixes in the given lines + for (int i= startLine; i <= endLine; i++) { + + IRegion line= document.getLineInformation(i); + String text= document.get(line.getOffset(), line.getLength()); + + int[] found= TextUtilities.indexOf(prefixes, text, 0); + + if (found[0] == -1) + // found a line which is not commented + return false; + + String s= document.get(line.getOffset(), found[0]); + s= s.trim(); + if (s.length() != 0) + // found a line which is not commented + return false; + + } + + return true; + + } catch (BadLocationException x) { + // should not happen + PHPeclipsePlugin.log(x); + } + + return false; + } + + /** * Implementation of the IUpdate prototype method discovers * the operation through the current editor's * ITextOperationTarget adapter, and sets the enabled state @@ -160,4 +284,37 @@ public final class ToggleCommentAction extends TextEditorAction { super.setEditor(editor); fOperationTarget= null; } + + public void configure(ISourceViewer sourceViewer, SourceViewerConfiguration configuration) { + fPrefixesMap= null; + + String[] types= configuration.getConfiguredContentTypes(sourceViewer); + Map prefixesMap= new HashMap(types.length); + for (int i= 0; i < types.length; i++) { + String type= types[i]; + String[] prefixes= configuration.getDefaultPrefixes(sourceViewer, type); + if (prefixes != null && prefixes.length > 0) { + int emptyPrefixes= 0; + for (int j= 0; j < prefixes.length; j++) + if (prefixes[j].length() == 0) + emptyPrefixes++; + + if (emptyPrefixes > 0) { + String[] nonemptyPrefixes= new String[prefixes.length - emptyPrefixes]; + for (int j= 0, k= 0; j < prefixes.length; j++) { + String prefix= prefixes[j]; + if (prefix.length() != 0) { + nonemptyPrefixes[k]= prefix; + k++; + } + } + prefixes= nonemptyPrefixes; + } + + prefixesMap.put(type, prefixes); + } + } + fDocumentPartitioning= configuration.getConfiguredDocumentPartitioning(sourceViewer); + fPrefixesMap= prefixesMap; + } }