package text
import "golang.org/x/exp/shiny/text"
Package text lays out paragraphs of text.
A body of text is laid out into a Frame: Frames contain Paragraphs (stacked vertically), Paragraphs contain Lines (stacked vertically), and Lines contain Boxes (stacked horizontally). Each Box holds a []byte slice of the text. For example, to simply print a Frame's text from start to finish:
var f *text.Frame = etc for p := f.FirstParagraph(); p != nil; p = p.Next(f) { for l := p.FirstLine(f); l != nil; l = l.Next(f) { for b := l.FirstBox(f); b != nil; b = b.Next(f) { fmt.Print(b.Text(f)) } } }
A Frame's structure (the tree of Paragraphs, Lines and Boxes), and its []byte text, are not modified directly. Instead, a Frame's maximum width can be re-sized, and text can be added and removed via Carets (which implement standard io interfaces). For example, to add some words to the end of a frame:
var f *text.Frame = etc c := f.NewCaret() c.Seek(0, text.SeekEnd) c.WriteString("Not with a bang but a whimper.\n") c.Close()
Either way, such modifications can cause re-layout, which can add or remove
Paragraphs, Lines and Boxes. The underlying memory for such structs can be
re-used, so pointer values, such as of type *Box, should not be held over
such modifications.
Code:play
Output:Example¶
package main
import (
"fmt"
"image"
"os"
"golang.org/x/exp/shiny/text"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// toyFace implements the font.Face interface by measuring every rune's width
// as 1 pixel.
type toyFace struct{}
func (toyFace) Close() error {
return nil
}
func (toyFace) Glyph(dot fixed.Point26_6, r rune) (image.Rectangle, image.Image, image.Point, fixed.Int26_6, bool) {
panic("unimplemented")
}
func (toyFace) GlyphBounds(r rune) (fixed.Rectangle26_6, fixed.Int26_6, bool) {
panic("unimplemented")
}
func (toyFace) GlyphAdvance(r rune) (fixed.Int26_6, bool) {
return fixed.I(1), true
}
func (toyFace) Kern(r0, r1 rune) fixed.Int26_6 {
return 0
}
func (toyFace) Metrics() font.Metrics {
return font.Metrics{}
}
func printFrame(f *text.Frame, softReturnsOnly bool) {
for p := f.FirstParagraph(); p != nil; p = p.Next(f) {
for l := p.FirstLine(f); l != nil; l = l.Next(f) {
for b := l.FirstBox(f); b != nil; b = b.Next(f) {
if softReturnsOnly {
os.Stdout.Write(b.TrimmedText(f))
} else {
os.Stdout.Write(b.Text(f))
}
}
if softReturnsOnly {
fmt.Println()
}
}
}
}
func main() {
var f text.Frame
f.SetFace(toyFace{})
f.SetMaxWidth(fixed.I(60))
c := f.NewCaret()
c.WriteString(mobyDick)
c.Close()
fmt.Println("====")
printFrame(&f, false)
fmt.Println("====")
fmt.Println("123456789_123456789_123456789_123456789_123456789_123456789_")
printFrame(&f, true)
fmt.Println("====")
}
const mobyDick = "CHAPTER 1. Loomings.\nCall me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...\n"
====
CHAPTER 1. Loomings.
Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...
====
123456789_123456789_123456789_123456789_123456789_123456789_
CHAPTER 1. Loomings.
Call me Ishmael. Some years ago—never mind how long
precisely—having little or no money in my purse, and nothing
particular to interest me on shore, I thought I would sail
about a little and see the watery part of the world...
====
Index ¶
- Constants
- type Box
- func (b *Box) Next(f *Frame) *Box
- func (b *Box) Text(f *Frame) []byte
- func (b *Box) TrimmedText(f *Frame) []byte
- type Caret
- func (c *Caret) Close() error
- func (c *Caret) Delete(dir Direction, nBytes int) (dBytes int)
- func (c *Caret) DeleteRunes(dir Direction, nRunes int) (dRunes, dBytes int)
- func (c *Caret) Read(buf []byte) (n int, err error)
- func (c *Caret) ReadByte() (x byte, err error)
- func (c *Caret) ReadRune() (r rune, size int, err error)
- func (c *Caret) Seek(offset int64, whence int) (int64, error)
- func (c *Caret) Write(s []byte) (n int, err error)
- func (c *Caret) WriteByte(x byte) error
- func (c *Caret) WriteRune(r rune) (size int, err error)
- func (c *Caret) WriteString(s string) (n int, err error)
- type Direction
- type Frame
- func (f *Frame) FirstParagraph() *Paragraph
- func (f *Frame) Height() int
- func (f *Frame) Len() int
- func (f *Frame) LineCount() int
- func (f *Frame) NewCaret() *Caret
- func (f *Frame) ParagraphCount() int
- func (f *Frame) SetFace(face font.Face)
- func (f *Frame) SetMaxWidth(m fixed.Int26_6)
- type Line
- func (l *Line) FirstBox(f *Frame) *Box
- func (l *Line) Height(f *Frame) int
- func (l *Line) Next(f *Frame) *Line
- type Paragraph
Examples ¶
Constants ¶
These constants are equal to os.SEEK_SET, os.SEEK_CUR and os.SEEK_END, understood by the io.Seeker interface, and are provided so that users of this package don't have to explicitly import "os".
Types ¶
type Box ¶
type Box struct {
// contains filtered or unexported fields
}
Box holds a contiguous run of text.
func (*Box) Next ¶
Next returns the next Box after this one in the Line.
f is the Frame that contains the Box.
func (*Box) Text ¶
Text returns the Box's text.
f is the Frame that contains the Box.
func (*Box) TrimmedText ¶
TrimmedText returns the Box's text, trimmed right of any white space if it is the last Box in its Line.
f is the Frame that contains the Box.
type Caret ¶
type Caret struct {
// contains filtered or unexported fields
}
Caret is a location in a Frame's text, and is the mechanism for adding and removing bytes of text. Conceptually, a Caret and a Frame's text is like an int c and a []byte t such that the text before and after that Caret is t[:c] and t[c:]. That byte-count location remains unchanged even when a Frame is re-sized and laid out into a new tree of Paragraphs, Lines and Boxes.
A Frame can have multiple open Carets. For example, the beginning and end of a text selection can be represented by two Carets. Multiple Carets for the one Frame are not safe to use concurrently, but it is valid to interleave such operations sequentially. For example, if two Carets c0 and c1 for the one Frame are positioned at the 10th and 20th byte, and 4 bytes are written to c0, inserting what becomes the equivalent of text[10:14], then c0's position is updated to be 14 but c1's position is also updated to be 24.
func (*Caret) Close ¶
Close closes the Caret.
func (*Caret) Delete ¶
Delete deletes nBytes bytes in the specified direction from the Caret's location. It returns the number of bytes deleted, which can be fewer than that requested if it hits the beginning or end of the Frame.
func (*Caret) DeleteRunes ¶
DeleteRunes deletes nRunes runes in the specified direction from the Caret's location. It returns the number of runes and bytes deleted, which can be fewer than that requested if it hits the beginning or end of the Frame.
func (*Caret) Read ¶
Read satisfies the io.Reader interface by copying those bytes after the Caret and incrementing the Caret.
func (*Caret) ReadByte ¶
ReadByte returns the next byte after the Caret and increments the Caret.
func (*Caret) ReadRune ¶
ReadRune returns the next rune after the Caret and increments the Caret.
func (*Caret) Seek ¶
Seek satisfies the io.Seeker interface.
func (*Caret) Write ¶
Write inserts s into the Frame's text at the Caret and increments the Caret.
func (*Caret) WriteByte ¶
WriteByte inserts x into the Frame's text at the Caret and increments the Caret.
func (*Caret) WriteRune ¶
WriteRune inserts r into the Frame's text at the Caret and increments the Caret.
func (*Caret) WriteString ¶
WriteString inserts s into the Frame's text at the Caret and increments the Caret.
type Direction ¶
type Direction bool
Direction is either forwards or backwards.
type Frame ¶
type Frame struct {
// contains filtered or unexported fields
}
Frame holds Paragraphs of text.
The zero value is a valid Frame of empty text, which contains one Paragraph, which contains one Line, which contains one Box.
func (*Frame) FirstParagraph ¶
FirstParagraph returns the first paragraph of this frame.
func (*Frame) Height ¶
Height returns the height in pixels of this Frame.
func (*Frame) Len ¶
Len returns the number of bytes in the Frame's text.
func (*Frame) LineCount ¶
LineCount returns the number of Lines in this Frame.
This count includes any soft returns inserted to wrap text to the maxWidth.
func (*Frame) NewCaret ¶
NewCaret returns a new Caret at the start of this Frame.
func (*Frame) ParagraphCount ¶
ParagraphCount returns the number of Paragraphs in this Frame.
This count excludes any soft returns inserted to wrap text to the maxWidth.
func (*Frame) SetFace ¶
SetFace sets the font face for measuring text.
func (*Frame) SetMaxWidth ¶
SetMaxWidth sets the target maximum width of a Line of text, as a fixed-point fractional number of pixels. Text will be broken so that a Line's width is less than or equal to this maximum width. This line breaking is not strict. A Line containing asingleverylongword combined with a narrow maximum width will not be broken and will remain longer than the target maximum width; soft hyphens are not inserted.
A non-positive argument is treated as an infinite maximum width.
type Line ¶
type Line struct {
// contains filtered or unexported fields
}
Line holds Boxes of text.
func (*Line) FirstBox ¶
FirstBox returns the first Box of this Line.
f is the Frame that contains the Line.
func (*Line) Height ¶
Height returns the height in pixels of this Line.
func (*Line) Next ¶
Next returns the next Line after this one in the Paragraph.
f is the Frame that contains the Line.
type Paragraph ¶
type Paragraph struct {
// contains filtered or unexported fields
}
Paragraph holds Lines of text.
func (*Paragraph) FirstLine ¶
FirstLine returns the first Line of this Paragraph.
f is the Frame that contains the Paragraph.
func (*Paragraph) Height ¶
Height returns the height in pixels of this Paragraph.
func (*Paragraph) LineCount ¶
LineCount returns the number of Lines in this Paragraph.
This count includes any soft returns inserted to wrap text to the maxWidth.
func (*Paragraph) Next ¶
Next returns the next Paragraph after this one in the Frame.
f is the Frame that contains the Paragraph.
Source Files ¶
caret.go text.go
- Version
- v0.0.0-20250218142911-aa4b98e5adaa (latest)
- Published
- Feb 18, 2025
- Platform
- linux/amd64
- Imports
- 7 packages
- Last checked
- 1 month ago –
Tools for package owners.