| 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)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str) , ((0))) : g_string_free_and_steal (str)) : (g_string_free) ( (str), ((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)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str) , ((0))) : g_string_free_and_steal (str)) : (g_string_free) ( (str), ((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)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str) , ((0))) : g_string_free_and_steal (str)) : (g_string_free) ( (str), ((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 | } |