Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 7625 Details for
Bug 40255
Ant formatter
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
ant formatter, first cut
patch.txt (text/plain), 78.19 KB, created by
John-Mason P. Shackelford
on 2004-01-29 04:14:40 EST
(
hide
)
Description:
ant formatter, first cut
Filename:
MIME Type:
Creator:
John-Mason P. Shackelford
Created:
2004-01-29 04:14:40 EST
Size:
78.19 KB
patch
obsolete
>Index: .project >=================================================================== >retrieving revision 1.17 >diff -u -r1.17 .project >--- .project 9 Jan 2004 23:40:25 -0000 1.17 >+++ .project 29 Jan 2004 08:47:30 -0000 >@@ -10,7 +10,6 @@ > <project>org.eclipse.core.variables</project> > <project>org.eclipse.debug.core</project> > <project>org.eclipse.debug.ui</project> >- <project>org.eclipse.jdt.debug.ui</project> > <project>org.eclipse.jdt.launching</project> > <project>org.eclipse.jface.text</project> > <project>org.eclipse.ui</project> >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java >=================================================================== >retrieving revision 1.14 >diff -u -r1.14 AntEditor.java >--- Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java 23 Jan 2004 00:43:36 -0000 1.14 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java 29 Jan 2004 08:47:34 -0000 >@@ -16,6 +16,8 @@ > > import java.util.ResourceBundle; > >+import org.eclipse.ant.internal.ui.editor.model.AntElementNode; >+import org.eclipse.ant.internal.ui.editor.model.IAntEditorConstants; > import org.eclipse.ant.internal.ui.editor.outline.AntEditorContentOutlinePage; > import org.eclipse.ant.internal.ui.editor.outline.AntModel; > import org.eclipse.ant.internal.ui.editor.outline.XMLCore; >@@ -26,6 +28,7 @@ > import org.eclipse.ant.internal.ui.model.AntUIPlugin; > import org.eclipse.ant.internal.ui.model.IAntUIHelpContextIds; > import org.eclipse.core.runtime.CoreException; >+import org.eclipse.jface.action.IAction; > import org.eclipse.jface.text.source.IAnnotationAccess; > import org.eclipse.jface.text.source.IOverviewRuler; > import org.eclipse.jface.text.source.ISourceViewer; >@@ -46,6 +49,7 @@ > import org.eclipse.ui.texteditor.IDocumentProvider; > import org.eclipse.ui.texteditor.IEditorStatusLine; > import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; >+import org.eclipse.ui.texteditor.TextOperationAction; > import org.eclipse.ui.views.contentoutline.IContentOutlinePage; > > /** >@@ -114,11 +118,14 @@ > protected void createActions() { > super.createActions(); > >- ContentAssistAction action = new ContentAssistAction(ResourceBundle.getBundle("org.eclipse.ant.internal.ui.editor.AntEditorMessages"), "ContentAssistProposal.", this); //$NON-NLS-1$ //$NON-NLS-2$ >- >+ ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.ant.internal.ui.editor.AntEditorMessages"); //$NON-NLS-1$ >+ IAction action = new ContentAssistAction(bundle, "ContentAssistProposal.", this); //$NON-NLS-1$ > // This action definition is associated with the accelerator Ctrl+Space > action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); > setAction("ContentAssistProposal", action); //$NON-NLS-1$ >+ >+ action = new TextOperationAction(bundle,"ContentFormatProposal.",this,ISourceViewer.FORMAT); //$NON-NLS-1$ >+ setAction("ContentFormatProposal", action); //$NON-NLS-1$ > } > > /* >@@ -218,7 +225,7 @@ > if (!moveCursor) { > return; > } >- >+ > if (offset > -1 && length > 0) { > sourceViewer.revealRange(offset, length); > // Selected region begins one index after offset >@@ -281,7 +288,7 @@ > } > } > } >- >+ > /** > * Returns the Ant model for the current editor input of this editor. > * @return the Ant model for this editor or <code>null</code> >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorActionContributor.java >=================================================================== >retrieving revision 1.1 >diff -u -r1.1 AntEditorActionContributor.java >--- Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorActionContributor.java 29 Aug 2003 18:16:32 -0000 1.1 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorActionContributor.java 29 Jan 2004 08:47:34 -0000 >@@ -17,7 +17,6 @@ > import java.util.ResourceBundle; > > import org.eclipse.jface.action.IMenuManager; >-import org.eclipse.ui.IActionBars; > import org.eclipse.ui.IEditorPart; > import org.eclipse.ui.IWorkbenchActionConstants; > import org.eclipse.ui.editors.text.TextEditorActionContributor; >@@ -32,56 +31,54 @@ > public class AntEditorActionContributor extends TextEditorActionContributor { > > protected RetargetTextEditorAction fContentAssistProposal; >-// protected RetargetTextEditorAction fContentAssistTip; >- >+ protected RetargetTextEditorAction fContentFormatProposal; >+ > /** > * Default constructor. > */ > public AntEditorActionContributor() { > super(); >- fContentAssistProposal= new RetargetTextEditorAction(ResourceBundle.getBundle("org.eclipse.ant.internal.ui.editor.AntEditorMessages"), "ContentAssistProposal."); //$NON-NLS-1$ //$NON-NLS-2$ >-// fContentAssistTip= new RetargetTextEditor(ResourceBundle.getBundle("org.eclipse.ant.internal.ui.editor.AntEditorMessages"), "ContentAssistTip."); //$NON-NLS-1$ >+ ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.ant.internal.ui.editor.AntEditorMessages"); //$NON-NLS-1$ >+ fContentAssistProposal = new RetargetTextEditorAction(bundle, "ContentAssistProposal."); //$NON-NLS-1$ >+ fContentFormatProposal = new RetargetTextEditorAction(bundle, "ContentFormatProposal."); //$NON-NLS-1$ > } >- >- private void doSetActiveEditor(IEditorPart part) { >- super.setActiveEditor(part); >- >- ITextEditor editor= null; >- if (part instanceof ITextEditor) >- editor= (ITextEditor) part; >- >- fContentAssistProposal.setAction(getAction(editor, "ContentAssistProposal")); //$NON-NLS-1$ >-// fContentAssistTip.setAction(getAction(editor, "ContentAssistTip")); //$NON-NLS-1$ >- } >- >- /* >- * @see IEditorActionBarContributor#init(IActionBars) >- */ >- public void init(IActionBars bars) { >- super.init(bars); >- >- IMenuManager menuManager= bars.getMenuManager(); >- IMenuManager editMenu= menuManager.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); >- if (editMenu != null) { >- editMenu.add(new org.eclipse.jface.action.Separator()); >- editMenu.add(fContentAssistProposal); >-// editMenu.add(fContentAssistTip); >- } >- >- } >- >+ > /* > * @see IEditorActionBarContributor#setActiveEditor(IEditorPart) > */ > public void setActiveEditor(IEditorPart part) { >- doSetActiveEditor(part); >+ super.setActiveEditor(part); >+ >+ ITextEditor editor= null; >+ if (part instanceof ITextEditor) >+ editor= (ITextEditor) part; >+ >+ fContentAssistProposal.setAction(getAction(editor, "ContentAssistProposal")); //$NON-NLS-1$ >+ fContentFormatProposal.setAction(getAction(editor, "ContentFormatProposal")); //$NON-NLS-1$ >+ >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.ui.part.EditorActionBarContributor#contributeToMenu(org.eclipse.jface.action.IMenuManager) >+ */ >+ public void contributeToMenu(IMenuManager menu) { >+ super.contributeToMenu(menu); >+ >+ IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); >+ if (editMenu != null) { >+ editMenu.add(new org.eclipse.jface.action.Separator()); >+ editMenu.add(fContentAssistProposal); >+ editMenu.add(fContentFormatProposal); >+ } > } > > /* > * @see IEditorActionBarContributor#dispose() > */ > public void dispose() { >- doSetActiveEditor(null); >+ setActiveEditor(null); > super.dispose(); > } >+ >+ > } >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorMessages.properties >=================================================================== >retrieving revision 1.3 >diff -u -r1.3 AntEditorMessages.properties >--- Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorMessages.properties 22 Jan 2004 13:32:07 -0000 1.3 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorMessages.properties 29 Jan 2004 08:47:34 -0000 >@@ -14,6 +14,11 @@ > ContentAssistProposal.image= > ContentAssistProposal.description=Content Assist > >+ContentFormatProposal.label=Format XML >+ContentFormatProposal.tooltip=Format build file source >+ContentFormatProposal.image= >+ContentFormatProposal.description=Format build file source >+ > AntEditorCompletionProcessor.Required___4=Required: > AntEditorCompletionProcessor.28=No attribute completions available > AntEditorCompletionProcessor.29=No task completions available >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorSourceViewerConfiguration.java >=================================================================== >retrieving revision 1.5 >diff -u -r1.5 AntEditorSourceViewerConfiguration.java >--- Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorSourceViewerConfiguration.java 23 Jan 2004 00:40:34 -0000 1.5 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditorSourceViewerConfiguration.java 29 Jan 2004 08:47:34 -0000 >@@ -15,6 +15,8 @@ > package org.eclipse.ant.internal.ui.editor; > > import org.eclipse.ant.internal.ui.editor.derived.HTMLTextPresenter; >+import org.eclipse.ant.internal.ui.editor.format.XmlDocumentFormattingStrategy; >+import org.eclipse.ant.internal.ui.editor.format.XmlElementFormattingStrategy; > import org.eclipse.ant.internal.ui.editor.text.AntEditorPartitionScanner; > import org.eclipse.ant.internal.ui.editor.text.AntEditorProcInstrScanner; > import org.eclipse.ant.internal.ui.editor.text.AntEditorTagScanner; >@@ -37,6 +39,10 @@ > import org.eclipse.jface.text.TextAttribute; > import org.eclipse.jface.text.contentassist.ContentAssistant; > import org.eclipse.jface.text.contentassist.IContentAssistant; >+import org.eclipse.jface.text.formatter.ContentFormatter2; >+import org.eclipse.jface.text.formatter.ContentFormatter3; >+import org.eclipse.jface.text.formatter.IContentFormatter; >+import org.eclipse.jface.text.formatter.IFormattingStrategy; > import org.eclipse.jface.text.presentation.IPresentationReconciler; > import org.eclipse.jface.text.presentation.PresentationReconciler; > import org.eclipse.jface.text.reconciler.IReconciler; >@@ -257,4 +263,21 @@ > } > } > } >+ /* (non-Javadoc) >+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getContentFormatter(org.eclipse.jface.text.source.ISourceViewer) >+ */ >+ public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) { >+ >+ ContentFormatter3 formatter = new ContentFormatter3(); >+ formatter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); >+ >+ IFormattingStrategy indentationStrategy = new XmlDocumentFormattingStrategy(sourceViewer); >+ IFormattingStrategy elementFormattingStrategy = new XmlElementFormattingStrategy(sourceViewer); >+ >+ formatter.setFormattingStrategy(indentationStrategy); >+ formatter.setFormattingStrategy(indentationStrategy,IDocument.DEFAULT_CONTENT_TYPE); >+ formatter.setFormattingStrategy(elementFormattingStrategy,AntEditorPartitionScanner.XML_TAG); >+ >+ return formatter; >+ } > } >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/format/FormattingPreferences.java >=================================================================== >RCS file: Ant Editor/org/eclipse/ant/internal/ui/editor/format/FormattingPreferences.java >diff -N Ant Editor/org/eclipse/ant/internal/ui/editor/format/FormattingPreferences.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/format/FormattingPreferences.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,74 @@ >+/* >+ * Created on Jan 29, 2004 >+ * >+ * To change the template for this generated file go to Window - Preferences - >+ * Java - Code Generation - Code and Comments >+ */ >+package org.eclipse.ant.internal.ui.editor.format; >+ >+/** >+ * >+ */ >+public class FormattingPreferences { >+ private String canonicalIndent; >+ >+ private boolean useTabs; >+ >+ private int tabWitdth; >+ >+ private int printMargin; >+ >+ private boolean useElementWrapping; >+ >+ /** >+ * @return >+ */ >+ public String getCanonicalIndent() { >+ if (this.canonicalIndent == null) { >+ if (this.useTabs) { >+ this.canonicalIndent = "\t"; >+ } else { >+ String tab = ""; >+ for (int i = 0; i < this.tabWitdth; i++) { >+ tab = tab.concat(" "); >+ } >+ this.canonicalIndent = tab; >+ } >+ } >+ return this.canonicalIndent; >+ } >+ >+ // TODO connect to ant preferences and remove this method (?) >+ public void useHorizontalTabs() { >+ this.useTabs = true; >+ } >+ >+ // TODO connect to ant preferences and remove this method (?) >+ public void useSpacesForTab(int tabWidth) { >+ this.useTabs = false; >+ this.tabWitdth = tabWidth; >+ } >+ >+ // TODO connect to ant preferences and remove this method (?) >+ public void setPrintMargin(int column) { >+ this.printMargin = column; >+ } >+ /** >+ * @return Returns the printMargin. >+ */ >+ public int getPrintMargin() { >+ return this.printMargin; >+ } >+ >+ /** >+ * @return >+ */ >+ public boolean useElementWrapping() { >+ return this.useElementWrapping; >+ } >+ >+ // TODO connect to ant preferences and remove this method (?) >+ public void setUseElementWrapping(boolean useElementWrapping) { >+ this.useElementWrapping = useElementWrapping; >+ } >+} >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/format/NonParsingXMLFormatter.java >=================================================================== >RCS file: Ant Editor/org/eclipse/ant/internal/ui/editor/format/NonParsingXMLFormatter.java >diff -N Ant Editor/org/eclipse/ant/internal/ui/editor/format/NonParsingXMLFormatter.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/format/NonParsingXMLFormatter.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,431 @@ >+/* >+ * Created on Jan 28, 2004 >+ * >+ * To change the template for this generated file go to Window - Preferences - >+ * Java - Code Generation - Code and Comments >+ */ >+package org.eclipse.ant.internal.ui.editor.format; >+ >+import java.io.IOException; >+import java.io.Reader; >+import java.io.StringReader; >+ >+import org.eclipse.jface.text.Assert; >+ >+/** >+ * @author shacj >+ * >+ * To change the template for this generated type comment go to Window - >+ * Preferences - Java - Code Generation - Code and Comments >+ */ >+public class NonParsingXMLFormatter { >+ >+ private static class CommentReader extends TagReader { >+ >+ private boolean complete = false; >+ >+ protected void clear() { >+ this.complete = false; >+ } >+ >+ public String getStartOfTag() { >+ return "<!--"; >+ } >+ >+ protected String readTag() throws IOException { >+ int intChar; >+ char c; >+ StringBuffer node = new StringBuffer(); >+ >+ while (!complete && (intChar = reader.read()) != -1) { >+ c = (char) intChar; >+ >+ node.append(c); >+ >+ if (c == '>' && node.toString().endsWith("-->")) { >+ complete = true; >+ } >+ } >+ return node.toString(); >+ } >+ } >+ >+ private static class DoctypeDeclarationReader extends TagReader { >+ >+ private boolean complete = false; >+ >+ protected void clear() { >+ this.complete = false; >+ } >+ >+ public String getStartOfTag() { >+ return "<!"; >+ } >+ >+ protected String readTag() throws IOException { >+ int intChar; >+ char c; >+ StringBuffer node = new StringBuffer(); >+ >+ while (!complete && (intChar = reader.read()) != -1) { >+ c = (char) intChar; >+ >+ node.append(c); >+ >+ if (c == '>') { >+ complete = true; >+ } >+ } >+ return node.toString(); >+ } >+ >+ } >+ >+ private static class ProcessingInstructionReader extends TagReader { >+ >+ private boolean complete = false; >+ >+ protected void clear() { >+ this.complete = false; >+ } >+ >+ public String getStartOfTag() { >+ return "<?"; >+ } >+ >+ protected String readTag() throws IOException { >+ int intChar; >+ char c; >+ StringBuffer node = new StringBuffer(); >+ >+ while (!complete && (intChar = reader.read()) != -1) { >+ c = (char) intChar; >+ >+ node.append(c); >+ >+ if (c == '>' && node.toString().endsWith("?>")) { >+ complete = true; >+ } >+ } >+ return node.toString(); >+ } >+ } >+ >+ /** >+ * >+ */ >+ private static abstract class TagReader { >+ >+ protected Reader reader; >+ >+ private String tagText; >+ >+ protected abstract void clear(); >+ >+ public int getPostTagDepthModifier() { >+ return 0; >+ } >+ >+ public int getPreTagDepthModifier() { >+ return 0; >+ } >+ >+ abstract public String getStartOfTag(); >+ >+ public String getTagText() { >+ return this.tagText; >+ } >+ >+ public boolean isTextNode() { >+ return false; >+ } >+ >+ protected abstract String readTag() throws IOException; >+ >+ public boolean requiresInitialIndent() { >+ return true; >+ } >+ >+ public void setReader(Reader reader) throws IOException { >+ this.reader = reader; >+ this.clear(); >+ this.tagText = readTag(); >+ } >+ >+ public boolean startsOnNewline() { >+ return true; >+ } >+ >+ } >+ >+ /** >+ * >+ */ >+ private static class TagReaderFactory { >+ >+ // Warning: the order of the Array is important! >+ private static TagReader[] tagReaders = new TagReader[]{new CommentReader(), >+ new DoctypeDeclarationReader(), >+ new ProcessingInstructionReader(), >+ new XmlElementReader()}; >+ >+ private static TagReader textNodeReader = new TextReader(); >+ >+ public static TagReader createTagReaderFor(Reader reader) >+ throws IOException { >+ >+ char[] buf = new char[10]; >+ reader.mark(10); >+ reader.read(buf, 0, 10); >+ reader.reset(); >+ >+ String startOfTag = String.valueOf(buf); >+ >+ for (int i = 0; i < tagReaders.length; i++) { >+ if (startOfTag.startsWith(tagReaders[i].getStartOfTag())) { >+ tagReaders[i].setReader(reader); >+ return tagReaders[i]; >+ } >+ } >+ // else >+ textNodeReader.setReader(reader); >+ return textNodeReader; >+ >+ } >+ >+ } >+ >+ private static class TextReader extends TagReader { >+ >+ private boolean complete; >+ >+ private boolean isTextNode; >+ >+ protected void clear() { >+ this.complete = false; >+ } >+ >+ public String getStartOfTag() { >+ return ""; >+ } >+ >+ public boolean isTextNode() { >+ return this.isTextNode; >+ } >+ >+ protected String readTag() throws IOException { >+ >+ StringBuffer node = new StringBuffer(); >+ >+ while (!complete) { >+ >+ reader.mark(1); >+ int intChar = reader.read(); >+ if (intChar == -1) break; >+ >+ char c = (char) intChar; >+ if (c == '<') { >+ reader.reset(); >+ complete = true; >+ } else { >+ node.append(c); >+ } >+ } >+ >+ // if this text node is just whitespace >+ // remove it, except for the newlines. >+ if (node.length() < 1) { >+ this.isTextNode = false; >+ >+ } else if (node.toString().trim().length() == 0) { >+ String whitespace = node.toString(); >+ node = new StringBuffer(); >+ for (int i = 0; i < whitespace.length(); i++) { >+ char whitespaceCharacter = whitespace.charAt(i); >+ if (whitespaceCharacter == '\n') >+ node.append(whitespaceCharacter); >+ } >+ this.isTextNode = false; >+ >+ } else { >+ this.isTextNode = true; >+ } >+ return node.toString(); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.ant.internal.ui.editor.format.NonParsingXMLFormatter.TagReader#requiresInitialIndent() >+ */ >+ public boolean requiresInitialIndent() { >+ return false; >+ } >+ >+ public boolean startsOnNewline() { >+ return false; >+ } >+ } >+ >+ private static class XmlElementReader extends TagReader { >+ >+ private boolean complete = false; >+ >+ protected void clear() { >+ this.complete = false; >+ } >+ >+ public int getPostTagDepthModifier() { >+ if (getTagText().endsWith("/>") || getTagText().endsWith("/ >")) { >+ return 0; >+ } else if (getTagText().startsWith("</")) { >+ return 0; >+ } else { >+ return +1; >+ } >+ } >+ >+ public int getPreTagDepthModifier() { >+ if (getTagText().startsWith("</")) { >+ return -1; >+ } else { >+ return 0; >+ } >+ >+ } >+ >+ public String getStartOfTag() { >+ return "<"; >+ } >+ >+ protected String readTag() throws IOException { >+ >+ StringBuffer node = new StringBuffer(); >+ >+ boolean insideQuote = false; >+ int intChar; >+ >+ while (!complete && (intChar = reader.read()) != -1) { >+ char c = (char) intChar; >+ >+ node.append(c); >+ >+ if (c == '"') { >+ insideQuote = !insideQuote; >+ } >+ if (c == '>' && !insideQuote) { >+ complete = true; >+ } >+ } >+ return node.toString(); >+ } >+ } >+ >+ private int depth; >+ >+ private String documentText; >+ >+ private StringBuffer formattedXml; >+ >+ private boolean lastNodeWasText; >+ >+ private FormattingPreferences prefs; >+ >+ /** >+ * @param reader >+ * @param out >+ * @throws IOException >+ */ >+ private void copyNode(Reader reader, StringBuffer out) throws IOException { >+ >+ TagReader tag = TagReaderFactory.createTagReaderFor(reader); >+ >+ depth = depth + tag.getPreTagDepthModifier(); >+ >+ if (!lastNodeWasText) { >+ >+ if (tag.startsOnNewline() && !hasNewlineAlready(out)) { >+ out.append("\n"); >+ } >+ >+ if (tag.requiresInitialIndent()) { >+ out.append(indent()); >+ } >+ } >+ >+ out.append(tag.getTagText()); >+ >+ depth = depth + tag.getPostTagDepthModifier(); >+ >+ lastNodeWasText = tag.isTextNode(); >+ >+ } >+ >+ /** >+ * @return >+ */ >+ public String format() { >+ >+ Assert.isNotNull(this.documentText); >+ Assert.isNotNull(this.prefs); >+ >+ Reader reader = new StringReader(documentText); >+ formattedXml = new StringBuffer(); >+ >+ depth = 0; >+ lastNodeWasText = false; >+ try { >+ while (true) { >+ reader.mark(1); >+ int intChar = reader.read(); >+ reader.reset(); >+ >+ if (intChar != -1) { >+ copyNode(reader, formattedXml); >+ } else { >+ break; >+ } >+ } >+ reader.close(); >+ } catch (IOException e) { >+ // TODO Auto-generated catch block >+ e.printStackTrace(); >+ } >+ return formattedXml.toString(); >+ } >+ >+ /** >+ * @param out >+ * @return >+ */ >+ private boolean hasNewlineAlready(StringBuffer out) { >+ return out.lastIndexOf("\n") == formattedXml.length() - 1 >+ || out.lastIndexOf("\r") == formattedXml.length() - 1; >+ } >+ >+ /** >+ * @return >+ */ >+ private String indent() { >+ StringBuffer indent = new StringBuffer(30); >+ for (int i = 0; i < depth; i++) { >+ indent.append(prefs.getCanonicalIndent()); >+ } >+ return indent.toString(); >+ } >+ >+ /** >+ * @param prefs >+ */ >+ public void setFormattingPreferences(FormattingPreferences prefs) { >+ this.prefs = prefs; >+ } >+ >+ /** >+ * @param documentText >+ */ >+ public void setText(String documentText) { >+ this.documentText = documentText; >+ } >+ >+} >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlDocumentFormattingStrategy.java >=================================================================== >RCS file: Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlDocumentFormattingStrategy.java >diff -N Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlDocumentFormattingStrategy.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlDocumentFormattingStrategy.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,151 @@ >+/* >+ * Created on Jan 17, 2004 >+ * >+ * To change the template for this generated file go to Window - Preferences - >+ * Java - Code Generation - Code and Comments >+ */ >+package org.eclipse.ant.internal.ui.editor.format; >+ >+import java.util.LinkedList; >+ >+import javax.xml.parsers.ParserConfigurationException; >+import javax.xml.parsers.SAXParser; >+import javax.xml.parsers.SAXParserFactory; >+ >+import org.eclipse.ant.internal.ui.model.AntUIPlugin; >+import org.eclipse.jface.text.Assert; >+import org.eclipse.jface.text.BadLocationException; >+import org.eclipse.jface.text.IDocument; >+import org.eclipse.jface.text.TypedPosition; >+import org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy; >+import org.eclipse.jface.text.formatter.FormattingContext; >+import org.eclipse.jface.text.formatter.FormattingContextProperties; >+import org.eclipse.jface.text.formatter.IFormattingContext; >+import org.eclipse.jface.text.source.ISourceViewer; >+import org.xml.sax.SAXException; >+ >+/** >+ * @author shacj >+ * >+ * To change the template for this generated type comment go to Window - >+ * Preferences - Java - Code Generation - Code and Comments >+ */ >+public class XmlDocumentFormattingStrategy extends >+ ContextBasedFormattingStrategy { >+ >+ /** Indentations to use by this strategy */ >+ private final LinkedList fIndentations = new LinkedList(); >+ >+ /** Partitions to be formatted by this strategy */ >+ private final LinkedList fPartitions = new LinkedList(); >+ >+ /** The position sets to keep track of during formatting */ >+ private final LinkedList fPositions = new LinkedList(); >+ >+ // TODO connect with preferences >+ private final boolean addNewlines = true; >+ >+ // TODO connect with preferences >+ private final String canonicalIndentStep = "\t"; >+ >+ /** >+ * @param viewer >+ */ >+ public XmlDocumentFormattingStrategy(ISourceViewer viewer) { >+ super(viewer); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.text.formatter.IFormattingStrategy#format(java.lang.String, >+ * boolean, java.lang.String, int[]) >+ */ >+ public void format() { >+ >+ super.format(); >+ >+ Assert.isLegal(fPartitions.size() > 0); >+ Assert.isLegal(fIndentations.size() > 0); >+ >+ final TypedPosition partition = (TypedPosition) fPartitions >+ .removeFirst(); >+ final String indent = fIndentations.removeFirst().toString(); >+ final IDocument document = getViewer().getDocument(); >+ >+ // Since we are running short on time, we'll >+ // format the whole document, not just a single partition. >+ // We can correct this later--if we want to. >+ >+ String documentText = document.get(); >+ >+ // setup formatter with preferences and format the text. >+ // TODO connect with ant preferences ui >+ FormattingPreferences prefs = new FormattingPreferences(); >+ prefs.useSpacesForTab(4); >+ >+ NonParsingXMLFormatter formatter = new NonParsingXMLFormatter(); >+ formatter.setText(documentText); >+ formatter.setFormattingPreferences(prefs); >+ >+ String formattedText = formatter.format(); >+ if(formattedText != null && ! formattedText.equals(documentText)) { >+ document.set(formattedText); >+ } >+ >+ >+ } >+ >+ private boolean partitionsShareLine(IDocument document, >+ TypedPosition partition1, TypedPosition partition2) >+ throws BadLocationException { >+ >+ Assert.isNotNull(document); >+ Assert.isNotNull(partition1); >+ Assert.isNotNull(partition2); >+ >+ int lineNumber1 = document.getLineOfOffset(partition1.getOffset()); >+ int lineNumber2 = document.getLineOfOffset(partition2.getOffset()); >+ return lineNumber1 == lineNumber2; >+ } >+ >+ /* >+ * @see org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy#formatterStarts(org.eclipse.jface.text.formatter.IFormattingContext) >+ */ >+ public void formatterStarts(IFormattingContext context) { >+ super.formatterStarts(context); >+ >+ final FormattingContext current = (FormattingContext) context; >+ >+ fIndentations.addLast(current >+ .getProperty(FormattingContextProperties.CONTEXT_INDENTATION)); >+ fPartitions.addLast(current >+ .getProperty(FormattingContextProperties.CONTEXT_PARTITION)); >+ fPositions.addLast(current >+ .getProperty(FormattingContextProperties.CONTEXT_POSITIONS)); >+ >+ } >+ >+ /* >+ * @see org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy#formatterStops() >+ */ >+ public void formatterStops() { >+ super.formatterStops(); >+ >+ fIndentations.clear(); >+ fPartitions.clear(); >+ fPositions.clear(); >+ } >+ >+ private SAXParser getSAXParser() { >+ SAXParser parser = null; >+ try { >+ parser = SAXParserFactory.newInstance().newSAXParser(); >+ } catch (ParserConfigurationException e) { >+ AntUIPlugin.log(e); >+ } catch (SAXException e) { >+ AntUIPlugin.log(e); >+ } >+ return parser; >+ } >+} >Index: Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlElementFormattingStrategy.java >=================================================================== >RCS file: Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlElementFormattingStrategy.java >diff -N Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlElementFormattingStrategy.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Ant Editor/org/eclipse/ant/internal/ui/editor/format/XmlElementFormattingStrategy.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,260 @@ >+/* >+ * Created on Jan 17, 2004 >+ * >+ * To change the template for this generated file go to Window - Preferences - >+ * Java - Code Generation - Code and Comments >+ */ >+package org.eclipse.ant.internal.ui.editor.format; >+ >+import java.util.ArrayList; >+import java.util.LinkedList; >+import java.util.List; >+ >+import org.eclipse.jface.text.Assert; >+import org.eclipse.jface.text.BadLocationException; >+import org.eclipse.jface.text.IDocument; >+import org.eclipse.jface.text.IRegion; >+import org.eclipse.jface.text.TypedPosition; >+import org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy; >+import org.eclipse.jface.text.formatter.FormattingContext; >+import org.eclipse.jface.text.formatter.FormattingContextProperties; >+import org.eclipse.jface.text.formatter.IFormattingContext; >+import org.eclipse.jface.text.source.ISourceViewer; >+ >+/** >+ * @author shacj >+ * >+ * To change the template for this generated type comment go to Window - >+ * Preferences - Java - Code Generation - Code and Comments >+ */ >+public class XmlElementFormattingStrategy extends >+ ContextBasedFormattingStrategy { >+ >+ /** Indentations to use by this strategy */ >+ private final LinkedList fIndentations = new LinkedList(); >+ >+ /** Partitions to be formatted by this strategy */ >+ private final LinkedList fPartitions = new LinkedList(); >+ >+ /** The position sets to keep track of during formatting */ >+ private final LinkedList fPositions = new LinkedList(); >+ >+ /** >+ * @param viewer >+ */ >+ public XmlElementFormattingStrategy(ISourceViewer viewer) { >+ super(viewer); >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.text.formatter.IFormattingStrategy#format(java.lang.String, >+ * boolean, java.lang.String, int[]) >+ */ >+ public void format() { >+ >+ super.format(); >+ >+ Assert.isLegal(fPartitions.size() > 0); >+ Assert.isLegal(fIndentations.size() > 0); >+ >+ final TypedPosition partition = (TypedPosition) fPartitions >+ .removeFirst(); >+ final String lineIndent = fIndentations.removeFirst().toString(); >+ final IDocument document = getViewer().getDocument(); >+ >+ try { >+ >+ // TODO connect to preferences >+ FormattingPreferences prefs = new FormattingPreferences(); >+ prefs.useSpacesForTab(4); >+ prefs.setPrintMargin(80); >+ prefs.setUseElementWrapping(true); >+ >+ String formatted = formatElement(document, partition, lineIndent, >+ prefs); >+ >+ String partitionText = document.get(partition.getOffset(), >+ partition.getLength()); >+ >+ if (formatted != null && !formatted.equals(partitionText)) >+ document.replace(partition.getOffset(), partition >+ .getLength(), formatted); >+ >+ } catch (BadLocationException e) { >+ // TODO Auto-generated catch block >+ e.printStackTrace(); >+ } >+ >+ } >+ >+ /** >+ * @param partitionText >+ * @param prefs >+ * @return >+ */ >+ private String formatElement(IDocument document, TypedPosition partition, >+ String indentation, FormattingPreferences prefs) >+ throws BadLocationException { >+ >+ final String partitionText = document.get(partition.getOffset(), >+ partition.getLength()); >+ >+ StringBuffer formattedElement = null; >+ >+ // do we even need to think about wrapping? >+ if (prefs.useElementWrapping() && !partitionText.startsWith("</")) { >+ >+ final IRegion line = document.getLineInformationOfOffset(partition >+ .getOffset()); >+ >+ final int partitionLineOffset = partition.getOffset() >+ - line.getOffset(); >+ >+ // do we have a good candidate for a wrap? >+ if (line.getLength() > prefs.getPrintMargin()) { >+ >+ List attributes = getAttributes(partitionText); >+ if (attributes.size() > 1) { >+ formattedElement = new StringBuffer(); >+ String startTag = elementStart(partitionText); >+ formattedElement.append(startTag); >+ formattedElement.append(' '); >+ formattedElement.append(attributes.get(0)); >+ formattedElement.append("\n"); >+ >+ for (int i = 1; i < attributes.size(); i++) { >+ formattedElement.append(indentation); >+ for (int j = 0; j < (partitionLineOffset - indentation >+ .length()) >+ + startTag.length() + 1; j++) { >+ formattedElement.append(' '); >+ } >+ formattedElement.append(attributes.get(i)); >+ formattedElement.append("\n"); >+ } >+ formattedElement.append(indentation); >+ for (int j = 0; j < (partitionLineOffset - indentation >+ .length()) + 1; j++) { >+ formattedElement.append(' '); >+ } >+ if (partitionText.endsWith("/>")) { >+ formattedElement.append("/>"); >+ } else if (partitionText.endsWith(">")) { >+ formattedElement.append(">"); >+ } else { >+ Assert.isTrue(false, "Bad Partitioner."); >+ } >+ } >+ } >+ } >+ return formattedElement != null ? formattedElement.toString() : null; >+ } >+ >+ /** >+ * @param partitionText >+ * @return >+ */ >+ private List getAttributes(String text) { >+ >+ List attributes = new ArrayList(); >+ >+ int start = firstWhitespaceIn(text); >+ boolean insideQuotes = false; >+ >+ boolean haveEquals = false; >+ int quotes = 0; >+ StringBuffer attributePair = new StringBuffer(); >+ >+ for (int i = start; i < text.length(); i++) { >+ char c = text.charAt(i); >+ switch (c) { >+ case '"': >+ insideQuotes = !insideQuotes; >+ quotes++; >+ attributePair.append(c); >+ if (!insideQuotes && haveEquals && quotes == 2) { >+ // we're done with this attribute >+ attributes.add(attributePair.toString()); >+ // reset >+ attributePair = new StringBuffer(); >+ quotes = 0; >+ haveEquals = false; >+ } >+ break; >+ case '=': >+ attributePair.append(c); >+ haveEquals = true; >+ break; >+ default: >+ if (Character.isWhitespace(c) && !insideQuotes) { >+ if (!Character.isWhitespace(text.charAt(i - 1)) >+ && attributePair.length() != 0) { >+ attributePair.append(' '); >+ } >+ } else { >+ attributePair.append(c); >+ } >+ break; >+ } >+ } >+ return attributes; >+ } >+ >+ private String elementStart(String text) { >+ return text.substring(0, firstWhitespaceIn(text)); >+ } >+ >+ /** >+ * @param partitionText >+ * @return >+ */ >+ private int firstWhitespaceIn(String text) { >+ for (int i = 0; i < text.length(); i++) { >+ if (Character.isWhitespace(text.charAt(i))) { return i; } >+ } >+ return -1; >+ } >+ >+ private boolean partitionsShareLine(IDocument document, >+ TypedPosition partition1, TypedPosition partition2) >+ throws BadLocationException { >+ >+ Assert.isNotNull(document); >+ Assert.isNotNull(partition1); >+ Assert.isNotNull(partition2); >+ >+ int lineNumber1 = document.getLineOfOffset(partition1.getOffset()); >+ int lineNumber2 = document.getLineOfOffset(partition2.getOffset()); >+ return lineNumber1 == lineNumber2; >+ } >+ >+ /* >+ * @see org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy#formatterStarts(org.eclipse.jface.text.formatter.IFormattingContext) >+ */ >+ public void formatterStarts(IFormattingContext context) { >+ super.formatterStarts(context); >+ >+ final FormattingContext current = (FormattingContext) context; >+ >+ fIndentations.addLast(current >+ .getProperty(FormattingContextProperties.CONTEXT_INDENTATION)); >+ fPartitions.addLast(current >+ .getProperty(FormattingContextProperties.CONTEXT_PARTITION)); >+ fPositions.addLast(current >+ .getProperty(FormattingContextProperties.CONTEXT_POSITIONS)); >+ >+ } >+ >+ /* >+ * @see org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy#formatterStops() >+ */ >+ public void formatterStops() { >+ super.formatterStops(); >+ >+ fIndentations.clear(); >+ fPartitions.clear(); >+ fPositions.clear(); >+ } >+} >Index: Ant Editor/org/eclipse/jface/text/formatter/ContentFormatter3.java >=================================================================== >RCS file: Ant Editor/org/eclipse/jface/text/formatter/ContentFormatter3.java >diff -N Ant Editor/org/eclipse/jface/text/formatter/ContentFormatter3.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Ant Editor/org/eclipse/jface/text/formatter/ContentFormatter3.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,1125 @@ >+/******************************************************************************* >+ * 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.jface.text.formatter; >+ >+ >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.LinkedList; >+import java.util.List; >+import java.util.Map; >+ >+import org.eclipse.jface.text.Assert; >+import org.eclipse.jface.text.BadLocationException; >+import org.eclipse.jface.text.BadPositionCategoryException; >+import org.eclipse.jface.text.ChildDocumentManager; >+import org.eclipse.jface.text.DefaultPositionUpdater; >+import org.eclipse.jface.text.DocumentEvent; >+import org.eclipse.jface.text.IDocument; >+import org.eclipse.jface.text.IDocumentExtension3; >+import org.eclipse.jface.text.IPositionUpdater; >+import org.eclipse.jface.text.IRegion; >+import org.eclipse.jface.text.ITypedRegion; >+import org.eclipse.jface.text.Position; >+import org.eclipse.jface.text.Region; >+import org.eclipse.jface.text.TextUtilities; >+import org.eclipse.jface.text.TypedPosition; >+ >+ >+/** >+ * Improved standard implementation of <code>IContentFormatter</code>. The formatter >+ * supports three operation modi: partition aware, partition unaware and >+ * context based. >+ * <p> >+ * In the partition aware mode, the formatter determines the partitioning of >+ * the document region to be formatted. For each partition it determines all >+ * document positions which are affected when text changes are applied to the >+ * partition. Those which overlap with the partition are remembered as >+ * character positions. These character positions are passed over to the >+ * formatting strategy registered for the partition's content type. The >+ * formatting strategy returns a string containing the formatted document >+ * partition as well as the adapted character positions. The formatted >+ * partition replaces the old content of the partition. The remembered document >+ * postions are updated with the adapted character positions. In addition, all >+ * other document positions are accordingly adapted to the formatting changes. >+ * <p> >+ * In the partition unaware mode, the document's partitioning is ignored and >+ * the document is considered consisting of only one partition of the content >+ * type <code>IDocument.DEFAULT_CONTENT_TYPE</code>. The formatting process >+ * is similar to the partition aware mode, with the exception of having only >+ * one partition. >+ * <p> >+ * The context based mode is supported by the extension interface <code>IContentFormatterExtension2</code> >+ * and supersedes the previous modes. Clients using context based formatting >+ * call the method <code>format(IDocument, IFormattingContext)</code> with a >+ * properly initialized formatting context. <br>The formatting context must be >+ * set up according to the desired formatting mode: >+ * <ul> >+ * <li>For whole document formatting set the property <code>CONTEXT_DOCUMENT</code>. >+ * </li> >+ * <li>For single partition formatting set the property <code>CONTEXT_PARTITION</code>. >+ * </li> >+ * <li>For multiple region formatting set the property <code>CONTEXT_REGION</code>. >+ * </li> >+ * </ul> >+ * Depending on the registered formatting strategies, more context information >+ * must be passed in the formatting context, like e.g. <code>CONTEXT_PREFERENCES</code>. >+ * <p> >+ * Note that in context based mode the content formatter is fully reentrant, >+ * but not thread-safe. Formatting strategies are therefore allowed to >+ * recursively call the method <code>format(IDocument, IFormattingContext)</code>. >+ * The formatting context is saved between calls to this method. >+ * <p> >+ * Usually, clients instantiate this class and configure it before using it. >+ * >+ * @see IContentFormatter >+ * @see IContentFormatterExtension2 >+ * @see IDocument >+ * @see ITypedRegion >+ * @see Position >+ */ >+public class ContentFormatter3 implements IContentFormatter, IContentFormatterExtension, IContentFormatterExtension2 { >+ >+ /** >+ * Defines a reference to either the offset or the end offset of >+ * a particular position. >+ */ >+ static class PositionReference implements Comparable { >+ >+ /** The referenced position */ >+ protected Position fPosition; >+ /** The reference to either the offset or the end offset */ >+ protected boolean fRefersToOffset; >+ /** The original category of the referenced position */ >+ protected String fCategory; >+ >+ /** >+ * Creates a new position reference. >+ * >+ * @param position the position to be referenced >+ * @param refersToOffset <code>true</code> if position offset should be referenced >+ * @param category the categpry the given position belongs to >+ */ >+ protected PositionReference(Position position, boolean refersToOffset, String category) { >+ fPosition= position; >+ fRefersToOffset= refersToOffset; >+ fCategory= category; >+ } >+ >+ /** >+ * Returns the offset of the referenced position. >+ * >+ * @return the offset of the referenced position >+ */ >+ protected int getOffset() { >+ return fPosition.getOffset(); >+ } >+ >+ /** >+ * Manipulates the offset of the referenced position. >+ * >+ * @param offset the new offset of the referenced position >+ */ >+ protected void setOffset(int offset) { >+ fPosition.setOffset(offset); >+ } >+ >+ /** >+ * Returns the length of the referenced position. >+ * >+ * @return the length of the referenced position >+ */ >+ protected int getLength() { >+ return fPosition.getLength(); >+ } >+ >+ /** >+ * Manipulates the length of the referenced position. >+ * >+ * @param the new length of the referenced position >+ */ >+ protected void setLength(int length) { >+ fPosition.setLength(length); >+ } >+ >+ /** >+ * Returns whether this reference points to the offset or endoffset >+ * of the references position. >+ * >+ * @return <code>true</code> if the offset of the position is referenced, <code>false</code> otherwise >+ */ >+ protected boolean refersToOffset() { >+ return fRefersToOffset; >+ } >+ >+ /** >+ * Returns the category of the referenced position. >+ * >+ * @return the category of the referenced position >+ */ >+ protected String getCategory() { >+ return fCategory; >+ } >+ >+ /** >+ * Returns the referenced position. >+ * >+ * @return the referenced position >+ */ >+ protected Position getPosition() { >+ return fPosition; >+ } >+ >+ /** >+ * Returns the referenced character position >+ * >+ * @return the referenced character position >+ */ >+ protected int getCharacterPosition() { >+ if (fRefersToOffset) >+ return getOffset(); >+ return getOffset() + getLength(); >+ } >+ >+ /* >+ * @see Comparable#compareTo(Object) >+ */ >+ public int compareTo(Object obj) { >+ >+ if (obj instanceof PositionReference) { >+ PositionReference r= (PositionReference) obj; >+ return getCharacterPosition() - r.getCharacterPosition(); >+ } >+ >+ throw new ClassCastException(); >+ } >+ } >+ >+ /** >+ * The position updater used to update the remembered partitions. >+ * >+ * @see IPositionUpdater >+ * @see DefaultPositionUpdater >+ */ >+ class NonDeletingPositionUpdater extends DefaultPositionUpdater { >+ >+ /** >+ * Creates a new updater for the given category. >+ * >+ * @param category the category >+ */ >+ protected NonDeletingPositionUpdater(String category) { >+ super(category); >+ } >+ >+ /* >+ * @see DefaultPositionUpdater#notDeleted() >+ */ >+ protected boolean notDeleted() { >+ return true; >+ } >+ } >+ >+ /** >+ * The position updater which runs as first updater on the document's positions. >+ * Used to remove all affected positions from their categories to avoid them >+ * from being regularily updated. >+ * >+ * @see IPositionUpdater >+ */ >+ class RemoveAffectedPositions implements IPositionUpdater { >+ /** >+ * @see IPositionUpdater#update(DocumentEvent) >+ */ >+ public void update(DocumentEvent event) { >+ removeAffectedPositions(event.getDocument()); >+ } >+ } >+ >+ /** >+ * The position updater which runs as last updater on the document's positions. >+ * Used to update all affected positions and adding them back to their >+ * original categories. >+ * >+ * @see IPositionUpdater >+ */ >+ class UpdateAffectedPositions implements IPositionUpdater { >+ >+ /** The affected positions */ >+ private int[] fPositions; >+ /** The offset */ >+ private int fOffset; >+ >+ /** >+ * Creates a new updater. >+ * >+ * @param positions the affected positions >+ * @param offset the offset >+ */ >+ public UpdateAffectedPositions(int[] positions, int offset) { >+ fPositions= positions; >+ fOffset= offset; >+ } >+ >+ /* >+ * @see IPositionUpdater#update(DocumentEvent) >+ */ >+ public void update(DocumentEvent event) { >+ updateAffectedPositions(event.getDocument(), fPositions, fOffset); >+ } >+ } >+ >+ >+ /** Internal position category used for the formatter partitioning */ >+ private final static String PARTITIONING= "__formatter_partitioning"; //$NON-NLS-1$ >+ >+ /** The map of slave <code>IFormattingStrategy</code> objects */ >+ private Map fStrategies; >+ /** >+ * The master <code>IFormattingStrategy</code> object >+ * @since 3.0 >+ */ >+ private IFormattingStrategy fMasterStrategy; >+ /** The indicator of whether the formatter operates in partition aware mode or not */ >+ private boolean fIsPartitionAware= true; >+ >+ /** The partition information managing document position categories */ >+ private String[] fPartitionManagingCategories; >+ /** The list of references to offset and end offset of all overlapping positions */ >+ private List fOverlappingPositionReferences; >+ /** >+ * The document partitioning used by this formatter. >+ * @since 3.0 >+ */ >+ private String fPartitioning; >+ /** >+ * The document this formatter works on. >+ * @since 3.0 >+ */ >+ private IDocument fDocument; >+ /** >+ * The external partition managing categories. >+ * @since 3.0 >+ */ >+ private String[] fExternalPartitonManagingCategories; >+ /** >+ * Indicates whether <code>fPartitionManagingCategories</code> must be computed. >+ * @since 3.0 >+ */ >+ private boolean fNeedsComputation= true; >+ /** >+ * Formatting context to use while formatting >+ * @since 3.0 >+ */ >+ private IFormattingContext fFormattingContext= null; >+ /** >+ * Queue of position arrays used during formatting. >+ * @since 3.0 >+ */ >+ private final LinkedList fPositions= new LinkedList(); >+ >+ /** >+ * Creates a new content formatter. >+ * <p> >+ * The content formatter operates by default in the partition-aware mode. >+ * There are no preconfigured formatting strategies. It will use the >+ * default document partitioning if not further configured. The context >+ * based mode is enabled by calls to <code>format(IDocument, IFormattingContext</code>. >+ */ >+ public ContentFormatter3() { >+ fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING; >+ } >+ >+ /** >+ * Informs this content formatter about the names of those position categories >+ * which are used to manage the document's partitioning information and thus should >+ * be ignored when this formatter updates positions. >+ * >+ * @param categories the categories to be ignored >+ * @deprecated incompatible with an open set of document partitionings. The provided information is only used >+ * if this formatter can not compute the partition managing position categories. >+ */ >+ public void setPartitionManagingPositionCategories(String[] categories) { >+ fExternalPartitonManagingCategories= categories; >+ } >+ >+ /** >+ * Sets the document partitioning to be used by this formatter. >+ * >+ * @param partitioning the document partitioning >+ * @since 3.0 >+ */ >+ public void setDocumentPartitioning(String partitioning) { >+ fPartitioning= partitioning; >+ } >+ >+ /* >+ * @see org.eclipse.jface.text.formatter.IContentFormatterExtension#getDocumentPartitioning() >+ * >+ * @since 3.0 >+ */ >+ public String getDocumentPartitioning() { >+ return fPartitioning; >+ } >+ >+ /** >+ * Sets whether the formatter operates in partition aware mode. >+ * >+ * @param enable >+ * <code>true</code> iff partition aware mode should be >+ * enabled, <code>false</code> otherwise. >+ */ >+ public void enablePartitionAwareFormatting(boolean enable) { >+ fIsPartitionAware= enable; >+ } >+ >+ /* >+ * @see IContentFormatter#getFormattingStrategy(String) >+ */ >+ public IFormattingStrategy getFormattingStrategy(String contentType) { >+ >+ Assert.isNotNull(contentType); >+ >+ if (fStrategies == null) >+ return null; >+ >+ return (IFormattingStrategy) fStrategies.get(contentType); >+ } >+ >+ /* >+ * @see IContentFormatter#format(IDocument, IRegion) >+ */ >+ public void format(IDocument document, IRegion region) { >+ >+ fNeedsComputation= true; >+ fFormattingContext= null; >+ >+ final IDocument last= fDocument; >+ fDocument= document; >+ >+ final boolean aware= fIsPartitionAware; >+ try { >+ >+ final int offset= region.getOffset(); >+ final int length= region.getLength(); >+ >+ if (fIsPartitionAware) >+ formatPartitions(offset, length); >+ else >+ formatRegion(offset, length, IDocument.DEFAULT_CONTENT_TYPE); >+ >+ } finally { >+ >+ fNeedsComputation= true; >+ fFormattingContext= null; >+ fDocument= last; >+ fIsPartitionAware= aware; >+ } >+ } >+ >+ /* >+ * @see org.eclipse.jface.text.formatter.IContentFormatterExtension2#format(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.formatter.IFormattingContext) >+ */ >+ public void format(IDocument document, IFormattingContext context) { >+ >+ fNeedsComputation= true; >+ >+ final IDocument last= fDocument; >+ fDocument= document; >+ >+ final LinkedList previous= new LinkedList(fPositions); >+ fPositions.clear(); >+ >+ final IFormattingContext predecessor= fFormattingContext; >+ fFormattingContext= context; >+ >+ final boolean aware= fIsPartitionAware; >+ try { >+ >+ final Boolean all= (Boolean)context.getProperty(FormattingContextProperties.CONTEXT_DOCUMENT); >+ if (all == null || !all.booleanValue()) { >+ >+ final TypedPosition partition= (TypedPosition)context.getProperty(FormattingContextProperties.CONTEXT_PARTITION); >+ final IRegion region= (IRegion)context.getProperty(FormattingContextProperties.CONTEXT_REGION); >+ >+ if (partition != null) { >+ formatRegion(partition.getOffset(), partition.getLength(), partition.getType()); >+ } else if (region != null) { >+ >+ int offset= region.getOffset(); >+ int length= region.getLength(); >+ >+ final ITypedRegion[] regions= TextUtilities.computePartitioning(fDocument, fPartitioning, offset, length); >+ final ITypedRegion start= TextUtilities.getPartition(fDocument, fPartitioning, regions[0].getOffset()); >+ >+ final String type= start.getType(); >+ if (regions.length > 1) { >+ >+ if (!type.equals(IDocument.DEFAULT_CONTENT_TYPE)) { >+ >+ final int delta= offset - start.getOffset(); >+ offset -= delta; >+ length += delta; >+ } >+ >+ final int rest= fDocument.getLength() - length; >+ try { >+ formatMaster(offset, length); >+ } finally { >+ formatPartitions(offset, fDocument.getLength() - rest); >+ } >+ } else if (regions.length == 1) >+ formatRegion(offset, length, type); >+ } >+ } else { >+ >+ try { >+ formatMaster(0, fDocument.getLength()); >+ } finally { >+ formatPartitions(0, fDocument.getLength()); >+ } >+ } >+ } catch (BadLocationException exception) { >+ // Should not happen >+ >+ } finally { >+ >+ fNeedsComputation= true; >+ fFormattingContext= predecessor; >+ fDocument= last; >+ fIsPartitionAware= aware; >+ >+ fPositions.clear(); >+ fPositions.addAll(previous); >+ } >+ } >+ >+ /** >+ * Registers a slave strategy for a particular content type. >+ * <p> >+ * If there is already a slave strategy registered for this type, the new >+ * strategy is registered instead of the old one. The content type <code>type</code> >+ * must be a valid content type of the registered partitioning of the >+ * formatter. >+ * <p> >+ * Note that slave strategies can only be registered if a master strategy >+ * has been registered before. >+ * </p> >+ * >+ * @param strategy >+ * The formatting strategy to register as a slave strategy, or >+ * <code>null</code> to remove an existing one >+ * @param type >+ * The content type under which to register the slave strategy >+ */ >+ public void setFormattingStrategy(IFormattingStrategy strategy, String type) { >+ >+ Assert.isNotNull(type); >+ >+ if (fStrategies == null) >+ fStrategies= new HashMap(); >+ >+ if (strategy == null) >+ fStrategies.remove(type); >+ else >+ fStrategies.put(type, strategy); >+ } >+ >+ /** >+ * Registers the master strategy for this content formatter. If there is >+ * already a master strategy registered, the new strategy is registered >+ * instead of the old one. >+ * <p> >+ * Note that slave strategies can only be registered if a master strategy >+ * has been registered before. >+ * </p> >+ * >+ * @param strategy >+ * The formatting strategy to register as the master strategy, or >+ * <code>null</code> to remove the existing one >+ */ >+ public void setFormattingStrategy(IFormattingStrategy strategy) { >+ fMasterStrategy= strategy; >+ } >+ >+ /** >+ * Aligns the region to a block selection. >+ * >+ * @param offset >+ * Offset of the region >+ * @param length >+ * Length of the region >+ * @return The aligned region >+ */ >+ private IRegion alignBlockSelect(int offset, int length) { >+ >+ try { >+ >+ final int aligned= fDocument.getLineOffset(fDocument.getLineOfOffset(offset)); >+ return new Region(aligned, length + offset - aligned); >+ >+ } catch (BadLocationException exception) { >+ // Should not happen >+ >+ return new Region(offset, length); >+ } >+ } >+ >+ /** >+ * Determines the partitioning of the given region of the document and >+ * formats each partition in the partitioning separately. >+ * <p> >+ * The formatting strategies of each partition about the start, the >+ * process, and the termination of the formatting session. >+ * >+ * @param offset >+ * The offset of the region to be formatted >+ * @param length >+ * The length of the region to be formatted >+ */ >+ private void formatPartitions(int offset, int length) { >+ >+ try { >+ >+ final TypedPosition[] ranges= getPartitioning(offset, length); >+ >+ if (ranges != null) { >+ // Instead of sending indentation information for the larger >+ // region, allow indents to be computed with every partition. >+ start(ranges); >+ format(ranges); >+ stop(ranges); >+ } >+ >+ } catch (BadLocationException exception) { >+ // Can not happen >+ } >+ } >+ >+ /** >+ * Formats the given region with the formatting >+ * strategy registered for the indicated type. The >+ * indicated type does not necessarily have to be >+ * the type of the region in the documents partitioning. >+ * <p> >+ * The formatting strategy is informed about the start, the process, and >+ * the termination of the formatting session. >+ * >+ * @param offset The offset of the region >+ * @param length The length of the region >+ * @param type The type of the region >+ */ >+ private void formatRegion(int offset, int length, String type) { >+ >+ IRegion range= null; >+ if (type.equals(IDocument.DEFAULT_CONTENT_TYPE)) >+ range= alignBlockSelect(offset, length); >+ else >+ range= new Region(offset, length); >+ >+ final IFormattingStrategy strategy= getFormattingStrategy(type); >+ if (strategy != null) { >+ >+ final TypedPosition region= new TypedPosition(range.getOffset(), range.getLength(), type); >+ >+ formatterStarts(strategy, region, getIndentation(region.getOffset())); >+ format(strategy, region); >+ strategy.formatterStops(); >+ } >+ } >+ >+ /** >+ * Formats the given region with the master formatting strategy. >+ * <p> >+ * The formatting strategy is informed about the start, the process, and >+ * the termination of the formatting session. >+ * >+ * @param offset >+ * The offset of the region >+ * @param length >+ * The length of the region >+ * @param type >+ * The type of the region >+ */ >+ private void formatMaster(int offset, int length) { >+ >+ if (fMasterStrategy != null) { >+ >+ final IRegion aligned= alignBlockSelect(offset, length); >+ final TypedPosition region= new TypedPosition(aligned.getOffset(), aligned.getLength(), IDocument.DEFAULT_CONTENT_TYPE); >+ >+ formatterStarts(fMasterStrategy, region, getIndentation(region.getOffset())); >+ format(fMasterStrategy, region); >+ fMasterStrategy.formatterStops(); >+ } >+ } >+ >+ /** >+ * Fires the <code>formatterStarts</code> event for the indicated >+ * formatting strategy. >+ * >+ * @param strategy >+ * Formatting strategy to fire the event for >+ * @param region >+ * Region where the strategy is supposed to format >+ * @param indentation >+ * Indentation to use while formatting the region >+ */ >+ private void formatterStarts(IFormattingStrategy strategy, TypedPosition region, String indentation) { >+ >+ if (fFormattingContext != null && strategy instanceof IFormattingStrategyExtension) { >+ >+ final IFormattingStrategyExtension extension= (IFormattingStrategyExtension)strategy; >+ final int[] positions= getAffectedPositions(region.getOffset(), region.getLength()); >+ >+ fPositions.addLast(positions); >+ >+ fFormattingContext.setProperty(FormattingContextProperties.CONTEXT_INDENTATION, indentation); >+ fFormattingContext.setProperty(FormattingContextProperties.CONTEXT_PARTITION, region); >+ fFormattingContext.setProperty(FormattingContextProperties.CONTEXT_POSITIONS, positions); >+ >+ extension.formatterStarts(fFormattingContext); >+ } else >+ strategy.formatterStarts(indentation); >+ } >+ >+ /** >+ * Returns the partitioning of the given region of the specified document. >+ * As one partition after the other will be formatted and formatting will >+ * probably change the length of the formatted partition, it must be kept >+ * track of the modifications in order to submit the correct partition to all >+ * formatting strategies. For this, all partitions are remembered as positions >+ * in a dedicated position category. >+ * >+ * @param offset Offset of the region for which the partitioning must be determined >+ * @param length Length of the region for which the partitioning must be determined >+ * @return the partitioning of the specified region >+ * @exception BadLocationException of region is invalid in the document >+ */ >+ private TypedPosition[] getPartitioning(int offset, int length) throws BadLocationException { >+ >+ ITypedRegion[] regions= TextUtilities.computePartitioning(fDocument, fPartitioning, offset, length); >+ TypedPosition[] positions= new TypedPosition[regions.length]; >+ >+ for (int i= 0; i < regions.length; i++) >+ positions[i]= new TypedPosition(regions[i]); >+ >+ return positions; >+ } >+ >+ /** >+ * Fires the <code>formatterStarts</code> event to all formatting >+ * strategies which will be involved in the forthcoming formatting process. >+ * >+ * @param partitions >+ * The partitioning of the document to be formatted >+ * @param indentation >+ * The initial indentation >+ */ >+ private void start(TypedPosition[] partitions) { >+ >+ String type= null; >+ TypedPosition region= null; >+ String indentation = null; >+ >+ for (int i= partitions.length - 1; i >= 0; i--) { >+ >+ region= partitions[i]; >+ type= region.getType(); >+ >+ // Instead of sending indentation information for the larger >+ // region, allow indents to be computed with every partition. >+ >+ // Note that the indentation given for the partition is actually >+ // the indentation of the line in which the partition occurs. >+ // If multiple partitions exist on the same line the String returned >+ // includes all of the spaces and tabs prior to the first partition >+ // on the line. >+ >+ indentation = getIndentation(partitions[i].offset); >+ >+ if (!type.equals(IDocument.DEFAULT_CONTENT_TYPE)) { >+ >+ final IFormattingStrategy strategy= getFormattingStrategy(type); >+ if (strategy != null && strategy != fMasterStrategy) >+ formatterStarts(strategy, region, indentation); >+ } >+ } >+ } >+ >+ /** >+ * Formats the partitions using the formatting strategy registered for each >+ * partition's content type. >+ * >+ * @param partitions >+ * The partitioning of the document to be formatted >+ */ >+ private void format(TypedPosition[] partitions) { >+ >+ String type= null; >+ TypedPosition region= null; >+ >+ for (int i= partitions.length - 1; i >= 0; i--) { >+ >+ region= partitions[i]; >+ type= region.getType(); >+ >+ if (!type.equals(IDocument.DEFAULT_CONTENT_TYPE)) { >+ >+ final IFormattingStrategy strategy= getFormattingStrategy(type); >+ if (strategy != null && strategy != fMasterStrategy) { >+ >+ if (fFormattingContext != null && strategy instanceof IFormattingStrategyExtension) { >+ >+ final IFormattingStrategyExtension extension= (IFormattingStrategyExtension)strategy; >+ extension.format(); >+ >+ } else >+ format(strategy, region); >+ } >+ } >+ } >+ } >+ >+ /** >+ * Formats the given region in the document using the indicated strategy. >+ * The type of the region does not have to be the same as the type for >+ * which the strategy was originally registered. >+ * <p> >+ * The formatting process will happen in the mode set up by the formatting >+ * context or changes to the partition aware/unaware property. >+ * >+ * @param strategy >+ * The strategy to be used >+ * @param region >+ * The region to be formatted >+ */ >+ private void format(IFormattingStrategy strategy, TypedPosition region) { >+ >+ if (fFormattingContext != null && strategy instanceof IFormattingStrategyExtension) { >+ >+ final int[] positions= (int[])fFormattingContext.getProperty(FormattingContextProperties.CONTEXT_POSITIONS); >+ >+ IPositionUpdater first= new RemoveAffectedPositions(); >+ fDocument.insertPositionUpdater(first, 0); >+ IPositionUpdater last= new UpdateAffectedPositions(positions, region.getOffset()); >+ fDocument.addPositionUpdater(last); >+ >+ final IFormattingStrategyExtension extension= (IFormattingStrategyExtension)strategy; >+ extension.format(); >+ >+ fDocument.removePositionUpdater(first); >+ fDocument.removePositionUpdater(last); >+ >+ } else { >+ >+ try { >+ >+ final int offset= region.getOffset(); >+ int length= region.getLength(); >+ >+ String content= fDocument.get(offset, length); >+ final int[] positions= getAffectedPositions(offset, length); >+ String formatted= strategy.format(content, isLineStart(offset), getIndentation(offset), positions); >+ >+ if (formatted != null && !formatted.equals(content)) { >+ >+ IPositionUpdater first= new RemoveAffectedPositions(); >+ fDocument.insertPositionUpdater(first, 0); >+ IPositionUpdater last= new UpdateAffectedPositions(positions, offset); >+ fDocument.addPositionUpdater(last); >+ >+ fDocument.replace(offset, length, formatted); >+ >+ fDocument.removePositionUpdater(first); >+ fDocument.removePositionUpdater(last); >+ } >+ >+ } catch (BadLocationException x) { >+ // should not happen >+ } >+ } >+ } >+ >+ /** >+ * Fires the <code>formatterStops</code> event to all formatting >+ * strategies which were involved in the formatting process which is about >+ * to terminate. >+ * >+ * @param partitions >+ * The partitioning of the document which has been formatted >+ */ >+ private void stop(TypedPosition[] partitions) { >+ >+ String type= null; >+ for (int i= partitions.length - 1; i >= 0; i--) { >+ >+ type= partitions[i].getType(); >+ if (!type.equals(IDocument.DEFAULT_CONTENT_TYPE)) { >+ >+ final IFormattingStrategy strategy= getFormattingStrategy(type); >+ if (strategy != null && strategy != fMasterStrategy) >+ strategy.formatterStops(); >+ } >+ } >+ } >+ >+ /** >+ * Returns the partition managing position categories for the formatted document. >+ * >+ * @return the position managing position categories >+ * @since 3.0 >+ */ >+ private String[] getPartitionManagingCategories() { >+ if (fNeedsComputation) { >+ fNeedsComputation= false; >+ fPartitionManagingCategories= TextUtilities.computePartitionManagingCategories(fDocument); >+ if (fPartitionManagingCategories == null) >+ fPartitionManagingCategories= fExternalPartitonManagingCategories; >+ } >+ return fPartitionManagingCategories; >+ } >+ >+ /** >+ * Determines whether the given document position category should be ignored >+ * by this formatter's position updating. >+ * >+ * @param category the category to check >+ * @return <code>true</code> if the category should be ignored, <code>false</code> otherwise >+ */ >+ private boolean ignoreCategory(String category) { >+ >+ if (PARTITIONING.equals(category)) >+ return true; >+ >+ String[] categories= getPartitionManagingCategories(); >+ if (categories != null) { >+ for (int i= 0; i < categories.length; i++) { >+ if (categories[i].equals(category)) >+ return true; >+ } >+ } >+ >+ return false; >+ } >+ >+ /** >+ * Determines all embracing, overlapping, and follow up positions >+ * for the given region of the document. >+ * >+ * @param offset the offset of the document region to be formatted >+ * @param length the length of the document to be formatted >+ */ >+ private void determinePositionsToUpdate(int offset, int length) { >+ >+ String[] categories= fDocument.getPositionCategories(); >+ if (categories != null) { >+ for (int i= 0; i < categories.length; i++) { >+ >+ if (ignoreCategory(categories[i])) >+ continue; >+ >+ try { >+ >+ Position[] positions= fDocument.getPositions(categories[i]); >+ >+ for (int j= 0; j < positions.length; j++) { >+ >+ Position p= positions[j]; >+ if (p.overlapsWith(offset, length)) { >+ >+ if (offset < p.getOffset()) >+ fOverlappingPositionReferences.add(new PositionReference(p, true, categories[i])); >+ >+ if (p.getOffset() + p.getLength() < offset + length) >+ fOverlappingPositionReferences.add(new PositionReference(p, false, categories[i])); >+ } >+ } >+ >+ } catch (BadPositionCategoryException x) { >+ // can not happen >+ } >+ } >+ } >+ } >+ >+ /** >+ * Returns all offset and the end offset of all positions overlapping with the >+ * specified document range. >+ * >+ * @param offset the offset of the document region to be formatted >+ * @param length the length of the document to be formatted >+ * @return all character positions of the interleaving positions >+ */ >+ private int[] getAffectedPositions(int offset, int length) { >+ >+ fOverlappingPositionReferences= new ArrayList(); >+ >+ determinePositionsToUpdate(offset, length); >+ >+ // since sort is stable, no reference pairs to the same zero-length position >+ // will get swapped. >+ Collections.sort(fOverlappingPositionReferences); >+ >+ int[] positions= new int[fOverlappingPositionReferences.size()]; >+ for (int i= 0; i < positions.length; i++) { >+ PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); >+ positions[i]= r.getCharacterPosition() - offset; >+ } >+ >+ return positions; >+ } >+ >+ /** >+ * Removes the affected positions from their categories to avoid >+ * that they are invalidly updated. >+ * >+ * @param document the document >+ */ >+ private void removeAffectedPositions(IDocument document) { >+ if (fOverlappingPositionReferences != null) { >+ int size= fOverlappingPositionReferences.size(); >+ for (int i= 0; i < size; i++) { >+ PositionReference r= (PositionReference)fOverlappingPositionReferences.get(i); >+ try { >+ document.removePosition(r.getCategory(), r.getPosition()); >+ } catch (BadPositionCategoryException x) { >+ // can not happen >+ } >+ } >+ } >+ } >+ >+ /** >+ * Updates all the overlapping positions. Note, all other positions are >+ * automatically updated by their document position updaters. >+ * >+ * @param document the document to has been formatted >+ * @param positions the adapted character positions to be used to update the document positions >+ * @param offset the offset of the document region that has been formatted >+ */ >+ protected void updateAffectedPositions(IDocument document, int[] positions, int offset) { >+ >+ if (document != fDocument) >+ return; >+ >+ if (fOverlappingPositionReferences == null || fOverlappingPositionReferences.size() == 0 || positions.length == 0) >+ return; >+ >+ for (int i= 0; i < positions.length; i++) { >+ >+ PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); >+ >+ if (r.refersToOffset()) { >+ int posOffset= offset + positions[i]; >+ if (posOffset >= 0) >+ r.setOffset(posOffset); >+// else >+// Protest >+ } else { >+ // positions are ordered by offset. For every position that has references >+ // to both offset and length, the offset comes first. >+ // Therefore, the end of the position (offset + positions[i]) is supposedly >+ // greater than r.getOffset() >+ // if this is not the case, perhaps the position returned from the formatter was negative? >+ // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=46617 >+ int length= offset + positions[i] - r.getOffset(); >+ if (length >= 0) >+ r.setLength(length); >+// else >+// Protest >+ } >+ >+ Position p= r.getPosition(); >+ String category= r.getCategory(); >+ if (!document.containsPosition(category, p.offset, p.length)) { >+ try { >+ if (positionAboutToBeAdded(document, category, p)) >+ document.addPosition(r.getCategory(), p); >+ } catch (BadPositionCategoryException x) { >+ // can not happen >+ } catch (BadLocationException x) { >+ // should not happen >+ } >+ } >+ >+ } >+ >+ fOverlappingPositionReferences= null; >+ } >+ >+ /** >+ * The given position is about to be added to the given position category of the given document. <p> >+ * This default implementation enacts the same rule as the TextViewer, i.e. if the position is used for >+ * managing slave documents it is ensured that the slave document starts at a line offset. >+ * >+ * @param document the document >+ * @param category the position categroy >+ * @param position the position that will be added >+ * @return <code>true</code> if the position can be added, <code>false</code> if it should be ignored >+ */ >+ protected boolean positionAboutToBeAdded(IDocument document, String category, Position position) { >+ if (ChildDocumentManager.CHILDDOCUMENTS.equals(category)) { >+ /* >+ * We assume child document offsets to be at the beginning >+ * of a line. Because the formatter might have moved the >+ * position to be somewhere in the middle of a line we patch it here. >+ */ >+ try { >+ int lineOffset= document.getLineInformationOfOffset(position.offset).getOffset(); >+ position.setLength(position.length + position.offset - lineOffset); >+ position.setOffset(lineOffset); >+ } catch (BadLocationException x) { >+ return false; >+ } >+ } >+ return true; >+ } >+ >+ /** >+ * Returns the indentation of the line of the given offset. >+ * >+ * @param offset the offset >+ * @return the indentation of the line of the offset >+ */ >+ private String getIndentation(int offset) { >+ >+ try { >+ int start= fDocument.getLineOfOffset(offset); >+ start= fDocument.getLineOffset(start); >+ >+ int end= start; >+ char c= fDocument.getChar(end); >+ while ('\t' == c || ' ' == c) >+ c= fDocument.getChar(++end); >+ >+ return fDocument.get(start, end - start); >+ } catch (BadLocationException x) { >+ } >+ >+ return ""; //$NON-NLS-1$ >+ } >+ >+ /** >+ * Determines whether the offset is the beginning of a line in the given document. >+ * >+ * @param offset the offset >+ * @return <code>true</code> if offset is the beginning of a line >+ * @exception BadLocationException if offset is invalid in document >+ */ >+ private boolean isLineStart(int offset) throws BadLocationException { >+ int start= fDocument.getLineOfOffset(offset); >+ start= fDocument.getLineOffset(start); >+ return (start == offset); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 40255
:
7625
|
7682
|
8117
|
8236
|
8258
|
8595
|
8596