AppKit: Add RTF list and Unicode support, and preserve rich content during internal copy-paste

The RTF producer and parser lacked support for text lists, failed to encode
non-ASCII characters properly (\uN), and treated first-line indents (\fi) as
absolute values rather than offsets relative to left indents (\li).
Additionally, paste operations ingested application-generated RTF rather than
the native internal archive, causing image attachments and tables to be stripped
during copy-paste workflows within the application.

* AppKit/CPTextView/_CPRTFProducer.j:
  - Implement RTF serialization for text lists using list tables, override tables,
    \levelmarker, \levelprepend, \lsN\ilvlK tags, and \listtext marker blocks.
  - Encode non-ASCII characters via \uc0\uN syntax and compute \fi indents
    relative to \li.
  - Omit image attachment characters from text runs and adjust run starting indices
    to accommodate list markers.

* AppKit/CPTextView/_CPRTFParser.j:
  - Implement pre-pass parsing for list and override tables.
  - Assign shared text lists to items using \ls and \ilvl, extracting marker formats
    from \levelmarker or standard number/level definitions.
  - Parse \uN sequences (skipping fallback characters) and evaluate relative \fi offsets.

* AppKit/CPTextView/CPTextView.j:
  - Configure paste handling to prioritize internal archives when clipboard RTF
    originates from the application, ensuring image attachments and tables survive internal copy-paste.

* AppKit/CPTextView/_CPTableTextAttachment.j:
  - Implement keyed archiving and decoding for table headers, rows, widths,
    and configuration settings, reconstructing cell instances upon unarchiving.

* Tests/AppKit/CPRTFTest.j:
  - Add comprehensive unit tests covering Unicode encoding, relative first-line indents,
    TextEdit and Word list interoperability, and nested list round-trip fidelity.

* Tests/AppKit/CPTextAttachmentTest.j:
  - Add test coverage for table attachment archiving.

* Tests/Manual/TextEditor/WORKLIST.md:
  - Mark intra-application copy and paste testing as completed.
  - Log external rich text exchange limitations as open items.

Intra-application copy and paste now fully preserves images, tables, and lists,
while RTF serialization supports Unicode and structured hierarchical lists.
This commit is contained in:
David Richardson committed 2026-10-24 14:37:57 -06:00
1 parent 3282323053
commit 2b77b98163
7 files changed
+804 -14

No files matched your search

+8 -4
View File
@@ -5040,16 +5040,20 @@ var _CPCopyPlaceholder = '-';
// Can we accept richtext? Then this is our preference (fixme: shift key to force plain text paste)
if ([currentFirstResponder respondsToSelector:@selector(isRichText)] && [currentFirstResponder isRichText])
{
var richtext = nativeClipboard.getData('text/rtf');
var richtext = nativeClipboard.getData('text/rtf'),
richData = [pasteboard stringForType:_CPASPboardType];
// RTF that this application wrote itself, on copy, describes the text on the internal
// pasteboard. The internal archive is pasted instead: it also keeps what RTF does not
// yet carry, such as images.
if (richtext && richData && richtext === [pasteboard stringForType:CPRTFPboardType])
richtext = [CPKeyedUnarchiver unarchiveObjectWithData:[CPData dataWithRawString:richData]];
// prefer RTF form the outside of cappuccino
if (richtext)
else if (richtext)
richtext = [[_CPRTFParser new] parseRTF:richtext];
else
{
// If no RTF is available, try to get the internal represatation of richtext from the pasteboard
var richData = [pasteboard stringForType:_CPASPboardType];
if (richData)
richtext = [CPKeyedUnarchiver unarchiveObjectWithData:[CPData dataWithRawString:richData]];
}