data/MarkdownTyping.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "MarkdownTyping.h" | ||
| 2 | |||
| 3 | #include <QRegularExpression> | ||
| 4 | |||
| 5 | namespace MarkdownTyping { | ||
| 6 | |||
| 7 | namespace { | ||
| 8 | |||
| 9 | // The word around `position` looks like a URL or a mail address. | ||
| 10 | 31 | bool insideLinkLikeWord(const QString &text, int position) { | |
| 11 | 31 | int start = position; | |
| 12 |
6/6✓ Branch 4 → 5 taken 131 times.
✓ Branch 4 → 9 taken 18 times.
✓ Branch 7 → 8 taken 118 times.
✓ Branch 7 → 9 taken 13 times.
✓ Branch 10 → 3 taken 118 times.
✓ Branch 10 → 11 taken 31 times.
|
149 | while (start > 0 && !text.at(start - 1).isSpace()) --start; |
| 13 | 31 | int end = position; | |
| 14 |
6/6✓ Branch 14 → 15 taken 119 times.
✓ Branch 14 → 19 taken 29 times.
✓ Branch 17 → 18 taken 117 times.
✓ Branch 17 → 19 taken 2 times.
✓ Branch 20 → 12 taken 117 times.
✓ Branch 20 → 21 taken 31 times.
|
148 | while (end < text.size() && !text.at(end).isSpace()) ++end; |
| 15 |
1/1✓ Branch 21 → 22 taken 31 times.
|
31 | const QString word = text.mid(start, end - start); |
| 16 |
5/6✓ Branch 23 → 24 taken 31 times.
✓ Branch 24 → 25 taken 30 times.
✓ Branch 24 → 36 taken 1 time.
✓ Branch 26 → 27 taken 30 times.
✓ Branch 27 → 28 taken 30 times.
✗ Branch 27 → 36 not taken.
|
61 | return word.contains(QLatin1String("://")) || word.startsWith(QLatin1String("www."), Qt::CaseInsensitive) || |
| 17 |
2/5✓ Branch 30 → 31 taken 30 times.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 37 taken 30 times.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
|
61 | (word.contains(QLatin1Char('@')) && word.indexOf(QLatin1Char('@')) > 0); |
| 18 | 31 | } | |
| 19 | |||
| 20 | 26 | Conversion blockStart(const QString &text, int caret, const Context &context) { | |
| 21 | 26 | Conversion none; | |
| 22 |
6/8✓ Branch 2 → 3 taken 25 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 3 → 4 taken 25 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 23 times.
✓ Branch 4 → 6 taken 2 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 23 times.
|
26 | if (context.inCodeBlock || context.inQuote || context.inList || context.inHeading) return none; |
| 23 |
1/1✓ Branch 7 → 8 taken 23 times.
|
23 | const QString prefix = text.left(caret); |
| 24 | 23 | Conversion result; | |
| 25 | 23 | result.prefixLength = caret; | |
| 26 |
6/6✓ Branch 10 → 11 taken 21 times.
✓ Branch 10 → 14 taken 2 times.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 20 times.
✓ Branch 16 → 17 taken 3 times.
✓ Branch 16 → 18 taken 20 times.
|
23 | if (prefix == QLatin1String("- ") || prefix == QLatin1String("* ")) { |
| 27 | 3 | result.kind = Kind::BulletList; | |
| 28 | 3 | return result; | |
| 29 | } | ||
| 30 |
4/7✓ Branch 18 → 19 taken 3 times.
✓ Branch 18 → 31 taken 17 times.
✓ Branch 20 → 21 taken 3 times.
✗ Branch 20 → 31 not taken.
✓ Branch 25 → 26 taken 3 times.
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 68 not taken.
|
23 | static const QRegularExpression numbered(QStringLiteral("^[0-9]{1,3}\\. $")); |
| 31 |
4/4✓ Branch 32 → 33 taken 20 times.
✓ Branch 33 → 34 taken 20 times.
✓ Branch 35 → 36 taken 2 times.
✓ Branch 35 → 37 taken 18 times.
|
20 | if (numbered.match(prefix).hasMatch()) { |
| 32 | 2 | result.kind = Kind::NumberedList; | |
| 33 | 2 | return result; | |
| 34 | } | ||
| 35 |
2/2✓ Branch 39 → 40 taken 1 time.
✓ Branch 39 → 41 taken 17 times.
|
18 | if (prefix == QLatin1String("> ")) { |
| 36 | 1 | result.kind = Kind::Quote; | |
| 37 | 1 | return result; | |
| 38 | } | ||
| 39 |
8/8✓ Branch 43 → 44 taken 16 times.
✓ Branch 43 → 50 taken 1 time.
✓ Branch 46 → 47 taken 15 times.
✓ Branch 46 → 50 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
✓ Branch 49 → 51 taken 14 times.
✓ Branch 52 → 53 taken 3 times.
✓ Branch 52 → 55 taken 14 times.
|
17 | if (prefix == QLatin1String("# ") || prefix == QLatin1String("## ") || prefix == QLatin1String("### ")) { |
| 40 | 3 | result.kind = Kind::Heading; | |
| 41 | 3 | result.headingLevel = int(prefix.size()) - 1; | |
| 42 | 3 | return result; | |
| 43 | } | ||
| 44 | 14 | return none; | |
| 45 | 23 | } | |
| 46 | |||
| 47 | 26 | Conversion inlineMarker(const QString &text, int caret, QChar typed, const Context &context) { | |
| 48 | 26 | Conversion none; | |
| 49 |
5/6✓ Branch 2 → 3 taken 26 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 25 times.
✓ Branch 3 → 5 taken 1 time.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 24 times.
|
26 | if (context.inCodeBlock || context.inInlineCode || context.inQuote) return none; |
| 50 |
5/6✓ Branch 6 → 7 taken 22 times.
✓ Branch 6 → 9 taken 2 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 22 times.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 13 taken 22 times.
|
24 | if (caret < 3 || caret > text.size()) return none; |
| 51 |
3/4✓ Branch 17 → 18 taken 15 times.
✗ Branch 17 → 26 not taken.
✓ Branch 22 → 23 taken 5 times.
✓ Branch 22 → 26 taken 10 times.
|
37 | const QString marker = (typed == QLatin1Char('*') && caret >= 2 && text.at(caret - 2) == QLatin1Char('*')) |
| 52 |
4/6✓ Branch 16 → 17 taken 15 times.
✓ Branch 16 → 26 taken 7 times.
✓ Branch 27 → 28 taken 5 times.
✓ Branch 27 → 29 taken 17 times.
✗ Branch 119 → 120 not taken.
✗ Branch 119 → 121 not taken.
|
44 | ? QStringLiteral("**") |
| 53 |
1/1✓ Branch 26 → 27 taken 17 times.
|
44 | : QString(typed); |
| 54 | 22 | const int length = int(marker.size()); | |
| 55 | 22 | const int closeStart = caret - length; | |
| 56 | // The opening marker: the nearest earlier occurrence on this line. | ||
| 57 |
1/1✓ Branch 30 → 31 taken 22 times.
|
22 | const int openStart = int(text.lastIndexOf(marker, closeStart - 1)); |
| 58 |
2/2✓ Branch 31 → 32 taken 3 times.
✓ Branch 31 → 33 taken 19 times.
|
22 | if (openStart < 0) return none; |
| 59 | 19 | const int contentStart = openStart + length; | |
| 60 | 19 | const int contentLength = closeStart - contentStart; | |
| 61 |
2/2✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 35 taken 18 times.
|
19 | if (contentLength <= 0) return none; |
| 62 |
1/1✓ Branch 35 → 36 taken 18 times.
|
18 | const QString content = text.mid(contentStart, contentLength); |
| 63 |
8/8✓ Branch 36 → 37 taken 18 times.
✓ Branch 38 → 39 taken 17 times.
✓ Branch 38 → 42 taken 1 time.
✓ Branch 39 → 40 taken 17 times.
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 43 taken 16 times.
✓ Branch 44 → 45 taken 2 times.
✓ Branch 44 → 46 taken 16 times.
|
18 | if (content.front().isSpace() || content.back().isSpace()) return none; |
| 64 |
7/8✓ Branch 46 → 47 taken 16 times.
✓ Branch 47 → 48 taken 15 times.
✓ Branch 47 → 50 taken 1 time.
✓ Branch 48 → 49 taken 15 times.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 15 times.
✓ Branch 52 → 53 taken 1 time.
✓ Branch 52 → 54 taken 15 times.
|
16 | if (insideLinkLikeWord(text, openStart) || insideLinkLikeWord(text, closeStart)) return none; |
| 65 |
2/2✓ Branch 54 → 55 taken 11 times.
✓ Branch 54 → 56 taken 4 times.
|
15 | const QChar before = openStart > 0 ? text.at(openStart - 1) : QChar(QLatin1Char(' ')); |
| 66 |
2/2✓ Branch 60 → 61 taken 2 times.
✓ Branch 60 → 66 taken 13 times.
|
15 | if (marker == QLatin1String("`")) { |
| 67 |
2/3✓ Branch 63 → 64 taken 2 times.
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 104 taken 2 times.
|
2 | if (content.contains(QLatin1Char('`'))) return none; |
| 68 |
2/2✓ Branch 68 → 69 taken 3 times.
✓ Branch 68 → 83 taken 10 times.
|
13 | } else if (marker == QLatin1String("**")) { |
| 69 |
3/6✓ Branch 70 → 71 taken 3 times.
✗ Branch 70 → 75 not taken.
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 76 taken 3 times.
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 79 taken 3 times.
|
3 | if (before.isLetterOrNumber() || before == QLatin1Char('*')) return none; |
| 70 |
2/3✓ Branch 80 → 81 taken 3 times.
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 104 taken 3 times.
|
3 | if (content.contains(QLatin1String("**"))) return none; |
| 71 | } else { | ||
| 72 | // Single * or _: both markers touch letters (D-7), the opening one does | ||
| 73 | // not follow a word character (2*3*4, snake_case, a*b*c stay). | ||
| 74 |
6/6✓ Branch 84 → 85 taken 5 times.
✓ Branch 84 → 87 taken 5 times.
✓ Branch 86 → 87 taken 1 time.
✓ Branch 86 → 88 taken 4 times.
✓ Branch 89 → 90 taken 6 times.
✓ Branch 89 → 91 taken 4 times.
|
10 | if (before.isLetterOrNumber() || before == typed) return none; |
| 75 |
7/8✓ Branch 91 → 92 taken 4 times.
✓ Branch 93 → 94 taken 3 times.
✓ Branch 93 → 97 taken 1 time.
✓ Branch 94 → 95 taken 3 times.
✗ Branch 96 → 97 not taken.
✓ Branch 96 → 98 taken 3 times.
✓ Branch 99 → 100 taken 1 time.
✓ Branch 99 → 101 taken 3 times.
|
4 | if (!content.front().isLetter() || !content.back().isLetter()) return none; |
| 76 |
2/3✓ Branch 101 → 102 taken 3 times.
✗ Branch 102 → 103 not taken.
✓ Branch 102 → 104 taken 3 times.
|
3 | if (content.contains(typed)) return none; |
| 77 | } | ||
| 78 | 8 | Conversion result; | |
| 79 |
2/2✓ Branch 106 → 107 taken 3 times.
✓ Branch 106 → 108 taken 5 times.
|
13 | result.kind = marker == QLatin1String("**") ? Kind::Bold |
| 80 |
2/2✓ Branch 110 → 111 taken 2 times.
✓ Branch 110 → 112 taken 3 times.
|
5 | : marker == QLatin1String("`") ? Kind::Code |
| 81 | : Kind::Italic; | ||
| 82 | 8 | result.openStart = openStart; | |
| 83 | 8 | result.markerLength = length; | |
| 84 | 8 | result.contentStart = contentStart; | |
| 85 | 8 | result.contentLength = contentLength; | |
| 86 | 8 | result.closeStart = closeStart; | |
| 87 | 8 | return result; | |
| 88 | 22 | } | |
| 89 | |||
| 90 | } // namespace | ||
| 91 | |||
| 92 | 163 | Conversion afterTyping(const QString &text, int caret, QChar typed, const Context &context) { | |
| 93 |
3/6✓ Branch 2 → 3 taken 163 times.
✗ Branch 2 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 163 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 163 times.
|
163 | if (caret <= 0 || caret > text.size()) return {}; |
| 94 |
2/2✓ Branch 12 → 13 taken 26 times.
✓ Branch 12 → 14 taken 137 times.
|
163 | if (typed == QLatin1Char(' ')) return blockStart(text, caret, context); |
| 95 |
8/8✓ Branch 17 → 18 taken 120 times.
✓ Branch 17 → 26 taken 17 times.
✓ Branch 21 → 22 taken 114 times.
✓ Branch 21 → 26 taken 6 times.
✓ Branch 25 → 26 taken 3 times.
✓ Branch 25 → 27 taken 111 times.
✓ Branch 28 → 29 taken 26 times.
✓ Branch 28 → 30 taken 111 times.
|
137 | if (typed == QLatin1Char('*') || typed == QLatin1Char('_') || typed == QLatin1Char('`')) |
| 96 | 26 | return inlineMarker(text, caret, typed, context); | |
| 97 | 111 | return {}; | |
| 98 | } | ||
| 99 | |||
| 100 | 5 | Conversion afterEnter(const QString &text, const Context &context) { | |
| 101 |
5/8✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 4 times.
|
5 | if (context.inCodeBlock || context.inQuote || context.inList || context.inHeading) return {}; |
| 102 |
2/2✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 2 times.
|
4 | if (text != QLatin1String("---")) return {}; |
| 103 | 2 | Conversion result; | |
| 104 | 2 | result.kind = Kind::Rule; | |
| 105 | 2 | result.prefixLength = 3; | |
| 106 | 2 | return result; | |
| 107 | } | ||
| 108 | |||
| 109 | } // namespace MarkdownTyping | ||
| 110 |