/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editors.unified.actions;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import com.aptana.ide.core.IdeLog;
import com.aptana.ide.core.StringUtils;
import com.aptana.ide.editors.UnifiedEditorsPlugin;
import com.aptana.ide.editors.formatting.BasicCodeFormatterConstants;
import com.aptana.ide.editors.unified.ICodeFormatter;
import com.aptana.ide.editors.unified.IUnifiedEditor;
import com.aptana.ide.editors.unified.LanguageRegistry;
import com.aptana.ide.io.SourceWriter;
import com.aptana.ide.lexer.Lexeme;
import com.aptana.ide.lexer.LexemeList;
import com.aptana.ide.parsing.nodes.IParseNode;
/**
* @author Pavel Petrochenko
*/
public class CodeFormatAction extends Action implements IEditorActionDelegate, IWorkbenchWindowActionDelegate
{
private static final String TEXT_HTML = "text/html"; //$NON-NLS-1$
private IUnifiedEditor part = null;
private String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
private int tabWitdh = 4;
private String tabChar = ""; //$NON-NLS-1$
/**
*
*/
public CodeFormatAction()
{
this.setText(Messages.CodeFormatAction_CodeFormatTitle);
this.setActionDefinitionId(UnifiedActionContributor.CODE_FORMAT_ACTION_ID);
}
/**
* @see org.eclipse.jface.action.Action#run()
*/
public void run()
{
// checking selection
ISelectionProvider selectionProvider = part.getViewer().getSelectionProvider();
TextSelection selection = (TextSelection) selectionProvider.getSelection();
LexemeList list = part.getFileContext().getParseState().getLexemeList();
StyledText textWidget = part.getViewer().getTextWidget();
int caretOffset = textWidget.getCaretOffset();
int lsIndex = list.getLexemeFloorIndex(caretOffset);
int offsetFromLex = 0;
if (lsIndex != -1)
{
offsetFromLex = caretOffset - list.get(lsIndex).getEndingOffset();
}
// saves the line offset to be restored after formatting
int lineOffset = textWidget.getOffsetAtLine(textWidget.getTopIndex());
int lineIndex = list.getLexemeFloorIndex(lineOffset);
int lineOffsetFromLex = 0;
if (lineIndex != -1)
{
lineOffsetFromLex = lineOffset - list.get(lineIndex).getEndingOffset();
}
IDocument document = part.getViewer().getDocument();
if (document instanceof IDocumentExtension4)
{
IDocumentExtension4 ext = (IDocumentExtension4) document;
lineSeparator = ext.getDefaultLineDelimiter();
}
try
{
lineSeparator = document.getLineDelimiter(0);
}
catch (BadLocationException e1)
{
// silently ignore
}
adjustTabwidthAndTabChar();
IEditorInput editorInput = part.getEditorInput();
IProject project = null;
if (editorInput instanceof IFileEditorInput)
{
IFileEditorInput fl = (IFileEditorInput) editorInput;
project = fl.getFile().getProject();
}
if (selection.getLength() == 0 || selection.getLength() == document.getLength())
{
formatWhole(selection, document, project);
}
else
{
formatSelection(selection, document, project);
}
super.run();
LexemeList lexemeList = part.getFileContext().getParseState().getLexemeList();
if (lexemeList.size() > lsIndex)
{
if (lsIndex != -1)
{
Lexeme lexeme = lexemeList.get(lsIndex);
int initialOffset = lexeme.getEndingOffset();
int endOffset = initialOffset;
if (lsIndex < lexemeList.size() - 1)
{
endOffset = lexemeList.get(lsIndex + 1).getStartingOffset();
}
initialOffset = Math.min(initialOffset + offsetFromLex, endOffset);
if (lineSeparator != null && lineSeparator.length() > 1)
{
try
{
char charAtOffset = document.getChar(initialOffset);
if (charAtOffset == lineSeparator.charAt(1))
{
// we are inside of multiline line delimeter
if (initialOffset > 0)
{
initialOffset--;
}
else
{
initialOffset++;
}
}
}
catch (BadLocationException e)
{
// should not ever happen
IdeLog.logInfo(UnifiedEditorsPlugin.getDefault(), e.getMessage(), e);
}
}
textWidget.setCaretOffset(initialOffset);
}
}
if (lineIndex > -1 && lineIndex < lexemeList.size())
{
// scrolls back the original top line index
Lexeme lexeme = lexemeList.get(lineIndex);
int initialOffset = lexeme.getEndingOffset();
int endOffset = initialOffset;
if (lineIndex < lexemeList.size() - 1)
{
endOffset = lexemeList.get(lineIndex + 1).getStartingOffset();
}
initialOffset = Math.min(initialOffset + lineOffsetFromLex, endOffset);
textWidget.setTopIndex(textWidget.getLineAtOffset(initialOffset));
}
part.getViewer().getTextWidget().redraw();
}
private void adjustTabwidthAndTabChar()
{
String defaultLanguage = part.getFileContext().getDefaultLanguage();
String pluginId = null;
// THIS IS WRONG BY DESIGN SHOULD BE CHANGED LATER
if (defaultLanguage.equals("text/html")) { //$NON-NLS-1$
pluginId = "com.aptana.ide.editor.html"; //$NON-NLS-1$
}
else if (defaultLanguage.equals("text/javascript")) { //$NON-NLS-1$
pluginId = "com.aptana.ide.editor.js"; //$NON-NLS-1$
}
else if (defaultLanguage.equals("text/css")) { //$NON-NLS-1$
pluginId = "com.aptana.ide.editor.css"; //$NON-NLS-1$
}
else if (defaultLanguage.equals("text/php")) { //$NON-NLS-1$
pluginId = "com.aptana.ide.editor.php"; //$NON-NLS-1$
}
if (pluginId != null)
{
tabWitdh = Platform.getPreferencesService().getInt(pluginId, BasicCodeFormatterConstants.FORMATTER_TAB_SIZE, 4, null);
tabChar = Platform.getPreferencesService().getString(pluginId, BasicCodeFormatterConstants.FORMATTER_TAB_CHAR, "", null); //$NON-NLS-1$
}
}
private void formatWhole(TextSelection selection, IDocument document, IProject project)
{
IParseNode parseResults = part.getFileContext().getParseState().getParseResults();
if (parseResults == null)
{
return;
}
String language = parseResults.getLanguage();
ICodeFormatter codeFormatter = LanguageRegistry.getCodeFormatter(language);
if (codeFormatter == null)
{
return;
}
String content = document.get();
if (!codeFormatter.handlesNested())
{
ArrayList languageList = new ArrayList();
checkNodes(languageList, parseResults);
// DIRTY HACK
// TODO TO BE REMOVED AFTER REPLACING TIDY
boolean hasPHP = false;
for (int a = 0; a < languageList.size(); a++)
{
IParseNode object = (IParseNode) languageList.get(a);
if (object.getLanguage().equals("text/php")) { //$NON-NLS-1$
hasPHP = true;
break;
}
}
StringBuffer clearedContent = new StringBuffer();
int prev = 0;
String nestedMark = codeFormatter.createNestedMark();
for (int a = 0; a < languageList.size(); a++)
{
IParseNode pnode = (IParseNode) languageList.get(a);
if (pnode.getStartingOffset() <= prev)
{
IdeLog
.logError(
UnifiedEditorsPlugin.getDefault(),
StringUtils
.format(
"Nodes seems to have wrong offset while formatting following content: {0} Node offset:{1} Prev offset:{2}", new String[] { content, pnode.getStartingOffset() + "", prev + "" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return;
}
clearedContent.append(content.substring(prev, pnode.getStartingOffset()));
prev = pnode.getEndingOffset();
clearedContent.append(nestedMark);
}
if (prev < content.length())
{
clearedContent.append(content.substring(prev));
}
String formattedContentNotMixed = codeFormatter.format(clearedContent.toString(), hasPHP, null, project,
lineSeparator);
for (int a = 0; a < languageList.size(); a++)
{
IParseNode pnode = (IParseNode) languageList.get(a);
int indexOf = formattedContentNotMixed.indexOf(nestedMark);
int iLevel = calcindent(formattedContentNotMixed, indexOf);
if (indexOf == -1)
{
IdeLog
.logError(
UnifiedEditorsPlugin.getDefault(),
StringUtils
.format(
"Nested mark not found, during formatting nested language Old:{0} New:{1}", new String[] { content, formattedContentNotMixed })); //$NON-NLS-1$
return;
}
String languageContent = formatNode(content, pnode, null, project);
languageContent = indent(iLevel + 2, languageContent, lineSeparator);
formattedContentNotMixed = formattedContentNotMixed.substring(0, indexOf) + languageContent
+ formattedContentNotMixed.substring(indexOf + nestedMark.length());
}
actualReplace(selection, content, formattedContentNotMixed);
}
else
{
String formattedContent = codeFormatter.format(content, false, null, project, lineSeparator);
actualReplace(selection, content, formattedContent);
}
}
private void formatSelection(TextSelection selection, IDocument document, IProject project)
{
IParseNode parseResults = part.getFileContext().getParseState().getParseResults();
LexemeList lexemeList = part.getFileContext().getLexemeList();
int selectionStart = selection.getOffset();
int selectionEnd = selection.getOffset() + selection.getLength();
if (!checkSplitting(lexemeList, selectionStart, selectionEnd))
{
return;
}
IParseNode old = parseResults;
parseResults = getSmallestNode(parseResults, selection.getOffset(), selection.getLength());
if (parseResults == null)
{
parseResults = old;
}
String language = determineLanguage(selection, document, parseResults, lexemeList);
ICodeFormatter codeFormatter = LanguageRegistry.getCodeFormatter(language);
String content;
try
{
// adjusting selection if needed and calculating indentation levels.
IRegion lineInformationOfOffset = document.getLineInformationOfOffset(selection.getOffset());
int offset = lineInformationOfOffset.getOffset();
String string = document.get(offset, lineInformationOfOffset.getLength());
int internalOffset = selection.getOffset() - offset;
int indentLevel = 0;
int lineOffset = calcLineOffset(string);
int lineOfOffset = document.getLineOfOffset(selection.getOffset());
boolean isLeading = false;
boolean isHtml = language.equals("text/html"); //$NON-NLS-1$
indentLevel = calculateIndentation(document, isHtml ? lineOfOffset - 1 : lineOfOffset - 1, isHtml);
// if (old.getLanguage().equals("text/html")){ //$NON-NLS-1$
// if (lineOfOffset>0){
// // this is wrong but this seems to be not the worsest solution for now
// indentLevel+=tabWitdh;
// }
// }
if (lineOffset >= internalOffset)
{
int length = selection.getLength() + (selection.getOffset() - offset);
if (document.getLength() <= offset + length)
{
length = document.getLength() - offset;
}
selection = new TextSelection(offset, length);
isLeading = true;
}
content = document.get(selection.getOffset(), selection.getLength());
// does not format empty content now.
if (content.trim().length() == 0)
{
return;
}
if (!codeFormatter.handlesNested())
{
ArrayList languageList = new ArrayList();
checkNodes(languageList, parseResults);
StringBuffer clearedContent = new StringBuffer();
int prev = 0;
String nestedMark = codeFormatter.createNestedMark();
for (int a = 0; a < languageList.size(); a++)
{
IParseNode pnode = (IParseNode) languageList.get(a);
int i = pnode.getStartingOffset() - selection.getOffset();
if (i < 0 || i < prev)
{
IdeLog.logError(UnifiedEditorsPlugin.getDefault(), StringUtils.format(
"Format failed bad ast positions {0},", new String[] { content, pnode.toString() })); //$NON-NLS-1$
return;
}
clearedContent.append(content.substring(prev, i));
prev = pnode.getEndingOffset() - selection.getOffset();
clearedContent.append(nestedMark);
}
if (prev < content.length())
{
clearedContent.append(content.substring(prev));
}
String formattedContentNotMixed = doActualFormat(selection, project, codeFormatter, content,
languageList, clearedContent, nestedMark);
formattedContentNotMixed = indent(indentLevel, formattedContentNotMixed, lineSeparator);
actualReplace(selection, content, formattedContentNotMixed);
}
else
{
if (content.length() > 0)
{
String formattedContent = codeFormatter.format(content, true, null, project, lineSeparator);
if (formattedContent.equals(content))
{
return;
}
formattedContent = indent(indentLevel, formattedContent, lineSeparator);
formattedContent = removeTrailingReturnsIfNeeded(content, formattedContent);
if (!isLeading)
{
formattedContent = removeLeadingWhiteSpaces(content, formattedContent);
}
actualReplace(selection, content, formattedContent);
}
}
}
catch (BadLocationException e)
{
throw new RuntimeException(e);
}
}
private String removeLeadingWhiteSpaces(String content, String formattedContent)
{
int pos = 0;
for (int a = 0; a < content.length(); a++)
{
char c = content.charAt(a);
if (Character.isWhitespace(c))
{
pos++;
}
else
{
break;
}
}
if (pos > 0)
{
content = content.substring(pos);
}
return content;
}
private String doActualFormat(TextSelection selection, IProject project, ICodeFormatter codeFormatter,
String content, ArrayList languageList, StringBuffer clearedContent, String nestedMark)
{
String formattedContentNotMixed = codeFormatter.format(clearedContent.toString(), true, null, project,
lineSeparator);
for (int a = 0; a < languageList.size(); a++)
{
IParseNode pnode = (IParseNode) languageList.get(a);
int indexOf = formattedContentNotMixed.indexOf(nestedMark);
int iLevel = calcindent(formattedContentNotMixed, indexOf);
String languageContent = formatNode(content, pnode, selection, project);
languageContent = indent(iLevel + 2, languageContent, lineSeparator);
formattedContentNotMixed = formattedContentNotMixed.substring(0, indexOf) + languageContent
+ formattedContentNotMixed.substring(indexOf + nestedMark.length());
}
return formattedContentNotMixed;
}
/**
* @param content
* @param formattedContent
* @return cleared string
*/
public String removeTrailingReturnsIfNeeded(String content, String formattedContent)
{
// Check for carriage return at end of original content
boolean isTrailingOriginal = false;
char charAt = content.charAt(content.length() - 1);
if (charAt == '\r' || charAt == '\n')
{
isTrailingOriginal = true;
}
// Check for carriage return at end of formatted content
boolean isTrailingFormatted = false;
if (formattedContent.length() > 0)
{
char charAt1 = formattedContent.charAt(formattedContent.length() - 1);
if (charAt1 == '\r' || charAt1 == '\n')
{
isTrailingFormatted = true;
}
}
// If old content ends in a carriage return and new content doesn't
if (isTrailingOriginal && !isTrailingFormatted)
{
formattedContent += lineSeparator;
}
if (!isTrailingOriginal && isTrailingFormatted)
{
int pos = formattedContent.length();
for (int a = formattedContent.length() - 1; a > 0; a--)
{
char charAt1 = formattedContent.charAt(a);
if (charAt1 == '\r' || charAt1 == '\n')
{
pos--;
}
else
{
break;
}
}
if (pos != formattedContent.length())
{
formattedContent = formattedContent.substring(0, pos);
}
}
return formattedContent;
}
private int calcLineOffset(String string)
{
int lineOffset = 0;
for (int a = 0; a < string.length(); a++)
{
char c = string.charAt(a);
if (Character.isWhitespace(c))
{
lineOffset++;
}
else
{
break;
}
}
return lineOffset;
}
/**
* returns prefered indentation level for a given offset in document
*
* @param document
* @param lineOfOffset
* @param isHtml
* @return indentation
* @throws BadLocationException
*/
public int calculateIndentation(IDocument document, int lineOfOffset, boolean isHtml) throws BadLocationException
{
int indentLevel;
String string = determineCorrectString(document, lineOfOffset);
indentLevel = 0;
boolean isInLeadingCode = true;
int braceCount = 0;
boolean leading = true;
for (int a = 0; a < string.length(); a++)
{
char c = string.charAt(a);
if (isInLeadingCode && Character.isWhitespace(c))
{
if (c == ' ')
{
indentLevel++;
}
if (c == '\t')
{
indentLevel += tabWitdh;
}
}
else
{
if (c == '{' && !isHtml)
{
braceCount++;
indentLevel += tabWitdh;
leading = false;
}
else if (c == '}' && !isHtml)
{
if (!leading)
{
if (braceCount > 0)
{
indentLevel -= tabWitdh;
braceCount--;
}
}
}
else
{
leading = false;
}
isInLeadingCode = false;
}
}
return indentLevel;
}
/*******************************************************************************************************************
* @param document
* @param lineOfOffset
* @return string
* @throws BadLocationException
*/
public String determineCorrectString(IDocument document, int lineOfOffset) throws BadLocationException
{
String string = ""; //$NON-NLS-1$
boolean inComment = false;
while (lineOfOffset >= 0)
{
IRegion lineInformation = document.getLineInformation(lineOfOffset);
string = document.get(lineInformation.getOffset(), lineInformation.getLength());
if (string.trim().length() == 0)
{
lineOfOffset--;
continue;
}
else
{
if (string.trim().endsWith("*/")) { //$NON-NLS-1$
if (!string.contains("/*")) { //$NON-NLS-1$
inComment = true;
lineOfOffset--;
continue;
}
}
if (!inComment)
{
break;
}
if (string.contains("/*")) { //$NON-NLS-1$
inComment = false;
}
lineOfOffset--;
}
}
if (inComment)
{
string = ""; //$NON-NLS-1$
}
return string;
}
private boolean checkSplitting(LexemeList lexemeList, int selectionStart, int selectionEnd)
{
// get lexeme right before selection
Lexeme lexemeFromOffset = lexemeList.getLexemeFromOffset(selectionStart);
// get lexeme right after selection
Lexeme lexemeFromSelection = lexemeList.getLexemeFromOffset(selectionEnd);
// basically, don't format if the selection cuts through the middle of a
// lexeme, except in HTML
if (lexemeFromOffset != null || lexemeFromSelection != null)
{
// is start of selection HTML. If so, we consider the lexeme not
// split
boolean startSplit = lexemeSplitByOffset(lexemeFromOffset, selectionStart);
// is end of selection HTML. If so, we consider the lexeme not split
boolean endSplit = lexemeSplitByOffset(lexemeFromSelection, selectionEnd);
// do not break lexemes in selection (except HTML)
if (startSplit || endSplit)
{
return false;
}
}
return true;
}
/**
* determines top level language that should be formatted for a selection.
*
* @param selection
* @param document
* @param parseResults
* @param lexemeList
* @return - language
*/
private String determineLanguage(TextSelection selection, IDocument document, IParseNode parseResults,
LexemeList lexemeList)
{
String language = parseResults.getLanguage();
// get lexeme right at selection. There is the case where the selection
// is right at a language
// transition, and we want to ensure that the selection chooses the
// proper parser
Lexeme lexemeFromOffsetStart = lexemeList.getCeilingLexeme(selection.getOffset());
if (lexemeFromOffsetStart != null && !lexemeFromOffsetStart.getLanguage().equals(language)
&& language.equals(TEXT_HTML))
{
language = lexemeFromOffsetStart.getLanguage();
}
// TODO FIX THIS LATER
if (language.equals("text/php")) { //$NON-NLS-1$
String string;
if (selection.getOffset() <= parseResults.getStartingOffset())
{
try
{
string = document.get(parseResults.getStartingOffset(), 3);
}
catch (BadLocationException e)
{
throw new RuntimeException(e);
}
if (string.startsWith("<?")) { //$NON-NLS-1$
language = "text/html"; //$NON-NLS-1$
}
}
}
return language;
}
/**
* Is this lexeme split by the offset? If HTML, we assume no
*
* @param lexeme
* @param offset
* @return - true if split
*/
private boolean lexemeSplitByOffset(Lexeme lexeme, int offset)
{
if (lexeme == null)
{
return false;
}
if (lexeme != null && lexeme.containsOffset(offset) && lexeme.getLanguage().equals(TEXT_HTML))
{
return false;
}
boolean condition = lexeme != null && lexeme.containsOffset(offset) && offset != lexeme.getStartingOffset();
return condition;
}
/**
* Verify that the old content and the new content at least both contain some content
*
* @param oldContent
* @param newContent
* @return - true if content preserved
*/
private boolean verifyContentPreserved(String oldContent, String newContent)
{
Pattern pattern = Pattern.compile("\\S"); //$NON-NLS-1$
Matcher oldMatcher = pattern.matcher(oldContent);
Matcher newMatcher = pattern.matcher(newContent);
// if old content has some non-whitespace content, and new content has
// only whitespace
// we must have deleted something important.
boolean condition = oldMatcher.find() && !newMatcher.find();
return !condition;
}
private IParseNode getSmallestNode(IParseNode parseResults, int offset, int length)
{
if (parseResults.getStartingOffset() <= offset && parseResults.getEndingOffset() >= offset + length)
{
for (int a = 0; a < parseResults.getChildCount(); a++)
{
IParseNode child = parseResults.getChild(a);
IParseNode smallestNode = getSmallestNode(child, offset, length);
if (smallestNode != null)
{
return smallestNode;
}
}
return parseResults;
}
return null;
}
private int calcindent(String formattedContentNotMixed, int indexOf)
{
int pos = 0;
for (int a = indexOf - 1; a >= 0; a--)
{
pos++;
char charAt = formattedContentNotMixed.charAt(a);
if (charAt == '\n')
{
break;
}
if (charAt == '\r')
{
break;
}
}
return pos;
}
/**
* indents string
*
* @param level
* @param languageContent
* @param lineSeparator
* @return indented string
*/
public String indent(int level, String languageContent, String lineSeparator)
{
if (lineSeparator == null)
{
return languageContent;
}
String[] split = languageContent.split(lineSeparator);
SourceWriter result = new SourceWriter(level, tabChar, tabWitdh);
if (split.length == 1)
{
result.printIndent();
result.print(split[0]);
return result.toString();
}
for (int a = 0; a < split.length; a++)
{
result.printlnWithIndent(split[a]);
}
return result.toString();
}
private String formatNode(String content, IParseNode pnode, TextSelection selection, IProject project)
{
int start = selection == null ? pnode.getStartingOffset() : pnode.getStartingOffset() - selection.getOffset();
int end = selection == null ? pnode.getEndingOffset() : pnode.getEndingOffset() - selection.getOffset();
String nodeContent = content.substring(start, end);
ICodeFormatter codeFormatter = LanguageRegistry.getCodeFormatter(pnode.getLanguage());
if (codeFormatter != null)
{
String formattedContent = codeFormatter.format(nodeContent, false, null, project, lineSeparator).trim();
return formattedContent;
}
return nodeContent;
}
private void actualReplace(TextSelection selection, String content, String formattedContent)
{
try
{
// If we somehow removed all content, don't format
if (!verifyContentPreserved(content, formattedContent))
{
IdeLog
.logError(
UnifiedEditorsPlugin.getDefault(),
StringUtils
.format(
"Format failed and removed non-whitespace content. old \"{0}\", new \"{1}\"", new String[] { content, formattedContent })); //$NON-NLS-1$
return;
}
int offset = 0;
if (selection.getLength() != 0)
{
offset = selection.getOffset();
}
IDocument document = part.getViewer().getDocument();
if (document.get(offset, content.length()).equals(formattedContent))
{
return;
}
part.getViewer().getTextWidget().setRedraw(false);
document.replace(offset, content.length(), formattedContent);
part.getViewer().setSelectedRange(selection.getOffset(), 0);
part.getViewer().getTextWidget().setRedraw(true);
}
catch (BadLocationException e)
{
}
}
private void checkNodes(ArrayList languageList, IParseNode parseResults)
{
for (int a = 0; a < parseResults.getChildCount(); a++)
{
IParseNode child = parseResults.getChild(a);
if (child.getLanguage().equals(parseResults.getLanguage()))
{
checkNodes(languageList, child);
}
else
{
if (child.getStartingOffset() != -1 && child.getEndingOffset() != -1)
{
languageList.add(child);
}
}
}
}
/**
* @see org.eclipse.ui.IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction,
* org.eclipse.ui.IEditorPart)
*/
public void setActiveEditor(IAction action, IEditorPart targetEditor)
{
part = (IUnifiedEditor) targetEditor;
if (part != null && part.getViewer() != null && part.getViewer().getDocument() != null)
{
String[] legalLineDelimiters = part.getViewer().getDocument().getLegalLineDelimiters();
if (legalLineDelimiters != null && legalLineDelimiters.length > 0)
{
this.lineSeparator = legalLineDelimiters[0];
}
}
}
/**
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
public void run(IAction action)
{
}
/**
* @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
*/
public void dispose()
{
// do nothing
}
/**
* @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow)
*/
public void init(IWorkbenchWindow window)
{
// do nothing
}
/**
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction,
* org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IAction action, ISelection selection)
{
// do nothing
}
}