/*******************************************************************************
* Copyright (c) 2009 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.ui.autoEdit;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.internal.core.util.MethodOverrideTester;
import org.eclipse.dltk.ui.IWorkingCopyManager;
import org.eclipse.jface.text.*;
import org.eclipse.jface.text.IRegion;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.internal.core.documentModel.parser.regions.IPhpScriptRegion;
import org.eclipse.php.internal.core.documentModel.parser.regions.PHPRegionTypes;
import org.eclipse.php.internal.core.documentModel.partitioner.PHPPartitionTypes;
import org.eclipse.php.internal.core.format.FormatterUtils;
import org.eclipse.php.internal.ui.Logger;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.corext.util.SuperTypeHierarchyCache;
import org.eclipse.php.ui.CodeGeneration;
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.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer;
/**
* TODO : move this auto strategy to DLTK? Auto indent strategy for Script doc
* comments.
*/
public class PhpDocAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
private static final String PHPDOC_COMMENT_BLOCK_START = "/**"; //$NON-NLS-1$
private static final String PHP_COMMENT_BLOCK_START = "/*"; //$NON-NLS-1$
private static final String PHP_COMMENT_BLOCK_MID = " *"; //$NON-NLS-1$
private static final String PHP_COMMENT_BLOCK_END = " */"; //$NON-NLS-1$
/** The partitioning that this strategy operates on. */
private final String fPartitioning;
/**
* Creates a new Scriptdoc auto indent strategy for the given document
* partitioning.
*
* @param partitioning
* the document partitioning
*/
public PhpDocAutoIndentStrategy(String partitioning) {
fPartitioning = partitioning;
}
/**
* Creates a new Scriptdoc auto indent strategy for the given document
* partitioning.
*
* @param partitioning
* the document partitioning
*/
public PhpDocAutoIndentStrategy() {
this(PHPPartitionTypes.PHP_DEFAULT);
}
/**
* Copies the indentation of the previous line and adds a star. If the
* Scriptdoc just started on this line add standard method tags and close
* the Scriptdoc.
*
* @param d
* the document to work on
* @param c
* the command to deal with
*/
private void indentAfterNewLine(IDocument d, DocumentCommand c) {
int offset = c.offset;
if (offset == -1 || d.getLength() == 0)
return;
try {
int p = (offset == d.getLength() ? offset - 1 : offset);
IRegion line = d.getLineInformationOfOffset(p);
int lineOffset = line.getOffset();
int firstNonWS = findEndOfWhiteSpace(d, lineOffset, offset);
Assert.isTrue(firstNonWS >= lineOffset,
"indentation must not be negative"); //$NON-NLS-1$
StringBuffer buf = new StringBuffer(c.text);
IRegion prefix = findPrefixRange(d, line);
String indentation = d.get(prefix.getOffset(), prefix.getLength());
int lengthToAdd = Math.min(offset - prefix.getOffset(),
prefix.getLength());
buf.append(indentation.substring(0, lengthToAdd));
if (firstNonWS < offset) {
if (d.getChar(firstNonWS) == '/') {
// phpdoc started on this line
buf.append(" * "); //$NON-NLS-1$
if (TypingPreferences.closePhpdoc
&& isNewComment(d, offset)) {
c.shiftsCaret = false;
c.caretOffset = c.offset + buf.length();
String lineDelimiter = TextUtilities
.getDefaultLineDelimiter(d);
int replacementLength = 0;
String restOfLine = d.get(p, replacementLength);
String endTag = lineDelimiter + indentation + " */"; //$NON-NLS-1$
// Check if we need end tag
if (getCommentEnd(d, offset) > 0) {
endTag = ""; //$NON-NLS-1$
}
if (TypingPreferences.addDocTags) {
// we need to close the comment before computing
// the correct tags in order to get the method
d.replace(offset, replacementLength, endTag);
// evaluate method signature
ISourceModule unit = getCompilationUnit();
if (unit != null) {
try {
ScriptModelUtil.reconcile(unit);
// PHPUiPlugin.getDefault().getASTProvider().reconciled(null,
// unit, new NullProgressMonitor());
String partitionType = FormatterUtils
.getPartitionType(
(IStructuredDocument) d,
c.offset);
String commentBlockBody;
if (partitionType
.equals(PHPPartitionTypes.PHP_DOC)) {
commentBlockBody = createScriptdocTags(
d, c, indentation,
lineDelimiter, unit);
} else {// Multiline comment
commentBlockBody = PHP_COMMENT_BLOCK_MID;
}
buf.append(restOfLine);
// only add tags if they are non-empty - the
// empty line has already been added above.
if (commentBlockBody != null
&& !commentBlockBody.trim().equals(
"*")) //$NON-NLS-1$
buf.append(commentBlockBody);
} catch (CoreException e) {
Logger.logException(e);
}
}
} else {
c.length = replacementLength;
buf.append(restOfLine);
buf.append(endTag);
}
}
}
}
// move the caret behind the prefix, even if we do not have to
// insert it.
if (lengthToAdd < prefix.getLength())
c.caretOffset = offset + prefix.getLength() - lengthToAdd;
c.text = buf.toString();
} catch (BadLocationException excp) {
Logger.logException(excp);
}
}
/**
* Returns the value of the given boolean-typed preference.
*
* @param preference
* the preference to look up
* @return the value of the given preference in the PHP plug-in's default
* preference store
*/
private boolean isPreferenceTrue(String preference) {
return PHPUiPlugin.getDefault().getPreferenceStore()
.getBoolean(preference);
}
/**
* Returns the range of the Scriptdoc prefix on the given line in
* <code>document</code>. The prefix greedily matches the following regex
* pattern: <code>\w*\*\w*</code>, that is, any number of whitespace
* characters, followed by an asterisk ('*'), followed by any number of
* whitespace characters.
*
* @param document
* the document to which <code>line</code> refers
* @param line
* the line from which to extract the prefix range
* @return an <code>IRegion</code> describing the range of the prefix on the
* given line
* @throws BadLocationException
* if accessing the document fails
*/
private IRegion findPrefixRange(IDocument document, IRegion line)
throws BadLocationException {
int lineOffset = line.getOffset();
int lineEnd = lineOffset + line.getLength();
int indentEnd = findEndOfWhiteSpace(document, lineOffset, lineEnd);
if (indentEnd < lineEnd && document.getChar(indentEnd) == '*') {
indentEnd++;
while (indentEnd < lineEnd && document.getChar(indentEnd) == ' ')
indentEnd++;
}
return new Region(lineOffset, indentEnd - lineOffset);
}
/**
*
* Returns the range of the Scriptdoc prefix on the given line in
* <code>document</code>. The prefix greedily matches the following regex
* pattern: <code>\w*</code>, that is, any number of whitespace characters,
* until non first non white space character.
*
* @param document
* the document to which <code>line</code> refers
* @param line
* the line from which to extract the prefix range
* @return an <code>IRegion</code> describing the range of the prefix on the
* given line
* @throws BadLocationException
* if accessing the document fails
*/
private IRegion findCommentBlockStartPrefixRange(IDocument document,
IRegion line) throws BadLocationException {
int lineOffset = line.getOffset();
int lineEnd = lineOffset + line.getLength();
int indentEnd = findEndOfWhiteSpace(document, lineOffset, lineEnd);
return new Region(lineOffset, indentEnd - lineOffset);
}
/**
* Creates the Scriptdoc tags for newly inserted comments.
*
* @param document
* the document
* @param command
* the command
* @param indentation
* the base indentation to use
* @param lineDelimiter
* the line delimiter to use
* @param unit
* the compilation unit shown in the editor
* @return the tags to add to the document
* @throws CoreException
* if accessing the PHP model fails
* @throws BadLocationException
* if accessing the document fails
*/
private String createScriptdocTags(IDocument document,
DocumentCommand command, String indentation, String lineDelimiter,
ISourceModule unit) throws CoreException, BadLocationException {
// searching for next element's start point
int nextElementOffset = getEndOfWhiteSpacesOffset(document,
command.caretOffset, document.getLength());
IModelElement element = getElementAt(unit, nextElementOffset);
if (element == null) {
return null;
}
// Checking the element we got is not the element within the "/**" was
// typed
if (getCodeDataOffset(element) <= command.caretOffset) {
return null;
}
int type = element != null ? element.getElementType() : -1;
if (type != IModelElement.METHOD && type != IModelElement.TYPE
&& type != IModelElement.FIELD
&& type != IModelElement.IMPORT_CONTAINER) {
assert false;
return null;
}
String comment = null;
try {
switch (type) {
case IModelElement.IMPORT_CONTAINER:
comment = createFileComment(unit, indentation, lineDelimiter);
break;
case IModelElement.TYPE:
IType sourceType = (IType) element;
if (PHPFlags.isNamespace(sourceType.getFlags())) {
comment = createFileComment(unit, indentation,
lineDelimiter);
} else {
comment = createTypeTags(document, command, indentation,
lineDelimiter, (IType) element);
}
break;
case IModelElement.FIELD:
comment = creatFieldTags(document, command, indentation,
lineDelimiter, (IField) element);
// bug: 430784
if (comment == null) {
comment = prepareTemplateComment("", indentation, //$NON-NLS-1$
element.getScriptProject(), lineDelimiter);
}
break;
case IModelElement.METHOD:
comment = createMethodTags(document, command, indentation,
lineDelimiter, (IMethod) element);
break;
default:
comment = createDefaultComment(lineDelimiter);
}
} catch (CoreException e) {
comment = createDefaultComment(lineDelimiter);
Logger.logException(e);
}
return indentPattern(comment, indentation, lineDelimiter);
}
private int getEndOfWhiteSpacesOffset(IDocument document, int offset,
int end) throws BadLocationException {
while (offset < end) {
if (!Character.isWhitespace(document.getChar(offset))) {
return offset;
}
offset++;
}
return -1;
}
private IModelElement getElementAt(ISourceModule unit, int nextElementOffset)
throws ModelException {
IModelElement modelElement = unit.getElementAt(nextElementOffset);
if (modelElement == null) {
// look for first in file use statement also
if (unit.getChildren().length != 0
&& unit.getChildren()[0].getElementType() == IModelElement.IMPORT_CONTAINER) {
return unit.getChildren()[0];
}
}
return modelElement;
}
/**
* Removes start and end of a comment and corrects indentation and line
* delimiters.
*
* @param comment
* the computed comment
* @param indentation
* the base indentation
* @param project
* the PHP project for the formatter settings, or
* <code>null</code> for global preferences
* @param lineDelimiter
* the line delimiter
* @return a trimmed version of <code>comment</code>
*/
private String prepareTemplateComment(String comment, String indentation,
IScriptProject project, 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 '/*'
}
}
// trim leading spaces, but not new lines
int nonSpace = 0;
int len = comment.length();
while (nonSpace < len
&& Character.getType(comment.charAt(nonSpace)) == Character.SPACE_SEPARATOR)
nonSpace++;
comment = comment.substring(nonSpace);
return comment;
// TODO : should fix the formatter step
// return Strings.changeIndent(comment, 0, project, indentation,
// lineDelimiter);
}
private String createFileComment(ISourceModule sourceModule,
String indentation, String lineDelimiter) throws CoreException {
String comment = CodeGeneration.getFileComment(sourceModule,
lineDelimiter);
if (comment != null) {
comment = comment.trim();
return prepareTemplateComment(comment.trim(), indentation,
sourceModule.getScriptProject(), lineDelimiter);
}
return comment;
}
private String createTypeTags(IDocument document, DocumentCommand command,
String indentation, String lineDelimiter, IType type)
throws CoreException, BadLocationException {
String comment = createTypeComment(type, lineDelimiter);
if (comment != null) {
comment = comment.trim();
return prepareTemplateComment(comment.trim(), indentation,
type.getScriptProject(), lineDelimiter);
}
return null;
}
private String creatFieldTags(IDocument document, DocumentCommand command,
String indentation, String lineDelimiter, IField field)
throws CoreException, BadLocationException {
String comment = createFieldComment(field, lineDelimiter);
if (comment != null) {
comment = comment.trim();
return prepareTemplateComment(comment.trim(), indentation,
field.getScriptProject(), lineDelimiter);
}
return null;
}
private String createMethodTags(IDocument document,
DocumentCommand command, String indentation, String lineDelimiter,
IMethod method) throws CoreException, BadLocationException {
// IMethod inheritedMethod = getInheritedMethod(method);
String comment = createMethodComment(method, lineDelimiter);// CodeGeneration.getMethodComment(method,
// inheritedMethod,
// lineDelimiter);
if (comment != null) {
comment = comment.trim();
return prepareTemplateComment(comment, indentation,
method.getScriptProject(), lineDelimiter);
}
return null;
}
/**
* Unindents a typed slash ('/') if it forms the end of a comment.
*
* @param d
* the document
* @param c
* the command
*/
private void indentAfterCommentEnd(IDocument d, DocumentCommand c) {
if (c.offset < 2 || d.getLength() == 0) {
return;
}
// Check the case that '/' is printed inside of a comment block
try {
if ("* ".equals(d.get(c.offset - 2, 2))) { //$NON-NLS-1$
int offset = c.offset;
int fixedOffset = offset;
if (offset == d.getLength()) {
fixedOffset -= 1;
}
IStructuredDocumentRegion sdRegion = ((IStructuredDocument) d)
.getRegionAtCharacterOffset(fixedOffset);
ITextRegion tRegion = sdRegion
.getRegionAtCharacterOffset(fixedOffset);
int regionOffset = offset;
if (tRegion instanceof ITextRegionContainer) {
tRegion = ((ITextRegionContainer) tRegion)
.getRegionAtCharacterOffset(fixedOffset);
regionOffset -= (sdRegion.getStartOffset(tRegion) + tRegion
.getStart());
}
int regionStart = sdRegion.getStartOffset(tRegion);
if (tRegion != null && tRegion instanceof IPhpScriptRegion) {
IPhpScriptRegion scriptRegion = (IPhpScriptRegion) tRegion;
regionOffset -= scriptRegion.getStart();
ITextRegion commentRegion = scriptRegion
.getPhpToken(regionOffset);
int phpScriptEndOffset = scriptRegion.getLength();
boolean isSpaceDeletionNeeded = false;
do {
int currentRegionEndOffset = commentRegion.getEnd();
commentRegion = scriptRegion
.getPhpToken(currentRegionEndOffset);
String tokenType = commentRegion.getType();
if (tokenType.equals(PHPRegionTypes.PHP_COMMENT_END)
|| PHPRegionTypes.PHPDOC_COMMENT_END
.equals(tokenType)) {
break;
} else if (currentRegionEndOffset >= phpScriptEndOffset) {
isSpaceDeletionNeeded = true;
break;
}
} while (true);
if (isSpaceDeletionNeeded) {
// perform the actual work
c.length++;
c.offset--;
return;
}
}
}
} catch (BadLocationException excp) {
Logger.logException(excp);
}
}
/**
* Guesses if the command operates within a newly created Scriptdoc comment
* or not. If in doubt, it will assume that the Scriptdoc is new.
*
* @param document
* the document
* @param commandOffset
* the command offset
* @return <code>true</code> if the comment should be closed,
* <code>false</code> if not
*/
private 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 = TextUtilities.getPartition(document,
fPartitioning, commandOffset, false);
int partitionEnd = partition.getOffset() + partition.getLength();
if (line.getOffset() >= partitionEnd)
return false;
if (document.getLength() == partitionEnd)
return true; // partition goes to end of document - probably a
// new comment
String comment = document.get(partition.getOffset(),
partition.getLength());
if (comment.indexOf("/*", 2) != -1) //$NON-NLS-1$
return true; // enclosed another comment -> probably a new
// comment
return false;
} catch (BadLocationException e) {
return false;
}
}
private boolean isSmartMode() {
IWorkbenchPage page = PHPUiPlugin.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;
if (command.text != null) {
if (command.length == 0) {
// get legal end of line set
String[] lineDelimiters = document.getLegalLineDelimiters();
// get the the last index of end of line in the command
int index = TextUtilities
.endsWith(lineDelimiters, command.text);
int offset = command.offset;
// if end of line exists in the command
if (index > -1) {
// ends with line delimiter
if (lineDelimiters[index].equals(command.text)) {
try {
IStructuredDocumentRegion sdRegion = ((IStructuredDocument) document)
.getRegionAtCharacterOffset(offset);
// in case we're at the end of file, go on char back
// to be in region
int fixedOffset = offset;
if (offset == document.getLength()) {
fixedOffset -= 1;
}
ITextRegion tRegion = sdRegion
.getRegionAtCharacterOffset(fixedOffset);
int regionOffset = offset;
// if netsed html/php structure exists
if (tRegion instanceof ITextRegionContainer) {
tRegion = ((ITextRegionContainer) tRegion)
.getRegionAtCharacterOffset(fixedOffset);
// update region offset for in order to get
// phpdoc region later
regionOffset -= (sdRegion
.getStartOffset(tRegion) + tRegion
.getStart());
}
if (tRegion != null
&& tRegion instanceof IPhpScriptRegion) {
IPhpScriptRegion scriptRegion = (IPhpScriptRegion) tRegion;
// update region offset for in order to get
// phpdoc region later
regionOffset -= scriptRegion.getStart();
ITextRegion commentRegion = scriptRegion
.getPhpToken(regionOffset);
String tokenType = commentRegion.getType();
if (document.getLength() == offset
&& (tokenType
.equals(PHPRegionTypes.PHPDOC_COMMENT_END) || tokenType
.equals(PHPRegionTypes.PHP_COMMENT_END))
&& document.get(offset - 2, 2).equals(
"*/")) { //$NON-NLS-1$
ITextRegion region = commentRegion;
// go up in document and search for the
// first line containing
// PHPDOC_COMMENT_START/PHP_COMMENT_START
// tag
do {
if (region.getType() == PHPRegionTypes.PHPDOC_COMMENT_START
|| region.getType() == PHPRegionTypes.PHP_COMMENT_START
|| region.getStart() <= scriptRegion
.getStart()) {
break;
}
// get previous region
region = scriptRegion
.getPhpToken(region.getStart()
- lineDelimiters[index]
.length());
} while (true);
// get the line region
IRegion line = document
.getLineInformationOfOffset(region
.getStart());
StringBuffer buf = new StringBuffer(
command.text);
// extract indentation from the found line
IRegion prefix = findCommentBlockStartPrefixRange(
document, line);
// build indentation based on the prefix
// length
String indentation = document.get(
prefix.getOffset(),
prefix.getLength());
buf.append(indentation);
// perform the actual work
command.shiftsCaret = false;
command.caretOffset = command.offset
+ buf.length();
command.text = buf.toString();
return;
}
}
} catch (BadLocationException e) {
// May be caused by concurrent threads. Can be
// ignored.
}
// just the line delimiter
if (lineDelimiters[index].equals(command.text)) {
indentAfterNewLine(document, command);
}
return;
}
}
}
if (command.text.equals("/")) { //$NON-NLS-1$
indentAfterCommentEnd(document, command);
return;
}
}
}
/**
* Returns the method inherited from, <code>null</code> if method is newly
* defined.
*
* @param method
* the method being written
* @return the ancestor method, or <code>null</code> if none
* @throws ModelException
* if accessing the PHP model fails
*/
private static IMethod getInheritedMethod(IMethod method)
throws ModelException {
IType declaringType = method.getDeclaringType();
if (null == declaringType)
return null;
MethodOverrideTester tester = SuperTypeHierarchyCache
.getMethodOverrideTester(declaringType);
return tester.findOverriddenMethod(method, true);
}
/**
* Returns the compilation unit of the compilation unit editor invoking the
* <code>AutoIndentStrategy</code>, might return <code>null</code> on error.
*
* @return the compilation unit represented by the document
*/
private static ISourceModule 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 = PHPUiPlugin.getWorkingCopyManager();
ISourceModule unit = manager.getWorkingCopy(editor.getEditorInput());
if (unit == null)
return null;
return unit;
}
/**
* Finds the offset of the closing bracket of the comment block which starts
* on "offset" The method search until EOF or another comment block begins
*
* @return the closing bracket offset, or negative number if no relevant
* closing bracket was found TODO when there are // at the end of
* line this method will throw BadLocationException
*/
private int getCommentEnd(IDocument d, int offset)
throws BadLocationException {
int endOfDoc = d.getLength();
while (offset + 1 < endOfDoc) {
if (d.getChar(offset) == '*' && d.getChar(offset + 1) == '/') {
return offset + 1;
} else if (d.getChar(offset) == '/' && d.getChar(offset + 1) == '*') {
return -1;
}
offset++;
}
return -2;
}
private String createTypeComment(IType type, String lineDelimiter)
throws CoreException {
// String[] typeParameterNames=
// StubUtility.getTypeParameterNames(type.getFields());
return CodeGeneration.getTypeComment(type.getScriptProject(),
type.getTypeQualifiedName(), /* typeParameterNames */null,
lineDelimiter);
}
private String createMethodComment(IMethod meth, String lineDelimiter)
throws CoreException {
IType declaringType = meth.getDeclaringType();
IMethod overridden = null;
if (!meth.isConstructor() && null != declaringType) {
try {
ITypeHierarchy hierarchy = SuperTypeHierarchyCache
.getTypeHierarchy(declaringType);
MethodOverrideTester tester = new MethodOverrideTester(
declaringType, hierarchy);
overridden = tester.findOverriddenMethod(meth, true);
} catch (CoreException e) {
Logger.logException(e);
}
}
return CodeGeneration.getMethodComment(meth, overridden, lineDelimiter);
}
private String createFieldComment(IField field, String lineDelimiter)
throws ModelException, CoreException {
return CodeGeneration.getFieldComment(field.getScriptProject(), field,
lineDelimiter);
}
private String createDefaultComment(String lineDelimiter) {
return PHPDOC_COMMENT_BLOCK_START + lineDelimiter
+ PHP_COMMENT_BLOCK_MID + lineDelimiter + PHP_COMMENT_BLOCK_END;
}
/**
* Calculates the leading string to be used as indentation prefix
*
* @param document
* The IStructuredDocument that we are working on
* @param modelElem
* A PHPFileData that need to be documented
*
* @return String to be used as leading indentation
*/
private String getIndentString(IDocument document, IModelElement modelElem)
throws BadLocationException {
int elementOffset = 0;
String leadingString = null;
try {
elementOffset = getCodeDataOffset(modelElem);
int lineStartOffset = document.getLineInformationOfOffset(
elementOffset).getOffset();
leadingString = document.get(lineStartOffset, elementOffset
- lineStartOffset);
} catch (ModelException e) {
Logger.logException(e);
return null;
}
// replacing all non-spaces/tabs to single-space, in order to get
// "char-clean" prefix
leadingString = leadingString.replaceAll("[^\\s]", " "); //$NON-NLS-1$ //$NON-NLS-2$
return leadingString;
}
private int getCodeDataOffset(IModelElement modelElem)
throws ModelException {
if (modelElem instanceof ISourceModule) {
ISourceReference primaryModelElem = (ISourceReference) (((ISourceModule) modelElem)
.getPrimaryElement());// .getPHPBlocks();
return primaryModelElem != null ? primaryModelElem.getSourceRange()
.getOffset()
+ primaryModelElem.getSourceRange().getLength()/*
* getPHPStartTag
* ( ).
* getEndPosition
* ()
*/: -1;
}
if (modelElem instanceof ISourceReference) {
int dataOffset = ((ISourceReference) modelElem).getSourceRange()
.getOffset();
return dataOffset;
}
assert false;
return -1;
}
private String indentPattern(String originalPattern, String indentation,
String lineDelim) {
String delimPlusIndent = lineDelim + indentation;
String indentedPattern = originalPattern.replaceAll(lineDelim,
delimPlusIndent);
return indentedPattern;
}
}