Skip to content

Add Marquee decorator for long message scrolling - #126

Open
DeathKing wants to merge 2 commits into
vbauerster:masterfrom
DeathKing:marquee-decorator
Open

Add Marquee decorator for long message scrolling#126
DeathKing wants to merge 2 commits into
vbauerster:masterfrom
DeathKing:marquee-decorator

Conversation

@DeathKing

Copy link
Copy Markdown

2023-03-22-231235

Add Marquee decorator that scrolls text from right to
left, it is useful when displaying long messages. The codes are not carefully written, modifications are welcomed.

@vbauerster

Copy link
Copy Markdown
Owner

Implementation assumes that (string width = bytes width), therefore it's going to fail with non Latin strings. Try it for example with Россия великая страна! string to see what I mean.

@DeathKing

Copy link
Copy Markdown
Author

@vbauerster Da, I know what you mean, I noticed that issue too. After opened this PR and some investigation of mpb source code, I found the go-runewidth library that you used may be the solution.

I implement this feature in my project like this (https://github.com/DeathKing/pico/blob/master/cmd/pdf2image/bar.go#L14-L28):

func Marquee(textGetter func() string, ws uint, wcc ...decor.WC) decor.Decorator {
	var count uint
	f := func(s decor.Statistics) string {
		text := textGetter()
		runes := []rune(text)

		msg := string(runes[int(count)%len(runes):])
		count++

		return runewidth.FillRight(
			runewidth.Truncate(msg, int(ws), ""),
			int(ws))
	}
	return decor.Any(f, wcc...)
}
bar.mov

For this specific implementation, the API requires a getter function to obtain the text for display, which may not suitable for most case, a string parameter should be used instead as I suppose.

I'd like to know your opinion about this feature.

@RikaCelery

Copy link
Copy Markdown

Try this?🤔
It works well for me.

func Marquee(t string, ws int, divider string, wcc ...decor.WC) decor.Decorator {
	var count int
	var f = func(s decor.Statistics) string {
		length := runewidth.StringWidth(t + divider)
		if runewidth.StringWidth(t) < ws {
			return runewidth.FillRight(t, ws)
		}
		text := t + divider
		var msg string

		if count-ws > length {
			msg = TruncateLeft(Truncate(text, count+ws), ws)
		} else {
			msg = TruncateLeft(Truncate(text, count+ws), count)
		}
		if count+ws > length {
			msg += Truncate(text, count+ws-length)
		}
		count++
		if count+ws >= len(t)+len(divider)-1 {
			count = 0
		}
		return runewidth.FillRight(msg, ws)
	}
	return decor.Any(f, wcc...)
}

func Truncate(s string, size int) string {
	return runewidth.Truncate(s, size, "")
}
func TruncateLeft(s string, size int) string {
	return runewidth.TruncateLeft(s, size, "")
}

@Solaris-star Solaris-star left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea — a scrolling marquee decorator for long filenames in progress bars.

A few things to address:

  1. Byte-level scrolling breaks multi-byte UTF-8: bytes := []byte(text) and indexing by byte offset will split multi-byte characters (CJK, emoji, accented chars), producing garbled output. Consider []rune instead, or use github.com/mattn/go-runewidth (already a dependency) for display-width-aware scrolling.

  2. No wrap-around: when start + i >= len(bytes) the remaining window is padded with spaces. A true marquee wraps around so the text scrolls continuously. Something like buf[i] = bytes[(start+i) % uint(len(bytes))] would fix this.

  3. count increments on every render call, not on a timer. Since mpb re-renders at ~10fps by default, the scroll speed is tied to the render rate. This is probably fine but worth documenting.

  4. Example go.mod pins mpb v8.3.0 — should use a replace directive pointing to ../.. like the other examples do, so it builds against the local checkout.

  5. The example uses deprecated rand.New(rand.NewSource(...)) — minor, but the other examples in the repo use the same pattern so this is consistent at least.

The core Marquee function is clean. With the UTF-8 and wrap-around fixes this would be a welcome addition to the decorator library.

@vbauerster

Copy link
Copy Markdown
Owner

I'm ok with updated PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants