[go: up one dir, main page]

gtk4/
text_buffer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, mem::transmute, slice, str};
4
5use glib::{
6    signal::{connect_raw, SignalHandlerId},
7    translate::*,
8};
9use libc::{c_char, c_int};
10
11use crate::{ffi, prelude::*, TextBuffer, TextIter, TextTag};
12
13#[cfg(feature = "v4_16")]
14use crate::TextBufferNotifyFlags;
15
16// rustdoc-stripper-ignore-next
17/// Trait containing manually implemented methods of
18/// [`TextBuffer`](crate::TextBuffer).
19pub trait TextBufferExtManual: IsA<TextBuffer> + 'static {
20    // rustdoc-stripper-ignore-next
21    /// # Panics
22    ///
23    /// If the properties don't exists or are not writeable.
24    #[doc(alias = "gtk_text_buffer_create_tag")]
25    fn create_tag(
26        &self,
27        tag_name: Option<&str>,
28        properties: &[(&str, &dyn ToValue)],
29    ) -> Option<TextTag> {
30        let tag = TextTag::new(tag_name);
31        tag.set_properties(properties);
32        if self.as_ref().tag_table().add(&tag) {
33            Some(tag)
34        } else {
35            None
36        }
37    }
38
39    #[doc(alias = "gtk_text_buffer_insert_with_tags")]
40    fn insert_with_tags(&self, iter: &mut TextIter, text: &str, tags: &[&TextTag]) {
41        let start_offset = iter.offset();
42        self.as_ref().insert(iter, text);
43        let start_iter = self.as_ref().iter_at_offset(start_offset);
44        tags.iter().for_each(|tag| {
45            self.as_ref().apply_tag(&(*tag).clone(), &start_iter, iter);
46        });
47    }
48
49    #[doc(alias = "gtk_text_buffer_insert_with_tags_by_name")]
50    fn insert_with_tags_by_name(&self, iter: &mut TextIter, text: &str, tags_names: &[&str]) {
51        let start_offset = iter.offset();
52        self.as_ref().insert(iter, text);
53        let start_iter = self.as_ref().iter_at_offset(start_offset);
54        let tag_table = self.as_ref().tag_table();
55        tags_names.iter().for_each(|tag_name| {
56            if let Some(tag) = tag_table.lookup(tag_name) {
57                self.as_ref().apply_tag(&tag, &start_iter, iter);
58            } else {
59                glib::g_warning!("TextBuffer", "No tag with name {}!", tag_name);
60            }
61        });
62    }
63
64    fn connect_insert_text<F: Fn(&Self, &mut TextIter, &str) + 'static>(
65        &self,
66        f: F,
67    ) -> SignalHandlerId {
68        unsafe {
69            unsafe extern "C" fn insert_text_trampoline<
70                T,
71                F: Fn(&T, &mut TextIter, &str) + 'static,
72            >(
73                this: *mut ffi::GtkTextBuffer,
74                location: *mut ffi::GtkTextIter,
75                text: *mut c_char,
76                len: c_int,
77                f: glib::ffi::gpointer,
78            ) where
79                T: IsA<TextBuffer>,
80            {
81                let mut location_copy = from_glib_none(location);
82                let f: &F = &*(f as *const F);
83                let text = if len <= 0 {
84                    &[]
85                } else {
86                    slice::from_raw_parts(text as *const u8, len as usize)
87                };
88
89                f(
90                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
91                    &mut location_copy,
92                    str::from_utf8(text).unwrap(),
93                )
94            }
95            let f: Box_<F> = Box_::new(f);
96            connect_raw(
97                self.to_glib_none().0 as *mut _,
98                c"insert-text".as_ptr() as *mut _,
99                Some(transmute::<usize, unsafe extern "C" fn()>(
100                    insert_text_trampoline::<Self, F> as usize,
101                )),
102                Box_::into_raw(f),
103            )
104        }
105    }
106
107    #[cfg(feature = "v4_16")]
108    #[cfg_attr(docsrs, doc(cfg(feature = "v4_16")))]
109    #[doc(alias = "gtk_text_buffer_add_commit_notify")]
110    fn add_commit_notify<P: Fn(&TextBuffer, TextBufferNotifyFlags, u32, u32) + 'static>(
111        &self,
112        flags: TextBufferNotifyFlags,
113        commit_notify: P,
114    ) -> u32 {
115        let commit_notify_data: Box_<P> = Box_::new(commit_notify);
116        unsafe extern "C" fn commit_notify_func<
117            P: Fn(&TextBuffer, TextBufferNotifyFlags, u32, u32) + 'static,
118        >(
119            buffer: *mut ffi::GtkTextBuffer,
120            flags: ffi::GtkTextBufferNotifyFlags,
121            position: std::ffi::c_uint,
122            length: std::ffi::c_uint,
123            user_data: glib::ffi::gpointer,
124        ) {
125            let buffer = from_glib_borrow(buffer);
126            let flags = from_glib(flags);
127            let callback = &*(user_data as *mut P);
128            (*callback)(&buffer, flags, position, length)
129        }
130        let commit_notify = Some(commit_notify_func::<P> as _);
131        unsafe extern "C" fn destroy_func<
132            P: Fn(&TextBuffer, TextBufferNotifyFlags, u32, u32) + 'static,
133        >(
134            data: glib::ffi::gpointer,
135        ) {
136            let _callback = Box_::from_raw(data as *mut P);
137        }
138        let destroy_call4 = Some(destroy_func::<P> as _);
139        let super_callback0: Box_<P> = commit_notify_data;
140        unsafe {
141            ffi::gtk_text_buffer_add_commit_notify(
142                self.as_ref().to_glib_none().0,
143                flags.into_glib(),
144                commit_notify,
145                Box_::into_raw(super_callback0) as *mut _,
146                destroy_call4,
147            )
148        }
149    }
150}
151
152impl<O: IsA<TextBuffer>> TextBufferExtManual for O {}
153
154impl std::fmt::Write for TextBuffer {
155    fn write_str(&mut self, s: &str) -> std::fmt::Result {
156        let mut iter = self.end_iter();
157        self.insert(&mut iter, s);
158        Ok(())
159    }
160}