-
Notifications
You must be signed in to change notification settings - Fork 3
chore: optimizations around the cells #47
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
Conversation
WalkthroughRefactors Cell to store text and display width privately ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
source/dcell/cell.d (1)
62-68: Width docs/control handling don’t match behavior (0-width + DEL)
- The doc says width will be 1 or 2, but code/tests allow 0 for empty/control (
'\t'=> 0). Update the comment to include 0.calcWidth()treats DEL (0x7F) as width 1; it’s typically a control character and should likely be 0-width like other controls.- if (ss.length < 1 || ss[0] < ' ') // empty or control characters + if (ss.length < 1 || ss[0] < ' ' || ss[0] == 0x7F) // empty or control characters (incl DEL) { return (0); }Also applies to: 84-91
🧹 Nitpick comments (1)
source/dcell/cell.d (1)
79-104: Clamp/checkdisplayWidth()result before narrowing toubyte
return cast(ubyte) displayWidth(d[0]);will silently wrap ifdisplayWidth()ever returns a negative or a value > 255. Even if “shouldn’t happen”, a defensive clamp makes failures predictable (esp. with emoji/variation selectors where libraries disagree).- return cast(ubyte) displayWidth(d[0]); + auto w = displayWidth(d[0]); + if (w <= 0) return 0; + if (w >= 2) return 2; + return 1;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
source/dcell/cell.d(6 hunks)
🔇 Additional comments (1)
source/dcell/cell.d (1)
36-48: Good caching change, but consider keepingwidth()return type for API stabilityYou’re already saving per-cell space by caching
ubyte dw; changing the public property type toubyteis an unnecessary breaking change for downstream code (and can cause overload/formatting surprises). Consider keeping the cached storage asubyte, but returninguint(orsize_t) from the property.- @property ubyte width() const pure @safe + @property uint width() const pure @safe { - return dw; + return dw; }Likely an incorrect or invalid review comment.
a3166a5 to
2038985
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
source/dcell/cell.d (1)
55-60:textsetter should normalize input viatoUTF8()like the constructors do.The constructors use
toUTF8(s)(line 45) but the setter stores input directly. If invalid UTF-8 is passed,calcWidth()will calltoUTF32(ss)which throws, and the exception may not be handled appropriately at the call site.@property const(string) text(const(string) s) pure @safe { - ss = s; + ss = toUTF8(s); dw = calcWidth(); return s; }
🧹 Nitpick comments (1)
source/dcell/cell.d (1)
85-119: Consider exception handling incalcWidth()for robustness.The function is marked
pure @safebut can throw in two places:
- Line 98:
toUTF32(ss)throwsUTFExceptionon malformed UTF-8- Line 104:
enforce(d.length > 0)throws if the condition failsSince
calcWidth()is called from setters and constructors, an exception here propagates to the caller. This is fine if the invariant is thatssis always valid UTF-8 (maintained by constructors), but thetextsetter currently doesn't enforce this (see earlier comment).The
enforceat line 104 appears defensive—after line 90's check,toUTF32on a non-empty string with a printable first byte should always produce a non-empty result. If it's truly unreachable, consider usingassertinstead to document the invariant without runtime cost in release builds.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
source/dcell/cell.d(6 hunks)
🔇 Additional comments (2)
source/dcell/cell.d (2)
36-48: LGTM!Both constructors properly normalize input via
toUTF8()and then compute width once usingcalcWidth(). This aligns with the PR's optimization goal of calculating width only once.
75-78: Return type changed fromuinttoubyte— no compatibility issues found.The width property now returns
ubyteinstead ofuint. Analysis of all callers (4 in ttyscreen.d and multiple unit tests in cell.d) shows only implicit conversions and arithmetic operations that are fully compatible withubyte. D handles the conversion seamlessly in all contexts: returns toint, additions withint, compound assignments, and comparisons with literals.
Specifically we pre-cache the width so it is only calculated once, and we eliminate some unused and redundant string storage.
2038985 to
dd315f5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
source/dcell/cell.d (1)
14-14: Remove unused import.The
std.exceptionimport doesn't appear to be used in this file. ThetoUTF32andtoUTF8calls are fromstd.utfand don't require this import.-import std.exception;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
source/dcell/cell.d(6 hunks)
🔇 Additional comments (5)
source/dcell/cell.d (5)
36-48: LGTM!The constructors correctly initialize the new private storage (
ssanddw) and usecalcWidth()to pre-compute the display width. This aligns with the PR's optimization goals.
55-60: LGTM!The text setter now normalizes input via
toUTF8(s)(consistent with the constructors) and recalculates the cached width. This addresses the previous review concern while maintaining the performance-oriented design.
62-78: LGTM!The width property refactoring delivers the PR's optimization goals: returning the pre-cached
dwfield avoids repeated calculation. The type change fromuinttoubyteis appropriate given the valid range (0-2), and adding@safeimproves memory safety guarantees.
122-145: LGTM!The unit test updates appropriately cover the refactored width calculation:
- Control characters and empty strings correctly expect width 0
- Expanded coverage for emoji sequences and skin tone modifiers
- The past review concerns about duplicate assertions have been addressed
The commented-out ZWJ test at line 144 acknowledges a known limitation with the current implementation/library combination.
85-119: Implementation looks sound; verify library version if considering updates.The
calcWidth()logic is correct with appropriate fast paths for empty/control/ASCII cases and defensive clamping for the east_asian_width library. The current version 1.0.0 works as intended. If you plan to update to version 1.1.0 (available since 2017), test edge cases like emoji and regional indicators to ensure behavior remains consistent.
Specifically we pre-cache the width so it is only calculated once, and we eliminate some unused and redundant string storage.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.