File: | _build/../ctksourceview/ctksourceregion.c |
Warning: | line 504, column 4 Value stored to 'l' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- |
2 | * ctksourceregion.c - CtkTextMark-based region utility |
3 | * This file is part of CtkSourceView |
4 | * |
5 | * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net> |
6 | * Copyright (C) 2016 Sébastien Wilmet <swilmet@gnome.org> |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2.1 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public License |
19 | * along with this library; if not, see <http://www.gnu.org/licenses/>. |
20 | */ |
21 | |
22 | #ifdef HAVE_CONFIG_H1 |
23 | #include <config.h> |
24 | #endif |
25 | |
26 | #include "ctksourceregion.h" |
27 | |
28 | /** |
29 | * SECTION:region |
30 | * @Short_description: Region utility |
31 | * @Title: CtkSourceRegion |
32 | * @See_also: #CtkTextBuffer |
33 | * |
34 | * A #CtkSourceRegion permits to store a group of subregions of a |
35 | * #CtkTextBuffer. #CtkSourceRegion stores the subregions with pairs of |
36 | * #CtkTextMark's, so the region is still valid after insertions and deletions |
37 | * in the #CtkTextBuffer. |
38 | * |
39 | * The #CtkTextMark for the start of a subregion has a left gravity, while the |
40 | * #CtkTextMark for the end of a subregion has a right gravity. |
41 | * |
42 | * The typical use-case of #CtkSourceRegion is to scan a #CtkTextBuffer chunk by |
43 | * chunk, not the whole buffer at once to not block the user interface. The |
44 | * #CtkSourceRegion represents in that case the remaining region to scan. You |
45 | * can listen to the #CtkTextBuffer::insert-text and |
46 | * #CtkTextBuffer::delete-range signals to update the #CtkSourceRegion |
47 | * accordingly. |
48 | * |
49 | * To iterate through the subregions, you need to use a #CtkSourceRegionIter, |
50 | * for example: |
51 | * |[ |
52 | * CtkSourceRegion *region; |
53 | * CtkSourceRegionIter region_iter; |
54 | * |
55 | * ctk_source_region_get_start_region_iter (region, ®ion_iter); |
56 | * |
57 | * while (!ctk_source_region_iter_is_end (®ion_iter)) |
58 | * { |
59 | * CtkTextIter subregion_start; |
60 | * CtkTextIter subregion_end; |
61 | * |
62 | * if (!ctk_source_region_iter_get_subregion (®ion_iter, |
63 | * &subregion_start, |
64 | * &subregion_end)) |
65 | * { |
66 | * break; |
67 | * } |
68 | * |
69 | * // Do something useful with the subregion. |
70 | * |
71 | * ctk_source_region_iter_next (®ion_iter); |
72 | * } |
73 | * ]| |
74 | */ |
75 | |
76 | /* With the gravities of the CtkTextMarks, it is possible for subregions to |
77 | * become interlaced: |
78 | * Buffer content: |
79 | * "hello world" |
80 | * Add two subregions: |
81 | * "[hello] [world]" |
82 | * Delete the space: |
83 | * "[hello][world]" |
84 | * Undo: |
85 | * "[hello[ ]world]" |
86 | * |
87 | * FIXME: when iterating through the subregions, it should simplify them first. |
88 | * I don't know if it's done (swilmet). |
89 | */ |
90 | |
91 | #undef ENABLE_DEBUG |
92 | /* |
93 | #define ENABLE_DEBUG |
94 | */ |
95 | |
96 | #ifdef ENABLE_DEBUG |
97 | #define DEBUG(x) (x) |
98 | #else |
99 | #define DEBUG(x) |
100 | #endif |
101 | |
102 | typedef struct _CtkSourceRegionPrivate CtkSourceRegionPrivate; |
103 | typedef struct _Subregion Subregion; |
104 | typedef struct _CtkSourceRegionIterReal CtkSourceRegionIterReal; |
105 | |
106 | struct _CtkSourceRegionPrivate |
107 | { |
108 | /* Weak pointer to the buffer. */ |
109 | CtkTextBuffer *buffer; |
110 | |
111 | /* List of sorted 'Subregion*' */ |
112 | GList *subregions; |
113 | |
114 | guint32 timestamp; |
115 | }; |
116 | |
117 | struct _Subregion |
118 | { |
119 | CtkTextMark *start; |
120 | CtkTextMark *end; |
121 | }; |
122 | |
123 | struct _CtkSourceRegionIterReal |
124 | { |
125 | CtkSourceRegion *region; |
126 | guint32 region_timestamp; |
127 | GList *subregions; |
128 | }; |
129 | |
130 | enum |
131 | { |
132 | PROP_0, |
133 | PROP_BUFFER, |
134 | N_PROPERTIES |
135 | }; |
136 | |
137 | static GParamSpec *properties[N_PROPERTIES]; |
138 | |
139 | G_DEFINE_TYPE_WITH_PRIVATE (CtkSourceRegion, ctk_source_region, G_TYPE_OBJECT)static void ctk_source_region_init (CtkSourceRegion *self); static void ctk_source_region_class_init (CtkSourceRegionClass *klass ); static GType ctk_source_region_get_type_once (void); static gpointer ctk_source_region_parent_class = ((void*)0); static gint CtkSourceRegion_private_offset; static void ctk_source_region_class_intern_init (gpointer klass) { ctk_source_region_parent_class = g_type_class_peek_parent (klass); if (CtkSourceRegion_private_offset != 0) g_type_class_adjust_private_offset (klass, &CtkSourceRegion_private_offset); ctk_source_region_class_init ((CtkSourceRegionClass*) klass); } __attribute__ ((__unused__ )) static inline gpointer ctk_source_region_get_instance_private (CtkSourceRegion *self) { return (((gpointer) ((guint8*) (self ) + (glong) (CtkSourceRegion_private_offset)))); } GType ctk_source_region_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); (void) ( 0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0)) ; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = ctk_source_region_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType ctk_source_region_get_type_once ( void) { GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))), g_intern_static_string ("CtkSourceRegion" ), sizeof (CtkSourceRegionClass), (GClassInitFunc)(void (*)(void )) ctk_source_region_class_intern_init, sizeof (CtkSourceRegion ), (GInstanceInitFunc)(void (*)(void)) ctk_source_region_init , (GTypeFlags) 0); { {{ CtkSourceRegion_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (CtkSourceRegionPrivate)); };} } return g_define_type_id; } |
140 | |
141 | #ifdef ENABLE_DEBUG |
142 | static void |
143 | print_region (CtkSourceRegion *region) |
144 | { |
145 | gchar *str; |
146 | |
147 | str = ctk_source_region_to_string (region); |
148 | g_print ("%s\n", str); |
149 | g_free (str); |
150 | } |
151 | #endif |
152 | |
153 | /* Find and return a subregion node which contains the given text |
154 | * iter. If left_side is TRUE, return the subregion which contains |
155 | * the text iter or which is the leftmost; else return the rightmost |
156 | * subregion. |
157 | */ |
158 | static GList * |
159 | find_nearest_subregion (CtkSourceRegion *region, |
160 | const CtkTextIter *iter, |
161 | GList *begin, |
162 | gboolean leftmost, |
163 | gboolean include_edges) |
164 | { |
165 | CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (region); |
166 | GList *retval; |
167 | GList *l; |
168 | |
169 | g_assert (iter != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_44 = 0; if (iter != ((void*)0)) _g_boolean_var_44 = 1; _g_boolean_var_44 ; }), 1)) ; else g_assertion_message_expr ("CtkSourceView", "../ctksourceview/ctksourceregion.c" , 169, ((const char*) (__func__)), "iter != NULL"); } while ( 0); |
170 | |
171 | if (begin == NULL((void*)0)) |
172 | { |
173 | begin = priv->subregions; |
174 | } |
175 | |
176 | if (begin != NULL((void*)0)) |
177 | { |
178 | retval = begin->prev; |
179 | } |
180 | else |
181 | { |
182 | retval = NULL((void*)0); |
183 | } |
184 | |
185 | for (l = begin; l != NULL((void*)0); l = l->next) |
186 | { |
187 | CtkTextIter sr_iter; |
188 | Subregion *sr = l->data; |
189 | gint cmp; |
190 | |
191 | if (!leftmost) |
192 | { |
193 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_iter, sr->end); |
194 | cmp = ctk_text_iter_compare (iter, &sr_iter); |
195 | if (cmp < 0 || (cmp == 0 && include_edges)) |
196 | { |
197 | retval = l; |
198 | break; |
199 | } |
200 | |
201 | } |
202 | else |
203 | { |
204 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_iter, sr->start); |
205 | cmp = ctk_text_iter_compare (iter, &sr_iter); |
206 | if (cmp > 0 || (cmp == 0 && include_edges)) |
207 | { |
208 | retval = l; |
209 | } |
210 | else |
211 | { |
212 | break; |
213 | } |
214 | } |
215 | } |
216 | |
217 | return retval; |
218 | } |
219 | |
220 | static void |
221 | ctk_source_region_get_property (GObject *object, |
222 | guint prop_id, |
223 | GValue *value, |
224 | GParamSpec *pspec) |
225 | { |
226 | CtkSourceRegion *region = CTK_SOURCE_REGION (object); |
227 | |
228 | switch (prop_id) |
229 | { |
230 | case PROP_BUFFER: |
231 | g_value_set_object (value, ctk_source_region_get_buffer (region)); |
232 | break; |
233 | |
234 | default: |
235 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "../ctksourceview/ctksourceregion.c", 235, ("property"), _glib__property_id , _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance *) (_glib__pspec))->g_class))->g_type)))), (g_type_name ((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
236 | break; |
237 | } |
238 | } |
239 | |
240 | static void |
241 | ctk_source_region_set_property (GObject *object, |
242 | guint prop_id, |
243 | const GValue *value, |
244 | GParamSpec *pspec) |
245 | { |
246 | CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (CTK_SOURCE_REGION (object)); |
247 | |
248 | switch (prop_id) |
249 | { |
250 | case PROP_BUFFER: |
251 | g_assert (priv->buffer == NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_45 = 0; if (priv->buffer == ((void*)0)) _g_boolean_var_45 = 1 ; _g_boolean_var_45; }), 1)) ; else g_assertion_message_expr ( "CtkSourceView", "../ctksourceview/ctksourceregion.c", 251, ( (const char*) (__func__)), "priv->buffer == NULL"); } while (0); |
252 | priv->buffer = g_value_get_object (value); |
253 | g_object_add_weak_pointer (G_OBJECT (priv->buffer)((((GObject*) (void *) ((priv->buffer))))), |
254 | (gpointer *) &priv->buffer); |
255 | break; |
256 | |
257 | default: |
258 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "../ctksourceview/ctksourceregion.c", 258, ("property"), _glib__property_id , _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance *) (_glib__pspec))->g_class))->g_type)))), (g_type_name ((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
259 | break; |
260 | } |
261 | } |
262 | |
263 | static void |
264 | ctk_source_region_dispose (GObject *object) |
265 | { |
266 | CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (CTK_SOURCE_REGION (object)); |
267 | |
268 | while (priv->subregions != NULL((void*)0)) |
269 | { |
270 | Subregion *sr = priv->subregions->data; |
271 | |
272 | if (priv->buffer != NULL((void*)0)) |
273 | { |
274 | ctk_text_buffer_delete_mark (priv->buffer, sr->start); |
275 | ctk_text_buffer_delete_mark (priv->buffer, sr->end); |
276 | } |
277 | |
278 | g_slice_free (Subregion, sr)do { if (1) g_slice_free1 (sizeof (Subregion), (sr)); else (void ) ((Subregion*) 0 == (sr)); } while (0); |
279 | priv->subregions = g_list_delete_link (priv->subregions, priv->subregions); |
280 | } |
281 | |
282 | if (priv->buffer != NULL((void*)0)) |
283 | { |
284 | g_object_remove_weak_pointer (G_OBJECT (priv->buffer)((((GObject*) (void *) ((priv->buffer))))), |
285 | (gpointer *) &priv->buffer); |
286 | |
287 | priv->buffer = NULL((void*)0); |
288 | } |
289 | |
290 | G_OBJECT_CLASS (ctk_source_region_parent_class)((((GObjectClass*) (void *) ((ctk_source_region_parent_class) ))))->dispose (object); |
291 | } |
292 | |
293 | static void |
294 | ctk_source_region_class_init (CtkSourceRegionClass *klass) |
295 | { |
296 | GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass))))); |
297 | |
298 | object_class->get_property = ctk_source_region_get_property; |
299 | object_class->set_property = ctk_source_region_set_property; |
300 | object_class->dispose = ctk_source_region_dispose; |
301 | |
302 | /** |
303 | * CtkSourceRegion:buffer: |
304 | * |
305 | * The #CtkTextBuffer. The #CtkSourceRegion has a weak reference to the |
306 | * buffer. |
307 | * |
308 | * Since: 3.22 |
309 | */ |
310 | properties[PROP_BUFFER] = |
311 | g_param_spec_object ("buffer", |
312 | "Buffer", |
313 | "", |
314 | CTK_TYPE_TEXT_BUFFER(ctk_text_buffer_get_type ()), |
315 | G_PARAM_READWRITE | |
316 | G_PARAM_CONSTRUCT_ONLY | |
317 | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB )); |
318 | |
319 | g_object_class_install_properties (object_class, N_PROPERTIES, properties); |
320 | } |
321 | |
322 | static void |
323 | ctk_source_region_init (CtkSourceRegion *region) |
324 | { |
325 | } |
326 | |
327 | /** |
328 | * ctk_source_region_new: |
329 | * @buffer: a #CtkTextBuffer. |
330 | * |
331 | * Returns: a new #CtkSourceRegion object for @buffer. |
332 | * Since: 3.22 |
333 | */ |
334 | CtkSourceRegion * |
335 | ctk_source_region_new (CtkTextBuffer *buffer) |
336 | { |
337 | g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_46 = 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((buffer)); GType __t = ((ctk_text_buffer_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_46 = 1; _g_boolean_var_46; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_IS_TEXT_BUFFER (buffer)" ); return (((void*)0)); } } while (0); |
338 | |
339 | return g_object_new (CTK_SOURCE_TYPE_REGION(ctk_source_region_get_type ()), |
340 | "buffer", buffer, |
341 | NULL((void*)0)); |
342 | } |
343 | |
344 | /** |
345 | * ctk_source_region_get_buffer: |
346 | * @region: a #CtkSourceRegion. |
347 | * |
348 | * Returns: (transfer none) (nullable): the #CtkTextBuffer. |
349 | * Since: 3.22 |
350 | */ |
351 | CtkTextBuffer * |
352 | ctk_source_region_get_buffer (CtkSourceRegion *region) |
353 | { |
354 | CtkSourceRegionPrivate *priv; |
355 | |
356 | g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_47 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_47 = 1 ; _g_boolean_var_47; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return (((void*)0)); } } while (0); |
357 | |
358 | priv = ctk_source_region_get_instance_private (region); |
359 | return priv->buffer; |
360 | } |
361 | |
362 | static void |
363 | ctk_source_region_clear_zero_length_subregions (CtkSourceRegion *region) |
364 | { |
365 | CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (region); |
366 | GList *node; |
367 | |
368 | node = priv->subregions; |
369 | while (node != NULL((void*)0)) |
370 | { |
371 | Subregion *sr = node->data; |
372 | CtkTextIter start; |
373 | CtkTextIter end; |
374 | |
375 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &start, sr->start); |
376 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &end, sr->end); |
377 | |
378 | if (ctk_text_iter_equal (&start, &end)) |
379 | { |
380 | ctk_text_buffer_delete_mark (priv->buffer, sr->start); |
381 | ctk_text_buffer_delete_mark (priv->buffer, sr->end); |
382 | g_slice_free (Subregion, sr)do { if (1) g_slice_free1 (sizeof (Subregion), (sr)); else (void ) ((Subregion*) 0 == (sr)); } while (0); |
383 | |
384 | if (node == priv->subregions) |
385 | { |
386 | priv->subregions = node = g_list_delete_link (node, node); |
387 | } |
388 | else |
389 | { |
390 | node = g_list_delete_link (node, node); |
391 | } |
392 | |
393 | priv->timestamp++; |
394 | } |
395 | else |
396 | { |
397 | node = node->next; |
398 | } |
399 | } |
400 | } |
401 | |
402 | /** |
403 | * ctk_source_region_add_subregion: |
404 | * @region: a #CtkSourceRegion. |
405 | * @_start: the start of the subregion. |
406 | * @_end: the end of the subregion. |
407 | * |
408 | * Adds the subregion delimited by @_start and @_end to @region. |
409 | * |
410 | * Since: 3.22 |
411 | */ |
412 | void |
413 | ctk_source_region_add_subregion (CtkSourceRegion *region, |
414 | const CtkTextIter *_start, |
415 | const CtkTextIter *_end) |
416 | { |
417 | CtkSourceRegionPrivate *priv; |
418 | GList *start_node; |
419 | GList *end_node; |
420 | CtkTextIter start; |
421 | CtkTextIter end; |
422 | |
423 | g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_48 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_48 = 1 ; _g_boolean_var_48; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return; } } while (0); |
424 | g_return_if_fail (_start != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_49 = 0; if (_start != ((void*)0)) _g_boolean_var_49 = 1; _g_boolean_var_49 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "_start != NULL"); return; } } while (0); |
425 | g_return_if_fail (_end != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_50 = 0; if (_end != ((void*)0)) _g_boolean_var_50 = 1; _g_boolean_var_50 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "_end != NULL"); return; } } while (0); |
426 | |
427 | priv = ctk_source_region_get_instance_private (region); |
428 | |
429 | if (priv->buffer == NULL((void*)0)) |
430 | { |
431 | return; |
432 | } |
433 | |
434 | start = *_start; |
435 | end = *_end; |
436 | |
437 | DEBUG (g_print ("---\n")); |
438 | DEBUG (print_region (region)); |
439 | DEBUG (g_message ("region_add (%d, %d)", |
440 | ctk_text_iter_get_offset (&start), |
441 | ctk_text_iter_get_offset (&end))); |
442 | |
443 | ctk_text_iter_order (&start, &end); |
444 | |
445 | /* Don't add zero-length regions. */ |
446 | if (ctk_text_iter_equal (&start, &end)) |
447 | { |
448 | return; |
449 | } |
450 | |
451 | /* Find bounding subregions. */ |
452 | start_node = find_nearest_subregion (region, &start, NULL((void*)0), FALSE(0), TRUE(!(0))); |
453 | end_node = find_nearest_subregion (region, &end, start_node, TRUE(!(0)), TRUE(!(0))); |
454 | |
455 | if (start_node == NULL((void*)0) || end_node == NULL((void*)0) || end_node == start_node->prev) |
456 | { |
457 | /* Create the new subregion. */ |
458 | Subregion *sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion ); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s ); __p; })); |
459 | sr->start = ctk_text_buffer_create_mark (priv->buffer, NULL((void*)0), &start, TRUE(!(0))); |
460 | sr->end = ctk_text_buffer_create_mark (priv->buffer, NULL((void*)0), &end, FALSE(0)); |
461 | |
462 | if (start_node == NULL((void*)0)) |
463 | { |
464 | /* Append the new region. */ |
465 | priv->subregions = g_list_append (priv->subregions, sr); |
466 | } |
467 | else if (end_node == NULL((void*)0)) |
468 | { |
469 | /* Prepend the new region. */ |
470 | priv->subregions = g_list_prepend (priv->subregions, sr); |
471 | } |
472 | else |
473 | { |
474 | /* We are in the middle of two subregions. */ |
475 | priv->subregions = g_list_insert_before (priv->subregions, start_node, sr); |
476 | } |
477 | } |
478 | else |
479 | { |
480 | CtkTextIter iter; |
481 | Subregion *sr = start_node->data; |
482 | |
483 | if (start_node != end_node) |
484 | { |
485 | /* We need to merge some subregions. */ |
486 | GList *l = start_node->next; |
487 | Subregion *q; |
488 | |
489 | ctk_text_buffer_delete_mark (priv->buffer, sr->end); |
490 | |
491 | while (l != end_node) |
492 | { |
493 | q = l->data; |
494 | ctk_text_buffer_delete_mark (priv->buffer, q->start); |
495 | ctk_text_buffer_delete_mark (priv->buffer, q->end); |
496 | g_slice_free (Subregion, q)do { if (1) g_slice_free1 (sizeof (Subregion), (q)); else (void ) ((Subregion*) 0 == (q)); } while (0); |
497 | l = g_list_delete_link (l, l); |
498 | } |
499 | |
500 | q = l->data; |
501 | ctk_text_buffer_delete_mark (priv->buffer, q->start); |
502 | sr->end = q->end; |
503 | g_slice_free (Subregion, q)do { if (1) g_slice_free1 (sizeof (Subregion), (q)); else (void ) ((Subregion*) 0 == (q)); } while (0); |
504 | l = g_list_delete_link (l, l); |
Value stored to 'l' is never read | |
505 | } |
506 | |
507 | /* Now move marks if that action expands the region. */ |
508 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &iter, sr->start); |
509 | if (ctk_text_iter_compare (&iter, &start) > 0) |
510 | { |
511 | ctk_text_buffer_move_mark (priv->buffer, sr->start, &start); |
512 | } |
513 | |
514 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &iter, sr->end); |
515 | if (ctk_text_iter_compare (&iter, &end) < 0) |
516 | { |
517 | ctk_text_buffer_move_mark (priv->buffer, sr->end, &end); |
518 | } |
519 | } |
520 | |
521 | priv->timestamp++; |
522 | |
523 | DEBUG (print_region (region)); |
524 | } |
525 | |
526 | /** |
527 | * ctk_source_region_add_region: |
528 | * @region: a #CtkSourceRegion. |
529 | * @region_to_add: (nullable): the #CtkSourceRegion to add to @region, or %NULL. |
530 | * |
531 | * Adds @region_to_add to @region. @region_to_add is not modified. |
532 | * |
533 | * Since: 3.22 |
534 | */ |
535 | void |
536 | ctk_source_region_add_region (CtkSourceRegion *region, |
537 | CtkSourceRegion *region_to_add) |
538 | { |
539 | CtkSourceRegionIter iter; |
540 | CtkTextBuffer *region_buffer; |
541 | CtkTextBuffer *region_to_add_buffer; |
542 | |
543 | g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_51 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_51 = 1 ; _g_boolean_var_51; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return; } } while (0); |
544 | g_return_if_fail (region_to_add == NULL || CTK_SOURCE_IS_REGION (region_to_add))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_52 = 0; if (region_to_add == ((void*)0) || CTK_SOURCE_IS_REGION (region_to_add)) _g_boolean_var_52 = 1; _g_boolean_var_52; } ), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "region_to_add == NULL || CTK_SOURCE_IS_REGION (region_to_add)" ); return; } } while (0); |
545 | |
546 | if (region_to_add == NULL((void*)0)) |
547 | { |
548 | return; |
549 | } |
550 | |
551 | region_buffer = ctk_source_region_get_buffer (region); |
552 | region_to_add_buffer = ctk_source_region_get_buffer (region_to_add); |
553 | g_return_if_fail (region_buffer == region_to_add_buffer)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_53 = 0; if (region_buffer == region_to_add_buffer) _g_boolean_var_53 = 1; _g_boolean_var_53; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "region_buffer == region_to_add_buffer" ); return; } } while (0); |
554 | |
555 | if (region_buffer == NULL((void*)0)) |
556 | { |
557 | return; |
558 | } |
559 | |
560 | ctk_source_region_get_start_region_iter (region_to_add, &iter); |
561 | |
562 | while (!ctk_source_region_iter_is_end (&iter)) |
563 | { |
564 | CtkTextIter subregion_start; |
565 | CtkTextIter subregion_end; |
566 | |
567 | if (!ctk_source_region_iter_get_subregion (&iter, |
568 | &subregion_start, |
569 | &subregion_end)) |
570 | { |
571 | break; |
572 | } |
573 | |
574 | ctk_source_region_add_subregion (region, |
575 | &subregion_start, |
576 | &subregion_end); |
577 | |
578 | ctk_source_region_iter_next (&iter); |
579 | } |
580 | } |
581 | |
582 | /** |
583 | * ctk_source_region_subtract_subregion: |
584 | * @region: a #CtkSourceRegion. |
585 | * @_start: the start of the subregion. |
586 | * @_end: the end of the subregion. |
587 | * |
588 | * Subtracts the subregion delimited by @_start and @_end from @region. |
589 | * |
590 | * Since: 3.22 |
591 | */ |
592 | void |
593 | ctk_source_region_subtract_subregion (CtkSourceRegion *region, |
594 | const CtkTextIter *_start, |
595 | const CtkTextIter *_end) |
596 | { |
597 | CtkSourceRegionPrivate *priv; |
598 | GList *start_node; |
599 | GList *end_node; |
600 | GList *node; |
601 | CtkTextIter sr_start_iter; |
602 | CtkTextIter sr_end_iter; |
603 | gboolean done; |
604 | gboolean start_is_outside; |
605 | gboolean end_is_outside; |
606 | Subregion *sr; |
607 | CtkTextIter start; |
608 | CtkTextIter end; |
609 | |
610 | g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_54 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_54 = 1 ; _g_boolean_var_54; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return; } } while (0); |
611 | g_return_if_fail (_start != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_55 = 0; if (_start != ((void*)0)) _g_boolean_var_55 = 1; _g_boolean_var_55 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "_start != NULL"); return; } } while (0); |
612 | g_return_if_fail (_end != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_56 = 0; if (_end != ((void*)0)) _g_boolean_var_56 = 1; _g_boolean_var_56 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "_end != NULL"); return; } } while (0); |
613 | |
614 | priv = ctk_source_region_get_instance_private (region); |
615 | |
616 | if (priv->buffer == NULL((void*)0)) |
617 | { |
618 | return; |
619 | } |
620 | |
621 | start = *_start; |
622 | end = *_end; |
623 | |
624 | DEBUG (g_print ("---\n")); |
625 | DEBUG (print_region (region)); |
626 | DEBUG (g_message ("region_substract (%d, %d)", |
627 | ctk_text_iter_get_offset (&start), |
628 | ctk_text_iter_get_offset (&end))); |
629 | |
630 | ctk_text_iter_order (&start, &end); |
631 | |
632 | /* Find bounding subregions. */ |
633 | start_node = find_nearest_subregion (region, &start, NULL((void*)0), FALSE(0), FALSE(0)); |
634 | end_node = find_nearest_subregion (region, &end, start_node, TRUE(!(0)), FALSE(0)); |
635 | |
636 | /* Easy case first. */ |
637 | if (start_node == NULL((void*)0) || end_node == NULL((void*)0) || end_node == start_node->prev) |
638 | { |
639 | return; |
640 | } |
641 | |
642 | /* Deal with the start point. */ |
643 | start_is_outside = end_is_outside = FALSE(0); |
644 | |
645 | sr = start_node->data; |
646 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start); |
647 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end); |
648 | |
649 | if (ctk_text_iter_in_range (&start, &sr_start_iter, &sr_end_iter) && |
650 | !ctk_text_iter_equal (&start, &sr_start_iter)) |
651 | { |
652 | /* The starting point is inside the first subregion. */ |
653 | if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter) && |
654 | !ctk_text_iter_equal (&end, &sr_end_iter)) |
655 | { |
656 | /* The ending point is also inside the first |
657 | * subregion: we need to split. |
658 | */ |
659 | Subregion *new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion ); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s ); __p; })); |
660 | new_sr->end = sr->end; |
661 | new_sr->start = ctk_text_buffer_create_mark (priv->buffer, |
662 | NULL((void*)0), |
663 | &end, |
664 | TRUE(!(0))); |
665 | |
666 | start_node = g_list_insert_before (start_node, start_node->next, new_sr); |
667 | |
668 | sr->end = ctk_text_buffer_create_mark (priv->buffer, |
669 | NULL((void*)0), |
670 | &start, |
671 | FALSE(0)); |
672 | |
673 | /* No further processing needed. */ |
674 | DEBUG (g_message ("subregion splitted")); |
675 | |
676 | return; |
677 | } |
678 | else |
679 | { |
680 | /* The ending point is outside, so just move |
681 | * the end of the subregion to the starting point. |
682 | */ |
683 | ctk_text_buffer_move_mark (priv->buffer, sr->end, &start); |
684 | } |
685 | } |
686 | else |
687 | { |
688 | /* The starting point is outside (and so to the left) |
689 | * of the first subregion. |
690 | */ |
691 | DEBUG (g_message ("start is outside")); |
692 | |
693 | start_is_outside = TRUE(!(0)); |
694 | } |
695 | |
696 | /* Deal with the end point. */ |
697 | if (start_node != end_node) |
698 | { |
699 | sr = end_node->data; |
700 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start); |
701 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end); |
702 | } |
703 | |
704 | if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter) && |
705 | !ctk_text_iter_equal (&end, &sr_end_iter)) |
706 | { |
707 | /* Ending point is inside, move the start mark. */ |
708 | ctk_text_buffer_move_mark (priv->buffer, sr->start, &end); |
709 | } |
710 | else |
711 | { |
712 | end_is_outside = TRUE(!(0)); |
713 | DEBUG (g_message ("end is outside")); |
714 | } |
715 | |
716 | /* Finally remove any intermediate subregions. */ |
717 | done = FALSE(0); |
718 | node = start_node; |
719 | |
720 | while (!done) |
721 | { |
722 | if (node == end_node) |
723 | { |
724 | /* We are done, exit in the next iteration. */ |
725 | done = TRUE(!(0)); |
726 | } |
727 | |
728 | if ((node == start_node && !start_is_outside) || |
729 | (node == end_node && !end_is_outside)) |
730 | { |
731 | /* Skip starting or ending node. */ |
732 | node = node->next; |
733 | } |
734 | else |
735 | { |
736 | GList *l = node->next; |
737 | sr = node->data; |
738 | ctk_text_buffer_delete_mark (priv->buffer, sr->start); |
739 | ctk_text_buffer_delete_mark (priv->buffer, sr->end); |
740 | g_slice_free (Subregion, sr)do { if (1) g_slice_free1 (sizeof (Subregion), (sr)); else (void ) ((Subregion*) 0 == (sr)); } while (0); |
741 | priv->subregions = g_list_delete_link (priv->subregions, node); |
742 | node = l; |
743 | } |
744 | } |
745 | |
746 | priv->timestamp++; |
747 | |
748 | DEBUG (print_region (region)); |
749 | |
750 | /* Now get rid of empty subregions. */ |
751 | ctk_source_region_clear_zero_length_subregions (region); |
752 | |
753 | DEBUG (print_region (region)); |
754 | } |
755 | |
756 | /** |
757 | * ctk_source_region_subtract_region: |
758 | * @region: a #CtkSourceRegion. |
759 | * @region_to_subtract: (nullable): the #CtkSourceRegion to subtract from |
760 | * @region, or %NULL. |
761 | * |
762 | * Subtracts @region_to_subtract from @region. @region_to_subtract is not |
763 | * modified. |
764 | * |
765 | * Since: 3.22 |
766 | */ |
767 | void |
768 | ctk_source_region_subtract_region (CtkSourceRegion *region, |
769 | CtkSourceRegion *region_to_subtract) |
770 | { |
771 | CtkTextBuffer *region_buffer; |
772 | CtkTextBuffer *region_to_subtract_buffer; |
773 | CtkSourceRegionIter iter; |
774 | |
775 | g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_57 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_57 = 1 ; _g_boolean_var_57; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return; } } while (0); |
776 | g_return_if_fail (region_to_subtract == NULL || CTK_SOURCE_IS_REGION (region_to_subtract))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_58 = 0; if (region_to_subtract == ((void*)0) || CTK_SOURCE_IS_REGION (region_to_subtract)) _g_boolean_var_58 = 1; _g_boolean_var_58 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "region_to_subtract == NULL || CTK_SOURCE_IS_REGION (region_to_subtract)" ); return; } } while (0); |
777 | |
778 | region_buffer = ctk_source_region_get_buffer (region); |
779 | region_to_subtract_buffer = ctk_source_region_get_buffer (region_to_subtract); |
780 | g_return_if_fail (region_buffer == region_to_subtract_buffer)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_59 = 0; if (region_buffer == region_to_subtract_buffer) _g_boolean_var_59 = 1; _g_boolean_var_59; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "region_buffer == region_to_subtract_buffer" ); return; } } while (0); |
781 | |
782 | if (region_buffer == NULL((void*)0)) |
783 | { |
784 | return; |
785 | } |
786 | |
787 | ctk_source_region_get_start_region_iter (region_to_subtract, &iter); |
788 | |
789 | while (!ctk_source_region_iter_is_end (&iter)) |
790 | { |
791 | CtkTextIter subregion_start; |
792 | CtkTextIter subregion_end; |
793 | |
794 | if (!ctk_source_region_iter_get_subregion (&iter, |
795 | &subregion_start, |
796 | &subregion_end)) |
797 | { |
798 | break; |
799 | } |
800 | |
801 | ctk_source_region_subtract_subregion (region, |
802 | &subregion_start, |
803 | &subregion_end); |
804 | |
805 | ctk_source_region_iter_next (&iter); |
806 | } |
807 | } |
808 | |
809 | /** |
810 | * ctk_source_region_is_empty: |
811 | * @region: (nullable): a #CtkSourceRegion, or %NULL. |
812 | * |
813 | * Returns whether the @region is empty. A %NULL @region is considered empty. |
814 | * |
815 | * Returns: whether the @region is empty. |
816 | * Since: 3.22 |
817 | */ |
818 | gboolean |
819 | ctk_source_region_is_empty (CtkSourceRegion *region) |
820 | { |
821 | CtkSourceRegionIter region_iter; |
822 | |
823 | if (region == NULL((void*)0)) |
824 | { |
825 | return TRUE(!(0)); |
826 | } |
827 | |
828 | /* A #CtkSourceRegion can contain empty subregions. So checking the |
829 | * number of subregions is not sufficient. |
830 | * When calling ctk_source_region_add_subregion() with equal iters, the |
831 | * subregion is not added. But when a subregion becomes empty, due to |
832 | * text deletion, the subregion is not removed from the |
833 | * #CtkSourceRegion. |
834 | */ |
835 | |
836 | ctk_source_region_get_start_region_iter (region, ®ion_iter); |
837 | |
838 | while (!ctk_source_region_iter_is_end (®ion_iter)) |
839 | { |
840 | CtkTextIter subregion_start; |
841 | CtkTextIter subregion_end; |
842 | |
843 | if (!ctk_source_region_iter_get_subregion (®ion_iter, |
844 | &subregion_start, |
845 | &subregion_end)) |
846 | { |
847 | return TRUE(!(0)); |
848 | } |
849 | |
850 | if (!ctk_text_iter_equal (&subregion_start, &subregion_end)) |
851 | { |
852 | return FALSE(0); |
853 | } |
854 | |
855 | ctk_source_region_iter_next (®ion_iter); |
856 | } |
857 | |
858 | return TRUE(!(0)); |
859 | } |
860 | |
861 | /** |
862 | * ctk_source_region_get_bounds: |
863 | * @region: a #CtkSourceRegion. |
864 | * @start: (out) (optional): iterator to initialize with the start of @region, |
865 | * or %NULL. |
866 | * @end: (out) (optional): iterator to initialize with the end of @region, |
867 | * or %NULL. |
868 | * |
869 | * Gets the @start and @end bounds of the @region. |
870 | * |
871 | * Returns: %TRUE if @start and @end have been set successfully (if non-%NULL), |
872 | * or %FALSE if the @region is empty. |
873 | * Since: 3.22 |
874 | */ |
875 | gboolean |
876 | ctk_source_region_get_bounds (CtkSourceRegion *region, |
877 | CtkTextIter *start, |
878 | CtkTextIter *end) |
879 | { |
880 | CtkSourceRegionPrivate *priv; |
881 | |
882 | g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_60 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_60 = 1 ; _g_boolean_var_60; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return ((0)); } } while (0); |
883 | |
884 | priv = ctk_source_region_get_instance_private (region); |
885 | |
886 | if (priv->buffer == NULL((void*)0) || |
887 | ctk_source_region_is_empty (region)) |
888 | { |
889 | return FALSE(0); |
890 | } |
891 | |
892 | g_assert (priv->subregions != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_61 = 0; if (priv->subregions != ((void*)0)) _g_boolean_var_61 = 1; _g_boolean_var_61; }), 1)) ; else g_assertion_message_expr ("CtkSourceView", "../ctksourceview/ctksourceregion.c", 892, ((const char*) (__func__)), "priv->subregions != NULL"); } while (0); |
893 | |
894 | if (start != NULL((void*)0)) |
895 | { |
896 | Subregion *first_subregion = priv->subregions->data; |
897 | ctk_text_buffer_get_iter_at_mark (priv->buffer, start, first_subregion->start); |
898 | } |
899 | |
900 | if (end != NULL((void*)0)) |
901 | { |
902 | Subregion *last_subregion = g_list_last (priv->subregions)->data; |
903 | ctk_text_buffer_get_iter_at_mark (priv->buffer, end, last_subregion->end); |
904 | } |
905 | |
906 | return TRUE(!(0)); |
907 | } |
908 | |
909 | /** |
910 | * ctk_source_region_intersect_subregion: |
911 | * @region: a #CtkSourceRegion. |
912 | * @_start: the start of the subregion. |
913 | * @_end: the end of the subregion. |
914 | * |
915 | * Returns the intersection between @region and the subregion delimited by |
916 | * @_start and @_end. @region is not modified. |
917 | * |
918 | * Returns: (transfer full) (nullable): the intersection as a new |
919 | * #CtkSourceRegion. |
920 | * Since: 3.22 |
921 | */ |
922 | CtkSourceRegion * |
923 | ctk_source_region_intersect_subregion (CtkSourceRegion *region, |
924 | const CtkTextIter *_start, |
925 | const CtkTextIter *_end) |
926 | { |
927 | CtkSourceRegionPrivate *priv; |
928 | CtkSourceRegion *new_region; |
929 | CtkSourceRegionPrivate *new_priv; |
930 | GList *start_node; |
931 | GList *end_node; |
932 | GList *node; |
933 | CtkTextIter sr_start_iter; |
934 | CtkTextIter sr_end_iter; |
935 | Subregion *sr; |
936 | Subregion *new_sr; |
937 | gboolean done; |
938 | CtkTextIter start; |
939 | CtkTextIter end; |
940 | |
941 | g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_62 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_62 = 1 ; _g_boolean_var_62; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return (((void*)0)); } } while (0); |
942 | g_return_val_if_fail (_start != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_63 = 0; if (_start != ((void*)0)) _g_boolean_var_63 = 1; _g_boolean_var_63 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "_start != NULL"); return (((void *)0)); } } while (0); |
943 | g_return_val_if_fail (_end != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_64 = 0; if (_end != ((void*)0)) _g_boolean_var_64 = 1; _g_boolean_var_64 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "_end != NULL"); return (((void *)0)); } } while (0); |
944 | |
945 | priv = ctk_source_region_get_instance_private (region); |
946 | |
947 | if (priv->buffer == NULL((void*)0)) |
948 | { |
949 | return NULL((void*)0); |
950 | } |
951 | |
952 | start = *_start; |
953 | end = *_end; |
954 | |
955 | ctk_text_iter_order (&start, &end); |
956 | |
957 | /* Find bounding subregions. */ |
958 | start_node = find_nearest_subregion (region, &start, NULL((void*)0), FALSE(0), FALSE(0)); |
959 | end_node = find_nearest_subregion (region, &end, start_node, TRUE(!(0)), FALSE(0)); |
960 | |
961 | /* Easy case first. */ |
962 | if (start_node == NULL((void*)0) || end_node == NULL((void*)0) || end_node == start_node->prev) |
963 | { |
964 | return NULL((void*)0); |
965 | } |
966 | |
967 | new_region = ctk_source_region_new (priv->buffer); |
968 | new_priv = ctk_source_region_get_instance_private (new_region); |
969 | done = FALSE(0); |
970 | |
971 | sr = start_node->data; |
972 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start); |
973 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end); |
974 | |
975 | /* Starting node. */ |
976 | if (ctk_text_iter_in_range (&start, &sr_start_iter, &sr_end_iter)) |
977 | { |
978 | new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion ); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s ); __p; })); |
979 | new_priv->subregions = g_list_prepend (new_priv->subregions, new_sr); |
980 | |
981 | new_sr->start = ctk_text_buffer_create_mark (new_priv->buffer, |
982 | NULL((void*)0), |
983 | &start, |
984 | TRUE(!(0))); |
985 | |
986 | if (start_node == end_node) |
987 | { |
988 | /* Things will finish shortly. */ |
989 | done = TRUE(!(0)); |
990 | if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter)) |
991 | { |
992 | new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer, |
993 | NULL((void*)0), |
994 | &end, |
995 | FALSE(0)); |
996 | } |
997 | else |
998 | { |
999 | new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer, |
1000 | NULL((void*)0), |
1001 | &sr_end_iter, |
1002 | FALSE(0)); |
1003 | } |
1004 | } |
1005 | else |
1006 | { |
1007 | new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer, |
1008 | NULL((void*)0), |
1009 | &sr_end_iter, |
1010 | FALSE(0)); |
1011 | } |
1012 | |
1013 | node = start_node->next; |
1014 | } |
1015 | else |
1016 | { |
1017 | /* start should be the same as the subregion, so copy it in the |
1018 | * loop. |
1019 | */ |
1020 | node = start_node; |
1021 | } |
1022 | |
1023 | if (!done) |
1024 | { |
1025 | while (node != end_node) |
1026 | { |
1027 | /* Copy intermediate subregions verbatim. */ |
1028 | sr = node->data; |
1029 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start); |
1030 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end); |
1031 | |
1032 | new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion ); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s ); __p; })); |
1033 | new_priv->subregions = g_list_prepend (new_priv->subregions, new_sr); |
1034 | |
1035 | new_sr->start = ctk_text_buffer_create_mark (new_priv->buffer, |
1036 | NULL((void*)0), |
1037 | &sr_start_iter, |
1038 | TRUE(!(0))); |
1039 | |
1040 | new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer, |
1041 | NULL((void*)0), |
1042 | &sr_end_iter, |
1043 | FALSE(0)); |
1044 | |
1045 | /* Next node. */ |
1046 | node = node->next; |
1047 | } |
1048 | |
1049 | /* Ending node. */ |
1050 | sr = node->data; |
1051 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start); |
1052 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end); |
1053 | |
1054 | new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion ); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s ); __p; })); |
1055 | new_priv->subregions = g_list_prepend (new_priv->subregions, new_sr); |
1056 | |
1057 | new_sr->start = ctk_text_buffer_create_mark (new_priv->buffer, |
1058 | NULL((void*)0), |
1059 | &sr_start_iter, |
1060 | TRUE(!(0))); |
1061 | |
1062 | if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter)) |
1063 | { |
1064 | new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer, |
1065 | NULL((void*)0), |
1066 | &end, |
1067 | FALSE(0)); |
1068 | } |
1069 | else |
1070 | { |
1071 | new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer, |
1072 | NULL((void*)0), |
1073 | &sr_end_iter, |
1074 | FALSE(0)); |
1075 | } |
1076 | } |
1077 | |
1078 | new_priv->subregions = g_list_reverse (new_priv->subregions); |
1079 | return new_region; |
1080 | } |
1081 | |
1082 | /** |
1083 | * ctk_source_region_intersect_region: |
1084 | * @region1: (nullable): a #CtkSourceRegion, or %NULL. |
1085 | * @region2: (nullable): a #CtkSourceRegion, or %NULL. |
1086 | * |
1087 | * Returns the intersection between @region1 and @region2. @region1 and |
1088 | * @region2 are not modified. |
1089 | * |
1090 | * Returns: (transfer full) (nullable): the intersection as a #CtkSourceRegion |
1091 | * object. |
1092 | * Since: 3.22 |
1093 | */ |
1094 | CtkSourceRegion * |
1095 | ctk_source_region_intersect_region (CtkSourceRegion *region1, |
1096 | CtkSourceRegion *region2) |
1097 | { |
1098 | CtkTextBuffer *region1_buffer; |
1099 | CtkTextBuffer *region2_buffer; |
1100 | CtkSourceRegion *full_intersect = NULL((void*)0); |
1101 | CtkSourceRegionIter region2_iter; |
1102 | |
1103 | g_return_val_if_fail (region1 == NULL || CTK_SOURCE_IS_REGION (region1), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_65 = 0; if (region1 == ((void*)0) || CTK_SOURCE_IS_REGION (region1 )) _g_boolean_var_65 = 1; _g_boolean_var_65; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) ( __func__)), "region1 == NULL || CTK_SOURCE_IS_REGION (region1)" ); return (((void*)0)); } } while (0); |
1104 | g_return_val_if_fail (region2 == NULL || CTK_SOURCE_IS_REGION (region2), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_66 = 0; if (region2 == ((void*)0) || CTK_SOURCE_IS_REGION (region2 )) _g_boolean_var_66 = 1; _g_boolean_var_66; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) ( __func__)), "region2 == NULL || CTK_SOURCE_IS_REGION (region2)" ); return (((void*)0)); } } while (0); |
1105 | |
1106 | if (region1 == NULL((void*)0) && region2 == NULL((void*)0)) |
1107 | { |
1108 | return NULL((void*)0); |
1109 | } |
1110 | if (region1 == NULL((void*)0)) |
1111 | { |
1112 | return g_object_ref (region2)((__typeof__ (region2)) (g_object_ref) (region2)); |
1113 | } |
1114 | if (region2 == NULL((void*)0)) |
1115 | { |
1116 | return g_object_ref (region1)((__typeof__ (region1)) (g_object_ref) (region1)); |
1117 | } |
1118 | |
1119 | region1_buffer = ctk_source_region_get_buffer (region1); |
1120 | region2_buffer = ctk_source_region_get_buffer (region2); |
1121 | g_return_val_if_fail (region1_buffer == region2_buffer, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_67 = 0; if (region1_buffer == region2_buffer) _g_boolean_var_67 = 1; _g_boolean_var_67; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "region1_buffer == region2_buffer" ); return (((void*)0)); } } while (0); |
1122 | |
1123 | if (region1_buffer == NULL((void*)0)) |
1124 | { |
1125 | return NULL((void*)0); |
1126 | } |
1127 | |
1128 | ctk_source_region_get_start_region_iter (region2, ®ion2_iter); |
1129 | |
1130 | while (!ctk_source_region_iter_is_end (®ion2_iter)) |
1131 | { |
1132 | CtkTextIter subregion2_start; |
1133 | CtkTextIter subregion2_end; |
1134 | CtkSourceRegion *sub_intersect; |
1135 | |
1136 | if (!ctk_source_region_iter_get_subregion (®ion2_iter, |
1137 | &subregion2_start, |
1138 | &subregion2_end)) |
1139 | { |
1140 | break; |
1141 | } |
1142 | |
1143 | sub_intersect = ctk_source_region_intersect_subregion (region1, |
1144 | &subregion2_start, |
1145 | &subregion2_end); |
1146 | |
1147 | if (full_intersect == NULL((void*)0)) |
1148 | { |
1149 | full_intersect = sub_intersect; |
1150 | } |
1151 | else |
1152 | { |
1153 | ctk_source_region_add_region (full_intersect, sub_intersect); |
1154 | g_clear_object (&sub_intersect)do { _Static_assert (sizeof *((&sub_intersect)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ ((( &sub_intersect))) _pp = ((&sub_intersect)); __typeof__ (*((&sub_intersect))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0); |
1155 | } |
1156 | |
1157 | ctk_source_region_iter_next (®ion2_iter); |
1158 | } |
1159 | |
1160 | return full_intersect; |
1161 | } |
1162 | |
1163 | static gboolean |
1164 | check_iterator (CtkSourceRegionIterReal *real) |
1165 | { |
1166 | CtkSourceRegionPrivate *priv; |
1167 | |
1168 | if (real->region == NULL((void*)0)) |
1169 | { |
1170 | goto invalid; |
1171 | } |
1172 | |
1173 | priv = ctk_source_region_get_instance_private (real->region); |
1174 | |
1175 | if (real->region_timestamp == priv->timestamp) |
1176 | { |
1177 | return TRUE(!(0)); |
1178 | } |
1179 | |
1180 | invalid: |
1181 | g_warning ("Invalid CtkSourceRegionIter: either the iterator is " |
1182 | "uninitialized, or the region has been modified since the " |
1183 | "iterator was created."); |
1184 | |
1185 | return FALSE(0); |
1186 | } |
1187 | |
1188 | /** |
1189 | * ctk_source_region_get_start_region_iter: |
1190 | * @region: a #CtkSourceRegion. |
1191 | * @iter: (out): iterator to initialize to the first subregion. |
1192 | * |
1193 | * Initializes a #CtkSourceRegionIter to the first subregion of @region. If |
1194 | * @region is empty, @iter will be initialized to the end iterator. |
1195 | * |
1196 | * Since: 3.22 |
1197 | */ |
1198 | void |
1199 | ctk_source_region_get_start_region_iter (CtkSourceRegion *region, |
1200 | CtkSourceRegionIter *iter) |
1201 | { |
1202 | CtkSourceRegionPrivate *priv; |
1203 | CtkSourceRegionIterReal *real; |
1204 | |
1205 | g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_68 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_68 = 1 ; _g_boolean_var_68; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return; } } while (0); |
1206 | g_return_if_fail (iter != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_69 = 0; if (iter != ((void*)0)) _g_boolean_var_69 = 1; _g_boolean_var_69 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
1207 | |
1208 | priv = ctk_source_region_get_instance_private (region); |
1209 | real = (CtkSourceRegionIterReal *)iter; |
1210 | |
1211 | /* priv->subregions may be NULL, -> end iter */ |
1212 | |
1213 | real->region = region; |
1214 | real->subregions = priv->subregions; |
1215 | real->region_timestamp = priv->timestamp; |
1216 | } |
1217 | |
1218 | /** |
1219 | * ctk_source_region_iter_is_end: |
1220 | * @iter: a #CtkSourceRegionIter. |
1221 | * |
1222 | * Returns: whether @iter is the end iterator. |
1223 | * Since: 3.22 |
1224 | */ |
1225 | gboolean |
1226 | ctk_source_region_iter_is_end (CtkSourceRegionIter *iter) |
1227 | { |
1228 | CtkSourceRegionIterReal *real; |
1229 | |
1230 | g_return_val_if_fail (iter != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_70 = 0; if (iter != ((void*)0)) _g_boolean_var_70 = 1; _g_boolean_var_70 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "iter != NULL"); return ((0)); } } while (0); |
1231 | |
1232 | real = (CtkSourceRegionIterReal *)iter; |
1233 | g_return_val_if_fail (check_iterator (real), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_71 = 0; if (check_iterator (real)) _g_boolean_var_71 = 1; _g_boolean_var_71 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "check_iterator (real)"); return ((0)); } } while (0); |
1234 | |
1235 | return real->subregions == NULL((void*)0); |
1236 | } |
1237 | |
1238 | /** |
1239 | * ctk_source_region_iter_next: |
1240 | * @iter: a #CtkSourceRegionIter. |
1241 | * |
1242 | * Moves @iter to the next subregion. |
1243 | * |
1244 | * Returns: %TRUE if @iter moved and is dereferenceable, or %FALSE if @iter has |
1245 | * been set to the end iterator. |
1246 | * Since: 3.22 |
1247 | */ |
1248 | gboolean |
1249 | ctk_source_region_iter_next (CtkSourceRegionIter *iter) |
1250 | { |
1251 | CtkSourceRegionIterReal *real; |
1252 | |
1253 | g_return_val_if_fail (iter != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_72 = 0; if (iter != ((void*)0)) _g_boolean_var_72 = 1; _g_boolean_var_72 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "iter != NULL"); return ((0)); } } while (0); |
1254 | |
1255 | real = (CtkSourceRegionIterReal *)iter; |
1256 | g_return_val_if_fail (check_iterator (real), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_73 = 0; if (check_iterator (real)) _g_boolean_var_73 = 1; _g_boolean_var_73 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "check_iterator (real)"); return ((0)); } } while (0); |
1257 | |
1258 | if (real->subregions != NULL((void*)0)) |
1259 | { |
1260 | real->subregions = real->subregions->next; |
1261 | return TRUE(!(0)); |
1262 | } |
1263 | |
1264 | return FALSE(0); |
1265 | } |
1266 | |
1267 | /** |
1268 | * ctk_source_region_iter_get_subregion: |
1269 | * @iter: a #CtkSourceRegionIter. |
1270 | * @start: (out) (optional): iterator to initialize with the subregion start, or %NULL. |
1271 | * @end: (out) (optional): iterator to initialize with the subregion end, or %NULL. |
1272 | * |
1273 | * Gets the subregion at this iterator. |
1274 | * |
1275 | * Returns: %TRUE if @start and @end have been set successfully (if non-%NULL), |
1276 | * or %FALSE if @iter is the end iterator or if the region is empty. |
1277 | * Since: 3.22 |
1278 | */ |
1279 | gboolean |
1280 | ctk_source_region_iter_get_subregion (CtkSourceRegionIter *iter, |
1281 | CtkTextIter *start, |
1282 | CtkTextIter *end) |
1283 | { |
1284 | CtkSourceRegionIterReal *real; |
1285 | CtkSourceRegionPrivate *priv; |
1286 | Subregion *sr; |
1287 | |
1288 | g_return_val_if_fail (iter != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_74 = 0; if (iter != ((void*)0)) _g_boolean_var_74 = 1; _g_boolean_var_74 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "iter != NULL"); return ((0)); } } while (0); |
1289 | |
1290 | real = (CtkSourceRegionIterReal *)iter; |
1291 | g_return_val_if_fail (check_iterator (real), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_75 = 0; if (check_iterator (real)) _g_boolean_var_75 = 1; _g_boolean_var_75 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "check_iterator (real)"); return ((0)); } } while (0); |
1292 | |
1293 | if (real->subregions == NULL((void*)0)) |
1294 | { |
1295 | return FALSE(0); |
1296 | } |
1297 | |
1298 | priv = ctk_source_region_get_instance_private (real->region); |
1299 | |
1300 | if (priv->buffer == NULL((void*)0)) |
1301 | { |
1302 | return FALSE(0); |
1303 | } |
1304 | |
1305 | sr = real->subregions->data; |
1306 | g_return_val_if_fail (sr != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_76 = 0; if (sr != ((void*)0)) _g_boolean_var_76 = 1; _g_boolean_var_76 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "sr != NULL"); return ((0)); } } while (0); |
1307 | |
1308 | if (start != NULL((void*)0)) |
1309 | { |
1310 | ctk_text_buffer_get_iter_at_mark (priv->buffer, start, sr->start); |
1311 | } |
1312 | |
1313 | if (end != NULL((void*)0)) |
1314 | { |
1315 | ctk_text_buffer_get_iter_at_mark (priv->buffer, end, sr->end); |
1316 | } |
1317 | |
1318 | return TRUE(!(0)); |
1319 | } |
1320 | |
1321 | /** |
1322 | * ctk_source_region_to_string: |
1323 | * @region: a #CtkSourceRegion. |
1324 | * |
1325 | * Gets a string represention of @region, for debugging purposes. |
1326 | * |
1327 | * The returned string contains the character offsets of the subregions. It |
1328 | * doesn't include a newline character at the end of the string. |
1329 | * |
1330 | * Returns: (transfer full) (nullable): a string represention of @region. Free |
1331 | * with g_free() when no longer needed. |
1332 | * Since: 3.22 |
1333 | */ |
1334 | gchar * |
1335 | ctk_source_region_to_string (CtkSourceRegion *region) |
1336 | { |
1337 | CtkSourceRegionPrivate *priv; |
1338 | GString *string; |
1339 | GList *l; |
1340 | |
1341 | g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_77 = 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_77 = 1 ; _g_boolean_var_77; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)" ); return (((void*)0)); } } while (0); |
1342 | |
1343 | priv = ctk_source_region_get_instance_private (region); |
1344 | |
1345 | if (priv->buffer == NULL((void*)0)) |
1346 | { |
1347 | return NULL((void*)0); |
1348 | } |
1349 | |
1350 | string = g_string_new ("Subregions:"); |
1351 | |
1352 | for (l = priv->subregions; l != NULL((void*)0); l = l->next) |
1353 | { |
1354 | Subregion *sr = l->data; |
1355 | CtkTextIter start; |
1356 | CtkTextIter end; |
1357 | |
1358 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &start, sr->start); |
1359 | ctk_text_buffer_get_iter_at_mark (priv->buffer, &end, sr->end); |
1360 | |
1361 | g_string_append_printf (string, |
1362 | " %d-%d", |
1363 | ctk_text_iter_get_offset (&start), |
1364 | ctk_text_iter_get_offset (&end)); |
1365 | } |
1366 | |
1367 | return g_string_free (string, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((string ), ((0))) : g_string_free_and_steal (string)) : (g_string_free ) ((string), ((0)))); |
1368 | } |