private final void processNode(SemanticToken token, DartNode node) {
   token.update(node);
   token.attachSource(fSourceViewer.getDocument());
   // sometimes node has wrong source range; log problem
   if (token.getSource() == null) {
     IDocument document = fSourceViewer.getDocument();
     if (node != null && document != null) {
       SourceInfo sourceInfo = node.getSourceInfo();
       if (sourceInfo != null) {
         DartToolsPlugin.log(
             "Bad node: "
                 + node.getClass().getName()
                 + " offset:"
                 + sourceInfo.getOffset()
                 + " len:"
                 + sourceInfo.getLength()
                 + " in document: "
                 + document.getLength());
       }
     }
     return;
   }
   // try SemanticHighlighting instances
   for (int i = 0, n = fJobSemanticHighlightings.length; i < n; i++) {
     if (fJobHighlightings[i].isEnabled()) {
       SemanticHighlighting semanticHighlighting = fJobSemanticHighlightings[i];
       // try multiple positions
       {
         List<SourceRange> ranges = semanticHighlighting.consumesMulti(token);
         if (ranges != null) {
           for (SourceRange range : ranges) {
             int offset = range.getOffset();
             int length = range.getLength();
             if (offset > -1 && length > 0) {
               fCollector.addPosition(offset, length, fJobHighlightings[i]);
             }
           }
           break;
         }
       }
       // try single position
       boolean consumes;
       if (node instanceof DartIdentifier) {
         consumes = semanticHighlighting.consumesIdentifier(token);
       } else {
         consumes = semanticHighlighting.consumes(token);
       }
       if (consumes) {
         int offset = node.getSourceInfo().getOffset();
         int length = node.getSourceInfo().getLength();
         if (offset > -1 && length > 0) {
           fCollector.addPosition(offset, length, fJobHighlightings[i]);
         }
         break;
       }
     }
   }
   token.clear();
 }
 protected Position getCurrentLinePosition() {
   Point selection = fViewer.getTextWidget().getSelectionRange();
   if (selection.y != 0) {
     return null;
   }
   try {
     int line = fViewer.getDocument().getLineOfOffset(selection.x);
     return new Position(fViewer.getDocument().getLineOffset(line), 0);
   } catch (BadLocationException e) {
     return null;
   }
 }
  /**
   * This level gives back only partition level scopes.
   *
   * @throws Exception
   */
  public void testGetScopeAtOffsetDoc() throws Exception {
    setUpStandardScopes();

    createAndOpenFile(
        "testing",
        ".js",
        "if(Object.isUndefined(Effect))\nthrow(\"dragdrop.js requires including script.aculo.us' effects.js library\");");
    ISourceViewer viewer = TextEditorUtils.getSourceViewer(editor);

    assertScope("source.js", 1, viewer.getDocument());
    assertScope("source.js", 7, viewer.getDocument());
    assertScope("source.js string.quoted.double.js", 50, viewer.getDocument());
  }
 /**
  * Helper function for {@link #getHoverInfo(ISourceViewer, int)}.
  *
  * @see #getHoverInfo(ISourceViewer, int)
  * @param sourceViewer The viewer whose annotation we wish to find.
  * @param lineNumber The line number in which the annotation(s) are.
  * @return The list of markers residing in the given line in the given editor.
  */
 protected List<IMarker> getMarkerForLine(final ISourceViewer sourceViewer, final int lineNumber) {
   List<IMarker> markers = new ArrayList<IMarker>();
   IAnnotationModel annotationModel = sourceViewer.getAnnotationModel();
   if (annotationModel == null) {
     return markers;
   }
   Iterator<?> iterator = annotationModel.getAnnotationIterator();
   while (iterator.hasNext()) {
     Object o = iterator.next();
     if (o instanceof MarkerAnnotation) {
       MarkerAnnotation actuaMarkerl = (MarkerAnnotation) o;
       try {
         int actualLine =
             sourceViewer
                 .getDocument()
                 .getLineOfOffset(annotationModel.getPosition(actuaMarkerl).getOffset());
         if (actualLine == lineNumber) {
           markers.add(actuaMarkerl.getMarker());
         }
       } catch (BadLocationException e) {
         ErrorReporter.logExceptionStackTrace(e);
       }
     }
   }
   return markers;
 }
  /*
   * @see IPainter#paint(int)
   */
  public void paint(int reason) {
    if (fViewer == null) {
      return;
    }
    if (fViewer.getDocument() == null) {
      deactivate(false);
      return;
    }

    // initialization
    if (!fIsActive) {
      StyledText textWidget = fViewer.getTextWidget();
      textWidget.addLineBackgroundListener(this);
      textWidget.addPaintListener(this);
      fPositionManager.managePosition(fCurrentLine);
      fIsActive = true;
    }

    // This forces redraw of the line highlight
    if (updateHighlightLine()) {
      // clear last line
      // Fix the background colors for tokens that didn't have the same as line!
      if (isOpaque() && !fLastLine.isDeleted() && fViewer instanceof ITextViewerExtension2) {
        ITextViewerExtension2 ext = (ITextViewerExtension2) fViewer;
        try {
          ext.invalidateTextPresentation(fLastLine.getOffset(), fLastLine.getLength());
        } catch (Exception e) {
          IdeLog.logError(CommonEditorPlugin.getDefault(), e);
        }
      }
      drawHighlightLine(fLastLine);
      // draw new line
      drawHighlightLine(fCurrentLine);
    }
  }
  private void doJSPELHyperlinkTestForELInTagBodyTest(
      String pageName, String template, String editorName) throws BadLocationException {
    IEditorPart editor = WorkbenchUtils.openEditor(pageName);
    assertTrue(editor instanceof JSPMultiPageEditor);
    JSPMultiPageEditor jspMultyPageEditor = (JSPMultiPageEditor) editor;
    ISourceViewer viewer = jspMultyPageEditor.getSourceEditor().getTextViewer();
    assertNotNull("Viewer couldn't be found for " + pageName, viewer);
    IDocument document = viewer.getDocument();
    IRegion reg =
        new FindReplaceDocumentAdapter(document).find(0, template, true, true, false, false);
    assertNotNull("Text: " + template + " not found", reg);

    IHyperlink[] links =
        elHyperlinkDetector.detectHyperlinks(
            viewer, new Region(reg.getOffset() + reg.getLength() - 1, 0), true);

    assertNotNull("Hyperlinks for EL:#{" + template + "} are not found", links);

    assertTrue("Hyperlinks for EL: #{" + template + "} are not found", links.length != 0);

    boolean found = false;
    for (IHyperlink link : links) {
      assertNotNull(link.toString());

      link.open();

      IEditorPart resultEditor =
          PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
      if (editorName.equals(resultEditor.getTitle())) {
        found = true;
        return;
      }
    }
    assertTrue("OpenOn have not opened " + editorName + " editor", found);
  }
 public IProject getProject() {
   IDocument doc = sourceViever.getDocument();
   if (doc != null) {
     return DocumentUtil.getProject(doc);
   }
   return null;
 }
 protected boolean isCurrentLine(int line) {
   try {
     int lineNumber = fViewer.getDocument().getLineOfOffset(getModelCaret());
     return line == lineNumber; // current line!
   } catch (BadLocationException e) {
     return false;
   }
 }
  /**
   * Post-save operations : re-wrapping if needed
   *
   * @param aSourceViewer The editor source viewer
   */
  public void postEditorPerformSave(final ISourceViewer aSourceViewer) {

    final IDocument document = aSourceViewer.getDocument();

    if (LineWrapUtil.get().isActiveMode(LineWrapMode.SOFT)) {
      pAutoEditLineWrap.registerListener(document);
      pAutoEditLineWrap.wrapWholeDocument();
    }
  }
    public void install() {
      ISourceViewer sourceViewer = editor.getISourceViewer();
      if (sourceViewer == null) return;

      StyledText text = sourceViewer.getTextWidget();
      if (text == null || text.isDisposed()) return;

      sourceViewer.addTextInputListener(this);

      IDocument document = sourceViewer.getDocument();
      if (document != null) document.addDocumentListener(this);
    }
  /** @return Returns the ValidatorStrategy. */
  protected ValidatorStrategy getValidatorStrategy() {
    ValidatorStrategy validatorStrategy = null;
    if (fValidatorStrategy == null && fValidationEnabled) {
      if (getTextViewer() instanceof ISourceViewer) {
        ISourceViewer viewer = (ISourceViewer) getTextViewer();
        String contentTypeId = null;

        IDocument doc = viewer.getDocument();
        contentTypeId = getContentType(doc);

        if (contentTypeId != null) {
          validatorStrategy = new ValidatorStrategy(viewer, contentTypeId);
          ValidatorBuilder vBuilder = new ValidatorBuilder();
          ValidatorMetaData[] vmds = vBuilder.getValidatorMetaData(SSE_UI_ID);
          List enabledValidators = new ArrayList(1);
          /* if any "must" handle this content type, just add them */
          boolean foundSpecificContentTypeValidators = false;
          for (int i = 0; i < vmds.length; i++) {
            if (vmds[i].mustHandleContentType(contentTypeId)) {
              if (DEBUG_VALIDATORS)
                Logger.log(
                    Logger.INFO,
                    contentTypeId
                        + " using specific validator "
                        + vmds[i].getValidatorId()); // $NON-NLS-1$
              foundSpecificContentTypeValidators = true;
              enabledValidators.add(vmds[i]);
            }
          }
          if (!foundSpecificContentTypeValidators) {
            for (int i = 0; i < vmds.length; i++) {
              if (vmds[i].canHandleContentType(contentTypeId)) {
                if (DEBUG_VALIDATORS)
                  Logger.log(
                      Logger.INFO,
                      contentTypeId
                          + " using inherited(?) validator "
                          + vmds[i].getValidatorId()); // $NON-NLS-1$
                enabledValidators.add(vmds[i]);
              }
            }
          }
          for (int i = 0; i < enabledValidators.size(); i++) {
            validatorStrategy.addValidatorMetaData((ValidatorMetaData) enabledValidators.get(i));
          }
        }
      }
      fValidatorStrategy = validatorStrategy;
    } else if (fValidatorStrategy != null && fValidationEnabled) {
      validatorStrategy = fValidatorStrategy;
    }
    return validatorStrategy;
  }
  /**
   * On-save operations :
   *
   * <p>* Un-wrapping if needed
   *
   * <p>* Auto section markers normalization
   *
   * <p>* Auto formating when the editor saves the file
   *
   * @param aSourceViewer The editor source viewer
   */
  public void onEditorPerformSave(final ISourceViewer aSourceViewer) {

    final IDocument document = aSourceViewer.getDocument();

    if (pPreferenceStore.getBoolean(IEditorPreferenceConstants.EDITOR_SAVE_RESET_MARKERS)) {
      // Auto section blocks normalization

      RestContentOutlinePage outlinePage = null;

      if (pEditor != null) {
        outlinePage = pEditor.getOutlinePage();
      }

      if (outlinePage != null) {

        // Don't forget to refresh the tree !
        outlinePage.update();

        OutlineUtil.normalizeSectionsMarker(
            pEditor.getOutlinePage().getContentProvider().getRoot());
      }
    }

    // Formatting text _must_ be the last thing to do : it modifies the
    // document content, therefore it may induce unpredictable behavior for
    // next document readers
    if (pPreferenceStore.getBoolean(IEditorPreferenceConstants.EDITOR_SAVE_FORMAT)) {
      // Text format on save

      // Doc informations
      IRegion docRegion = new Region(0, document.getLength());

      // Store current pointer location
      Point currentLocation = aSourceViewer.getSelectedRange();

      // Format the document
      pDocFormatter.format(document, docRegion);

      // Reset point location
      aSourceViewer.setSelectedRange(currentLocation.x, currentLocation.y);
    }

    if (LineWrapUtil.get().isActiveMode(LineWrapMode.SOFT)) {
      // Soft wrap mode : remove all added end-of-line

      pAutoEditLineWrap.unregisterListener();
      pAutoEditLineWrap.removeWrapping();
    }
  }
  /**
   * Updates all the cached information about the lines to be painted and to be cleared. Returns
   * <code>true</code> if the line number of the cursor line has changed.
   *
   * @return <code>true</code> if cursor line changed
   */
  private boolean updateHighlightLine() {
    try {

      IDocument document = fViewer.getDocument();
      int modelCaret = getModelCaret();
      int lineNumber = document.getLineOfOffset(modelCaret);
      Point selection = fViewer.getTextWidget().getSelectionRange();

      // redraw if the current line number is different from the last line number we painted
      // initially fLastLineNumber is -1
      if (lineNumber != fLastLineNumber
          || !overlaps(fCurrentLine, modelCaret)
          || (selection.y != 0)) {
        // Handle non-empty selections (turn off highlight line)
        if (selection.y != 0 && fLastLine.equals(fCurrentLine)) {
          if (fLastSelection.equals(selection)) // selection didn't change
          {
            return false; // don't redraw the highlight line
          }
          fLastSelection = selection;
          return true; // selection changed
        }
        fLastSelection = selection;
        // Update the current and last lines
        fLastLine.offset = fCurrentLine.offset;
        fLastLine.length = fCurrentLine.length;
        fLastLine.isDeleted = fCurrentLine.isDeleted;

        if (fCurrentLine.isDeleted) {
          fCurrentLine.isDeleted = false;
          fPositionManager.managePosition(fCurrentLine);
        }

        fCurrentLine.offset = document.getLineOffset(lineNumber);
        if (lineNumber == document.getNumberOfLines() - 1) {
          fCurrentLine.length = document.getLength() - fCurrentLine.offset;
        } else {
          fCurrentLine.length = document.getLineOffset(lineNumber + 1) - fCurrentLine.offset;
        }

        fLastLineNumber = lineNumber;
        return true;
      }
    } catch (BadLocationException e) {
    }

    return false;
  }
  /**
   * Sets the caret to the offset of the given element.
   *
   * @param element has to be contained in the resource of this editor.
   */
  public void setCaret(EObject element, String text) {
    try {
      if (element == null || text == null || text.equals("")) {
        return;
      }
      ISourceViewer viewer = getSourceViewer();
      com.github.funthomas424242.rezeptsammler.rezept.resource.rezept.IRezeptTextResource
          textResource =
              (com.github.funthomas424242.rezeptsammler.rezept.resource.rezept.IRezeptTextResource)
                  element.eResource();
      com.github.funthomas424242.rezeptsammler.rezept.resource.rezept.IRezeptLocationMap
          locationMap = textResource.getLocationMap();
      int destination = locationMap.getCharStart(element);
      int length = locationMap.getCharEnd(element) + 1 - destination;

      com.github.funthomas424242.rezeptsammler.rezept.resource.rezept.IRezeptTextScanner lexer =
          getResource().getMetaInformation().createLexer();
      try {
        lexer.setText(viewer.getDocument().get(destination, length));
        com.github.funthomas424242.rezeptsammler.rezept.resource.rezept.IRezeptTextToken token =
            lexer.getNextToken();
        String tokenText = token.getText();
        while (tokenText != null) {
          if (token.getText().equals(text)) {
            destination += token.getOffset();
            break;
          }
          token = lexer.getNextToken();
          if (token == null) {
            break;
          }
          tokenText = token.getText();
        }
      } catch (BadLocationException e) {
      }
      destination = ((ProjectionViewer) viewer).modelOffset2WidgetOffset(destination);
      if (destination < 0) {
        destination = 0;
      }
      viewer.getTextWidget().setSelection(destination);
    } catch (Exception e) {
      com.github.funthomas424242.rezeptsammler.rezept.resource.rezept.ui.RezeptUIPlugin.logError(
          "Exception in setCaret()", e);
    }
  }
    public void install() {
      final ISourceViewer sourceViewer = erlangEditor.getViewer();
      if (sourceViewer == null) {
        return;
      }

      final StyledText text = sourceViewer.getTextWidget();
      if (text == null || text.isDisposed()) {
        return;
      }

      sourceViewer.addTextInputListener(this);

      final IDocument document = sourceViewer.getDocument();
      if (document != null) {
        document.addDocumentListener(this);
      }
    }
  public void lineGetBackground(LineBackgroundEvent event) {
    if (fViewer == null) {
      return;
    }
    final StyledText textWidget = fViewer.getTextWidget();
    if (textWidget == null) {
      return;
    }

    try {
      final int offset = event.lineOffset;
      IDocument document = fViewer.getDocument();
      int line = document.getLineOfOffset(offset);
      final IRegion lineRegion = document.getLineInformation(line);

      // Handle fully opaque line highlight here. A modified approach from CursorLinePainter.
      if (fEnabled && isOpaque() && isCurrentLine(line)) {
        // draw current line
        drawCurrentLine(event, lineRegion);
        return;
      }

      // Not drawing an opaque line highlight, so we need to do our normal line coloring here.
      // This extends the bg color out for a given line based on it's end scope.
      String endOfLineScope =
          getScopeManager().getScopeAtOffset(document, lineRegion.getLength() + offset);
      String commonPrefix = getScope(document, line, endOfLineScope);
      TextAttribute at = getCurrentTheme().getTextAttribute(commonPrefix);

      // if we have no color we need to extend to end of line, but this used to be the highlight
      // line, force the
      // theme bg color
      if (at.getBackground() == null && isOpaque() && fLastLine.includes(offset)) {
        event.lineBackground = getColorManager().getColor(getCurrentTheme().getBackground());
      } else {
        event.lineBackground = at.getBackground();
      }
    } catch (BadLocationException e) {
      IdeLog.logError(CommonEditorPlugin.getDefault(), e);
    }
  }
  protected Object getHoverInfoForLine(ISourceViewer viewer, int line) {
    IAnnotationModel model = viewer.getAnnotationModel();
    IDocument document = viewer.getDocument();

    if (model == null) return null;

    List<Annotation> exact = new ArrayList<>();
    HashMap<Position, Object> messagesAtPosition = new HashMap<>();

    Iterator<Annotation> e = model.getAnnotationIterator();
    while (e.hasNext()) {
      Annotation annotation = e.next();
      Position position = model.getPosition(annotation);
      if (position == null) continue;

      if (compareRulerLine(position, document, line) == 1) {
        if (isDuplicateMessage(messagesAtPosition, position, annotation.getText())) continue;

        exact.add(annotation);
      }
    }

    if (exact.size() < 1) return null;

    sort(exact, model);

    if (exact.size() > 0) setLastRulerMouseLocation(viewer, line);

    AnnotationHoverInput input = new AnnotationHoverInput();
    input.fAnnotations = exact.toArray(new Annotation[0]);
    input.fViewer = viewer;
    input.fRulerInfo = fCompositeRuler;
    input.fAnnotationListener = fgListener;
    input.fDoubleClickListener = fDblClickListener;
    input.model = model;

    return input;
  }
    /**
     * Tries to make a text hover focusable (or "sticky").
     *
     * @param sourceViewer the source viewer to display the hover over
     * @param textHover the hover to make focusable
     * @return <code>true</code> if successful, <code>false</code> otherwise
     */
    @SuppressWarnings("deprecation")
    private boolean makeTextHoverFocusable(ISourceViewer sourceViewer, ITextHover textHover) {
      Point hoverEventLocation = ((ITextViewerExtension2) sourceViewer).getHoverEventLocation();
      int offset =
          computeOffsetAtLocation(sourceViewer, hoverEventLocation.x, hoverEventLocation.y);
      if (offset == -1) return false;

      try {
        IRegion hoverRegion = textHover.getHoverRegion(sourceViewer, offset);
        if (hoverRegion == null) return false;

        String hoverInfo = textHover.getHoverInfo(sourceViewer, hoverRegion);

        IInformationControlCreator controlCreator = null;
        if (textHover instanceof IInformationProviderExtension2)
          controlCreator =
              ((IInformationProviderExtension2) textHover).getInformationPresenterControlCreator();

        IInformationProvider informationProvider =
            new InformationProvider(hoverRegion, hoverInfo, controlCreator);

        fInformationPresenter.setOffset(offset);
        fInformationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_BOTTOM);
        fInformationPresenter.setMargins(
            6, 6); // default values from AbstractInformationControlManager
        String contentType =
            TextUtilities.getContentType(
                sourceViewer.getDocument(), AutoconfPartitionScanner.AUTOCONF_MACRO, offset, true);
        fInformationPresenter.setInformationProvider(informationProvider, contentType);
        fInformationPresenter.showInformation();

        return true;

      } catch (BadLocationException e) {
        return false;
      }
    }
  public void start() {
    if (getActiveLinkedMode() != null) {
      // for safety; should already be handled in RenameDartElementAction
      fgActiveLinkedMode.startFullDialog();
      return;
    }

    ISourceViewer viewer = fEditor.getViewer();
    IDocument document = viewer.getDocument();
    fOriginalSelection = viewer.getSelectedRange();
    int offset = fOriginalSelection.x;

    try {
      fLinkedPositionGroup = new LinkedPositionGroup();
      prepareElement();
      if (fDartElement == null) {
        return;
      }

      if (viewer instanceof ITextViewerExtension6) {
        IUndoManager undoManager = ((ITextViewerExtension6) viewer).getUndoManager();
        if (undoManager instanceof IUndoManagerExtension) {
          IUndoManagerExtension undoManagerExtension = (IUndoManagerExtension) undoManager;
          IUndoContext undoContext = undoManagerExtension.getUndoContext();
          IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory();
          fStartingUndoOperation = operationHistory.getUndoOperation(undoContext);
        }
      }

      fOriginalName = nameNode.getName();
      final int pos = nameNode.getOffset();
      final List<ASTNode> sameNodes = Lists.newArrayList();
      nameNode
          .getRoot()
          .accept(
              new RecursiveASTVisitor<Void>() {
                @Override
                public Void visitSimpleIdentifier(SimpleIdentifier node) {
                  Element element = node.getElement();
                  element = getCanonicalElement(element);
                  if (Objects.equal(element, fDartElement)) {
                    sameNodes.add(node);
                  }
                  return super.visitSimpleIdentifier(node);
                }
              });

      // TODO: copied from LinkedNamesAssistProposal#apply(..):
      // sort for iteration order, starting with the node @ offset
      Collections.sort(
          sameNodes,
          new Comparator<ASTNode>() {
            @Override
            public int compare(ASTNode o1, ASTNode o2) {
              return rank(o1) - rank(o2);
            }

            /**
             * Returns the absolute rank of an <code>ASTNode</code>. Nodes preceding <code>pos
             * </code> are ranked last.
             *
             * @param node the node to compute the rank for
             * @return the rank of the node with respect to the invocation offset
             */
            private int rank(ASTNode node) {
              int relativeRank = node.getOffset() + node.getLength() - pos;
              if (relativeRank < 0) {
                return Integer.MAX_VALUE + relativeRank;
              } else {
                return relativeRank;
              }
            }
          });
      for (int i = 0; i < sameNodes.size(); i++) {
        ASTNode elem = sameNodes.get(i);
        LinkedPosition linkedPosition =
            new LinkedPosition(document, elem.getOffset(), elem.getLength(), i);
        if (i == 0) {
          fNamePosition = linkedPosition;
        }
        fLinkedPositionGroup.addPosition(linkedPosition);
      }

      fLinkedModeModel = new LinkedModeModel();
      fLinkedModeModel.addGroup(fLinkedPositionGroup);
      fLinkedModeModel.forceInstall();
      fLinkedModeModel.addLinkingListener(new EditorHighlightingSynchronizer(fEditor));
      fLinkedModeModel.addLinkingListener(new EditorSynchronizer());

      LinkedModeUI ui = new EditorLinkedModeUI(fLinkedModeModel, viewer);
      ui.setExitPosition(viewer, offset, 0, Integer.MAX_VALUE);
      ui.setExitPolicy(new ExitPolicy(document));
      ui.enter();

      viewer.setSelectedRange(
          fOriginalSelection.x,
          fOriginalSelection.y); // by default, full word is selected; restore original selection

      if (viewer instanceof IEditingSupportRegistry) {
        IEditingSupportRegistry registry = (IEditingSupportRegistry) viewer;
        registry.register(fFocusEditingSupport);
      }

      openSecondaryPopup();
      //			startAnimation();
      fgActiveLinkedMode = this;

    } catch (BadLocationException e) {
      DartToolsPlugin.log(e);
    }
  }
  public void start() {
    if (getActiveLinkedMode() != null) {
      // for safety; should already be handled in RenameDartElementAction
      fgActiveLinkedMode.startFullDialog();
      return;
    }

    ISourceViewer viewer = fEditor.getViewer();
    IDocument document = viewer.getDocument();
    fOriginalSelection = viewer.getSelectedRange();
    int offset = fOriginalSelection.x;

    try {
      DartUnit root =
          ASTProvider.getASTProvider().getAST(getCompilationUnit(), ASTProvider.WAIT_YES, null);

      fLinkedPositionGroup = new LinkedPositionGroup();
      DartNode selectedNode = NodeFinder.perform(root, fOriginalSelection.x, fOriginalSelection.y);
      if (!(selectedNode instanceof DartIdentifier)) {
        return; // TODO: show dialog
      }
      DartIdentifier nameNode = (DartIdentifier) selectedNode;

      if (viewer instanceof ITextViewerExtension6) {
        IUndoManager undoManager = ((ITextViewerExtension6) viewer).getUndoManager();
        if (undoManager instanceof IUndoManagerExtension) {
          IUndoManagerExtension undoManagerExtension = (IUndoManagerExtension) undoManager;
          IUndoContext undoContext = undoManagerExtension.getUndoContext();
          IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory();
          fStartingUndoOperation = operationHistory.getUndoOperation(undoContext);
        }
      }

      fOriginalName = nameNode.getName();
      final int pos = nameNode.getSourceInfo().getOffset();
      DartNode[] sameNodes = LinkedNodeFinder.findByNode(root, nameNode);

      // TODO: copied from LinkedNamesAssistProposal#apply(..):
      // sort for iteration order, starting with the node @ offset
      Arrays.sort(
          sameNodes,
          new Comparator<DartNode>() {
            @Override
            public int compare(DartNode o1, DartNode o2) {
              return rank(o1) - rank(o2);
            }

            /**
             * Returns the absolute rank of an <code>DartNode</code>. Nodes preceding <code>pos
             * </code> are ranked last.
             *
             * @param node the node to compute the rank for
             * @return the rank of the node with respect to the invocation offset
             */
            private int rank(DartNode node) {
              int relativeRank =
                  node.getSourceInfo().getOffset() + node.getSourceInfo().getLength() - pos;
              if (relativeRank < 0) {
                return Integer.MAX_VALUE + relativeRank;
              } else {
                return relativeRank;
              }
            }
          });
      for (int i = 0; i < sameNodes.length; i++) {
        DartNode elem = sameNodes[i];
        LinkedPosition linkedPosition =
            new LinkedPosition(
                document, elem.getSourceInfo().getOffset(), elem.getSourceInfo().getLength(), i);
        if (i == 0) {
          fNamePosition = linkedPosition;
        }
        fLinkedPositionGroup.addPosition(linkedPosition);
      }

      fLinkedModeModel = new LinkedModeModel();
      fLinkedModeModel.addGroup(fLinkedPositionGroup);
      fLinkedModeModel.forceInstall();
      fLinkedModeModel.addLinkingListener(new EditorHighlightingSynchronizer(fEditor));
      fLinkedModeModel.addLinkingListener(new EditorSynchronizer());

      LinkedModeUI ui = new EditorLinkedModeUI(fLinkedModeModel, viewer);
      ui.setExitPosition(viewer, offset, 0, Integer.MAX_VALUE);
      ui.setExitPolicy(new ExitPolicy(document));
      ui.enter();

      viewer.setSelectedRange(
          fOriginalSelection.x,
          fOriginalSelection.y); // by default, full word is selected; restore original selection

      if (viewer instanceof IEditingSupportRegistry) {
        IEditingSupportRegistry registry = (IEditingSupportRegistry) viewer;
        registry.register(fFocusEditingSupport);
      }

      openSecondaryPopup();
      //			startAnimation();
      fgActiveLinkedMode = this;

    } catch (BadLocationException e) {
      DartToolsPlugin.log(e);
    }
  }
  public String getHoverHelpAt(
      IParseController parseController, ISourceViewer srcViewer, int offset) {
    // If there are any annotations associated with the line that contains
    // the given offset, return those
    try {
      List<Annotation> annotations =
          AnnotationHoverBase.getSourceAnnotationsForLine(
              srcViewer, srcViewer.getDocument().getLineOfOffset(offset));
      if (annotations != null && annotations.size() > 0) {
        // Some annotations have no text, such as breakpoint annotations;
        // if that's all we have, then don't bother returning it
        String msg = AnnotationHoverBase.formatAnnotationList(annotations);
        if (msg != null) {
          return msg;
        }
      }
    } catch (BadLocationException e) {
      return "??? (BadLocationException for annotation)";
    }

    // Otherwise, return a message determined directly or indirectly based
    // on the node whose representation occurs at the given offset

    // Get the current AST; no AST implies no message
    Object ast = parseController.getCurrentAst();
    if (ast == null) return null;

    // Declare variables used in formulating the message
    Object sourceNode = null; // node at current hover point
    Object targetNode = null; // node referenced from current hover point
    Object helpNode = null; // node for which a help message is to be constructed
    String msg = null; // the help message for helpNode

    // Get the node at the given offset; no node implies no message
    ISourcePositionLocator nodeLocator = parseController.getSourcePositionLocator();
    sourceNode = nodeLocator.findNode(ast, offset);
    if (sourceNode == null) return null;

    if (fResolver != null) {
      targetNode = fResolver.getLinkTarget(sourceNode, parseController);
    }

    // If the target node is not null, provide help based on that;
    // otherwise, provide help based on the source node
    if (targetNode != null) helpNode = targetNode;
    else helpNode = sourceNode;

    // Now need to determine whether the help message should be determined
    // based on the text represented by the node or based on some separate
    // text provided through an IDocumentationProvider

    if (docProvider != null) {
      msg = docProvider.getDocumentation(helpNode, parseController);
      if (msg != null) return msg;
    }

    //		// Otherwise, base the help message on the text that is represented
    //		// by the help node
    //		if (helpNode instanceof ASTNode) {
    //			ASTNode def = (ASTNode) helpNode;
    //			msg = getSubstring(parseController, def.getLeftIToken()
    //					.getStartOffset(), def.getRightIToken().getEndOffset());
    //			int maxMsgLen = 80;
    //			if (msg == null || msg.length() == 0)
    //				return "No help available";
    //			else if (msg.length() <= maxMsgLen)
    //				return msg;
    //			else
    //				return msg.subSequence(0, maxMsgLen) + "...";
    //		} else {
    //			return "No help available";
    //		}
    return "no help available";
  }
    /**
     * (non-Javadoc)
     *
     * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
     */
    @SuppressWarnings("fallthrough")
    public void verifyKey(VerifyEvent event) {

      if (!event.doit || getInsertMode() != SMART_INSERT) {
        return;
      }

      ISourceViewer sourceViewer = getSourceViewer();
      IDocument document = sourceViewer.getDocument();

      final Point selection = sourceViewer.getSelectedRange();
      final int offset = selection.x;
      final int length = selection.y;

      switch (event.character) {
        case ']':
          if (!this.fCloseBrackets) {
            return;
          }
          // Fall through

        case ')':
          if (hasCharacterAtOffset(document, offset + length, event.character)) {
            sourceViewer.setSelectedRange(offset + length + 1, 0);
            event.doit = false;
            return;
          }
          break;

        case '(':
          if (hasCharacterToTheRight(document, offset + length, '(')) return;

          // fall through

        case '[':
          if (!this.fCloseBrackets) return;
          if (hasIdentifierToTheRight(document, offset + length)) return;

          // fall through

        case '\'':
          if (event.character == '\'') {
            if (!this.fCloseStrings) return;

            if (hasCharacterAtOffset(document, offset - 1, '\\')) {
              return;
            }

            if (hasCharacterAtOffset(document, offset + length, '\'')) {
              sourceViewer.setSelectedRange(offset + length + 1, 0);
              event.doit = false;
              return;
            }

            if (hasIdentifierToTheLeft(document, offset)
                || hasIdentifierToTheRight(document, offset + length)) {
              return;
            }
          }

          // fall through

        case '"':
          if (event.character == '"') {
            if (!this.fCloseStrings) return;

            if (hasCharacterAtOffset(document, offset - 1, '\\')) {
              return;
            }
            if (hasCharacterAtOffset(document, offset + length, '"')) {
              sourceViewer.setSelectedRange(offset + length + 1, 0);
              event.doit = false;
              return;
            }

            if (hasIdentifierToTheLeft(document, offset)
                || hasIdentifierToTheRight(document, offset + length)) return;
          }

          try {
            //					ITypedRegion partition= TextUtilities.getPartition(document,
            // IJavaPartitions.JAVA_PARTITIONING, offset, true);
            ////					if (! IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType()) &&
            // partition.getOffset() != offset)
            //					if (! IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType()))
            //						return;
            //
            if (!validateEditorInputState()) {
              return;
            }

            final StringBuffer buffer = new StringBuffer();
            buffer.append(event.character);
            buffer.append(getPeerCharacter(event.character));

            document.replace(offset, length, buffer.toString());

            // move to the right of the inserted element
            sourceViewer.setSelectedRange(offset + 1, 0);

            //
            //					BracketLevel level= new BracketLevel();
            //					fBracketLevelStack.push(level);
            //
            //					LinkedPositionGroup group= new LinkedPositionGroup();
            //					group.addPosition(new LinkedPosition(document, offset + 1, 0,
            // LinkedPositionGroup.NO_STOP));
            //
            //					LinkedModeModel model= new LinkedModeModel();
            //					model.addLinkingListener(this);
            //					model.addGroup(group);
            //					model.forceInstall();
            //
            //					level.fOffset= offset;
            //					level.fLength= 2;
            //
            //					// set up position tracking for our magic peers
            //					if (fBracketLevelStack.size() == 1) {
            //						document.addPositionCategory(CATEGORY);
            //						document.addPositionUpdater(fUpdater);
            //					}
            //					level.fFirstPosition= new Position(offset, 1);
            //					level.fSecondPosition= new Position(offset + 1, 1);
            //					document.addPosition(CATEGORY, level.fFirstPosition);
            //					document.addPosition(CATEGORY, level.fSecondPosition);
            //
            //					level.fUI= new EditorLinkedModeUI(model, sourceViewer);
            //					level.fUI.setSimpleMode(true);
            //					level.fUI.setExitPolicy(new ExitPolicy(closingCharacter,
            // getEscapeCharacter(closingCharacter), fBracketLevelStack));
            //					level.fUI.setExitPosition(sourceViewer, offset + 2, 0, Integer.MAX_VALUE);
            //					level.fUI.setCyclingMode(LinkedModeUI.CYCLE_NEVER);
            //					level.fUI.enter();
            //
            //
            //					IRegion newSelection= level.fUI.getSelectedRegion();
            // sourceViewer.setSelectedRange(newSelection.getOffset(), newSelection.getLength());

            event.doit = false;

          } catch (BadLocationException e) {
            BPELUIPlugin.log(e);
          }
          //					catch (BadPositionCategoryException e) {
          //					BPELUIPlugin.log(e);
          //				}
          break;
      }
    }
  /*
   * @see org.eclipse.ui.internal.texteditor.AnnotationExpandHover#getHoverInfoForLine(org.eclipse.jface.text.source.ISourceViewer, int)
   */
  @Override
  protected Object getHoverInfoForLine(final ISourceViewer viewer, final int line) {
    final boolean showTemporaryProblems =
        PreferenceConstants.getPreferenceStore()
            .getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION);
    IAnnotationModel model = viewer.getAnnotationModel();
    IDocument document = viewer.getDocument();

    if (model == null) return null;

    List<Annotation> exact = new ArrayList<Annotation>();
    HashMap<Position, Object> messagesAtPosition = new HashMap<Position, Object>();

    Iterator<Annotation> e = model.getAnnotationIterator();
    while (e.hasNext()) {
      Annotation annotation = e.next();

      if (fAnnotationAccess instanceof IAnnotationAccessExtension)
        if (!((IAnnotationAccessExtension) fAnnotationAccess).isPaintable(annotation)) continue;

      if (annotation instanceof IJavaAnnotation
          && !isIncluded((IJavaAnnotation) annotation, showTemporaryProblems)) continue;

      AnnotationPreference pref = fLookup.getAnnotationPreference(annotation);
      if (pref != null) {
        String key = pref.getVerticalRulerPreferenceKey();
        if (key != null && !fStore.getBoolean(key)) continue;
      }

      Position position = model.getPosition(annotation);
      if (position == null) continue;

      if (compareRulerLine(position, document, line) == 1) {

        if (isDuplicateMessage(messagesAtPosition, position, annotation.getText())) continue;

        exact.add(annotation);
      }
    }

    sort(exact, model);

    if (exact.size() > 0) setLastRulerMouseLocation(viewer, line);

    if (exact.size() > 0) {
      Annotation first = exact.get(0);
      if (!isBreakpointAnnotation(first)) exact.add(0, new NoBreakpointAnnotation());
    }

    if (exact.size() <= 1) return null;

    AnnotationHoverInput input = new AnnotationHoverInput();
    input.fAnnotations = exact.toArray(new Annotation[0]);
    input.fViewer = viewer;
    input.fRulerInfo = fCompositeRuler;
    input.fAnnotationListener = fgListener;
    input.fDoubleClickListener = fDblClickListener;
    input.redoAction =
        new AnnotationExpansionControl.ICallback() {

          public void run(IInformationControlExtension2 control) {
            control.setInput(getHoverInfoForLine(viewer, line));
          }
        };
    input.model = model;

    return input;
  }
  protected void assertContentAssistResults(
      int offset,
      int length,
      String[] expected,
      boolean isCompletion,
      boolean isTemplate,
      boolean filterResults,
      int compareType)
      throws Exception {
    if (CTestPlugin.getDefault().isDebugging()) {
      System.out.println("\n\n\n\n\nTesting " + this.getClass().getName());
    }

    // Call the CContentAssistProcessor
    ISourceViewer sourceViewer = EditorTestHelper.getSourceViewer((AbstractTextEditor) fEditor);
    String contentType =
        TextUtilities.getContentType(
            sourceViewer.getDocument(), ICPartitions.C_PARTITIONING, offset, true);
    boolean isCode = IDocument.DEFAULT_CONTENT_TYPE.equals(contentType);
    ContentAssistant assistant = new ContentAssistant();
    CContentAssistProcessor processor =
        new CContentAssistProcessor(fEditor, assistant, contentType);
    long startTime = System.currentTimeMillis();
    sourceViewer.setSelectedRange(offset, length);
    Object[] results =
        isCompletion
            ? (Object[]) processor.computeCompletionProposals(sourceViewer, offset)
            : (Object[]) processor.computeContextInformation(sourceViewer, offset);
    long endTime = System.currentTimeMillis();
    assertTrue(results != null);

    if (filterResults) {
      if (isTemplate) {
        results = filterResultsKeepTemplates(results);
      } else {
        results = filterResults(results, isCode);
      }
    }
    String[] resultStrings = toStringArray(results, compareType);
    Arrays.sort(expected);
    Arrays.sort(resultStrings);

    if (CTestPlugin.getDefault().isDebugging()) {
      System.out.println("Time (ms): " + (endTime - startTime));
      for (String proposal : resultStrings) {
        System.out.println("Result: " + proposal);
      }
    }

    boolean allFound = true; // for the time being, let's be optimistic

    for (String element : expected) {
      boolean found = false;
      for (String proposal : resultStrings) {
        if (element.equals(proposal)) {
          found = true;
          if (CTestPlugin.getDefault().isDebugging()) {
            System.out.println("Lookup success for " + element);
          }
          break;
        }
      }
      if (!found) {
        allFound = false;
        if (CTestPlugin.getDefault().isDebugging()) {
          System.out.println("Lookup failed for " + element); // $NON-NLS-1$
        }
      }
    }

    if (!allFound) {
      assertEquals("Missing results!", toString(expected), toString(resultStrings));
    } else if (doCheckExtraResults()) {
      assertEquals("Extra results!", toString(expected), toString(resultStrings));
    }
  }
    /**
     * Tries to make an annotation hover focusable (or "sticky").
     *
     * @param sourceViewer the source viewer to display the hover over
     * @param annotationHover the hover to make focusable
     * @return <code>true</code> if successful, <code>false</code> otherwise
     */
    private boolean makeAnnotationHoverFocusable(
        ISourceViewer sourceViewer, IAnnotationHover annotationHover) {
      IVerticalRulerInfo info = getVerticalRuler();
      int line = info.getLineOfLastMouseButtonActivity();
      if (line == -1) return false;

      try {

        // compute the hover information
        Object hoverInfo;
        if (annotationHover instanceof IAnnotationHoverExtension) {
          IAnnotationHoverExtension extension = (IAnnotationHoverExtension) annotationHover;
          ILineRange hoverLineRange = extension.getHoverLineRange(sourceViewer, line);
          if (hoverLineRange == null) return false;
          final int maxVisibleLines =
              Integer
                  .MAX_VALUE; // allow any number of lines being displayed, as we support scrolling
          hoverInfo = extension.getHoverInfo(sourceViewer, hoverLineRange, maxVisibleLines);
        } else {
          hoverInfo = annotationHover.getHoverInfo(sourceViewer, line);
        }

        // hover region: the beginning of the concerned line to place the control right over the
        // line
        IDocument document = sourceViewer.getDocument();
        int offset = document.getLineOffset(line);
        String contentType =
            TextUtilities.getContentType(
                document, AutoconfPartitionScanner.AUTOCONF_MACRO, offset, true);

        IInformationControlCreator controlCreator = null;

        //    			/*
        //    			 * XXX: This is a hack to avoid API changes at the end of 3.2,
        //    			 * and should be fixed for 3.3, see:
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=137967
        //    			 */
        //    			if
        // ("org.eclipse.jface.text.source.projection.ProjectionAnnotationHover".equals(annotationHover.getClass().getName())) { //$NON-NLS-1$
        //    				controlCreator= new IInformationControlCreator() {
        //    					public IInformationControl createInformationControl(Shell shell) {
        //    						int shellStyle= SWT.RESIZE | SWT.TOOL | getOrientation();
        //    						int style= SWT.V_SCROLL | SWT.H_SCROLL;
        //    						return new SourceViewerInformationControl(shell, shellStyle, style);
        //    					}
        //    				};
        //
        //    			} else {
        if (annotationHover instanceof IInformationProviderExtension2)
          controlCreator =
              ((IInformationProviderExtension2) annotationHover)
                  .getInformationPresenterControlCreator();
        else if (annotationHover instanceof IAnnotationHoverExtension)
          controlCreator = ((IAnnotationHoverExtension) annotationHover).getHoverControlCreator();
        //    			}

        IInformationProvider informationProvider =
            new InformationProvider(new Region(offset, 0), hoverInfo, controlCreator);

        fInformationPresenter.setOffset(offset);
        fInformationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_RIGHT);
        fInformationPresenter.setMargins(
            4, 0); // AnnotationBarHoverManager sets (5,0), minus SourceViewer.GAP_SIZE_1
        fInformationPresenter.setInformationProvider(informationProvider, contentType);
        fInformationPresenter.showInformation();

        return true;

      } catch (BadLocationException e) {
        return false;
      }
    }