X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/IndentAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/IndentAction.java deleted file mode 100644 index ce26e9b..0000000 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/IndentAction.java +++ /dev/null @@ -1,564 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2004 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package net.sourceforge.phpdt.internal.ui.actions; - -import java.util.ResourceBundle; - -import net.sourceforge.phpdt.core.JavaCore; -import net.sourceforge.phpdt.core.formatter.DefaultCodeFormatterConstants; -import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions; -import net.sourceforge.phpdt.internal.ui.text.JavaHeuristicScanner; -import net.sourceforge.phpdt.internal.ui.text.JavaIndenter; -import net.sourceforge.phpdt.internal.ui.text.SmartBackspaceManager; -import net.sourceforge.phpdt.internal.ui.text.SmartBackspaceManager.UndoSpec; -import net.sourceforge.phpdt.internal.ui.text.phpdoc.JavaDocAutoIndentStrategy; -import net.sourceforge.phpdt.ui.PreferenceConstants; -import net.sourceforge.phpeclipse.PHPeclipsePlugin; -import net.sourceforge.phpeclipse.phpeditor.PHPEditor; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.text.Assert; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentCommand; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.IRewriteTarget; -import org.eclipse.jface.text.ITextSelection; -import org.eclipse.jface.text.ITypedRegion; -import org.eclipse.jface.text.Position; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.TextSelection; -import org.eclipse.jface.text.TextUtilities; -import org.eclipse.jface.text.source.ISourceViewer; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.swt.custom.BusyIndicator; -import org.eclipse.swt.widgets.Display; -import org.eclipse.text.edits.MalformedTreeException; -import org.eclipse.text.edits.ReplaceEdit; -import org.eclipse.text.edits.TextEdit; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.ui.texteditor.ITextEditor; -import org.eclipse.ui.texteditor.ITextEditorExtension3; -import org.eclipse.ui.texteditor.TextEditorAction; - -/** - * Indents a line or range of lines in a Java document to its correct position. - * No complete AST must be present, the indentation is computed using - * heuristics. The algorith used is fast for single lines, but does not store - * any information and therefore not so efficient for large line ranges. - * - * @see net.sourceforge.phpdt.internal.ui.text.JavaHeuristicScanner - * @see net.sourceforge.phpdt.internal.ui.text.JavaIndenter - * @since 3.0 - */ -public class IndentAction extends TextEditorAction { - - /** The caret offset after an indent operation. */ - private int fCaretOffset; - - /** - * Whether this is the action invoked by TAB. When true, - * indentation behaves differently to accomodate normal TAB operation. - */ - private final boolean fIsTabAction; - - /** - * Creates a new instance. - * - * @param bundle - * the resource bundle - * @param prefix - * the prefix to use for keys in bundle - * @param editor - * the text editor - * @param isTabAction - * whether the action should insert tabs if over the indentation - */ - public IndentAction(ResourceBundle bundle, String prefix, - ITextEditor editor, boolean isTabAction) { - super(bundle, prefix, editor); - fIsTabAction = isTabAction; - } - - /* - * @see org.eclipse.jface.action.Action#run() - */ - public void run() { - // update has been called by the framework - if (!isEnabled() || !validateEditorInputState()) - return; - - ITextSelection selection = getSelection(); - final IDocument document = getDocument(); - - if (document != null) { - - final int offset = selection.getOffset(); - final int length = selection.getLength(); - final Position end = new Position(offset + length); - final int firstLine, nLines; - fCaretOffset = -1; - - try { - document.addPosition(end); - firstLine = document.getLineOfOffset(offset); - // check for marginal (zero-length) lines - int minusOne = length == 0 ? 0 : 1; - nLines = document.getLineOfOffset(offset + length - minusOne) - - firstLine + 1; - } catch (BadLocationException e) { - // will only happen on concurrent modification - PHPeclipsePlugin.log(new Status(IStatus.ERROR, PHPeclipsePlugin - .getPluginId(), IStatus.OK, "", e)); //$NON-NLS-1$ - return; - } - - Runnable runnable = new Runnable() { - public void run() { - IRewriteTarget target = (IRewriteTarget) getTextEditor() - .getAdapter(IRewriteTarget.class); - if (target != null) { - target.beginCompoundChange(); - target.setRedraw(false); - } - - try { - JavaHeuristicScanner scanner = new JavaHeuristicScanner( - document); - JavaIndenter indenter = new JavaIndenter(document, - scanner); - boolean hasChanged = false; - for (int i = 0; i < nLines; i++) { - hasChanged |= indentLine(document, firstLine + i, - offset, indenter, scanner); - } - - // update caret position: move to new position when - // indenting just one line - // keep selection when indenting multiple - int newOffset, newLength; - if (fIsTabAction) { - newOffset = fCaretOffset; - newLength = 0; - } else if (nLines > 1) { - newOffset = offset; - newLength = end.getOffset() - offset; - } else { - newOffset = fCaretOffset; - newLength = 0; - } - - // always reset the selection if anything was replaced - // but not when we had a singleline nontab invocation - if (newOffset != -1 - && (hasChanged || newOffset != offset || newLength != length)) - selectAndReveal(newOffset, newLength); - - document.removePosition(end); - } catch (BadLocationException e) { - // will only happen on concurrent modification - PHPeclipsePlugin.log(new Status(IStatus.ERROR, - PHPeclipsePlugin.getPluginId(), IStatus.OK, - "ConcurrentModification in IndentAction", e)); //$NON-NLS-1$ - - } finally { - - if (target != null) { - target.endCompoundChange(); - target.setRedraw(true); - } - } - } - }; - - if (nLines > 50) { - Display display = getTextEditor().getEditorSite() - .getWorkbenchWindow().getShell().getDisplay(); - BusyIndicator.showWhile(display, runnable); - } else - runnable.run(); - - } - } - - /** - * Selects the given range on the editor. - * - * @param newOffset - * the selection offset - * @param newLength - * the selection range - */ - private void selectAndReveal(int newOffset, int newLength) { - Assert.isTrue(newOffset >= 0); - Assert.isTrue(newLength >= 0); - ITextEditor editor = getTextEditor(); - if (editor instanceof PHPEditor) { - ISourceViewer viewer = ((PHPEditor) editor).getViewer(); - if (viewer != null) - viewer.setSelectedRange(newOffset, newLength); - } else - // this is too intrusive, but will never get called anyway - getTextEditor().selectAndReveal(newOffset, newLength); - - } - - /** - * Indents a single line using the java heuristic scanner. Javadoc and - * multiline comments are indented as specified by the - * JavaDocAutoIndentStrategy. - * - * @param document - * the document - * @param line - * the line to be indented - * @param caret - * the caret position - * @param indenter - * the java indenter - * @param scanner - * the heuristic scanner - * @return true if document was modified, - * false otherwise - * @throws BadLocationException - * if the document got changed concurrently - */ - private boolean indentLine(IDocument document, int line, int caret, - JavaIndenter indenter, JavaHeuristicScanner scanner) - throws BadLocationException { - IRegion currentLine = document.getLineInformation(line); - int offset = currentLine.getOffset(); - int wsStart = offset; // where we start searching for non-WS; after - // the "//" in single line comments - - String indent = null; - if (offset < document.getLength()) { - ITypedRegion partition = TextUtilities.getPartition(document, - IPHPPartitions.PHP_PARTITIONING, offset, true); - String type = partition.getType(); - if (type.equals(IPHPPartitions.PHP_PHPDOC_COMMENT) - || type.equals(IPHPPartitions.PHP_MULTILINE_COMMENT)) { - - // TODO this is a hack - // what I want to do - // new JavaDocAutoIndentStrategy().indentLineAtOffset(document, - // offset); - // return; - - int start = 0; - if (line > 0) { - - IRegion previousLine = document - .getLineInformation(line - 1); - start = previousLine.getOffset() + previousLine.getLength(); - } - - DocumentCommand command = new DocumentCommand() { - }; - command.text = "\n"; //$NON-NLS-1$ - command.offset = start; - new JavaDocAutoIndentStrategy(IPHPPartitions.PHP_PARTITIONING) - .customizeDocumentCommand(document, command); - int to = 1; - while (to < command.text.length() - && Character.isWhitespace(command.text.charAt(to))) - to++; - indent = command.text.substring(1, to); - -// omit Java style -// } else if (!fIsTabAction && partition.getOffset() == offset -// && type.equals(IPHPPartitions.PHP_SINGLELINE_COMMENT)) { -// -// // line comment starting at position 0 -> indent inside -// int slashes = 2; -// while (slashes < document.getLength() - 1 -// && document.get(offset + slashes, 2).equals("//")) //$NON-NLS-1$ -// slashes += 2; -// -// wsStart = offset + slashes; -// -// StringBuffer computed = indenter.computeIndentation(offset); -// int tabSize = PHPeclipsePlugin -// .getDefault() -// .getPreferenceStore() -// .getInt( -// AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); -// while (slashes > 0 && computed.length() > 0) { -// char c = computed.charAt(0); -// if (c == '\t') -// if (slashes > tabSize) -// slashes -= tabSize; -// else -// break; -// else if (c == ' ') -// slashes--; -// else -// break; -// -// computed.deleteCharAt(0); -// } -// -// indent = document.get(offset, wsStart - offset) + computed; - - } - } - - // standard java indentation - if (indent == null) { - StringBuffer computed = indenter.computeIndentation(offset); - if (computed != null) - indent = computed.toString(); - else - //indent = new String(); - return true; // prevent affecting html part - } - - // change document: - // get current white space - int lineLength = currentLine.getLength(); - int end = scanner.findNonWhitespaceForwardInAnyPartition(wsStart, - offset + lineLength); - if (end == JavaHeuristicScanner.NOT_FOUND) - end = offset + lineLength; - int length = end - offset; - 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. - if (fIsTabAction && caret == end - && whiteSpaceLength(currentIndent) >= whiteSpaceLength(indent)) { - String tab = getTabEquivalent(); - document.replace(caret, 0, tab); - fCaretOffset = caret + tab.length(); - return true; - } - - // set the caret offset so it can be used when setting the selection - if (caret >= offset && caret <= end) - fCaretOffset = offset + indent.length(); - else - fCaretOffset = -1; - - // only change the document if it is a real change - if (!indent.equals(currentIndent)) { - String deletedText = document.get(offset, length); - document.replace(offset, length, indent); - - if (fIsTabAction - && indent.length() > currentIndent.length() - && PHPeclipsePlugin.getDefault().getPreferenceStore() - .getBoolean( - PreferenceConstants.EDITOR_SMART_BACKSPACE)) { - ITextEditor editor = getTextEditor(); - if (editor != null) { - final SmartBackspaceManager manager = (SmartBackspaceManager) editor - .getAdapter(SmartBackspaceManager.class); - if (manager != null) { - try { - // restore smart portion - ReplaceEdit smart = new ReplaceEdit(offset, indent - .length(), deletedText); - - final UndoSpec spec = new UndoSpec(offset - + indent.length(), new Region(caret, 0), - new TextEdit[] { smart }, 2, null); - manager.register(spec); - } catch (MalformedTreeException e) { - // log & ignore - PHPeclipsePlugin.log(new Status(IStatus.ERROR, - PHPeclipsePlugin.getPluginId(), IStatus.OK, - "Illegal smart backspace action", e)); //$NON-NLS-1$ - } - } - } - } - - return true; - } else - return false; - } - - /** - * Returns the size in characters of a string. All characters count one, - * tabs count the editor's preference for the tab display - * - * @param indent - * the string to be measured. - * @return - */ - private int whiteSpaceLength(String indent) { - if (indent == null) - return 0; - else { - int size = 0; - int l = indent.length(); - int tabSize = PHPeclipsePlugin - .getDefault() - .getPreferenceStore() - .getInt( - AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); - - for (int i = 0; i < l; i++) - size += indent.charAt(i) == '\t' ? tabSize : 1; - return size; - } - } - - /** - * Returns a tab equivalent, either as a tab character or as spaces, - * depending on the editor and formatter preferences. - * - * @return a string representing one tab in the editor, never - * null - */ - private String getTabEquivalent() { - String tab; - if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean( - PreferenceConstants.EDITOR_SPACES_FOR_TABS)) { - int size = JavaCore.getPlugin().getPluginPreferences().getInt( - DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE); - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < size; i++) - buf.append(' '); - tab = buf.toString(); - } else - tab = "\t"; //$NON-NLS-1$ - - return tab; - } - - /** - * Returns the editor's selection provider. - * - * @return the editor's selection provider or null - */ - private ISelectionProvider getSelectionProvider() { - ITextEditor editor = getTextEditor(); - if (editor != null) { - return editor.getSelectionProvider(); - } - return null; - } - - /* - * @see org.eclipse.ui.texteditor.IUpdate#update() - */ - public void update() { - super.update(); - - if (isEnabled()) - if (fIsTabAction) - setEnabled(canModifyEditor() && isSmartMode() - && isValidSelection()); - else - setEnabled(canModifyEditor() && !getSelection().isEmpty()); - } - - /** - * Returns if the current selection is valid, i.e. whether it is empty and - * the caret in the whitespace at the start of a line, or covers multiple - * lines. - * - * @return true if the selection is valid for an indent - * operation - */ - private boolean isValidSelection() { - ITextSelection selection = getSelection(); - if (selection.isEmpty()) - return false; - - int offset = selection.getOffset(); - int length = selection.getLength(); - - IDocument document = getDocument(); - if (document == null) - return false; - - try { - IRegion firstLine = document.getLineInformationOfOffset(offset); - int lineOffset = firstLine.getOffset(); - - // either the selection has to be empty and the caret in the WS at - // the line start - // or the selection has to extend over multiple lines - if (length == 0) - return document.get(lineOffset, offset - lineOffset).trim() - .length() == 0; - else - // return lineOffset + firstLine.getLength() < offset + length; - return false; // only enable for empty selections for now - - } catch (BadLocationException e) { - } - - return false; - } - - /** - * Returns the smart preference state. - * - * @return true if smart mode is on, false - * otherwise - */ - private boolean isSmartMode() { - ITextEditor editor = getTextEditor(); - - if (editor instanceof ITextEditorExtension3) - return ((ITextEditorExtension3) editor).getInsertMode() == ITextEditorExtension3.SMART_INSERT; - - return false; - } - - /** - * Returns the document currently displayed in the editor, or - * null if none can be obtained. - * - * @return the current document or null - */ - private IDocument getDocument() { - - ITextEditor editor = getTextEditor(); - if (editor != null) { - - IDocumentProvider provider = editor.getDocumentProvider(); - IEditorInput input = editor.getEditorInput(); - if (provider != null && input != null) - return provider.getDocument(input); - - } - return null; - } - - /** - * Returns the selection on the editor or an invalid selection if none can - * be obtained. Returns never null. - * - * @return the current selection, never null - */ - private ITextSelection getSelection() { - ISelectionProvider provider = getSelectionProvider(); - if (provider != null) { - - ISelection selection = provider.getSelection(); - if (selection instanceof ITextSelection) - return (ITextSelection) selection; - } - - // null object - return TextSelection.emptySelection(); - } - -}