private Fold findOpenFoldClosestTo(Point p) {

    Fold fold = null;

    RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
    if (rsta.isCodeFoldingEnabled()) { // Should always be true
      int offs = rsta.viewToModel(p); // TODO: Optimize me
      if (offs > -1) {
        try {
          int line = rsta.getLineOfOffset(offs);
          int origLine = line;
          FoldManager fm = rsta.getFoldManager();
          do {
            fold = fm.getFoldForLine(line);
          } while (fold == null && line-- >= 0);
          if (fold != null && !fold.containsOrStartsOnLine(origLine)) {
            // Found closest fold, but doesn't actually contain line
            fold = null;
          }
        } catch (BadLocationException ble) {
          ble.printStackTrace(); // Never happens
        }
      }
    }

    return fold;
  }
  /**
   * Overridden to show the content of a collapsed fold on mouse-overs.
   *
   * @param e The mouse location.
   */
  public String getToolTipText(MouseEvent e) {

    String text = null;

    RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
    if (rsta.isCodeFoldingEnabled()) {
      FoldManager fm = rsta.getFoldManager();
      int pos = rsta.viewToModel(new Point(0, e.getY()));
      if (pos >= 0) { // Not -1
        int line = 0;
        try {
          line = rsta.getLineOfOffset(pos);
        } catch (BadLocationException ble) {
          ble.printStackTrace(); // Never happens
          return null;
        }
        Fold fold = fm.getFoldForLine(line);
        if (fold != null && fold.isCollapsed()) {

          int endLine = fold.getEndLine();
          if (fold.getLineCount() > 25) { // Not too big
            endLine = fold.getStartLine() + 25;
          }

          StringBuffer sb = new StringBuffer("<html><nobr>");
          while (line <= endLine && line < rsta.getLineCount()) { // Sanity
            Token t = rsta.getTokenListForLine(line);
            while (t != null && t.isPaintable()) {
              t.appendHTMLRepresentation(sb, rsta, true, true);
              t = t.getNextToken();
            }
            sb.append("<br>");
            line++;
          }

          text = sb.toString();
        }
      }
    }

    return text;
  }
    public void mouseClicked(MouseEvent e) {

      //			// TODO: Implement code folding with word wrap enabled
      //			if (textArea.getLineWrap()) {
      //				UIManager.getLookAndFeel().provideErrorFeedback(textArea);
      //				return;
      //			}

      Point p = e.getPoint();
      int line = rowAtPoint(p);

      RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
      FoldManager fm = rsta.getFoldManager();

      Fold fold = fm.getFoldForLine(line);
      if (fold != null) {
        fold.toggleCollapsedState();
        getGutter().repaint();
        textArea.repaint();
      }
    }
  /**
   * Selects a range of text in a text component. If the new selection is outside of the previous
   * viewable rectangle, then the view is centered around the new selection.
   *
   * @param textArea The text component whose selection is to be centered.
   * @param start The start of the range to select.
   * @param end The end of the range to select.
   */
  private static void selectAndPossiblyCenter(JTextArea textArea, int start, int end) {

    boolean foldsExpanded = false;
    if (textArea instanceof RSyntaxTextArea) {
      RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
      FoldManager fm = rsta.getFoldManager();
      if (fm.isCodeFoldingSupportedAndEnabled()) {
        foldsExpanded = fm.ensureOffsetNotInClosedFold(start);
        foldsExpanded |= fm.ensureOffsetNotInClosedFold(end);
      }
    }

    textArea.setSelectionStart(start);
    textArea.setSelectionEnd(end);

    Rectangle r = null;
    try {
      r = textArea.modelToView(start);
      if (r == null) { // Not yet visible; i.e. JUnit tests
        return;
      }
      if (end != start) {
        r = r.union(textArea.modelToView(end));
      }
    } catch (BadLocationException ble) { // Never happens
      ble.printStackTrace();
      textArea.setSelectionStart(start);
      textArea.setSelectionEnd(end);
      return;
    }

    Rectangle visible = textArea.getVisibleRect();

    // If the new selection is already in the view, don't scroll,
    // as that is visually jarring.
    if (!foldsExpanded && visible.contains(r)) {
      textArea.setSelectionStart(start);
      textArea.setSelectionEnd(end);
      return;
    }

    visible.x = r.x - (visible.width - r.width) / 2;
    visible.y = r.y - (visible.height - r.height) / 2;

    Rectangle bounds = textArea.getBounds();
    Insets i = textArea.getInsets();
    bounds.x = i.left;
    bounds.y = i.top;
    bounds.width -= i.left + i.right;
    bounds.height -= i.top + i.bottom;

    if (visible.x < bounds.x) {
      visible.x = bounds.x;
    }

    if (visible.x + visible.width > bounds.x + bounds.width) {
      visible.x = bounds.x + bounds.width - visible.width;
    }

    if (visible.y < bounds.y) {
      visible.y = bounds.y;
    }

    if (visible.y + visible.height > bounds.y + bounds.height) {
      visible.y = bounds.y + bounds.height - visible.height;
    }

    textArea.scrollRectToVisible(visible);
  }
  protected void paintComponent(Graphics g) {

    if (textArea == null) {
      return;
    }

    visibleRect = g.getClipBounds(visibleRect);
    if (visibleRect == null) { // ???
      visibleRect = getVisibleRect();
    }
    // System.out.println("IconRowHeader repainting: " + visibleRect);
    if (visibleRect == null) {
      return;
    }

    Color bg = getBackground();
    if (getGutter() != null) { // Should always be true
      bg = getGutter().getBackground();
    }
    g.setColor(bg);
    g.fillRect(0, visibleRect.y, getWidth(), visibleRect.height);

    RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
    if (!rsta.isCodeFoldingEnabled()) {
      return; // We should be hidden in this case, but still...
    }

    if (textArea.getLineWrap()) {
      paintComponentWrapped(g);
      return;
    }

    // Get where to start painting (top of the row).
    // We need to be "scrolled up" up just enough for the missing part of
    // the first line.
    int cellHeight = textArea.getLineHeight();
    int topLine = visibleRect.y / cellHeight;
    int y = topLine * cellHeight + (cellHeight - collapsedFoldIcon.getIconHeight()) / 2;
    textAreaInsets = textArea.getInsets(textAreaInsets);
    if (textAreaInsets != null) {
      y += textAreaInsets.top;
    }

    // Get the first and last lines to paint.
    FoldManager fm = rsta.getFoldManager();
    topLine += fm.getHiddenLineCountAbove(topLine, true);

    int width = getWidth();
    int x = width - 10;
    int line = topLine;
    boolean paintingOutlineLine =
        foldWithOutlineShowing != null && foldWithOutlineShowing.containsLine(line);

    while (y < visibleRect.y + visibleRect.height) {
      if (paintingOutlineLine) {
        g.setColor(getForeground());
        int w2 = width / 2;
        if (line == foldWithOutlineShowing.getEndLine()) {
          int y2 = y + cellHeight / 2;
          g.drawLine(w2, y, w2, y2);
          g.drawLine(w2, y2, width - 2, y2);
          paintingOutlineLine = false;
        } else {
          g.drawLine(w2, y, w2, y + cellHeight);
        }
      }
      Fold fold = fm.getFoldForLine(line);
      if (fold != null) {
        if (fold == foldWithOutlineShowing && !fold.isCollapsed()) {
          g.setColor(getForeground());
          int w2 = width / 2;
          g.drawLine(w2, y + cellHeight / 2, w2, y + cellHeight);
          paintingOutlineLine = true;
        }
        if (fold.isCollapsed()) {
          collapsedFoldIcon.paintIcon(this, g, x, y);
          // Skip to next line to paint, taking extra care for lines with
          // block ends and begins together, e.g. "} else {"
          do {
            line += fold.getLineCount();
            fold = fm.getFoldForLine(line);
          } while (fold != null && fold.isCollapsed());
        } else {
          expandedFoldIcon.paintIcon(this, g, x, y);
        }
      }
      line++;
      y += cellHeight;
    }
  }