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:
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"
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".
type Box struct {
// contains filtered or unexported fields
}
Box holds a contiguous run of text.
Next returns the next Box after this one in the Line.
f is the Frame that contains the Box.
Text returns the Box's text.
f is the Frame that contains the Box.
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 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.
Close closes the Caret.
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.
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.
Read satisfies the io.Reader interface by copying those bytes after the Caret and incrementing the Caret.
ReadByte returns the next byte after the Caret and increments the Caret.
ReadRune returns the next rune after the Caret and increments the Caret.
Seek satisfies the io.Seeker interface.
Write inserts s into the Frame's text at the Caret and increments the Caret.
WriteByte inserts x into the Frame's text at the Caret and increments the Caret.
WriteRune inserts r into the Frame's text at the Caret and increments the Caret.
WriteString inserts s into the Frame's text at the Caret and increments the Caret.
Direction is either forwards or backwards.
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.
FirstParagraph returns the first paragraph of this frame.
Len returns the number of bytes in the Frame's text.
NewCaret returns a new Caret at the start of this Frame.
SetFace sets the font face for measuring text.
SetMaxWidth sets the target maximum width of a Line of text. 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 struct {
// contains filtered or unexported fields
}
Line holds Boxes of text.
FirstBox returns the first Box of this Line.
f is the Frame that contains the Line.
Next returns the next Line after this one in the Paragraph.
f is the Frame that contains the Line.
type Paragraph struct {
// contains filtered or unexported fields
}
Paragraph holds Lines of text.
FirstLine returns the first Line of this Paragraph.
f is the Frame that contains the Paragraph.
Next returns the next Paragraph after this one in the Frame.
f is the Frame that contains the Paragraph.
Package text imports 7 packages (graph). Updated 3 days ago. Refresh now. Tools for package owners.