Add TruncateString to shorten a string without splitting a character #6

Merged
sneak merged 1 commits from clawbot/util:proposal-truncate-string into master 2026-09-05 05:45:39 +02:00
Contributor

Adds TruncateString(s string, max int) string, which returns at most max
characters from the start of the string. A max of zero or less returns an empty
string, and a string already within the limit comes back unchanged.

This belongs here because every program that puts text into a fixed-width
column, a log line or a summary needs to shorten it, and the obvious way of
doing that, s[:max], is wrong for any text that is not plain ASCII: it splits
a multi-byte character and produces invalid output. The correct version is
short but not obvious.

Things to know:

  • The limit counts characters, not bytes and not display width. Text with
    combining marks, or with characters that a terminal draws double width, will
    still count as one character each, so this is not a way to fit text into a
    fixed number of screen columns.
  • The implementation walks the string with range, which yields the byte
    offset of each character start, so nothing is allocated and no conversion to
    a rune slice happens.
  • Nothing is appended to the result, so there is no ellipsis. A caller that
    wants one can add it, and can decide whether it counts against the limit.
  • The code is in a new file, truncate.go, so that the ten proposal branches
    do not all conflict in the same place.
  • make test on this branch reports one failure, TestNowUnixMicro. That test
    already fails on master and is unrelated to this change.

Model: opus-5

Adds `TruncateString(s string, max int) string`, which returns at most `max` characters from the start of the string. A max of zero or less returns an empty string, and a string already within the limit comes back unchanged. This belongs here because every program that puts text into a fixed-width column, a log line or a summary needs to shorten it, and the obvious way of doing that, `s[:max]`, is wrong for any text that is not plain ASCII: it splits a multi-byte character and produces invalid output. The correct version is short but not obvious. Things to know: - The limit counts characters, not bytes and not display width. Text with combining marks, or with characters that a terminal draws double width, will still count as one character each, so this is not a way to fit text into a fixed number of screen columns. - The implementation walks the string with `range`, which yields the byte offset of each character start, so nothing is allocated and no conversion to a rune slice happens. - Nothing is appended to the result, so there is no ellipsis. A caller that wants one can add it, and can decide whether it counts against the limit. - The code is in a new file, `truncate.go`, so that the ten proposal branches do not all conflict in the same place. - `make test` on this branch reports one failure, `TestNowUnixMicro`. That test already fails on `master` and is unrelated to this change. Model: opus-5
clawbot self-assigned this 2026-09-05 05:25:10 +02:00
clawbot added 1 commit 2026-09-05 05:25:10 +02:00
TruncateString returns at most the requested number of characters from the
start of a string, counting characters rather than bytes so a multi-byte
character is never cut in half. Comes with a doc comment and table-driven
tests. (closes #5)

Model: opus-5
sneak merged commit 1a6d1b429b into master 2026-09-05 05:45:39 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/util#6