mirror of
https://github.com/mum4k/termdash.git
synced 2025-05-01 22:17:51 +08:00
Removing Text's dependency on wrap.Needed.
It was rune based and thus incompatible with word wrapping.
This commit is contained in:
parent
54c5dff63e
commit
61aca3fb62
@ -34,7 +34,11 @@ func (m Mode) String() string {
|
||||
}
|
||||
|
||||
// modeNames maps Mode values to human readable names.
|
||||
var modeNames = map[Mode]string{}
|
||||
var modeNames = map[Mode]string{
|
||||
Never: "WrapModeNever",
|
||||
AtRunes: "WrapModeAtRunes",
|
||||
AtWords: "WrapModeAtWords",
|
||||
}
|
||||
|
||||
const (
|
||||
// Never is the default wrapping mode, which disables line wrapping.
|
||||
@ -49,11 +53,11 @@ const (
|
||||
AtWords
|
||||
)
|
||||
|
||||
// Needed returns true if wrapping is needed for the rune at the horizontal
|
||||
// needed returns true if wrapping is needed for the rune at the horizontal
|
||||
// position on the canvas that has the specified width.
|
||||
// This will always return false if no options are provided, since the default
|
||||
// behavior is to not wrap the text.
|
||||
func Needed(r rune, posX, width int, m Mode) bool {
|
||||
func needed(r rune, posX, width int, m Mode) bool {
|
||||
if r == '\n' {
|
||||
// Don't wrap for newline characters as they aren't printed on the
|
||||
// canvas, i.e. they take no horizontal space.
|
||||
@ -82,7 +86,7 @@ func Lines(text string, width int, m Mode) []int {
|
||||
// input text or when the canvas width and configuration requires line
|
||||
// wrapping.
|
||||
type lineScanner struct {
|
||||
// scanner lexes the input text.
|
||||
// scanner is a lexer of the input text.
|
||||
scanner *scanner.Scanner
|
||||
|
||||
// width is the width of the canvas the text will be drawn on.
|
||||
@ -142,7 +146,7 @@ func scanLine(ls *lineScanner) scannerState {
|
||||
case tok == scanner.Ident:
|
||||
return scanLineBreak
|
||||
|
||||
case Needed(tok, ls.posX, ls.width, ls.mode):
|
||||
case needed(tok, ls.posX, ls.width, ls.mode):
|
||||
return scanLineWrap
|
||||
|
||||
default:
|
||||
|
@ -93,9 +93,9 @@ func TestNeeded(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := Needed(tc.r, tc.posX, tc.width, tc.mode)
|
||||
got := needed(tc.r, tc.posX, tc.width, tc.mode)
|
||||
if got != tc.want {
|
||||
t.Errorf("Needed => got %v, want %v", got, tc.want)
|
||||
t.Errorf("needed => got %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -60,7 +60,13 @@ type Text struct {
|
||||
contentChanged bool
|
||||
// lines stores the starting locations in bytes of all the lines in the
|
||||
// buffer. I.e. positions of newline characters and of any calculated line wraps.
|
||||
// The indexes in this slice are the line numbers.
|
||||
lines []int
|
||||
// lineStartToIdx maps the rune positions where line starts are to indexes,
|
||||
// the line numbers.
|
||||
// This is the same data as in lines, but available for quick lookup based
|
||||
// on character index.
|
||||
lineStartToIdx map[int]int
|
||||
|
||||
// mu protects the Text widget.
|
||||
mu sync.Mutex
|
||||
@ -98,6 +104,7 @@ func (t *Text) reset() {
|
||||
t.lastWidth = 0
|
||||
t.contentChanged = true
|
||||
t.lines = nil
|
||||
t.lineStartToIdx = map[int]int{}
|
||||
}
|
||||
|
||||
// Write writes text for the widget to display. Multiple calls append
|
||||
@ -173,6 +180,16 @@ func (t *Text) drawScrollDown(cvs *canvas.Canvas, cur image.Point, fromLine int)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// isLineStart asserts whether a rune from the text at the specified position
|
||||
// should be placed on a new line.
|
||||
// Argument fromLine indicates the starting line we are drawing the text from
|
||||
// and is needed, because this function must return false for the very first
|
||||
// line drawn. The first line is already a new line.
|
||||
func (t *Text) isLineStart(pos, fromLine int) bool {
|
||||
idx, ok := t.lineStartToIdx[pos]
|
||||
return ok && idx != fromLine
|
||||
}
|
||||
|
||||
// draw draws the text context on the canvas starting at the specified line.
|
||||
func (t *Text) draw(text string, cvs *canvas.Canvas) error {
|
||||
var cur image.Point // Tracks the current drawing position on the canvas.
|
||||
@ -183,6 +200,7 @@ func (t *Text) draw(text string, cvs *canvas.Canvas) error {
|
||||
return err
|
||||
}
|
||||
startPos := t.lines[fromLine]
|
||||
var drawnScrollUp bool // Indicates if a scroll up marker was drawn.
|
||||
for i, r := range text {
|
||||
if i < startPos {
|
||||
continue
|
||||
@ -196,11 +214,18 @@ func (t *Text) draw(text string, cvs *canvas.Canvas) error {
|
||||
if scrlUp {
|
||||
cur = image.Point{0, cur.Y + 1} // Move to the next line.
|
||||
startPos = t.lines[fromLine+1] // Skip one line of text, the marker replaced it.
|
||||
drawnScrollUp = true
|
||||
continue
|
||||
}
|
||||
|
||||
// Line wrapping.
|
||||
if r == '\n' || wrap.Needed(r, cur.X, cvs.Area().Dx(), t.opts.wrapMode) {
|
||||
fr := fromLine
|
||||
if drawnScrollUp {
|
||||
// The scroll marker inserted a line so we are off-by-one when
|
||||
// looking up new lines.
|
||||
fr++
|
||||
}
|
||||
if t.isLineStart(i, fr) {
|
||||
cur = image.Point{0, cur.Y + 1} // Move to the next line.
|
||||
}
|
||||
|
||||
@ -255,6 +280,10 @@ func (t *Text) Draw(cvs *canvas.Canvas) error {
|
||||
// The previous text preprocessing (line wrapping) is invalidated when
|
||||
// new text is added or the width of the canvas changed.
|
||||
t.lines = wrap.Lines(text, width, t.opts.wrapMode)
|
||||
t.lineStartToIdx = map[int]int{}
|
||||
for idx, start := range t.lines {
|
||||
t.lineStartToIdx[start] = idx
|
||||
}
|
||||
}
|
||||
t.lastWidth = width
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user