/**
   * Actually paints the text area. Only lines that have been damaged are repainted.
   *
   * @param g The graphics context with which to paint.
   * @param a The allocated region in which to render.
   */
  @Override
  public void paint(Graphics g, Shape a) {

    RSyntaxDocument document = (RSyntaxDocument) getDocument();

    Rectangle alloc = a.getBounds();

    tabBase = alloc.x;
    host = (RSyntaxTextArea) getContainer();

    Rectangle clip = g.getClipBounds();
    // An attempt to speed things up for files with long lines.  Note that
    // this will actually slow things down a bit for the common case of
    // regular-length lines, but it doesn't make a perceivable difference.
    clipStart = clip.x;
    clipEnd = clipStart + clip.width;

    lineHeight = host.getLineHeight();
    ascent = host.getMaxAscent(); // metrics.getAscent();
    int heightAbove = clip.y - alloc.y;
    int linesAbove = Math.max(0, heightAbove / lineHeight);

    FoldManager fm = host.getFoldManager();
    linesAbove += fm.getHiddenLineCountAbove(linesAbove, true);
    Rectangle lineArea = lineToRect(a, linesAbove);
    int y = lineArea.y + ascent;
    int x = lineArea.x;
    Element map = getElement();
    int lineCount = map.getElementCount();

    // Whether token styles should always be painted, even in selections
    int selStart = host.getSelectionStart();
    int selEnd = host.getSelectionEnd();

    RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) host.getHighlighter();

    Graphics2D g2d = (Graphics2D) g;
    Token token;
    // System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1));

    TokenPainter painter = host.getTokenPainter();
    int line = linesAbove;
    // int count = 0;
    while (y < clip.y + clip.height + ascent && line < lineCount) {

      Fold fold = fm.getFoldForLine(line);
      Element lineElement = map.getElement(line);
      int startOffset = lineElement.getStartOffset();
      // int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 :
      //							lineElement.getEndOffset()-1);
      int endOffset = lineElement.getEndOffset() - 1; // Why always "-1"?
      h.paintLayeredHighlights(g2d, startOffset, endOffset, a, host, this);

      // Paint a line of text.
      token = document.getTokenListForLine(line);
      if (selStart == selEnd || startOffset >= selEnd || endOffset < selStart) {
        drawLine(painter, token, g2d, x, y, line);
      } else {
        // System.out.println("Drawing line with selection: " + line);
        drawLineWithSelection(painter, token, g2d, x, y, selStart, selEnd);
      }

      if (fold != null && fold.isCollapsed()) {

        // Visible indicator of collapsed lines
        Color c = RSyntaxUtilities.getFoldedLineBottomColor(host);
        if (c != null) {
          g.setColor(c);
          g.drawLine(x, y + lineHeight - ascent - 1, host.getWidth(), y + lineHeight - ascent - 1);
        }

        // Skip to next line to paint, taking extra care for lines with
        // block ends and begins together, e.g. "} else {"
        do {
          int hiddenLineCount = fold.getLineCount();
          if (hiddenLineCount == 0) {
            // Fold parser identified a zero-line fold region.
            // This is really a bug, but we'll be graceful here
            // and avoid an infinite loop.
            break;
          }
          line += hiddenLineCount;
          fold = fm.getFoldForLine(line);
        } while (fold != null && fold.isCollapsed());
      }

      y += lineHeight;
      line++;
      // count++;

    }

    // System.out.println("SyntaxView: lines painted=" + count);

  }
Пример #2
0
  /** {@inheritDoc} */
  public void markOccurrences(
      RSyntaxDocument doc,
      Token t,
      RSyntaxTextAreaHighlighter h,
      MarkOccurrencesHighlightPainter p) {

    char[] lexeme = t.getLexeme().toCharArray();
    int tokenOffs = t.getOffset();
    Element root = doc.getDefaultRootElement();
    int lineCount = root.getElementCount();
    int curLine = root.getElementIndex(t.getOffset());

    // For now, we only check for tags on the current line, for
    // simplicity.  Tags spanning multiple lines aren't common anyway.
    boolean found = false;
    boolean forward = true;
    t = doc.getTokenListForLine(curLine);
    while (t != null && t.isPaintable()) {
      if (t.getType() == Token.MARKUP_TAG_DELIMITER) {
        if (t.isSingleChar('<') && t.getOffset() + 1 == tokenOffs) {
          found = true;
          break;
        } else if (t.is(CLOSE_TAG_START) && t.getOffset() + 2 == tokenOffs) {
          found = true;
          forward = false;
          break;
        }
      }
      t = t.getNextToken();
    }

    if (!found) {
      return;
    }

    if (forward) {

      int depth = 0;
      t = t.getNextToken().getNextToken();

      do {

        while (t != null && t.isPaintable()) {
          if (t.getType() == Token.MARKUP_TAG_DELIMITER) {
            if (t.isSingleChar('<')) {
              depth++;
            } else if (t.is(TAG_SELF_CLOSE)) {
              if (depth > 0) {
                depth--;
              } else {
                return; // No match for this tag
              }
            } else if (t.is(CLOSE_TAG_START)) {
              if (depth > 0) {
                depth--;
              } else {
                Token match = t.getNextToken();
                if (match != null && match.is(lexeme)) {
                  try {
                    int end = match.getOffset() + match.length();
                    h.addMarkedOccurrenceHighlight(match.getOffset(), end, p);
                    end = tokenOffs + match.length();
                    h.addMarkedOccurrenceHighlight(tokenOffs, end, p);
                  } catch (BadLocationException ble) {
                    ble.printStackTrace(); // Never happens
                  }
                }
                return; // We're done!
              }
            }
          }
          t = t.getNextToken();
        }

        if (++curLine < lineCount) {
          t = doc.getTokenListForLine(curLine);
        }

      } while (curLine < lineCount);

    } else { // !forward

      Stack<Token> matches = new Stack<Token>();
      boolean inPossibleMatch = false;
      t = doc.getTokenListForLine(curLine);
      final int endBefore = tokenOffs - 2; // Stop before "</".

      do {

        while (t != null && t.getOffset() < endBefore && t.isPaintable()) {
          if (t.getType() == Token.MARKUP_TAG_DELIMITER) {
            if (t.isSingleChar('<')) {
              Token next = t.getNextToken();
              if (next != null) {
                if (next.is(lexeme)) {
                  matches.push(next);
                  inPossibleMatch = true;
                } else {
                  inPossibleMatch = false;
                }
                t = next;
              }
            } else if (t.isSingleChar('>')) {
              inPossibleMatch = false;
            } else if (inPossibleMatch && t.is(TAG_SELF_CLOSE)) {
              matches.pop();
            } else if (t.is(CLOSE_TAG_START)) {
              Token next = t.getNextToken();
              if (next != null) {
                // Invalid XML might not have a match
                if (next.is(lexeme) && !matches.isEmpty()) {
                  matches.pop();
                }
                t = next;
              }
            }
          }
          t = t.getNextToken();
        }

        if (!matches.isEmpty()) {
          try {
            Token match = matches.pop();
            int end = match.getOffset() + match.length();
            h.addMarkedOccurrenceHighlight(match.getOffset(), end, p);
            end = tokenOffs + match.length();
            h.addMarkedOccurrenceHighlight(tokenOffs, end, p);
          } catch (BadLocationException ble) {
            ble.printStackTrace(); // Never happens
          }
          return;
        }

        if (--curLine >= 0) {
          t = doc.getTokenListForLine(curLine);
        }

      } while (curLine >= 0);
    }
  }