fc-gpui-macos 0.9.0

macOS platform and Metal renderer backend for Adabraka GPUI
Documentation
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};

/// Bindings for NSAttributedString-related APIs used when copying rich text
/// (that is, text intermingled with images) to the clipboard.
#[allow(non_snake_case)]
pub trait NSAttributedString: Sized {
    unsafe fn alloc(_: Self) -> *mut Object {
        msg_send![class!(NSAttributedString), alloc]
    }

    unsafe fn init_attributed_string(self, string: *mut Object) -> *mut Object;
    unsafe fn appendAttributedString_(self, attr_string: *mut Object);
    unsafe fn RTFDFromRange_documentAttributes_(
        self,
        range: super::NSRange,
        attrs: *mut Object,
    ) -> *mut Object;
    unsafe fn RTFFromRange_documentAttributes_(
        self,
        range: super::NSRange,
        attrs: *mut Object,
    ) -> *mut Object;
    unsafe fn string(self) -> *mut Object;
}

impl NSAttributedString for *mut Object {
    unsafe fn init_attributed_string(self, string: *mut Object) -> *mut Object {
        msg_send![self, initWithString: string]
    }

    unsafe fn appendAttributedString_(self, attr_string: *mut Object) {
        let _: () = msg_send![self, appendAttributedString: attr_string];
    }

    unsafe fn RTFDFromRange_documentAttributes_(
        self,
        range: super::NSRange,
        attrs: *mut Object,
    ) -> *mut Object {
        msg_send![self, RTFDFromRange: range documentAttributes: attrs]
    }

    unsafe fn RTFFromRange_documentAttributes_(
        self,
        range: super::NSRange,
        attrs: *mut Object,
    ) -> *mut Object {
        msg_send![self, RTFFromRange: range documentAttributes: attrs]
    }

    unsafe fn string(self) -> *mut Object {
        msg_send![self, string]
    }
}

pub trait NSMutableAttributedString: NSAttributedString {
    unsafe fn alloc(_: Self) -> *mut Object {
        msg_send![class!(NSMutableAttributedString), alloc]
    }
}

impl NSMutableAttributedString for *mut Object {}

#[cfg(test)]
mod tests {
    use super::*;
    use objc::runtime::Object;
    use objc2_foundation::NSSize;
    use std::ptr;

    use crate::mac::{NSRange, ns_string};

    type Id = *mut Object;

    #[allow(non_upper_case_globals)]
    const nil: Id = ptr::null_mut();

    #[test]
    #[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
    fn test_nsattributed_string() {
        // TODO move these to parent module once it's actually ready to be used
        #[allow(non_snake_case)]
        pub trait NSTextAttachment: Sized {
            unsafe fn alloc(_: Self) -> Id {
                msg_send![class!(NSTextAttachment), alloc]
            }
        }

        impl NSTextAttachment for Id {}

        unsafe {
            let image: Id = msg_send![class!(NSImage), alloc];
            let image: Id = msg_send![image, initWithContentsOfFile: ns_string("test.jpeg")];
            let _size: NSSize = msg_send![image, size];

            let string = ns_string("Test String");
            let attr_string = NSMutableAttributedString::alloc(nil).init_attributed_string(string);
            let hello_string = ns_string("Hello World");
            let hello_attr_string =
                NSAttributedString::alloc(nil).init_attributed_string(hello_string);
            attr_string.appendAttributedString_(hello_attr_string);

            let attachment = NSTextAttachment::alloc(nil);
            let _: () = msg_send![attachment, setImage: image];
            let image_attr_string =
                msg_send![class!(NSAttributedString), attributedStringWithAttachment: attachment];
            attr_string.appendAttributedString_(image_attr_string);

            let another_string = ns_string("Another String");
            let another_attr_string =
                NSAttributedString::alloc(nil).init_attributed_string(another_string);
            attr_string.appendAttributedString_(another_attr_string);

            let len: usize = msg_send![attr_string, length];

            ///////////////////////////////////////////////////
            // pasteboard.clearContents();

            let rtfd_data =
                attr_string.RTFDFromRange_documentAttributes_(NSRange::from(0..len), nil);
            assert_ne!(rtfd_data, nil);
            // if rtfd_data != nil {
            //     pasteboard.setData_forType(rtfd_data, NSPasteboardTypeRTFD);
            // }

            // let rtf_data = attributed_string.RTFFromRange_documentAttributes_(
            //     NSRange::new(0, attributed_string.length()),
            //     nil,
            // );
            // if rtf_data != nil {
            //     pasteboard.setData_forType(rtf_data, NSPasteboardTypeRTF);
            // }

            // let plain_text = attributed_string.string();
            // pasteboard.setString_forType(plain_text, NSPasteboardTypeString);
        }
    }
}