2 * templates.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2006-2010 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.
25 * Templates to insert into the current document, or filetype templates to create a new
34 #include "templates.h"
38 #include "filetypes.h"
41 #include "geanymenubuttonaction.h"
45 GeanyTemplatePrefs template_prefs
;
47 static GtkWidget
*new_with_template_menu
= NULL
; /* submenu used for both file menu and toolbar */
50 /* TODO: implement custom insertion templates, put these into files in data/templates */
52 /* default templates, only for initial tempate file creation on first start of Geany */
53 static const gchar templates_gpl_notice
[] = "\
54 This program is free software; you can redistribute it and/or modify\n\
55 it under the terms of the GNU General Public License as published by\n\
56 the Free Software Foundation; either version 2 of the License, or\n\
57 (at your option) any later version.\n\
59 This program is distributed in the hope that it will be useful,\n\
60 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
61 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
62 GNU General Public License for more details.\n\
64 You should have received a copy of the GNU General Public License\n\
65 along with this program; if not, write to the Free Software\n\
66 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n\
67 MA 02110-1301, USA.\n\
70 static const gchar templates_bsd_notice
[] = "\
71 Redistribution and use in source and binary forms, with or without\n\
72 modification, are permitted provided that the following conditions are\n\
75 * Redistributions of source code must retain the above copyright\n\
76 notice, this list of conditions and the following disclaimer.\n\
77 * Redistributions in binary form must reproduce the above\n\
78 copyright notice, this list of conditions and the following disclaimer\n\
79 in the documentation and/or other materials provided with the\n\
81 * Neither the name of the {company} nor the names of its\n\
82 contributors may be used to endorse or promote products derived from\n\
83 this software without specific prior written permission.\n\
85 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\
86 \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\
87 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
88 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n\
89 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n\
90 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n\
91 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n\
92 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n\
93 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n\
94 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\
95 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
98 static const gchar templates_function_description
[] = "\
100 name: {functionname}\n\
105 static const gchar templates_multiline
[] = "\
110 static const gchar templates_fileheader
[] = "\
113 Copyright {year} {developer} <{mail}>\n\
118 static const gchar templates_changelog
[] = "\
119 {date} {developer} <{mail}>\n\
123 static gchar
*templates
[GEANY_MAX_TEMPLATES
];
125 /* We should probably remove filetype templates support soon - users can use custom
126 * file templates instead. */
127 static gchar
*ft_templates
[GEANY_MAX_BUILT_IN_FILETYPES
] = {NULL
};
130 static void replace_static_values(GString
*text
);
131 static gchar
*get_template_fileheader(GeanyFiletype
*ft
);
133 /* called by templates_replace_common */
134 static void templates_replace_default_dates(GString
*text
);
135 static void templates_replace_command(GString
*text
, const gchar
*file_name
,
136 const gchar
*file_type
, const gchar
*func_name
);
139 /* some simple macros to reduce code size and make the code readable */
140 #define TEMPLATES_GET_FILENAME(shortname) \
141 g_strconcat(app->configdir, \
142 G_DIR_SEPARATOR_S GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S, shortname, NULL)
144 #define TEMPLATES_READ_FILE(fname, contents_ptr) \
145 g_file_get_contents(fname, contents_ptr, NULL, NULL);
148 static void create_template_file_if_necessary(const gchar
*filename
, const gchar
*content
)
150 if (! g_file_test(filename
, G_FILE_TEST_EXISTS
))
152 if (file_prefs
.default_eol_character
!= SC_EOL_LF
)
154 /* Replace the \n characters in the default template text by the proper
155 * platform-specific line ending characters. */
156 GString
*tmp
= g_string_new(content
);
157 const gchar
*eol_str
= (file_prefs
.default_eol_character
== SC_EOL_CR
) ? "\r" : "\r\n";
159 utils_string_replace_all(tmp
, "\n", eol_str
);
160 utils_write_file(filename
, tmp
->str
);
161 g_string_free(tmp
, TRUE
);
164 utils_write_file(filename
, content
);
169 /* FIXME the callers should use GStrings instead of char arrays */
170 static gchar
*replace_all(gchar
*text
, const gchar
*year
, const gchar
*date
, const gchar
*datetime
)
177 str
= g_string_new(text
);
180 templates_replace_valist(str
,
183 "{datetime}", datetime
,
186 return g_string_free(str
, FALSE
);
190 static void init_general_templates(const gchar
*year
, const gchar
*date
, const gchar
*datetime
)
192 gchar
*template_filename_fileheader
= TEMPLATES_GET_FILENAME("fileheader");
193 gchar
*template_filename_gpl
= TEMPLATES_GET_FILENAME("gpl");
194 gchar
*template_filename_bsd
= TEMPLATES_GET_FILENAME("bsd");
195 gchar
*template_filename_function
= TEMPLATES_GET_FILENAME("function");
196 gchar
*template_filename_changelog
= TEMPLATES_GET_FILENAME("changelog");
198 /* create the template files in the configuration directory, if they don't exist */
199 create_template_file_if_necessary(template_filename_fileheader
, templates_fileheader
);
200 create_template_file_if_necessary(template_filename_gpl
, templates_gpl_notice
);
201 create_template_file_if_necessary(template_filename_bsd
, templates_bsd_notice
);
202 create_template_file_if_necessary(template_filename_function
, templates_function_description
);
203 create_template_file_if_necessary(template_filename_changelog
, templates_changelog
);
205 /* read the contents */
206 TEMPLATES_READ_FILE(template_filename_fileheader
, &templates
[GEANY_TEMPLATE_FILEHEADER
]);
207 templates
[GEANY_TEMPLATE_FILEHEADER
] = replace_all(templates
[GEANY_TEMPLATE_FILEHEADER
], year
, date
, datetime
);
209 TEMPLATES_READ_FILE(template_filename_gpl
, &templates
[GEANY_TEMPLATE_GPL
]);
210 templates
[GEANY_TEMPLATE_GPL
] = replace_all(templates
[GEANY_TEMPLATE_GPL
], year
, date
, datetime
);
212 TEMPLATES_READ_FILE(template_filename_bsd
, &templates
[GEANY_TEMPLATE_BSD
]);
213 templates
[GEANY_TEMPLATE_BSD
] = replace_all(templates
[GEANY_TEMPLATE_BSD
], year
, date
, datetime
);
215 TEMPLATES_READ_FILE(template_filename_function
, &templates
[GEANY_TEMPLATE_FUNCTION
]);
216 templates
[GEANY_TEMPLATE_FUNCTION
] = replace_all(templates
[GEANY_TEMPLATE_FUNCTION
], year
, date
, datetime
);
218 TEMPLATES_READ_FILE(template_filename_changelog
, &templates
[GEANY_TEMPLATE_CHANGELOG
]);
219 templates
[GEANY_TEMPLATE_CHANGELOG
] = replace_all(templates
[GEANY_TEMPLATE_CHANGELOG
], year
, date
, datetime
);
221 /* free the whole stuff */
222 g_free(template_filename_fileheader
);
223 g_free(template_filename_gpl
);
224 g_free(template_filename_bsd
);
225 g_free(template_filename_function
);
226 g_free(template_filename_changelog
);
230 static void init_ft_templates(const gchar
*year
, const gchar
*date
, const gchar
*datetime
)
234 for (ft_id
= 0; ft_id
< GEANY_MAX_BUILT_IN_FILETYPES
; ft_id
++)
236 gchar
*ext
= filetypes_get_conf_extension(ft_id
);
237 gchar
*shortname
= g_strconcat("filetype.", ext
, NULL
);
238 gchar
*fname
= TEMPLATES_GET_FILENAME(shortname
);
240 TEMPLATES_READ_FILE(fname
, &ft_templates
[ft_id
]);
241 ft_templates
[ft_id
] = replace_all(ft_templates
[ft_id
], year
, date
, datetime
);
251 on_new_with_filetype_template(GtkMenuItem
*menuitem
, gpointer user_data
)
253 GeanyFiletype
*ft
= user_data
;
254 gchar
*template = templates_get_template_new_file(ft
);
256 document_new_file(NULL
, ft
, template);
261 /* TODO: remove filetype template support after 0.19 */
262 static gboolean
create_new_filetype_items(void)
265 gboolean ret
= FALSE
;
266 GtkWidget
*menu
= NULL
;
268 foreach_slist(node
, filetypes_by_title
)
270 GeanyFiletype
*ft
= node
->data
;
273 if (ft
->id
>= GEANY_MAX_BUILT_IN_FILETYPES
|| ft_templates
[ft
->id
] == NULL
)
278 item
= gtk_menu_item_new_with_label(_("Old"));
279 menu
= gtk_menu_new();
280 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), menu
);
281 gtk_widget_show_all(item
);
282 gtk_container_add(GTK_CONTAINER(new_with_template_menu
), item
);
284 item
= gtk_menu_item_new_with_label(ft
->title
);
285 gtk_widget_show(item
);
286 gtk_container_add(GTK_CONTAINER(menu
), item
);
287 g_signal_connect(item
, "activate", G_CALLBACK(on_new_with_filetype_template
), ft
);
294 void templates_replace_common(GString
*template, const gchar
*fname
,
295 GeanyFiletype
*ft
, const gchar
*func_name
)
302 shortname
= g_strdup(GEANY_STRING_UNTITLED
);
304 shortname
= g_strconcat(GEANY_STRING_UNTITLED
, ".", ft
->extension
, NULL
);
307 shortname
= g_path_get_basename(fname
);
309 templates_replace_valist(template,
310 "{filename}", shortname
,
311 "{project}", app
->project
? app
->project
->name
: "",
312 "{description}", app
->project
? app
->project
->description
: "",
316 templates_replace_default_dates(template);
317 templates_replace_command(template, fname
, ft
->name
, func_name
);
318 /* Bug: command results could have {ob} {cb} strings in! */
319 /* replace braces last */
320 templates_replace_valist(template,
327 static gchar
*get_template_from_file(const gchar
*locale_fname
, const gchar
*doc_filename
,
331 GString
*template = NULL
;
333 g_file_get_contents(locale_fname
, &content
, NULL
, NULL
);
339 template = g_string_new(content
);
341 file_header
= get_template_fileheader(ft
);
342 templates_replace_valist(template,
343 "{fileheader}", file_header
,
345 templates_replace_common(template, doc_filename
, ft
, NULL
);
347 utils_free_pointers(2, file_header
, content
, NULL
);
348 return g_string_free(template, FALSE
);
355 on_new_with_file_template(GtkMenuItem
*menuitem
, G_GNUC_UNUSED gpointer user_data
)
357 gchar
*fname
= ui_menu_item_get_text(menuitem
);
360 const gchar
*extension
= strrchr(fname
, '.'); /* easy way to get the file extension */
361 gchar
*new_filename
= g_strconcat(GEANY_STRING_UNTITLED
, extension
, NULL
);
364 ft
= filetypes_detect_from_extension(fname
);
365 setptr(fname
, utils_get_locale_from_utf8(fname
));
367 /* fname is just the basename from the menu item, so prepend the custom files path */
368 path
= g_build_path(G_DIR_SEPARATOR_S
, app
->configdir
, GEANY_TEMPLATES_SUBDIR
,
369 "files", fname
, NULL
);
370 template = get_template_from_file(path
, new_filename
, ft
);
373 /* try the system path */
375 path
= g_build_path(G_DIR_SEPARATOR_S
, app
->datadir
, GEANY_TEMPLATES_SUBDIR
,
376 "files", fname
, NULL
);
377 template = get_template_from_file(path
, new_filename
, ft
);
380 document_new_file(new_filename
, ft
, template);
383 setptr(fname
, utils_get_utf8_from_locale(fname
));
384 ui_set_statusbar(TRUE
, _("Could not find file '%s'."), fname
);
388 g_free(new_filename
);
393 static void add_file_item(const gchar
*fname
, GtkWidget
*menu
)
395 GtkWidget
*tmp_button
;
398 g_return_if_fail(fname
);
399 g_return_if_fail(menu
);
401 label
= utils_get_utf8_from_locale(fname
);
403 tmp_button
= gtk_menu_item_new_with_label(label
);
404 gtk_widget_show(tmp_button
);
405 gtk_container_add(GTK_CONTAINER(menu
), tmp_button
);
406 g_signal_connect(tmp_button
, "activate", G_CALLBACK(on_new_with_file_template
), NULL
);
412 static gboolean
add_custom_template_items(void)
414 GSList
*list
= utils_get_config_files(GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S
"files");
417 foreach_slist(node
, list
)
419 gchar
*fname
= node
->data
;
421 add_file_item(fname
, new_with_template_menu
);
429 static void create_file_template_menu(void)
431 GtkWidget
*sep
= NULL
;
433 new_with_template_menu
= gtk_menu_new();
435 if (add_custom_template_items())
437 sep
= gtk_separator_menu_item_new();
438 gtk_container_add(GTK_CONTAINER(new_with_template_menu
), sep
);
440 if (create_new_filetype_items() && sep
)
442 gtk_widget_show(sep
);
444 /* unless the file menu is showing, menu should be in the toolbar widget */
445 geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(
446 toolbar_get_action_by_name("New")), new_with_template_menu
);
450 static void on_file_menu_show(GtkWidget
*item
)
452 geany_menu_button_action_set_menu(
453 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL
);
454 item
= ui_lookup_widget(main_widgets
.window
, "menu_new_with_template1");
455 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), new_with_template_menu
);
459 static void on_file_menu_hide(GtkWidget
*item
)
461 item
= ui_lookup_widget(main_widgets
.window
, "menu_new_with_template1");
462 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), NULL
);
463 geany_menu_button_action_set_menu(
464 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), new_with_template_menu
);
468 /* reload templates if any file in the templates path is saved */
469 static void on_document_save(G_GNUC_UNUSED GObject
*object
, GeanyDocument
*doc
)
471 const gchar
*path
= utils_build_path(app
->configdir
, GEANY_TEMPLATES_SUBDIR
, NULL
);
473 g_return_if_fail(NZV(doc
->real_path
));
475 if (strncmp(doc
->real_path
, path
, strlen(path
)) == 0)
477 /* reload templates */
478 templates_free_templates();
484 /* warning: also called when reloading template settings */
485 void templates_init(void)
487 gchar
*year
= utils_get_date_time(template_prefs
.year_format
, NULL
);
488 gchar
*date
= utils_get_date_time(template_prefs
.date_format
, NULL
);
489 gchar
*datetime
= utils_get_date_time(template_prefs
.datetime_format
, NULL
);
490 static gboolean init_done
= FALSE
;
492 init_general_templates(year
, date
, datetime
);
493 init_ft_templates(year
, date
, datetime
);
499 create_file_template_menu();
500 /* we hold our own ref for the menu as it has no parent whilst being moved */
501 g_object_ref(new_with_template_menu
);
503 /* only connect signals to persistent objects once */
507 /* reparent the template menu as needed */
508 item
= ui_lookup_widget(main_widgets
.window
, "file1");
509 item
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(item
));
510 g_signal_connect(item
, "show", G_CALLBACK(on_file_menu_show
), NULL
);
511 g_signal_connect(item
, "hide", G_CALLBACK(on_file_menu_hide
), NULL
);
513 g_signal_connect(geany_object
, "document-save", G_CALLBACK(on_document_save
), NULL
);
519 /* indent is used to make some whitespace between comment char and real start of the line
520 * e.g. indent = 8 prints " * here comes the text of the line"
521 * indent is meant to be the whole amount of characters before the real line content follows, i.e.
522 * 6 characters are filled with whitespace when the comment characters include " *" */
523 /* TODO make this function operating on a GString */
524 static gchar
*make_comment_block(const gchar
*comment_text
, gint filetype_idx
, guint indent
)
526 gchar
*frame_start
; /* to add before comment_text */
527 gchar
*frame_end
; /* to add after comment_text */
528 const gchar
*line_prefix
; /* to add before every line in comment_text */
534 GeanyFiletype
*ft
= filetypes_index(filetype_idx
);
536 g_return_val_if_fail(ft
!= NULL
, NULL
);
538 if (NZV(ft
->comment_open
))
540 if (NZV(ft
->comment_close
))
542 frame_start
= g_strconcat(ft
->comment_open
, "\n", NULL
);
543 frame_end
= g_strconcat(ft
->comment_close
, "\n", NULL
);
550 line_prefix
= ft
->comment_open
;
554 { /* use C-like multi-line comments as fallback */
555 frame_start
= g_strdup("/*\n");
556 frame_end
= g_strdup("*/\n");
560 /* do some magic to nicely format C-like multi-line comments */
561 if (NZV(frame_start
) && frame_start
[1] == '*')
563 /* prefix the string with a space */
564 setptr(frame_end
, g_strconcat(" ", frame_end
, NULL
));
568 /* construct the real prefix with given amount of whitespace */
569 i
= (indent
> strlen(line_prefix
)) ? (indent
- strlen(line_prefix
)) : strlen(line_prefix
);
570 tmp
= g_strnfill(i
, ' ');
571 prefix
= g_strconcat(line_prefix
, tmp
, NULL
);
574 /* add line_prefix to every line of comment_text */
575 lines
= g_strsplit(comment_text
, "\n", -1);
576 len
= g_strv_length(lines
) - 1;
577 for (i
= 0; i
< len
; i
++)
580 lines
[i
] = g_strconcat(prefix
, tmp
, NULL
);
583 tmp
= g_strjoinv("\n", lines
);
585 /* add frame_start and frame_end */
586 if (frame_start
!= NULL
)
587 result
= g_strconcat(frame_start
, tmp
, frame_end
, NULL
);
589 result
= g_strconcat(tmp
, frame_end
, NULL
);
591 utils_free_pointers(4, prefix
, tmp
, frame_start
, frame_end
, NULL
);
597 gchar
*templates_get_template_licence(GeanyDocument
*doc
, gint licence_type
)
600 gchar
*result
= NULL
;
602 g_return_val_if_fail(doc
!= NULL
, NULL
);
603 g_return_val_if_fail(licence_type
== GEANY_TEMPLATE_GPL
|| licence_type
== GEANY_TEMPLATE_BSD
, NULL
);
605 template = g_string_new(templates
[licence_type
]);
606 replace_static_values(template);
607 templates_replace_default_dates(template);
608 templates_replace_command(template, DOC_FILENAME(doc
), doc
->file_type
->name
, NULL
);
610 result
= make_comment_block(template->str
, FILETYPE_ID(doc
->file_type
), 8);
612 g_string_free(template, TRUE
);
618 static gchar
*get_template_fileheader(GeanyFiletype
*ft
)
620 GString
*template = g_string_new(templates
[GEANY_TEMPLATE_FILEHEADER
]);
623 filetypes_load_config(ft
->id
, FALSE
); /* load any user extension setting */
625 templates_replace_valist(template,
626 "{gpl}", templates
[GEANY_TEMPLATE_GPL
],
627 "{bsd}", templates
[GEANY_TEMPLATE_BSD
],
630 /* we don't replace other wildcards here otherwise they would get done twice for files */
631 result
= make_comment_block(template->str
, ft
->id
, 8);
632 g_string_free(template, TRUE
);
637 /* TODO change the signature to take a GeanyDocument? this would break plugin API/ABI */
638 gchar
*templates_get_template_fileheader(gint filetype_idx
, const gchar
*fname
)
640 GeanyFiletype
*ft
= filetypes
[filetype_idx
];
641 gchar
*str
= get_template_fileheader(ft
);
642 GString
*template = g_string_new(str
);
645 templates_replace_common(template, fname
, ft
, NULL
);
646 return g_string_free(template, FALSE
);
650 gchar
*templates_get_template_new_file(GeanyFiletype
*ft
)
652 GString
*ft_template
;
653 gchar
*file_header
= NULL
;
655 g_return_val_if_fail(ft
!= NULL
, NULL
);
656 g_return_val_if_fail(ft
->id
< GEANY_MAX_BUILT_IN_FILETYPES
, NULL
);
658 ft_template
= g_string_new(ft_templates
[ft
->id
]);
659 if (FILETYPE_ID(ft
) == GEANY_FILETYPES_NONE
)
661 replace_static_values(ft_template
);
664 { /* file template only used for new files */
665 file_header
= get_template_fileheader(ft
);
666 templates_replace_valist(ft_template
, "{fileheader}", file_header
, NULL
);
668 templates_replace_common(ft_template
, NULL
, ft
, NULL
);
671 return g_string_free(ft_template
, FALSE
);
675 gchar
*templates_get_template_function(GeanyDocument
*doc
, const gchar
*func_name
)
680 func_name
= (func_name
!= NULL
) ? func_name
: "";
681 text
= g_string_new(templates
[GEANY_TEMPLATE_FUNCTION
]);
683 templates_replace_valist(text
, "{functionname}", func_name
, NULL
);
684 templates_replace_default_dates(text
);
685 templates_replace_command(text
, DOC_FILENAME(doc
), doc
->file_type
->name
, func_name
);
687 result
= make_comment_block(text
->str
, doc
->file_type
->id
, 3);
689 g_string_free(text
, TRUE
);
694 gchar
*templates_get_template_changelog(GeanyDocument
*doc
)
696 GString
*result
= g_string_new(templates
[GEANY_TEMPLATE_CHANGELOG
]);
697 const gchar
*file_type_name
= (doc
!= NULL
) ? doc
->file_type
->name
: "";
699 replace_static_values(result
);
700 templates_replace_default_dates(result
);
701 templates_replace_command(result
, DOC_FILENAME(doc
), file_type_name
, NULL
);
703 return g_string_free(result
, FALSE
);
707 void templates_free_templates(void)
710 GList
*children
, *item
;
712 /* disconnect the menu from the action widget, so destroying the items below doesn't
713 * trigger rebuilding of the menu on each item destroy */
714 geany_menu_button_action_set_menu(
715 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL
);
717 for (i
= 0; i
< GEANY_MAX_TEMPLATES
; i
++)
719 g_free(templates
[i
]);
721 for (i
= 0; i
< GEANY_MAX_BUILT_IN_FILETYPES
; i
++)
723 g_free(ft_templates
[i
]);
725 /* destroy "New with template" sub menu items (in case we want to reload the templates) */
726 children
= gtk_container_get_children(GTK_CONTAINER(new_with_template_menu
));
727 foreach_list(item
, children
)
729 gtk_widget_destroy(GTK_WIDGET(item
->data
));
731 g_list_free(children
);
733 g_object_unref(new_with_template_menu
);
734 new_with_template_menu
= NULL
;
738 static void replace_static_values(GString
*text
)
740 utils_string_replace_all(text
, "{version}", template_prefs
.version
);
741 utils_string_replace_all(text
, "{initial}", template_prefs
.initials
);
742 utils_string_replace_all(text
, "{developer}", template_prefs
.developer
);
743 utils_string_replace_all(text
, "{mail}", template_prefs
.mail
);
744 utils_string_replace_all(text
, "{company}", template_prefs
.company
);
745 utils_string_replace_all(text
, "{untitled}", GEANY_STRING_UNTITLED
);
746 utils_string_replace_all(text
, "{geanyversion}", "Geany " VERSION
);
750 /* Replaces all static template wildcards (version, mail, company, name, ...)
751 * plus those wildcard, value pairs which are passed, e.g.
753 * templates_replace_valist(text, "{some_wildcard}", "some value",
754 * "{another_wildcard}", "another value", NULL);
756 * The argument list must be terminated with NULL. */
757 void templates_replace_valist(GString
*text
, const gchar
*first_wildcard
, ...)
760 const gchar
*key
, *value
;
762 g_return_if_fail(text
!= NULL
);
764 va_start(args
, first_wildcard
);
766 key
= first_wildcard
;
767 value
= va_arg(args
, gchar
*);
771 utils_string_replace_all(text
, key
, value
);
773 key
= va_arg(args
, gchar
*);
774 if (key
== NULL
|| text
== NULL
)
776 value
= va_arg(args
, gchar
*);
780 replace_static_values(text
);
784 static void templates_replace_default_dates(GString
*text
)
786 gchar
*year
= utils_get_date_time(template_prefs
.year_format
, NULL
);
787 gchar
*date
= utils_get_date_time(template_prefs
.date_format
, NULL
);
788 gchar
*datetime
= utils_get_date_time(template_prefs
.datetime_format
, NULL
);
790 g_return_if_fail(text
!= NULL
);
792 templates_replace_valist(text
,
795 "{datetime}", datetime
,
798 utils_free_pointers(3, year
, date
, datetime
, NULL
);
802 static gchar
*run_command(const gchar
*command
, const gchar
*file_name
,
803 const gchar
*file_type
, const gchar
*func_name
)
805 gchar
*result
= NULL
;
808 if (g_shell_parse_argv(command
, NULL
, &argv
, NULL
))
810 GError
*error
= NULL
;
813 file_name
= (file_name
!= NULL
) ? file_name
: "";
814 file_type
= (file_type
!= NULL
) ? file_type
: "";
815 func_name
= (func_name
!= NULL
) ? func_name
: "";
817 env
= utils_copy_environment(NULL
,
818 "GEANY_FILENAME", file_name
,
819 "GEANY_FILETYPE", file_type
,
820 "GEANY_FUNCNAME", func_name
,
822 if (! utils_spawn_sync(NULL
, argv
, env
, G_SPAWN_SEARCH_PATH
,
823 NULL
, NULL
, &result
, NULL
, NULL
, &error
))
825 g_warning("templates_replace_command: %s", error
->message
);
836 static void templates_replace_command(GString
*text
, const gchar
*file_name
,
837 const gchar
*file_type
, const gchar
*func_name
)
840 gchar
*wildcard
= NULL
;
844 g_return_if_fail(text
!= NULL
);
846 while ((match
= strstr(text
->str
, "{command:")) != NULL
)
849 while (*match
!= '}' && *match
!= '\0')
852 wildcard
= g_strndup(cmd
, match
- cmd
+ 1);
853 cmd
= g_strndup(wildcard
+ 9, strlen(wildcard
) - 10);
855 result
= run_command(cmd
, file_name
, file_type
, func_name
);
858 utils_string_replace_first(text
, wildcard
, result
);
862 utils_string_replace_first(text
, wildcard
, "");