@Override
  public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {

    int offs = -1;

    if (!isAllocationValid()) {
      Rectangle alloc = a.getBounds();
      setSize(alloc.width, alloc.height);
    }

    // Get the child view for the line at (x,y), and ask it for the
    // specific offset.
    Rectangle alloc = getInsideAllocation(a);
    View v = getViewAtPoint((int) x, (int) y, alloc);
    if (v != null) {
      offs = v.viewToModel(x, y, alloc, bias);
    }

    // Code folding may have hidden the last line.  If so, return the last
    // visible offset instead of the last offset.
    if (host.isCodeFoldingEnabled()
        && v == getView(getViewCount() - 1)
        && offs == v.getEndOffset() - 1) {
      offs = host.getLastVisibleOffset();
    }

    return offs;
  }
 /**
  * Determines the preferred span for this view along an axis.
  *
  * @param axis may be either View.X_AXIS or View.Y_AXIS
  * @return the span the view would like to be rendered into >= 0. Typically the view is told to
  *     render into the span that is returned, although there is no guarantee. The parent may
  *     choose to resize or break the view.
  * @exception IllegalArgumentException for an invalid axis
  */
 @Override
 public float getPreferredSpan(int axis) {
   updateMetrics();
   switch (axis) {
     case View.X_AXIS:
       float span = longLineWidth + getRhsCorrection(); // fudge factor
       if (host.getEOLMarkersVisible()) {
         span += metrics.charWidth('\u00B6');
       }
       return span;
     case View.Y_AXIS:
       // We update lineHeight here as when this method is first
       // called, lineHeight isn't initialized.  If we don't do it
       // here, we get no vertical scrollbar (as lineHeight==0).
       lineHeight = host != null ? host.getLineHeight() : lineHeight;
       //				return getElement().getElementCount() * lineHeight;
       int visibleLineCount = getElement().getElementCount();
       if (host.isCodeFoldingEnabled()) {
         visibleLineCount -= host.getFoldManager().getHiddenLineCount();
       }
       return visibleLineCount * (float) lineHeight;
     default:
       throw new IllegalArgumentException("Invalid axis: " + axis);
   }
 }
 /** {@inheritDoc} */
 public int yForLineContaining(Rectangle alloc, int offs) throws BadLocationException {
   if (isAllocationValid()) {
     // TODO: make cached Y_AXIS offsets valid even with folding enabled
     // to speed this back up!
     Rectangle r = (Rectangle) modelToView(offs, alloc, Bias.Forward);
     if (r != null) {
       if (host.isCodeFoldingEnabled()) {
         int line = host.getLineOfOffset(offs);
         FoldManager fm = host.getFoldManager();
         if (fm.isLineHidden(line)) {
           return -1;
         }
       }
       return r.y;
     }
   }
   return -1;
 }
 /**
  * Determine the rectangle that represents the given line.
  *
  * @param a The region allocated for the view to render into
  * @param line The line number to find the region of. This must be a valid line number in the
  *     model.
  */
 protected Rectangle lineToRect(Shape a, int line) {
   Rectangle r = null;
   updateMetrics();
   if (metrics != null) {
     Rectangle alloc = a.getBounds();
     // NOTE:  lineHeight is not initially set here, leading to the
     // current line not being highlighted when a document is first
     // opened.  So, we set it here just in case.
     lineHeight = host != null ? host.getLineHeight() : lineHeight;
     if (host != null && host.isCodeFoldingEnabled()) {
       FoldManager fm = host.getFoldManager();
       int hiddenCount = fm.getHiddenLineCountAbove(line);
       line -= hiddenCount;
     }
     r = new Rectangle(alloc.x, alloc.y + line * lineHeight, alloc.width, lineHeight);
   }
   return r;
 }
 /**
  * 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;
 }
 /**
  * Determines the preferred span for this view along an axis. This is implemented to provide the
  * superclass behavior after first making sure that the current font metrics are cached (for the
  * nested lines which use the metrics to determine the height of the potentially wrapped lines).
  *
  * @param axis may be either View.X_AXIS or View.Y_AXIS
  * @return the span the view would like to be rendered into. Typically the view is told to render
  *     into the span that is returned, although there is no guarantee. The parent may choose to
  *     resize or break the view.
  * @see View#getPreferredSpan
  */
 public float getPreferredSpan(int axis) {
   updateMetrics();
   float span = 0;
   if (axis == View.X_AXIS) { // Add EOL marker
     span = super.getPreferredSpan(axis);
     span += metrics.charWidth('\u00b6'); // metrics set in updateMetrics
   } else {
     span = super.getPreferredSpan(axis);
     host = (RSyntaxTextArea) getContainer();
     if (host.isCodeFoldingEnabled()) {
       // TODO: Cache y-offsets again to speed this up
       // System.out.println("y-axis baby");
       int lineCount = host.getLineCount();
       FoldManager fm = host.getFoldManager();
       for (int i = 0; i < lineCount; i++) {
         if (fm.isLineHidden(i)) {
           span -= getSpan(View.Y_AXIS, i);
         }
       }
     }
   }
   return span;
 }