Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/text/StructuredDocumentReParser.java')
-rw-r--r--bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/text/StructuredDocumentReParser.java1658
1 files changed, 0 insertions, 1658 deletions
diff --git a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/text/StructuredDocumentReParser.java b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/text/StructuredDocumentReParser.java
deleted file mode 100644
index f846682f8a..0000000000
--- a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/text/StructuredDocumentReParser.java
+++ /dev/null
@@ -1,1658 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2001, 2010 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- * Jens Lukowski/Innoopract - initial renaming/restructuring
- * David Carver (Intalio) - bug 300427 - Comparison of String Objects using == or !=
- *******************************************************************************/
-package org.eclipse.wst.sse.core.internal.text;
-
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.FindReplaceDocumentAdapter;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.wst.sse.core.internal.Logger;
-import org.eclipse.wst.sse.core.internal.ltk.parser.BlockTagParser;
-import org.eclipse.wst.sse.core.internal.provisional.events.NoChangeEvent;
-import org.eclipse.wst.sse.core.internal.provisional.events.RegionChangedEvent;
-import org.eclipse.wst.sse.core.internal.provisional.events.RegionsReplacedEvent;
-import org.eclipse.wst.sse.core.internal.provisional.events.StructuredDocumentEvent;
-import org.eclipse.wst.sse.core.internal.provisional.events.StructuredDocumentRegionsReplacedEvent;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredTextReParser;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
-import org.eclipse.wst.sse.core.internal.util.Debug;
-import org.eclipse.wst.sse.core.internal.util.Utilities;
-import org.eclipse.wst.sse.core.utils.StringUtils;
-
-
-/**
- * This class provides a centralized place to put "reparsing" logic. This is
- * the logic that reparses the text incrementally, as a user types in new
- * characters, or DOM nodes are inserted or deleted. Note: it is not a thread
- * safe class.
- */
-public class StructuredDocumentReParser implements IStructuredTextReParser {
- protected IStructuredDocumentRegion dirtyEnd = null;
- protected IStructuredDocumentRegion dirtyStart = null;
- final private String doubleQuote = new String(new char[]{'\"'});
- protected final CoreNodeList EMPTY_LIST = new CoreNodeList();
- protected String fChanges;
- protected String fDeletedText;
- protected boolean fIsEntireDocument;
-
- private FindReplaceDocumentAdapter fFindReplaceDocumentAdapter = null;
- protected int fLengthDifference;
- protected int fLengthToReplace;
- protected Object fRequester;
- protected int fStart;
- // note: this is the impl class of IStructuredDocument, not the interface
- // FUTURE_TO_DO: I believe some of these can be made private now.?
- protected BasicStructuredDocument fStructuredDocument;
-
- /**
- * variable used in anticiapation of multithreading
- */
- protected boolean isParsing;
- final private String singleQuote = new String(new char[]{'\''});
-
- public StructuredDocumentReParser() {
- super();
- }
-
- public StructuredDocumentEvent _checkBlockNodeList(List blockTagList) {
- StructuredDocumentEvent result = null;
- if (blockTagList != null) {
- for (int i = 0; i < blockTagList.size(); i++) {
- org.eclipse.wst.sse.core.internal.ltk.parser.BlockMarker blockTag = (org.eclipse.wst.sse.core.internal.ltk.parser.BlockMarker) blockTagList.get(i);
- String tagName = blockTag.getTagName();
- result = checkForCriticalName("<" + tagName); //$NON-NLS-1$
- if (result != null)
- break;
- result = checkForCriticalName("</" + tagName); //$NON-NLS-1$
- if (result != null)
- break;
- }
- }
- return result;
- }
-
- /**
- * Common utility for checking for critical word such as " <SCRIPT>"
- */
- private StructuredDocumentEvent _checkForCriticalWord(String criticalTarget, boolean checkEnd) {
- StructuredDocumentEvent result = null;
- int documentLength = fStructuredDocument.getLength();
- int propLen = fLengthToReplace;
- if (propLen > documentLength)
- propLen = documentLength;
- int startNeighborhood = fStart - criticalTarget.length();
- int adjustInsert = 0;
- if (startNeighborhood < 0) {
- adjustInsert = 0 - startNeighborhood;
- startNeighborhood = 0;
- }
- int endNeighborhood = fStart + fLengthToReplace + criticalTarget.length() - 1;
- if (endNeighborhood > documentLength)
- endNeighborhood = documentLength - 1;
- int oldlen = endNeighborhood - startNeighborhood; // + 1;
- if (oldlen + startNeighborhood > documentLength) {
- oldlen = documentLength - startNeighborhood;
- }
- String oldText = fStructuredDocument.get(startNeighborhood, oldlen);
- String peek = StringUtils.paste(oldText, fChanges, criticalTarget.length() - adjustInsert, fLengthToReplace);
- boolean isCriticalString = checkTagNames(oldText, criticalTarget, checkEnd);
- boolean toBeCriticalString = checkTagNames(peek, criticalTarget, checkEnd);
- if ((isCriticalString != toBeCriticalString) || // OR if both are
- // critical and there's
- // a change in the end
- // tag ('>')
- ((isCriticalString && toBeCriticalString) && (changeInIsEndedState(oldText, peek)))) {
- // if it involves a change of a critical string (making one where
- // there wasn't, or removing
- // one where there was one) then reparse everthing.
- result = reparse(0, documentLength - 1);
- }
- return result;
- }
-
- private int _computeStartOfDifferences(CoreNodeList oldNodes, CoreNodeList newNodes) {
- int startOfDifferences = -1;
- int newNodesLength = newNodes.getLength();
- boolean foundDifference = false;
- boolean done = false;
- // we'll control our loop based on the old List length
- int oldNodesLength = oldNodes.getLength();
- // be sure to check 'done' first, so startOfDifferences isn't
- // icremented if done is true
- done : while ((!done) && (++startOfDifferences < oldNodesLength)) {
- IStructuredDocumentRegion oldNode = oldNodes.item(startOfDifferences);
- // this lessThanEffectedRegion is to check to be sure the node is
- // infact a candidate
- // to be considered as "old". This check is important for the case
- // where some
- // text is replaceing text that
- // appears identical, but is a different instance. For example, if
- // the text
- // is <P><B></B></P> and <B></B> is inserted at postion 3,
- // resulting in <P><B></B><B></B></P>
- // we do not want the
- // first <B> to be considered old ... it is the new one, the
- // second
- // <B> is the old one.
- if (_lessThanEffectedRegion(oldNode)) {
- // be sure to check that we have new nodes to compare against.
- if (startOfDifferences > newNodesLength) {
- foundDifference = false;
- done = true;
- continue done;
- } else {
- //
- IStructuredDocumentRegion newNode = newNodes.item(startOfDifferences);
- // note: shift is 0 while at beginning of list, before the
- // insertion (or deletion) point. After that, it is
- // fStart+fLengthDifference
- if (!(oldNode.sameAs(newNode, 0))) {
- foundDifference = true;
- done = true;
- continue done;
- } else { // if they are equal, then we will be keeping the
- // old one, so
- // we need to be sure its parentDocument is set back
- // to
- // the right instance
- oldNode.setParentDocument(fStructuredDocument);
- }
- }
- } else {
- // we didn't literally find a difference, but we count it as
- // such by implication
- foundDifference = true;
- done = true;
- continue done;
- }
- }
- // if we literally found a difference, then all is ok and we can
- // return
- // it.
- // if we did not literally find one, then we have to decide why.
- if (!foundDifference) {
- if (newNodesLength == oldNodesLength) { // then lists are
- // identical
- // (and may be of zero
- // length)
- startOfDifferences = -1;
- } else {
- if (newNodesLength > oldNodesLength) { // then lists are
- // identical except for
- // newNodes added
- startOfDifferences = oldNodesLength;
- } else {
- if (newNodesLength < oldNodesLength) { // then lists are
- // identical except
- // for old Nodes
- // deleted
- startOfDifferences = newNodesLength;
- }
- }
- }
- }
- return startOfDifferences;
- }
-
- private int _computeStartOfDifferences(IStructuredDocumentRegion oldNodeParam, ITextRegionList oldRegions, IStructuredDocumentRegion newNodeParam, ITextRegionList newRegions) {
- int startOfDifferences = -1;
- int newRegionsLength = newRegions.size();
- boolean foundDifference = false;
- boolean done = false;
- // we'll control our loop based on the old List length
- int oldRegionsLength = oldRegions.size();
- // be sure to check 'done' first, so startOfDifferences isn't
- // icremented if done is true
- done : while ((!done) && (++startOfDifferences < oldRegionsLength)) {
- ITextRegion oldRegion = oldRegions.get(startOfDifferences);
- // this lessThanEffectedRegion is to check to be sure the node is
- // infact a candidate
- // to be considered as "old". This check is important for the case
- // where some
- // text is replaceing text that
- // appears identical, but is a different instance. For example, if
- // the text
- // is <P><B></B></P> and <B></B> is inserted at postion 3,
- // resulting in <P><B></B><B></B></P>
- // we do not want the
- // first <B> to be considered old ... it is the new one, the
- // second
- // <B> is the old one.
- if (_lessThanEffectedRegion(oldNodeParam, oldRegion)) {
- // be sure to check that we have new nodes to compare against.
- if (startOfDifferences > newRegionsLength) {
- foundDifference = false;
- done = true;
- continue done;
- } else {
- //
- ITextRegion newRegion = newRegions.get(startOfDifferences);
- // note: shift is 0 while at beginning of list, before the
- // insertion (or deletion) point. After that, it is
- // fStart+fLengthDifference
- if (!(oldNodeParam.sameAs(oldRegion, newNodeParam, newRegion, 0))) {
- foundDifference = true;
- done = true;
- continue done;
- } else {
- // if they are equal, then we will be keeping the old
- // one.
- // unlike the flatnode case, there is no reason to
- // update
- // the textstore, since its the same text store in
- // either case
- // (since its the same flatnode)
- //oldRegion.setTextStore(fStructuredDocument.parentDocument);
- }
- }
- } else {
- // we didn't literally find a difference, but we count it as
- // such by implication
- foundDifference = true;
- done = true;
- continue done;
- }
- }
- // if we literally found a difference, then all is ok and we can
- // return
- // it.
- // if we did not literally find one, then we have to decide why.
- if (!foundDifference) {
- if (newRegionsLength == oldRegionsLength) { // then lists are
- // identical (and may
- // be of zero length)
- startOfDifferences = -1;
- } else {
- if (newRegionsLength > oldRegionsLength) { // then lists are
- // identical except
- // for newRegions
- // added
- startOfDifferences = oldRegionsLength;
- } else {
- if (newRegionsLength < oldRegionsLength) { // then lists
- // are identical
- // except for
- // old Nodes
- // deleted
- startOfDifferences = newRegionsLength;
- }
- }
- }
- }
- return startOfDifferences;
- }
-
- /**
- * Part 1 of 2 steps to do a core_reparse
- *
- * Parses a portion of the current text in the IStructuredDocument and
- * returns the raw result
- */
- private IStructuredDocumentRegion _core_reparse_text(int rescanStart, int rescanEnd) {
- fStructuredDocument.resetParser(rescanStart, rescanEnd);
- return fStructuredDocument.getParser().getDocumentRegions();
- }
-
- /**
- * Part 2 of 2 steps to do a core_reparse
- *
- * Integrates a list of StructuredDocumentRegions based on the current
- * text contents of the IStructuredDocument into the IStructuredDocument
- * data structure
- */
- private StructuredDocumentEvent _core_reparse_update_model(IStructuredDocumentRegion newNodesHead, int rescanStart, int rescanEnd, CoreNodeList oldNodes, boolean firstTime) {
- StructuredDocumentEvent result = null;
- CoreNodeList newNodes = null;
- // rescan
- newNodes = new CoreNodeList(newNodesHead);
- // adjust our newNode chain so the offset positions match
- // our text store (not the simple string of text reparsed)
- StructuredDocumentRegionIterator.adjustStart(newNodesHead, rescanStart);
- // initialize the parentDocument variable of each instance in the new
- // chain
- StructuredDocumentRegionIterator.setParentDocument(newNodesHead, fStructuredDocument);
- // initialize the structuredDocument variable of each instance in the
- // new chain
- //StructuredDocumentRegionIterator.setStructuredDocument(newNodesHead,
- // fStructuredDocument);
- //
- if (firstTime) {
- fStructuredDocument.setCachedDocumentRegion(newNodesHead);
- fStructuredDocument.initializeFirstAndLastDocumentRegion();
- // note: since we are inserting nodes, for the first time, there
- // is
- // no adjustments
- // to downstream stuff necessary.
- result = new StructuredDocumentRegionsReplacedEvent(fStructuredDocument, fRequester, oldNodes, newNodes, fChanges, fStart, fLengthToReplace, fIsEntireDocument);
- } else {
- // note: integrates changes into model as a side effect
- result = minimumEvent(oldNodes, newNodes);
- }
- result.setDeletedText(fDeletedText);
- return result;
- }
-
- private CoreNodeList _formMinimumList(CoreNodeList flatnodes, int startOfDifferences, int endOfDifferences) {
- CoreNodeList minimalNodes = null;
- // if startOfDifferces is still its initial value, then we have an
- // empty document
- if (startOfDifferences == -1) {
- minimalNodes = EMPTY_LIST;
- } else {
- // if we do not have any flatnode in our flatnode list, then
- // simply
- // return our standard empty list
- if (flatnodes.getLength() == 0) {
- minimalNodes = EMPTY_LIST;
- } else {
- // if startOfDifferences is greater than endOfDifferences,
- // then
- // that means the calculations "crossed" each other, and
- // hence,
- // there really is no differences, so, again, return the empty
- // list
- if (startOfDifferences > endOfDifferences) {
- minimalNodes = EMPTY_LIST;
- } else {
- // the last check be sure we have some differnces
- if ((endOfDifferences > -1)) {
- minimalNodes = new CoreNodeList(flatnodes.item(startOfDifferences), flatnodes.item(endOfDifferences));
- } else {
- // there were no differences, the list wasn't
- // minimized, so simply return it.
- minimalNodes = flatnodes;
- }
- }
- }
- }
- return minimalNodes;
- }
-
- private boolean _greaterThanEffectedRegion(IStructuredDocumentRegion oldNode) {
- boolean result = false;
- int nodeStart = oldNode.getStartOffset();
- int changedRegionEnd = fStart + fLengthToReplace - 1;
- result = nodeStart > changedRegionEnd;
- return result;
- }
-
- private boolean _greaterThanEffectedRegion(IStructuredDocumentRegion oldNode, ITextRegion oldRegion) {
- boolean result = false;
- int regionStartOffset = oldNode.getStartOffset(oldRegion);
- int effectedRegionEnd = fStart + fLengthToReplace - 1;
- result = regionStartOffset > effectedRegionEnd;
- return result;
- }
-
- private boolean _lessThanEffectedRegion(IStructuredDocumentRegion oldNode) {
- boolean result = false;
- int nodeEnd = oldNode.getEndOffset() - 1;
- result = nodeEnd < fStart;
- return result;
- }
-
- private boolean _lessThanEffectedRegion(IStructuredDocumentRegion oldNode, ITextRegion oldRegion) {
- boolean result = false;
- int nodeEnd = oldNode.getEndOffset(oldRegion) - 1;
- result = nodeEnd < fStart;
- return result;
- }
-
- private boolean _regionsSameKind(ITextRegion newRegion, ITextRegion oldRegion) {
- boolean result = false;
- // if one region is a container region, and the other not, always
- // return false
- // else, just check their type.
- // DW druing refactoring, looks like a "typo" here, using 'old' in
- // both.
- // if (isContainerRegion(oldRegion) != isContainerRegion(oldRegion))
- if (isCollectionRegion(oldRegion) != isCollectionRegion(newRegion))
- result = false;
- else if (oldRegion.getType().equals(newRegion.getType()))
- result = true;
- return result;
- }
-
- // private boolean hasCollectionRegions(ITextRegion aRegion) {
- // boolean result = false;
- // if (aRegion instanceof ITextRegionCollection) {
- // ITextRegionCollection regionContainter = (ITextRegionCollection)
- // aRegion;
- // ITextRegionList regions = regionContainter.getRegions();
- // Iterator iterator = regions.iterator();
- // while (iterator.hasNext()) {
- // if (aRegion instanceof ITextRegionCollection) {
- // result = true;
- // break;
- // }
- // }
- // }
- // return result;
- // }
- /**
- * This method is specifically to detect changes in 'isEnded' state,
- * although it still does so with heuristics. If number of '>' changes,
- * assume the isEnded state has changed.
- */
- private boolean changeInIsEndedState(String oldText, String newText) {
- int nOld = StringUtils.occurrencesOf(oldText, '>');
- int nNew = StringUtils.occurrencesOf(newText, '>');
- return !(nOld == nNew);
- }
-
- private void checkAndAssignParent(IStructuredDocumentRegion oldNode, ITextRegion region) {
- if (region instanceof ITextRegionContainer) {
- ((ITextRegionContainer) region).setParent(oldNode);
- return;
- }
- if (region instanceof ITextRegionCollection) {
- ITextRegionCollection textRegionCollection = (ITextRegionCollection) region;
- ITextRegionList regionList = textRegionCollection.getRegions();
- for (int i = 0; i < regionList.size(); i++) {
- ITextRegion innerRegion = regionList.get(i);
- checkAndAssignParent(oldNode, innerRegion);
- }
- }
- }
-
- /**
- * A change to a CDATA tag can result in all being reparsed.
- */
- private StructuredDocumentEvent checkForCDATA() {
- StructuredDocumentEvent result = null;
- result = checkForCriticalKey("<![CDATA["); //$NON-NLS-1$
- if (result == null)
- result = checkForCriticalKey("]]>"); //$NON-NLS-1$
- return result;
- }
-
- /**
- * If a comment start or end tag is being added or deleted, we'll rescan
- * the whole document. The reason is that content that is revealed or
- * commented out can effect the interpretation of the rest of the
- * document. Note: for now this is very XML specific, can refactor/improve
- * later.
- */
- protected StructuredDocumentEvent checkForComments() {
- StructuredDocumentEvent result = null;
- result = checkForCriticalKey("<!--"); //$NON-NLS-1$
- if (result == null)
- result = checkForCriticalKey("-->"); //$NON-NLS-1$
- // we'll also check for these degenerate cases
- if (result == null)
- result = checkForCriticalKey("<!--->"); //$NON-NLS-1$
- return result;
- }
-
- /**
- * Common utility for checking for critical word such as " <SCRIPT>"
- */
- protected StructuredDocumentEvent checkForCriticalKey(String criticalTarget) {
- return _checkForCriticalWord(criticalTarget, false);
- }
-
- /**
- * Common utility for checking for critical word such as " <SCRIPT>"
- */
- private StructuredDocumentEvent checkForCriticalName(String criticalTarget) {
- return _checkForCriticalWord(criticalTarget, true);
- }
-
- // /**
- // * Currently this method is pretty specific to ?ML
- // * @deprecated - not really deprecated, but plan to make
- // * protected ... I'm not sure why its public or misspelled?
- // */
- protected StructuredDocumentEvent checkForCrossStructuredDocumentRegionBoundryCases() {
- StructuredDocumentEvent result = null;
- // Case 1: See if the language's syntax requires that multiple
- // StructuredDocumentRegions be rescanned
- if (result == null) {
- result = checkForCrossStructuredDocumentRegionSyntax();
- }
- // Case 2: "block tags" whose content is left unparsed
- if (result == null) {
- Object parser = fStructuredDocument.getParser();
- if (parser instanceof BlockTagParser) {
- List blockTags = ((BlockTagParser) parser).getBlockMarkers();
- result = _checkBlockNodeList(blockTags);
- }
- }
- // FUTURE_TO_DO: is there a better place to do this?
- // or! do we already do it some other more central place?
- if (result != null) {
- result.setDeletedText(fDeletedText);
- }
- return result;
- }
-
- /**
- * Allow a reparser to check for extra syntactic cases that require
- * parsing beyond the flatNode boundary.
- *
- * This implementation is very XML-centric.
- */
- protected StructuredDocumentEvent checkForCrossStructuredDocumentRegionSyntax() {
- StructuredDocumentEvent result;
- // Case 1: Quote characters are involved
- result = checkForQuotes();
- if (result == null) {
- // Case 2: The input forms or undoes a comment beginning or
- // comment
- // end
- result = checkForComments();
- }
- if (result == null) {
- // Case 3: The input forms or undoes a processing instruction
- result = checkForPI();
- }
- if (result == null) {
- // Case 4: The input forms or undoes a CDATA section
- result = checkForCDATA();
- }
- return result;
- }
-
- /**
- * Checks to see if change request exactly matches the text it would be
- * replacing. (In future, this, or similar method is where to check for
- * "read only" attempted change.)
- */
- private StructuredDocumentEvent checkForNoChange() {
- StructuredDocumentEvent result = null;
- // don't check equals unless lengths match
- // should be a tiny bit faster, since usually not
- // of equal lengths (I'm surprised String's equals method
- // doesn't do this.)
- if ((fChanges != null) && (fDeletedText != null) && (fChanges.length() == fDeletedText.length()) && (fChanges.equals(fDeletedText))) {
- result = new NoChangeEvent(fStructuredDocument, fRequester, fChanges, fStart, fLengthToReplace);
- ((NoChangeEvent)result).reason = NoChangeEvent.NO_CONTENT_CHANGE;
- }
- return result;
- }
-
- /**
- * A change to a PI tag can result in all being reparsed.
- */
- private StructuredDocumentEvent checkForPI() {
- StructuredDocumentEvent result = null;
- result = checkForCriticalKey("<?"); //$NON-NLS-1$
- if (result == null)
- result = checkForCriticalKey("?>"); //$NON-NLS-1$
- return result;
- }
-
- // For simplicity, if either text to be deleted, or text to be inserted
- // contains at least
- // one quote, we'll search for previous quote in document, if any, and use
- // that flatnode as
- // a dirty start, and we'll use end of document as dirty end. We need to
- // assume either \" or
- // \' is an exceptable quote. (NOTE: this is, loosely, an XML assumption
- // --
- // other languages
- // would differ, but we'll "hard code" for XML for now.
- // future_TODO: this is a really bad heuristic ... we should be looking
- // for
- // odd number of quotes
- // within a structuredDocumentRegion (or something!) This causes way too
- // much reparsing on
- // simple cases, like deleting a tag with a quoted attribute!
- private StructuredDocumentEvent checkForQuotes() {
- // routine is supported with null or empty string meaning the same
- // thing: deletion
- if (fChanges == null)
- fChanges = ""; //$NON-NLS-1$
- //
- StructuredDocumentEvent result = null;
- try {
- int dirtyStartPos = -1;
- String proposedDeletion = fStructuredDocument.get(fStart, fLengthToReplace);
- if (fStart < fStructuredDocument.getLength()) {
- if ((fChanges.indexOf(singleQuote) > -1) || (proposedDeletion.indexOf(singleQuote) > -1)) {
- IRegion singleQuoteRegion = getFindReplaceDocumentAdapter().find(fStart, singleQuote, false, false, false, false);
- if (singleQuoteRegion != null) {
- dirtyStartPos = singleQuoteRegion.getOffset();
- }
- } else if ((fChanges.indexOf(doubleQuote) > -1) || (proposedDeletion.indexOf(doubleQuote) > -1)) {
- IRegion doubleQuoteRegion = getFindReplaceDocumentAdapter().find(fStart, doubleQuote, false, false, false, false);
- if (doubleQuoteRegion != null) {
- dirtyStartPos = doubleQuoteRegion.getOffset();
- }
- }
- }
- if (dirtyStartPos > -1) {
- // then we found one, do create new structuredDocument event
- // based on the previous quote to end of document
- // except, we need to be positive that the previous quote is
- // in a "safe start" region (e.g. if in JSP content, we need
- // to
- // backup till we include the whole JSP region, in order for
- // it
- // to be correctly re-parsed. The backing up is done in the
- // reparse/find dirty start from hint
- // method.
- result = reparse(dirtyStartPos, fStructuredDocument.getLength() - 1);
- }
- } catch (BadLocationException e) {
- Logger.logException(e);
- }
- if (result != null) {
- result.setDeletedText(fDeletedText);
- }
- return result;
- }
-
- private StructuredDocumentEvent checkHeuristics() {
- StructuredDocumentEvent result = null;
- result = checkForNoChange();
- if (result == null) {
- result = checkForCrossStructuredDocumentRegionBoundryCases();
- if (result == null) {
- result = quickCheck();
- }
- }
- return result;
- }
-
- /**
- * Takes into account "tag name" rules for comparisons; case-insensitive.
- */
- private boolean checkTagNames(String compareText, String criticalTarget, boolean checkEnd) {
- boolean result = false;
- if ((compareText == null) || (criticalTarget == null))
- return false;
- int posOfCriticalWord = compareText.toLowerCase().indexOf(criticalTarget.toLowerCase());
- result = posOfCriticalWord > -1;
- if (checkEnd && result) {
- // instead of returning true right away, we'll only return true
- // the
- // potentially matched tag is indeed a tag, for example, if
- // <SCRIPT
- // becomes <SCRIPTS we don't want to say the latter is a critical
- // tag
- int lastPos = posOfCriticalWord + criticalTarget.length();
- if (lastPos < compareText.length()) {
- char lastChar = compareText.charAt(lastPos);
- // Future: check formal definition of this java method, vs.
- // XML
- // parsing rules
- result = (!Character.isLetterOrDigit(lastChar));
- }
- }
- return result;
- }
-
- /**
- * The core reparsing method ... after the dirty start and dirty end have
- * been calculated elsewhere, and the text updated.
- */
- protected StructuredDocumentEvent core_reparse(int rescanStart, int rescanEnd, CoreNodeList oldNodes, boolean firstTime) {
- IStructuredDocumentRegion newNodesHead = null;
- StructuredDocumentEvent result = null;
- newNodesHead = _core_reparse_text(rescanStart, rescanEnd);
- result = _core_reparse_update_model(newNodesHead, rescanStart, rescanEnd, oldNodes, firstTime);
- return result;
- }
-
- /**
- * Resets state to "not parsing"
- */
- private synchronized void endReParse() {
- isParsing = false;
- dirtyStart = null;
- dirtyEnd = null;
- fChanges = null;
- fDeletedText = null;
- fIsEntireDocument = false;
- }
-
- protected IStructuredDocumentRegion findDirtyEnd(int end) {
- // Caution: here's one place we have to cast
- IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(end);
- // if not well formed, get one past, if there is something there
- if ((result != null) && (!result.isEnded())) {
- if (result.getNext() != null) {
- result = result.getNext();
- }
- }
- // also, get one past if exactly equal to the end (this was needed
- // as a simple fix to when a whole exact region is deleted.
- // there's probably a better way.
- if ((result != null) && (end == result.getEnd())) {
- if (result.getNext() != null) {
- result = result.getNext();
- }
- }
- // moved to subclass for quick transition
- // 12/6/2001 - Since we've changed the parser/scanner to allow a lone
- // '<' without
- // always interpretting it as start of a tag name, we need to be a
- // little fancier, in order
- // to "skip" over any plain 'ol content between the lone '<' and any
- // potential meating
- // regions past plain 'ol content.
- // if (isLoneOpenFollowedByContent(result) && (result.getNext() !=
- // null)) {
- // result = result.getNext();
- // }
- if (result != null)
- fStructuredDocument.setCachedDocumentRegion(result);
- dirtyEnd = result;
- return dirtyEnd;
- }
-
- protected void findDirtyStart(int start) {
- IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(start);
- // heuristic: if the postion is exactly equal to the start, then
- // go back one more, if it exists. This prevents problems with
- // insertions
- // of text that should be merged with the previous node instead of
- // simply hung
- // off of it as a separate node (ex.: XML content inserted right
- // before
- // an open
- // bracket should become part of the previous content node)
- if (result != null) {
- IStructuredDocumentRegion previous = result.getPrevious();
- if ((previous != null) && ((!(previous.isEnded())) || (start == result.getStart()))) {
- result = previous;
- }
- // If we are now at the end of a "tag dependent" content area (or
- // JSP area)
- // then we need to back up all the way to the beginning of that.
- IStructuredDocumentRegion potential = result;
- // moved to subclass to speed transition
- // while (isPartOfBlockRegion(potential)) {
- // potential = potential.getPrevious();
- // }
- if (potential != null) {
- result = potential;
- fStructuredDocument.setCachedDocumentRegion(result);
- }
- }
- dirtyStart = result;
- }
-
- protected CoreNodeList formOldNodes(IStructuredDocumentRegion dirtyStart, IStructuredDocumentRegion dirtyEnd) {
- CoreNodeList oldNodes = new CoreNodeList(dirtyStart, dirtyEnd);
- // Now save the old text, that "goes with" the old nodes and regions.
- // Notice we are getting it directly from the text store
- String oldText = null;
- int oldStart = -1;
- int oldEnd = -1;
- // make sure there is some text, if not, use empty string
- // (if one node is not null, the other should ALWAYS be not null too,
- // since it
- // would at least be equal to it.)
- if (dirtyStart != null) {
- oldStart = dirtyStart.getStart();
- oldEnd = dirtyEnd.getEnd();
- oldText = fStructuredDocument.get(oldStart, oldEnd - oldStart);
- } else {
- oldStart = 0;
- oldEnd = 0;
- oldText = ""; //$NON-NLS-1$
- }
- // create a temporary text store for this text
- SubSetTextStore subTextStore = new SubSetTextStore(oldText, oldStart, oldEnd, fStructuredDocument.getLength());
- // Now update the text store of the oldNodes
- StructuredDocumentRegionIterator.setParentDocument(oldNodes, new MinimalDocument(subTextStore));
- return oldNodes;
- }
-
- /**
- * @return Returns the findReplaceDocumentAdapter.
- */
- public FindReplaceDocumentAdapter getFindReplaceDocumentAdapter() {
- if (fFindReplaceDocumentAdapter == null) {
- fFindReplaceDocumentAdapter = new FindReplaceDocumentAdapter(fStructuredDocument);
- }
- return fFindReplaceDocumentAdapter;
- }
-
- // Note: if thead safety is needed, this and all the other public methods
- // of this class
- // should be synchronized.
- public void initialize(Object requester, int start, int lengthToReplace, String changes) {
- isParsing = true;
- fRequester = requester;
- fStart = start;
- fLengthToReplace = lengthToReplace;
- fChanges = changes;
- // notice this one is derived
- fLengthDifference = Utilities.calculateLengthDifference(fChanges, fLengthToReplace);
- fDeletedText = fStructuredDocument.get(fStart, fLengthToReplace);
- int docLength = fStructuredDocument.getLength();
- fIsEntireDocument = lengthToReplace >= docLength && docLength > 0;
- }
-
- protected void insertNodes(IStructuredDocumentRegion previousOldNode, IStructuredDocumentRegion nextOldNode, CoreNodeList newNodes) {
- //
- IStructuredDocumentRegion firstNew = null;
- IStructuredDocumentRegion lastNew = null;
- //
- IStructuredDocumentRegion oldPrevious = previousOldNode;
- IStructuredDocumentRegion oldNext = nextOldNode;
- //
- if (newNodes.getLength() > 0) {
- // get pointers
- firstNew = newNodes.item(0);
- lastNew = newNodes.item(newNodes.getLength() - 1);
- // switch surrounding StructuredDocumentRegions' references to
- // lists
- if (oldPrevious != null)
- oldPrevious.setNext(firstNew);
- if (oldNext != null) {
- oldNext.setPrevious(lastNew);
- } else {
- // SIDE EFFECT
- // if oldNext is null, that means we are replaceing the
- // lastNode in the chain,
- // so we need to update the structuredDocuments lastNode as
- // the
- // last of the new nodes.
- fStructuredDocument.setLastDocumentRegion(newNodes.item(newNodes.getLength() - 1));
- }
- if (firstNew != null)
- firstNew.setPrevious(oldPrevious);
- if (lastNew != null)
- lastNew.setNext(oldNext);
- }
- // else nothing to insert
- }
-
- /**
- * @param oldRegion
- */
- private boolean isCollectionRegion(ITextRegion aRegion) {
- return (aRegion instanceof ITextRegionCollection);
- }
-
- /**
- * @return boolean
- */
- public boolean isParsing() {
- return isParsing;
- }
-
- /**
- * The minimization algorithm simply checks the old nodes to see if any of
- * them "survived" the rescan and are unchanged. If so, the instance of
- * the old node is used instead of the new node. Before the requested
- * change, need to check type, offsets, and text to determine if the same.
- * After the requested change, need to check type and text, but adjust the
- * offsets to what ever the change was.
- */
- protected StructuredDocumentEvent minimumEvent(CoreNodeList oldNodes, CoreNodeList newNodes) {
- StructuredDocumentEvent event = null;
- CoreNodeList minimalOldNodes = null;
- CoreNodeList minimalNewNodes = null;
- // To minimize nodes, we'll collect all those
- // that are not equal into old and new lists
- // Note: we assume that old and new nodes
- // are basically contiguous -- and we force it to be so,
- // by starting at the beginning to
- // find first difference, and then starting at the end to find
- // last difference. Everything in between we assume is different.
- //
- //
- //
- // startOfDifferences is the index into the core node list where the
- // first difference
- // occurs. But it may point into the old or the new list.
- int startOfDifferences = _computeStartOfDifferences(oldNodes, newNodes);
- int endOfDifferencesOld = -1;
- int endOfDifferencesNew = -1;
- // if one of the lists are shorter than where the differences start,
- // then
- // then some portion of the lists are identical
- if ((startOfDifferences >= oldNodes.getLength()) || (startOfDifferences >= newNodes.getLength())) {
- if (oldNodes.getLength() < newNodes.getLength()) {
- // Then there are new regions to add
- // these lengths will cause the vector of old ones to not
- // have any elements, and the vector of new regions to have
- // just the new ones not in common with the old ones
- //startOfDifferences should equal oldNodes.getLength(),
- // calculated above on _computeStartOfDifferences
- minimalOldNodes = EMPTY_LIST;
- endOfDifferencesNew = newNodes.getLength() - 1;
- minimalNewNodes = _formMinimumList(newNodes, startOfDifferences, endOfDifferencesNew);
- } else {
- if (oldNodes.getLength() > newNodes.getLength()) {
- // delete old
- // then there are old regions to delete
- // these lengths will cause the vector of old regions to
- // contain the ones to delete, and the vector of new
- // regions
- // not have any elements
- //startOfDifferences should equal newNodes.getLength(),
- // calculated above on _computeStartOfDifferences
- endOfDifferencesOld = oldNodes.getLength() - 1;
- minimalOldNodes = _formMinimumList(oldNodes, startOfDifferences, endOfDifferencesOld);
- minimalNewNodes = EMPTY_LIST;
- } else
- // unlikely event
- event = new NoChangeEvent(fStructuredDocument, fRequester, fChanges, fStart, fLengthToReplace);
- }
- } else {
- // We found a normal startOfDiffernces, but have not yet found the
- // ends.
- // We'll look for the end of differences by going backwards down
- // the two lists.
- // Here we need a seperate index for each array, since they may be
- // (and
- // probably are) of different lengths.
- int indexOld = oldNodes.getLength() - 1;
- int indexNew = newNodes.getLength() - 1;
- // The greaterThanEffectedRegion is important to gaurd against
- // incorrect counting
- // when something identical is inserted to what's already there
- // (see minimization test case 5)
- // Note: the indexOld > startOfDifferences keeps indexOld from
- // getting too small,
- // so that the subsequent oldNodes.item(indexOld) is always valid.
- while ((indexOld >= startOfDifferences) && (_greaterThanEffectedRegion(oldNodes.item(indexOld)))) {
- if (!(oldNodes.item(indexOld).sameAs(newNodes.item(indexNew), fLengthDifference))) {
- break;
- } else {
- // if they are equal, then we will be keeping the old one,
- // so
- // we need to be sure its parentDocument is set back to
- // the
- // right instance
- oldNodes.item(indexOld).setParentDocument(fStructuredDocument);
- }
- indexOld--;
- indexNew--;
- }
- endOfDifferencesOld = indexOld;
- endOfDifferencesNew = indexNew;
- minimalOldNodes = _formMinimumList(oldNodes, startOfDifferences, endOfDifferencesOld);
- minimalNewNodes = _formMinimumList(newNodes, startOfDifferences, endOfDifferencesNew);
- } /////////////////////////////////////////
- //
- IStructuredDocumentRegion firstDownStreamNode = null;
- event = regionCheck(minimalOldNodes, minimalNewNodes);
- if (event != null) {
- firstDownStreamNode = minimalOldNodes.item(0).getNext();
- if (firstDownStreamNode != null && fLengthDifference != 0) { // if
- // firstDownStream
- // is
- // null,
- // then
- // we're
- // at
- // the
- // end
- // of
- // the
- // document
- StructuredDocumentRegionIterator.adjustStart(firstDownStreamNode, fLengthDifference);
- } //
- } else {
- event = nodesReplacedCheck(minimalOldNodes, minimalNewNodes);
- // now splice the new chain of nodes to where the old chain is (or
- // was)
- // the firstDownStreamNode (the first of those after the new
- // nodes)
- // is
- // remembered as a tiny optimization.
- if (minimalOldNodes.getLength() == 0 && minimalNewNodes.getLength() > 0) {
- // if no old nodes are being deleted, then use the
- // the newNodes offset (minus one) to find the point to
- // update downstream nodes, and after updating downstream
- // nodes postions, insert the new ones.
- int insertOffset = minimalNewNodes.item(0).getStartOffset();
- IStructuredDocumentRegion lastOldUnchangedNode = null;
- if (insertOffset > 0) {
- lastOldUnchangedNode = fStructuredDocument.getRegionAtCharacterOffset(insertOffset - 1);
- firstDownStreamNode = lastOldUnchangedNode.getNext();
- } else {
- // we're inserting at very beginning
- firstDownStreamNode = fStructuredDocument.getFirstStructuredDocumentRegion();
- // SIDE EFFECT: change the firstNode pointer if we're
- // inserting at beginning
- fStructuredDocument.setFirstDocumentRegion(minimalNewNodes.item(0));
- }
- StructuredDocumentRegionIterator.adjustStart(firstDownStreamNode, fLengthDifference);
- insertNodes(lastOldUnchangedNode, firstDownStreamNode, minimalNewNodes);
- // this (nodes replaced) is the only case where we need to
- // update the cached Node
- reSetCachedNode(minimalOldNodes, minimalNewNodes);
- } else {
- firstDownStreamNode = switchNodeLists(minimalOldNodes, minimalNewNodes);
- // no need to adjust the length of the new nodes themselves,
- // they
- // are already correct, but we do need to
- // adjust all "down stream" nodes with the length of the
- // insertion or deletion
- // --- adjustment moved to calling method.
- if (firstDownStreamNode != null) {
- // && event != null
- StructuredDocumentRegionIterator.adjustStart(firstDownStreamNode, fLengthDifference);
- } //
- // this (nodes replaced) is the only case where we need to
- // update the cached Node
- reSetCachedNode(minimalOldNodes, minimalNewNodes);
- }
- }
- return event;
- }
-
- // TODO: This should be abstract.
- public IStructuredTextReParser newInstance() {
- return new StructuredDocumentReParser();
- }
-
- protected StructuredDocumentEvent nodesReplacedCheck(CoreNodeList oldNodes, CoreNodeList newNodes) {
- // actually, nothing to check here, since (and assuming) we've already
- // minimized the number of nodes, and ruled out mere region changes
- StructuredDocumentEvent result = new StructuredDocumentRegionsReplacedEvent(fStructuredDocument, fRequester, oldNodes, newNodes, fChanges, fStart, fLengthToReplace, fIsEntireDocument);
- return result;
- }
-
- /**
- * A method to allow any heuristic "quick checks" that might cover many
- * many cases, before expending the time on a full reparse.
- *
- */
- public StructuredDocumentEvent quickCheck() {
- StructuredDocumentEvent result = null;
- // if the dirty start is null, then we have an empty document.
- // in which case we'll return null so everything can be
- // reparsed "from scratch" . If its not null, we'll give the flatnode
- // a
- // chance
- // to handle, but only if there is one flatnode involved.
- if (dirtyStart != null && dirtyStart == dirtyEnd) {
- IStructuredDocumentRegion targetNode = dirtyStart;
- result = dirtyStart.updateRegion(fRequester, targetNode, fChanges, fStart, fLengthToReplace);
- if (result != null) {
- // at this point only, we need to update the text store and
- // and downstream nodes.
- // FUTURE_TO_DO: can this dependency on structuredDocument
- // method be eliminated?
- fStructuredDocument.updateDocumentData(fStart, fLengthToReplace, fChanges);
- IStructuredDocumentRegion firstDownStreamNode = targetNode.getNext();
- // then flatnode must have been the last one, so need to
- // update
- // any downstream ones
- if (firstDownStreamNode != null) {
- StructuredDocumentRegionIterator.adjustStart(firstDownStreamNode, fLengthDifference);
- }
- }
- }
- if (result != null) {
- result.setDeletedText(fDeletedText);
- }
- return result;
- }
-
- /**
- * If only one node is involved, sees how many regions are changed. If
- * only one, then its a 'regionChanged' event ... if more than one, its a
- * 'regionsReplaced' event.
- */
- protected StructuredDocumentEvent regionCheck(CoreNodeList oldNodes, CoreNodeList newNodes) {
- if (Debug.debugStructuredDocument)
- System.out.println("IStructuredDocument::regionsReplacedCheck"); //$NON-NLS-1$
- //$NON-NLS-1$
- //$NON-NLS-1$
- // the "regionsReplaced" event could only be true if and only if the
- // nodelists
- // are each only "1" in length.
- StructuredDocumentEvent result = null;
- int oldLength = oldNodes.getLength();
- int newLength = newNodes.getLength();
- if ((oldLength != 1) || (newLength != 1)) {
- result = null;
- } else {
- IStructuredDocumentRegion oldNode = oldNodes.item(0);
- IStructuredDocumentRegion newNode = newNodes.item(0);
- result = regionCheck(oldNode, newNode);
- }
- return result;
- }
-
- /**
- * If only one node is involved, sees how many regions are changed. If
- * only one, then its a 'regionChanged' event ... if more than one, its a
- * 'regionsReplaced' event.
- */
- protected StructuredDocumentEvent regionCheck(IStructuredDocumentRegion oldNode, IStructuredDocumentRegion newNode) {
- //
- StructuredDocumentEvent result = null;
- ITextRegionList oldRegions = oldNode.getRegions();
- ITextRegionList newRegions = newNode.getRegions();
- ITextRegion[] oldRegionsArray = oldRegions.toArray();
- ITextRegion[] newRegionsArray = newRegions.toArray();
- //
- // for the 'regionsReplaced' event, we don't care if
- // the regions changed due to type, or text,
- // we'll just collect all those that are not equal
- // into the old and new region lists.
- // Note: we, of course, assume that old and new regions
- // are basically contiguous -- and we force it to be so,
- // even if not literally so, by starting at beginning to
- // find first difference, and then starting at end to find
- // last difference. Everything in between we assume is different.
- //
- // going up is easy, we start at zero in each, and continue
- // till regions are not the same.
- int startOfDifferences = _computeStartOfDifferences(oldNode, oldRegions, newNode, newRegions);
- int endOfDifferencesOld = -1;
- int endOfDifferencesNew = -1;
- //
- //
- // if one of the lists are shorter than where the differences start,
- // then
- // then some portion of the lists are identical
- if ((startOfDifferences >= oldRegions.size()) || (startOfDifferences >= newRegions.size())) {
- if (oldRegions.size() < newRegions.size()) {
- // INSERT CASE
- // then there are new regions to add
- // these lengths will cause the vector of old ones to not
- // have any elements, and the vector of new regions to have
- // just the new ones.
- startOfDifferences = oldRegionsArray.length;
- endOfDifferencesOld = oldRegionsArray.length - 1;
- endOfDifferencesNew = newRegionsArray.length - 1;
- } else {
- if (oldRegions.size() > newRegions.size()) {
- // DELETE CASE
- // then there are old regions to delete
- // these lengths will cause the vector of old regions to
- // contain the ones to delete, and the vector of new
- // regions
- // not have any elements
- startOfDifferences = newRegionsArray.length;
- endOfDifferencesOld = oldRegionsArray.length - 1;
- endOfDifferencesNew = newRegionsArray.length - 1;
- } else {
- // else the lists are identical!
- // unlikely event, probably error in current design, since
- // we check for identity at the very beginning of
- // reparsing.
- result = new NoChangeEvent(fStructuredDocument, fRequester, fChanges, fStart, fLengthToReplace);
- }
- }
- } else {
- if ((startOfDifferences > -1) && (endOfDifferencesOld < 0) && (endOfDifferencesNew < 0)) {
- // We found a normal startOfDiffernces, but have not yet found
- // the ends.
- // We'll look for the end of differences by going backwards
- // down the two lists.
- // Here we need a seperate index for each array, since they
- // may
- // be (and
- // probably are) of different lengths.
- int indexOld = oldRegionsArray.length - 1;
- int indexNew = newRegionsArray.length - 1;
- while ((indexOld >= startOfDifferences) && (_greaterThanEffectedRegion(oldNode, oldRegionsArray[indexOld]))) {
- if ((!(oldNode.sameAs(oldRegionsArray[indexOld], newNode, newRegionsArray[indexNew], fLengthDifference)))) {
- //endOfDifferencesOld = indexOne;
- //endOfDifferencesNew = indexTwo;
- break;
- }
- indexOld--;
- indexNew--;
- }
- endOfDifferencesOld = indexOld;
- endOfDifferencesNew = indexNew;
- }
- }
- //
- // result != null means the impossible case above occurred
- if (result == null) {
- // Now form the two vectors of different regions
- ITextRegionList holdOldRegions = new TextRegionListImpl();
- ITextRegionList holdNewRegions = new TextRegionListImpl();
- if (startOfDifferences > -1 && endOfDifferencesOld > -1) {
- for (int i = startOfDifferences; i <= endOfDifferencesOld; i++) {
- holdOldRegions.add(oldRegionsArray[i]);
- }
- }
- if (startOfDifferences > -1 && endOfDifferencesNew > -1) {
- for (int i = startOfDifferences; i <= endOfDifferencesNew; i++) {
- holdNewRegions.add(newRegionsArray[i]);
- }
- }
- if (holdOldRegions.size() == 0 && holdNewRegions.size() == 0) {
- // then this means the regions were identical, which means
- // someone
- // pasted exactly the same thing they had selected, or !!!
- // someone deleted the end bracket of the tag. !!!?
- result = new NoChangeEvent(fStructuredDocument, fRequester, fChanges, fStart, fLengthToReplace);
- } else {
- //If both holdOldRegions and holdNewRegions are of length 1,
- // then its
- // a "region changed" event, else a "regions replaced" event.
- // so we want the new instance of region to become part of the
- // old instance of old node
- if ((holdOldRegions.size() == 1) && (holdNewRegions.size() == 1) && _regionsSameKind((holdNewRegions.get(0)), (holdOldRegions.get(0)))) {
- ITextRegion newOldRegion = swapNewForOldRegion(oldNode, holdOldRegions.get(0), newNode, holdNewRegions.get(0));
- // -- need to update any down stream regions, within this
- // 'oldNode'
- updateDownStreamRegions(oldNode, newOldRegion);
- result = new RegionChangedEvent(fStructuredDocument, fRequester, oldNode, newOldRegion, fChanges, fStart, fLengthToReplace);
- } else {
- replaceRegions(oldNode, holdOldRegions, newNode, holdNewRegions);
- // -- need to update any down stream regions, within this
- // 'oldNode'
- // don't need with the way replaceRegions is implemented.
- // It handles.
- //if(holdNewRegions.size() > 0)
- //updateDownStreamRegions(oldNode, (ITextRegion)
- // holdNewRegions.lastElement());
- result = new RegionsReplacedEvent(fStructuredDocument, fRequester, oldNode, holdOldRegions, holdNewRegions, fChanges, fStart, fLengthToReplace);
- }
- }
- }
- return result;
- }
-
- /**
- * An entry point for reparsing. It calculates the dirty start and dirty
- * end flatnodes based on the start point and length of the changes.
- *
- */
- public StructuredDocumentEvent reparse() {
- StructuredDocumentEvent result = null;
- // if we do not have a cachedNode, then the document
- // must be empty, so simply use 'null' as the dirtyStart and dirtyEnd
- // otherwise, find them.
- if (fStructuredDocument.getCachedDocumentRegion() != null) {
- findDirtyStart(fStart);
- int end = fStart + fLengthToReplace;
- findDirtyEnd(end);
- }
- if (fStructuredDocument.getCachedDocumentRegion() != null) {
- result = checkHeuristics();
- }
- if (result == null) {
- result = reparse(dirtyStart, dirtyEnd);
- }
- endReParse();
- return result;
- }
-
- /**
- * An entry point for reparsing. It calculates the dirty start and dirty
- * end flatnodes based on suggested positions to begin and end. This is
- * needed for cases where parsing must go beyond the immediate node and
- * its direct neighbors.
- *
- */
- protected StructuredDocumentEvent reparse(int reScanStartHint, int reScanEndHint) {
- StructuredDocumentEvent result = null;
- // if we do not have a cachedNode, then the document
- // must be empty, so simply use 'null' as the dirtyStart and dirtyEnd
- if (fStructuredDocument.getCachedDocumentRegion() != null) {
- findDirtyStart(reScanStartHint);
- findDirtyEnd(reScanEndHint);
- }
- result = reparse(dirtyStart, dirtyEnd);
- isParsing = false;
- // debug
- //verifyStructured(result);
- return result;
- }
-
- /**
- * The core reparsing method ... after the dirty start and dirty end have
- * been calculated elsewhere.
- */
- protected StructuredDocumentEvent reparse(IStructuredDocumentRegion dirtyStart, IStructuredDocumentRegion dirtyEnd) {
- StructuredDocumentEvent result = null;
- int rescanStart = -1;
- int rescanEnd = -1;
- boolean firstTime = false;
- //
- // "save" the oldNodes (that may be replaced) in a list
- CoreNodeList oldNodes = formOldNodes(dirtyStart, dirtyEnd);
- if (dirtyStart == null || dirtyEnd == null) {
- // dirtyStart or dirty end are null, then that means we didn't
- // have
- // a
- // cached node, which means we have an empty document, so we
- // just need to rescan the changes
- rescanStart = 0;
- rescanEnd = fChanges.length();
- firstTime = true;
- } else {
- // set the start of the text to rescan
- rescanStart = dirtyStart.getStart();
- //
- // set the end of the text to rescan
- // notice we use the same rationale as for the rescanStart,
- // with the added caveat that length has to be added to it,
- // to compensate for the new text which has been added or deleted.
- // If changes has zero length, then "length" will be negative,
- // since
- // we are deleting text. Otherwise, use the difference between
- // what's selected to be replaced and the length of the new text.
- rescanEnd = dirtyEnd.getEnd() + fLengthDifference;
- }
- // now that we have the old stuff "saved" away, update the document
- // with the changes.
- // FUTURE_TO_DO -- don't fire "document changed" event till later
- fStructuredDocument.updateDocumentData(fStart, fLengthToReplace, fChanges);
- // ------------------ now the real work
- result = core_reparse(rescanStart, rescanEnd, oldNodes, firstTime);
- //
- // event is returned to the caller, incase there is
- // some opitmization they can do
- return result;
- }
-
- protected void replaceRegions(IStructuredDocumentRegion oldNode, ITextRegionList oldRegions, IStructuredDocumentRegion newNode, ITextRegionList newRegions) {
- int insertPos = -1;
- ITextRegionList regions = oldNode.getRegions();
- // make a fake flatnode to be new parent of oldRegions, so their text
- // will be right.
- //IStructuredDocumentRegion holdOldStructuredDocumentRegion = new
- // BasicStructuredDocumentRegion(oldNode);
- //
- // need to reset the parent of the new to-be-inserted regions to be
- // the
- // same oldNode that is the one having its regions changed
- // DW, 4/16/2003, removed since ITextRegion no longer has parent.
- // ITextRegionContainer oldParent = oldNode;
- // for (int i = 0; i < newRegions.size(); i++) {
- // AbstractRegion region = (AbstractRegion) newRegions.elementAt(i);
- // region.setParent(oldParent);
- // }
- // if there are no old regions, insert the new regions according to
- // offset
- if (oldRegions.size() == 0) {
- ITextRegion firstNewRegion = newRegions.get(0);
- int firstOffset = newNode.getStartOffset(firstNewRegion);
- // if at beginning, insert there
- if (firstOffset == 0) {
- insertPos = 0;
- } else {
- //
- ITextRegion regionAtOffset = oldNode.getRegionAtCharacterOffset(firstOffset);
- if (regionAtOffset == null)
- insertPos = regions.size();
- else
- insertPos = regions.indexOf(regionAtOffset);
- }
- } else {
- // else, delete old ones before inserting new ones in their place
- ITextRegion firstOldRegion = oldRegions.get(0);
- insertPos = regions.indexOf(firstOldRegion);
- regions.removeAll(oldRegions);
- }
- regions.addAll(insertPos, newRegions);
- // now regions vector of each node should be of equal length,
- // so go through each, and make sure the old regions
- // offsets matches the new regions offsets
- // (we'll just assign them all, but could be slightly more effiecient)
- ITextRegionList allNewRegions = newNode.getRegions();
- for (int i = 0; i < regions.size(); i++) {
- ITextRegion nextOldishRegion = regions.get(i);
- ITextRegion nextNewRegion = allNewRegions.get(i);
- nextOldishRegion.equatePositions(nextNewRegion);
- checkAndAssignParent(oldNode, nextOldishRegion);
- }
- oldNode.setLength(newNode.getLength());
- oldNode.setEnded(newNode.isEnded());
- oldNode.setParentDocument(newNode.getParentDocument());
- // removed concept of part of these regions, so no longer need to do.
- // for (int i = 0; i < oldRegions.size(); i++) {
- // ITextRegion region = (ITextRegion) oldRegions.elementAt(i);
- // region.setParent(holdOldStructuredDocumentRegion);
- // }
- }
-
- private void reSetCachedNode(CoreNodeList oldNodes, CoreNodeList newNodes) {
- // use the last newNode as the new cachedNode postion, unless its null
- // (e.g. when nodes are deleted) in which case, assign
- // it to a "safe" node so we don't lose reference to the
- // structuredDocument!
- if (newNodes.getLength() > 0) {
- // use last new node as the cache
- fStructuredDocument.setCachedDocumentRegion(newNodes.item(newNodes.getLength() - 1));
- } else {
- // if cachedNode is an old node, then we're in trouble:
- // we can't leave it as the cached node! and its already
- // been disconnected from the model, so we can't do getNext
- // or getPrevious, so we'll get one that is right before
- // (or right after) the offset of the old nodes that are being
- // deleted.
- //
- // if newNodesHead and cachedNode are both null, then
- // it means we were asked to insert an empty string into
- // an empty document. So we have nothing to do here
- // (that is, we have no node to cache)
- // similarly if there are no new nodes and no old nodes then
- // nothing to do (but that should never happen ... we shouldn't
- // get there if there is no event to generate).
- if ((fStructuredDocument.getCachedDocumentRegion() != null) && (oldNodes.getLength() > 0)) {
- // note: we can't simple use nodeAtCharacterOffset, since it
- // depends on cachedNode.
- if (oldNodes.includes(fStructuredDocument.getCachedDocumentRegion()))
- fStructuredDocument.setCachedDocumentRegion(fStructuredDocument.getFirstStructuredDocumentRegion());
- }
- if ((fStructuredDocument.getCachedDocumentRegion() == null) && (Debug.displayWarnings)) {
- // this will happen now legitamately when all text is deleted
- // from a document
- System.out.println("Warning: StructuredDocumentReParser::reSetCachedNode: could not find a node to cache! (its ok if all text deleted)"); //$NON-NLS-1$
- }
- }
- }
-
- public void setStructuredDocument(IStructuredDocument newStructuredDocument) {
- // NOTE: this method (and class) depend on being able to
- // do the following cast (i.e. references some fields directly)
- fStructuredDocument = (BasicStructuredDocument) newStructuredDocument;
- fFindReplaceDocumentAdapter = null;
- }
-
- private IStructuredDocumentRegion splice(CoreNodeList oldNodes, CoreNodeList newNodes) {
- //
- IStructuredDocumentRegion firstOld = null;
- IStructuredDocumentRegion firstNew = null;
- IStructuredDocumentRegion lastOld = null;
- IStructuredDocumentRegion lastNew = null;
- //
- IStructuredDocumentRegion oldPrevious = null;
- IStructuredDocumentRegion oldNext = null;
- IStructuredDocumentRegion newPrevious = null;
- IStructuredDocumentRegion newNext = null;
- //
- // if called with both arguments empty lists, we can disregard.
- // this happens, for example, when some text is replaced with the
- // identical text.
- if ((oldNodes.getLength() == 0) && (newNodes.getLength() == 0)) {
- return null;
- }
- // get pointers
- if (newNodes.getLength() > 0) {
- firstNew = newNodes.item(0);
- lastNew = newNodes.item(newNodes.getLength() - 1);
- }
- //
- if (oldNodes.getLength() > 0) {
- firstOld = oldNodes.item(0);
- lastOld = oldNodes.item(oldNodes.getLength() - 1);
- if (firstOld != null)
- oldPrevious = firstOld.getPrevious();
- if (lastOld != null)
- oldNext = lastOld.getNext();
- }
- // handle switch
- if (newNodes.getLength() > 0) {
- // switch surrounding StructuredDocumentRegions' references to
- // lists
- if (oldPrevious != null)
- oldPrevious.setNext(firstNew);
- if (newPrevious != null)
- newPrevious.setNext(firstOld);
- if (oldNext != null)
- oldNext.setPrevious(lastNew);
- if (newNext != null)
- newNext.setPrevious(lastOld);
- // switch list pointers to surrounding StructuredDocumentRegions
- if (firstOld != null)
- firstOld.setPrevious(newPrevious);
- if (lastOld != null)
- lastOld.setNext(newNext);
- if (firstNew != null)
- firstNew.setPrevious(oldPrevious);
- if (lastNew != null)
- lastNew.setNext(oldNext);
- } else {
- // short circuit when there are no new nodes
- if (oldPrevious != null)
- oldPrevious.setNext(oldNext);
- if (oldNext != null)
- oldNext.setPrevious(oldPrevious);
- }
- //
- // SIDE EFFECTs
- // if we have oldNodes, and if oldNext or oldPrevious is null,
- // that means we are replacing
- // the lastNode or firstNode the structuredDocuments's chain of nodes,
- // so we need to update the structuredDocuments last or first Node
- // as the last or first of the new nodes.
- // (and sometimes even these will be null! such as when deleting all
- // text in a document).
- if ((oldNext == null) && (oldNodes.getLength() > 0)) {
- if (newNodes.getLength() > 0) {
- fStructuredDocument.setLastDocumentRegion(lastNew);
- } else {
- // in this case, the last node is being deleted, but not
- // replaced
- // with anything. In this case, we can just back up one
- // from the first old node
- fStructuredDocument.setLastDocumentRegion(firstOld.getPrevious());
- }
- }
- if ((oldPrevious == null) && (oldNodes.getLength() > 0)) {
- if (newNodes.getLength() > 0) {
- fStructuredDocument.setFirstDocumentRegion(firstNew);
- } else {
- // in this case the first node is being deleted, but not
- // replaced
- // with anything. So, we just go one forward past the last old
- // node.
- fStructuredDocument.setFirstDocumentRegion(lastOld.getNext());
- }
- }
- // as a tiny optimization, we return the first of the downstream
- // nodes,
- // if any
- return oldNext;
- }
-
- /**
- * The purpose of this method is to "reuse" the old container region, when
- * found to be same (so same instance doesn't change). The goal is to
- * "transform" the old region, so its equivelent to the newly parsed one.
- *
- */
- private ITextRegion swapNewForOldRegion(IStructuredDocumentRegion oldNode, ITextRegion oldRegion, IStructuredDocumentRegion newNode, ITextRegion newRegion) {
- // makes the old region instance the correct size.
- oldRegion.equatePositions(newRegion);
- // adjusts old node instance appropriately
- oldNode.setLength(newNode.getLength());
- oldNode.setEnded(newNode.isEnded());
- // we do have to set the parent document, since the oldNode's
- // were set to a temporary one, then newNode's have the
- // right one.
- oldNode.setParentDocument(newNode.getParentDocument());
- // if we're transforming a container region, we need to be sure to
- // transfer the new embedded regions, to the old parent
- // Note: if oldRegion hasEmbeddedRegions, then we know the
- // newRegion does too, since we got here because they were the
- // same type.
- if (isCollectionRegion(oldRegion)) { // ||
- // hasContainerRegions(oldRegion))
- // {
- transferEmbeddedRegions(oldNode, (ITextRegionContainer) oldRegion, (ITextRegionContainer) newRegion);
- }
- return oldRegion;
- }
-
- private IStructuredDocumentRegion switchNodeLists(CoreNodeList oldNodes, CoreNodeList newNodes) {
- IStructuredDocumentRegion result = splice(oldNodes, newNodes);
- // ensure that the old nodes hold no references to the existing model
- if (oldNodes.getLength() > 0) {
- IStructuredDocumentRegion firstItem = oldNodes.item(0);
- firstItem.setPrevious(null);
- IStructuredDocumentRegion lastItem = oldNodes.item(oldNodes.getLength() - 1);
- lastItem.setNext(null);
- }
- return result;
- }
-
- /**
- * The purpose of this method is to "reuse" the old container region, when
- * found to be same (so same instance doesn't change). The goal is to
- * "transform" the old region, so its equivelent to the newly parsed one.
- *
- */
- private void transferEmbeddedRegions(IStructuredDocumentRegion oldNode, ITextRegionContainer oldRegion, ITextRegionContainer newRegion) {
- // the oldRegion should already have the right parent, since
- // we got here because all's equivelent except the region
- // postions have changed.
- //oldRegion.setParent(newRegion.getParent());
- // but we should check if there's "nested" embedded regions, and if
- // so, we can just move them over. setting their parent as this old
- // region.
- ITextRegionList newRegionsToTransfer = newRegion.getRegions();
- oldRegion.setRegions(newRegionsToTransfer);
- Iterator newRegionsInOldOne = newRegionsToTransfer.iterator();
- while (newRegionsInOldOne.hasNext()) {
- ITextRegion newOne = (ITextRegion) newRegionsInOldOne.next();
- if (isCollectionRegion(newOne)) { // ||
- // hasContainerRegions(newOne)) {
- //((ITextRegionContainer) newOne).setParent(oldRegion);
- oldRegion.setRegions(newRegion.getRegions());
- }
- }
- }
-
- private void updateDownStreamRegions(IStructuredDocumentRegion flatNode, ITextRegion lastKnownRegion) {
- // so all regions after the last known region (last known to be ok)
- // have to have their start and end values adjusted.
- ITextRegionList regions = flatNode.getRegions();
- int listLength = regions.size();
- int startIndex = 0;
- // first, loop through to find where to start
- for (int i = 0; i < listLength; i++) {
- ITextRegion region = regions.get(i);
- if (region == lastKnownRegion) {
- startIndex = i;
- break;
- }
- }
- // now, beginning one past the last known one, loop
- // through to end of list, adjusting the start and end postions.
- startIndex++;
- for (int j = startIndex; j < listLength; j++) {
- ITextRegion region = regions.get(j);
- region.adjustStart(fLengthDifference);
- }
- }
-}

Back to the top