# LispKit Styled-Text

Library `(lispkit styled-text)` provides an API to define and manipulate styled text. Styled text is a string with individual character ranges being layed out using a range of stylistic attributes. The library defines the layout of text in terms of objects encapsulating these stylistic attributes. There are three different style parameter collections: text styles, text block styles, and paragraph styles. Besides textual content, styled text objects may also contain tables (on macOS) and images.

Library `(lispkit styled-text)` also supports loading styled text from RTF, RTFD, and various Word formats (doc, docx). It can also save styled text in these formats.

## Styled text

A styled text object is mutable and consists of a string and a set of character ranges associated with stylistic attributes determining how the range of characters is layed out. Both the string and the attributed character ranges can be mutated. The following stylistic attributes are supported:

- `background-color`: Color object defining the background color of the text range.
- `foreground-color`: Color object defining the text color of the text range.
- `strikethrough-color`: Color object defining the strike-through color of the text range.
- `stroke-color`: Color object defining the outline color of the text range, i.e. the stroke color used for text displayed in outlined style.
- `underline-color`: Color object defining the underline color of the text range for text using underlined style.
- `baseline-offset`: The vertical offset for the position of the text in points.
- `expansion`: The expansion factor of the text, i.e. a flonum corresponding to the log of the expansion factor to be applied to the glyphs. 0 is the default, indicating no expansion.
- `kern`: The kerning of the text, i.e. the number of points by which to adjust kern-pair characters. This can be used to reduce/create space between characters. Kerning gets disabled by setting this attribute to 0.
- `obliqueness`: The obliqueness of the text expressed as a flonum indicating skew to be applied to the glyphs. 0 is the default, indicating no skew.
- `stroke-width`: The width of the stroke, i.e. the amount to change the stroke width for outlined text and is specified as a percentage of the font point size. 0 represents the default outline stroke width, negative values make the stroke extend inward, positive values extend it outward.
- `ligature`: A boolean value indicating whether ligatures should be used in the text range.
- `font`: Font object defining the font used in the text range.
- `link`: A string representing the link used for the text range. This is, in most cases, a URL, but could also be a file path.
- `paragraph-style`: Paragraph style object defining all parameters for laying out paragraphs in the text range.
- `shadow`: The shadow of the text range. This is defined by a pair whose car is a size object and cdr is a positive flonum representing the shadow blur radius. The size object represents vertical and horizontal offsets of the shadow. Example: `((2.0 . -3.0) . 6.5)`.
- `superscript`: The superscript of the text expressed as an offset in points.

Library `(lispkit styled-text)` provides functionality to create styled text objects, to compose them, to style them, and to introspect existing stylistic attributes.

styled-text-type-tag [object]

Symbol representing the `styled-text` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all styled text objects.

(styled-text? obj) [procedure]

Returns `#t` if obj is a styled text object, otherwise `#f` is returned.

(styled-text str) [procedure]
(styled-text str style)
(styled-text str font)
(styled-text str font color)
(styled-text str font color pstyle)

Creates and returns a styled text object representing string str using the stylistic attributes provided by text style object style, if provided. Alternatively, the given font, color, and paragraph style pstyle objects are used to define the style of str.

(make-styled-text str key val …) [procedure]
(make-styled-text image)

Creates and returns a styled text object representing string str layed out by the given stylistic attributes provided as key/value pairs. The attributes are applicable to the whole string. The following attribute key symbols are supported:

- `background-color:` Background color
- `foreground-color:` Text color
- `strikethrough-color:` Strike-through color
- `stroke-color:` Outline color
- `underline-color:` Underline color
- `baseline-offset:` Vertical offset for position of the text in points
- `expansion:` Text expansion factor
- `kern:` The kerning of the text, i.e. the number of points by which to adjust kern-pair characters
- `obliqueness:` The skew to be applied to the glyphs
- `stroke-width:` The relative width of the outline stroke
- `ligature:` Boolean indicating whether ligatures are used
- `font:` Font of the text
- `link:` Link target string, e.g. a URL
- `paragraph-style:` Paragraph style for laying out paragraphs
- `shadow:`: The shadow defined by a pair whose car is a size object defining horizontal and vertical offset and cdr is a positive flonum representing the shadow blur radius
- `superscript:`: The superscript offset in points

The second use case for `make-styled-text` is creating a styled text object for a given image.

This example shows how to use `make-styled-text`:

    (make-styled-text "Mauris scelerisque massa erat."
      'font: (font "Helvetica" 12.0)
      'foreground-color: (color 0.3 0.5 0.7)
      'paragraph-style:
        (make-paragraph-style
          'alignment: 'left
          'head-indent: 40.0
          'paragraph-spacing-before: 4.0))

(make-styled-text-table cols rows) [procedure]
(make-styled-text-table cols rows style)
(make-styled-text-table cols rows style pstyle)
(make-styled-text-table cols rows style pstyle collapse)
(make-styled-text-table cols rows style pstyle collapse hide-empty)

This procedure is only available on macOS. It creates a styled text table with cols number of columns. rows is a list of table rows. Each row is a list of table columns. A table column is either a string, styled text, or a text cell descriptor, which is a list containing at least a prefix of the following four components: (text col-span tbstyle pstyle). text is either a string or styled text, col-span is a number indicating how many columns the cell spans, tbstyle is a text block style object and pstyle is a paragraph style object, both of which are used to lay out the cell content.

style is a default text block style object, and pstyle is a default paragraph style object. They are both used to lay out cells which do not come with their own stylistic attributes. collapse is a boolean argument which collapses table borders if set to `#t` (which is the default). hide-empty is a boolean argument which hides empty cells if set to `#t` (`#f` is the default).

Styled text tables are represented as a styled text object, so `make-styled-text-table` returns styled text.

    (make-styled-text-table 3
      (list ; list of rows
        (list ; list of columns
          "Cell 1,1"
          "Cell 1,2"
          (styled-text "Cell 1,3" (font "Helvetica" 11.0)))
        (list ; list of columns
          "Cell 2,1"
          (list ; column spanning 2 cells
            (styled-text "Cell 2,3" (font "Times" 10.0) red)
            2
            tbstyle
            pstyle)))
        def-tbstyle ; default text block style
        def-pstyle  ; default paragraph style
        #t)

(load-styled-text path format) [procedure]

Loads the document at file path and returns its content as styled text. format specifies the file format to load. format is one of the following symbols:

- `plain`: Plain text file
- `doc`: Microsoft Word file
- `docx`: ECMA Office Open XML text document
- `rtf`: RTF file
- `rtfd`: RTFD file

(save-styled-text path txt format) [procedure]

Saves the styled text txt in a new file at file path in file format. format is one of the following symbols:

- `plain`: Plain text file
- `doc`: Microsoft Word file
- `docx`: ECMA Office Open XML text document
- `rtf`: RTF file
- `rtfd`: RTFD file

(copy-styled-text txt) [procedure]
(copy-styled-text txt start)
(copy-styled-text txt start end)

Returns a copy of styled text txt between positions start (inclusive) and end (exclusive). start is an index between 0 and the length of txt (default is 0). end is an index between start and the length of txt (default is the length of txt).

(html->styled-text html) [procedure]

Returns styled text for the given html string.

(styled-text->html txt) [procedure]
(styled-text->html txt start)
(styled-text->html txt start end)

Returns HTML as a string representing the styled text txt between position start and end. If end is not provided, it is assumed to be the length of txt. If start is not provided, it is assumed to be 0.

(bytevector->styled-text bvec format) [procedure]
(bytevector->styled-text bvec format start)
(bytevector->styled-text bvec format start end)

`bytevector->styled-text` interprets bytevector bvec between start and end as a file of text format and returns its content as a new styled text object. If end is not provided, it is assumed to be the length of bytevector. If start is not provided, it is assumed to be 0.

(styled-text->bytevector txt format) [procedure]
(styled-text->bytevector txt format start)
(styled-text->bytevector txt format start end)

Stores the styled text txt between position start and end in the given format in a new bytevector and returns that bytevector. If end is not provided, it is assumed to be the length of bytevector. If start is not provided, it is assumed to be 0. format is one of the following symbols:

- `plain`: Plain text file
- `doc`: Microsoft Word file
- `docx`: ECMA Office Open XML text document
- `rtf`: RTF file

(styled-text=? txt0 txt1 …) [procedure]

Returns `#t` if txt0, txt1, … are all equals, otherwise `#f` is returned.

(styled-text-string txt) [procedure]

Returns a string for the given styled text txt.

(styled-text-insert! txt obj) [procedure]
(styled-text-insert! txt obj start)
(styled-text-insert! txt obj start end)

Inserts obj into the styled text txt replacing the characters between the position start and end with obj. If obj is `#f`, then the characters between start and end are being deleted. If obj is a string, styled text or an image, obj gets converted into styled text and inserted accordingly. If start is not provided, it is assumed to be 0. If end is not provided, it is assumed to be the same like start.

(styled-text-append! txt obj …) [procedure]

Appends the objects obj, … to the styled text txt in the given order. obj may be either a string, styled text, or an image.

(styled-text-ref txt index) [procedure]

Returns a text style object encapsulating all stylistic attributes that are applicable to the character at index of styled text txt.

(styled-text-set! txt start end style) [procedure]
(styled-text-set! txt start end key val)

If style is provided, sets the stylistic attributes of styled text txt in the character range from start (inclusive) to end (exclusive) to the attributes encapsulated by style. If key and val are provided instead, procedure `styled-text-set!` sets a single attribute key to the value val for the given character range of txt. Supported keys are: `background-color`, `foreground-color`, `strikethrough-color`, `stroke-color`, `underline-color`, `baseline-offset`, `expansion`, `kern`, `obliqueness`, `stroke-width`, `ligature`, `font`, `link`, `paragraph-style`, `shadow`, and `superscript`.

(styled-text-add! txt start end style) [procedure]
(styled-text-add! txt start end key val)

If style is provided, adds the stylistic attributes encapsulated by style to the existing stylistic attributes of styled text txt for the character range from start (inclusive) to end (exclusive). If key and val are provided instead, procedure `styled-text-add!` adds a single attribute key to the value val for the given character range of txt. Supported keys are: `background-color`, `foreground-color`, `strikethrough-color`, `stroke-color`, `underline-color`, `baseline-offset`, `expansion`, `kern`, `obliqueness`, `stroke-width`, `ligature`, `font`, `link`, `paragraph-style`, `shadow`, and `superscript`.

(styled-text-remove! txt start end key) [procedure]

Removes the stylistic attribute key from the styled text txt in the character range from start (inclusive) to end (exclusive).

(styled-text-attribute txt key index) [procedure]
(styled-text-attribute txt key index start)
(styled-text-attribute txt key index start end)

This procedure returns two values. The first is the stylistic attribute value for attribute key at character index in the styled text txt within the character range from start (inclusive) to end (exclusive). The second return value is the longest effective range of this attribute. If the attribute is not set at the given index, `styled-text-attribute` returns two `#f` values.

(styled-text-attributes txt index) [procedure]
(styled-text-attributes txt index start)
(styled-text-attributes txt index start end)

This procedure returns two values. The first is a text style object capturing all stylistic attributes at character index in the styled text txt within the character range from start (inclusive) to end (exclusive). The second return value is the longest effective range of this text style. Two `#f` values are returned if no attributes are found.

(styled-text-first-attribute text key) [procedure]
(styled-text-first-attribute text key start)
(styled-text-first-attribute text key start end)

This procedure returns two values. The first is the first stylistic attribute value for attribute key in the styled text txt within the character range from start (inclusive) to end (exclusive). The second return value is the longest effective range of this attribute. If the attribute is not set in range start to end, `styled-text-first-attribute` returns two `#f` values.

(styled-text-first-attributes txt) [procedure]
(styled-text-first-attributes txt start)
(styled-text-first-attributes txt start end)

This procedure returns two values. The first is a text style object capturing all stylistic attributes that were found first in the styled text txt within the character range from start (inclusive) to end (exclusive). The second return value is the longest effective range of this text style. Two `#f` values are returned if no attributes are found.

## Text styles

Text style objects encapsulate a set of stylistic attributes, such as `font`, `background-color`, `baseline-offset`, `kern`, `obli queness`, etc. Text style objects are mutable. Attributes can be inspected, added, and removed.

text-style-type-tag [object]

Symbol representing the `text-style` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all text style objects.

(text-style? obj) [procedure]

Returns `#t` if obj is a text style object; otherwise `#f` is returned.

(make-text-style key val …) [procedure]

Returns a text style object encapsulating the given stylistic attributes provided as key/value pairs. The following attribute key symbols are supported:

- `background-color:` Background color
- `foreground-color:` Text color
- `strikethrough-color:` Strike-through color
- `stroke-color:` Outline color
- `underline-color:` Underline color
- `baseline-offset:` Vertical offset for position of the text in points
- `expansion:` Text expansion factor
- `kern:` The kerning of the text, i.e. the number of points by which to adjust kern-pair characters
- `obliqueness:` The skew to be applied to the glyphs
- `stroke-width:` The relative width of the outline stroke
- `ligature:` Boolean indicating whether ligatures are used
- `font:` Font of the text
- `link:` Link target string, e.g. a URL
- `paragraph-style:` Paragraph style for laying out paragraphs
- `shadow:`: The shadow defined by a pair whose car is a size object defining horizontal and vertical offset and cdr is a positive flonum representing the shadow blur radius
- `superscript:`: The superscript offset in points

This example shows how to use `make-text-style`:

    (make-text-style
      'font: (font "Times" 13.5)
      'foreground-color: (color 0.8 0.8 0.8)
      'paragraph-style:
        (make-paragraph-style
          'alignment: 'left
          'paragraph-spacing-before: 5.0))

(copy-text-style style) [procedure]

Returns a copy of style.

(text-style-empty? style) [procedure]

Returns `#t` if the style object does not include any stylistic attributes; otherwise `#f` is returned.

(text-style-ref style key) [procedure]

Returns the attribute value for stylistic attribute key defined by style. `#f` is returned if no value is set.

(text-style-set! style key value) [procedure]

Sets the stylistic attribute key to value in style.

(text-style-merge! style style1 …) [procedure]

Merges all the text style objects style1 … into style. The text style objects are merged in the order provided, i.e. later values override values in earlier style objects.

(text-style-remove! style key) [procedure]

Removes the stylistic attribute key from style.

(text-style-attributes expr) [procedure]

Returns the stylistic attributes of style as an association list. The result is a list of key/value pairs.

    (text-style-attributes
      (make-text-style
        'font: (font "Times" 13.5)
        'foreground-color: (color 0.8 0.8 0.8)
        'obliqueness: 1.2))
    ⇒ ((font . #<font Times-Roman 13.5>)
       (obliqueness . 1.2)
       (foreground-color . #<color 0.8 0.8 0.8>))

## Text block styles

Text block style objects encapsulate attributes describing how text is layed out in a box. Text block styles are currently only used for defining the layout of cells in a table. The following text block style attributes are supported:

- `width`: The width of the text block in points or as a percentage.
- `height`: The height of the text block in points or as a percentage.
- `margin`: The margin around the text block. This is either one value representing the same margin in points or as a percentage for all four sides, or it is a list of four values `(left right top bottom)`.
- `border`: The “thickness”/size of the border in points or as a percentage. This is either one value representing the same border size for all four sides, or it is a list of four values `(left right top bottom)`. 0 means “no border”.
- `padding`: The padding within the text block in points or as a percentage. This is either one value representing the same padding for all four sides, or it is a list of four values `(left right top bottom)`.
- `background-color`: The background color of the text block.
- `border-color`: The color of the border of the text block.
- `vertical-alignment`: The vertical alignment of the text within the block. Supported are the following four alignment values: `top`, `middle`, `bottom`, and `baseline`.

Text block style objects are mutable. They define values for all attributes, i.e. there are defaults for all attributes set for newly created text block style objects.

text-block-style-type-tag [object]

Symbol representing the `text-block-style` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all text block style objects.

(percent num) [procedure]

Some text block style attributes allow for relative values. Procedure `percent` encodes a fixnum num as a percentage (i.e. `(num . %)`).

(percent? obj) [procedure]

Returns `#t` if obj is an object representing a percentage; otherwise `#f` is returned.

(text-block-style? obj) [procedure]

Returns `#t` if obj is a text block style object; otherwise `#f` is returned.

(make-text-block-style key value …) [procedure]

Returns a text block style object encapsulating the given attributes provided as key/value pairs. The following attribute key symbols are supported:

- `width:` The width of the text block in points or as a percentage.
- `height:` The height of the text block in points or as a percentage.
- `margin:` The margin around the text block. This is either one value representing the same margin in points or as a percentage for all four sides, or it is a list of four values `(left right top bottom)`.
- `border:` The “thickness”/size of the border in points or as a percentage. This is either one value representing the same border size for all four sides, or it is a list of four values `(left right top bottom)`. 0 means “no border”.
- `padding:` The padding within the text block in points or as a percentage. This is either one value representing the same padding for all four sides, or it is a list of four values `(left right top bottom)`.
- `background-color:` The background color of the text block.
- `border-color:` The color of the border of the text block.
- `vertical-alignment:` The vertical alignment of the text within the block. Supported are the following four alignment values: `top`, `middle`, `bottom`, and `baseline`.

(copy-text-block-style bstyle) [procedure]

Returns a copy of bstyle.

(text-block-style=? bstyle bstyle0 …) [procedure]

Returns `#t` if all bstyle0 … are equal to bstyle; otherwise `#f` is returned.

(text-block-style-ref bstyle key) [procedure]

Returns the value associated with text block style attribute key.

(text-block-style-set! bstyle key value) [procedure]

Sets the text block style attribute key to value for the text block style object bstyle.

## Paragraph styles

Paragraph style objects define how a paragraph of text is layed out in terms of a number of attributes. The following attributes are supported:

- `alignment`: Horizontal text alignment mode. Supported are: `left`, `right`, `center`, `justified`, and `natural`.
- `first-head-indent`: Distance in points from the leading margin of a text container to the beginning of the paragraph’s first line.
- `head-indent`: Distance in points from the leading margin of a text container to the beginning of lines other than the first.
- `tail-indent`: If positive, this is the distance from the leading margin (e.g. the left margin in left-to-right text). If 0 or negative, it’s the distance from the trailing margin. For example, a paragraph style designed to fit exactly in a container has a head indent of 0.0 and a tail indent of 0.0. One designed to fit with a quarter-inch margin has a head indent of 0.25 and a tail indent of –0.25.
- `line-height-multiple`: Multiplier for the natural line height of the text (if positive), and constrains the resulting value by the minimum and maximum line height. The default value is 0.0.
- `max-line-height`: This attribute defines the maximum height in points that any line in the paragraph occupies, regardless of the font size or size of any attached image. Default is 0 (= no constaint).
- `min-line-height`: This attribute defines the minimum height in points that any line in the paragraph occupies, regardless of the font size or size of any attached image. Default is 0.
- `line-spacing`: The distance in points between the bottom of one line fragment and the top of the next.
- `paragraph-spacing-after`: Distance between the bottom of a paragraph and the top of the next. The layout algorithm determines the space between paragraphs by adding `paragraph-spacing-after` of the previous paragraph to the next paragraph’s `paragraph-spacing-before`.
- `paragraph-spacing-before`: The distance between the paragraph’s top and the beginning of its text content.
- `tab-interval`: The default tab interval in points. Tabs after the last specified tab stops are placed at multiples of this distance (if positive). Default is 0.0.
- `text-fit-mode`: Attribute that specifies what happens when a line is too long for a container. Supported are: `word-wrap`, `char-wrap`, `clip`, `truncate`, `truncate-head`, and `truncate-tail`.
- `push-out-line-break`: Boolean value that, if set to `#t`, makes the line layout algorithm push out individual lines to avoid an orphan word on the last line of a paragraph.
- `hypenation-factor`: A paragraph’s threshold for hyphenation. The line layout algorithm attempts hyphenation when the ratio of the text width (as broken without hyphenation) to the width of the line fragment is less than the hyphenation factor. Default is 0 (= system-defined hyphenation threshold).
- `writing-direction`: Writing direction of a paragraph. Supported are: `natural` (automatic), `left-to-right`, and `right-to-left`.

Paragraph style objects are mutable. They encapsulate one value for each supported paragraph style attribute.

paragraph-style-type-tag [object]

Symbol representing the `paragraph-style` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all paragraph style objects.

(paragraph-style? obj) [procedure]

Returns `#t` if obj is a paragraph style object obj; otherwise `#f` is returned.

(make-paragraph-style key value …) [procedure]

Returns a paragraph style object encapsulating the given attributes provided as key/value pairs. The following attribute key symbols are supported:

- `alignment`: Horizontal text alignment mode; i.e. either `left`, `right`, `center`, `justified`, and `natural`.
- `first-head-indent`: Distance in points from the leading margin of a text container to the beginning of the paragraph’s first line.
- `head-indent`: Distance in points from the leading margin of a text container to the beginning of lines other than the first.
- `tail-indent`: Distance from the leading margin if positive. If 0 or negative, it’s the distance from the trailing margin.
- `line-height-multiple`: Multiplier for the natural line height of the text.
- `max-line-height`: Defines the maximum height in points that any line in the paragraph occupies.
- `min-line-height`: Defines the minimum height in points that any line in the paragraph occupies.
- `line-spacing`: The distance in points between the bottom of one line fragment and the top of the next.
- `paragraph-spacing-after`: Distance between the bottom of a paragraph and the top of the next.
- `paragraph-spacing-before`: The distance between the paragraph’s top and the beginning of its text content.
- `tab-interval`: The default tab interval in points.
- `text-fit-mode`: Specifies what happens when a line is too long; supported are: `word-wrap`, `char-wrap`, `clip`, `truncate`, `truncate-head`, and `truncate-tail`.
- `push-out-line-break`: Boolean that, if set to `#t`, makes the line layout algorithm push out individual lines to avoid an orphan word on the last line of a paragraph.
- `hypenation-factor`: A paragraph’s threshold for hyphenation.
- `writing-direction`: Writing direction of a paragraph; supported are: `natural`, `left-to-right`, and `right-to-left`.

(copy-paragraph-style pstyle) [procedure]

Returns a copy of pstyle.

(paragraph-style=? pstyle pstyle0 …) [procedure]

Returns `#t` if all pstyle0 … are equal to pstyle; otherwise `#f` is returned.

(paragraph-style-ref pstyle key) [procedure]

Returns the value associated with paragraph style attribute key.

(paragraph-style-set! pstyle key value) [procedure]

Sets the paragraph style attribute key to value for the paragraph style object pstyle.

(paragraph-style-tabstops pstyle) [procedure]

Returns a list of tab stops for the given paragraph style. Each tab stop is represented as a pair consisting of a location in points and a text alignment, i.e. either `left`, `right`, `center`, `justified`, and `natural`.

(paragraph-style-tabstop-add! pstyle loc) [procedure]
(paragraph-style-tabstop-add! pstyle loc align)
(paragraph-style-tabstop-add! pstyle loc align cs)

Adds a new tab stop to paragraph style pstyle. loc is the location of the tab stop in points, align is the alignment of the text at the location (e.g. one of `left`, `right`, `center`, `justified`, and `natural`), and cs is a char-set object that is used to determine the terminating character for a tab column. The tab and newline characters are implied even if they don’t exist in the character set. The default for align is `natural`.

(paragraph-style-tabstop-remove! pstyle loc) [procedure]
(paragraph-style-tabstop-remove! pstyle loc align)

Removes the tab stop in pstyle at the given location loc and using the provided text alignment align (default is `natural`).

(paragraph-style-tabstops-clear! pstyle) [procedure]

Removes all tab stops from paragraph style pstyle.