data/MarkdownTyping.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QChar> | ||
| 4 | #include <QString> | ||
| 5 | |||
| 6 | // Sprint 108 S108.3.2 (D-7): Markdown-style typing in formatted mails as | ||
| 7 | // pure rules. The editor (RichTextController) asks after every typed | ||
| 8 | // character whether the text before the caret now forms one of these | ||
| 9 | // patterns and applies the answer as one undo step, so Ctrl+Z right after | ||
| 10 | // a conversion brings the typed characters back. | ||
| 11 | // | ||
| 12 | // - at the start of a paragraph, after the space: "- " / "* " bullets, | ||
| 13 | // "1. " numbers, "> " quote, "# " "## " "### " headings; | ||
| 14 | // - "---" alone in a paragraph, on Enter: a horizontal rule; | ||
| 15 | // - inline, on the closing marker: **bold**, *italic*, _italic_, `code`. | ||
| 16 | // A single * or _ converts only when both markers touch letters and the | ||
| 17 | // opening one does not follow a letter or digit (2*3*4, snake_case and | ||
| 18 | // a*b stay as typed). | ||
| 19 | // Nothing converts inside code, URLs, mail addresses or quotes, or while an | ||
| 20 | // input method is composing (the caller passes that context). | ||
| 21 | namespace MarkdownTyping { | ||
| 22 | |||
| 23 | enum class Kind { None, BulletList, NumberedList, Quote, Heading, Rule, Bold, Italic, Code }; | ||
| 24 | |||
| 25 | struct Context { | ||
| 26 | bool inCodeBlock = false; | ||
| 27 | bool inInlineCode = false; | ||
| 28 | bool inQuote = false; | ||
| 29 | bool inList = false; | ||
| 30 | bool inHeading = false; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct Conversion { | ||
| 34 | Kind kind = Kind::None; | ||
| 35 | int headingLevel = 0; | ||
| 36 | // Block-start kinds: the prefix [0, prefixLength) is removed. | ||
| 37 | int prefixLength = 0; | ||
| 38 | // Inline kinds, in block offsets of the text as it is now: the opening | ||
| 39 | // marker, the content and the closing marker (removed after formatting). | ||
| 40 | int openStart = 0; | ||
| 41 | int markerLength = 0; | ||
| 42 | int contentStart = 0; | ||
| 43 | int contentLength = 0; | ||
| 44 | int closeStart = 0; | ||
| 45 | 142 | bool isNone() const { return kind == Kind::None; } | |
| 46 | }; | ||
| 47 | |||
| 48 | // `text` is the paragraph's text after the keystroke, `caret` the caret's | ||
| 49 | // offset in it (just after the typed character), `typed` that character. | ||
| 50 | Conversion afterTyping(const QString &text, int caret, QChar typed, const Context &context = {}); | ||
| 51 | // Enter pressed at the end of a paragraph whose text is `text`. | ||
| 52 | Conversion afterEnter(const QString &text, const Context &context = {}); | ||
| 53 | |||
| 54 | } // namespace MarkdownTyping | ||
| 55 |