File: | _build/../ctksourceview/ctksourceutils.c |
Warning: | line 727, column 3 Value stored to 'scroll_dest' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */ |
2 | /* |
3 | * This file is part of CtkSourceView |
4 | * |
5 | * Copyright (C) 2005 - Paolo Borelli |
6 | * Copyright (C) 2007 - Gustavo Giráldez |
7 | * Copyright (C) 2007 - Paolo Maggi |
8 | * Copyright (C) 2013, 2017 - Sébastien Wilmet <swilmet@gnome.org> |
9 | * |
10 | * CtkSourceView is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU Lesser General Public |
12 | * License as published by the Free Software Foundation; either |
13 | * version 2.1 of the License, or (at your option) any later version. |
14 | * |
15 | * CtkSourceView is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * Lesser General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU Lesser General Public License |
21 | * along with this library; if not, see <http://www.gnu.org/licenses/>. |
22 | */ |
23 | |
24 | /** |
25 | * SECTION:utils |
26 | * @title: CtkSourceUtils |
27 | * @short_description: Utility functions |
28 | * |
29 | * Utility functions. |
30 | */ |
31 | |
32 | #ifdef HAVE_CONFIG_H1 |
33 | #include <config.h> |
34 | #endif |
35 | |
36 | #include "ctksourceutils.h" |
37 | #include "ctksourceutils-private.h" |
38 | #include <string.h> |
39 | #include <errno(*__errno_location ()).h> |
40 | #include <math.h> |
41 | #include <glib/gi18n-lib.h> |
42 | |
43 | /** |
44 | * ctk_source_utils_unescape_search_text: |
45 | * @text: the text to unescape. |
46 | * |
47 | * Use this function before ctk_source_search_settings_set_search_text(), to |
48 | * unescape the following sequences of characters: `\n`, `\r`, `\t` and `\\`. |
49 | * The purpose is to easily write those characters in a search entry. |
50 | * |
51 | * Note that unescaping the search text is not needed for regular expression |
52 | * searches. |
53 | * |
54 | * See also: ctk_source_utils_escape_search_text(). |
55 | * |
56 | * Returns: the unescaped @text. |
57 | * Since: 3.10 |
58 | */ |
59 | gchar * |
60 | ctk_source_utils_unescape_search_text (const gchar *text) |
61 | { |
62 | GString *str; |
63 | gint length; |
64 | gboolean drop_prev = FALSE(0); |
65 | const gchar *cur; |
66 | const gchar *end; |
67 | const gchar *prev; |
68 | |
69 | if (text == NULL((void*)0)) |
70 | { |
71 | return NULL((void*)0); |
72 | } |
73 | |
74 | length = strlen (text); |
75 | |
76 | str = g_string_new (""); |
77 | |
78 | cur = text; |
79 | end = text + length; |
80 | prev = NULL((void*)0); |
81 | |
82 | while (cur != end) |
83 | { |
84 | const gchar *next; |
85 | next = g_utf8_next_char (cur)((cur) + g_utf8_skip[*(const guchar *)(cur)]); |
86 | |
87 | if (prev && (*prev == '\\')) |
88 | { |
89 | switch (*cur) |
90 | { |
91 | case 'n': |
92 | str = g_string_append (str, "\n")(__builtin_constant_p ("\n") ? __extension__ ({ const char * const __val = ("\n"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_51 = 0; if (__val != (( void*)0)) _g_boolean_var_51 = 1; _g_boolean_var_51; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\n", (gssize) -1)); |
93 | break; |
94 | case 'r': |
95 | str = g_string_append (str, "\r")(__builtin_constant_p ("\r") ? __extension__ ({ const char * const __val = ("\r"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_52 = 0; if (__val != (( void*)0)) _g_boolean_var_52 = 1; _g_boolean_var_52; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\r", (gssize) -1)); |
96 | break; |
97 | case 't': |
98 | str = g_string_append (str, "\t")(__builtin_constant_p ("\t") ? __extension__ ({ const char * const __val = ("\t"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_53 = 0; if (__val != (( void*)0)) _g_boolean_var_53 = 1; _g_boolean_var_53; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\t", (gssize) -1)); |
99 | break; |
100 | case '\\': |
101 | str = g_string_append (str, "\\")(__builtin_constant_p ("\\") ? __extension__ ({ const char * const __val = ("\\"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_54 = 0; if (__val != (( void*)0)) _g_boolean_var_54 = 1; _g_boolean_var_54; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\", (gssize) -1)); |
102 | drop_prev = TRUE(!(0)); |
103 | break; |
104 | default: |
105 | str = g_string_append (str, "\\")(__builtin_constant_p ("\\") ? __extension__ ({ const char * const __val = ("\\"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_55 = 0; if (__val != (( void*)0)) _g_boolean_var_55 = 1; _g_boolean_var_55; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\", (gssize) -1)); |
106 | str = g_string_append_len (str, cur, next - cur)g_string_append_len_inline (str, cur, next - cur); |
107 | break; |
108 | } |
109 | } |
110 | else if (*cur != '\\') |
111 | { |
112 | str = g_string_append_len (str, cur, next - cur)g_string_append_len_inline (str, cur, next - cur); |
113 | } |
114 | else if ((next == end) && (*cur == '\\')) |
115 | { |
116 | str = g_string_append (str, "\\")(__builtin_constant_p ("\\") ? __extension__ ({ const char * const __val = ("\\"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_56 = 0; if (__val != (( void*)0)) _g_boolean_var_56 = 1; _g_boolean_var_56; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\", (gssize) -1)); |
117 | } |
118 | |
119 | if (!drop_prev) |
120 | { |
121 | prev = cur; |
122 | } |
123 | else |
124 | { |
125 | prev = NULL((void*)0); |
126 | drop_prev = FALSE(0); |
127 | } |
128 | |
129 | cur = next; |
130 | } |
131 | |
132 | return g_string_free (str, FALSE(0)); |
133 | } |
134 | |
135 | /** |
136 | * ctk_source_utils_escape_search_text: |
137 | * @text: the text to escape. |
138 | * |
139 | * Use this function to escape the following characters: `\n`, `\r`, `\t` and `\`. |
140 | * |
141 | * For a regular expression search, use g_regex_escape_string() instead. |
142 | * |
143 | * One possible use case is to take the #CtkTextBuffer's selection and put it in a |
144 | * search entry. The selection can contain tabulations, newlines, etc. So it's |
145 | * better to escape those special characters to better fit in the search entry. |
146 | * |
147 | * See also: ctk_source_utils_unescape_search_text(). |
148 | * |
149 | * <warning> |
150 | * Warning: the escape and unescape functions are not reciprocal! For example, |
151 | * escape (unescape (\)) = \\. So avoid cycles such as: search entry -> unescape |
152 | * -> search settings -> escape -> search entry. The original search entry text |
153 | * may be modified. |
154 | * </warning> |
155 | * |
156 | * Returns: the escaped @text. |
157 | * Since: 3.10 |
158 | */ |
159 | gchar * |
160 | ctk_source_utils_escape_search_text (const gchar* text) |
161 | { |
162 | GString *str; |
163 | gint length; |
164 | const gchar *p; |
165 | const gchar *end; |
166 | |
167 | if (text == NULL((void*)0)) |
168 | { |
169 | return NULL((void*)0); |
170 | } |
171 | |
172 | length = strlen (text); |
173 | |
174 | str = g_string_new (""); |
175 | |
176 | p = text; |
177 | end = text + length; |
178 | |
179 | while (p != end) |
180 | { |
181 | const gchar *next = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]); |
182 | |
183 | switch (*p) |
184 | { |
185 | case '\n': |
186 | g_string_append (str, "\\n")(__builtin_constant_p ("\\n") ? __extension__ ({ const char * const __val = ("\\n"); g_string_append_len_inline (str, __val , (__builtin_expect (__extension__ ({ int _g_boolean_var_57 = 0; if (__val != ((void*)0)) _g_boolean_var_57 = 1; _g_boolean_var_57 ; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\n", (gssize) - 1)); |
187 | break; |
188 | case '\r': |
189 | g_string_append (str, "\\r")(__builtin_constant_p ("\\r") ? __extension__ ({ const char * const __val = ("\\r"); g_string_append_len_inline (str, __val , (__builtin_expect (__extension__ ({ int _g_boolean_var_58 = 0; if (__val != ((void*)0)) _g_boolean_var_58 = 1; _g_boolean_var_58 ; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\r", (gssize) - 1)); |
190 | break; |
191 | case '\t': |
192 | g_string_append (str, "\\t")(__builtin_constant_p ("\\t") ? __extension__ ({ const char * const __val = ("\\t"); g_string_append_len_inline (str, __val , (__builtin_expect (__extension__ ({ int _g_boolean_var_59 = 0; if (__val != ((void*)0)) _g_boolean_var_59 = 1; _g_boolean_var_59 ; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\t", (gssize) - 1)); |
193 | break; |
194 | case '\\': |
195 | g_string_append (str, "\\\\")(__builtin_constant_p ("\\\\") ? __extension__ ({ const char * const __val = ("\\\\"); g_string_append_len_inline (str, __val , (__builtin_expect (__extension__ ({ int _g_boolean_var_60 = 0; if (__val != ((void*)0)) _g_boolean_var_60 = 1; _g_boolean_var_60 ; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, "\\\\", (gssize) - 1)); |
196 | break; |
197 | default: |
198 | g_string_append_len (str, p, next - p)g_string_append_len_inline (str, p, next - p); |
199 | break; |
200 | } |
201 | |
202 | p = next; |
203 | } |
204 | |
205 | return g_string_free (str, FALSE(0)); |
206 | } |
207 | |
208 | #define GSV_DATA_SUBDIR"ctksourceview-" "4" "ctksourceview-" GSV_API_VERSION_S"4" |
209 | |
210 | gchar ** |
211 | _ctk_source_utils_get_default_dirs (const gchar *basename) |
212 | { |
213 | const gchar * const *system_dirs; |
214 | GPtrArray *dirs; |
215 | |
216 | dirs = g_ptr_array_new (); |
217 | |
218 | /* User dir */ |
219 | g_ptr_array_add (dirs, g_build_filename (g_get_user_data_dir (), |
220 | GSV_DATA_SUBDIR"ctksourceview-" "4", |
221 | basename, |
222 | NULL((void*)0))); |
223 | |
224 | /* System dirs */ |
225 | for (system_dirs = g_get_system_data_dirs (); |
226 | system_dirs != NULL((void*)0) && *system_dirs != NULL((void*)0); |
227 | system_dirs++) |
228 | { |
229 | g_ptr_array_add (dirs, g_build_filename (*system_dirs, |
230 | GSV_DATA_SUBDIR"ctksourceview-" "4", |
231 | basename, |
232 | NULL((void*)0))); |
233 | } |
234 | |
235 | g_ptr_array_add (dirs, NULL((void*)0)); |
236 | |
237 | return (gchar **) g_ptr_array_free (dirs, FALSE(0)); |
238 | } |
239 | |
240 | static GSList * |
241 | build_file_listing (const gchar *item, |
242 | GSList *filenames, |
243 | const gchar *suffix, |
244 | gboolean only_dirs) |
245 | { |
246 | GDir *dir; |
247 | const gchar *name; |
248 | |
249 | if (!only_dirs && g_file_test (item, G_FILE_TEST_IS_REGULAR)) |
250 | { |
251 | filenames = g_slist_prepend (filenames, g_strdup(item)g_strdup_inline (item)); |
252 | return filenames; |
253 | |
254 | } |
255 | dir = g_dir_open (item, 0, NULL((void*)0)); |
256 | |
257 | if (dir == NULL((void*)0)) |
258 | { |
259 | return filenames; |
260 | } |
261 | |
262 | while ((name = g_dir_read_name (dir)) != NULL((void*)0)) |
263 | { |
264 | gchar *full_path = g_build_filename (item, name, NULL((void*)0)); |
265 | |
266 | if (!g_file_test (full_path, G_FILE_TEST_IS_DIR) && |
267 | g_str_has_suffix (name, suffix)(__builtin_constant_p (suffix)? __extension__ ({ const char * const __str = (name); const char * const __suffix = (suffix) ; gboolean __result = (0); if (__builtin_expect (__extension__ ({ int _g_boolean_var_61 = 0; if (__str == ((void*)0) || __suffix == ((void*)0)) _g_boolean_var_61 = 1; _g_boolean_var_61; }), 0)) __result = (g_str_has_suffix) (__str, __suffix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len , ((__suffix) + !(__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix) (name, suffix) )) |
268 | { |
269 | filenames = g_slist_prepend (filenames, full_path); |
270 | } |
271 | else |
272 | { |
273 | g_free (full_path); |
274 | } |
275 | } |
276 | |
277 | g_dir_close (dir); |
278 | |
279 | return filenames; |
280 | } |
281 | |
282 | GSList * |
283 | _ctk_source_utils_get_file_list (gchar **path, |
284 | const gchar *suffix, |
285 | gboolean only_dirs) |
286 | { |
287 | GSList *files = NULL((void*)0); |
288 | |
289 | for ( ; path && *path; ++path) |
290 | { |
291 | files = build_file_listing (*path, files, suffix, only_dirs); |
292 | } |
293 | |
294 | return g_slist_reverse (files); |
295 | } |
296 | |
297 | /* Wrapper around strtoull for easier use: tries |
298 | * to convert @str to a number and return -1 if it is not. |
299 | * Used to check if references in subpattern contexts |
300 | * (e.g. \%{1@start} or \%{blah@start}) are named or numbers. |
301 | */ |
302 | gint |
303 | _ctk_source_utils_string_to_int (const gchar *str) |
304 | { |
305 | guint64 number; |
306 | gchar *end_str; |
307 | |
308 | if (str == NULL((void*)0) || *str == '\0') |
309 | { |
310 | return -1; |
311 | } |
312 | |
313 | errno(*__errno_location ()) = 0; |
314 | number = g_ascii_strtoull (str, &end_str, 10); |
315 | |
316 | if (errno(*__errno_location ()) != 0 || number > G_MAXINT2147483647 || *end_str != '\0') |
317 | { |
318 | return -1; |
319 | } |
320 | |
321 | return number; |
322 | } |
323 | |
324 | #define FONT_FAMILY"font-family" "font-family" |
325 | #define FONT_VARIANT"font-variant" "font-variant" |
326 | #define FONT_STRETCH"font-stretch" "font-stretch" |
327 | #define FONT_WEIGHT"font-weight" "font-weight" |
328 | #define FONT_STYLE"font-style" "font-style" |
329 | #define FONT_SIZE"font-size" "font-size" |
330 | |
331 | gchar * |
332 | _ctk_source_utils_pango_font_description_to_css (const PangoFontDescription *font_desc) |
333 | { |
334 | PangoFontMask mask; |
335 | GString *str; |
336 | |
337 | #define ADD_KEYVAL(key,fmt) \ |
338 | g_string_append(str,key":"fmt";")(__builtin_constant_p (key":"fmt";") ? __extension__ ({ const char * const __val = (key":"fmt";"); g_string_append_len_inline (str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_62 = 0; if (__val != ((void*)0)) _g_boolean_var_62 = 1; _g_boolean_var_62 ; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (str, key":"fmt";", (gssize ) -1)) |
339 | #define ADD_KEYVAL_PRINTF(key,fmt,...) \ |
340 | g_string_append_printf(str,key":"fmt";", __VA_ARGS__) |
341 | |
342 | g_return_val_if_fail (font_desc, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_63 = 0; if (font_desc) _g_boolean_var_63 = 1; _g_boolean_var_63 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "font_desc"); return (((void*)0 )); } } while (0); |
343 | |
344 | str = g_string_new (NULL((void*)0)); |
345 | |
346 | mask = pango_font_description_get_set_fields (font_desc); |
347 | |
348 | if ((mask & PANGO_FONT_MASK_FAMILY) != 0) |
349 | { |
350 | const gchar *family; |
351 | |
352 | family = pango_font_description_get_family (font_desc); |
353 | ADD_KEYVAL_PRINTF (FONT_FAMILY"font-family", "\"%s\"", family); |
354 | } |
355 | |
356 | if ((mask & PANGO_FONT_MASK_STYLE) != 0) |
357 | { |
358 | PangoStyle style; |
359 | |
360 | style = pango_font_description_get_style (font_desc); |
361 | |
362 | switch (style) |
363 | { |
364 | case PANGO_STYLE_NORMAL: |
365 | ADD_KEYVAL (FONT_STYLE"font-style", "normal"); |
366 | break; |
367 | |
368 | case PANGO_STYLE_OBLIQUE: |
369 | ADD_KEYVAL (FONT_STYLE"font-style", "oblique"); |
370 | break; |
371 | |
372 | case PANGO_STYLE_ITALIC: |
373 | ADD_KEYVAL (FONT_STYLE"font-style", "italic"); |
374 | break; |
375 | |
376 | default: |
377 | break; |
378 | } |
379 | } |
380 | |
381 | if ((mask & PANGO_FONT_MASK_VARIANT) != 0) |
382 | { |
383 | PangoVariant variant; |
384 | |
385 | variant = pango_font_description_get_variant (font_desc); |
386 | |
387 | switch (variant) |
388 | { |
389 | case PANGO_VARIANT_NORMAL: |
390 | ADD_KEYVAL (FONT_VARIANT"font-variant", "normal"); |
391 | break; |
392 | |
393 | case PANGO_VARIANT_SMALL_CAPS: |
394 | ADD_KEYVAL (FONT_VARIANT"font-variant", "small-caps"); |
395 | break; |
396 | |
397 | #if PANGO_VERSION_CHECK(1, 49, 3)(( ((1) * 10000) + ((56) * 100) + ((3) * 1)) >= ( ((1) * 10000 ) + ((49) * 100) + ((3) * 1))) |
398 | case PANGO_VARIANT_ALL_SMALL_CAPS: |
399 | ADD_KEYVAL (FONT_VARIANT"font-variant", "all-small-caps"); |
400 | break; |
401 | |
402 | case PANGO_VARIANT_PETITE_CAPS: |
403 | ADD_KEYVAL (FONT_VARIANT"font-variant", "petite-caps"); |
404 | break; |
405 | |
406 | case PANGO_VARIANT_ALL_PETITE_CAPS: |
407 | ADD_KEYVAL (FONT_VARIANT"font-variant", "all-petite-caps"); |
408 | break; |
409 | |
410 | case PANGO_VARIANT_UNICASE: |
411 | ADD_KEYVAL (FONT_VARIANT"font-variant", "unicase"); |
412 | break; |
413 | |
414 | case PANGO_VARIANT_TITLE_CAPS: |
415 | ADD_KEYVAL (FONT_VARIANT"font-variant", "titling-caps"); |
416 | break; |
417 | #endif |
418 | |
419 | default: |
420 | break; |
421 | } |
422 | } |
423 | |
424 | if ((mask & PANGO_FONT_MASK_WEIGHT)) |
425 | { |
426 | gint weight; |
427 | |
428 | weight = pango_font_description_get_weight (font_desc); |
429 | |
430 | /* |
431 | * WORKAROUND: |
432 | * |
433 | * font-weight with numbers does not appear to be working as expected |
434 | * right now. So for the common (bold/normal), let's just use the string |
435 | * and let ctk warn for the other values, which shouldn't really be |
436 | * used for this. |
437 | */ |
438 | |
439 | switch (weight) |
440 | { |
441 | case PANGO_WEIGHT_SEMILIGHT: |
442 | /* |
443 | * 350 is not actually a valid css font-weight, so we will just round |
444 | * up to 400. |
445 | */ |
446 | case PANGO_WEIGHT_NORMAL: |
447 | ADD_KEYVAL (FONT_WEIGHT"font-weight", "normal"); |
448 | break; |
449 | |
450 | case PANGO_WEIGHT_BOLD: |
451 | ADD_KEYVAL (FONT_WEIGHT"font-weight", "bold"); |
452 | break; |
453 | |
454 | case PANGO_WEIGHT_THIN: |
455 | case PANGO_WEIGHT_ULTRALIGHT: |
456 | case PANGO_WEIGHT_LIGHT: |
457 | case PANGO_WEIGHT_BOOK: |
458 | case PANGO_WEIGHT_MEDIUM: |
459 | case PANGO_WEIGHT_SEMIBOLD: |
460 | case PANGO_WEIGHT_ULTRABOLD: |
461 | case PANGO_WEIGHT_HEAVY: |
462 | case PANGO_WEIGHT_ULTRAHEAVY: |
463 | default: |
464 | /* round to nearest hundred */ |
465 | weight = round (weight / 100.0) * 100; |
466 | ADD_KEYVAL_PRINTF ("font-weight", "%d", weight); |
467 | break; |
468 | } |
469 | } |
470 | |
471 | if ((mask & PANGO_FONT_MASK_STRETCH)) |
472 | { |
473 | switch (pango_font_description_get_stretch (font_desc)) |
474 | { |
475 | case PANGO_STRETCH_ULTRA_CONDENSED: |
476 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "ultra-condensed"); |
477 | break; |
478 | |
479 | case PANGO_STRETCH_EXTRA_CONDENSED: |
480 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "extra-condensed"); |
481 | break; |
482 | |
483 | case PANGO_STRETCH_CONDENSED: |
484 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "condensed"); |
485 | break; |
486 | |
487 | case PANGO_STRETCH_SEMI_CONDENSED: |
488 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "semi-condensed"); |
489 | break; |
490 | |
491 | case PANGO_STRETCH_NORMAL: |
492 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "normal"); |
493 | break; |
494 | |
495 | case PANGO_STRETCH_SEMI_EXPANDED: |
496 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "semi-expanded"); |
497 | break; |
498 | |
499 | case PANGO_STRETCH_EXPANDED: |
500 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "expanded"); |
501 | break; |
502 | |
503 | case PANGO_STRETCH_EXTRA_EXPANDED: |
504 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "extra-expanded"); |
505 | break; |
506 | |
507 | case PANGO_STRETCH_ULTRA_EXPANDED: |
508 | ADD_KEYVAL (FONT_STRETCH"font-stretch", "ultra-expanded"); |
509 | break; |
510 | |
511 | default: |
512 | break; |
513 | } |
514 | } |
515 | |
516 | if ((mask & PANGO_FONT_MASK_SIZE)) |
517 | { |
518 | gint font_size; |
519 | |
520 | font_size = pango_font_description_get_size (font_desc) / PANGO_SCALE1024; |
521 | ADD_KEYVAL_PRINTF ("font-size", "%dpt", font_size); |
522 | } |
523 | |
524 | return g_string_free (str, FALSE(0)); |
525 | |
526 | #undef ADD_KEYVAL |
527 | #undef ADD_KEYVAL_PRINTF |
528 | } |
529 | |
530 | /* |
531 | * _ctk_source_utils_dgettext: |
532 | * |
533 | * Try to translate string from given domain. It returns |
534 | * duplicated string which must be freed with g_free(). |
535 | */ |
536 | gchar * |
537 | _ctk_source_utils_dgettext (const gchar *domain, |
538 | const gchar *string) |
539 | { |
540 | const gchar *translated; |
541 | gchar *tmp; |
542 | |
543 | g_return_val_if_fail (string != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_64 = 0; if (string != ((void*)0)) _g_boolean_var_64 = 1; _g_boolean_var_64 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "string != NULL"); return (((void *)0)); } } while (0); |
544 | |
545 | if (domain == NULL((void*)0)) |
546 | { |
547 | return g_strdup (_(string))g_strdup_inline (((char *) g_dgettext ("ctksourceview-4", string ))); |
548 | } |
549 | |
550 | translated = dgettext (domain, string)dcgettext (domain, string, 5); |
551 | |
552 | if (g_strcmp0 (translated, string) == 0) |
553 | { |
554 | return g_strdup (_(string))g_strdup_inline (((char *) g_dgettext ("ctksourceview-4", string ))); |
555 | } |
556 | |
557 | if (g_utf8_validate (translated, -1, NULL((void*)0))) |
558 | { |
559 | return g_strdup (translated)g_strdup_inline (translated); |
560 | } |
561 | |
562 | tmp = g_locale_to_utf8 (translated, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
563 | return tmp != NULL((void*)0) ? tmp : g_strdup (string)g_strdup_inline (string); |
564 | } |
565 | |
566 | /* |
567 | * _ctk_source_utils_int_to_string: |
568 | * @value: the integer to convert to a string |
569 | * @outstr: (out): a location for a pointer to the result string |
570 | * |
571 | * The following implementation uses an internal cache to speed up the |
572 | * conversion of integers to strings by comparing the value to the |
573 | * previous value that was calculated. |
574 | * |
575 | * If we detect a simple increment, we can alter the previous string directly |
576 | * and then carry the number to each of the previous chars sequentually. If we |
577 | * still have a carry bit at the end of the loop, we need to move the whole |
578 | * string over 1 place to take account for the new "1" at the start. |
579 | * |
580 | * This function is not thread-safe, as the resulting string is stored in |
581 | * static data. |
582 | * |
583 | * Returns: the number of characters in the resulting string |
584 | */ |
585 | gint |
586 | _ctk_source_utils_int_to_string (guint value, |
587 | const gchar **outstr) |
588 | { |
589 | static struct{ |
590 | guint value; |
591 | guint len; |
592 | gchar str[12]; |
593 | } fi; |
594 | |
595 | *outstr = fi.str; |
596 | |
597 | if (value == fi.value) |
598 | { |
599 | return fi.len; |
600 | } |
601 | |
602 | if G_LIKELY (value == fi.value + 1)(__builtin_expect (__extension__ ({ int _g_boolean_var_65 = 0 ; if (value == fi.value + 1) _g_boolean_var_65 = 1; _g_boolean_var_65 ; }), 1)) |
603 | { |
604 | guint carry = 1; |
605 | gint i; |
606 | |
607 | for (i = fi.len - 1; i >= 0; i--) |
608 | { |
609 | fi.str[i] += carry; |
610 | carry = fi.str[i] == ':'; |
611 | |
612 | if (carry) |
613 | { |
614 | fi.str[i] = '0'; |
615 | } |
616 | else |
617 | { |
618 | break; |
619 | } |
620 | } |
621 | |
622 | if G_UNLIKELY (carry)(__builtin_expect (__extension__ ({ int _g_boolean_var_66 = 0 ; if (carry) _g_boolean_var_66 = 1; _g_boolean_var_66; }), 0) ) |
623 | { |
624 | for (i = fi.len; i > 0; i--) |
625 | { |
626 | fi.str[i] = fi.str[i-1]; |
627 | } |
628 | |
629 | fi.len++; |
630 | fi.str[0] = '1'; |
631 | fi.str[fi.len] = 0; |
632 | } |
633 | |
634 | fi.value++; |
635 | |
636 | return fi.len; |
637 | } |
638 | |
639 | #ifdef G_OS_WIN32 |
640 | fi.len = g_snprintf (fi.str, sizeof fi.str - 1, "%u", value); |
641 | #else |
642 | /* Use snprintf() directly when possible to reduce overhead */ |
643 | fi.len = snprintf (fi.str, sizeof fi.str - 1, "%u", value); |
644 | #endif |
645 | fi.str[fi.len] = 0; |
646 | fi.value = value; |
647 | |
648 | return fi.len; |
649 | } |
650 | |
651 | /* |
652 | * The goal of this function is to be like ctk_text_view_scroll_to_iter() but |
653 | * without any of the scrolling animation. We use it from the source map where |
654 | * the updates are so fast the scrolling animation makes it feel very delayed. |
655 | * |
656 | * Many parts of this function were taken from ctk_text_view_scroll_to_iter () |
657 | * https://developer.gnome.org/ctk3/stable/CtkTextView.html#ctk-text-view-scroll-to-iter |
658 | */ |
659 | void |
660 | _ctk_source_view_jump_to_iter (CtkTextView *text_view, |
661 | const CtkTextIter *iter, |
662 | double within_margin, |
663 | gboolean use_align, |
664 | double xalign, |
665 | double yalign) |
666 | { |
667 | CtkAdjustment *hadj; |
668 | CtkAdjustment *vadj; |
669 | CdkRectangle rect; |
670 | CdkRectangle screen; |
671 | int xvalue = 0; |
672 | int yvalue = 0; |
673 | int scroll_dest; |
674 | int screen_bottom; |
675 | int screen_right; |
676 | int screen_xoffset; |
677 | int screen_yoffset; |
678 | int current_x_scroll; |
679 | int current_y_scroll; |
680 | |
681 | g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_67 = 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((text_view)); GType __t = ((ctk_text_view_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_67 = 1; _g_boolean_var_67; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "CTK_IS_TEXT_VIEW (text_view)" ); return; } } while (0); |
682 | g_return_if_fail (iter != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_68 = 0; if (iter != ((void*)0)) _g_boolean_var_68 = 1; _g_boolean_var_68 ; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView" , ((const char*) (__func__)), "iter != NULL"); return; } } while (0); |
683 | g_return_if_fail (within_margin >= 0.0 && within_margin <= 0.5)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_69 = 0; if (within_margin >= 0.0 && within_margin <= 0.5) _g_boolean_var_69 = 1; _g_boolean_var_69; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) ( __func__)), "within_margin >= 0.0 && within_margin <= 0.5" ); return; } } while (0); |
684 | g_return_if_fail (xalign >= 0.0 && xalign <= 1.0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_70 = 0; if (xalign >= 0.0 && xalign <= 1.0) _g_boolean_var_70 = 1; _g_boolean_var_70; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "xalign >= 0.0 && xalign <= 1.0" ); return; } } while (0); |
685 | g_return_if_fail (yalign >= 0.0 && yalign <= 1.0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_71 = 0; if (yalign >= 0.0 && yalign <= 1.0) _g_boolean_var_71 = 1; _g_boolean_var_71; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView", ((const char*) (__func__)), "yalign >= 0.0 && yalign <= 1.0" ); return; } } while (0); |
686 | |
687 | hadj = ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (text_view)((((CtkScrollable*) (void *) ((text_view)))))); |
688 | vadj = ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (text_view)((((CtkScrollable*) (void *) ((text_view)))))); |
689 | |
690 | ctk_text_view_get_iter_location (text_view, iter, &rect); |
691 | ctk_text_view_get_visible_rect (text_view, &screen); |
692 | |
693 | current_x_scroll = screen.x; |
694 | current_y_scroll = screen.y; |
695 | |
696 | screen_xoffset = screen.width * within_margin; |
697 | screen_yoffset = screen.height * within_margin; |
698 | |
699 | screen.x += screen_xoffset; |
700 | screen.y += screen_yoffset; |
701 | screen.width -= screen_xoffset * 2; |
702 | screen.height -= screen_yoffset * 2; |
703 | |
704 | |
705 | /* paranoia check */ |
706 | if (screen.width < 1) |
707 | screen.width = 1; |
708 | if (screen.height < 1) |
709 | screen.height = 1; |
710 | |
711 | /* The -1 here ensures that we leave enough space to draw the cursor |
712 | * when this function is used for horizontal scrolling. |
713 | */ |
714 | screen_right = screen.x + screen.width - 1; |
715 | screen_bottom = screen.y + screen.height; |
716 | |
717 | |
718 | /* The alignment affects the point in the target character that we |
719 | * choose to align. If we're doing right/bottom alignment, we align |
720 | * the right/bottom edge of the character the mark is at; if we're |
721 | * doing left/top we align the left/top edge of the character; if |
722 | * we're doing center alignment we align the center of the |
723 | * character. |
724 | */ |
725 | |
726 | /* Vertical alignment */ |
727 | scroll_dest = current_y_scroll; |
Value stored to 'scroll_dest' is never read | |
728 | if (use_align) |
729 | { |
730 | scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign); |
731 | |
732 | /* if scroll_dest < screen.y, we move a negative increment (up), |
733 | * else a positive increment (down) |
734 | */ |
735 | yvalue = scroll_dest - screen.y + screen_yoffset; |
736 | } |
737 | else |
738 | { |
739 | /* move minimum to get onscreen */ |
740 | if (rect.y < screen.y) |
741 | { |
742 | scroll_dest = rect.y; |
743 | yvalue = scroll_dest - screen.y - screen_yoffset; |
744 | } |
745 | else if ((rect.y + rect.height) > screen_bottom) |
746 | { |
747 | scroll_dest = rect.y + rect.height; |
748 | yvalue = scroll_dest - screen_bottom + screen_yoffset; |
749 | } |
750 | } |
751 | yvalue += current_y_scroll; |
752 | |
753 | /* Horizontal alignment */ |
754 | scroll_dest = current_x_scroll; |
755 | if (use_align) |
756 | { |
757 | scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign); |
758 | |
759 | /* if scroll_dest < screen.y, we move a negative increment (left), |
760 | * else a positive increment (right) |
761 | */ |
762 | xvalue = scroll_dest - screen.x + screen_xoffset; |
763 | } |
764 | else |
765 | { |
766 | /* move minimum to get onscreen */ |
767 | if (rect.x < screen.x) |
768 | { |
769 | scroll_dest = rect.x; |
770 | xvalue = scroll_dest - screen.x - screen_xoffset; |
771 | } |
772 | else if ((rect.x + rect.width) > screen_right) |
773 | { |
774 | scroll_dest = rect.x + rect.width; |
775 | xvalue = scroll_dest - screen_right + screen_xoffset; |
776 | } |
777 | } |
778 | xvalue += current_x_scroll; |
779 | |
780 | ctk_adjustment_set_value (hadj, xvalue); |
781 | ctk_adjustment_set_value (vadj, yvalue); |
782 | } |