-
-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace go-runewidth with uniseg #71
Replace go-runewidth with uniseg #71
Conversation
2ec4ca0
to
e59a5fa
Compare
@rivo Would you be able to help provide some guidance on how to boost the performance of these two regressed functions? I switched the
Is this a mistake in my refactor or is it a case that identifying grapheme clusters just requires more CPU cycles? |
e59a5fa
to
053c46d
Compare
(I only see one function here, I'm not quite sure what you're asking. Your patch looks like you switched from using the Under the hood, the So using Anyway, It should be quite simple to replace I haven't run comparison benchmarks with But again, if you're really just interested in the width and don't care about other types of boundaries, don't use the |
See also my follow-up comment here: charmbracelet/bubbletea#831 (comment) |
@rivo As usual, thanks again for the very detailed explanation as well as recommendations. A quick clarification; while I only provided the patch for a refactor of the BenchmarksI have taken the opportunity to rerun all the benchmarks in this package to determine how the changes have impacted them. master
refactor/go-runewidth-to-uniseg
refactor/go-runewidth-to-uniseg-go-1.21-uniseg-0.4.6
PerformanceComparing the results from before the switch to master -> refactor/go-runewidth-to-uniseg-go-1.21-uniseg-0.4.6
Considering that The only major concern is the performance issues with |
484ab73
to
fa505b9
Compare
@rivo Here are the updated benchmarks for the
This has improved the truncate function to now perform faster than the original version 😄 |
a5a63a6
to
26d85b8
Compare
BenchmarksBefore
After
Performance
OutcomeAll functions except All unit tests are passing which helps confirm we are getting the same results. Obviously, some emojis will provide a different result, which is to be expected and the driver for this work. ThanksA special thanks to @rivo for taking so much of his time for explaining and helping with this refactor. I doubt this pull request would have gotten to this state without him. Improving the performance of Nest StepsI am hoping @muesli can help with reviewing this pull request and providing guidance on any changes necessary. I do think some mention of these changes needs to go into the documentation and some thought should be considered to bumping the major version to indicate there are breaking changes. |
We'll have to bump the required Go version to 1.18. |
Replace the use of `RuneWidth` and `StringWidth` from `mattn/go- runewidth` with equivalent functions from `rivo/uniseg`. It is important to be aware that using `RuneWidth` will not be accurate as the width of a rune cannot be determined in isolation. This requires a shift to thinking about grapheme clusters instead. Unfortunately due to the complexity of identifying grapheme clusters, there has been some signifcant performance regressions in two functions: - PrintableRuneWidth: 10x slower - TruncateString: 4x slower Two other functions have had performance improvements: - MarginString: 2x faster - PaddingString: 2x faster The documentation for `rivo/uniseg` mentions the use of `Step` and `StepString` performing "orders of magnitude faster" than using the `NewGraphemes` method. However, implementing these changes only resulted in a 10% performance increase. Signed-off-by: Michael Lorant <[email protected]>
26d85b8
to
7edce3e
Compare
Bumped |
@muesli Would be great to get your sign off on this work. This is going to have some pretty big performance impacts on many of the |
@muesli Any chance you can take a look at this. Without this going to master branch I cant begin the changes to switch Lipgloss and Bubbles over to it. To drive home the point how much of a benefit this will be, we will likely see 10x performance in Bubbles components especially |
@mikelorant just a heads up that I talked to muesli and he's been looking into this. so far so good, from what I hear. |
All good, this one should take a while because this is going to have a huge ripple effect as it updated in the other Charm tools. We likely need a test repository to verify the suite of tools works as expected. But we also need a reference terminal to go with it (crossing fingers Ghostty is near perfect for rendering emojis). Personally, I believe if this is accepted, it may be worth using semantic versions here to indicate breaking changes. That would make it very clear and require applications depending on it to specifically use it. Risk factor would drop to zero as developers are aware that something major has changed. |
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
This implements an ANSI and wide-characters aware truncation algorithm that uses the newly merged [ANSI parser state machine][statemachine] and the fantastic library uniseg. Since this is using the ANSI state machine, it's compatible with `CSI m` (SGR) style sequence, `OSC 8` (hyperlinks), and basically any other escape sequence supported in the state machine (DCS, ESC, SOS, PM, APC). Related: muesli/reflow#71 [statemachine]: https://github.com/charmbracelet/x/blob/main/exp/term/ansi/parser/transition_table.go
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
* feat: switch to term/ansi for text manipulation Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220 * Update get.go
* feat: switch to term/ansi for text manipulation Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220 * fix: combining both conditional and unconditional wrapping Uses `ansi.SmartWrap` charmbracelet/x#57 Fixes: muesli/reflow#43 * chore: update deps * Update get.go
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Use ANSI aware, wide characters support, uniseg backed term/ansi package to calculate string widths, truncate, and wrap strings. Related: muesli/reflow#71 Fixes: #258 Fixes: #220
Withdrawing this pull request as this issue has been resolved for the Charm suite of tools by the creation of the new |
Replace the use of
RuneWidth
andStringWidth
frommattn/go- runewidth
with equivalent functions fromrivo/uniseg
.It is important to be aware that using
RuneWidth
will not be accurate as the width of a rune cannot be determined in isolation. This requires a shift to thinking about grapheme clusters instead.Unfortunately due to the complexity of identifying grapheme clusters, there has been some signifcant performance regressions in two functions:
Two other functions have had performance improvements:
The documentation for
rivo/uniseg
mentions the use ofStep
andStepString
performing "orders of magnitude faster" than using theNewGraphemes
method. However, implementing these changes only resulted in a 10% performance increase.