attributed_string.rs

  1use cocoa::base::id;
  2use cocoa::foundation::NSRange;
  3use objc::{class, msg_send, sel, sel_impl};
  4
  5/// The `cocoa` crate does not define NSAttributedString (and related Cocoa classes),
  6/// which are needed for copying rich text (that is, text intermingled with images)
  7/// to the clipboard. This adds access to those APIs.
  8#[allow(non_snake_case)]
  9pub trait NSAttributedString: Sized {
 10    unsafe fn alloc(_: Self) -> id {
 11        msg_send![class!(NSAttributedString), alloc]
 12    }
 13
 14    unsafe fn init_attributed_string(self, string: id) -> id;
 15    unsafe fn appendAttributedString_(self, attr_string: id);
 16    unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id;
 17    unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id;
 18    unsafe fn string(self) -> id;
 19}
 20
 21impl NSAttributedString for id {
 22    unsafe fn init_attributed_string(self, string: id) -> id {
 23        msg_send![self, initWithString: string]
 24    }
 25
 26    unsafe fn appendAttributedString_(self, attr_string: id) {
 27        let _: () = msg_send![self, appendAttributedString: attr_string];
 28    }
 29
 30    unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id {
 31        msg_send![self, RTFDFromRange: range documentAttributes: attrs]
 32    }
 33
 34    unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id {
 35        msg_send![self, RTFFromRange: range documentAttributes: attrs]
 36    }
 37
 38    unsafe fn string(self) -> id {
 39        msg_send![self, string]
 40    }
 41}
 42
 43pub trait NSMutableAttributedString: NSAttributedString {
 44    unsafe fn alloc(_: Self) -> id {
 45        msg_send![class!(NSMutableAttributedString), alloc]
 46    }
 47}
 48
 49impl NSMutableAttributedString for id {}
 50
 51#[cfg(test)]
 52mod tests {
 53    use crate::platform::mac::ns_string;
 54
 55    use super::*;
 56    use cocoa::appkit::NSImage;
 57    use cocoa::base::nil;
 58    use cocoa::foundation::NSAutoreleasePool;
 59    #[test]
 60    #[ignore] // This was SIGSEGV-ing on CI but not locally; need to investigate https://github.com/zed-industries/zed/actions/runs/10362363230/job/28684225486?pr=15782#step:4:1348
 61    fn test_nsattributed_string() {
 62        // TODO move these to parent module once it's actually ready to be used
 63        #[allow(non_snake_case)]
 64        pub trait NSTextAttachment: Sized {
 65            unsafe fn alloc(_: Self) -> id {
 66                msg_send![class!(NSTextAttachment), alloc]
 67            }
 68        }
 69
 70        impl NSTextAttachment for id {}
 71
 72        unsafe {
 73            let image: id = {
 74                let img: id = msg_send![class!(NSImage), alloc];
 75                let img: id = msg_send![img, initWithContentsOfFile: ns_string("test.jpeg")];
 76                let img: id = msg_send![img, autorelease];
 77                img
 78            };
 79            let _size = image.size();
 80
 81            let string = ns_string("Test String");
 82            let attr_string = NSMutableAttributedString::alloc(nil)
 83                .init_attributed_string(string)
 84                .autorelease();
 85            let hello_string = ns_string("Hello World");
 86            let hello_attr_string = NSAttributedString::alloc(nil)
 87                .init_attributed_string(hello_string)
 88                .autorelease();
 89            attr_string.appendAttributedString_(hello_attr_string);
 90
 91            let attachment: id = msg_send![NSTextAttachment::alloc(nil), autorelease];
 92            let _: () = msg_send![attachment, setImage: image];
 93            let image_attr_string =
 94                msg_send![class!(NSAttributedString), attributedStringWithAttachment: attachment];
 95            attr_string.appendAttributedString_(image_attr_string);
 96
 97            let another_string = ns_string("Another String");
 98            let another_attr_string = NSAttributedString::alloc(nil)
 99                .init_attributed_string(another_string)
100                .autorelease();
101            attr_string.appendAttributedString_(another_attr_string);
102
103            let _len: cocoa::foundation::NSUInteger = msg_send![attr_string, length];
104
105            ///////////////////////////////////////////////////
106            // pasteboard.clearContents();
107
108            let rtfd_data = attr_string.RTFDFromRange_documentAttributes_(
109                NSRange::new(0, msg_send![attr_string, length]),
110                nil,
111            );
112            assert_ne!(rtfd_data, nil);
113            // if rtfd_data != nil {
114            //     pasteboard.setData_forType(rtfd_data, NSPasteboardTypeRTFD);
115            // }
116
117            // let rtf_data = attributed_string.RTFFromRange_documentAttributes_(
118            //     NSRange::new(0, attributed_string.length()),
119            //     nil,
120            // );
121            // if rtf_data != nil {
122            //     pasteboard.setData_forType(rtf_data, NSPasteboardTypeRTF);
123            // }
124
125            // let plain_text = attributed_string.string();
126            // pasteboard.setString_forType(plain_text, NSPasteboardTypeString);
127        }
128    }
129}