X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/php/JavaFormatter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/php/JavaFormatter.java index 5a9666d..d1cd8bc 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/php/JavaFormatter.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/php/JavaFormatter.java @@ -1,10 +1,10 @@ /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials + * 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 *******************************************************************************/ @@ -13,12 +13,9 @@ package net.sourceforge.phpdt.internal.corext.template.php; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map; -import net.sourceforge.phpdt.core.JavaCore; import net.sourceforge.phpdt.internal.corext.util.CodeFormatterUtil; import net.sourceforge.phpdt.internal.corext.util.Strings; -import net.sourceforge.phpdt.internal.formatter.CodeFormatter; import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions; import net.sourceforge.phpdt.internal.ui.text.JavaHeuristicScanner; import net.sourceforge.phpdt.internal.ui.text.JavaIndenter; @@ -47,312 +44,349 @@ import org.eclipse.text.edits.TextEdit; */ public class JavaFormatter { - private static final String MARKER = "/*${" + GlobalTemplateVariables.Cursor.NAME + "}*/"; //$NON-NLS-1$ //$NON-NLS-2$ - - /** The line delimiter to use if code formatter is not used. */ - private final String fLineDelimiter; - - /** The initial indent level */ - private final int fInitialIndentLevel; - - /** The java partitioner */ - private boolean fUseCodeFormatter; - - /** - * Creates a JavaFormatter with the target line delimiter. - * - * @param lineDelimiter - * the line delimiter to use - * @param initialIndentLevel - * the initial indentation level - * @param useCodeFormatter - * true if the core code formatter should be used - */ - public JavaFormatter(String lineDelimiter, int initialIndentLevel, boolean useCodeFormatter) { - fLineDelimiter = lineDelimiter; - fUseCodeFormatter = useCodeFormatter; - fInitialIndentLevel = initialIndentLevel; - } - - /** - * Formats the template buffer. - * - * @param buffer - * @param context - * @throws BadLocationException - */ - public void format(TemplateBuffer buffer, TemplateContext context) throws BadLocationException { - try { - if (fUseCodeFormatter) - // try to format and fall back to indenting - try { - format(buffer, (JavaContext) context); - } catch (BadLocationException e) { - indent(buffer); - } catch (MalformedTreeException e) { - indent(buffer); - } - else - indent(buffer); - - // don't trim the buffer if the replacement area is empty - // case: surrounding empty lines with block - if (context instanceof DocumentTemplateContext) { - DocumentTemplateContext dtc = (DocumentTemplateContext) context; - if (dtc.getStart() == dtc.getCompletionOffset()) - if (dtc.getDocument().get(dtc.getStart(), dtc.getEnd() - dtc.getEnd()).trim().length() == 0) - return; - } - - trimBegin(buffer); - } catch (MalformedTreeException e) { - throw new BadLocationException(); - } - } - - private static int getCaretOffset(TemplateVariable[] variables) { - for (int i = 0; i != variables.length; i++) { - TemplateVariable variable = variables[i]; - - if (variable.getType().equals(GlobalTemplateVariables.Cursor.NAME)) - return variable.getOffsets()[0]; - } - - return -1; - } - - private boolean isInsideCommentOrString(String string, int offset) { - - IDocument document = new Document(string); - PHPeclipsePlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(document); - - try { - ITypedRegion partition = document.getPartition(offset); - String partitionType = partition.getType(); - - return partitionType != null - && (partitionType.equals(IPHPPartitions.PHP_MULTILINE_COMMENT) - || partitionType.equals(IPHPPartitions.PHP_SINGLELINE_COMMENT) || partitionType.equals(IPHPPartitions.PHP_STRING_DQ) - || partitionType.equals(IPHPPartitions.PHP_STRING_SQ) || partitionType.equals(IPHPPartitions.PHP_PHPDOC_COMMENT)); - - } catch (BadLocationException e) { - return false; - } - } - - private void format(TemplateBuffer templateBuffer, JavaContext context) throws BadLocationException { - // XXX 4360, 15247 - // workaround for code formatter limitations - // handle a special case where cursor position is surrounded by whitespaces - - String string = templateBuffer.getString(); - TemplateVariable[] variables = templateBuffer.getVariables(); - - int caretOffset = getCaretOffset(variables); - if ((caretOffset > 0) && Character.isWhitespace(string.charAt(caretOffset - 1)) && (caretOffset < string.length()) - && Character.isWhitespace(string.charAt(caretOffset)) && !isInsideCommentOrString(string, caretOffset)) { - List positions = variablesToPositions(variables); - - TextEdit insert = new InsertEdit(caretOffset, MARKER); - string = edit(string, positions, insert); - positionsToVariables(positions, variables); - templateBuffer.setContent(string, variables); - - plainFormat(templateBuffer, context); - - string = templateBuffer.getString(); - variables = templateBuffer.getVariables(); - caretOffset = getCaretOffset(variables); - - positions = variablesToPositions(variables); - TextEdit delete = new DeleteEdit(caretOffset, MARKER.length()); - string = edit(string, positions, delete); - positionsToVariables(positions, variables); - templateBuffer.setContent(string, variables); - - } else { - plainFormat(templateBuffer, context); - } - } - - private void plainFormat(TemplateBuffer templateBuffer, JavaContext context) throws BadLocationException { - } - - // private void plainFormat(TemplateBuffer templateBuffer, JavaContext context) throws BadLocationException { - // - // IDocument doc= new Document(templateBuffer.getString()); - // - // TemplateVariable[] variables= templateBuffer.getVariables(); - // - // List offsets= variablesToPositions(variables); - // - // Map options; - // if (context.getCompilationUnit() != null) - // options= context.getCompilationUnit().getJavaProject().getOptions(true); - // else - // options= JavaCore.getOptions(); - // - // TextEdit edit= CodeFormatterUtil.format2(CodeFormatter.K_UNKNOWN, doc.get(), fInitialIndentLevel, fLineDelimiter, options); - // if (edit == null) - // throw new BadLocationException(); // fall back to indenting - // - // MultiTextEdit root; - // if (edit instanceof MultiTextEdit) - // root= (MultiTextEdit) edit; - // else { - // root= new MultiTextEdit(0, doc.getLength()); - // root.addChild(edit); - // } - // for (Iterator it= offsets.iterator(); it.hasNext();) { - // TextEdit position= (TextEdit) it.next(); - // try { - // root.addChild(position); - // } catch (MalformedTreeException e) { - // // position conflicts with formatter edit - // // ignore this position - // } - // } - // - // root.apply(doc, TextEdit.UPDATE_REGIONS); - // - // positionsToVariables(offsets, variables); - // - // templateBuffer.setContent(doc.get(), variables); - // } - - private void indent(TemplateBuffer templateBuffer) throws BadLocationException, MalformedTreeException { - - TemplateVariable[] variables = templateBuffer.getVariables(); - List positions = variablesToPositions(variables); - - IDocument document = new Document(templateBuffer.getString()); - MultiTextEdit root = new MultiTextEdit(0, document.getLength()); - root.addChildren((TextEdit[]) positions.toArray(new TextEdit[positions.size()])); - - JavaHeuristicScanner scanner = new JavaHeuristicScanner(document); - JavaIndenter indenter = new JavaIndenter(document, scanner); - - // first line - int offset = document.getLineOffset(0); - TextEdit edit = new InsertEdit(offset, CodeFormatterUtil.createIndentString(fInitialIndentLevel)); - root.addChild(edit); - root.apply(document, TextEdit.UPDATE_REGIONS); - root.removeChild(edit); - - formatDelimiter(document, root, 0); - - // following lines - int lineCount = document.getNumberOfLines(); - - for (int line = 1; line < lineCount; line++) { - IRegion region = document.getLineInformation(line); - offset = region.getOffset(); - StringBuffer indent = indenter.computeIndentation(offset); - if (indent == null) - continue; - // axelcl delete start -// int nonWS = scanner.findNonWhitespaceForwardInAnyPartition(offset, offset + region.getLength()); -// if (nonWS == JavaHeuristicScanner.NOT_FOUND) -// continue; -// edit = new ReplaceEdit(offset, nonWS - offset, indent.toString()); -// axelcl delete end -// axelcl insert start - int nonWS = offset; - edit = new ReplaceEdit(offset, nonWS - offset, CodeFormatterUtil.createIndentString(fInitialIndentLevel)); - // axelcl insert end - root.addChild(edit); - root.apply(document, TextEdit.UPDATE_REGIONS); - root.removeChild(edit); - - formatDelimiter(document, root, line); - } - - positionsToVariables(positions, variables); - templateBuffer.setContent(document.get(), variables); - } - - /** - * Changes the delimiter to the configured line delimiter. - * - * @param document - * the temporary document being edited - * @param root - * the root edit containing all positions that will be updated along the way - * @param line - * the line to format - * @throws BadLocationException - * if applying the changes fails - */ - private void formatDelimiter(IDocument document, MultiTextEdit root, int line) throws BadLocationException { - IRegion region = document.getLineInformation(line); - String lineDelimiter = document.getLineDelimiter(line); - if (lineDelimiter != null) { - TextEdit edit = new ReplaceEdit(region.getOffset() + region.getLength(), lineDelimiter.length(), fLineDelimiter); - root.addChild(edit); - root.apply(document, TextEdit.UPDATE_REGIONS); - root.removeChild(edit); - } - } - - private static void trimBegin(TemplateBuffer templateBuffer) throws BadLocationException { - String string = templateBuffer.getString(); - TemplateVariable[] variables = templateBuffer.getVariables(); - - List positions = variablesToPositions(variables); - - int i = 0; - while ((i != string.length()) && Character.isWhitespace(string.charAt(i))) - i++; - - string = edit(string, positions, new DeleteEdit(0, i)); - positionsToVariables(positions, variables); - - templateBuffer.setContent(string, variables); - } - - private static String edit(String string, List positions, TextEdit edit) throws BadLocationException { - MultiTextEdit root = new MultiTextEdit(0, string.length()); - root.addChildren((TextEdit[]) positions.toArray(new TextEdit[positions.size()])); - root.addChild(edit); - IDocument document = new Document(string); - root.apply(document); - - return document.get(); - } - - private static List variablesToPositions(TemplateVariable[] variables) { - List positions = new ArrayList(5); - for (int i = 0; i != variables.length; i++) { - int[] offsets = variables[i].getOffsets(); - - // trim positions off whitespace - String value = variables[i].getDefaultValue(); - int wsStart = 0; - while (wsStart < value.length() && Character.isWhitespace(value.charAt(wsStart)) - && !Strings.isLineDelimiterChar(value.charAt(wsStart))) - wsStart++; - - variables[i].getValues()[0] = value.substring(wsStart); - - for (int j = 0; j != offsets.length; j++) { - offsets[j] += wsStart; - positions.add(new RangeMarker(offsets[j], 0)); - } - } - return positions; - } - - private static void positionsToVariables(List positions, TemplateVariable[] variables) { - Iterator iterator = positions.iterator(); - - for (int i = 0; i != variables.length; i++) { - TemplateVariable variable = variables[i]; - - int[] offsets = new int[variable.getOffsets().length]; - for (int j = 0; j != offsets.length; j++) - offsets[j] = ((TextEdit) iterator.next()).getOffset(); - - variable.setOffsets(offsets); - } - } + private static final String MARKER = "/*${" + GlobalTemplateVariables.Cursor.NAME + "}*/"; //$NON-NLS-1$ //$NON-NLS-2$ + + /** The line delimiter to use if code formatter is not used. */ + private final String fLineDelimiter; + + /** The initial indent level */ + private final int fInitialIndentLevel; + + /** The java partitioner */ + private boolean fUseCodeFormatter; + + /** + * Creates a JavaFormatter with the target line delimiter. + * + * @param lineDelimiter + * the line delimiter to use + * @param initialIndentLevel + * the initial indentation level + * @param useCodeFormatter + * true if the core code formatter should be used + */ + public JavaFormatter(String lineDelimiter, int initialIndentLevel, + boolean useCodeFormatter) { + fLineDelimiter = lineDelimiter; + fUseCodeFormatter = useCodeFormatter; + fInitialIndentLevel = initialIndentLevel; + } + + /** + * Formats the template buffer. + * + * @param buffer + * @param context + * @throws BadLocationException + */ + public void format(TemplateBuffer buffer, TemplateContext context) + throws BadLocationException { + try { + if (fUseCodeFormatter) + // try to format and fall back to indenting + try { + format(buffer, (JavaContext) context); + } catch (BadLocationException e) { + indent(buffer); + } catch (MalformedTreeException e) { + indent(buffer); + } + else + indent(buffer); + + // don't trim the buffer if the replacement area is empty + // case: surrounding empty lines with block + if (context instanceof DocumentTemplateContext) { + DocumentTemplateContext dtc = (DocumentTemplateContext) context; + if (dtc.getStart() == dtc.getCompletionOffset()) + if (dtc.getDocument().get(dtc.getStart(), + dtc.getEnd() - dtc.getEnd()).trim().length() == 0) + return; + } + + trimBegin(buffer); + } catch (MalformedTreeException e) { + throw new BadLocationException(); + } + } + + private static int getCaretOffset(TemplateVariable[] variables) { + for (int i = 0; i != variables.length; i++) { + TemplateVariable variable = variables[i]; + + if (variable.getType().equals(GlobalTemplateVariables.Cursor.NAME)) + return variable.getOffsets()[0]; + } + + return -1; + } + + private boolean isInsideCommentOrString(String string, int offset) { + + IDocument document = new Document(string); + PHPeclipsePlugin.getDefault().getJavaTextTools() + .setupJavaDocumentPartitioner(document); + + try { + ITypedRegion partition = document.getPartition(offset); + String partitionType = partition.getType(); + + return partitionType != null + && (partitionType + .equals(IPHPPartitions.PHP_MULTILINE_COMMENT) + || partitionType + .equals(IPHPPartitions.PHP_SINGLELINE_COMMENT) + || partitionType + .equals(IPHPPartitions.PHP_STRING_DQ) + || partitionType + .equals(IPHPPartitions.PHP_STRING_SQ) + || partitionType + .equals(IPHPPartitions.PHP_STRING_HEREDOC) || partitionType + .equals(IPHPPartitions.PHP_PHPDOC_COMMENT)); + + } catch (BadLocationException e) { + return false; + } + } + + private void format(TemplateBuffer templateBuffer, JavaContext context) + throws BadLocationException { + // XXX 4360, 15247 + // workaround for code formatter limitations + // handle a special case where cursor position is surrounded by + // whitespaces + + String string = templateBuffer.getString(); + TemplateVariable[] variables = templateBuffer.getVariables(); + + int caretOffset = getCaretOffset(variables); + if ((caretOffset > 0) + && Character.isWhitespace(string.charAt(caretOffset - 1)) + && (caretOffset < string.length()) + && Character.isWhitespace(string.charAt(caretOffset)) + && !isInsideCommentOrString(string, caretOffset)) { + List positions = variablesToPositions(variables); + + TextEdit insert = new InsertEdit(caretOffset, MARKER); + string = edit(string, positions, insert); + positionsToVariables(positions, variables); + templateBuffer.setContent(string, variables); + + plainFormat(templateBuffer, context); + + string = templateBuffer.getString(); + variables = templateBuffer.getVariables(); + caretOffset = getCaretOffset(variables); + + positions = variablesToPositions(variables); + TextEdit delete = new DeleteEdit(caretOffset, MARKER.length()); + string = edit(string, positions, delete); + positionsToVariables(positions, variables); + templateBuffer.setContent(string, variables); + + } else { + plainFormat(templateBuffer, context); + } + } + + private void plainFormat(TemplateBuffer templateBuffer, JavaContext context) + throws BadLocationException { + } + + // private void plainFormat(TemplateBuffer templateBuffer, JavaContext + // context) throws BadLocationException { + // + // IDocument doc= new Document(templateBuffer.getString()); + // + // TemplateVariable[] variables= templateBuffer.getVariables(); + // + // List offsets= variablesToPositions(variables); + // + // Map options; + // if (context.getCompilationUnit() != null) + // options= context.getCompilationUnit().getJavaProject().getOptions(true); + // else + // options= JavaCore.getOptions(); + // + // TextEdit edit= CodeFormatterUtil.format2(CodeFormatter.K_UNKNOWN, + // doc.get(), fInitialIndentLevel, fLineDelimiter, options); + // if (edit == null) + // throw new BadLocationException(); // fall back to indenting + // + // MultiTextEdit root; + // if (edit instanceof MultiTextEdit) + // root= (MultiTextEdit) edit; + // else { + // root= new MultiTextEdit(0, doc.getLength()); + // root.addChild(edit); + // } + // for (Iterator it= offsets.iterator(); it.hasNext();) { + // TextEdit position= (TextEdit) it.next(); + // try { + // root.addChild(position); + // } catch (MalformedTreeException e) { + // // position conflicts with formatter edit + // // ignore this position + // } + // } + // + // root.apply(doc, TextEdit.UPDATE_REGIONS); + // + // positionsToVariables(offsets, variables); + // + // templateBuffer.setContent(doc.get(), variables); + // } + + private void indent(TemplateBuffer templateBuffer) + throws BadLocationException, MalformedTreeException { + + TemplateVariable[] variables = templateBuffer.getVariables(); + List positions = variablesToPositions(variables); + + IDocument document = new Document(templateBuffer.getString()); + MultiTextEdit root = new MultiTextEdit(0, document.getLength()); + root.addChildren((TextEdit[]) positions.toArray(new TextEdit[positions + .size()])); + + JavaHeuristicScanner scanner = new JavaHeuristicScanner(document); + JavaIndenter indenter = new JavaIndenter(document, scanner); + + // first line + int offset = document.getLineOffset(0); + TextEdit edit = new InsertEdit(offset, CodeFormatterUtil + .createIndentString(fInitialIndentLevel)); + root.addChild(edit); + root.apply(document, TextEdit.UPDATE_REGIONS); + root.removeChild(edit); + + formatDelimiter(document, root, 0); + + // following lines + int lineCount = document.getNumberOfLines(); + + for (int line = 1; line < lineCount; line++) { + IRegion region = document.getLineInformation(line); + offset = region.getOffset(); + StringBuffer indent = indenter.computeIndentation(offset); + if (indent == null) + continue; + // axelcl delete start + // int nonWS = + // scanner.findNonWhitespaceForwardInAnyPartition(offset, offset + + // region.getLength()); + // if (nonWS == JavaHeuristicScanner.NOT_FOUND) + // continue; + // edit = new ReplaceEdit(offset, nonWS - offset, + // indent.toString()); + // axelcl delete end + // axelcl insert start + int nonWS = offset; + edit = new ReplaceEdit(offset, nonWS - offset, CodeFormatterUtil + .createIndentString(fInitialIndentLevel)); + // axelcl insert end + root.addChild(edit); + root.apply(document, TextEdit.UPDATE_REGIONS); + root.removeChild(edit); + + formatDelimiter(document, root, line); + } + + positionsToVariables(positions, variables); + templateBuffer.setContent(document.get(), variables); + } + + /** + * Changes the delimiter to the configured line delimiter. + * + * @param document + * the temporary document being edited + * @param root + * the root edit containing all positions that will be updated + * along the way + * @param line + * the line to format + * @throws BadLocationException + * if applying the changes fails + */ + private void formatDelimiter(IDocument document, MultiTextEdit root, + int line) throws BadLocationException { + IRegion region = document.getLineInformation(line); + String lineDelimiter = document.getLineDelimiter(line); + if (lineDelimiter != null) { + TextEdit edit = new ReplaceEdit(region.getOffset() + + region.getLength(), lineDelimiter.length(), + fLineDelimiter); + root.addChild(edit); + root.apply(document, TextEdit.UPDATE_REGIONS); + root.removeChild(edit); + } + } + + private static void trimBegin(TemplateBuffer templateBuffer) + throws BadLocationException { + String string = templateBuffer.getString(); + TemplateVariable[] variables = templateBuffer.getVariables(); + + List positions = variablesToPositions(variables); + + int i = 0; + while ((i != string.length()) + && Character.isWhitespace(string.charAt(i))) + i++; + + string = edit(string, positions, new DeleteEdit(0, i)); + positionsToVariables(positions, variables); + + templateBuffer.setContent(string, variables); + } + + private static String edit(String string, List positions, TextEdit edit) + throws BadLocationException { + MultiTextEdit root = new MultiTextEdit(0, string.length()); + root.addChildren((TextEdit[]) positions.toArray(new TextEdit[positions + .size()])); + root.addChild(edit); + IDocument document = new Document(string); + root.apply(document); + + return document.get(); + } + + private static List variablesToPositions(TemplateVariable[] variables) { + List positions = new ArrayList(5); + for (int i = 0; i != variables.length; i++) { + int[] offsets = variables[i].getOffsets(); + + // trim positions off whitespace + String value = variables[i].getDefaultValue(); + int wsStart = 0; + while (wsStart < value.length() + && Character.isWhitespace(value.charAt(wsStart)) + && !Strings.isLineDelimiterChar(value.charAt(wsStart))) + wsStart++; + + variables[i].getValues()[0] = value.substring(wsStart); + + for (int j = 0; j != offsets.length; j++) { + offsets[j] += wsStart; + positions.add(new RangeMarker(offsets[j], 0)); + } + } + return positions; + } + + private static void positionsToVariables(List positions, + TemplateVariable[] variables) { + Iterator iterator = positions.iterator(); + + for (int i = 0; i != variables.length; i++) { + TemplateVariable variable = variables[i]; + + int[] offsets = new int[variable.getOffsets().length]; + for (int j = 0; j != offsets.length; j++) + offsets[j] = ((TextEdit) iterator.next()).getOffset(); + + variable.setOffsets(offsets); + } + } } \ No newline at end of file