/**
   * Provides a mapping from the view coordinate space to the logical coordinate space of the model.
   *
   * @param fx the X coordinate >= 0
   * @param fy the Y coordinate >= 0
   * @param a the allocated region to render into
   * @return the location within the model that best represents the given point in the view >= 0
   */
  @Override
  public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {

    bias[0] = Position.Bias.Forward;

    Rectangle alloc = a.getBounds();
    RSyntaxDocument doc = (RSyntaxDocument) getDocument();
    int x = (int) fx;
    int y = (int) fy;

    // If they're asking about a view position above the area covered by
    // this view, then the position is assumed to be the starting position
    // of this view.
    if (y < alloc.y) {
      return getStartOffset();
    }

    // If they're asking about a position below this view, the position
    // is assumed to be the ending position of this view.
    else if (y > alloc.y + alloc.height) {
      return host.getLastVisibleOffset();
    }

    // They're asking about a position within the coverage of this view
    // vertically.  So, we figure out which line the point corresponds to.
    // If the line is greater than the number of lines contained, then
    // simply use the last line as it represents the last possible place
    // we can position to.
    else {

      Element map = doc.getDefaultRootElement();
      int lineIndex = Math.abs((y - alloc.y) / lineHeight); // metrics.getHeight() );
      FoldManager fm = host.getFoldManager();
      // System.out.print("--- " + lineIndex);
      lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
      // System.out.println(" => " + lineIndex);
      if (lineIndex >= map.getElementCount()) {
        return host.getLastVisibleOffset();
      }

      Element line = map.getElement(lineIndex);

      // If the point is to the left of the line...
      if (x < alloc.x) {
        return line.getStartOffset();
      } else if (x > alloc.x + alloc.width) {
        return line.getEndOffset() - 1;
      } else {
        // Determine the offset into the text
        int p0 = line.getStartOffset();
        Token tokenList = doc.getTokenListForLine(lineIndex);
        tabBase = alloc.x;
        int offs = tokenList.getListOffset((RSyntaxTextArea) getContainer(), this, tabBase, x);
        return offs != -1 ? offs : p0;
      }
    } // End of else.
  }
Пример #2
0
    /**
     * Provides a mapping from the document model coordinate space to the coordinate space of the
     * view mapped to it.
     *
     * @param pos the position to convert
     * @param a the allocated region to render into
     * @return the bounding box of the given position is returned
     * @exception BadLocationException if the given position does not represent a valid location in
     *     the associated document.
     */
    @Override
    public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {

      // System.err.println("--- begin modelToView ---");
      Rectangle alloc = a.getBounds();
      RSyntaxTextArea textArea = (RSyntaxTextArea) getContainer();
      alloc.height = textArea.getLineHeight(); // metrics.getHeight();
      alloc.width = 1;
      int p0 = getStartOffset();
      int p1 = getEndOffset();
      int testP = (b == Position.Bias.Forward) ? pos : Math.max(p0, pos - 1);

      // Get the token list for this line so we don't have to keep
      // recomputing it if this logical line spans multiple physical
      // lines.
      RSyntaxDocument doc = (RSyntaxDocument) getDocument();
      Element map = doc.getDefaultRootElement();
      int line = map.getElementIndex(p0);
      Token tokenList = doc.getTokenListForLine(line);
      float x0 = alloc.x; // 0;

      while (p0 < p1) {
        TokenSubList subList =
            TokenUtils.getSubTokenList(
                tokenList, p0, WrappedSyntaxView.this, textArea, x0, lineCountTempToken);
        x0 = subList != null ? subList.x : x0;
        tokenList = subList != null ? subList.tokenList : null;
        int p = calculateBreakPosition(p0, tokenList, x0);
        if ((pos >= p0) && (testP < p)) { // pos < p)) {
          // it's in this line
          alloc =
              RSyntaxUtilities.getLineWidthUpTo(
                  textArea, s, p0, pos, WrappedSyntaxView.this, alloc, alloc.x);
          // System.err.println("--- end modelToView ---");
          return alloc;
        }
        // if (p == p1 && pos == p1) {
        if (p == p1 - 1 && pos == p1 - 1) {
          // Wants end.
          if (pos > p0) {
            alloc =
                RSyntaxUtilities.getLineWidthUpTo(
                    textArea, s, p0, pos, WrappedSyntaxView.this, alloc, alloc.x);
          }
          // System.err.println("--- end modelToView ---");
          return alloc;
        }

        p0 = (p == p0) ? p1 : p;
        // System.err.println("... ... Incrementing y");
        alloc.y += alloc.height;
      }

      throw new BadLocationException(null, pos);
    }
Пример #3
0
 /**
  * Returns a token list for the <i>physical</i> line above the physical line containing the
  * specified offset into the document. Note that for this plain (non-wrapped) view, this is simply
  * the token list for the logical line above the line containing <code>offset</code>, since lines
  * are not wrapped.
  *
  * @param offset The offset in question.
  * @return A token list for the physical (and in this view, logical) line before this one. If
  *     <code>offset</code> is in the first line in the document, <code>null</code> is returned.
  */
 public Token getTokenListForPhysicalLineAbove(int offset) {
   RSyntaxDocument document = (RSyntaxDocument) getDocument();
   Element map = document.getDefaultRootElement();
   int line = map.getElementIndex(offset);
   FoldManager fm = host.getFoldManager();
   if (fm == null) {
     line--;
     if (line >= 0) {
       return document.getTokenListForLine(line);
     }
   } else {
     line = fm.getVisibleLineAbove(line);
     if (line >= 0) {
       return document.getTokenListForLine(line);
     }
   }
   //		int line = map.getElementIndex(offset) - 1;
   //		if (line>=0)
   //			return document.getTokenListForLine(line);
   return null;
 }
Пример #4
0
 /**
  * Returns a token list for the <i>physical</i> line below the physical line containing the
  * specified offset into the document. Note that for this plain (non-wrapped) view, this is simply
  * the token list for the logical line below the line containing <code>offset</code>, since lines
  * are not wrapped.
  *
  * @param offset The offset in question.
  * @return A token list for the physical (and in this view, logical) line after this one. If
  *     <code>offset</code> is in the last physical line in the document, <code>null</code> is
  *     returned.
  */
 public Token getTokenListForPhysicalLineBelow(int offset) {
   RSyntaxDocument document = (RSyntaxDocument) getDocument();
   Element map = document.getDefaultRootElement();
   int lineCount = map.getElementCount();
   int line = map.getElementIndex(offset);
   if (!host.isCodeFoldingEnabled()) {
     if (line < lineCount - 1) {
       return document.getTokenListForLine(line + 1);
     }
   } else {
     FoldManager fm = host.getFoldManager();
     line = fm.getVisibleLineBelow(line);
     if (line >= 0 && line < lineCount) {
       return document.getTokenListForLine(line);
     }
   }
   //		int line = map.getElementIndex(offset);
   //		int lineCount = map.getElementCount();
   //		if (line<lineCount-1)
   //			return document.getTokenListForLine(line+1);
   return null;
 }
Пример #5
0
    /** Calculate the number of lines that will be rendered by logical line when it is wrapped. */
    final int calculateLineCount() {

      int nlines = 0;
      int startOffset = getStartOffset();
      int p1 = getEndOffset();

      // Get the token list for this line so we don't have to keep
      // recomputing it if this logical line spans multiple physical
      // lines.
      RSyntaxTextArea textArea = (RSyntaxTextArea) getContainer();
      RSyntaxDocument doc = (RSyntaxDocument) getDocument();
      Element map = doc.getDefaultRootElement();
      int line = map.getElementIndex(startOffset);
      Token tokenList = doc.getTokenListForLine(line);
      float x0 = 0; // FIXME:  should be alloc.x!! alloc.x;//0;

      // System.err.println(">>> calculateLineCount: " + startOffset + "-" + p1);
      for (int p0 = startOffset; p0 < p1; ) {
        // System.err.println("... ... " + p0 + ", " + p1);
        nlines += 1;
        TokenSubList subList =
            TokenUtils.getSubTokenList(
                tokenList, p0, WrappedSyntaxView.this, textArea, x0, lineCountTempToken);
        x0 = subList != null ? subList.x : x0;
        tokenList = subList != null ? subList.tokenList : null;
        int p = calculateBreakPosition(p0, tokenList, x0);

        // System.err.println("... ... ... break position p==" + p);
        p0 = (p == p0) ? ++p : p; // this is the fix of #4410243
        // we check on situation when
        // width is too small and
        // break position is calculated
        // incorrectly.
        // System.err.println("... ... ... new p0==" + p0);
      }
      /*
      int numLines = 0;
      try {
      	numLines = textArea.getLineCount();
      } catch (BadLocationException ble) {
      	ble.printStackTrace();
      }
      System.err.println(">>> >>> calculated number of lines for this view (line " + line + "/" + numLines + ": " + nlines);
      */
      return nlines;
    }
  /**
   * Provides a mapping from the document model coordinate space to the coordinate space of the view
   * mapped to it.
   *
   * @param pos the position to convert &gt;= 0
   * @param a the allocated region to render into
   * @return the bounding box of the given position
   * @exception BadLocationException if the given position does not represent a valid location in
   *     the associated document
   * @see View#modelToView
   */
  @Override
  public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {

    // line coordinates
    Element map = getElement();
    RSyntaxDocument doc = (RSyntaxDocument) getDocument();
    int lineIndex = map.getElementIndex(pos);
    Token tokenList = doc.getTokenListForLine(lineIndex);
    Rectangle lineArea = lineToRect(a, lineIndex);
    tabBase = lineArea.x; // Used by listOffsetToView().

    // int x = (int)RSyntaxUtilities.getTokenListWidthUpTo(tokenList,
    //							(RSyntaxTextArea)getContainer(),
    //							this, 0, pos);
    // We use this method instead as it returns the actual bounding box,
    // not just the x-coordinate.
    lineArea =
        tokenList.listOffsetToView((RSyntaxTextArea) getContainer(), this, pos, tabBase, lineArea);

    return lineArea;
  }
Пример #7
0
  /**
   * Draws a single view (i.e., a line of text for a wrapped view), wrapping the text onto multiple
   * lines if necessary. Any selected text is rendered with the editor's "selected text" color.
   *
   * @param painter The painter to use to render tokens.
   * @param g The graphics context in which to paint.
   * @param r The rectangle in which to paint.
   * @param view The <code>View</code> to paint.
   * @param fontHeight The height of the font being used.
   * @param y The y-coordinate at which to begin painting.
   * @param selStart The start of the selection.
   * @param selEnd The end of the selection.
   */
  protected void drawViewWithSelection(
      TokenPainter painter,
      Graphics2D g,
      Rectangle r,
      View view,
      int fontHeight,
      int y,
      int selStart,
      int selEnd) {

    float x = r.x;

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

    RSyntaxDocument document = (RSyntaxDocument) getDocument();
    Element map = getElement();

    int p0 = view.getStartOffset();
    int lineNumber = map.getElementIndex(p0);
    int p1 = view.getEndOffset(); // - 1;

    setSegment(p0, p1 - 1, document, drawSeg);
    // System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")");
    int start = p0 - drawSeg.offset;
    Token token = document.getTokenListForLine(lineNumber);

    // If this line is an empty line, then the token list is simply a
    // null token.  In this case, the line highlight will be skipped in
    // the loop below, so unfortunately we must manually do it here.
    if (token != null && token.getType() == Token.NULL) {
      h.paintLayeredHighlights(g, p0, p1, r, host, this);
      return;
    }

    // Loop through all tokens in this view and paint them!
    while (token != null && token.isPaintable()) {

      int p = calculateBreakPosition(p0, token, x);
      x = r.x;

      h.paintLayeredHighlights(g, p0, p, r, host, this);

      while (token != null && token.isPaintable() && token.getEndOffset() - 1 < p) { // <=p) {

        // Selection starts in this token
        if (token.containsPosition(selStart)) {

          if (selStart > token.getOffset()) {
            tempToken.copyFrom(token);
            tempToken.textCount = selStart - tempToken.getOffset();
            x = painter.paint(tempToken, g, x, y, host, this);
            tempToken.textCount = token.length();
            tempToken.makeStartAt(selStart);
            // Clone required since token and tempToken must be
            // different tokens for else statement below
            token = new TokenImpl(tempToken);
          }

          int selCount = Math.min(token.length(), selEnd - token.getOffset());
          if (selCount == token.length()) {
            x = painter.paintSelected(token, g, x, y, host, this);
          } else {
            tempToken.copyFrom(token);
            tempToken.textCount = selCount;
            x = painter.paintSelected(tempToken, g, x, y, host, this);
            tempToken.textCount = token.length();
            tempToken.makeStartAt(token.getOffset() + selCount);
            token = tempToken;
            x = painter.paint(token, g, x, y, host, this);
          }

        }

        // Selection ends in this token
        else if (token.containsPosition(selEnd)) {
          tempToken.copyFrom(token);
          tempToken.textCount = selEnd - tempToken.getOffset();
          x = painter.paintSelected(tempToken, g, x, y, host, this);
          tempToken.textCount = token.length();
          tempToken.makeStartAt(selEnd);
          token = tempToken;
          x = painter.paint(token, g, x, y, host, this);
        }

        // This token is entirely selected
        else if (token.getOffset() >= selStart && token.getEndOffset() <= selEnd) {
          x = painter.paintSelected(token, g, x, y, host, this);
        }

        // This token is entirely unselected
        else {
          x = painter.paint(token, g, x, y, host, this);
        }

        token = token.getNextToken();
      }

      // If there's a token that's going to be split onto the next line
      if (token != null && token.isPaintable() && token.getOffset() < p) {

        int tokenOffset = token.getOffset();
        Token orig = token;
        token =
            new TokenImpl(
                drawSeg, tokenOffset - start, p - 1 - start, tokenOffset, token.getType());

        // Selection starts in this token
        if (token.containsPosition(selStart)) {

          if (selStart > token.getOffset()) {
            tempToken.copyFrom(token);
            tempToken.textCount = selStart - tempToken.getOffset();
            x = painter.paint(tempToken, g, x, y, host, this);
            tempToken.textCount = token.length();
            tempToken.makeStartAt(selStart);
            // Clone required since token and tempToken must be
            // different tokens for else statement below
            token = new TokenImpl(tempToken);
          }

          int selCount = Math.min(token.length(), selEnd - token.getOffset());
          if (selCount == token.length()) {
            x = painter.paintSelected(token, g, x, y, host, this);
          } else {
            tempToken.copyFrom(token);
            tempToken.textCount = selCount;
            x = painter.paintSelected(tempToken, g, x, y, host, this);
            tempToken.textCount = token.length();
            tempToken.makeStartAt(token.getOffset() + selCount);
            token = tempToken;
            x = painter.paint(token, g, x, y, host, this);
          }

        }

        // Selection ends in this token
        else if (token.containsPosition(selEnd)) {
          tempToken.copyFrom(token);
          tempToken.textCount = selEnd - tempToken.getOffset();
          x = painter.paintSelected(tempToken, g, x, y, host, this);
          tempToken.textCount = token.length();
          tempToken.makeStartAt(selEnd);
          token = tempToken;
          x = painter.paint(token, g, x, y, host, this);
        }

        // This token is entirely selected
        else if (token.getOffset() >= selStart && token.getEndOffset() <= selEnd) {
          x = painter.paintSelected(token, g, x, y, host, this);
        }

        // This token is entirely unselected
        else {
          x = painter.paint(token, g, x, y, host, this);
        }

        token = new TokenImpl(orig);
        ((TokenImpl) token).makeStartAt(p);
      }

      p0 = (p == p0) ? p1 : p;
      y += fontHeight;
    } // End of while (token!=null && token.isPaintable()).

    // NOTE: We should re-use code from Token (paintBackground()) here,
    // but don't because I'm just too lazy.
    if (host.getEOLMarkersVisible()) {
      g.setColor(host.getForegroundForTokenType(Token.WHITESPACE));
      g.setFont(host.getFontForTokenType(Token.WHITESPACE));
      g.drawString("\u00B6", x, y - fontHeight);
    }
  }
Пример #8
0
  /**
   * Draws a single view (i.e., a line of text for a wrapped view), wrapping the text onto multiple
   * lines if necessary.
   *
   * @param painter The painter to use to render tokens.
   * @param g The graphics context in which to paint.
   * @param r The rectangle in which to paint.
   * @param view The <code>View</code> to paint.
   * @param fontHeight The height of the font being used.
   * @param y The y-coordinate at which to begin painting.
   */
  protected void drawView(
      TokenPainter painter, Graphics2D g, Rectangle r, View view, int fontHeight, int y) {

    float x = r.x;

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

    RSyntaxDocument document = (RSyntaxDocument) getDocument();
    Element map = getElement();

    int p0 = view.getStartOffset();
    int lineNumber = map.getElementIndex(p0);
    int p1 = view.getEndOffset(); // - 1;

    setSegment(p0, p1 - 1, document, drawSeg);
    // System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")");
    int start = p0 - drawSeg.offset;
    Token token = document.getTokenListForLine(lineNumber);

    // If this line is an empty line, then the token list is simply a
    // null token.  In this case, the line highlight will be skipped in
    // the loop below, so unfortunately we must manually do it here.
    if (token != null && token.getType() == Token.NULL) {
      h.paintLayeredHighlights(g, p0, p1, r, host, this);
      return;
    }

    // Loop through all tokens in this view and paint them!
    while (token != null && token.isPaintable()) {

      int p = calculateBreakPosition(p0, token, x);
      x = r.x;

      h.paintLayeredHighlights(g, p0, p, r, host, this);

      while (token != null && token.isPaintable() && token.getEndOffset() - 1 < p) { // <=p) {
        x = painter.paint(token, g, x, y, host, this);
        token = token.getNextToken();
      }

      if (token != null && token.isPaintable() && token.getOffset() < p) {
        int tokenOffset = token.getOffset();
        tempToken.set(
            drawSeg.array, tokenOffset - start, p - 1 - start, tokenOffset, token.getType());
        painter.paint(tempToken, g, x, y, host, this);
        tempToken.copyFrom(token);
        tempToken.makeStartAt(p);
        token = new TokenImpl(tempToken);
      }

      p0 = (p == p0) ? p1 : p;
      y += fontHeight;
    } // End of while (token!=null && token.isPaintable()).

    // NOTE: We should re-use code from Token (paintBackground()) here,
    // but don't because I'm just too lazy.
    if (host.getEOLMarkersVisible()) {
      g.setColor(host.getForegroundForTokenType(Token.WHITESPACE));
      g.setFont(host.getFontForTokenType(Token.WHITESPACE));
      g.drawString("\u00B6", x, y - fontHeight);
    }
  }
Пример #9
0
    /**
     * Provides a mapping from the view coordinate space to the logical coordinate space of the
     * model.
     *
     * @param fx the X coordinate
     * @param fy the Y coordinate
     * @param a the allocated region to render into
     * @return the location within the model that best represents the given point in the view
     * @see View#viewToModel
     */
    @Override
    public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {

      // PENDING(prinz) implement bias properly
      bias[0] = Position.Bias.Forward;

      Rectangle alloc = (Rectangle) a;
      RSyntaxDocument doc = (RSyntaxDocument) getDocument();
      int x = (int) fx;
      int y = (int) fy;
      if (y < alloc.y) {
        // above the area covered by this icon, so the the position
        // is assumed to be the start of the coverage for this view.
        return getStartOffset();
      } else if (y > alloc.y + alloc.height) {
        // below the area covered by this icon, so the the position
        // is assumed to be the end of the coverage for this view.
        return getEndOffset() - 1;
      } else {

        // positioned within the coverage of this view vertically,
        // so we figure out which line the point corresponds to.
        // if the line is greater than the number of lines
        // contained, then simply use the last line as it represents
        // the last possible place we can position to.

        RSyntaxTextArea textArea = (RSyntaxTextArea) getContainer();
        alloc.height = textArea.getLineHeight();
        int p1 = getEndOffset();

        // Get the token list for this line so we don't have to keep
        // recomputing it if this logical line spans multiple
        // physical lines.
        Element map = doc.getDefaultRootElement();
        int p0 = getStartOffset();
        int line = map.getElementIndex(p0);
        Token tlist = doc.getTokenListForLine(line);

        // Look at each physical line-chunk of this logical line.
        while (p0 < p1) {

          // We can always use alloc.x since we always break
          // lines so they start at the beginning of a physical
          // line.
          TokenSubList subList =
              TokenUtils.getSubTokenList(
                  tlist, p0, WrappedSyntaxView.this, textArea, alloc.x, lineCountTempToken);
          tlist = subList != null ? subList.tokenList : null;
          int p = calculateBreakPosition(p0, tlist, alloc.x);

          // If desired view position is in this physical chunk.
          if ((y >= alloc.y) && (y < (alloc.y + alloc.height))) {

            // Point is to the left of the line
            if (x < alloc.x) {
              return p0;
            }

            // Point is to the right of the line
            else if (x > alloc.x + alloc.width) {
              return p - 1;
            }

            // Point is in this physical line!
            else {

              // Start at alloc.x since this chunk starts
              // at the beginning of a physical line.
              int n = tlist.getListOffset(textArea, WrappedSyntaxView.this, alloc.x, x);

              // NOTE:  We needed to add the max() with
              // p0 as getTokenListForLine returns -1
              // for empty lines (just a null token).
              // How did this work before?
              // FIXME:  Have null tokens have their
              // offset but a -1 length.
              return Math.max(Math.min(n, p1 - 1), p0);
            } // End of else.
          } // End of if ((y>=alloc.y) && ...

          p0 = (p == p0) ? p1 : p;
          alloc.y += alloc.height;
        } // End of while (p0<p1).

        return getEndOffset() - 1;
      } // End of else.
    }
  /**
   * 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);

  }