wxMaxima
Loading...
Searching...
No Matches
Data Structures | Typedefs | Enumerations | Functions | Variables
TextFormat.h File Reference

Character formatting (bold, italic, superscript, ...) of the text in a text cell (GH #492). More...

#include <cstdint>
#include <cstddef>
#include <vector>
#include <wx/string.h>
Include dependency graph for TextFormat.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TextFormat::Run
 A stretch of text whose characters all have the same format. More...
 

Typedefs

using TextFormat::Format = std::uint8_t
 The formatting of one character: a combination of the flags below.
 
using TextFormat::Formats = std::vector< Format >
 One Format per character, indexed like the text it belongs to; empty = plain.
 

Enumerations

enum  : Format {
  None = 0 , Bold = 1 , Italic = 2 , Underline = 4 ,
  Strikethrough = 8 , TextFormat::Superscript = 16 , TextFormat::Subscript = 32
}
 

Functions

constexpr std::size_t TextFormat::FontIndex (Format format)
 A number below FontVariants that tells the fonts the WidthAffecting flags ask for apart.
 
constexpr Format TextFormat::WithFlag (Format format, Format flag)
 The format that results from switching flag on in format.
 
bool TextFormat::IsPlain (const Formats &formats)
 Does this formatting vector describe plain text?
 
Format TextFormat::At (const Formats &formats, std::size_t pos)
 The format of character pos, None past the end (or for plain text).
 
Format TextFormat::FormatForInsertionAt (const wxString &text, const Formats &formats, std::size_t pos)
 The format a character typed at pos gets.
 
Formats TextFormat::Reconcile (const wxString &oldText, const Formats &oldFormats, const wxString &newText, bool hasPending=false, std::size_t pendingPos=0, Format pendingFormat=None)
 The formatting of newText, given that it came from oldText by editing.
 
std::vector< Run > TextFormat::Runs (const wxString &text, const Formats &formats, std::size_t start, std::size_t end)
 Splits [start, end) of text into runs of equally formatted characters.
 
wxString TextFormat::LineAttributes (const wxString &text, const Formats &formats, std::size_t lineStart, std::size_t lineEnd)
 The attributes that store the formatting of [lineStart, lineEnd) of text.
 
void TextFormat::ReadLine (const wxXmlNode *line, wxString &text, Formats &formats, wxString *unknownAttributes=nullptr)
 Append the text and formatting of a <line> element.
 
void TextFormat::ReadHTML (const wxString &html, wxString &text, Formats &formats)
 The text and formatting of an HTML fragment other programs put on the clipboard.
 
std::vector< std::pair< std::size_t, std::size_t > > TextFormat::ParseRanges (const wxString &ranges)
 Parse a range list like "0-4,10-12" (half-open, in code points).
 
std::size_t TextFormat::CodePointsBefore (const wxString &text, std::size_t start, std::size_t index)
 How many Unicode code points text[0, index) holds - which differs from index where wxString stores UTF-16 (MS Windows) and the text contains a character outside the Basic Multilingual Plane.
 
std::size_t TextFormat::IndexOfCodePoint (const wxString &text, std::size_t start, std::size_t codePoints)
 The wxString index of the codePoints'th code point after start.
 

Variables

constexpr Format TextFormat::WidthAffecting = Bold | Italic | Superscript | Subscript
 The flags that change a character's width, and therefore the font it is measured and drawn with. Underline and strikethrough are lines drawn on top.
 
constexpr std::size_t TextFormat::FontVariants = 16
 How many different fonts the WidthAffecting flags can ask for.
 
constexpr Format TextFormat::VerticalPosition = Superscript | Subscript
 The flags that move a character up or down. A character is never both.
 

Detailed Description

Character formatting (bold, italic, superscript, ...) of the text in a text cell (GH #492).

Everything here is a pure function of strings and vectors, needing neither a cell nor a GUI, so that it can be tested on its own.

The model: one Format per character of the cell's text, stored in a vector indexed exactly like the wxString it describes. An empty vector means "no formatting at all", which is what every cell that never had any carries, so plain cells pay nothing.

How it is saved: .wxmx stores a text cell as one <line> element per line. Formatting goes into attributes of those elements, one per format, each a list of half-open ranges counted in Unicode code points from the start of the line:

<line bold="0-4,10-12" italic="6-9">Bold, italic and bold</line>

This is not a pretty format, but it is the one older wxMaxima versions can read: they take the element's text and never look at its attributes, so they show the text unformatted instead of losing any of it. Inline tags (<b>, <i>, ...) would have been nicer, but an older version reading <line>a <b>b</b> c</line> keeps only the "a ".

ReadLine() nevertheless understands such inline tags too, so a future version can switch to them: <b>/<strong>, <i>/<em>, <u>, <s>/<strike>/<del>, <sup> and <sub> set the matching format, and any other tag is read as if it weren't there - its text is kept, only the formatting it stands for is lost.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum : Format
Enumerator
Superscript 

Smaller, and raised above the baseline.

Subscript 

Smaller, and lowered below the baseline.

Function Documentation

◆ FormatForInsertionAt()

Format TextFormat::FormatForInsertionAt ( const wxString &  text,
const Formats &  formats,
std::size_t  pos 
)

The format a character typed at pos gets.

The one of the character before it, as in any word processor (typing at the end of a bold word continues it in bold) - unless there is none on the same line, in which case the character after it decides.

◆ LineAttributes()

wxString TextFormat::LineAttributes ( const wxString &  text,
const Formats &  formats,
std::size_t  lineStart,
std::size_t  lineEnd 
)

The attributes that store the formatting of [lineStart, lineEnd) of text.

Returns
a string like bold="0-4" italic="2-3" (with a leading space), or an empty one if that line is plain.

◆ ParseRanges()

std::vector< std::pair< std::size_t, std::size_t > > TextFormat::ParseRanges ( const wxString &  ranges)

Parse a range list like "0-4,10-12" (half-open, in code points).

Malformed entries are skipped. Exposed for the tests.

◆ ReadHTML()

void TextFormat::ReadHTML ( const wxString &  html,
wxString &  text,
Formats &  formats 
)

The text and formatting of an HTML fragment other programs put on the clipboard.

Lenient, as clipboard HTML is rarely well-formed XML: unclosed <br>, <meta> or <p>, entities like &nbsp;, a Windows CF_HTML header. Reads what is inside <body>, or else between the <!--StartFragment–> and <!--EndFragment–> markers, if there are any. Understands the elements FlagForTag() knows and the CSS a <span> or any other element carries in its style attribute (font-weight, font-style, text-decoration, vertical-align), which is how Google Docs and Word mark their formatting - including switching a format off again, as Google Docs wraps a whole copy in <b style="font-weight:normal">. Whitespace collapses as a browser collapses it; <br> and the end of a paragraph, heading, list item, table row or <div> make a line break; <script>, <style> and <head> are skipped.

Parameters
formatsReceives one format per character of text.

◆ ReadLine()

void TextFormat::ReadLine ( const wxXmlNode *  line,
wxString &  text,
Formats &  formats,
wxString *  unknownAttributes = nullptr 
)

Append the text and formatting of a <line> element.

Parameters
lineThe <line> element.
textThe line's text is appended to it.
formatsReceives one format per appended character. Resized to match text first, so it may be passed empty.
unknownAttributesIf not null, receives every attribute of line this version doesn't understand, serialized as name="value", so a newer version's formatting survives being opened and saved by this one.

◆ Reconcile()

Formats TextFormat::Reconcile ( const wxString &  oldText,
const Formats &  oldFormats,
const wxString &  newText,
bool  hasPending = false,
std::size_t  pendingPos = 0,
Format  pendingFormat = None 
)

The formatting of newText, given that it came from oldText by editing.

Finds which characters of newText already existed in oldText and lets them keep their format; characters that are new take the format of the character(s) they replaced, or else of the one before them (as in any word processor, typing at the end of a bold word continues it in bold).

One contiguous edit - typing, deleting, pasting, replacing a selection - is mapped exactly via the common prefix and suffix. Several separate edits at once (a "replace all", indenting several lines) are mapped by a longest-common-subsequence diff of the part that changed, which is bounded in size; past that bound the changed part keeps its formats by position.

Parameters
pendingPos,pendingFormatIf hasPending and the edit was a pure insertion at pendingPos, the inserted characters get pendingFormat: that is what pressing "bold" with nothing selected and then typing does.
Returns
the new formatting, empty if it is plain.

◆ Runs()

std::vector< Run > TextFormat::Runs ( const wxString &  text,
const Formats &  formats,
std::size_t  start,
std::size_t  end 
)

Splits [start, end) of text into runs of equally formatted characters.

For the formats of other programs (RTF, HTML), which switch formatting on and off around runs of text rather than storing one format per character. A hard line break ('
') is always a run of its own and never formatted, so a run never spans two paragraphs: RTF and HTML both end a paragraph in a way that doesn't nest in a formatting group.

◆ WithFlag()

constexpr Format TextFormat::WithFlag ( Format  format,
Format  flag 
)
constexpr

The format that results from switching flag on in format.

Superscript and subscript exclude each other: switching one on switches the other off.