blob: 6f4c00952a7375eb841664d04aa6a693985d384b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 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 org.eclipse.jdt.internal.ui.text.javadoc;
import java.text.BreakIterator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DefaultAutoIndentStrategy;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditorExtension3;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.CodeGeneration;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Strings;
import org.eclipse.jdt.internal.corext.util.SuperTypeHierarchyCache;
import org.eclipse.jdt.internal.ui.JavaPlugin;
/**
* Auto indent strategy for java doc comments
*/
public class JavaDocAutoIndentStrategy extends DefaultAutoIndentStrategy {
public JavaDocAutoIndentStrategy() {
}
private static String getLineDelimiter(IDocument document) {
try {
if (document.getNumberOfLines() > 1)
return document.getLineDelimiter(0);
} catch (BadLocationException e) {
JavaPlugin.log(e);
}
return System.getProperty("line.separator"); //$NON-NLS-1$
}
/**
* Copies the indentation of the previous line and add a star.
* If the javadoc just started on this line add standard method tags
* and close the javadoc.
*
* @param d the document to work on
* @param c the command to deal with
*/
private void jdocIndentAfterNewLine(IDocument d, DocumentCommand c) {
if (c.offset == -1 || d.getLength() == 0)
return;
try {
// find start of line
int p= (c.offset == d.getLength() ? c.offset - 1 : c.offset);
IRegion info= d.getLineInformationOfOffset(p);
int start= info.getOffset();
// find white spaces
int end= findEndOfWhiteSpace(d, start, c.offset);
StringBuffer buf= new StringBuffer(c.text);
if (end >= start) { // 1GEYL1R: ITPJUI:ALL - java doc edit smartness not work for class comments
// append to input
String indentation= jdocExtractLinePrefix(d, d.getLineOfOffset(c.offset));
buf.append(indentation);
if (end < c.offset) {
if (d.getChar(end) == '/') {
// javadoc started on this line
buf.append(" * "); //$NON-NLS-1$
if (JavaPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CLOSE_JAVADOCS) &&
isNewComment(d, c.offset))
{
String lineDelimiter= getLineDelimiter(d);
c.doit= false;
d.replace(c.offset, 0, lineDelimiter + indentation + " */"); //$NON-NLS-1$
// evaluate method signature
ICompilationUnit unit= getCompilationUnit();
if (JavaPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS) &&
unit != null)
{
try {
unit.reconcile();
String string= createJavaDocTags(d, c, indentation, lineDelimiter, unit);
if (string != null)
d.replace(c.offset, 0, string);
} catch (CoreException e) {
// ignore
}
}
}
}
}
}
c.text= buf.toString();
} catch (BadLocationException excp) {
// stop work
}
}
private String createJavaDocTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, ICompilationUnit unit)
throws CoreException, BadLocationException
{
IJavaElement element= unit.getElementAt(command.offset);
if (element == null)
return null;
switch (element.getElementType()) {
case IJavaElement.TYPE:
return createTypeTags(document, command, indentation, lineDelimiter, (IType) element);
case IJavaElement.METHOD:
return createMethodTags(document, command, indentation, lineDelimiter, (IMethod) element);
default:
return null;
}
}
/*
* Removes start and end of a comment and corrects indentation and line delimiters.
*/
private String prepareTemplateComment(String comment, String indentation, String lineDelimiter) {
// trim comment start and end if any
if (comment.endsWith("*/")) //$NON-NLS-1$
comment= comment.substring(0, comment.length() - 2);
comment= comment.trim();
if (comment.startsWith("/*")) { //$NON-NLS-1$
if (comment.length() > 2 && comment.charAt(2) == '*') {
comment= comment.substring(3); // remove '/**'
} else {
comment= comment.substring(2); // remove '/*'
}
}
return Strings.changeIndent(comment, 0, CodeFormatterUtil.getTabWidth(), indentation, lineDelimiter);
}
private String createTypeTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, IType type)
throws CoreException
{
String comment= CodeGeneration.getTypeComment(type.getCompilationUnit(), type.getTypeQualifiedName('.'), lineDelimiter);
if (comment != null) {
return prepareTemplateComment(comment.trim(), indentation, lineDelimiter);
}
return null;
}
private String createMethodTags(IDocument document, DocumentCommand command, String indentation, String lineDelimiter, IMethod method)
throws CoreException, BadLocationException
{
IRegion partition= document.getPartition(command.offset);
ISourceRange sourceRange= method.getSourceRange();
if (sourceRange == null || sourceRange.getOffset() != partition.getOffset())
return null;
IMethod inheritedMethod= getInheritedMethod(method);
String comment= CodeGeneration.getMethodComment(method, inheritedMethod, lineDelimiter);
if (comment != null) {
comment= comment.trim();
boolean javadocComment= comment.startsWith("/**"); //$NON-NLS-1$
boolean isJavaDoc= partition.getLength() >= 3 && document.get(partition.getOffset(), 3).equals("/**"); //$NON-NLS-1$
if (javadocComment == isJavaDoc) {
return prepareTemplateComment(comment, indentation, lineDelimiter);
}
}
return null;
}
/**
* Returns the method inherited from, <code>null</code> if method is newly defined.
*/
private static IMethod getInheritedMethod(IMethod method) throws JavaModelException {
IType declaringType= method.getDeclaringType();
ITypeHierarchy typeHierarchy= SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
return JavaModelUtil.findMethodDeclarationInHierarchy(typeHierarchy, declaringType,
method.getElementName(), method.getParameterTypes(), method.isConstructor());
}
protected void jdocIndentForCommentEnd(IDocument d, DocumentCommand c) {
if (c.offset < 2 || d.getLength() == 0) {
return;
}
try {
if ("* ".equals(d.get(c.offset - 2, 2))) { //$NON-NLS-1$
// modify document command
c.length++;
c.offset--;
}
} catch (BadLocationException excp) {
// stop work
}
}
/**
* Guesses if the command operates within a newly created javadoc comment or not.
* If in doubt, it will assume that the javadoc is new.
*/
private static boolean isNewComment(IDocument document, int commandOffset) {
try {
int lineIndex= document.getLineOfOffset(commandOffset) + 1;
if (lineIndex >= document.getNumberOfLines())
return true;
IRegion line= document.getLineInformation(lineIndex);
ITypedRegion partition= document.getPartition(commandOffset);
if (document.getLineOffset(lineIndex) >= partition.getOffset() + partition.getLength())
return false;
String string= document.get(line.getOffset(), line.getLength());
if (!string.trim().startsWith("*")) //$NON-NLS-1$
return true;
return false;
} catch (BadLocationException e) {
return false;
}
}
private boolean isSmartMode() {
IWorkbenchPage page= JavaPlugin.getActivePage();
if (page != null) {
IEditorPart part= page.getActiveEditor();
if (part instanceof ITextEditorExtension3) {
ITextEditorExtension3 extension= (ITextEditorExtension3) part;
return extension.getInsertMode() == ITextEditorExtension3.SMART_INSERT;
}
}
return false;
}
/*
* @see IAutoIndentStrategy#customizeDocumentCommand
*/
public void customizeDocumentCommand(IDocument document, DocumentCommand command) {
if (!isSmartMode())
return;
try {
if (command.text != null && command.length == 0) {
String[] lineDelimiters= document.getLegalLineDelimiters();
int index= TextUtilities.endsWith(lineDelimiters, command.text);
if (index > -1) {
// ends with line delimiter
if (lineDelimiters[index].equals(command.text))
// just the line delimiter
jdocIndentAfterNewLine(document, command);
return;
}
}
if (command.text != null && command.text.equals("/")) { //$NON-NLS-1$
jdocIndentForCommentEnd(document, command);
return;
}
ITypedRegion partition= document.getPartition(command.offset);
int partitionStart= partition.getOffset();
int partitionEnd= partition.getLength() + partitionStart;
String text= command.text;
int offset= command.offset;
int length= command.length;
// partition change
final int PREFIX_LENGTH= "/*".length(); //$NON-NLS-1$
final int POSTFIX_LENGTH= "*/".length(); //$NON-NLS-1$
if ((offset < partitionStart + PREFIX_LENGTH || offset + length > partitionEnd - POSTFIX_LENGTH) ||
text != null && text.length() >= 2 && ((text.indexOf("*/") != -1) || (document.getChar(offset) == '*' && text.startsWith("/")))) //$NON-NLS-1$ //$NON-NLS-2$
return;
if (command.text == null || command.text.length() == 0)
jdocHandleBackspaceDelete(document, command);
else if (command.text != null && command.length == 0 && command.text.length() > 0)
jdocWrapParagraphOnInsert(document, command);
} catch (BadLocationException e) {
JavaPlugin.log(e);
}
}
private void flushCommand(IDocument document, DocumentCommand command) throws BadLocationException {
if (!command.doit)
return;
document.replace(command.offset, command.length, command.text);
command.doit= false;
if (command.text != null)
command.offset += command.text.length();
command.length= 0;
command.text= null;
}
protected void jdocWrapParagraphOnInsert(IDocument document, DocumentCommand command) throws BadLocationException {
// Assert.isTrue(command.length == 0);
// Assert.isTrue(command.text != null && command.text.length() == 1);
if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
return;
int line= document.getLineOfOffset(command.offset);
IRegion region= document.getLineInformation(line);
int lineOffset= region.getOffset();
int lineLength= region.getLength();
String lineContents= document.get(lineOffset, lineLength);
StringBuffer buffer= new StringBuffer(lineContents);
int start= command.offset - lineOffset;
int end= command.length + start;
buffer.replace(start, end, command.text);
// handle whitespace
if (command.text != null && command.text.length() != 0 && command.text.trim().length() == 0) {
String endOfLine= document.get(command.offset, lineOffset + lineLength - command.offset);
// end of line
if (endOfLine.length() == 0) {
// move caret to next line
flushCommand(document, command);
if (isLineTooShort(document, line)) {
int[] caretOffset= {command.offset};
jdocWrapParagraphFromLine(document, line, caretOffset, false);
command.offset= caretOffset[0];
return;
}
// move caret to next line if possible
if (line < document.getNumberOfLines() - 1 && isJavaDocLine(document, line + 1)) {
String lineDelimiter= document.getLineDelimiter(line);
String nextLinePrefix= jdocExtractLinePrefix(document, line + 1);
command.offset += lineDelimiter.length() + nextLinePrefix.length();
}
return;
// inside whitespace at end of line
} else if (endOfLine.trim().length() == 0) {
// simply insert space
return;
}
}
// change in prefix region
String prefix= jdocExtractLinePrefix(document, line);
boolean wrapAlways= command.offset >= lineOffset && command.offset <= lineOffset + prefix.length();
// must insert the text now because it may include whitepace
flushCommand(document, command);
if (wrapAlways || calculateDisplayedWidth(buffer.toString()) > getMargin() || isLineTooShort(document, line)) {
int[] caretOffset= {command.offset};
jdocWrapParagraphFromLine(document, line, caretOffset, wrapAlways);
if (!wrapAlways)
command.offset= caretOffset[0];
}
}
/**
* Method jdocWrapParagraphFromLine.
*
* @param document
* @param line
* @param always
*/
private void jdocWrapParagraphFromLine(IDocument document, int line, int[] caretOffset, boolean always) throws BadLocationException {
String indent= jdocExtractLinePrefix(document, line);
if (!always) {
if (!indent.trim().startsWith("*")) //$NON-NLS-1$
return;
if (indent.trim().startsWith("*/")) //$NON-NLS-1$
return;
if (!isLineTooLong(document, line) && !isLineTooShort(document, line))
return;
}
boolean caretRelativeToParagraphOffset= false;
int caret= caretOffset[0];
int caretLine= document.getLineOfOffset(caret);
int lineOffset= document.getLineOffset(line);
int paragraphOffset= lineOffset + indent.length();
if (paragraphOffset < caret) {
caret -= paragraphOffset;
caretRelativeToParagraphOffset= true;
} else {
caret -= lineOffset;
}
StringBuffer buffer= new StringBuffer();
int currentLine= line;
while (line == currentLine || isJavaDocLine(document, currentLine)) {
if (buffer.length() != 0 && !Character.isWhitespace(buffer.charAt(buffer.length() - 1))) {
buffer.append(' ');
if (currentLine <= caretLine) {
// in this case caretRelativeToParagraphOffset is always true
++caret;
}
}
String string= getLineContents(document, currentLine);
buffer.append(string);
currentLine++;
}
String paragraph= buffer.toString();
if (paragraph.trim().length() == 0)
return;
caretOffset[0]= caretRelativeToParagraphOffset ? caret : 0;
String delimiter= document.getLineDelimiter(0);
String wrapped= formatParagraph(paragraph, caretOffset, indent, delimiter, getMargin());
int beginning= document.getLineOffset(line);
int end= document.getLineOffset(currentLine);
document.replace(beginning, end - beginning, wrapped.toString());
caretOffset[0]= caretRelativeToParagraphOffset ? caretOffset[0] + beginning : caret + beginning;
}
/**
* Line break iterator to handle whitespaces as first class citizens.
*/
private static class LineBreakIterator {
private final String fString;
private final BreakIterator fIterator= BreakIterator.getLineInstance();
private int fStart;
private int fEnd;
private int fBufferedEnd;
public LineBreakIterator(String string) {
fString= string;
fIterator.setText(string);
}
public int first() {
fBufferedEnd= -1;
fStart= fIterator.first();
return fStart;
}
public int next() {
if (fBufferedEnd != -1) {
fStart= fEnd;
fEnd= fBufferedEnd;
fBufferedEnd= -1;
return fEnd;
}
fStart= fEnd;
fEnd= fIterator.next();
if (fEnd == BreakIterator.DONE)
return fEnd;
final String string= fString.substring(fStart, fEnd);
// whitespace
if (string.trim().length() == 0)
return fEnd;
final String word= string.trim();
if (word.length() == string.length())
return fEnd;
// suspected whitespace
fBufferedEnd= fEnd;
return fStart + word.length();
}
};
/**
* Formats a paragraph, using break iterator.
*
* @param offset an offset within the paragraph, which will be updated with respect to formatting.
*/
private static String formatParagraph(String paragraph, int[] offset, String prefix, String lineDelimiter, int margin) {
LineBreakIterator iterator= new LineBreakIterator(paragraph);
StringBuffer paragraphBuffer= new StringBuffer();
StringBuffer lineBuffer= new StringBuffer();
StringBuffer whiteSpaceBuffer= new StringBuffer();
int index= offset[0];
int indexBuffer= -1;
// line delimiter could be null
if (lineDelimiter == null)
lineDelimiter= ""; //$NON-NLS-1$
for (int start= iterator.first(), end= iterator.next(); end != BreakIterator.DONE; start= end, end= iterator.next()) {
String word= paragraph.substring(start, end);
// word is whitespace
if (word.trim().length() == 0) {
whiteSpaceBuffer.append(word);
// first word of line is always appended
} else if (lineBuffer.length() == 0) {
lineBuffer.append(prefix);
lineBuffer.append(whiteSpaceBuffer.toString());
lineBuffer.append(word);
} else {
String line= lineBuffer.toString() + whiteSpaceBuffer.toString() + word.toString();
// margin exceeded
if (calculateDisplayedWidth(line) > margin) {
// flush line buffer and wrap paragraph
paragraphBuffer.append(lineBuffer.toString());
paragraphBuffer.append(lineDelimiter);
lineBuffer.setLength(0);
lineBuffer.append(prefix);
lineBuffer.append(word);
// flush index buffer
if (indexBuffer != -1) {
offset[0]= indexBuffer;
// correct for caret in whitespace at the end of line
if (whiteSpaceBuffer.length() != 0 && index < start && index >= start - whiteSpaceBuffer.length())
offset[0] -= (index - (start - whiteSpaceBuffer.length()));
indexBuffer= -1;
}
whiteSpaceBuffer.setLength(0);
// margin not exceeded
} else {
lineBuffer.append(whiteSpaceBuffer.toString());
lineBuffer.append(word);
whiteSpaceBuffer.setLength(0);
}
}
if (index >= start && index < end) {
indexBuffer= paragraphBuffer.length() + lineBuffer.length() + (index - start);
if (word.trim().length() != 0)
indexBuffer -= word.length();
}
}
// flush line buffer
paragraphBuffer.append(lineBuffer.toString());
paragraphBuffer.append(lineDelimiter);
// flush index buffer
if (indexBuffer != -1)
offset[0]= indexBuffer;
// last position is not returned by break iterator
else if (offset[0] == paragraph.length())
offset[0]= paragraphBuffer.length() - lineDelimiter.length();
return paragraphBuffer.toString();
}
private static IPreferenceStore getPreferenceStore() {
return JavaPlugin.getDefault().getPreferenceStore();
}
/**
* Returns the displayed width of a string, taking in account the displayed tab width.
* The result can be compared against the print margin.
*/
private static int calculateDisplayedWidth(String string) {
final int tabWidth= getPreferenceStore().getInt(PreferenceConstants.EDITOR_TAB_WIDTH);
int column= 0;
for (int i= 0; i < string.length(); i++)
if ('\t' == string.charAt(i))
column += tabWidth - (column % tabWidth);
else
column++;
return column;
}
private String jdocExtractLinePrefix(IDocument d, int line) throws BadLocationException {
IRegion region= d.getLineInformation(line);
int lineOffset= region.getOffset();
int index= findEndOfWhiteSpace(d, lineOffset, lineOffset + d.getLineLength(line));
if (d.getChar(index) == '*') {
index++;
if (index != lineOffset + region.getLength() &&d.getChar(index) == ' ')
index++;
}
return d.get(lineOffset, index - lineOffset);
}
private String getLineContents(IDocument d, int line) throws BadLocationException {
int offset = d.getLineOffset(line);
int length = d.getLineLength(line);
String lineDelimiter= d.getLineDelimiter(line);
if (lineDelimiter != null)
length= length - lineDelimiter.length();
String lineContents = d.get(offset, length);
int trim = jdocExtractLinePrefix(d, line).length();
return lineContents.substring(trim);
}
private static String getLine(IDocument document, int line) throws BadLocationException {
IRegion region= document.getLineInformation(line);
return document.get(region.getOffset(), region.getLength());
}
/**
* Returns <code>true</code> if the javadoc line is too short, <code>false</code> otherwise.
*/
private boolean isLineTooShort(IDocument document, int line) throws BadLocationException {
if (!isJavaDocLine(document, line + 1))
return false;
String nextLine= getLineContents(document, line + 1);
if (nextLine.trim().length() == 0)
return false;
return true;
}
/**
* Returns <code>true</code> if the line is too long, <code>false</code> otherwise.
*/
private boolean isLineTooLong(IDocument document, int line) throws BadLocationException {
String lineContents= getLine(document, line);
return calculateDisplayedWidth(lineContents) > getMargin();
}
private static int getMargin() {
return getPreferenceStore().getInt(PreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN);
}
private static final String[] fgInlineTags= {
"<b>", "<i>", "<em>", "<strong>", "<code>" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
};
private boolean isInlineTag(String string) {
for (int i= 0; i < fgInlineTags.length; i++)
if (string.startsWith(fgInlineTags[i]))
return true;
return false;
}
/**
* returns true if the specified line is part of a paragraph and should be merged with
* the previous line.
*/
private boolean isJavaDocLine(IDocument document, int line) throws BadLocationException {
if (document.getNumberOfLines() < line)
return false;
int offset= document.getLineOffset(line);
int length= document.getLineLength(line);
int firstChar= findEndOfWhiteSpace(document, offset, offset + length);
length -= firstChar - offset;
String lineContents= document.get(firstChar, length);
String prefix= lineContents.trim();
if (!prefix.startsWith("*") || prefix.startsWith("*/")) //$NON-NLS-1$ //$NON-NLS-2$
return false;
lineContents= lineContents.substring(1).trim().toLowerCase();
// preserve empty lines
if (lineContents.length() == 0)
return false;
// preserve @TAGS
if (lineContents.startsWith("@")) //$NON-NLS-1$
return false;
// preserve HTML tags which are not inline
if (lineContents.startsWith("<") && !isInlineTag(lineContents)) //$NON-NLS-1$
return false;
return true;
}
protected void jdocHandleBackspaceDelete(IDocument document, DocumentCommand c) {
if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FORMAT_JAVADOCS))
return;
try {
String text= document.get(c.offset, c.length);
int line= document.getLineOfOffset(c.offset);
int lineOffset= document.getLineOffset(line);
// erase line delimiter
String lineDelimiter= document.getLineDelimiter(line);
if (lineDelimiter != null && lineDelimiter.equals(text)) {
String prefix= jdocExtractLinePrefix(document, line + 1);
// strip prefix if any
if (prefix.length() > 0) {
int length= document.getLineDelimiter(line).length() + prefix.length();
document.replace(c.offset, length, null);
c.doit= false;
c.length= 0;
return;
}
// backspace: beginning of a javadoc line
} else if (document.getChar(c.offset - 1) == '*' && jdocExtractLinePrefix(document, line).length() - 1 >= c.offset - lineOffset) {
lineDelimiter= document.getLineDelimiter(line - 1);
String prefix= jdocExtractLinePrefix(document, line);
int length= (lineDelimiter != null ? lineDelimiter.length() : 0) + prefix.length();
document.replace(c.offset - length + 1, length, null);
c.doit= false;
c.offset -= length - 1;
c.length= 0;
return;
} else {
document.replace(c.offset, c.length, null);
c.doit= false;
c.length= 0;
}
} catch (BadLocationException e) {
JavaPlugin.log(e);
}
try {
int line= document.getLineOfOffset(c.offset);
int lineOffset= document.getLineOffset(line);
String prefix= jdocExtractLinePrefix(document, line);
boolean always= c.offset > lineOffset && c.offset <= lineOffset + prefix.length();
int[] caretOffset= {c.offset};
jdocWrapParagraphFromLine(document, document.getLineOfOffset(c.offset), caretOffset, always);
c.offset= caretOffset[0];
} catch (BadLocationException e) {
JavaPlugin.log(e);
}
}
/**
* Returns the compilation unit of the CompilationUnitEditor invoking the AutoIndentStrategy,
* might return <code>null</code> on error.
*/
private static ICompilationUnit getCompilationUnit() {
IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window == null)
return null;
IWorkbenchPage page= window.getActivePage();
if (page == null)
return null;
IEditorPart editor= page.getActiveEditor();
if (editor == null)
return null;
IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager();
ICompilationUnit unit= manager.getWorkingCopy(editor.getEditorInput());
if (unit == null)
return null;
return unit;
}
}