-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Add direct system clipboard access via OSC 52 (fixes #45) #57
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
|
Caution Review failedThe pull request is closed. WalkthroughAdds OSC 52 clipboard support: parser Base64 decode and binary paste events, Screen API for set/get clipboard, VtScreen Base64 encode/request implementation, and a new clipboard demo demonstrating set/get and paste handling. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Demo App
participant Scr as Screen API
participant VT as VtScreen
participant Term as Terminal
participant Parser as Parser
rect rgb(240,248,255)
Note over App,Term: Set clipboard (App → terminal)
App->>Scr: setClipboard(data)
Scr->>VT: setClipboard(data)
VT->>VT: Base64 encode data
VT->>Term: emit OSC 52 set sequence
end
rect rgb(240,248,255)
Note over App,Term: Get clipboard (request → response)
App->>Scr: getClipboard()
Scr->>VT: getClipboard()
VT->>Term: emit OSC 52 request ("?")
Term-->>Parser: OSC 52 response (Base64 payload)
Parser->>Parser: Base64 decode → binary or text
Parser-->>App: enqueue PasteEvent(binary or string)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related issues
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (6)
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: 2
🧹 Nitpick comments (3)
source/dcell/vt.d (1)
559-575: Consider adding a size limit for clipboard data.Large clipboard data could result in extremely long escape sequences. Some terminals have limits on OSC sequence length (commonly 100KB-1MB). Consider documenting this limitation or adding a size guard.
That said, the implementation is correct and functional as-is. The guard on
vt.setClipboard.emptyproperly handles legacy terminals.demos/clipboard/source/clipboard.d (2)
11-11: Use a more appropriate module name for the clipboard demo
module hello;is misleading for a clipboard demo and may also clash with other simple examples. Consider renaming it to better reflect the file path / purpose, e.g.:-module hello; +module clipboard;(or a more fully‑qualified name consistent with how demos are organized in this repo).
50-59: Avoid mutating stored clipboard content when truncating for display
display()truncatescontentin place:if (content.length >= 40) { content = content[0 .. 36] ~ " ..."; }This permanently shortens the stored clipboard text after the first render. Prefer keeping the full value and only truncating a temporary copy for display:
- auto msg = "No clipboard data"; - if (!content.empty) - { - auto len = content.length; - if (content.length >= 40) - { - content = content[0 .. 36] ~ " ..."; - } - msg = format("Clipboard (length %d): %s", len, content); - } + auto msg = "No clipboard data"; + if (!content.empty) + { + auto len = content.length; + auto shown = content; + if (shown.length >= 40) + { + shown = shown[0 .. 36] ~ " ..."; + } + msg = format("Clipboard (length %d): %s", len, shown); + }This preserves the full clipboard text while still rendering a shortened version.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
demos/clipboard/dub.json(1 hunks)demos/clipboard/source/clipboard.d(1 hunks)source/dcell/event.d(1 hunks)source/dcell/parser.d(5 hunks)source/dcell/screen.d(1 hunks)source/dcell/vt.d(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-15T05:12:35.344Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 56
File: source/dcell/vt.d:2-2
Timestamp: 2025-12-15T05:12:35.344Z
Learning: In D (as used in gdamore/dcell), an enum-type variable like Attr attr can be referred to in case statements using either attr.EnumMember or Attr.EnumMember due to aliasing. For consistency and readability, prefer using the type name (Attr.EnumMember) in case statements instead of the lowercase variable name (attr.EnumMember). This guideline applies to D files across the repository (source/**/*.d or any .d files).
Applied to files:
source/dcell/event.ddemos/clipboard/source/clipboard.dsource/dcell/screen.dsource/dcell/parser.dsource/dcell/vt.d
📚 Learning: 2025-12-08T19:17:33.678Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 27
File: source/dcell/ttyscreen.d:448-494
Timestamp: 2025-12-08T19:17:33.678Z
Learning: In source/dcell/ttyscreen.d, Color.reset is defined as a value above the range of valid colors. In the sendColors() function, after emitting the reset sequence (vt.resetFgBg), Color.reset values naturally skip all subsequent color-setting logic (isRGB checks and palette range checks < 8, < 256) because they are out of range, which is the correct behavior by design.
Applied to files:
source/dcell/vt.d
🔇 Additional comments (5)
source/dcell/event.d (1)
61-67: LGTM! Clear struct design for dual-mode paste data.The mutual exclusivity of
contentandbinaryis well-documented. The change fromdstringtostringforcontentaligns with the OSC 52 binary pathway where UTF-8 string data is more common.demos/clipboard/dub.json (1)
1-12: LGTM! Standard demo manifest configuration.The DUB configuration follows the expected pattern for demo executables within the repository.
source/dcell/screen.d (1)
271-288: LGTM! Well-designed clipboard API with appropriate security notes.The asynchronous design for
getClipboard()returning data viaPasteEventis appropriate for terminal I/O. The documentation appropriately warns about security considerations and terminal restrictions.source/dcell/parser.d (1)
1209-1227: LGTM! Clean overloaded event constructors.The two
newPasteEventoverloads correctly handle the string and binary pathways, following the established pattern for event creation in this module.source/dcell/vt.d (1)
123-128: LGTM! Correct OSC 52 sequence format.The OSC 52 format string
"\x1b]52;c;%s\x1b\\"follows the standard clipboard sequence specification correctly, withcindicating the clipboard selection.
6c9ec97 to
5138122
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: 2
🧹 Nitpick comments (1)
demos/clipboard/source/clipboard.d (1)
67-70: Remove unused import.
core.stdc.stdlib : exitis imported but never used.void handleEvent(Event ev) { - import core.stdc.stdlib : exit; - switch (ev.type)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
demos/clipboard/dub.json(1 hunks)demos/clipboard/source/clipboard.d(1 hunks)source/dcell/event.d(1 hunks)source/dcell/parser.d(5 hunks)source/dcell/screen.d(1 hunks)source/dcell/vt.d(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- demos/clipboard/dub.json
- source/dcell/screen.d
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-15T05:12:35.344Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 56
File: source/dcell/vt.d:2-2
Timestamp: 2025-12-15T05:12:35.344Z
Learning: In D (as used in gdamore/dcell), an enum-type variable like Attr attr can be referred to in case statements using either attr.EnumMember or Attr.EnumMember due to aliasing. For consistency and readability, prefer using the type name (Attr.EnumMember) in case statements instead of the lowercase variable name (attr.EnumMember). This guideline applies to D files across the repository (source/**/*.d or any .d files).
Applied to files:
source/dcell/parser.ddemos/clipboard/source/clipboard.dsource/dcell/event.dsource/dcell/vt.d
📚 Learning: 2025-12-08T19:17:33.678Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 27
File: source/dcell/ttyscreen.d:448-494
Timestamp: 2025-12-08T19:17:33.678Z
Learning: In source/dcell/ttyscreen.d, Color.reset is defined as a value above the range of valid colors. In the sendColors() function, after emitting the reset sequence (vt.resetFgBg), Color.reset values naturally skip all subsequent color-setting logic (isRGB checks and palette range checks < 8, < 256) because they are out of range, which is the correct behavior by design.
Applied to files:
source/dcell/vt.d
🔇 Additional comments (7)
source/dcell/parser.d (2)
665-676: LGTM! Exception handling for Base64 decoding is now in place.The OSC 52 clipboard response handling correctly:
- Detects the
52;c;prefix- Strips the prefix before decoding
- Wraps
Base64.decodein a try-catch to gracefully handle malformed clipboard data
1215-1233: LGTM! Clean overloads for string vs binary paste data.The two
newPasteEventoverloads correctly separate:
- String content path (from bracketed paste mode)
- Binary data path (from OSC 52 clipboard response)
This aligns well with the updated
PasteEventstruct.source/dcell/vt.d (3)
123-128: LGTM! OSC 52 clipboard format string is correct.The OSC 52 sequence format
\x1b]52;c;%s\x1b\\follows the standard:
\x1b]- OSC introducer52- clipboard operationc- system clipboard selection%s- Base64 payload (or?for query)\x1b\\- ST (String Terminator)
559-575: LGTM! Clipboard methods correctly implement OSC 52 set/get.
setClipboardencodes data as Base64 and sends it via OSC 52.getClipboardsends a query (?) and the response will arrive asynchronously as aPasteEventwith binary data.
257-257: LGTM! Correctly disables clipboard for legacy terminals.demos/clipboard/source/clipboard.d (1)
93-110: LGTM! Binary paste handling correctly usesidupfor safe string conversion.The past review concern about buffer aliasing has been addressed. Using
chars.idupcreates an owned immutable copy, ensuringcontentdoesn't alias the event buffer.source/dcell/event.d (1)
61-67: LGTM! Clean struct extension for binary clipboard data.The
PasteEventupdate correctly:
- Maintains
contentasstring(compatible with all current usages)- Adds
binaryfield for raw clipboard data from OSC 52- Documents the mutual exclusivity in the comment
All downstream usages of
paste.contentin the codebase are compatible with thestringtype, including in test assertions, clipboard demo, and mouse demo code.
| auto msg = "No clipboard data"; | ||
| if (!content.empty) | ||
| { | ||
| auto len = content.length; | ||
| if (content.length >= 40) | ||
| { | ||
| content = content[0 .. 36] ~ " ..."; | ||
| } | ||
| msg = format("Clipboard (length %d): %s", len, content); | ||
| } |
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.
Bug: Content truncation mutates the class field permanently.
The truncation logic modifies content in place. On each display() call, if content.length >= 40, it gets truncated again. This corrupts the stored clipboard data.
Use a local variable for display:
auto msg = "No clipboard data";
if (!content.empty)
{
auto len = content.length;
- if (content.length >= 40)
- {
- content = content[0 .. 36] ~ " ...";
- }
- msg = format("Clipboard (length %d): %s", len, content);
+ auto displayContent = content;
+ if (displayContent.length >= 40)
+ {
+ displayContent = displayContent[0 .. 36] ~ " ...";
+ }
+ msg = format("Clipboard (length %d): %s", len, displayContent);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| auto msg = "No clipboard data"; | |
| if (!content.empty) | |
| { | |
| auto len = content.length; | |
| if (content.length >= 40) | |
| { | |
| content = content[0 .. 36] ~ " ..."; | |
| } | |
| msg = format("Clipboard (length %d): %s", len, content); | |
| } | |
| auto msg = "No clipboard data"; | |
| if (!content.empty) | |
| { | |
| auto len = content.length; | |
| auto displayContent = content; | |
| if (displayContent.length >= 40) | |
| { | |
| displayContent = displayContent[0 .. 36] ~ " ..."; | |
| } | |
| msg = format("Clipboard (length %d): %s", len, displayContent); | |
| } |
🤖 Prompt for AI Agents
In demos/clipboard/source/clipboard.d around lines 50 to 59, the display() code
truncates the class field content in place which mutates stored clipboard data
on each call; fix by using a local variable (e.g., auto displayContent =
content) for any truncation/formatting and leave the original content untouched,
then build msg from that local variable; ensure you do not assign back to the
field and preserve its length/value.
5138122 to
77b5d73
Compare
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.