Skip to content

Add clipboard shortcuts to immediate text fields - #41

Open
struckchure wants to merge 2 commits into
vlang:masterfrom
struckchure:immediate-text-clipboard
Open

struckchure wants to merge 2 commits into
vlang:masterfrom
struckchure:immediate-text-clipboard

Conversation

@struckchure

Copy link
Copy Markdown

Summary

  • Cmd/Ctrl+C, X and V now copy, cut and paste in the focused text field of the immediate renderer; single-line fields receive pasted newlines as spaces.
  • handle_char_input now takes the event modifiers and drops the chord's letter, which macOS (Cmd+V'v') and X11 (Ctrl+V'v') both deliver as a char event. Ctrl+Alt passes through because Windows reports AltGr that way and AltGr characters (@, , …) are real text. macOS Backspace (0x7F) is dropped too.
  • The clipboard is a single lazily-created instance (system_clipboard()). On X11 the clipboard window holds CLIPBOARD selection ownership, so a per-keystroke new()/destroy() would surrender it immediately and also leak a display connection and listener thread per press.

Test plan

  • v fmt -verify and v -d ui2_custom_rendering -check ui/ pass
  • macOS (custom rendering): Cmd+C/X/V in a text field and text area; Cmd+V does not insert a stray v; Backspace does not insert DEL
  • Linux: Ctrl+C/X/V; cut text is pasteable afterwards; repeated shortcuts do not exhaust X connections
  • Windows (custom rendering, non-US layout): AltGr characters still type

Cmd/Ctrl+C, X and V now copy, cut and paste in the focused text field
of the immediate renderer, with pasted newlines flattened to spaces in
single-line fields.

Char events are filtered by modifier so the chord's letter is not also
inserted as text: macOS delivers 'v' for Cmd+V and X11 delivers it for
Ctrl+V. Ctrl+Alt is deliberately allowed through because Windows
reports AltGr that way and AltGr characters are genuine text. macOS
Backspace (reported as 0x7F) is dropped as well.

The clipboard is a single lazily-created instance: on X11 the clipboard
window owns the CLIPBOARD selection, so a per-keystroke instance that
is destroyed right after copying would hand ownership back to nobody.

@medvednikov medvednikov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changed input handlers, editor state updates, existing custom-renderer tests, and V's clipboard implementations. Two actionable findings are inline: cut must preserve the selection when the clipboard write fails, and the newly required character-event modifier argument needs to be supplied by the existing test caller.

Validation: source-level review only; I could not run V compilation or platform clipboard tests in this environment. The one-argument handle_key_down calls in the same test already exist in the base commit and are not counted as regressions introduced by this PR.

Comment thread ui/ui_immediate.c.v Outdated
Comment on lines +1288 to +1289
cb.copy(selected)
editor.replace_selection('')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Preserve selected text when the clipboard write fails

clipboard.Clipboard.copy() returns a success boolean, but this branch deletes the selection regardless of that result. For example, V's Windows backend returns false when it cannot acquire the clipboard lock or SetClipboardData fails; Ctrl+X would then remove the user's text and fire the change event without putting that text on the clipboard. Please only call replace_selection and publish the editor/change updates after a successful copy (for example, return true without changing the editor when !cb.copy(selected)). A failed-copy regression test should assert that both the text and selection are preserved.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e1c0875. Cut now only edits the field after cb.copy() returns true; on failure the text and selection stay untouched and no change event fires.

To make that testable without the system clipboard, the shortcut handler reads through a small TextClipboard interface (copy/paste) and tests install a fake via g_clipboard_override. test_cut_keeps_the_text_when_the_clipboard_rejects_it asserts the text, the selection range and the absence of a change event; I verified it fails against the previous unconditional cut.

Comment thread ui/ui_immediate.c.v
}

fn handle_char_input(ch u32) {
fn handle_char_input(ch u32, modifiers u32) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Update the existing test caller for the new required argument

test_custom_text_editor_replaces_owned_state_after_caret_moves in ui/ui_custom_test.v still calls handle_char_input(x) with one argument. With ui2_custom_rendering enabled, this signature change introduces an additional test-compilation error because modifiers is now required. Please update that call to handle_char_input(x, 0) and exercise the modifier-filtering cases here as well (Ctrl/Super shortcut characters are suppressed, Ctrl+Alt text is retained, and DEL is ignored). The reported -check ui/ verification does not exercise this _test.v caller.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e1c0875, with one wrinkle: ui_custom_test.v can't compile regardless of the argument count. It sorts before ui_immediate.c.v, so it never sees the renderer globals (g_text_values, g_focused_field, …), it doesn't import gg for the key codes, and its typed map[string]bool{ ... } literals are rejected by 0.5.2 too. It isn't in CI, which is why nobody noticed.

Rather than patch the one call in a file that still can't build, I moved the caret-move test into a new ui/ui_text_clipboard_immediate_test.v that follows the ui_pointer_capture_immediate_test.v pattern (sorts after the renderer, @[has_globals], same platform guard). Besides the original assertion it covers:

  • handle_char_input: Ctrl+V / Cmd+V / Ctrl+Shift+V letters are dropped, DEL (127) and BS (8) are dropped, Ctrl+Alt @ (AltGr) and Shift+a are kept, and change events fire only for real insertions
  • copy/cut/paste through the fake clipboard, newline flattening in single-line fields vs. text areas, empty-paste being a no-op, and chords without the primary modifier not touching the clipboard

CI runs the new file on the same matrix entries as the scrolling test. I left the rest of ui_custom_test.v alone since that's unrelated to this PR; happy to fix it up separately.

clipboard.Clipboard.copy reports failure (the Windows backend returns
false when it cannot lock the clipboard or SetClipboardData fails), but
Ctrl+X removed the selected text regardless, so a failed cut destroyed
the user's text without putting it anywhere. The cut now only edits the
field after a successful copy.

The shortcut handler reads the clipboard through a small TextClipboard
interface, and tests install a fake via g_clipboard_override. The new
ui_text_clipboard_immediate_test.v covers copy, cut, paste, the failed
copy, newline flattening in single-line fields, the modifier filtering
in handle_char_input (Ctrl/Super chord letters and DEL dropped, Ctrl+Alt
text kept), and the caret-move test that used to live in
ui_custom_test.v with a now-stale one-argument call. That file sorts
before ui_immediate.c.v so it cannot see the renderer globals at all;
the test moved to a file that can. CI runs the new test on the same
matrix entries as the scrolling test.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants