Md4qt

poscache.h
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2022-2024 Igor Mironchik <igor.mironchik@gmail.com>
3 SPDX-License-Identifier: MIT
4*/
5
6#ifndef MD4QT_MD_POSCACHE_HPP_INCLUDED
7#define MD4QT_MD_POSCACHE_HPP_INCLUDED
8
9#include "visitor.h"
10
11// C++ include.
12#include <algorithm>
13#include <cassert>
14#include <vector>
15
16namespace MD
17{
18
19namespace details
20{
21
22//
23// PosRange
24//
25
26//! Cached position of Item.
27template<class Trait>
28struct PosRange {
29 //! Start column
30 long long int m_startColumn = -1;
31 //! Start line.
32 long long int m_startLine = -1;
33 //! End column.
34 long long int m_endColumn = -1;
35 //! End line.
36 long long int m_endLine = -1;
37 //! Pointer to this item.
38 Item<Trait> *m_item = nullptr;
39 //! List of children.
40 std::vector<PosRange<Trait>> m_children = {};
41
42 //! \return Is position valid.
43 inline bool isValidPos() const
44 {
45 return m_startColumn > -1 && m_startLine > -1 && m_endColumn > -1 && m_endLine > -1;
46 }
47};
48
49// Look at this equality operator like on rectangles intersection.
50// If rectangles in text intersect then rectangles are equal.
51template<class Trait>
53{
54 return (l.m_startLine <= r.m_endLine && l.m_endLine >= r.m_startLine &&
55 (l.m_startLine == r.m_endLine && l.m_endLine == r.m_startLine ?
56 l.m_endColumn >= r.m_startColumn && l.m_startColumn <= r.m_endColumn : true));
57}
58
59template<class Trait>
61{
62 return (l.m_endLine < r.m_startLine ||
64}
65
66} /* namespace details */
67
68//
69// PosCache
70//
71
72//! Cache of Markdown items to be accessed via position.
73template<class Trait>
74class PosCache : public MD::Visitor<Trait>
75{
76public:
77 PosCache() = default;
78 ~PosCache() override = default;
79
80 //! Initialize m_cache with the give document.
81 //! \note Document should not be recursive.
82 virtual void initialize(std::shared_ptr<MD::Document<Trait>> doc)
83 {
84 m_cache.clear();
85
86 if (doc) {
88
89 for (auto it = doc->footnotesMap().cbegin(), last = doc->footnotesMap().cend(); it != last; ++it) {
90 onFootnote(it->second.get());
91 }
92
93 for (auto it = doc->labeledLinks().cbegin(), last = doc->labeledLinks().cend(); it != last; ++it) {
94 onReferenceLink(it->second.get());
95 }
96 }
97 }
98
99 //! Vector with items, where front is a top-level item,
100 //! and back is most nested child.
101 using Items = typename Trait::template Vector<Item<Trait> *>;
102
103 //! \return First occurense of Markdown item with all first children by the give position.
105 {
106 Items res;
107
109 pos.endColumn(), pos.endLine()};
110
111 findFirstInCache(m_cache, tmp, res);
112
113 return res;
114 }
115
116protected:
117 //! Find in cache an item with the given position.
119 //! Cache of position.
120 std::vector<details::PosRange<Trait>> &vec,
121 //! Position of sought-for item.
122 const details::PosRange<Trait> &pos) const
123 {
124 const auto it = std::lower_bound(vec.begin(), vec.end(), pos);
125
126 if (it != vec.end() && *it == pos) {
127 if (!it->m_children.empty()) {
128 auto nested = findInCache(it->m_children, pos);
129
130 return (nested ? nested : &(*it));
131 } else {
132 return &(*it);
133 }
134 } else {
135 return nullptr;
136 }
137 }
138
139 //! Find in cache items with the given position with all parents.
141 //! Cache.
142 const std::vector<details::PosRange<Trait>> &vec,
143 //! Position of sought-for item.
144 const details::PosRange<Trait> &pos,
145 //! Reference to result of search.
146 Items &res) const
147 {
148 const auto it = std::lower_bound(vec.begin(), vec.end(), pos);
149
150 if (it != vec.end() && *it == pos) {
151 res.push_back(it->m_item);
152
153 if (!it->m_children.empty()) {
154 findFirstInCache(it->m_children, pos, res);
155 }
156 }
157 }
158
159 //! Insert in cache.
161 //! Position for insertion.
162 const details::PosRange<Trait> &item,
163 //! Should we sord when insert top-level item, or we can be sure that this item is last?
164 bool sort = false)
165 {
166 if (!m_skipInCache) {
167 assert(item.isValidPos());
168
169 auto pos = findInCache(m_cache, item);
170
171 if (pos) {
172 pos->m_children.push_back(item);
173 } else {
174 if (sort) {
175 const auto it = std::upper_bound(m_cache.begin(), m_cache.end(), item);
176
177 if (it != m_cache.end()) {
178 m_cache.insert(it, item);
179 } else {
180 m_cache.push_back(item);
181 }
182 } else {
183 m_cache.push_back(item);
184 }
185 }
186 }
187 }
188
189protected:
190 //! Cache user defined item.
191 void onUserDefined(Item<Trait> *i) override
192 {
194
195 insertInCache(r);
196 }
197
198 //! Cache shortcut link.
199 virtual void onReferenceLink(
200 //! Link.
201 Link<Trait> *l)
202 {
204
205 insertInCache(r, true);
206 }
207
208 void onAddLineEnding() override
209 {
210 }
211
212 //! Cache text item.
213 void onText(Text<Trait> *t) override
214 {
215 details::PosRange<Trait> r{t->openStyles().empty() ? t->startColumn() : t->openStyles().front().startColumn(),
216 t->startLine(),
217 t->closeStyles().empty() ? t->endColumn() : t->closeStyles().back().endColumn(),
218 t->endLine(),
219 t};
220
221 insertInCache(r);
222 }
223
224 //! Cache LaTeX math expression.
225 void onMath(Math<Trait> *m) override
226 {
227 auto startColumn = m->startDelim().startColumn();
228 auto startLine = m->startDelim().startLine();
229 auto endColumn = m->endDelim().endColumn();
230 auto endLine = m->endDelim().endLine();
231
232 if (!m->openStyles().empty()) {
233 startColumn = m->openStyles().front().startColumn();
234 startLine = m->openStyles().front().startLine();
235 }
236
237 if (!m->closeStyles().empty()) {
238 endColumn = m->closeStyles().back().endColumn();
239 endLine = m->closeStyles().back().endLine();
240 }
241
242 details::PosRange<Trait> r{startColumn, startLine, endColumn, endLine, m};
243
244 insertInCache(r);
245 }
246
248 {
249 }
250
251 //! Cache paragraph.
252 void onParagraph(Paragraph<Trait> *p, bool wrap) override
253 {
255
256 insertInCache(r);
257
259 }
260
261 //! Cache heading.
262 void onHeading(Heading<Trait> *h) override
263 {
265
266 insertInCache(r);
267
268 if (h->text() && !h->text()->isEmpty()) {
269 onParagraph(h->text().get(), false);
270 }
271 }
272
273 //! Cache code.
274 void onCode(Code<Trait> *c) override
275 {
276 auto startColumn = c->isFensedCode() ? c->startDelim().startColumn() : c->startColumn();
277 auto startLine = c->isFensedCode() ? c->startDelim().startLine() : c->startLine();
278 auto endColumn = c->isFensedCode() && c->endDelim().endColumn() > -1 ? c->endDelim().endColumn() : c->endColumn();
279 auto endLine = c->isFensedCode() && c->endDelim().endLine() > -1 ? c->endDelim().endLine() : c->endLine();
280
281 details::PosRange<Trait> r{startColumn, startLine, endColumn, endLine, c};
282
283 insertInCache(r);
284 }
285
286 //! Cache inline code.
287 void onInlineCode(Code<Trait> *c) override
288 {
289 auto startColumn = c->startDelim().startColumn();
290 auto startLine = c->startDelim().startLine();
291 auto endColumn = c->endDelim().endColumn();
292 auto endLine = c->endDelim().endLine();
293
294 if (!c->openStyles().empty()) {
295 startColumn = c->openStyles().front().startColumn();
296 startLine = c->openStyles().front().startLine();
297 }
298
299 if (!c->closeStyles().empty()) {
300 endColumn = c->closeStyles().back().endColumn();
301 endLine = c->closeStyles().back().endLine();
302 }
303
304 details::PosRange<Trait> r{startColumn, startLine, endColumn, endLine, c};
305
306 insertInCache(r);
307 }
308
309 //! Cache blockquote.
311 {
313
314 insertInCache(r);
315
317 }
318
319 //! Cache list.
320 void onList(List<Trait> *l) override
321 {
322 bool first = true;
323
325
326 insertInCache(r);
327
328 for (auto it = l->items().cbegin(), last = l->items().cend(); it != last; ++it) {
329 if ((*it)->type() == ItemType::ListItem) {
330 onListItem(static_cast<ListItem<Trait> *>(it->get()), first);
331
332 first = false;
333 }
334 }
335 }
336
337 //! Cache table.
338 void onTable(Table<Trait> *t) override
339 {
341
342 insertInCache(r);
343
344 if (!t->isEmpty()) {
345 int columns = 0;
346
347 for (auto th = (*t->rows().cbegin())->cells().cbegin(), last = (*t->rows().cbegin())->cells().cend(); th != last; ++th) {
349
350 ++columns;
351 }
352
353 for (auto r = std::next(t->rows().cbegin()), rlast = t->rows().cend(); r != rlast; ++r) {
354 int i = 0;
355
356 for (auto c = (*r)->cells().cbegin(), clast = (*r)->cells().cend(); c != clast; ++c) {
358
359 ++i;
360
361 if (i == columns) {
362 break;
363 }
364 }
365 }
366 }
367 }
368
369 void onAnchor(Anchor<Trait> *) override
370 {
371 }
372
373 //! Cache raw HTML.
374 void onRawHtml(RawHtml<Trait> *h) override
375 {
377
378 insertInCache(r);
379 }
380
381 //! Cache horizontal line.
383 {
385
386 insertInCache(r);
387 }
388
389 //! Cache link.
390 void onLink(Link<Trait> *l) override
391 {
392 auto startColumn = l->startColumn();
393 auto startLine = l->startLine();
394 auto endColumn = l->endColumn();
395 auto endLine = l->endLine();
396
397 if (!l->openStyles().empty()) {
398 startColumn = l->openStyles().front().startColumn();
399 startLine = l->openStyles().front().startLine();
400 }
401
402 if (!l->closeStyles().empty()) {
403 endColumn = l->closeStyles().back().endColumn();
404 endLine = l->closeStyles().back().endLine();
405 }
406
407 details::PosRange<Trait> r{startColumn, startLine, endColumn, endLine, l};
408
409 insertInCache(r);
410
411 if (l->p()) {
412 m_skipInCache = true;
413 onParagraph(l->p().get(), true);
414 m_skipInCache = false;
415 }
416 }
417
418 //! Cache image.
419 void onImage(Image<Trait> *i) override
420 {
421 auto startColumn = i->startColumn();
422 auto startLine = i->startLine();
423 auto endColumn = i->endColumn();
424 auto endLine = i->endLine();
425
426 if (!i->openStyles().empty()) {
427 startColumn = i->openStyles().front().startColumn();
428 startLine = i->openStyles().front().startLine();
429 }
430
431 if (!i->closeStyles().empty()) {
432 endColumn = i->closeStyles().back().endColumn();
433 endLine = i->closeStyles().back().endLine();
434 }
435
436 details::PosRange<Trait> r{startColumn, startLine, endColumn, endLine, i};
437
438 insertInCache(r);
439
440 if (i->p()) {
441 m_skipInCache = true;
442 onParagraph(i->p().get(), true);
443 m_skipInCache = false;
444 }
445 }
446
447 //! Cache footnote reference.
449 {
450 auto startColumn = ref->startColumn();
451 auto startLine = ref->startLine();
452 auto endColumn = ref->endColumn();
453 auto endLine = ref->endLine();
454
455 if (!ref->openStyles().empty()) {
456 startColumn = ref->openStyles().front().startColumn();
457 startLine = ref->openStyles().front().startLine();
458 }
459
460 if (!ref->closeStyles().empty()) {
461 endColumn = ref->closeStyles().back().endColumn();
462 endLine = ref->closeStyles().back().endLine();
463 }
464
465 details::PosRange<Trait> r{startColumn, startLine, endColumn, endLine, ref};
466
467 insertInCache(r);
468 }
469
470 //! Cache footnote.
471 void onFootnote(Footnote<Trait> *f) override
472 {
474
475 insertInCache(r, true);
476
478 }
479
480 //! Cache list item.
481 void onListItem(ListItem<Trait> *l, bool first) override
482 {
484
485 insertInCache(r);
486
488 }
489
490protected:
491 //! Cache.
492 std::vector<details::PosRange<Trait>> m_cache;
493 //! Skip adding in cache.
494 bool m_skipInCache = false;
495}; // class PosCache
496
497} /* namespace MD */
498
499#endif // MD4QT_MD_POSCACHE_HPP_INCLUDED
Just an anchor.
Definition doc.h:397
const Items & items() const
Definition doc.h:629
Blockquote.
Definition doc.h:836
Code.
Definition doc.h:1269
const WithPosition & startDelim() const
Definition doc.h:1362
const WithPosition & endDelim() const
Definition doc.h:1374
bool isFensedCode() const
Definition doc.h:1386
Document.
Definition doc.h:1774
Footnote reference.
Definition doc.h:1666
Footnote.
Definition doc.h:1727
Heading.
Definition doc.h:710
ParagraphSharedPointer text() const
Definition doc.h:749
Horizontal line.
Definition doc.h:364
Image.
Definition doc.h:1183
const Styles & closeStyles() const
Definition doc.h:305
const Styles & openStyles() const
Definition doc.h:293
Base class for item in Markdown document.
Definition doc.h:177
Line break.
Definition doc.h:570
ParagraphSharedPointer p() const
Definition doc.h:1126
List item in a list.
Definition doc.h:886
List.
Definition doc.h:1039
LaTeX math expression.
Definition doc.h:1423
Paragraph.
Definition doc.h:679
Cache of Markdown items to be accessed via position.
Definition poscache.h:75
~PosCache() override=default
void onParagraph(Paragraph< Trait > *p, bool wrap) override
Cache paragraph.
Definition poscache.h:252
void onTable(Table< Trait > *t) override
Cache table.
Definition poscache.h:338
void onBlockquote(Blockquote< Trait > *b) override
Cache blockquote.
Definition poscache.h:310
void onAnchor(Anchor< Trait > *) override
Handle anchor.
Definition poscache.h:369
virtual void onReferenceLink(Link< Trait > *l)
Cache shortcut link.
Definition poscache.h:199
void onCode(Code< Trait > *c) override
Cache code.
Definition poscache.h:274
void onImage(Image< Trait > *i) override
Cache image.
Definition poscache.h:419
void onHorizontalLine(HorizontalLine< Trait > *l) override
Cache horizontal line.
Definition poscache.h:382
std::vector< details::PosRange< Trait > > m_cache
Cache.
Definition poscache.h:492
void findFirstInCache(const std::vector< details::PosRange< Trait > > &vec, const details::PosRange< Trait > &pos, Items &res) const
Find in cache items with the given position with all parents.
Definition poscache.h:140
void onAddLineEnding() override
For some generator it's important to keep line endings like they were in Markdown.
Definition poscache.h:208
PosCache()=default
void onLink(Link< Trait > *l) override
Cache link.
Definition poscache.h:390
void insertInCache(const details::PosRange< Trait > &item, bool sort=false)
Insert in cache.
Definition poscache.h:160
void onList(List< Trait > *l) override
Cache list.
Definition poscache.h:320
void onHeading(Heading< Trait > *h) override
Cache heading.
Definition poscache.h:262
void onUserDefined(Item< Trait > *i) override
Cache user defined item.
Definition poscache.h:191
void onFootnote(Footnote< Trait > *f) override
Cache footnote.
Definition poscache.h:471
void onMath(Math< Trait > *m) override
Cache LaTeX math expression.
Definition poscache.h:225
void onFootnoteRef(FootnoteRef< Trait > *ref) override
Cache footnote reference.
Definition poscache.h:448
details::PosRange< Trait > * findInCache(std::vector< details::PosRange< Trait > > &vec, const details::PosRange< Trait > &pos) const
Find in cache an item with the given position.
Definition poscache.h:118
void onRawHtml(RawHtml< Trait > *h) override
Cache raw HTML.
Definition poscache.h:374
void onLineBreak(LineBreak< Trait > *) override
Handle line break.
Definition poscache.h:247
typename Trait::template Vector< Item< Trait > * > Items
Vector with items, where front is a top-level item, and back is most nested child.
Definition poscache.h:101
Items findFirstInCache(const MD::WithPosition &pos) const
Definition poscache.h:104
bool m_skipInCache
Skip adding in cache.
Definition poscache.h:494
void onInlineCode(Code< Trait > *c) override
Cache inline code.
Definition poscache.h:287
void onListItem(ListItem< Trait > *l, bool first) override
Cache list item.
Definition poscache.h:481
virtual void initialize(std::shared_ptr< MD::Document< Trait > > doc)
Initialize m_cache with the give document.
Definition poscache.h:82
void onText(Text< Trait > *t) override
Cache text item.
Definition poscache.h:213
Raw HTML.
Definition doc.h:440
Table.
Definition doc.h:1564
bool isEmpty() const
Definition doc.h:1645
const Rows & rows() const
Definition doc.h:1598
Text item in Paragraph.
Definition doc.h:513
Visitor interface to walk through Document.
Definition visitor.h:27
virtual void onFootnote(Footnote< Trait > *f)
Handle footnote.
Definition visitor.h:389
virtual void onListItem(ListItem< Trait > *i, bool first)
Handle list item.
Definition visitor.h:292
virtual void onBlockquote(Blockquote< Trait > *b)
Handle blockquote.
Definition visitor.h:203
virtual void onTableCell(TableCell< Trait > *c)
Handle table cell.
Definition visitor.h:345
virtual void onParagraph(Paragraph< Trait > *p, bool wrap)
Handle paragraph.
Definition visitor.h:126
void process(std::shared_ptr< Document< Trait > > d)
Walk through the document.
Definition visitor.h:33
Base for any thing with start and end position.
Definition doc.h:76
long long int startColumn() const
Definition doc.h:101
long long int startLine() const
Definition doc.h:107
long long int endColumn() const
Definition doc.h:113
long long int endLine() const
Definition doc.h:119
bool operator<(const PosRange< Trait > &l, const PosRange< Trait > &r)
Definition poscache.h:60
bool operator==(const PosRange< Trait > &l, const PosRange< Trait > &r)
Definition poscache.h:52
Definition algo.h:17
@ ListItem
List item.
Cached position of Item.
Definition poscache.h:28
long long int m_startLine
Start line.
Definition poscache.h:32
Item< Trait > * m_item
Pointer to this item.
Definition poscache.h:38
long long int m_endLine
End line.
Definition poscache.h:36
long long int m_startColumn
Start column.
Definition poscache.h:30
bool isValidPos() const
Definition poscache.h:43
std::vector< PosRange< Trait > > m_children
List of children.
Definition poscache.h:40
long long int m_endColumn
End column.
Definition poscache.h:34
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Nov 6 2024 12:12:28 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.