Index: src/view/kateviewhelpers.h =================================================================== --- src/view/kateviewhelpers.h +++ src/view/kateviewhelpers.h @@ -323,6 +323,10 @@ void leaveEvent(QEvent *event) override; void wheelEvent(QWheelEvent *e) override; + bool unfoldLine(int line); + KTextEditor::Range foldLine(int line); + bool toggleFoldingInRange(int line); + void showMarkMenu(uint line, const QPoint &pos); void hideAnnotationTooltip(); Index: src/view/kateviewhelpers.cpp =================================================================== --- src/view/kateviewhelpers.cpp +++ src/view/kateviewhelpers.cpp @@ -2440,28 +2440,17 @@ } if (area == FoldingMarkers) { - // ask the folding info for this line, if any folds are around! - QVector > startingRanges = m_view->textFolding().foldingRangesStartingOnLine(cursorOnLine); - bool anyFolded = false; - for (int i = 0; i < startingRanges.size(); ++i) - if (startingRanges[i].second & Kate::TextFolding::Folded) { - anyFolded = true; - } + // Prefer the highlighted range over the exact clicked line + const int lineToToggle = m_foldingRange ? m_foldingRange->toRange().start().line() : cursorOnLine; - // fold or unfold all ranges, remember if any action happened! - bool actionDone = false; - for (int i = 0; i < startingRanges.size(); ++i) { - actionDone = (anyFolded ? m_view->textFolding().unfoldRange(startingRanges[i].first) : m_view->textFolding().foldRange(startingRanges[i].first)) || actionDone; - } + // Whatever button it was, try to unfold + bool actionDone = unfoldLine(lineToToggle); - // if no action done, try to fold it, create non-persistent folded range, if possible! - if (!actionDone) { - // either use the fold for this line or the range that is highlighted ATM if any! - KTextEditor::Range foldingRange = m_view->doc()->buffer().computeFoldingRangeForStartLine(cursorOnLine); - if (!foldingRange.isValid() && m_foldingRange) { - foldingRange = m_foldingRange->toRange(); - } - m_view->textFolding().newFoldingRange(foldingRange, Kate::TextFolding::Folded); + // Nothing happens? Then do whatever button should do + if (!actionDone && e->button() == Qt::LeftButton) { + foldLine(lineToToggle); + } else if (!actionDone && e->button() == Qt::RightButton) { + toggleFoldingInRange(lineToToggle); } delete m_foldingPreview; @@ -2482,6 +2471,68 @@ m_viewInternal->mouseReleaseEvent(&forward); } +KTextEditor::Range KateIconBorder::foldLine(int line) +{ + KTextEditor::Range foldingRange = m_view->doc()->buffer().computeFoldingRangeForStartLine(line); + if (!foldingRange.isValid()) { + return foldingRange; + } + + // Ensure not to fold the end marker to avoid a deceptive look, but only on token based folding + Kate::TextLine startTextLine = m_view->doc()->buffer().plainLine(line); + const int adjust = startTextLine->markedAsFoldingStartIndentation() ? 0 : 1; + foldingRange.setEnd(KTextEditor::Cursor(foldingRange.end().line() - adjust, 0)); + m_view->textFolding().newFoldingRange(foldingRange, Kate::TextFolding::Folded); + + return foldingRange; +} + +bool KateIconBorder::unfoldLine(int line) +{ + bool actionDone = false; + + // ask the folding info for this line, if any folds are around! + // auto = QVector> + auto startingRanges = m_view->textFolding().foldingRangesStartingOnLine(line); + for (int i = 0; i < startingRanges.size(); ++i) { + actionDone |= m_view->textFolding().unfoldRange(startingRanges[i].first); + } + + return actionDone; +} + +bool KateIconBorder::toggleFoldingInRange(int line) +{ + KTextEditor::Range foldingRange = m_view->doc()->buffer().computeFoldingRangeForStartLine(line); + if (!foldingRange.isValid()) { + return false; + } + + bool actionDone = false; + for (int ln = foldingRange.start().line() + 1; ln <= foldingRange.end().line(); ++ln) { + actionDone |= unfoldLine(ln); + } + + if (!actionDone) { + // Fold all in range, but not the range itself + for (int ln = foldingRange.start().line() + 1; ln <= foldingRange.end().line(); ++ln) { + KTextEditor::Range fr = foldLine(ln); + if (fr.isValid()) { + ln = fr.end().line() - 1; + actionDone = true; + } + } + } + + if (!actionDone) { + // At this place was an unfolded range clicked which contains no "childs" + // We assume the user want to fold it by the wrong button, be obliging! + actionDone |= foldLine(line).isValid(); + } + + return actionDone; +} + void KateIconBorder::mouseDoubleClickEvent(QMouseEvent *e) { int cursorOnLine = m_viewInternal->yToKateTextLayout(e->y()).line(); Index: src/view/kateviewinternal.cpp =================================================================== --- src/view/kateviewinternal.cpp +++ src/view/kateviewinternal.cpp @@ -2646,6 +2646,14 @@ e->accept(); break; + case Qt::RightButton: + if (e->pos().x() == 0) { + // Special handling for folding by right click + placeCursor(e->pos()); + e->accept(); + } + break; + default: e->ignore(); break;