8#include "katelayoutcache.h"
10#include "katedocument.h"
11#include "katepartdebug.h"
12#include "katerenderer.h"
17bool enableLayoutCache =
false;
19bool lessThan(
const KateLineLayoutMap::LineLayoutPair &lhs,
const KateLineLayoutMap::LineLayoutPair &rhs)
21 return lhs.first < rhs.first;
28void KateLineLayoutMap::clear()
30 m_lineLayouts.clear();
33void KateLineLayoutMap::insert(
int realLine, std::unique_ptr<KateLineLayout> lineLayoutPtr)
35 auto it = std::upper_bound(m_lineLayouts.begin(), m_lineLayouts.end(), LineLayoutPair(realLine,
nullptr), lessThan);
36 m_lineLayouts.insert(it, LineLayoutPair(realLine, std::move(lineLayoutPtr)));
39void KateLineLayoutMap::relayoutLines(
int startRealLine,
int endRealLine)
41 auto start = std::lower_bound(m_lineLayouts.begin(), m_lineLayouts.end(), LineLayoutPair(startRealLine,
nullptr), lessThan);
42 auto end = std::upper_bound(
start, m_lineLayouts.end(), LineLayoutPair(endRealLine,
nullptr), lessThan);
44 while (
start != end) {
45 (*start).second->layoutDirty =
true;
50void KateLineLayoutMap::slotEditDone(
int fromLine,
int toLine,
int shiftAmount, std::vector<KateTextLayout> &textLayouts)
52 auto start = std::lower_bound(m_lineLayouts.begin(), m_lineLayouts.end(), LineLayoutPair(fromLine,
nullptr), lessThan);
53 auto end = std::upper_bound(
start, m_lineLayouts.end(), LineLayoutPair(toLine,
nullptr), lessThan);
55 if (shiftAmount != 0) {
56 for (
auto it = end; it != m_lineLayouts.end(); ++it) {
57 (*it).first += shiftAmount;
58 (*it).second->setLine((*it).second->line() + shiftAmount);
61 for (
auto it =
start; it !=
end; ++it) {
62 (*it).second->clear();
63 for (
auto &tl : textLayouts) {
64 if (tl.kateLineLayout() == it->second.get()) {
66 tl = KateTextLayout::invalid();
71 m_lineLayouts.erase(
start, end);
73 for (
auto it =
start; it !=
end; ++it) {
74 (*it).second->layoutDirty =
true;
79KateLineLayout *KateLineLayoutMap::find(
int i)
81 const auto it = std::lower_bound(m_lineLayouts.begin(), m_lineLayouts.end(), LineLayoutPair(i,
nullptr), lessThan);
82 if (it != m_lineLayouts.end() && it->first == i) {
83 return it->second.get();
91 , m_renderer(renderer)
102void KateLayoutCache::updateViewCache(
const KTextEditor::Cursor startPos,
int newViewLineCount,
int viewLinesScrolled)
106 int oldViewLineCount = m_textLayouts.size();
107 if (newViewLineCount == -1) {
108 newViewLineCount = oldViewLineCount;
111 enableLayoutCache =
true;
114 if (newViewLineCount == -1) {
115 realLine = m_renderer->folding().visibleLineToLine(m_renderer->folding().lineToVisibleLine(startPos.
line()));
117 realLine = m_renderer->folding().visibleLineToLine(startPos.
line());
123 if (KateLineLayout *l =
line(realLine)) {
124 Q_ASSERT(l->isValid());
125 Q_ASSERT(l->length() >= startPos.
column() || m_renderer->view()->wrapCursor());
127 for (; _viewLine < l->viewLineCount(); ++_viewLine) {
128 const KateTextLayout &t = l->viewLine(_viewLine);
129 if (t.startCol() >= startPos.
column() || _viewLine == l->viewLineCount() - 1) {
138 m_startPos = startPos;
141 if (viewLinesScrolled != 0) {
143 bool forwards = viewLinesScrolled >= 0 ? true :
false;
144 for (
int z = forwards ? 0 : m_textLayouts.size() - 1; forwards ? ((
size_t)z < m_textLayouts.size()) : (z >= 0); forwards ? z++ : z--) {
145 int oldZ = z + viewLinesScrolled;
146 if (oldZ >= 0 && (
size_t)oldZ < m_textLayouts.size()) {
147 m_textLayouts[z] = m_textLayouts[oldZ];
153 if (newViewLineCount > oldViewLineCount) {
154 m_textLayouts.reserve(newViewLineCount);
155 }
else if (newViewLineCount < oldViewLineCount) {
156 m_textLayouts.resize(newViewLineCount);
159 KateLineLayout *l =
line(realLine);
160 for (
int i = 0; i < newViewLineCount; ++i) {
162 if ((
size_t)i < m_textLayouts.size()) {
163 if (m_textLayouts[i].
isValid()) {
164 m_textLayouts[i] = KateTextLayout::invalid();
167 m_textLayouts.push_back(KateTextLayout::invalid());
172 Q_ASSERT(l->isValid());
173 Q_ASSERT(_viewLine < l->viewLineCount());
175 if ((
size_t)i < m_textLayouts.size()) {
177 if (m_textLayouts[i].
line() != realLine || m_textLayouts[i].
viewLine() != _viewLine
178 || (!m_textLayouts[i].
isValid() && l->viewLine(_viewLine).isValid())) {
181 m_textLayouts[i] = l->viewLine(_viewLine);
183 m_textLayouts[i].setDirty(
true);
187 m_textLayouts.push_back(l->viewLine(_viewLine));
195 if (_viewLine > l->viewLineCount() - 1) {
196 int virtualLine = l->virtualLine() + 1;
197 realLine = m_renderer->folding().visibleLineToLine(virtualLine);
199 if (realLine < m_renderer->doc()->lines()) {
200 l =
line(realLine, virtualLine);
207 enableLayoutCache =
false;
212 if (
auto l = m_lineLayouts.find(realLine)) {
214 Q_ASSERT(l->line() == realLine);
215 Q_ASSERT(realLine < m_renderer->doc()->lines());
217 if (virtualLine != -1) {
218 l->setVirtualLine(virtualLine);
222 l->usePlainTextLine = acceptDirtyLayouts();
223 l->textLine(!acceptDirtyLayouts());
224 m_renderer->layoutLine(l, wrap() ? m_viewWidth : -1, enableLayoutCache);
225 }
else if (l->layoutDirty && !acceptDirtyLayouts()) {
227 l->usePlainTextLine =
false;
229 m_renderer->layoutLine(l, wrap() ? m_viewWidth : -1, enableLayoutCache);
232 Q_ASSERT(l->layout().
lineCount() > 0 && (!l->layoutDirty || acceptDirtyLayouts()));
237 if (realLine < 0 || realLine >= m_renderer->doc()->lines()) {
241 KateLineLayout *l =
new KateLineLayout(*m_renderer);
242 l->setLine(realLine, virtualLine);
246 if (acceptDirtyLayouts()) {
247 l->usePlainTextLine =
true;
250 m_renderer->layoutLine(l, wrap() ? m_viewWidth : -1, enableLayoutCache);
251 Q_ASSERT(l->isValid());
253 if (acceptDirtyLayouts()) {
254 l->layoutDirty =
true;
258 m_lineLayouts.insert(realLine, std::unique_ptr<KateLineLayout>(l));
269 auto l =
line(realLine);
270 if (l && l->isValid()) {
271 return l->viewLine(_viewLine);
273 return KateTextLayout::invalid();
278 Q_ASSERT(_viewLine >= 0 && (
size_t)_viewLine < m_textLayouts.size());
279 return m_textLayouts[_viewLine];
282int KateLayoutCache::viewCacheLineCount()
const
284 return m_textLayouts.size();
289 return !m_textLayouts.empty() ? m_textLayouts.front().
start() : KTextEditor::Cursor();
294 return !m_textLayouts.empty() ? m_textLayouts.back().end() : KTextEditor::Cursor();
297int KateLayoutCache::viewWidth()
const
312 if (realCursor.
column() < 0 || realCursor.
line() < 0 || realCursor.
line() > m_renderer->doc()->lines()) {
316 KateLineLayout *thisLine =
line(realCursor.
line());
321 for (
int i = 0; i < thisLine->viewLineCount(); ++i) {
328 return thisLine->viewLineCount() - 1;
333 if (!virtualCursor.
isValid()) {
341 work.
setLine(m_renderer->folding().lineToVisibleLine(work.
line()));
345 return virtualCursor.
line();
348 int limit = m_textLayouts.size();
351 if (!m_renderer->view()->dynWordWrap()) {
352 int ret = virtualCursor.
line() - work.
line();
353 if (limitToVisible && (ret < 0)) {
355 }
else if (limitToVisible && (ret > limit)) {
362 if (work == virtualCursor) {
366 int ret = -(int)
viewLine(viewCacheStart());
367 bool forwards = (work < virtualCursor);
371 while (work.
line() != virtualCursor.
line()) {
372 ret += viewLineCount(m_renderer->folding().visibleLineToLine(work.
line()));
374 if (limitToVisible && ret > limit) {
379 while (work.
line() != virtualCursor.
line()) {
381 ret -= viewLineCount(m_renderer->folding().visibleLineToLine(work.
line()));
382 if (limitToVisible && ret < 0) {
390 realCursor.
setLine(m_renderer->folding().visibleLineToLine(realCursor.
line()));
391 if (realCursor.
column() == -1) {
392 realCursor.
setColumn(m_renderer->doc()->lineLength(realCursor.
line()));
396 if (limitToVisible && (ret < 0 || ret > limit)) {
403int KateLayoutCache::lastViewLine(
int realLine)
405 if (!m_renderer->
view()->dynWordWrap()) {
409 if (KateLineLayout *l =
line(realLine)) {
410 return l->viewLineCount() - 1;
415int KateLayoutCache::viewLineCount(
int realLine)
417 return lastViewLine(realLine) + 1;
420void KateLayoutCache::viewCacheDebugOutput()
const
422 qCDebug(LOG_KTE) <<
"Printing values for " << m_textLayouts.size() <<
" lines:";
423 for (
const KateTextLayout &t : std::as_const(m_textLayouts)) {
427 qCDebug(LOG_KTE) <<
"Line Invalid.";
434 m_lineLayouts.slotEditDone(position.
line(), position.
line() + 1, 1, m_textLayouts);
439 m_lineLayouts.slotEditDone(
line - 1,
line, -1, m_textLayouts);
444 m_lineLayouts.slotEditDone(position.
line(), position.
line(), 0, m_textLayouts);
449 m_lineLayouts.slotEditDone(range.
start().
line(), range.
start().
line(), 0, m_textLayouts);
452void KateLayoutCache::clear()
454 m_textLayouts.clear();
455 m_lineLayouts.clear();
456 m_startPos = KTextEditor::Cursor(-1, -1);
459void KateLayoutCache::setViewWidth(
int width)
462 m_lineLayouts.clear();
463 m_textLayouts.clear();
464 m_startPos = KTextEditor::Cursor(-1, -1);
467bool KateLayoutCache::wrap()
const
472void KateLayoutCache::setWrap(
bool wrap)
478void KateLayoutCache::relayoutLines(
int startRealLine,
int endRealLine)
480 if (startRealLine > endRealLine) {
481 qCWarning(LOG_KTE) <<
"start" << startRealLine <<
"before end" << endRealLine;
484 m_lineLayouts.relayoutLines(startRealLine, endRealLine);
487bool KateLayoutCache::acceptDirtyLayouts()
const
489 return m_acceptDirtyLayouts;
492void KateLayoutCache::setAcceptDirtyLayouts(
bool accept)
494 m_acceptDirtyLayouts = accept;
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.
constexpr bool isValid() const noexcept
Returns whether the current position of this cursor is a valid position (line + column must both be >...
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.
A KParts derived class representing a text document.
void lineUnwrapped(KTextEditor::Document *document, int line)
A line got unwrapped.
void lineWrapped(KTextEditor::Document *document, KTextEditor::Cursor position)
A line got wrapped.
void textInserted(KTextEditor::Document *document, KTextEditor::Cursor position, const QString &text)
Text got inserted.
void textRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &text)
Text got removed.
An object representing a section of text, from one Cursor to another.
constexpr Cursor start() const noexcept
Get the start position of this range.
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)
KTextEditor::ViewPrivate * view() const
Returns the view to which this renderer is bound.
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.
Q_SCRIPTABLE Q_NOREPLY void start()
bool isValid(QStringView ifopt)
const QList< QKeySequence > & end()
int lineCount() const const