Expose core unicode display-width to plugins (charWidth/stringWidth)#2401
Merged
Conversation
…h/stringWidth)
Adds a single source of truth for terminal display width in `fresh-core`
(`display_width::{char_width, str_width}`, backed by the `unicode-width`
crate) and exposes it to plugins as `editor.charWidth(codePoint)` and
`editor.stringWidth(text)`.
Why: plugins currently have to re-derive their own Unicode width tables (e.g.
markdown_compose's hand-rolled `charDisplayWidth`), which inevitably drift from
how the editor itself measures cells. With this, a plugin measures width with
the exact same logic the renderer uses for layout and cursor positioning — so
column widths, wrapping, and alignment agree by construction.
- `fresh-core::display_width` is now canonical; `fresh-editor`'s
`primitives::display_width` re-exports `char_width`/`str_width` from it
(its byte/column helpers and the `DisplayWidth` trait are unchanged), so
there's one implementation, not two.
- The plugin runtime calls the core function directly (pure, no command
round-trip), matching the existing synchronous backend methods.
No behavior change to the editor; this only adds APIs. The follow-up
markdown-compose PR will use these to delete its duplicated width table
(addresses @sinelaw's review note on sinelaw#2325).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
A single source of truth for terminal display width and two plugin APIs built on it:
fresh-core::display_width::{char_width, str_width}— backed by theunicode-widthcrate.editor.charWidth(codePoint: number): number— width of one code point (0 for control/zero-width, 2 for CJK/fullwidth and most emoji, else 1).editor.stringWidth(text: string): number— width of a whole string.Why
This directly addresses @sinelaw's review note on #2325:
Plugins otherwise have to re-derive their own Unicode width tables (e.g. markdown_compose's hand-rolled
charDisplayWidth), which inevitably drift from how the editor actually measures cells. With these APIs a plugin measures width with the exact same logic the renderer uses for layout and cursor positioning, so column widths, wrapping, and alignment agree by construction.Design
fresh-core::display_widthis now canonical.fresh-editor'sprimitives::display_widthre-exportschar_width/str_widthfrom it (its byte↔column helpers and theDisplayWidthtrait are unchanged), so there is one implementation rather than two copies.fresh-core(notfresh-editor) because the plugin runtime —fresh-plugin-runtime, whichfresh-editordepends on, not the reverse — needs to call it. The runtime invokes the core function directly (pure, no command round-trip), matching the existing synchronous backend methods.fresh.d.tsupdated with the two methods;ts_exportAPI-surface list updated. (Only the two additions are infresh.d.ts— I deliberately avoided a full regenerate, which would have pulled in unrelated pre-existing drift between the committed file and the generator.)Risk
Low. Purely additive APIs; the editor's own width behavior is unchanged (the re-export is the identical
unicode-widthcall it already made).Tests / CI (all green locally)
fmt,clippy --all-features --all-targets,doc(nightly), schema diff,check --no-default-features --features runtime, plus unit tests for the new core module, the editor re-export, and thets_exportAPI-present / generated-.d.ts-validates tests (now coveringcharWidth/stringWidth).Split out of #2325 (closed) as one of the non-graphics pieces. Independent of the other splits — branches from
master. The follow-up markdown-compose PR will consume these to delete its duplicatedcharDisplayWidthtable.