17#include "kateviewinternal.h"
19#include "kateabstractinputmode.h"
20#include "kateabstractinputmodefactory.h"
21#include "katebuffer.h"
22#include "katecompletionwidget.h"
23#include "kateconfig.h"
24#include "kateglobal.h"
25#include "katehighlight.h"
26#include "katelayoutcache.h"
27#include "katemessagewidget.h"
28#include "katepartdebug.h"
29#include "katerenderer.h"
30#include "katetextanimation.h"
31#include "katetextpreview.h"
33#include "kateviewaccessible.h"
34#include "kateviewhelpers.h"
35#include "spellcheck/spellingmenu.h"
38#include <ktexteditor/documentcursor.h>
39#include <ktexteditor/inlinenoteprovider.h>
40#include <ktexteditor/movingrange.h>
41#include <ktexteditor/texthintinterface.h>
44#include <QApplication>
57static const bool debugPainting =
false;
62 ZoomEventFilter() =
default;
67 if (modState == modifier) {
68 if (m_lastWheelEvent.
isValid()) {
69 const qint64 deltaT = m_lastWheelEvent.
elapsed();
72 if (m_lastWheelEventUnmodified && deltaT < 200) {
74 }
else if (deltaT > 1000) {
85 m_lastWheelEventUnmodified =
false;
89 modState &= ~modifier;
90 e->setModifiers(modState);
94 m_lastWheelEventUnmodified =
true;
97 m_lastWheelEvent.
start();
100 return !m_ignoreZoom && modState == modifier;
105 bool m_ignoreZoom =
false;
106 bool m_lastWheelEventUnmodified =
false;
109KateViewInternal::KateViewInternal(KTextEditor::ViewPrivate *view)
111 , editSessionNumber(0)
112 , editIsRunning(false)
114 , m_cursor(doc()->buffer(),
KTextEditor::Cursor(0, 0), Kate::TextCursor::MoveOnInsert)
116 , m_possibleTripleClick(false)
120 , m_bmLastFlashPos(doc()->newMovingCursor(
KTextEditor::Cursor::invalid()))
129 , m_startPos(doc()->buffer(),
KTextEditor::Cursor(0, 0), Kate::TextCursor::StayOnInsert)
131 , m_visibleLineCount(0)
132 , m_madeVisible(false)
133 , m_shiftKeyPressed(false)
134 , m_autoCenterLines(0)
135 , m_minLinesVisible(0)
136 , m_selChangedByUser(false)
137 , m_selectAnchor(-1, -1)
138 , m_selectionMode(Default)
142 , m_cachedMaxStartPos(-1, -1)
143 , m_dragScrollTimer(this)
144 , m_scrollTimer(this)
145 , m_cursorTimer(this)
146 , m_textHintTimer(this)
147 , m_textHintDelay(500)
148 , m_textHintPos(-1, -1)
149 , m_imPreeditRange(nullptr)
159 setMinimumSize(0, 0);
167 m_bm->setView(m_view);
168 m_bmStart->setView(m_view);
169 m_bmEnd->setView(m_view);
170 m_bm->setAttributeOnlyForViews(
true);
171 m_bmStart->setAttributeOnlyForViews(
true);
172 m_bmEnd->setAttributeOnlyForViews(
true);
175 m_bm->setZDepth(-1000.0);
176 m_bmStart->setZDepth(-1000.0);
177 m_bmEnd->setZDepth(-1000.0);
180 updateBracketMarkAttributes();
186 m_lineScroll->show();
187 m_lineScroll->setTracking(
true);
193 auto viewScrollLinesSlot = qOverload<int>(&KateViewInternal::scrollLines);
195 connect(m_lineScroll, &KateScrollBar::sliderMMBMoved,
this, viewScrollLinesSlot);
211 m_scroller->setScrollerProperties(prop);
217 m_scroller->grabGesture(
this);
220 if (m_view->dynWordWrap()) {
221 m_columnScroll->hide();
223 m_columnScroll->show();
226 m_columnScroll->setTracking(
true);
233 m_dummy->setFixedSize(m_lineScroll->width(), m_columnScroll->sizeHint().height());
236 if (m_view->dynWordWrap()) {
242 cache()->setWrap(m_view->dynWordWrap());
247 m_leftBorder =
new KateIconBorder(
this, m_view);
248 m_leftBorder->show();
253 m_displayCursor.setPosition(0, 0);
255 setAcceptDrops(
true);
257 m_zoomEventFilter.reset(
new ZoomEventFilter());
259 installEventFilter(
this);
263 setCursor(m_mouseCursor);
266 setMouseTracking(
true);
268 m_dragInfo.state = diNone;
282#ifndef QT_NO_ACCESSIBILITY
285 connect(doc(), &KTextEditor::DocumentPrivate::textInsertedRange,
this, &KateViewInternal::documentTextInserted);
286 connect(doc(), &KTextEditor::DocumentPrivate::textRemoved,
this, &KateViewInternal::documentTextRemoved);
292KateViewInternal::~KateViewInternal()
294#ifndef QT_NO_ACCESSIBILITY
299 delete m_textAnimation;
303 m_leftBorder =
nullptr;
306void KateViewInternal::dynWrapChanged()
309 if (view()->dynWordWrap()) {
310 m_columnScroll->
hide();
315 m_columnScroll->
show();
319 cache()->setWrap(view()->dynWordWrap());
322 if (view()->dynWordWrap()) {
332 if (!cache()->viewCacheLineCount()) {
336 for (
int i = qMin(linesDisplayed() - 1, cache()->viewCacheLineCount() - 1); i >= 0; i--) {
339 if (thisLine.line() == -1) {
343 if (thisLine.virtualLine() >= view()->textFolding().visibleLines()) {
346 doc()->lineLength(view()->textFolding().visibleLineToLine(view()->textFolding().visibleLines() - 1)));
356int KateViewInternal::endLine()
const
358 return endPos().
line();
364 return KateTextLayout::invalid();
367 int range =
y / renderer()->lineHeight();
370 if (range >= 0 && range < cache()->viewCacheLineCount()) {
374 return KateTextLayout::invalid();
377int KateViewInternal::lineToY(
int viewLine)
const
379 return (viewLine - startLine()) * renderer()->lineHeight();
382void KateViewInternal::slotIncFontSizes(qreal step)
387void KateViewInternal::slotDecFontSizes(qreal step)
389 renderer()->decreaseFontSizes(step);
392void KateViewInternal::slotResetFontSizes()
394 renderer()->resetFontSizes();
400void KateViewInternal::scrollLines(
int line)
407void KateViewInternal::scrollViewLines(
int offset)
413 m_lineScroll->
setValue(startLine());
417void KateViewInternal::scrollAction(
int action)
446void KateViewInternal::scrollNextPage()
448 scrollViewLines(qMax(linesDisplayed() - 1, 0));
451void KateViewInternal::scrollPrevPage()
453 scrollViewLines(-qMax(linesDisplayed() - 1, 0));
456void KateViewInternal::scrollPrevLine()
461void KateViewInternal::scrollNextLine()
468 cache()->setAcceptDirtyLayouts(
true);
470 if (m_cachedMaxStartPos.
line() == -1 || changed) {
472 doc()->lineLength(view()->textFolding().visibleLineToLine(view()->textFolding().visibleLines() - 1)));
474 if (view()->config()->scrollPastEnd()) {
475 m_cachedMaxStartPos = viewLineOffset(end, -m_minLinesVisible);
477 m_cachedMaxStartPos = viewLineOffset(end, -(linesDisplayed() - 1));
481 cache()->setAcceptDirtyLayouts(
false);
483 return m_cachedMaxStartPos;
487void KateViewInternal::scrollPos(
KTextEditor::Cursor &c,
bool force,
bool calledExternally,
bool emitSignals)
489 if (!force && ((!view()->dynWordWrap() && c.
line() == startLine()) || c == startPos())) {
502 if (!force && ((!view()->dynWordWrap() && c.
line() == startLine()) || c == startPos())) {
507 int viewLinesScrolled = 0;
512 bool viewLinesScrolledUsable = !force && (c.
line() >= startLine() - linesDisplayed() - 1) && (c.
line() <= endLine() + linesDisplayed() + 1);
514 if (viewLinesScrolledUsable) {
521 m_madeVisible =
false;
523 if (viewLinesScrolledUsable) {
524 int lines = linesDisplayed();
525 if (view()->textFolding().visibleLines() < lines) {
527 doc()->lineLength(view()->textFolding().visibleLineToLine(view()->textFolding().visibleLines() - 1)));
528 lines = qMin(linesDisplayed(), cache()->displayViewLine(end) + 1);
531 Q_ASSERT(lines >= 0);
533 if (!calledExternally && qAbs(viewLinesScrolled) < lines &&
539 updateView(
false, viewLinesScrolled);
541 int scrollHeight = -(viewLinesScrolled * (int)renderer()->lineHeight());
545 m_leftBorder->
scroll(0, scrollHeight);
549 Q_EMIT view()->displayRangeChanged(m_view);
560 Q_EMIT view()->displayRangeChanged(m_view);
564void KateViewInternal::scrollColumns(
int x)
570 if (
x > m_columnScroll->
maximum()) {
578 int dx = startX() -
x;
581 if (qAbs(dx) <
width()) {
589 Q_EMIT view()->displayRangeChanged(m_view);
597void KateViewInternal::updateView(
bool changed,
int viewLinesScrolled)
599 if (!
isVisible() && !viewLinesScrolled && !changed) {
603 view()->doc()->delayAutoReload();
606 int wrapWidth =
width();
607 if (view()->config()->dynWrapAtStaticMarker() && view()->config()->dynWordWrap()) {
611 wrapWidth = qMin(
width(),
static_cast<int>(renderer()->currentFontMetrics().boundingRect(s).
width()));
614 if (wrapWidth != cache()->viewWidth()) {
615 cache()->setViewWidth(wrapWidth);
624 int newSize = (qMax(0,
height()) / renderer()->lineHeight()) + 1;
625 cache()->updateViewCache(startPos(), newSize, viewLinesScrolled);
626 m_visibleLineCount = newSize;
629 int maxLineScrollRange = maxStart.
line();
630 if (view()->dynWordWrap() && maxStart.
column() != 0) {
631 maxLineScrollRange++;
633 m_lineScroll->
setRange(0, maxLineScrollRange);
635 m_lineScroll->
setValue(startLine());
640 KateViewConfig::ScrollbarMode show_scrollbars =
static_cast<KateViewConfig::ScrollbarMode
>(view()->config()->showScrollbars());
642 bool visible = ((show_scrollbars == KateViewConfig::AlwaysOn) || ((show_scrollbars == KateViewConfig::ShowWhenNeeded) && (maxLineScrollRange != 0)));
647 if (!view()->dynWordWrap()) {
648 int max = maxLen(startLine()) -
width();
663 visible = ((show_scrollbars == KateViewConfig::AlwaysOn) || ((show_scrollbars == KateViewConfig::ShowWhenNeeded) && (max != 0)));
667 m_columnScroll->
setRange(0, max + (renderer()->spaceWidth() / 2));
677 visible_dummy =
false;
691void KateViewInternal::makeVisible(
const KTextEditor::Cursor c,
int endCol,
bool force,
bool center,
bool calledExternally)
698 const int lnDisp = linesDisplayed();
700 const bool curBelowScreen = (viewLine == -2);
704 scrollPos(
scroll, force, calledExternally);
705 }
else if (center && (c < startPos() || c > endPos())) {
707 scrollPos(
scroll,
false, calledExternally);
708 }
else if ((viewLine >= (lnDisp - m_minLinesVisible)) || (curBelowScreen)) {
710 scrollPos(
scroll,
false, calledExternally);
711 }
else if (c < viewLineOffset(startPos(), m_minLinesVisible)) {
713 scrollPos(
scroll,
false, calledExternally);
717 if (startPos() > max) {
718 scrollPos(max, max.
column(), calledExternally);
722 if (!view()->dynWordWrap() && (endCol != -1 || view()->wrapCursor())) {
724 int sX = renderer()->
cursorToX(cache()->textLayout(rc), rc, !view()->wrapCursor());
726 int sXborder = sX - 8;
732 scrollColumns(sXborder);
733 }
else if (sX > startX() +
width()) {
734 scrollColumns(sX -
width() + 8);
738 m_madeVisible = !force;
740#ifndef QT_NO_ACCESSIBILITY
746void KateViewInternal::slotRegionVisibilityChanged()
756 m_cachedMaxStartPos.
setLine(-1);
758 if (startPos() > max) {
759 scrollPos(max,
false,
false,
false );
763 qint64 foldedRangeId = -1;
764 if (!view()->textFolding().isLineVisible(m_cursor.
line(), &foldedRangeId)) {
769 updateCursor(foldingRange.
start(),
true);
773 updateCursor(m_cursor,
true);
782 Q_EMIT view()->displayRangeChanged(m_view);
785void KateViewInternal::slotRegionBeginEndAddedRemoved(
unsigned int)
792void KateViewInternal::showEvent(
QShowEvent *e)
807int KateViewInternal::linesDisplayed()
const
812 int fh = qMax(1, renderer()->lineHeight());
816 return qMax(1, (h - (h % fh)) / fh);
821 if (
cursor.line() >= doc()->lines()) {
827 if (viewLine < 0 || viewLine >= cache()->viewCacheLineCount()) {
831 const int y = (int)viewLine * renderer()->lineHeight();
835 const auto textLength = doc()->lineLength(
cursor.line());
836 if (
cursor.column() > textLength) {
844 if (!
layout.isRightToLeft() || (
layout.isRightToLeft() && view()->dynWordWrap())) {
849 x = (int)
layout.lineLayout().cursorToX(textLength -
cursor.column());
856 x += m_leftBorder->
width();
864QPoint KateViewInternal::cursorCoordinates(
bool includeBorder)
const
866 return cursorToCoordinate(m_displayCursor,
false, includeBorder);
873 if (!m_bm->toRange().isValid()) {
877 Q_ASSERT(m_bmEnd->toRange().isValid());
878 Q_ASSERT(m_bmStart->toRange().isValid());
882 if (m_bmEnd->toRange().contains(m_cursor) || m_bmEnd->end() == m_cursor.
toCursor()) {
883 c = m_bmStart->start();
884 }
else if (m_bmStart->toRange().contains(m_cursor) || m_bmStart->end() == m_cursor.
toCursor()) {
887 if (doc()->config()->ovr()) {
899class CalculatingCursor
905 CalculatingCursor(KateViewInternal *vi)
918 CalculatingCursor(KateViewInternal *vi,
int line,
int col)
919 : m_cursor(line, col)
925 virtual ~CalculatingCursor()
931 return m_cursor.
line();
944 virtual CalculatingCursor &operator+=(
int n) = 0;
946 virtual CalculatingCursor &operator-=(
int n) = 0;
948 CalculatingCursor &operator++()
950 return operator+=(1);
953 CalculatingCursor &operator--()
955 return operator-=(1);
960 m_cursor.
setLine(qBound(0, line(),
int(doc()->lines() - 1)));
961 if (view()->wrapCursor()) {
962 m_cursor.
setColumn(qBound(0, column(), doc()->lineLength(line())));
969 void toEdge(KateViewInternal::Bias bias)
971 if (bias == KateViewInternal::left) {
973 }
else if (bias == KateViewInternal::right) {
974 m_cursor.
setColumn(doc()->lineLength(line()));
980 return atEdge(KateViewInternal::left) || atEdge(KateViewInternal::right);
983 bool atEdge(KateViewInternal::Bias bias)
const
986 case KateViewInternal::left:
987 return column() == 0;
988 case KateViewInternal::none:
990 case KateViewInternal::right:
991 return column() >= doc()->lineLength(line());
1001 return line() >= 0 && line() < doc()->lines() && column() >= 0 && (!view()->wrapCursor() || column() <= doc()->lineLength(line()));
1003 KTextEditor::ViewPrivate *view()
1005 return m_vi->m_view;
1007 const KTextEditor::ViewPrivate *view()
const
1009 return m_vi->m_view;
1011 KTextEditor::DocumentPrivate *doc()
1013 return view()->doc();
1015 const KTextEditor::DocumentPrivate *doc()
const
1017 return view()->doc();
1020 KateViewInternal *m_vi;
1023class BoundedCursor final :
public CalculatingCursor
1026 BoundedCursor(KateViewInternal *vi)
1027 : CalculatingCursor(vi)
1031 : CalculatingCursor(vi, c)
1034 BoundedCursor(KateViewInternal *vi,
int line,
int col)
1035 : CalculatingCursor(vi, line, col)
1038 CalculatingCursor &operator+=(
int n)
override
1040 KateLineLayout *thisLine = m_vi->cache()->
line(line());
1041 if (!thisLine || !thisLine->isValid()) {
1042 qCWarning(LOG_KTE) <<
"Did not retrieve valid layout for line " << line();
1046 const bool wrapCursor = view()->wrapCursor();
1049 for (
int i = 0; i < n; i++) {
1050 if (column() >= thisLine->length()) {
1054 }
else if (view()->dynWordWrap()) {
1056 if (maxColumn == -1) {
1057 maxColumn = thisLine->length() + ((m_vi->
width() - thisLine->widthOfLastLine()) / m_vi->renderer()->spaceWidth()) - 1;
1060 if (column() >= maxColumn) {
1076 for (
int i = 0; i > n; i--) {
1077 if (column() >= thisLine->length()) {
1079 }
else if (column() == 0) {
1090 CalculatingCursor &operator-=(
int n)
override
1092 return operator+=(-n);
1096class WrappingCursor final :
public CalculatingCursor
1099 WrappingCursor(KateViewInternal *vi)
1100 : CalculatingCursor(vi)
1104 : CalculatingCursor(vi, c)
1107 WrappingCursor(KateViewInternal *vi,
int line,
int col)
1108 : CalculatingCursor(vi, line, col)
1112 CalculatingCursor &operator+=(
int n)
override
1114 KateLineLayout *thisLine = m_vi->cache()->
line(line());
1115 if (!thisLine || !thisLine->isValid()) {
1116 qCWarning(LOG_KTE) <<
"Did not retrieve a valid layout for line " << line();
1121 for (
int i = 0; i < n; i++) {
1122 if (column() >= thisLine->length()) {
1124 if (line() >= doc()->lines() - 1)
1135 thisLine = m_vi->cache()->
line(line());
1136 if (!thisLine || !thisLine->isValid()) {
1137 qCWarning(LOG_KTE) <<
"Did not retrieve a valid layout for line " << line();
1148 for (
int i = 0; i > n; i--) {
1149 if (column() == 0) {
1159 thisLine = m_vi->cache()->
line(line());
1160 if (!thisLine || !thisLine->isValid()) {
1161 qCWarning(LOG_KTE) <<
"Did not retrieve a valid layout for line " << line();
1171 if (column() > thisLine->length()) {
1182 CalculatingCursor &operator-=(
int n)
override
1184 return operator+=(-n);
1271class CamelCursor final :
public CalculatingCursor
1275 : CalculatingCursor(vi, c)
1279 CalculatingCursor &operator+=(
int n)
override
1281 KateLineLayout *thisLine = m_vi->cache()->
line(line());
1282 if (!thisLine || !thisLine->isValid()) {
1283 qCWarning(LOG_KTE) <<
"Did not retrieve valid layout for line " << line();
1287 auto isSurrogate = [](
QChar c) {
1288 return c.isLowSurrogate() || c.isHighSurrogate();
1309 const QString &text = thisLine->textLine().
text();
1312 skipCaps(text, col);
1315 for (
int i = col; i < thisLine->length(); ++i) {
1316 const auto c = text.
at(i);
1317 if (isSurrogate(c)) {
1320 }
else if (c.isUpper() || !c.isLetterOrNumber()) {
1340 jump = col < 0 || (column() == col) ? (column() + 1) : col;
1345 auto skipCapsRev = [](
QStringView text,
int &col) {
1347 while (col > 0 && text.
at(col).
isUpper()) {
1355 if (count >= 1 && col >= 0 && !text.
at(col).
isUpper()) {
1360 const QString &text = thisLine->textLine().
text();
1361 int col = std::min<int>(column(), text.
size() - 1);
1367 if (column() == text.
size()) {
1371 if (col >= 0 && text.
at(col).
isSpace()) {
1380 if (col > 0 && text.
at(col).
isSpace()) {
1381 while (text.
at(col).
isSpace() && col > 0) {
1393 if (col > 0 && text.
at(col).
isUpper()) {
1394 skipCapsRev(text, col);
1397 for (
int i = col; i > 0; --i) {
1398 const auto c = text.
at(i);
1399 if (isSurrogate(c)) {
1402 }
else if (c.isUpper() || !c.isLetterOrNumber()) {
1414 }
else if (col == column() && column() > 0) {
1415 jump = column() - 1;
1427 CalculatingCursor &operator-=(
int n)
override
1429 return operator+=(-n);
1433void KateViewInternal::moveChar(KateViewInternal::Bias bias,
bool sel)
1436 if (view()->wrapCursor()) {
1437 c = WrappingCursor(
this, m_cursor) += bias;
1439 c = BoundedCursor(
this, m_cursor) += bias;
1442 const auto &sc = view()->m_secondaryCursors;
1444 const int lastLine = doc()->lastLine();
1445 bool shouldEnsureUniqueCursors =
false;
1446 for (
const auto &c : sc) {
1447 auto oldPos = c.cursor();
1448 if (view()->wrapCursor()) {
1449 c.pos->
setPosition(WrappingCursor(
this, oldPos) += bias);
1451 c.pos->
setPosition(BoundedCursor(
this, oldPos) += bias);
1453 const auto newPos = c.pos->toCursor();
1454 multiCursors.
push_back({oldPos, newPos});
1456 if (!shouldEnsureUniqueCursors) {
1457 shouldEnsureUniqueCursors = newPos.line() == 0 || newPos.line() == lastLine;
1461 updateSelection(c, sel);
1463 updateSecondaryCursors(multiCursors, sel);
1464 if (shouldEnsureUniqueCursors) {
1465 view()->ensureUniqueCursors();
1469void KateViewInternal::cursorPrevChar(
bool sel)
1471 if (!view()->wrapCursor() && m_cursor.
column() == 0) {
1475 moveChar(KateViewInternal::left, sel);
1478void KateViewInternal::cursorNextChar(
bool sel)
1480 moveChar(KateViewInternal::right, sel);
1483void KateViewInternal::wordPrev(
bool sel)
1486 return doc()->characterAt({
cursor.line(),
cursor.column() - 1});
1490 WrappingCursor c(
this,
cursor);
1500 KateHighlighting *h = doc()->highlight();
1502 while (!c.atEdge(left) && (c.
column() > doc()->lineLength(c.
line()) || characterAtPreviousColumn(c).isSpace())) {
1506 if (c.atEdge(left)) {
1508 }
else if (h->isInWord(characterAtPreviousColumn(c))) {
1509 if (doc()->config()->camelCursor()) {
1510 CamelCursor cc(
this,
cursor);
1514 while (!c.atEdge(left) && h->isInWord(characterAtPreviousColumn(c))) {
1519 while (!c.atEdge(left)
1520 && !h->isInWord(characterAtPreviousColumn(c))
1523 && !characterAtPreviousColumn(c).isSpace()) {
1531 const auto &secondaryCursors = view()->m_secondaryCursors;
1533 for (
const auto &
cursor : secondaryCursors) {
1534 auto oldPos =
cursor.cursor();
1535 auto newCursorPos = wordPrevious(
cursor.cursor());
1536 cursor.pos->setPosition(newCursorPos);
1537 cursorsToUpdate.
push_back({oldPos, newCursorPos});
1541 const auto c = wordPrevious(m_cursor);
1542 updateSelection(c, sel);
1546 view()->ensureUniqueCursors();
1548 updateSecondaryCursors(cursorsToUpdate, sel);
1551void KateViewInternal::wordNext(
bool sel)
1554 WrappingCursor c(
this,
cursor);
1564 KateHighlighting *h = doc()->highlight();
1565 if (c.atEdge(right)) {
1567 }
else if (h->isInWord(doc()->characterAt(c))) {
1568 if (doc()->config()->camelCursor()) {
1569 CamelCursor cc(
this,
cursor);
1573 while (!c.atEdge(right) && h->isInWord(doc()->characterAt(c))) {
1578 while (!c.atEdge(right)
1579 && !h->isInWord(doc()->characterAt(c))
1582 && !doc()->characterAt(c).isSpace()) {
1587 while (!c.atEdge(right) && doc()->characterAt(c).isSpace()) {
1594 const auto &secondaryCursors = view()->m_secondaryCursors;
1596 for (
const auto &
cursor : secondaryCursors) {
1597 auto oldPos =
cursor.cursor();
1598 auto newCursorPos = nextWord(
cursor.cursor());
1599 cursor.pos->setPosition(newCursorPos);
1600 cursorsToUpdate.
push_back({oldPos, newCursorPos});
1604 const auto c = nextWord(m_cursor);
1605 updateSelection(c, sel);
1610 view()->ensureUniqueCursors();
1612 updateSecondaryCursors(cursorsToUpdate, sel);
1615void KateViewInternal::moveEdge(KateViewInternal::Bias bias,
bool sel)
1617 BoundedCursor c(
this, m_cursor);
1619 updateSelection(c, sel);
1625 if (view()->dynWordWrap() && currentLayout(
cursor).startCol()) {
1627 if (
cursor.column() != currentLayout(
cursor).startCol()) {
1633 if (!doc()->config()->smartHome()) {
1634 BoundedCursor c(
this,
cursor);
1639 if (
cursor.line() < 0 ||
cursor.line() >= doc()->lines()) {
1648 if (lc < 0 || c.
column() == lc) {
1656void KateViewInternal::home(
bool sel)
1659 view()->ensureUniqueCursors(
true);
1660 const auto &secondaryCursors = view()->m_secondaryCursors;
1662 for (
const auto &c : secondaryCursors) {
1663 auto oldPos = c.cursor();
1665 auto newPos = moveCursorToLineStart(oldPos);
1667 cursorsToUpdate.
push_back({oldPos, newPos});
1671 auto newPos = moveCursorToLineStart(m_cursor);
1672 if (newPos.isValid()) {
1673 updateSelection(newPos, sel);
1674 updateCursor(newPos,
true);
1676 updateSecondaryCursors(cursorsToUpdate, sel);
1683 if (view()->dynWordWrap() &&
layout.wrap()) {
1691 if (!doc()->config()->smartHome()) {
1692 BoundedCursor c(
this,
cursor);
1697 if (
cursor.line() < 0 ||
cursor.line() >= doc()->lines()) {
1704 if (
cursor.column() == doc()->lineLength(
cursor.line())) {
1709 BoundedCursor c(
this,
cursor);
1715void KateViewInternal::end(
bool sel)
1718 view()->ensureUniqueCursors(
true);
1721 const auto &secondaryCursors = view()->m_secondaryCursors;
1722 for (
const auto &c : secondaryCursors) {
1723 auto oldPos = c.cursor();
1725 auto newPos = moveCursorToLineEnd(oldPos);
1727 cursorsToUpdate.
push_back({oldPos, newPos});
1730 auto newPos = moveCursorToLineEnd(m_cursor);
1731 if (newPos.isValid()) {
1732 updateSelection(newPos, sel);
1733 updateCursor(newPos);
1736 updateSecondaryCursors(cursorsToUpdate, sel);
1747 int currentViewLine = cache()->
viewLine(c);
1749 if (currentViewLine) {
1752 return cache()->
textLayout(view()->textFolding().visibleLineToLine(toVirtualCursor(c).line() - 1), -1);
1758 int currentViewLine = cache()->
viewLine(c) + 1;
1760 const KateLineLayout *thisLine = cache()->
line(c.
line());
1761 if (thisLine && currentViewLine >= thisLine->viewLineCount()) {
1762 currentViewLine = 0;
1763 return cache()->
textLayout(view()->textFolding().visibleLineToLine(toVirtualCursor(c).line() + 1), currentViewLine);
1779 if (!view()->dynWordWrap()) {
1780 KTextEditor::Cursor ret(qMin((
int)view()->textFolding().visibleLines() - 1, virtualCursor.
line() + offset), 0);
1782 if (ret.line() < 0) {
1789 Q_ASSERT(t.isValid());
1791 ret.setColumn(renderer()->xToCursor(t, m_preservedX, !view()->wrapCursor()).column());
1798 realCursor.
setLine(view()->textFolding().visibleLineToLine(view()->textFolding().lineToVisibleLine(virtualCursor.
line())));
1800 int cursorViewLine = cache()->
viewLine(realCursor);
1802 int currentOffset = 0;
1803 int virtualLine = 0;
1805 bool forwards = (offset > 0) ?
true : false;
1808 currentOffset = cache()->lastViewLine(realCursor.
line()) - cursorViewLine;
1809 if (offset <= currentOffset) {
1812 Q_ASSERT(thisLine.virtualLine() == (
int)view()->textFolding().lineToVisibleLine(virtualCursor.
line()));
1816 virtualLine = virtualCursor.
line() + 1;
1820 currentOffset = cursorViewLine;
1821 if (offset <= currentOffset) {
1824 Q_ASSERT(thisLine.virtualLine() == (
int)view()->textFolding().lineToVisibleLine(virtualCursor.
line()));
1828 virtualLine = virtualCursor.
line() - 1;
1833 while (virtualLine >= 0 && virtualLine < (
int)view()->textFolding().visibleLines()) {
1835 KateLineLayout *thisLine = cache()->
line(realLine, virtualLine);
1840 for (
int i = 0; i < thisLine->viewLineCount(); ++i) {
1841 if (offset == currentOffset) {
1846 int requiredViewLine = cache()->lastViewLine(realLine) - thisViewLine.
viewLine();
1847 if (requiredViewLine != thisViewLine.
viewLine()) {
1848 thisViewLine = thisLine->viewLine(requiredViewLine);
1856 realCursor = renderer()->
xToCursor(thisViewLine, m_preservedX, !view()->wrapCursor());
1877 doc()->lineLength(view()->textFolding().visibleLineToLine(view()->textFolding().visibleLines() - 1)));
1885 if (!view()->wrapCursor() && !range.wrap()) {
1889 int maxX = range.endX();
1891 if (maxX && range.wrap()) {
1892 QChar lastCharInLine = doc()->kateTextLine(range.line()).at(range.
endCol() - 1);
1901 int maxCol = range.
endCol();
1903 if (maxCol && range.wrap()) {
1910void KateViewInternal::cursorUp(
bool sel)
1912 if (!sel && view()->completionWidget()->isCompletionActive()) {
1913 view()->completionWidget()->cursorUp();
1922 for (
const auto &c : view()->m_secondaryCursors) {
1923 auto cursor = c.pos->toCursor();
1924 auto vCursor = toVirtualCursor(
cursor);
1927 if (vCursor.line() == 0 && (!view()->dynWordWrap() || cache()->viewLine(
cursor) == 0)) {
1928 auto newPos = moveCursorToLineStart(
cursor);
1930 auto newVcursor = toVirtualCursor(newPos);
1932 updateSecondarySelection(i,
cursor, newPos);
1934 view()->clearSecondarySelections();
1936 tagLines(newVcursor.line(), vCursor.line());
1941 auto lineLayout = currentLayout(
cursor);
1942 Q_ASSERT(lineLayout.line() ==
cursor.line());
1943 Q_ASSERT(lineLayout.startCol() <=
cursor.column());
1944 Q_ASSERT(!lineLayout.wrap() ||
cursor.column() < lineLayout.endCol());
1951 auto newVcursor = toVirtualCursor(newPos);
1953 updateSecondarySelection(i,
cursor, newPos);
1955 view()->clearSecondarySelections();
1957 tagLines(newVcursor.line(), vCursor.line());
1961 auto mergeOnFuncEnd = qScopeGuard([
this, sel] {
1965 view()->ensureUniqueCursors();
1972 Q_ASSERT(m_displayCursor.
line() < view()->textFolding().visibleLines());
1975 if (m_displayCursor.
line() == 0 && (!view()->dynWordWrap() || cache()->viewLine(m_cursor) == 0)) {
1976 auto newPos = moveCursorToLineStart(m_cursor);
1978 updateSelection(newPos, sel);
1979 updateCursor(newPos,
true);
1989 Q_ASSERT(m_cursor.
line() == thisLine.line());
1990 Q_ASSERT(m_cursor.
column() >= thisLine.startCol());
1991 Q_ASSERT(!thisLine.wrap() || m_cursor.
column() < thisLine.
endCol());
1995 updateSelection(c, sel);
1999void KateViewInternal::cursorDown(
bool sel)
2001 if (!sel && view()->completionWidget()->isCompletionActive()) {
2002 view()->completionWidget()->cursorDown();
2010 for (
const auto &c : view()->m_secondaryCursors) {
2011 auto cursor = c.cursor();
2012 auto vCursor = toVirtualCursor(
cursor);
2015 if ((vCursor.line() >= view()->textFolding().visibleLines() - 1)
2016 && (!view()->dynWordWrap() || cache()->viewLine(
cursor) == cache()->lastViewLine(
cursor.line()))) {
2020 updateSecondarySelection(i,
cursor, newPos);
2022 view()->clearSecondarySelections();
2024 auto vNewPos = toVirtualCursor(newPos);
2025 tagLines(vCursor.line(), vNewPos.line());
2035 Q_ASSERT((
cursor.line() == thisLine.line()) && (
cursor.column() >= thisLine.startCol()) && (!thisLine.wrap() ||
cursor.column() < thisLine.
endCol()));
2040 updateSecondarySelection(i,
cursor, newPos);
2042 view()->clearSecondarySelections();
2044 auto vNewPos = toVirtualCursor(newPos);
2045 tagLines(vCursor.line(), vNewPos.line());
2048 auto mergeOnFuncEnd = qScopeGuard([
this, sel] {
2052 view()->ensureUniqueCursors();
2059 if ((m_displayCursor.
line() >= view()->textFolding().visibleLines() - 1)
2060 && (!view()->dynWordWrap() || cache()->
viewLine(m_cursor) == cache()->lastViewLine(m_cursor.
line()))) {
2061 auto newPos = moveCursorToLineEnd(m_cursor);
2063 updateSelection(newPos, sel);
2064 updateCursor(newPos);
2074 Q_ASSERT((m_cursor.
line() == thisLine.line()) && (m_cursor.
column() >= thisLine.startCol()) && (!thisLine.wrap() || m_cursor.
column() < thisLine.
endCol()));
2078 updateSelection(c, sel);
2082void KateViewInternal::cursorToMatchingBracket(
bool sel)
2087 updateSelection(c, sel);
2092void KateViewInternal::topOfView(
bool sel)
2094 view()->clearSecondaryCursors();
2096 updateSelection(toRealCursor(c), sel);
2097 updateCursor(toRealCursor(c));
2100void KateViewInternal::bottomOfView(
bool sel)
2102 view()->clearSecondaryCursors();
2104 updateSelection(toRealCursor(c), sel);
2105 updateCursor(toRealCursor(c));
2109void KateViewInternal::scrollLines(
int lines,
bool sel)
2114 c.
setLine(view()->textFolding().visibleLineToLine(c.
line()));
2116 updateSelection(c, sel);
2121void KateViewInternal::scrollUp()
2127void KateViewInternal::scrollDown()
2133void KateViewInternal::setAutoCenterLines(
int viewLines,
bool updateView)
2135 m_autoCenterLines = viewLines;
2136 m_minLinesVisible = qMin(
int((linesDisplayed() - 1) / 2), m_autoCenterLines);
2138 KateViewInternal::updateView();
2142void KateViewInternal::pageUp(
bool sel,
bool half)
2144 if (view()->isCompletionActive()) {
2145 view()->completionWidget()->pageUp();
2148 view()->clearSecondaryCursors();
2152 if (!view()->visibleRange().contains(m_displayCursor)) {
2153 scrollLines(m_displayCursor.
line());
2161 int lineadj = m_minLinesVisible;
2165 linesToScroll = -qMax((linesDisplayed() - 1) - lineadj, 0);
2167 linesToScroll = -qMax((linesDisplayed() / 2 - 1) - lineadj, 0);
2172 if (!doc()->pageUpDownMovesCursor() && !atTop) {
2174 scrollPos(newStartPos);
2181 newPos = renderer()->
xToCursor(newLine, m_preservedX, !view()->wrapCursor());
2184 updateSelection(newPos, sel);
2185 updateCursor(newPos);
2188 scrollLines(linesToScroll, sel);
2192void KateViewInternal::pageDown(
bool sel,
bool half)
2194 if (view()->isCompletionActive()) {
2195 view()->completionWidget()->pageDown();
2199 view()->clearSecondaryCursors();
2203 if (!view()->visibleRange().contains(m_displayCursor)) {
2204 scrollLines(m_displayCursor.
line());
2209 bool atEnd = startPos() >= m_cachedMaxStartPos;
2212 int lineadj = m_minLinesVisible;
2216 linesToScroll = qMax((linesDisplayed() - 1) - lineadj, 0);
2218 linesToScroll = qMax((linesDisplayed() / 2 - 1) - lineadj, 0);
2223 if (!doc()->pageUpDownMovesCursor() && !atEnd) {
2225 scrollPos(newStartPos);
2232 newPos = renderer()->
xToCursor(newLine, m_preservedX, !view()->wrapCursor());
2235 updateSelection(newPos, sel);
2236 updateCursor(newPos);
2239 scrollLines(linesToScroll, sel);
2243int KateViewInternal::maxLen(
int startLine)
2245 Q_ASSERT(!view()->dynWordWrap());
2247 int displayLines = (view()->
height() / renderer()->lineHeight()) + 1;
2251 for (
int z = 0; z < displayLines; z++) {
2252 int virtualLine = startLine + z;
2254 if (virtualLine < 0 || virtualLine >= (
int)view()->textFolding().
visibleLines()) {
2258 const KateLineLayout *line = cache()->
line(view()->textFolding().visibleLineToLine(virtualLine));
2263 maxLen = qMax(maxLen, line->width());
2269bool KateViewInternal::columnScrollingPossible()
2271 return !view()->dynWordWrap() && m_columnScroll->
isEnabled() && (m_columnScroll->
maximum() > 0);
2274bool KateViewInternal::lineScrollingPossible()
2279void KateViewInternal::top(
bool sel)
2283 newCursor = renderer()->
xToCursor(cache()->textLayout(newCursor), m_preservedX, !view()->wrapCursor());
2285 view()->clearSecondaryCursors();
2286 updateSelection(newCursor, sel);
2287 updateCursor(newCursor);
2290void KateViewInternal::bottom(
bool sel)
2294 newCursor = renderer()->
xToCursor(cache()->textLayout(newCursor), m_preservedX, !view()->wrapCursor());
2296 view()->clearSecondaryCursors();
2297 updateSelection(newCursor, sel);
2298 updateCursor(newCursor);
2301void KateViewInternal::top_home(
bool sel)
2303 if (view()->isCompletionActive()) {
2304 view()->completionWidget()->top();
2308 view()->clearSecondaryCursors();
2310 updateSelection(c, sel);
2314void KateViewInternal::bottom_end(
bool sel)
2316 if (view()->isCompletionActive()) {
2317 view()->completionWidget()->bottom();
2321 view()->clearSecondaryCursors();
2323 updateSelection(c, sel);
2329 if (m_selectionMode != SelectionMode::Default) {
2330 view()->clearSecondaryCursors();
2333 auto &secondaryCursors = view()->m_secondaryCursors;
2334 if (secondaryCursors.empty()) {
2335 qWarning() <<
"Invalid updateSecondarySelection with no secondaryCursors";
2338 Q_ASSERT(secondaryCursors.size() > (
size_t)cursorIdx);
2340 auto &
cursor = secondaryCursors[cursorIdx];
2341 if (
cursor.cursor() != newPos) {
2342 qWarning() <<
"Unexpected different cursor at cursorIdx" << cursorIdx <<
"found" <<
cursor.cursor() <<
"looking for: " << newPos;
2347 Q_ASSERT(
cursor.anchor.isValid());
2350 cursor.range.reset(view()->newSecondarySelectionRange({old, newPos}));
2359 if (!view()->selection()
2360 || (m_selectAnchor.
line() == -1)
2363 || (view()->config()->persistentSelection()
2364 && !(view()->selectionRange().contains(m_cursor) || view()->selectionRange().boundaryAtCursor(m_cursor)))) {
2365 m_selectAnchor = m_cursor;
2368 bool doSelect =
true;
2369 switch (m_selectionMode) {
2378 if (!m_selectionCached.
isValid()) {
2379 m_selectionCached.
setStart(m_selectionCached.
end());
2383 if (newCursor > m_selectionCached.
start()) {
2384 m_selectAnchor = m_selectionCached.
start();
2389 if (c > 0 && doc()->highlight()->isInWord(l.
at(c - 1))) {
2390 for (; c < l.
length(); c++) {
2391 if (!doc()->highlight()->isInWord(l.
at(c))) {
2398 }
else if (newCursor < m_selectionCached.
start()) {
2399 m_selectAnchor = m_selectionCached.
end();
2404 if (c > 0 && c < doc()->lineLength(newCursor.
line()) && doc()->highlight()->isInWord(l.
at(c))
2405 && doc()->highlight()->isInWord(l.
at(c - 1))) {
2406 for (c -= 2; c >= 0; c--) {
2407 if (!doc()->highlight()->isInWord(l.
at(c))) {
2419 if (!m_selectionCached.
isValid()) {
2423 if (newCursor.
line() + 1 >= doc()->lines()) {
2424 newCursor.
setColumn(doc()->line(newCursor.
line()).length());
2429 m_selectAnchor = m_selectionCached.
start();
2431 }
else if (newCursor.
line() < m_selectionCached.
start().
line()) {
2434 m_selectAnchor = m_selectionCached.
end();
2435 if (m_selectAnchor.
column() > 0) {
2436 if (m_selectAnchor.
line() + 1 >= doc()->lines()) {
2437 m_selectAnchor.
setColumn(doc()->line(newCursor.
line()).length());
2447 if (!m_selectionCached.
isValid()) {
2451 if (newCursor > m_selectionCached.
end()) {
2452 m_selectAnchor = m_selectionCached.
start();
2453 }
else if (newCursor < m_selectionCached.
start()) {
2454 m_selectAnchor = m_selectionCached.
end();
2464 }
else if (m_selectionCached.
isValid()) {
2465 setSelection(m_selectionCached);
2469 m_selChangedByUser =
true;
2470 }
else if (!view()->config()->persistentSelection()) {
2471 view()->clearSelection();
2477#ifndef QT_NO_ACCESSIBILITY
2487 view()->setSelection(range);
2491void KateViewInternal::moveCursorToSelectionEdge(
bool scroll)
2493 if (!view()->selection()) {
2497 int tmp = m_minLinesVisible;
2498 m_minLinesVisible = 0;
2500 if (view()->selectionRange().
start() < m_selectAnchor) {
2501 updateCursor(view()->selectionRange().
start(),
false,
false,
false,
scroll);
2503 updateCursor(view()->selectionRange().end(),
false,
false,
false,
scroll);
2506 m_madeVisible =
false;
2509 m_minLinesVisible = tmp;
2517 int foldCounter = 0;
2518 int lineCounter = 0;
2519 const auto foldMarkers = m_view->doc()->buffer().computeFoldings(currentCursorPos.
line());
2523 long i = direction == 1 ? 0 : (long)foldMarkers.size() - 1;
2526 for (; i >= 0 && i < (long)foldMarkers.size(); i += direction) {
2527 if ((foldMarkers[i].offset - currentCursorPos.
column()) * direction > 0 && foldMarkers[i].foldingRegion.
id() == foldingRegion.
id()) {
2528 if (foldMarkers[i].foldingRegion.
type() == foldingRegion.
type()) {
2530 }
else if (foldCounter > 0) {
2532 }
else if (foldCounter == 0) {
2534 getStartOffset(direction, foldMarkers[i].offset, foldMarkers[i].length),
2535 currentCursorPos.
line(),
2536 getEndOffset(direction, foldMarkers[i].offset, foldMarkers[i].length));
2542 int currentLine = currentCursorPos.
line() + direction;
2543 for (; currentLine >= 0 && currentLine < m_view->doc()->lines() && lineCounter < maxLines; currentLine += direction) {
2545 const auto foldMarkers = m_view->doc()->buffer().computeFoldings(currentLine);
2546 i = direction == 1 ? 0 : (long)foldMarkers.size() - 1;
2549 for (; i >= 0 && i < (long)foldMarkers.size(); i += direction) {
2550 if (foldMarkers[i].foldingRegion.
id() == foldingRegion.
id()) {
2551 if (foldMarkers[i].foldingRegion.
type() == foldingRegion.
type()) {
2553 }
else if (foldCounter != 0) {
2555 }
else if (foldCounter == 0) {
2557 getStartOffset(direction, foldMarkers[i].offset, foldMarkers[i].length),
2559 getEndOffset(direction, foldMarkers[i].offset, foldMarkers[i].length));
2571void KateViewInternal::updateFoldingMarkersHighlighting()
2573 const auto foldings = m_view->doc()->buffer().computeFoldings(m_cursor.
line());
2574 for (
unsigned long i = 0; i < foldings.size(); i++) {
2579 int startOffset = getStartOffset(-direction, foldings[i].offset, foldings[i].length);
2580 int endOffset = getEndOffset(-direction, foldings[i].offset, foldings[i].length);
2582 if (m_cursor.
column() >= startOffset && m_cursor.
column() <= endOffset) {
2583 const auto foldingMarkerMatch = findMatchingFoldingMarker(
KTextEditor::Cursor(m_cursor.
line(), m_cursor.
column()), foldings[i].foldingRegion, 2000);
2585 if (!foldingMarkerMatch.isValid()) {
2590 if (direction == 1) {
2592 m_fmEnd->setRange(foldingMarkerMatch);
2594 m_fmStart->setRange(foldingMarkerMatch);
2599 fill->setBackground(view()->rendererConfig()->highlightedBracketColor());
2601 m_fmStart->setAttribute(fill);
2602 m_fmEnd->setAttribute(fill);
2613 for (
int i = 0; i < cursors.
size(); ++i) {
2614 updateSecondarySelection(i, cursors[i].oldPos, cursors[i].newPos);
2620 view()->clearSecondarySelections();
2624 for (
auto cpair : cursors) {
2625 linesToUpdate.
push_back(cpair.oldPos.line());
2626 linesToUpdate.
push_back(cpair.newPos.line());
2629 std::sort(linesToUpdate.
begin(), linesToUpdate.
end());
2630 auto it = std::unique(linesToUpdate.
begin(), linesToUpdate.
end());
2633 using Range = std::pair<int, int>;
2636 for (
auto i = linesToUpdate.
begin(); i != it; ++i) {
2638 if (!ranges.
isEmpty() && prev + 1 == curLine) {
2639 ranges.
back().second++;
2646 for (
auto range : ranges) {
2647 int startLine = range.first;
2648 int endLine = range.first + range.second;
2649 tagLines(startLine, endLine,
true);
2654void KateViewInternal::mergeSelections()
2656 using SecondaryCursor = KTextEditor::ViewPrivate::SecondaryCursor;
2658 auto doMerge = [](
Range newRange, SecondaryCursor &a, SecondaryCursor &b) {
2665 auto &cursors = view()->m_secondaryCursors;
2666 for (
auto it = cursors.
begin(); it != cursors.
end(); ++it) {
2669 if (it + 1 == cursors.
end()) {
2673 auto n = std::next(it);
2678 auto curRange = it->range->toRange();
2679 auto nextRange = n->range->toRange();
2680 if (!curRange.overlaps(nextRange)) {
2684 bool isLefSel = it->cursor() < it->anchor;
2689 auto curPos = it->cursor();
2690 nextRange.expandToRange(curRange);
2695 n->pos->setPosition(curPos);
2696 n->anchor = qMax(n->anchor, it->anchor);
2698 n->anchor = qMin(n->anchor, it->anchor);
2700 doMerge(nextRange, *n, *it);
2703 if (view()->selection()) {
2704 auto primarySel = view()->m_selection.
toRange();
2705 auto primCursor = cursorPosition();
2706 for (
auto it = cursors.
begin(); it != cursors.
end(); ++it) {
2710 auto curRange = it->range ? it->range->toRange() : Range::invalid();
2711 if (curRange.isValid() && primarySel.overlaps(curRange)) {
2712 primarySel.expandToRange(curRange);
2713 bool isLeft = it->cursor() < it->anchor;
2716 if (it->cursor() < primCursor) {
2717 updateCursor(it->cursor());
2719 m_selectAnchor = qMax(m_selectAnchor, it->anchor);
2721 if (it->cursor() > primCursor) {
2722 updateCursor(it->cursor());
2724 m_selectAnchor = qMin(m_selectAnchor, it->anchor);
2727 setSelection(primarySel);
2730 }
else if (it->pos) {
2734 auto pos = it->cursor();
2735 if (!primarySel.boundaryAtCursor(
pos) && primarySel.contains(
pos)) {
2742 cursors.
erase(std::remove_if(cursors.
begin(),
2744 [](
const SecondaryCursor &c) {
2745 return !c.pos.get();
2750void KateViewInternal::updateCursor(
const KTextEditor::Cursor newCursor,
bool force,
bool center,
bool calledExternally,
bool scroll)
2752 if (!force && (m_cursor.
toCursor() == newCursor)) {
2753 m_displayCursor = toVirtualCursor(newCursor);
2754 if (
scroll && !m_madeVisible && m_view == doc()->activeView()) {
2758 makeVisible(m_displayCursor, m_displayCursor.
column(),
false, center, calledExternally);
2764 if (m_cursor.
line() != newCursor.
line()) {
2765 m_leftBorder->updateForCursorLineChange();
2773 m_displayCursor = toVirtualCursor(newCursor);
2776 if (m_view == doc()->activeView() &&
scroll) {
2777 makeVisible(m_displayCursor, m_displayCursor.
column(),
false, center, calledExternally);
2780 updateBracketMarks();
2782 updateFoldingMarkersHighlighting();
2785 tagLine(oldDisplayCursor);
2786 if (oldDisplayCursor.
line() != m_displayCursor.
line()) {
2787 tagLine(m_displayCursor);
2801 m_preserveX =
false;
2803 m_preservedX = renderer()->
cursorToX(cache()->textLayout(m_cursor), m_cursor, !view()->wrapCursor());
2817void KateViewInternal::updateBracketMarkAttributes()
2820 bracketFill->setBackground(view()->rendererConfig()->highlightedBracketColor());
2821 bracketFill->setBackgroundFillWhitespace(
false);
2822 if (
QFontInfo(renderer()->currentFont()).fixedPitch()) {
2824 bracketFill->setFontBold();
2827 m_bmStart->setAttribute(bracketFill);
2828 m_bmEnd->setAttribute(bracketFill);
2830 if (view()->rendererConfig()->showWholeBracketExpression()) {
2832 expressionFill->setBackground(view()->rendererConfig()->highlightedBracketColor());
2833 expressionFill->setBackgroundFillWhitespace(
false);
2835 m_bm->setAttribute(expressionFill);
2841void KateViewInternal::updateBracketMarks()
2844 const int maxLines = 5000;
2849 if (m_bm->toRange() == newRange) {
2851 hideBracketMatchPreview();
2856 m_bm->setRange(newRange);
2863 if (m_view->config()->
value(KateViewConfig::ShowBracketMatchPreview).
toBool()) {
2864 showBracketMatchPreview();
2868 if (!m_view->rendererConfig()->animateBracketMatching()) {
2872 const KTextEditor::Cursor flashPos = (m_cursor == m_bmStart->start() || m_cursor == m_bmStart->end()) ? m_bmEnd->start() : m_bm->start();
2873 if (flashPos != m_bmLastFlashPos->toCursor()) {
2874 m_bmLastFlashPos->setPosition(flashPos);
2877 attribute->setBackground(view()->rendererConfig()->highlightedBracketColor());
2878 if (m_bmStart->attribute()->fontBold()) {
2879 attribute->setFontBold(
true);
2882 flashChar(flashPos, attribute);
2892 hideBracketMatchPreview();
2898 return tagLines(virtualCursor, virtualCursor,
false);
2901bool KateViewInternal::tagLines(
int start,
int end,
bool realLines)
2909 cache()->relayoutLines(
start.line(),
end.line());
2913 end = toVirtualCursor(end);
2916 cache()->relayoutLines(toRealCursor(
start).line(), toRealCursor(end).line());
2919 if (
end.line() < startLine()) {
2925 if (
start.line() > startLine() + cache()->viewCacheLineCount()) {
2930 cache()->updateViewCache(startPos());
2936 for (
int z = 0; z < cache()->viewCacheLineCount(); z++) {
2938 if ((line.virtualLine() >
start.line() || (line.virtualLine() ==
start.line() && line.
endCol() >=
start.column() &&
start.column() != -1))
2939 && (line.virtualLine() <
end.line() || (line.virtualLine() ==
end.line() && (line.startCol() <=
end.column() ||
end.column() == -1)))) {
2947 if (!m_view->config()->showFoldingOnHoverOnly() && doc()->highlight() && doc()->highlight()->foldingIndentationSensitive()) {
2950 }
else if (!view()->dynWordWrap()) {
2951 int y = lineToY(
start.line());
2953 int h = (
end.line() -
start.line() + 2) * renderer()->lineHeight();
2962 for (
int z = 0; z < cache()->viewCacheLineCount(); z++) {
2965 || ((line.virtualLine() >
start.line() || (line.virtualLine() ==
start.line() && line.
endCol() >=
start.column() &&
start.column() != -1))
2966 && (line.virtualLine() <
end.line() || (line.virtualLine() ==
end.line() && (line.startCol() <=
end.column() ||
end.column() == -1))))) {
2968 m_leftBorder->
update(0, z * renderer()->lineHeight(), m_leftBorder->
width(), m_leftBorder->
height());
2985 return tagLines(range.
start(), range.
end(), realCursors);
2988void KateViewInternal::tagAll()
2993 m_leftBorder->updateFont();
2997void KateViewInternal::paintCursor()
2999 if (tagLine(m_displayCursor)) {
3005 for (
const auto &c : view()->m_secondaryCursors) {
3006 auto p = c.cursor();
3007 if (p.line() >= s - 1 && p.line() <= e + 1) {
3008 tagLines(p, p,
true);
3020 if (!thisLine.isValid()) {
3021 thisLine = cache()->
textLayout(doc()->lines() - 1, -1);
3024 c = renderer()->
xToCursor(thisLine, startX() + p.
x(), !view()->wrapCursor());
3026 if (c.
line() < 0 || c.
line() >= doc()->lines()) {
3031 const auto inlineNotes = view()->inlineNotes(c.
line());
3033 for (
const auto ¬e : inlineNotes) {
3034 auto noteCursor = note.m_position;
3036 if (note.m_position.column() >= doc()->lineLength(c.
line()) || note.m_position.column() == 0) {
3042 const auto caretWidth = renderer()->
caretStyle() == KTextEditor::caretStyles::Line ? 2. : 0.;
3045 const auto halfCharWidth = (charWidth / 2);
3048 const auto totalWidth =
width + halfCharWidth;
3052 if (r.contains(p)) {
3062void KateViewInternal::placeCursor(
const QPoint &p,
bool keepSelection,
bool updateSelection)
3069 if (updateSelection) {
3070 KateViewInternal::updateSelection(c, keepSelection);
3073 int tmp = m_minLinesVisible;
3074 m_minLinesVisible = 0;
3076 m_minLinesVisible = tmp;
3078 if (updateSelection && keepSelection) {
3079 moveCursorToSelectionEdge();
3084bool KateViewInternal::isTargetSelected(
const QPoint &p)
3087 if (!thisLine.isValid()) {
3091 return view()->cursorSelected(renderer()->xToCursor(thisLine, startX() + p.
x(), !view()->wrapCursor()));
3098 switch (e->
type()) {
3114 if (!view()->m_secondaryCursors.empty()) {
3115 view()->clearSecondaryCursors();
3120 if (view()->isCompletionActive()) {
3121 view()->abortCompletion();
3125 }
else if (view()->bottomViewBar()->barWidgetVisible()) {
3126 view()->bottomViewBar()->hideCurrentBarWidget();
3130 }
else if (!view()->config()->persistentSelection() && view()->selection()) {
3131 m_currentInputMode->clearSelection();
3138 if (m_currentInputMode->stealKey(k)) {
3171 QRect doNotScrollRegion(s_scrollMargin, s_scrollMargin,
width() - s_scrollMargin * 2,
height() - s_scrollMargin * 2);
3173 if (!doNotScrollRegion.contains(currentPoint)) {
3188 hideBracketMatchPreview();
3193 scrollPrepareEvent(s);
3210void KateViewInternal::keyPressEvent(
QKeyEvent *e)
3214 view()->emitNavigateLeft();
3219 view()->emitNavigateRight();
3224 view()->emitNavigateUp();
3229 view()->emitNavigateDown();
3234 view()->emitNavigateAccept();
3239 view()->emitNavigateBack();
3244 if (e->
key() ==
Qt::Key_Alt && view()->completionWidget()->isCompletionActive()) {
3245 view()->completionWidget()->toggleDocumentation();
3251 if (m_currentInputMode->keyPress(e)) {
3255 if (!doc()->isReadWrite()) {
3262 view()->keyReturn();
3276 uint tabHandling = doc()->config()->tabHandling();
3278 if (tabHandling == KateDocumentConfig::tabSmart) {
3280 if (view()->selection() && !view()->selectionRange().onSingleLine()) {
3281 tabHandling = KateDocumentConfig::tabIndents;
3291 if (first < 0 || m_cursor.
column() <= first) {
3292 tabHandling = KateDocumentConfig::tabIndents;
3294 tabHandling = KateDocumentConfig::tabInsertsTab;
3300 if (tabHandling == KateDocumentConfig::tabInsertsTab) {
3301 doc()->typeChars(m_view, QStringLiteral(
"\t"));
3304 for (
const auto &c :
std::as_const(m_view->m_secondaryCursors)) {
3305 auto cursor = c.cursor();
3309 doc()->indent(view()->selection() ? view()->selectionRange() :
KTextEditor::
Range(m_cursor.line(), 0, m_cursor.line(), 0), 1);
3316 }
else if (doc()->config()->tabHandling() != KateDocumentConfig::tabInsertsTab) {
3318 doc()->indent(view()->selection() ? view()->selectionRange() :
KTextEditor::
Range(m_cursor.line(), 0, m_cursor.line(), 0), -1);
3325 if (isAcceptableInput(e)) {
3326 doc()->typeChars(m_view, e->
text());
3334void KateViewInternal::keyReleaseEvent(
QKeyEvent *e)
3337 m_shiftKeyPressed =
false;
3339 if (m_selChangedByUser) {
3340 if (view()->selection()) {
3344 m_selChangedByUser =
false;
3352bool KateViewInternal::isAcceptableInput(
const QKeyEvent *e)
3394 makeVisible(m_displayCursor, 0);
3395 p = cursorCoordinates(
false);
3397 }
else if (!view()->selection() || view()->config()->persistentSelection()) {
3398 placeCursor(e->
pos());
3402 QMenu *cm = view()->contextMenu();
3404 view()->spellingMenu()->prepareToBeShown(cm);
3410void KateViewInternal::mousePressEvent(
QMouseEvent *e)
3412 if (sendMouseEventToInputContext(e)) {
3419 if (note.position().isValid()) {
3430 m_selChangedByUser =
false;
3432 if (!view()->isMulticursorNotAllowed() && e->
modifiers() == view()->config()->multiCursorModifiers()) {
3433 auto pos = cursorForPoint(e->
pos());
3434 if (
pos.isValid()) {
3435 view()->addSecondaryCursor(
pos);
3440 view()->clearSecondaryCursors();
3443 if (m_possibleTripleClick) {
3444 m_possibleTripleClick =
false;
3446 m_selectionMode = Line;
3449 updateSelection(m_cursor,
true);
3451 view()->selectLine(m_cursor);
3452 if (view()->selection()) {
3453 m_selectAnchor = view()->selectionRange().
start();
3457 if (view()->selection()) {
3463 if (m_selectAnchor.
line() > view()->selectionRange().
start().line()) {
3465 if (m_selectAnchor == view()->selectionRange().
end() && m_selectAnchor.
column() == 0) {
3470 m_selectionCached.
setEnd(view()->selectionRange().
end());
3473 m_selectionCached.
setStart(view()->selectionRange().
start());
3474 if (view()->selectionRange().
end().line() > view()->selectionRange().
start().line()) {
3477 m_selectionCached.
setEnd(view()->selectionRange().
end());
3481 moveCursorToSelectionEdge();
3485 m_scrollTimer.
start(50);
3489 }
else if (m_selectionMode == Default) {
3490 m_selectionMode = Mouse;
3503 if (!m_selectAnchor.
isValid()) {
3504 m_selectAnchor = m_cursor;
3511 m_dragInfo.state = diPending;
3512 m_dragInfo.start = e->
pos();
3514 m_dragInfo.state = diNone;
3517 placeCursor(e->
pos(),
true,
false);
3520 m_selectAnchor = m_selectionCached.
end();
3522 m_selectAnchor = m_selectionCached.
start();
3528 if (view()->selection()) {
3532 placeCursor(e->
pos());
3538 m_scrollTimer.
start(50);
3545 if (e->
pos().
x() == 0) {
3547 placeCursor(e->
pos());
3558void KateViewInternal::mouseDoubleClickEvent(
QMouseEvent *e)
3560 if (sendMouseEventToInputContext(e)) {
3564 m_selectionMode = Word;
3572 ce = m_selectAnchor.
column();
3573 if (ce > 0 && doc()->highlight()->isInWord(l.
at(ce))) {
3574 for (; ce < l.
length(); ce++) {
3575 if (!doc()->highlight()->isInWord(l.
at(ce))) {
3581 cs = m_selectAnchor.
column() - 1;
3582 if (cs < doc()->lineLength(m_selectAnchor.
line()) && doc()->highlight()->isInWord(l.
at(cs))) {
3583 for (cs--; cs >= 0; cs--) {
3584 if (!doc()->highlight()->isInWord(l.
at(cs))) {
3595 m_selectionCached.
setStart(m_selectAnchor);
3596 m_selectionCached.
setEnd(m_selectAnchor);
3599 placeCursor(e->
pos(),
true);
3606 view()->clearSelection(
false,
false);
3607 placeCursor(e->
pos());
3608 view()->selectWord(m_cursor);
3609 cursorToMatchingBracket(
true);
3611 if (view()->selection()) {
3612 m_selectAnchor = view()->selectionRange().
start();
3613 m_selectionCached = view()->selectionRange();
3615 m_selectAnchor = m_cursor;
3622 if (view()->selection()) {
3627 moveCursorToSelectionEdge();
3628 m_possibleTripleClick =
true;
3634 m_scrollTimer.
start(50);
3642void KateViewInternal::tripleClickTimeout()
3644 m_possibleTripleClick =
false;
3647void KateViewInternal::beginSelectLine(
const QPoint &pos)
3650 m_possibleTripleClick =
true;
3653void KateViewInternal::mouseReleaseEvent(
QMouseEvent *e)
3655 if (sendMouseEventToInputContext(e)) {
3661 m_selectionMode = Default;
3664 if (m_selChangedByUser) {
3665 if (view()->selection()) {
3668 moveCursorToSelectionEdge();
3670 m_selChangedByUser =
false;
3673 if (m_dragInfo.state == diPending) {
3675 }
else if (m_dragInfo.state == diNone) {
3676 m_scrollTimer.
stop();
3679 m_dragInfo.state = diNone;
3682 if (view()->selection() && !view()->m_secondaryCursors.empty()) {
3690 if (!view()->config()->mousePasteAtCursorPosition()) {
3691 placeCursor(e->
pos());
3694 if (doc()->isReadWrite()) {
3696 view()->paste(&clipboard);
3708void KateViewInternal::leaveEvent(
QEvent *)
3710 m_textHintTimer.
stop();
3714 if (m_dragInfo.state == diNone) {
3715 m_scrollTimer.
stop();
3718 hideBracketMatchPreview();
3727 if (includeBorder) {
3728 coord.rx() -= m_leftBorder->
width();
3730 coord.rx() += startX();
3733 if (thisLine.isValid()) {
3734 ret = renderer()->
xToCursor(thisLine, coord.x(), !view()->wrapCursor());
3737 if (ret.
column() > view()->document()->lineLength(ret.
line())) {
3746void KateViewInternal::mouseMoveEvent(
QMouseEvent *e)
3753 if (newPosition != m_mouse) {
3754 m_mouse = newPosition;
3760 auto focusChanged =
false;
3761 if (noteData.m_position.isValid()) {
3762 if (!m_activeInlineNote.m_position.
isValid()) {
3764 tagLine(noteData.m_position);
3765 focusChanged =
true;
3766 noteData.m_underMouse =
true;
3768 m_activeInlineNote = noteData;
3772 }
else if (m_activeInlineNote.m_position.
isValid()) {
3773 tagLine(m_activeInlineNote.m_position);
3774 focusChanged =
true;
3775 m_activeInlineNote.m_underMouse =
false;
3777 m_activeInlineNote = {};
3786 if (m_dragInfo.state == diPending) {
3797 }
else if (m_dragInfo.state == diDragging) {
3808 int d = renderer()->lineHeight();
3814 if (m_mouseX >
width()) {
3823 if (m_mouseY >
height()) {
3835 placeCursor(
QPoint(m_mouseX, m_mouseY),
true);
3838 if (view()->config()->textDragAndDrop() && isTargetSelected(e->
pos())) {
3859 m_textHintTimer.
start(m_textHintDelay);
3860 m_textHintPos = e->
pos();
3865void KateViewInternal::updateDirty()
3867 const int h = renderer()->lineHeight();
3869 int currentRectStart = -1;
3870 int currentRectEnd = -1;
3875 for (
int i = 0; i < cache()->viewCacheLineCount(); ++i) {
3876 if (cache()->
viewLine(i).isDirty()) {
3877 if (currentRectStart == -1) {
3878 currentRectStart = h * i;
3881 currentRectEnd += h;
3884 }
else if (currentRectStart != -1) {
3885 updateRegion +=
QRect(0, currentRectStart,
width(), currentRectEnd);
3886 currentRectStart = -1;
3887 currentRectEnd = -1;
3892 if (currentRectStart != -1) {
3893 updateRegion +=
QRect(0, currentRectStart,
width(), currentRectEnd);
3896 if (!updateRegion.
isEmpty()) {
3897 if (debugPainting) {
3898 qCDebug(LOG_KTE) <<
"Update dirty region " << updateRegion;
3904void KateViewInternal::hideEvent(
QHideEvent *e)
3907 if (view()->isCompletionActive()) {
3908 view()->completionWidget()->abortCompletion();
3914 if (debugPainting) {
3915 qCDebug(LOG_KTE) <<
"GOT PAINT EVENT: Region" << e->
region();
3920 int xStart = startX() + unionRect.
x();
3921 int xEnd = xStart + unionRect.
width();
3922 uint h = renderer()->lineHeight();
3923 uint startz = (unionRect.
y() / h);
3924 uint endz = startz + 1 + (unionRect.
height() / h);
3925 uint lineRangesSize = cache()->viewCacheLineCount();
3936 renderer()->
setCaretStyle(m_currentInputMode->caretStyle());
3937 renderer()->
setShowTabs(doc()->config()->showTabs());
3944 paint.translate(unionRect.
x(), startz * h);
3945 for (uint z = startz; z <= endz; z++) {
3947 if ((z >= lineRangesSize) || (cache()->viewLine(z).line() == -1)) {
3948 if (!(z >= lineRangesSize)) {
3949 cache()->
viewLine(z).setDirty(
false);
3951 paint.fillRect(0, 0, unionRect.
width(), h, m_view->rendererConfig()->backgroundColor());
3965 if (!thisLine.
viewLine() || z == startz) {
3969 const int thisLineTop = h * thisLine.
viewLine();
3970 paint.translate(
QPoint(0, -thisLineTop));
3974 const QRectF lineRect(0, 0, unionRect.
width(), h * thisLine.kateLineLayout()->viewLineCount());
3975 paint.fillRect(lineRect, m_view->rendererConfig()->backgroundColor());
3980 paint.setClipRect(lineRect);
3985 const QRect textClipRect{xStart, thisLineTop, xEnd - xStart,
height()};
3987 renderer()->
paintTextLine(paint, thisLine.kateLineLayout(), xStart, xEnd, textClipRect.toRectF(), &
pos);
3991 thisLine.setDirty(
false);
3996 paint.translate(0, h);
4001 if (m_textAnimation) {
4002 m_textAnimation->draw(paint);
4013 m_madeVisible =
false;
4017 showBracketMatchPreview();
4020 if (heightChanged) {
4021 setAutoCenterLines(m_autoCenterLines,
false);
4025 if (view()->dynWordWrap()) {
4026 bool dirtied =
false;
4028 for (
int i = 0; i < cache()->viewCacheLineCount(); i++) {
4033 if (viewLine.wrap() || viewLine.isRightToLeft() || viewLine.width() >
width()) {
4035 viewLine.setDirty();
4040 if (dirtied || heightChanged) {
4047 if (expandedHorizontally && startX() > 0) {
4054 if (m_cursor.
column() > doc()->lineLength(m_cursor.
line())) {
4058 thisLine.
endCol() + ((
width() - thisLine.xOffset() - (thisLine.width() - startX())) / renderer()->spaceWidth()) - 1);
4060 updateCursor(newCursor);
4065 if (expandedVertically) {
4067 if (startPos() > max) {
4072 Q_EMIT view()->displayRangeChanged(m_view);
4075void KateViewInternal::moveEvent(
QMoveEvent *e)
4078 if (e->
pos() != e->
oldPos() && m_bmPreview) {
4079 showBracketMatchPreview();
4085void KateViewInternal::scrollTimeout()
4087 if (m_scrollX || m_scrollY) {
4088 const int scrollTo = startPos().
line() + (m_scrollY / (int)renderer()->lineHeight());
4089 placeCursor(
QPoint(m_mouseX, m_mouseY),
true);
4090 scrollLines(scrollTo);
4094void KateViewInternal::cursorTimeout()
4096 if (!debugPainting && m_currentInputMode->blinkCaret()) {
4102void KateViewInternal::textHintTimeout()
4104 m_textHintTimer.
stop();
4118 if (!
hint.isEmpty()) {
4124 qCDebug(LOG_KTE) <<
"Hint text: " << textHints;
4126 for (
const QString &str :
std::as_const(textHints)) {
4127 hint += QStringLiteral(
"<p>%1</p>").arg(str);
4129 QPoint pos(startX() + m_textHintPos.
x(), m_textHintPos.
y());
4142 doc()->setActiveView(m_view);
4145 view()->slotGotFocus();
4148void KateViewInternal::focusOutEvent(
QFocusEvent *)
4153 m_cursorTimer.
stop();
4157 m_textHintTimer.
stop();
4159 view()->slotLostFocus();
4161 hideBracketMatchPreview();
4164void KateViewInternal::doDrag()
4166 m_dragInfo.state = diDragging;
4167 m_dragInfo.dragObject =
new QDrag(
this);
4168 std::unique_ptr<QMimeData> mimeData(
new QMimeData());
4169 mimeData->setText(view()->selectionText());
4171 const auto startCur = view()->selectionRange().
start();
4172 const auto endCur = view()->selectionRange().
end();
4173 if (!startCur.isValid() || !endCur.isValid()) {
4177 int startLine = startCur.line();
4178 int endLine = endCur.line();
4189 for (
int l = startLine; l <= endLine; ++l) {
4190 if (l >= firstVisibleLine) {
4195 for (
int l = endLine; l >= startLine; --l) {
4196 if (l <= lastVisibleLine) {
4206 for (
int l = startLine; l <= endLine; ++l) {
4208 h += renderer()->lineHeight();
4210 qreal scale = h > m_view->
height() / 2 ? 0.75 : 1.0;
4214 if (startLine == startCur.line()) {
4215 sX = renderer()->
cursorToX(cache()->textLayout(startCur), startCur, !view()->wrapCursor());
4220 if (endLine == endCur.line()) {
4221 eX = renderer()->
cursorToX(cache()->textLayout(endCur), endCur, !view()->wrapCursor());
4227 if (view()->selection()) {
4228 view()->clearHighlights();
4233 QPixmap pixmap(w * dpr, h * dpr);
4234 if (!pixmap.isNull()) {
4235 pixmap.setDevicePixelRatio(dpr);
4237 renderer()->
paintSelection(&pixmap, startLine, sX, endLine, eX, scale);
4239 if (view()->selection()) {
4254 const int y = lineToY(view()->m_textFolding.lineToVisibleLine(startLine));
4257 m_dragInfo.dragObject->
setPixmap(pixmap);
4259 m_dragInfo.dragObject->
setMimeData(mimeData.release());
4265 if (
event->source() ==
this) {
4268 event->setAccepted((
event->mimeData()->hasText() && doc()->isReadWrite()) ||
event->mimeData()->hasUrls());
4271void KateViewInternal::fixDropEvent(
QDropEvent *event)
4273 if (
event->source() !=
this) {
4286 event->setDropAction(action);
4293 placeCursor(
event->position().toPoint(),
true,
false);
4297 fixDropEvent(
event);
4300void KateViewInternal::dropEvent(
QDropEvent *event)
4303 if (
event->mimeData()->hasUrls()) {
4308 if (
event->mimeData()->hasText() && doc()->isReadWrite()) {
4309 const QString text =
event->mimeData()->text();
4310 const bool blockMode = view()->blockSelection();
4312 fixDropEvent(
event);
4317 std::unique_ptr<KTextEditor::MovingCursor> targetCursor2(doc()->newMovingCursor(m_cursor));
4325 editSetCursor(selRange.end());
4327 view()->clearSelection();
4334 view()->removeSelectedText();
4335 if (targetCursor2->toCursor() != targetCursor) {
4337 targetCursor = targetCursor2->toCursor();
4339 doc()->insertText(targetCursor2->toCursor(), text, blockMode);
4342 doc()->insertText(targetCursor, text, blockMode);
4347 editSetCursor(targetCursor + blockAdjust);
4350 editSetCursor(targetCursor2->toCursor());
4355 event->acceptProposedAction();
4360 m_dragInfo.state = diNone;
4366void KateViewInternal::clear()
4371 view()->clearSecondaryCursors();
4374 m_lineScroll->updatePixmap();
4381 if (m_zoomEventFilter->detectZoomingEvent(e)) {
4383 slotIncFontSizes(qreal(e->
angleDelta().
y()) / (qreal)QWheelEvent::DefaultDeltasPerStep);
4385 slotDecFontSizes(qreal(-e->
angleDelta().
y()) / (qreal)QWheelEvent::DefaultDeltasPerStep);
4397 auto offset = sign * qreal(e->
angleDelta().
y()) / 120.0;
4399 const auto pageStep = m_lineScroll->
pageStep();
4400 offset = qBound(-pageStep,
int(offset * pageStep), pageStep);
4406 m_accumulatedScroll += offset - int(offset);
4407 const auto extraAccumulated = int(m_accumulatedScroll);
4408 m_accumulatedScroll -= extraAccumulated;
4411 scrollViewLines(
int(offset) + extraAccumulated);
4418 if (view()->dynWordWrap()) {
4435 hideBracketMatchPreview();
4440 int lineHeight = renderer()->lineHeight();
4441 event->setViewportSize(
QSizeF(0.0, 0.0));
4442 event->setContentPosRange(
QRectF(0.0, 0.0, 0.0, m_lineScroll->
maximum() * lineHeight));
4443 event->setContentPos(
QPointF(0.0, m_lineScroll->
value() * lineHeight));
4455void KateViewInternal::startDragScroll()
4457 if (!m_dragScrollTimer.
isActive()) {
4458 m_dragScrollTimer.
start(s_scrollTime);
4462void KateViewInternal::stopDragScroll()
4464 m_dragScrollTimer.
stop();
4468void KateViewInternal::doDragScroll()
4474 if (p.
y() < s_scrollMargin) {
4475 dy = p.
y() - s_scrollMargin;
4476 }
else if (p.
y() >
height() - s_scrollMargin) {
4477 dy = s_scrollMargin - (
height() - p.
y());
4480 if (p.
x() < s_scrollMargin) {
4481 dx = p.
x() - s_scrollMargin;
4482 }
else if (p.
x() >
width() - s_scrollMargin) {
4483 dx = s_scrollMargin - (
width() - p.
x());
4489 scrollLines(startLine() + dy);
4492 if (columnScrollingPossible() && dx) {
4493 scrollColumns(qMin(startX() + dx, m_columnScroll->
maximum()));
4503 if (std::find(m_textHintProviders.cbegin(), m_textHintProviders.cend(), provider) == m_textHintProviders.cend()) {
4504 m_textHintProviders.push_back(provider);
4508 m_textHintTimer.
start(m_textHintDelay);
4513 const auto it = std::find(m_textHintProviders.cbegin(), m_textHintProviders.cend(), provider);
4514 if (it != m_textHintProviders.cend()) {
4515 m_textHintProviders.erase(it);
4518 if (m_textHintProviders.empty()) {
4519 m_textHintTimer.
stop();
4523void KateViewInternal::setTextHintDelay(
int delay)
4526 m_textHintDelay = 200;
4528 m_textHintDelay = delay;
4532int KateViewInternal::textHintDelay()
const
4534 return m_textHintDelay;
4537bool KateViewInternal::textHintsEnabled()
4539 return !m_textHintProviders.empty();
4543void KateViewInternal::editStart()
4545 editSessionNumber++;
4547 if (editSessionNumber > 1) {
4551 editIsRunning =
true;
4552 editOldCursor = m_cursor;
4553 editOldSelection = view()->selectionRange();
4556void KateViewInternal::editEnd(
int editTagLineStart,
int editTagLineEnd,
bool tagFrom)
4558 if (editSessionNumber == 0) {
4562 editSessionNumber--;
4564 if (editSessionNumber > 0) {
4571 if (view()->dynWordWrap()) {
4572 if (KateLineLayout *
layout = cache()->line(startLine())) {
4573 int index =
layout->viewLineForColumn(startPos().column());
4574 if (index >= 0 && index < layout->viewLineCount()) {
4575 col =
layout->viewLine(index).startCol();
4581 if (tagFrom && (editTagLineStart <=
int(view()->textFolding().visibleLineToLine(startLine())))) {
4584 tagLines(editTagLineStart, tagFrom ? qMax(doc()->lastLine() + 1, editTagLineEnd) : editTagLineEnd, true);
4587 if (editOldCursor == m_cursor.
toCursor()) {
4588 updateBracketMarks();
4593 if (editOldCursor != m_cursor.
toCursor() || m_view == doc()->activeView()) {
4597 if (m_cursor.
line() >= editTagLineStart && m_cursor.
line() <= editTagLineEnd) {
4598 m_madeVisible =
false;
4599 updateCursor(m_cursor,
true);
4605 if (editOldSelection != view()->selectionRange()
4607 && !(editTagLineStart > editOldSelection.
end().
line() && editTagLineEnd < editOldSelection.
start().
line()))) {
4611 editIsRunning =
false;
4616 if (m_cursor.
toCursor() != _cursor) {
4622void KateViewInternal::viewSelectionChanged()
4624 if (!view()->selection()) {
4627 const auto r = view()->selectionRange();
4628 m_selectAnchor = r.
start() == m_cursor ? r.end() : r.start();
4641 return m_layoutCache;
4653 if (realCursor.
line() < 0) {
4662 return view()->renderer();
4665void KateViewInternal::mouseMoved()
4667 view()->notifyMousePositionChanged(m_mouse);
4671void KateViewInternal::cursorMoved()
4675#ifndef QT_NO_ACCESSIBILITY
4683KTextEditor::DocumentPrivate *KateViewInternal::doc()
4685 return m_view->doc();
4688KTextEditor::DocumentPrivate *KateViewInternal::doc()
const
4690 return m_view->doc();
4693bool KateViewInternal::rangeAffectsView(
KTextEditor::Range range,
bool realCursors)
const
4695 int startLine = KateViewInternal::startLine();
4696 int endLine = startLine + (int)m_visibleLineCount;
4703 return (range.
end().
line() >= startLine) || (range.
start().
line() <= endLine);
4720 auto lineHeight = renderer()->lineHeight();
4721 return QRect(cursorToCoordinate(m_cursor,
true,
false),
QSize(1, lineHeight ? lineHeight : 1));
4728 return m_cursor.
column();
4733 if (view()->selection() && m_selectAnchor.
line() == m_cursor.
line()) {
4734 return m_selectAnchor.
column();
4736 return m_cursor.
column();
4740 return doc()->kateTextLine(m_cursor.
line()).text();
4743 if (view()->selection()) {
4744 return view()->selectionText();
4758 if (doc()->readOnly()) {
4766 if (!m_imPreeditRange) {
4767 m_imPreeditRange.reset(
4771 if (!m_imPreeditRange->toRange().isEmpty()) {
4772 doc()->inputMethodStart();
4773 doc()->removeText(*m_imPreeditRange);
4774 doc()->inputMethodEnd();
4778 view()->removeSelectedText();
4788 if (
start != removeEnd) {
4801 m_imPreeditRange->setRange(preeditRange);
4805 doc()->inputMethodStart();
4806 doc()->insertText(m_imPreeditRange->start(), e->
preeditString());
4807 doc()->inputMethodEnd();
4814 m_imPreeditRange.reset();
4815 m_imPreeditRangeChildren.clear();
4827 bool hideCursor =
false;
4830 if (m_imPreeditRange) {
4831 m_imPreeditRangeChildren.clear();
4833 int decorationColumn = 0;
4835 for (
auto &a : attributes) {
4839 hideCursor = !a.length;
4840 QColor c = qvariant_cast<QColor>(a.value);
4851 const int startLine = preEditRangeStart.
line();
4852 const int startCol = preEditRangeStart.
column();
4854 std::unique_ptr<KTextEditor::MovingRange> formatRange(doc()->newMovingRange(fr));
4856 attribute->merge(f);
4857 formatRange->setAttribute(attribute);
4858 decorationColumn =
end;
4859 m_imPreeditRangeChildren.push_back(std::move(formatRange));
4868 if (newCursor != m_cursor.
toCursor()) {
4869 updateCursor(newCursor);
4879 Q_ASSERT(
pos.isValid());
4883 if (!view()->textFolding().isLineVisible(
pos.line())) {
4888 if (m_textAnimation) {
4889 m_textAnimation->deleteLater();
4894void KateViewInternal::showBracketMatchPreview()
4903 if (m_cursor == openBracketCursor || toVirtualCursor(openBracketCursor).line() >= startLine() || m_cursor.
line() - startLine() < 2) {
4904 hideBracketMatchPreview();
4914 const int previewLine = openBracketCursor.
line();
4916 KateLineLayout *lineLayout(
new KateLineLayout(*renderer_));
4917 lineLayout->setLine(previewLine, -1);
4920 const int col = lineLayout->textLine().firstChar();
4921 if (previewLine > 0 && (col == -1 || col == openBracketCursor.
column())) {
4922 lineLayout->setLine(previewLine - 1, lineLayout->virtualLine() - 1);
4925 renderer_->
layoutLine(lineLayout, -1 ,
false );
4926 const int lineWidth =
4927 qBound(m_view->
width() / 5,
int(lineLayout->width() + renderer_->spaceWidth() * 2), m_view->
width() - m_leftBorder->
width() - m_lineScroll->
width());
4928 m_bmPreview->resize(lineWidth, renderer_->lineHeight() * 2);
4930 m_bmPreview->move(topLeft.
x(), topLeft.
y());
4931 m_bmPreview->setLine(lineLayout->virtualLine());
4932 m_bmPreview->setCenterView(
false);
4933 m_bmPreview->raise();
4934 m_bmPreview->show();
4937void KateViewInternal::hideBracketMatchPreview()
4939 m_bmPreview.reset();
4944#ifndef QT_NO_ACCESSIBILITY
4946 auto doc = view()->doc();
4955#ifndef QT_NO_ACCESSIBILITY
4957 auto doc = view()->doc();
4968 const auto noteWidth = note.width();
4969 auto noteCursor = note.position();
4973 const auto lineLength = view()->document()->
lineLength(noteCursor.line());
4974 int extraOffset = -noteWidth;
4975 if (noteCursor.column() == lineLength) {
4977 }
else if (noteCursor.column() > lineLength) {
4978 extraOffset = (noteCursor.column() - lineLength) * renderer()->spaceWidth();
4979 noteCursor.setColumn(lineLength);
4981 auto noteStartPos =
mapToGlobal(cursorToCoordinate(noteCursor,
true,
false));
4983 if (view()->dynWordWrap()) {
4984 const KateLineLayout *lineLayout = cache()->
line(noteCursor.line());
4988 noteStartPos.rx() -= note.width();
4989 extraOffset = -extraOffset;
4993 auto globalNoteRect =
QRect(noteStartPos +
QPoint{extraOffset, 0},
QSize(noteWidth, renderer()->lineHeight()));
4995 return globalNoteRect;
5002 const auto inlineNotes = view()->inlineNotes(line);
5004 for (
const auto ¬e : inlineNotes) {
5005 auto globalNoteRect = inlineNoteRect(note);
5006 if (globalNoteRect.contains(globalPos)) {
5014bool KateViewInternal::sendMouseEventToInputContext(
QMouseEvent *e)
5016 if (!m_imPreeditRange) {
5021 if (!m_imPreeditRange->contains(c) && c != m_imPreeditRange->end()) {
5025 auto cursorPos = (c - m_imPreeditRange->start());
5027 if (cursorPos.column() >= 0) {
5036void KateViewInternal::commitPreedit()
5038 if (!m_imPreeditRange) {
5045#include "moc_kateviewinternal.cpp"
A class which provides customized text decorations.
@ ActivateMouseIn
Activate attribute on mouse in.
@ ActivateCaretIn
Activate attribute on caret in.
QExplicitlySharedDataPointer< Attribute > Ptr
Shared data pointer for Attribute.
The Cursor represents a position in a Document.
constexpr int column() const noexcept
Retrieve the column on which this cursor is situated.
void setColumn(int column) noexcept
Set the cursor column to column.
void setPosition(Cursor position) noexcept
Set the current cursor position to position.
constexpr bool isValid() const noexcept
Returns whether the current position of this cursor is a valid position (line + column must both be >...
constexpr bool atStartOfDocument() const noexcept
Determine if this cursor is located at the start of a document (= at position (0, 0)).
static constexpr Cursor start() noexcept
Returns a cursor representing the start of any document - i.e., line 0, column 0.
void setLine(int line) noexcept
Set the cursor line to line.
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
static constexpr Cursor invalid() noexcept
Returns an invalid cursor.
A KParts derived class representing a text document.
virtual int lineLength(int line) const =0
Get the length of a given line in characters.
const std::array< std::unique_ptr< KateAbstractInputModeFactory >, KTextEditor::View::ViInputMode+1 > & inputModeFactories()
static KTextEditor::EditorPrivate * self()
Kate Part Internal stuff ;)
virtual void inlineNoteMouseMoveEvent(const InlineNote ¬e, const QPoint &globalPos)
Invoked when the mouse cursor moves inside the note.
virtual void inlineNoteFocusOutEvent(const InlineNote ¬e)
Invoked when the mouse cursor leaves the note.
Describes an inline note.
qreal width() const
Returns the width of this note in pixels.
@ TopInView
show message as view overlay in the top right corner.
@ CenterInView
show message as view overlay in the center of the view.
@ BottomInView
show message as view overlay in the bottom right corner.
A Cursor which is bound to a specific Document, and maintains its position.
const Cursor toCursor() const
Convert this clever cursor into a dumb one.
virtual int column() const =0
Retrieve the column on which this cursor is situated.
virtual int line() const =0
Retrieve the line on which this cursor is situated.
@ ExpandRight
Expand to encapsulate new characters to the right of the range.
@ ExpandLeft
Expand to encapsulate new characters to the left of the range.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
void setEnd(Cursor end) noexcept
Set the end cursor to end.
constexpr bool isEmpty() const noexcept
Returns true if this range contains no characters, ie.
void setRange(Range range) noexcept
Set the start and end cursors to range.start() and range.end() respectively.
static constexpr Range invalid() noexcept
Returns an invalid range.
constexpr bool isValid() const noexcept
Validity check.
void setStart(Cursor start) noexcept
Set the start cursor to start.
Class to provide text hints for a View.
void horizontalScrollPositionChanged(KTextEditor::View *view)
This signal should be emitted whenever the view is scrolled horizontally.
int lastDisplayedLine(LineType lineType=RealLine) const
Get the last displayed line in the view.
int firstDisplayedLine(LineType lineType=RealLine) const
Get the first displayed line in the view.
@ NormalInputMode
Normal Mode.
void cursorPositionChanged(KTextEditor::View *view, KTextEditor::Cursor newPosition)
This signal is emitted whenever the view's cursor position changed.
void selectionChanged(KTextEditor::View *view)
This signal is emitted whenever the view's selection changes.
void verticalScrollPositionChanged(KTextEditor::View *view, KTextEditor::Cursor newPos)
This signal should be emitted whenever the view is scrolled vertically.
QVariant value(const int key) const
Get a config value.
Internal data container for KTextEditor::InlineNote interface.
This class handles Kate's caching of layouting information (in KateLineLayout and KateTextLayout).
KateTextLayout & viewLine(int viewLine)
Returns the layout of the corresponding line in the view.
KateLineLayout * line(int realLine, int virtualLine=-1)
Returns the KateLineLayout for the specified line.
KateTextLayout textLayout(const KTextEditor::Cursor realCursor)
Returns the layout describing the text line which is occupied by realCursor.
int displayViewLine(const KTextEditor::Cursor virtualCursor, bool limitToVisible=false)
Find the view line of the cursor, relative to the display (0 = top line of view, 1 = second line,...
Handles all of the work of rendering the text (used for the views and printing)
void increaseFontSizes(qreal step=1.0) const
Change to a different font (soon to be font set?)
void paintSelection(QPaintDevice *d, int startLine, int xStart, int endLine, int xEnd, qreal scale=1.0)
Paints a range of text into d.
void setShowTabs(bool showTabs)
Set whether a mark should be painted to help identifying tabs.
const QFont & currentFont() const
Access currently used font.
const AttributePtr & attribute(uint pos) const
This takes an in index, and returns all the attributes for it.
KTextEditor::caretStyles caretStyle() const
The style of the caret (text cursor) to be painted.
void setDrawCaret(bool drawCaret)
Set whether the caret (text cursor) will be drawn.
int cursorToX(const KateTextLayout &range, int col, bool returnPastLine=false) const
Returns the x position of cursor col on the line range.
KTextEditor::Cursor xToCursor(const KateTextLayout &range, int x, bool returnPastLine=false) const
Returns the real cursor which is occupied by the specified x value, or that closest to it.
void setShowSpaces(KateDocumentConfig::WhitespaceRendering showSpaces)
Set which spaces should be rendered.
const QFontMetricsF & currentFontMetrics() const
Access currently used font metrics.
void setCaretOverrideColor(const QColor &color)
Set a brush with which to override drawing of the caret.
void setCaretStyle(KTextEditor::caretStyles style)
Set the style of caret to be painted.
void layoutLine(KateLineLayout *line, int maxwidth=-1, bool cacheLayout=false) const
Text width & height calculation functions...
void updateMarkerSize()
Update marker size shown.
void paintTextLine(QPainter &paint, KateLineLayout *range, int xStart, int xEnd, const QRectF &textClipRect=QRectF(), const KTextEditor::Cursor *cursor=nullptr, PaintTextLineFlags flags=PaintTextLineFlags())
This is the ultimate function to perform painting of a text line.
This class is used to flash text in the text view.
This class represents one visible line of text; with dynamic wrapping, many KateTextLayouts can be ne...
int endCol(bool indicateEOL=false) const
Return the end column of this text line.
int viewLine() const
Return the index of this visual line inside the document line (KateLineLayout).
This class implements a QAccessible-interface for a KateViewInternal.
int column() const override
Retrieve the column on which this cursor is situated.
void setPosition(const TextCursor &position)
Fast way to set the current cursor position to position.
int line() const override
Retrieve the line on which this cursor is situated.
void foldingRangesChanged()
If the folding state of existing ranges changes or ranges are added/removed, this signal is emitted.
int visibleLines() const
Query number of visible lines.
KTextEditor::Range foldingRange(qint64 id) const
Returns the folding range associated with id.
int visibleLineToLine(int visibleLine) const
Convert a visible line number to a line number in the text buffer.
void ensureLineIsVisible(int line)
Ensure that a given line will be visible.
Class representing a single text line.
int attribute(int pos) const
Gets the attribute at the given position use KRenderer::attributes to get the KTextAttribute for this...
const QString & text() const
Accessor to the text contained in this line.
int length() const
Returns the line's length.
int lastChar() const
Returns the position of the last non-whitespace character.
QChar at(int column) const
Returns the character at the given column.
int firstChar() const
Returns the position of the first non-whitespace character.
Q_SCRIPTABLE Q_NOREPLY void start()
QAction * hint(const QObject *recvr, const char *slot, QObject *parent)
const QList< QKeySequence > & end()
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
void actionTriggered(int action)
void setRange(int min, int max)
void sliderMoved(int value)
void valueChanged(int value)
void installFactory(InterfaceFactory factory)
QAccessibleInterface * queryAccessibleInterface(QObject *object)
void removeFactory(InterfaceFactory factory)
void updateAccessibility(QAccessibleEvent *event)
Category category(char32_t ucs4)
bool isHighSurrogate(char32_t ucs4)
bool isLetter(char32_t ucs4)
bool isLetterOrNumber(char32_t ucs4)
bool isLowSurrogate(char32_t ucs4)
bool isPrint(char32_t ucs4)
bool isSpace(char32_t ucs4)
bool isUpper(char32_t ucs4)
QObject * child() const const
bool removed() const const
void setText(const QString &text, Mode mode)
QString text(Mode mode) const const
bool isValid() const const
bool sendEvent(QObject *receiver, QEvent *event)
Qt::DropAction exec(Qt::DropActions supportedActions)
void setHotSpot(const QPoint &hotspot)
void setMimeData(QMimeData *data)
void setPixmap(const QPixmap &pixmap)
qint64 elapsed() const const
bool isValid() const const
bool isAccepted() const const
const T * constData() const const
qreal horizontalAdvance(QChar ch) const const
Qt::KeyboardModifiers modifiers() const const
QString text() const const
void append(QList< T > &&value)
bool isEmpty() const const
const QPoint & oldPos() const const
const QPoint & pos() const const
bool blockSignals(bool block)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
virtual bool eventFilter(QObject *watched, QEvent *event)
void installEventFilter(QObject *filterObj)
void removeEventFilter(QObject *obj)
qreal devicePixelRatioF() const const
const QRect & rect() const const
const QRegion & region() const const
int manhattanLength() const const
virtual void setAccepted(bool accepted) override
QPoint toPoint() const const
bool isEmpty() const const
const QSize & oldSize() const const
QPointF globalPosition() const const
QPointF position() const const
const QChar at(qsizetype position) const const
QString & fill(QChar ch, qsizetype size)
bool isEmpty() const const
qsizetype length() const const
qsizetype size() const const
QChar at(qsizetype n) const const
qsizetype size() const const
SH_RequestSoftwareInputPanel
typedef KeyboardModifiers
bool isValid() const const
QTextCharFormat toCharFormat() const const
int nextCursorPosition(int oldPos, CursorMode mode) const const
int previousCursorPosition(int oldPos, CursorMode mode) const const
const QTextOption & textOption() const const
Qt::LayoutDirection textDirection() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isActive() const const
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
bool toBool() const const
iterator erase(const_iterator begin, const_iterator end)
bool isEmpty() const const
qsizetype size() const const
QPoint angleDelta() const const