Repository navigation
Markdown: a transcript owns its text selection, in document order - #1009
Merged
Merged
Conversation
gpui-base's window text selection served Markdown for the whole window: every left press anywhere cleared it and began a gesture, one gesture spanned every pane, and a gesture ended only from a release that reached the root in the bubble phase. A drop target stops that release, so a thread dragged from the sidebar and dropped on a pane left a selection following the pointer across every chat view. It also selected by screen geometry, so a table was read row band by row band instead of cell by cell. A document now owns its selection. The chat transcript is one document, each message an entry at its timeline index; a standalone selectable view is its own. Only a press on the document's area begins a selection, the drag and the release are heard in the capture phase, and the ends are positions in the text (render path, code line, byte offset), so highlight and copy read the same range: a table cell by cell along its rows, cells joined by tabs, and messages never painted copied from the timeline. Touch keeps the long press, handles, edit menu and pan behaviour, drawn by the document. The workarounds that existed only for the window selection go: the gpui-base participant bridge, painted-selection storage, residency pinning of selection participants, stop_click_propagation, the titlebar's default prevention and the input's window-selection clear.
…hanged A double or triple click takes what gpui-base's multi-click took: the character under the pointer, words of ASCII, Latin or Cyrillic letters with every other character (each CJK character) its own word, the line within a paragraph, and no extension by a later drag. A long press drags its far end from the word's start by character. Copy trims as the root's Copy did, a touch handle whose end is clipped is not drawn, and a titlebar press keeps the focus where it was.
The chat view holds a focus handle over everything it draws, the composer included, and clears the transcript's selection when the focus leaves it; a standalone view clears its own selection when the focus leaves the view. A press on something outside that takes no focus leaves the selection, one that takes the focus puts it away.
gpui-base's multi-click rule makes every CJK character a word of its own. A double-click or long press now asks the platform's own segmentation through the client host: Core Foundation's tokenizer on Apple platforms, the ICU Windows ships (loaded on first use, so a Windows without it still starts), the browser's Intl.Segmenter, Android's Java ICU through the activity, and on Linux, which no system segmenter is certain to be on, a bundled dictionary. Where none answers, gpui-base's rule stays.
…the deprecated Env ones
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.
Summary
Drop gpui-base's window-wide text selection for Markdown; a document owns it instead. The chat transcript is one document whose entries are its messages (at their timeline index). A selectable view outside a transcript, such as a PR comment, is a document of its own.
What changes for a reader:
\twhen copied (previously a space), so a pasted table splits into columns in a spreadsheet.Intl.Segmenterin a browser, Android's Java ICU through the activity, and a bundled ICU4X dictionary on Linux only, which has no system segmenter every install carries. Where none answers, gpui-base's rule. Otherwise double and triple click match the window selection: the character under the pointer, the line within a paragraph, no extension by a later drag.Removed because only the window selection needed them:
stop_click_propagation(now plainstop_propagation), the titlebar'sprevent_default/suppress_text_selection(added in 97034b2 for this), the input'sTextSelection::clearon long press,WindowTouchSelectionOverlay, the touch-UI registration plumbing, andSelectAllTouched.Evidence
Hello world, a drop on a target, then the free pointer crossing the text:TextSelection::selected_text="Hello wor".After:
a_drag_and_drop_across_the_text_leaves_nothing_selected→"".a_drag_through_a_table_takes_each_cell_whole_before_the_next: a cell wrapped over several rows, dragged to the cell beside its first row → the whole first cell +\t+x.a_drag_ending_off_the_code_lines_ends_at_the_nearest_line.nodes.rs): document order, cells, edge-only segments.<whole cell>\tOwn.cargo fmt --check,cargo clippy --workspace --all-targets -D warnings, andcargo nextest run --workspace(1351 passed) on macOS. Not run: Windows by hand, phone/iPad touch on a device, the mobile/Web checks (left to CI).Tests met in this area:
a_scroll_jump_mid_drag_drops_text_left_behinddrag_auto_scrolls_at_viewport_edge_not_participant_edgea_drag_scrolls_at_the_viewport_edge_not_the_message_edge. It caught a real bug in the port: the viewport must be the clip, not the view's bounds. Fails with the old choice.text_wrapping_after_an_inline_image_paints_on_its_own_rowslong_press_on_a_message_offers_copy_and_select_all_past_the_viewport,one_touch_selection_at_a_time_and_the_menu_steps_aside_for_a_panselection.rs. Pan hiding was missing until this port.long_press_release_keeps_handles_which_drag_the_selectiondrag_copies_exactly_the_highlighted_text,a_drag_ending_off_the_code_lines_copies_what_it_highlightsextraction_*(nodes.rs)text_betweentests.press_on_titlebar_drag_area_does_not_start_selection,click_that_stops_propagation_does_not_leave_selection_following_pointertext_bounds_cover_one_rect_per_visual_linerunning_tail_and_selection_pins_are_honoredthe_running_tail_stays_resident; selection pinning is gone.Added after the first push:
the_selection_goes_when_the_focus_leaves_the_text,a_double_click_on_chinese_takes_the_word_the_platform_segments, and intcode-clientthe_system_segmenter_finds_chinese_wordsplus a UTF-16 offset test. The Android segmenter is checked only by CI (no NDK here); its JNI calls were type-checked against jni 0.22.4 on their own.Merge Danger
Door: two-way
Self-contained in
crates/ui. No wire, persistence or protocol change.Blast Radius: selection
Every Markdown selection path changes (mouse, keyboard Copy/Select All, the context menu, touch), and so does every click handler that used
stop_click_propagation. The likeliest regressions are on platforms not exercised here: Windows mouse input and touch on a real device.