pkg/text/truncate.go (49 lines of code) (raw):

package text import "bytes" // Truncate resizes the string with the given length. It ellipses with '...' when the string's length exceeds // the desired length or pads spaces to the right of the string when length is smaller than desired func Truncate(s string, length int) string { slen := StringWidth(s) n := length if slen == n { return s } // Pads only when length of the string smaller than len needed s = PadRight(s, n, ' ') if slen > n { buf := bytes.Buffer{} w := 0 dotsWritten := 0 hyperlinkMatches := hyperlinkOSCRegexp.FindAllStringIndex(s, -1) // append a faked match so that we always have something in // hyperlinkMatches[0] and can avoid nil checks hyperlinkMatches = append(hyperlinkMatches, []int{len(s), len(s)}) for i, r := range s { startPos := hyperlinkMatches[0][0] endPos := hyperlinkMatches[0][1] if i >= startPos && i < endPos { // write runes inside hyperlink OSC sequences - this doesn't count // against our grapheme total buf.WriteRune(r) } else if w == 0 { // always write the first character buf.WriteRune(r) w += RuneWidth(r) } else { rw := RuneWidth(r) if w+rw <= n-3 { // if we have room before the ellipsis, go ahead and write it buf.WriteRune(r) w += rw } else if dotsWritten < 3 { buf.WriteRune('.') w++ dotsWritten++ } else { break } } if i == endPos-1 { // we're at the end of this hyperlink OSC sequence - get ready // to check for the next one hyperlinkMatches = hyperlinkMatches[1:] } } // if we currently have an "open" hyperlink OSC sequence, we need to write // a closing sequence nextOSC := s[hyperlinkMatches[0][0]:hyperlinkMatches[0][1]] isNextOSCClosing := nextOSC == "\x1b]8;;\x1b\\" if isNextOSCClosing { buf.WriteString(nextOSC) } s = buf.String() } return s }