Try to fix Gtk warning when using Tools->Reload Configuration.
[geany-mirror.git] / src / templates.c
blobf9cf2f8ae61da5c1dbcfb560c759fd5c21215aa8
1 /*
2 * templates.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005-2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2006-2009 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * $Id$
25 * Templates to insert into the current document, or filetype templates to create a new
26 * document from.
29 #include <time.h>
30 #include <string.h>
32 #include "geany.h"
34 #include "templates.h"
35 #include "support.h"
36 #include "utils.h"
37 #include "document.h"
38 #include "filetypes.h"
39 #include "ui_utils.h"
40 #include "toolbar.h"
41 #include "geanymenubuttonaction.h"
44 GeanyTemplatePrefs template_prefs;
46 static GtkWidget *new_with_template_menu = NULL; /* submenu used for both file menu and toolbar */
49 /* TODO: implement custom insertion templates, put these into files in data/templates */
51 /* default templates, only for initial tempate file creation on first start of Geany */
52 static const gchar templates_gpl_notice[] = "\
53 This program is free software; you can redistribute it and/or modify\n\
54 it under the terms of the GNU General Public License as published by\n\
55 the Free Software Foundation; either version 2 of the License, or\n\
56 (at your option) any later version.\n\
57 \n\
58 This program is distributed in the hope that it will be useful,\n\
59 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
60 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
61 GNU General Public License for more details.\n\
62 \n\
63 You should have received a copy of the GNU General Public License\n\
64 along with this program; if not, write to the Free Software\n\
65 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n\
66 MA 02110-1301, USA.\n\
69 static const gchar templates_bsd_notice[] = "\
70 Redistribution and use in source and binary forms, with or without\n\
71 modification, are permitted provided that the following conditions are\n\
72 met:\n\
73 \n\
74 * Redistributions of source code must retain the above copyright\n\
75 notice, this list of conditions and the following disclaimer.\n\
76 * Redistributions in binary form must reproduce the above\n\
77 copyright notice, this list of conditions and the following disclaimer\n\
78 in the documentation and/or other materials provided with the\n\
79 distribution.\n\
80 * Neither the name of the {company} nor the names of its\n\
81 contributors may be used to endorse or promote products derived from\n\
82 this software without specific prior written permission.\n\
83 \n\
84 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\
85 \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\
86 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
87 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n\
88 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n\
89 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n\
90 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n\
91 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n\
92 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n\
93 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\
94 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
97 static const gchar templates_function_description[] = "\
98 \n\
99 name: {functionname}\n\
100 @param\n\
101 @return\n\
104 static const gchar templates_multiline[] = "\
109 static const gchar templates_fileheader[] = "\
110 {filename}\n\
112 Copyright {year} {developer} <{mail}>\n\
114 {gpl}\
117 static const gchar templates_changelog[] = "\
118 {date} {developer} <{mail}>\n\
120 * \n\n\n";
122 static gchar *templates[GEANY_MAX_TEMPLATES];
124 /* We should probably remove filetype templates support soon - users can use custom
125 * file templates instead. */
126 static gchar *ft_templates[GEANY_MAX_BUILT_IN_FILETYPES] = {NULL};
129 /* some simple macros to reduce code size and make the code readable */
130 #define TEMPLATES_GET_FILENAME(shortname) \
131 g_strconcat(app->configdir, \
132 G_DIR_SEPARATOR_S GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S, shortname, NULL)
134 #define TEMPLATES_READ_FILE(fname, contents_ptr) \
135 g_file_get_contents(fname, contents_ptr, NULL, NULL);
138 static void create_template_file_if_necessary(const gchar *filename, const gchar *content)
140 if (! g_file_test(filename, G_FILE_TEST_EXISTS))
142 if (file_prefs.default_eol_character != SC_EOL_LF)
144 /* Replace the \n characters in the default template text by the proper
145 * platform-specific line ending characters. */
146 GString *tmp = g_string_new(content);
147 const gchar *eol_str = (file_prefs.default_eol_character == SC_EOL_CR) ? "\r" : "\r\n";
149 utils_string_replace_all(tmp, "\n", eol_str);
150 utils_write_file(filename, tmp->str);
151 g_string_free(tmp, TRUE);
153 else
154 utils_write_file(filename, content);
159 /* FIXME the callers should use GStrings instead of char arrays */
160 static gchar *replace_all(gchar *text, const gchar *year, const gchar *date, const gchar *datetime)
162 GString *str;
164 if (text == NULL)
165 return NULL;
167 str = g_string_new(text);
169 g_free(text);
170 templates_replace_all(str, year, date, datetime);
172 return g_string_free(str, FALSE);
176 static void init_general_templates(const gchar *year, const gchar *date, const gchar *datetime)
178 gchar *template_filename_fileheader = TEMPLATES_GET_FILENAME("fileheader");
179 gchar *template_filename_gpl = TEMPLATES_GET_FILENAME("gpl");
180 gchar *template_filename_bsd = TEMPLATES_GET_FILENAME("bsd");
181 gchar *template_filename_function = TEMPLATES_GET_FILENAME("function");
182 gchar *template_filename_changelog = TEMPLATES_GET_FILENAME("changelog");
184 /* create the template files in the configuration directory, if they don't exist */
185 create_template_file_if_necessary(template_filename_fileheader, templates_fileheader);
186 create_template_file_if_necessary(template_filename_gpl, templates_gpl_notice);
187 create_template_file_if_necessary(template_filename_bsd, templates_bsd_notice);
188 create_template_file_if_necessary(template_filename_function, templates_function_description);
189 create_template_file_if_necessary(template_filename_changelog, templates_changelog);
191 /* read the contents */
192 TEMPLATES_READ_FILE(template_filename_fileheader, &templates[GEANY_TEMPLATE_FILEHEADER]);
193 templates[GEANY_TEMPLATE_FILEHEADER] = replace_all(templates[GEANY_TEMPLATE_FILEHEADER], year, date, datetime);
195 TEMPLATES_READ_FILE(template_filename_gpl, &templates[GEANY_TEMPLATE_GPL]);
196 templates[GEANY_TEMPLATE_GPL] = replace_all(templates[GEANY_TEMPLATE_GPL], year, date, datetime);
198 TEMPLATES_READ_FILE(template_filename_bsd, &templates[GEANY_TEMPLATE_BSD]);
199 templates[GEANY_TEMPLATE_BSD] = replace_all(templates[GEANY_TEMPLATE_BSD], year, date, datetime);
201 TEMPLATES_READ_FILE(template_filename_function, &templates[GEANY_TEMPLATE_FUNCTION]);
202 templates[GEANY_TEMPLATE_FUNCTION] = replace_all(templates[GEANY_TEMPLATE_FUNCTION], year, date, datetime);
204 TEMPLATES_READ_FILE(template_filename_changelog, &templates[GEANY_TEMPLATE_CHANGELOG]);
205 templates[GEANY_TEMPLATE_CHANGELOG] = replace_all(templates[GEANY_TEMPLATE_CHANGELOG], year, date, datetime);
207 /* free the whole stuff */
208 g_free(template_filename_fileheader);
209 g_free(template_filename_gpl);
210 g_free(template_filename_bsd);
211 g_free(template_filename_function);
212 g_free(template_filename_changelog);
216 static void init_ft_templates(const gchar *year, const gchar *date, const gchar *datetime)
218 filetype_id ft_id;
220 for (ft_id = 0; ft_id < GEANY_MAX_BUILT_IN_FILETYPES; ft_id++)
222 gchar *ext = filetypes_get_conf_extension(ft_id);
223 gchar *shortname = g_strconcat("filetype.", ext, NULL);
224 gchar *fname = TEMPLATES_GET_FILENAME(shortname);
226 TEMPLATES_READ_FILE(fname, &ft_templates[ft_id]);
227 ft_templates[ft_id] = replace_all(ft_templates[ft_id], year, date, datetime);
229 g_free(fname);
230 g_free(shortname);
231 g_free(ext);
236 static void
237 on_new_with_filetype_template(GtkMenuItem *menuitem, gpointer user_data)
239 GeanyFiletype *ft = user_data;
240 gchar *template = templates_get_template_new_file(ft);
242 document_new_file(NULL, ft, template);
243 g_free(template);
247 /* TODO: remove filetype template support after 0.19 */
248 static gboolean create_new_filetype_items(void)
250 GSList *node;
251 gboolean ret = FALSE;
252 GtkWidget *menu = NULL;
254 foreach_slist(node, filetypes_by_title)
256 GeanyFiletype *ft = node->data;
257 GtkWidget *item;
259 if (ft->id >= GEANY_MAX_BUILT_IN_FILETYPES || ft_templates[ft->id] == NULL)
260 continue;
262 if (!menu)
264 item = gtk_menu_item_new_with_label(_("Old"));
265 menu = gtk_menu_new();
266 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
267 gtk_widget_show_all(item);
268 gtk_container_add(GTK_CONTAINER(new_with_template_menu), item);
270 item = gtk_menu_item_new_with_label(ft->title);
271 gtk_widget_show(item);
272 gtk_container_add(GTK_CONTAINER(menu), item);
273 g_signal_connect(item, "activate", G_CALLBACK(on_new_with_filetype_template), ft);
274 ret = TRUE;
276 return ret;
280 static gchar *get_template_from_file(const gchar *locale_fname, const gchar *doc_filename,
281 GeanyFiletype *ft)
283 gchar *content;
284 GString *template = NULL;
286 g_file_get_contents(locale_fname, &content, NULL, NULL);
288 if (content != NULL)
290 gchar *file_header;
291 gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
292 gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
293 gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
295 template = g_string_new(content);
297 file_header = templates_get_template_fileheader(FILETYPE_ID(ft), doc_filename);
298 templates_replace_all(template, year, date, datetime);
299 utils_string_replace_all(template, "{filename}", doc_filename);
300 utils_string_replace_all(template, "{fileheader}", file_header);
302 utils_free_pointers(5, year, date, datetime, file_header, content, NULL);
303 return g_string_free(template, FALSE);
305 return NULL;
309 static void
310 on_new_with_file_template(GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
312 gchar *fname = ui_menu_item_get_text(menuitem);
313 GeanyFiletype *ft;
314 gchar *template;
315 const gchar *extension = strrchr(fname, '.'); /* easy way to get the file extension */
316 gchar *new_filename = g_strconcat(GEANY_STRING_UNTITLED, extension, NULL);
317 gchar *path;
319 ft = filetypes_detect_from_extension(fname);
320 setptr(fname, utils_get_locale_from_utf8(fname));
322 /* fname is just the basename from the menu item, so prepend the custom files path */
323 path = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_TEMPLATES_SUBDIR,
324 "files", fname, NULL);
325 template = get_template_from_file(path, new_filename, ft);
326 if (!template)
328 /* try the system path */
329 g_free(path);
330 path = g_build_path(G_DIR_SEPARATOR_S, app->datadir, GEANY_TEMPLATES_SUBDIR,
331 "files", fname, NULL);
332 template = get_template_from_file(path, new_filename, ft);
334 if (template)
335 document_new_file(new_filename, ft, template);
336 else
338 setptr(fname, utils_get_utf8_from_locale(fname));
339 ui_set_statusbar(TRUE, _("Could not find file '%s'."), fname);
341 g_free(template);
342 g_free(path);
343 g_free(new_filename);
344 g_free(fname);
348 static void add_file_item(const gchar *fname, GtkWidget *menu)
350 GtkWidget *tmp_button;
351 gchar *label;
353 g_return_if_fail(fname);
354 g_return_if_fail(menu);
356 label = utils_get_utf8_from_locale(fname);
358 tmp_button = gtk_menu_item_new_with_label(label);
359 gtk_widget_show(tmp_button);
360 gtk_container_add(GTK_CONTAINER(menu), tmp_button);
361 g_signal_connect(tmp_button, "activate", G_CALLBACK(on_new_with_file_template), NULL);
363 g_free(label);
367 static gboolean add_custom_template_items(void)
369 GSList *list = utils_get_config_files(GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S "files");
370 GSList *node;
372 foreach_slist(node, list)
374 gchar *fname = node->data;
376 add_file_item(fname, new_with_template_menu);
377 g_free(fname);
379 g_slist_free(list);
380 return list != NULL;
384 static void create_file_template_menu(void)
386 GtkWidget *sep = NULL;
388 new_with_template_menu = gtk_menu_new();
390 if (add_custom_template_items())
392 sep = gtk_separator_menu_item_new();
393 gtk_container_add(GTK_CONTAINER(new_with_template_menu), sep);
395 if (create_new_filetype_items() && sep)
397 gtk_widget_show(sep);
399 /* unless the file menu is showing, menu should be in the toolbar widget */
400 geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(
401 toolbar_get_action_by_name("New")), new_with_template_menu);
405 static void on_file_menu_show(GtkWidget *item)
407 geany_menu_button_action_set_menu(
408 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL);
409 item = ui_lookup_widget(main_widgets.window, "menu_new_with_template1");
410 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_with_template_menu);
414 static void on_file_menu_hide(GtkWidget *item)
416 item = ui_lookup_widget(main_widgets.window, "menu_new_with_template1");
417 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), NULL);
418 geany_menu_button_action_set_menu(
419 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), new_with_template_menu);
423 void templates_init(void)
425 gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
426 gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
427 gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
428 GtkWidget *item;
430 init_general_templates(year, date, datetime);
431 init_ft_templates(year, date, datetime);
433 g_free(date);
434 g_free(datetime);
435 g_free(year);
437 create_file_template_menu();
438 /* we hold our own ref for the menu as it has no parent whilst being moved */
439 g_object_ref(new_with_template_menu);
441 /* reparent the template menu as needed */
442 item = ui_lookup_widget(main_widgets.window, "file1");
443 item = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
444 g_signal_connect(item, "show", G_CALLBACK(on_file_menu_show), NULL);
445 g_signal_connect(item, "hide", G_CALLBACK(on_file_menu_hide), NULL);
449 /* indent is used to make some whitespace between comment char and real start of the line
450 * e.g. indent = 8 prints " * here comes the text of the line"
451 * indent is meant to be the whole amount of characters before the real line content follows, i.e.
452 * 6 characters are filled with whitespace when the comment characters include " *" */
453 static gchar *make_comment_block(const gchar *comment_text, gint filetype_idx, guint indent)
455 gchar *frame_start; /* to add before comment_text */
456 gchar *frame_end; /* to add after comment_text */
457 gchar *line_prefix; /* to add before every line in comment_text */
458 gchar *result;
459 gchar *tmp;
460 gchar *prefix;
461 gchar **lines;
462 guint i, len;
463 GeanyFiletype *ft = filetypes_index(filetype_idx);
465 g_return_val_if_fail(ft != NULL, NULL);
467 if (NZV(ft->comment_open))
469 if (NZV(ft->comment_close))
471 frame_start = g_strconcat(ft->comment_open, "\n", NULL);
472 frame_end = g_strconcat(ft->comment_close, "\n", NULL);
473 line_prefix = "";
475 else
477 frame_start = NULL;
478 frame_end = NULL;
479 line_prefix = ft->comment_open;
482 else
483 { /* use C-like multi-line comments as fallback */
484 frame_start = g_strdup("/*\n");
485 frame_end = g_strdup("*/\n");
486 line_prefix = "";
489 /* do some magic to nicely format C-like multi-line comments */
490 if (NZV(frame_start) && frame_start[1] == '*')
492 /* prefix the string with a space */
493 setptr(frame_end, g_strconcat(" ", frame_end, NULL));
494 line_prefix = " *";
497 /* construct the real prefix with given amount of whitespace */
498 i = (indent > strlen(line_prefix)) ? (indent - strlen(line_prefix)) : strlen(line_prefix);
499 tmp = g_strnfill(i, ' ');
500 prefix = g_strconcat(line_prefix, tmp, NULL);
501 g_free(tmp);
503 /* add line_prefix to every line of comment_text */
504 lines = g_strsplit(comment_text, "\n", -1);
505 len = g_strv_length(lines) - 1;
506 for (i = 0; i < len; i++)
508 tmp = lines[i];
509 lines[i] = g_strconcat(prefix, tmp, NULL);
510 g_free(tmp);
512 tmp = g_strjoinv("\n", lines);
514 /* add frame_start and frame_end */
515 if (frame_start != NULL)
516 result = g_strconcat(frame_start, tmp, frame_end, NULL);
517 else
518 result = g_strconcat(tmp, frame_end, NULL);
520 utils_free_pointers(4, prefix, tmp, frame_start, frame_end, NULL);
521 g_strfreev(lines);
522 return result;
526 gchar *templates_get_template_licence(gint filetype_idx, gint licence_type)
528 if (licence_type != GEANY_TEMPLATE_GPL && licence_type != GEANY_TEMPLATE_BSD)
529 return NULL;
531 return make_comment_block(templates[licence_type], filetype_idx, 8);
535 gchar *templates_get_template_fileheader(gint filetype_idx, const gchar *fname)
537 gchar *template = g_strdup(templates[GEANY_TEMPLATE_FILEHEADER]);
538 gchar *shortname;
539 gchar *result;
540 gchar *date = utils_get_date_time(template_prefs.datetime_format, NULL);
541 filetype_id ft_id = filetype_idx;
542 GeanyFiletype *ft = filetypes[ft_id];
544 filetypes_load_config(ft_id, FALSE); /* load any user extension setting */
546 if (fname == NULL)
548 if (!ft->extension)
549 shortname = g_strdup(GEANY_STRING_UNTITLED);
550 else
551 shortname = g_strconcat(GEANY_STRING_UNTITLED, ".", ft->extension, NULL);
553 else
554 shortname = g_path_get_basename(fname);
556 utils_str_replace_all(&template, "{filename}", shortname);
557 utils_str_replace_all(&template, "{gpl}", templates[GEANY_TEMPLATE_GPL]);
558 utils_str_replace_all(&template, "{bsd}", templates[GEANY_TEMPLATE_BSD]);
559 utils_str_replace_all(&template, "{datetime}", date);
561 result = make_comment_block(template, ft_id, 8);
563 g_free(template);
564 g_free(shortname);
565 g_free(date);
566 return result;
570 static gchar *get_file_template(GeanyFiletype *ft)
572 filetype_id ft_id = FILETYPE_ID(ft);
574 g_return_val_if_fail(ft_id < GEANY_MAX_BUILT_IN_FILETYPES, NULL);
576 return g_strdup(ft_templates[ft_id]);
580 gchar *templates_get_template_new_file(GeanyFiletype *ft)
582 gchar *ft_template = NULL;
583 gchar *file_header = NULL;
585 g_return_val_if_fail(ft->id < GEANY_MAX_BUILT_IN_FILETYPES, NULL);
587 if (FILETYPE_ID(ft) == GEANY_FILETYPES_NONE)
588 return get_file_template(ft);
590 file_header = templates_get_template_fileheader(ft->id, NULL); /* file template only used for new files */
591 ft_template = get_file_template(ft);
592 utils_str_replace_all(&ft_template, "{fileheader}", file_header);
593 g_free(file_header);
594 return ft_template;
598 gchar *templates_get_template_generic(gint template)
600 return g_strdup(templates[template]);
604 gchar *templates_get_template_function(gint filetype_idx, const gchar *func_name)
606 gchar *template = g_strdup(templates[GEANY_TEMPLATE_FUNCTION]);
607 gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
608 gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
609 gchar *result;
611 utils_str_replace_all(&template, "{date}", date);
612 utils_str_replace_all(&template, "{datetime}", datetime);
613 utils_str_replace_all(&template, "{functionname}", (func_name) ? func_name : "");
615 result = make_comment_block(template, filetype_idx, 3);
617 g_free(template);
618 g_free(date);
619 g_free(datetime);
620 return result;
624 gchar *templates_get_template_changelog(void)
626 gchar *date = utils_get_date_time(template_prefs.datetime_format, NULL);
627 gchar *result = g_strdup(templates[GEANY_TEMPLATE_CHANGELOG]);
629 utils_str_replace_all(&result, "{date}", date);
631 g_free(date);
632 return result;
636 void templates_free_templates(void)
638 gint i;
639 GList *children, *item;
641 for (i = 0; i < GEANY_MAX_TEMPLATES; i++)
643 g_free(templates[i]);
645 for (i = 0; i < GEANY_MAX_BUILT_IN_FILETYPES; i++)
647 g_free(ft_templates[i]);
649 /* destroy "New with template" sub menu items (in case we want to reload the templates) */
650 children = gtk_container_get_children(GTK_CONTAINER(new_with_template_menu));
651 foreach_list(item, children)
653 gtk_widget_destroy(GTK_WIDGET(item->data));
655 g_list_free(children);
657 /* Shouldn't unrefing destroy children anyway? */
658 g_object_unref(new_with_template_menu);
659 new_with_template_menu = NULL;
663 void templates_replace_all(GString *text, const gchar *year, const gchar *date,
664 const gchar *datetime)
666 utils_string_replace_all(text, "{year}", year);
667 utils_string_replace_all(text, "{date}", date);
668 utils_string_replace_all(text, "{datetime}", datetime);
669 utils_string_replace_all(text, "{version}", template_prefs.version);
670 utils_string_replace_all(text, "{initial}", template_prefs.initials);
671 utils_string_replace_all(text, "{developer}", template_prefs.developer);
672 utils_string_replace_all(text, "{mail}", template_prefs.mail);
673 utils_string_replace_all(text, "{company}", template_prefs.company);
674 utils_string_replace_all(text, "{untitled}", GEANY_STRING_UNTITLED);
675 utils_string_replace_all(text, "{geanyversion}", "Geany " VERSION);