TurtleGit for Mac

View Markdown source ↗

Compare and Merge word input

Pinned TortoiseGit: 7338078f8ddd924b8cddee35f512f2286072136d. This continuation of pane input covers word movement, Shift selection and word deletion in the actual Compare and Merge text views. It does not certify the full editor.

Source behavior

TortoiseMerge/BaseView.cpp::GetCharGroup, IsWordSeparator, IsCaretAtWordBoundary and MoveCaretWordLeft/Right define word movement by separator transitions. Space, tab, control characters and the configured WordSeparators are separators. Other characters, including an underscore by default, remain letters for this operation. Consecutive punctuation and whitespace form a separator run even though double-click marking distinguishes their groups. A nonempty line edge is a boundary only when its adjacent character is a letter. Empty lines have no word boundary. Word traversal therefore crosses blank and alignment Empty rows until the next boundary or document edge.

The source word-delete handlers first move the caret to that same boundary, then remove the resulting range. An existing selection is removed as selected. RemoveSelectedText normalizes endpoints off Empty alignment rows. Ordinary blank lines and removed/resolved-empty records are not reclassified as alignment gaps. Collapsed marker and hidden rows are skipped as caret destinations while the selected/deleted source span can include their payload.

Native implementation

A shared cached MergePaneInput.WordDocument provides source word geometry for all actual Compare and Merge pane subclasses. Native Option-arrow selectors, forward/backward aliases and their Shift variants retain the original selection anchor. Option-delete selectors and delivered Control-Backspace/Delete events use the same boundaries. macOS composed characters and CRLF are indivisible; invalid interior UTF-16 positions are refused. This deliberately adapts the Windows single-code-unit caret to native text editing.

Every command reads TurtleGitMerge.WordSeparators from its owning preference domain. Preference changes take effect on the next command without rebuilding the document. Source revision and text-change invalidation prevent same-length edits or Undo from retaining stale word geometry. The implementation walks the cached rows and current line rather than repeatedly reconstructing the document for every character step. Plain unaligned text uses the same boundary rules and preserves its real line endings.

Word deletion uses the existing aligned Compare/Merge edit delegates and one Undo transaction. It preserves peer bytes and saved-source ownership. Registered window/pane identity, busy state, sheets, read-only mutation and retirement gates apply before movement or deletion; read-only panes still permit navigation. Marked-text composition continues through AppKit's composition handling.

Validation and remaining work

The grouped native receiver is qa/merge-word-input-native-2026-10-20.swift, invoked by scripts/test-merge-pane-input.py; focused Core tests exercise source boundaries independently of the native adapter. The dated checkpoint records the actual grouped run, the CRLF failure and repair, and final passes: 11 word Core methods plus seven existing pane-input methods, final Debug app, and four native cases on system and bundled Git. Native checks include actual readonly source navigation, same-length edit/Undo cache invalidation, private separator changes, ghost/blank rows, collapsed Compare/Merge deletion with peer preservation and Undo/Redo, selected deletion, aliases and owner refusal. All eight owned receivers were reaped and independently absent. Passed diff/history Core checks were not rerun for the word repair.

Physical keyboard layouts and OS-reserved Control shortcuts, live IME input, VoiceOver, Windows font/page geometry and every possible source state remain separate acceptance work. These commands do not change Find, marking, inline difference tokenization or the selected Git comparison engine.