Save build commands for filetype None (patch by Lex, thanks).
[geany-mirror.git] / src / templates.c
blobab2a3595cb9d800e94d81c55a191126060b9bc2a
1 /*
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.
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 "editor.h"
39 #include "filetypes.h"
40 #include "ui_utils.h"
41 #include "toolbar.h"
42 #include "geanymenubuttonaction.h"
43 #include "project.h"
46 GeanyTemplatePrefs template_prefs;
48 static GtkWidget *new_with_template_menu = NULL; /* submenu used for both file menu and toolbar */
50 /* TODO: implement custom insertion templates instead? */
51 static gchar *templates[GEANY_MAX_TEMPLATES];
53 /* We should probably remove filetype templates support soon - users can use custom
54 * file templates instead. */
55 static gchar *ft_templates[GEANY_MAX_BUILT_IN_FILETYPES] = {NULL};
58 static void replace_static_values(GString *text);
59 static gchar *get_template_fileheader(GeanyFiletype *ft);
61 /* called by templates_replace_common */
62 static void templates_replace_default_dates(GString *text);
63 static void templates_replace_command(GString *text, const gchar *file_name,
64 const gchar *file_type, const gchar *func_name);
67 /* some simple macros to reduce code size and make the code readable */
68 #define TEMPLATES_GET_FILENAME(shortname) \
69 g_strconcat(app->configdir, \
70 G_DIR_SEPARATOR_S GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S, shortname, NULL)
72 #define TEMPLATES_READ_FILE(fname, contents_ptr) \
73 g_file_get_contents(fname, contents_ptr, NULL, NULL);
76 static void read_template(const gchar *name, gint id)
78 gchar *fname = TEMPLATES_GET_FILENAME(name);
80 /* try system if user template doesn't exist */
81 if (!g_file_test(fname, G_FILE_TEST_EXISTS))
82 setptr(fname, g_strconcat(app->datadir,
83 G_DIR_SEPARATOR_S GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S, name, NULL));
85 TEMPLATES_READ_FILE(fname, &templates[id]);
87 /* FIXME: we should replace the line ends on insertion with doc pref, not on loading */
89 GString *tmp = g_string_new(templates[id]);
90 const gchar *eol_str = (file_prefs.default_eol_character == SC_EOL_CR) ? "\r" : "\r\n";
92 /* first convert data to LF only */
93 utils_string_replace_all(tmp, "\r\n", "\n");
94 utils_string_replace_all(tmp, "\r", "\n");
95 /* now convert to desired line endings */
96 utils_string_replace_all(tmp, "\n", eol_str);
97 setptr(templates[id], tmp->str);
98 g_string_free(tmp, FALSE);
100 g_free(fname);
104 /* FIXME the callers should use GStrings instead of char arrays */
105 static gchar *replace_all(gchar *text, const gchar *year, const gchar *date, const gchar *datetime)
107 GString *str;
109 if (text == NULL)
110 return NULL;
112 str = g_string_new(text);
114 g_free(text);
115 templates_replace_valist(str,
116 "{year}", year,
117 "{date}", date,
118 "{datetime}", datetime,
119 NULL);
121 return g_string_free(str, FALSE);
125 static void convert_eol_characters(GString *template, GeanyDocument *doc)
127 gint doc_eol_mode;
129 if (doc == NULL)
130 doc = document_get_current();
132 g_return_if_fail(doc != NULL);
134 doc_eol_mode = editor_get_eol_char_mode(doc->editor);
135 utils_ensure_same_eol_characters(template, doc_eol_mode);
139 static void init_general_templates(const gchar *year, const gchar *date, const gchar *datetime)
141 guint id;
143 /* read the contents */
144 read_template("fileheader", GEANY_TEMPLATE_FILEHEADER);
145 read_template("gpl", GEANY_TEMPLATE_GPL);
146 read_template("bsd", GEANY_TEMPLATE_BSD);
147 read_template("function", GEANY_TEMPLATE_FUNCTION);
148 read_template("changelog", GEANY_TEMPLATE_CHANGELOG);
150 /* FIXME: we should replace the dates on insertion, not on loading */
151 for (id = 0; id < GEANY_MAX_TEMPLATES; id++)
152 templates[id] = replace_all(templates[id], year, date, datetime);
156 static void init_ft_templates(const gchar *year, const gchar *date, const gchar *datetime)
158 filetype_id ft_id;
160 for (ft_id = 0; ft_id < GEANY_MAX_BUILT_IN_FILETYPES; ft_id++)
162 gchar *ext = (ft_id != GEANY_FILETYPES_NONE) ?
163 filetypes_get_conf_extension(ft_id) : g_strdup("none");
164 gchar *shortname = g_strconcat("filetype.", ext, NULL);
165 gchar *fname = TEMPLATES_GET_FILENAME(shortname);
167 TEMPLATES_READ_FILE(fname, &ft_templates[ft_id]);
168 ft_templates[ft_id] = replace_all(ft_templates[ft_id], year, date, datetime);
170 g_free(fname);
171 g_free(shortname);
172 g_free(ext);
177 static void
178 on_new_with_filetype_template(GtkMenuItem *menuitem, gpointer user_data)
180 GeanyFiletype *ft = user_data;
181 gchar *template = templates_get_template_new_file(ft);
183 document_new_file(NULL, ft, template);
184 g_free(template);
188 /* TODO: remove filetype template support after 0.19 */
189 static gboolean create_new_filetype_items(void)
191 GSList *node;
192 gboolean ret = FALSE;
193 GtkWidget *menu = NULL;
195 foreach_slist(node, filetypes_by_title)
197 GeanyFiletype *ft = node->data;
198 GtkWidget *item;
200 if (ft->id >= GEANY_MAX_BUILT_IN_FILETYPES || ft_templates[ft->id] == NULL)
201 continue;
203 if (!menu)
205 item = gtk_menu_item_new_with_label(_("Old"));
206 menu = gtk_menu_new();
207 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
208 gtk_widget_show_all(item);
209 gtk_container_add(GTK_CONTAINER(new_with_template_menu), item);
211 item = gtk_menu_item_new_with_label(ft->title);
212 gtk_widget_show(item);
213 gtk_container_add(GTK_CONTAINER(menu), item);
214 g_signal_connect(item, "activate", G_CALLBACK(on_new_with_filetype_template), ft);
215 ret = TRUE;
217 return ret;
221 void templates_replace_common(GString *template, const gchar *fname,
222 GeanyFiletype *ft, const gchar *func_name)
224 gchar *shortname;
226 if (fname == NULL)
228 if (!ft->extension)
229 shortname = g_strdup(GEANY_STRING_UNTITLED);
230 else
231 shortname = g_strconcat(GEANY_STRING_UNTITLED, ".", ft->extension, NULL);
233 else
234 shortname = g_path_get_basename(fname);
236 templates_replace_valist(template,
237 "{filename}", shortname,
238 "{project}", app->project ? app->project->name : "",
239 "{description}", app->project ? app->project->description : "",
240 NULL);
241 g_free(shortname);
243 templates_replace_default_dates(template);
244 templates_replace_command(template, fname, ft->name, func_name);
245 /* Bug: command results could have {ob} {cb} strings in! */
246 /* replace braces last */
247 templates_replace_valist(template,
248 "{ob}", "{",
249 "{cb}", "}",
250 NULL);
254 static gchar *get_template_from_file(const gchar *locale_fname, const gchar *doc_filename,
255 GeanyFiletype *ft)
257 gchar *content;
258 GString *template = NULL;
260 g_file_get_contents(locale_fname, &content, NULL, NULL);
262 if (content != NULL)
264 gchar *file_header;
266 template = g_string_new(content);
268 file_header = get_template_fileheader(ft);
269 templates_replace_valist(template,
270 "{fileheader}", file_header,
271 NULL);
272 templates_replace_common(template, doc_filename, ft, NULL);
274 utils_free_pointers(2, file_header, content, NULL);
275 return g_string_free(template, FALSE);
277 return NULL;
281 static void
282 on_new_with_file_template(GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
284 gchar *fname = ui_menu_item_get_text(menuitem);
285 GeanyFiletype *ft;
286 gchar *template;
287 const gchar *extension = strrchr(fname, '.'); /* easy way to get the file extension */
288 gchar *new_filename = g_strconcat(GEANY_STRING_UNTITLED, extension, NULL);
289 gchar *path;
291 ft = filetypes_detect_from_extension(fname);
292 setptr(fname, utils_get_locale_from_utf8(fname));
294 /* fname is just the basename from the menu item, so prepend the custom files path */
295 path = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_TEMPLATES_SUBDIR,
296 "files", fname, NULL);
297 template = get_template_from_file(path, new_filename, ft);
298 if (!template)
300 /* try the system path */
301 g_free(path);
302 path = g_build_path(G_DIR_SEPARATOR_S, app->datadir, GEANY_TEMPLATES_SUBDIR,
303 "files", fname, NULL);
304 template = get_template_from_file(path, new_filename, ft);
306 if (template)
307 document_new_file(new_filename, ft, template);
308 else
310 setptr(fname, utils_get_utf8_from_locale(fname));
311 ui_set_statusbar(TRUE, _("Could not find file '%s'."), fname);
313 g_free(template);
314 g_free(path);
315 g_free(new_filename);
316 g_free(fname);
320 static void add_file_item(const gchar *fname, GtkWidget *menu)
322 GtkWidget *tmp_button;
323 gchar *label;
325 g_return_if_fail(fname);
326 g_return_if_fail(menu);
328 label = utils_get_utf8_from_locale(fname);
330 tmp_button = gtk_menu_item_new_with_label(label);
331 gtk_widget_show(tmp_button);
332 gtk_container_add(GTK_CONTAINER(menu), tmp_button);
333 g_signal_connect(tmp_button, "activate", G_CALLBACK(on_new_with_file_template), NULL);
335 g_free(label);
339 static gboolean add_custom_template_items(void)
341 GSList *list = utils_get_config_files(GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S "files");
342 GSList *node;
344 foreach_slist(node, list)
346 gchar *fname = node->data;
348 add_file_item(fname, new_with_template_menu);
349 g_free(fname);
351 g_slist_free(list);
352 return list != NULL;
356 static void create_file_template_menu(void)
358 GtkWidget *sep = NULL;
360 new_with_template_menu = gtk_menu_new();
362 if (add_custom_template_items())
364 sep = gtk_separator_menu_item_new();
365 gtk_container_add(GTK_CONTAINER(new_with_template_menu), sep);
367 if (create_new_filetype_items() && sep)
369 gtk_widget_show(sep);
371 /* unless the file menu is showing, menu should be in the toolbar widget */
372 geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(
373 toolbar_get_action_by_name("New")), new_with_template_menu);
377 static void on_file_menu_show(GtkWidget *item)
379 geany_menu_button_action_set_menu(
380 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL);
381 item = ui_lookup_widget(main_widgets.window, "menu_new_with_template1");
382 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_with_template_menu);
386 static void on_file_menu_hide(GtkWidget *item)
388 item = ui_lookup_widget(main_widgets.window, "menu_new_with_template1");
389 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), NULL);
390 geany_menu_button_action_set_menu(
391 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), new_with_template_menu);
395 /* reload templates if any file in the templates path is saved */
396 static void on_document_save(G_GNUC_UNUSED GObject *object, GeanyDocument *doc)
398 const gchar *path = utils_build_path(app->configdir, GEANY_TEMPLATES_SUBDIR, NULL);
400 g_return_if_fail(NZV(doc->real_path));
402 if (strncmp(doc->real_path, path, strlen(path)) == 0)
404 /* reload templates */
405 templates_free_templates();
406 templates_init();
411 /* warning: also called when reloading template settings */
412 void templates_init(void)
414 gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
415 gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
416 gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
417 static gboolean init_done = FALSE;
419 init_general_templates(year, date, datetime);
420 init_ft_templates(year, date, datetime);
422 g_free(date);
423 g_free(datetime);
424 g_free(year);
426 create_file_template_menu();
427 /* we hold our own ref for the menu as it has no parent whilst being moved */
428 g_object_ref(new_with_template_menu);
430 /* only connect signals to persistent objects once */
431 if (!init_done)
433 GtkWidget *item;
434 /* reparent the template menu as needed */
435 item = ui_lookup_widget(main_widgets.window, "file1");
436 item = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
437 g_signal_connect(item, "show", G_CALLBACK(on_file_menu_show), NULL);
438 g_signal_connect(item, "hide", G_CALLBACK(on_file_menu_hide), NULL);
440 g_signal_connect(geany_object, "document-save", G_CALLBACK(on_document_save), NULL);
442 init_done = TRUE;
446 /* indent is used to make some whitespace between comment char and real start of the line
447 * e.g. indent = 8 prints " * here comes the text of the line"
448 * indent is meant to be the whole amount of characters before the real line content follows, i.e.
449 * 6 characters are filled with whitespace when the comment characters include " *" */
450 static void make_comment_block(GString *comment_text, gint filetype_idx, guint indent)
452 gchar *frame_start; /* to add before comment_text */
453 gchar *frame_end; /* to add after comment_text */
454 const gchar *line_prefix; /* to add before every line in comment_text */
455 gchar *tmp;
456 gchar *prefix;
457 gchar **lines;
458 guint i, len;
459 gint template_eol_mode;
460 const gchar *template_eol_char;
461 GeanyFiletype *ft = filetypes_index(filetype_idx);
463 g_return_if_fail(comment_text != NULL);
464 g_return_if_fail(ft != NULL);
466 template_eol_mode = utils_get_line_endings(comment_text->str, comment_text->len);
467 template_eol_char = utils_get_eol_char(template_eol_mode);
469 if (NZV(ft->comment_open))
471 if (NZV(ft->comment_close))
473 frame_start = g_strconcat(ft->comment_open, template_eol_char, NULL);
474 frame_end = g_strconcat(ft->comment_close, template_eol_char, NULL);
475 line_prefix = "";
477 else
479 frame_start = NULL;
480 frame_end = NULL;
481 line_prefix = ft->comment_open;
484 else
485 { /* use C-like multi-line comments as fallback */
486 frame_start = g_strconcat("/*", template_eol_char, NULL);
487 frame_end = g_strconcat("*/", template_eol_char, NULL);
488 line_prefix = "";
491 /* do some magic to nicely format C-like multi-line comments */
492 if (NZV(frame_start) && frame_start[1] == '*')
494 /* prefix the string with a space */
495 setptr(frame_end, g_strconcat(" ", frame_end, NULL));
496 line_prefix = " *";
499 /* construct the real prefix with given amount of whitespace */
500 i = (indent > strlen(line_prefix)) ? (indent - strlen(line_prefix)) : strlen(line_prefix);
501 tmp = g_strnfill(i, ' ');
502 prefix = g_strconcat(line_prefix, tmp, NULL);
503 g_free(tmp);
505 /* add line_prefix to every line of comment_text */
506 lines = g_strsplit(comment_text->str, template_eol_char, -1);
507 len = g_strv_length(lines) - 1;
508 for (i = 0; i < len; i++)
510 tmp = lines[i];
511 lines[i] = g_strconcat(prefix, tmp, NULL);
512 g_free(tmp);
514 tmp = g_strjoinv(template_eol_char, lines);
516 /* clear old contents */
517 g_string_erase(comment_text, 0, -1);
519 /* add frame_end */
520 if (frame_start != NULL)
521 g_string_append(comment_text, frame_start);
522 /* add the new main content */
523 g_string_append(comment_text, tmp);
524 /* add frame_start */
525 if (frame_end != NULL)
526 g_string_append(comment_text, frame_end);
528 utils_free_pointers(4, prefix, tmp, frame_start, frame_end, NULL);
529 g_strfreev(lines);
533 gchar *templates_get_template_licence(GeanyDocument *doc, gint licence_type)
535 GString *template;
537 g_return_val_if_fail(doc != NULL, NULL);
538 g_return_val_if_fail(licence_type == GEANY_TEMPLATE_GPL || licence_type == GEANY_TEMPLATE_BSD, NULL);
540 template = g_string_new(templates[licence_type]);
541 replace_static_values(template);
542 templates_replace_default_dates(template);
543 templates_replace_command(template, DOC_FILENAME(doc), doc->file_type->name, NULL);
545 make_comment_block(template, doc->file_type->id, 8);
546 convert_eol_characters(template, doc);
548 return g_string_free(template, FALSE);
552 static gchar *get_template_fileheader(GeanyFiletype *ft)
554 GString *template = g_string_new(templates[GEANY_TEMPLATE_FILEHEADER]);
556 filetypes_load_config(ft->id, FALSE); /* load any user extension setting */
558 templates_replace_valist(template,
559 "{gpl}", templates[GEANY_TEMPLATE_GPL],
560 "{bsd}", templates[GEANY_TEMPLATE_BSD],
561 NULL);
563 /* we don't replace other wildcards here otherwise they would get done twice for files */
564 make_comment_block(template, ft->id, 8);
565 return g_string_free(template, FALSE);
569 /* TODO change the signature to take a GeanyDocument? this would break plugin API/ABI */
570 gchar *templates_get_template_fileheader(gint filetype_idx, const gchar *fname)
572 GeanyFiletype *ft = filetypes[filetype_idx];
573 gchar *str = get_template_fileheader(ft);
574 GString *template = g_string_new(str);
576 g_free(str);
577 templates_replace_common(template, fname, ft, NULL);
578 convert_eol_characters(template, NULL);
579 return g_string_free(template, FALSE);
583 gchar *templates_get_template_new_file(GeanyFiletype *ft)
585 GString *ft_template;
586 gchar *file_header = NULL;
588 g_return_val_if_fail(ft != NULL, NULL);
589 g_return_val_if_fail(ft->id < GEANY_MAX_BUILT_IN_FILETYPES, NULL);
591 ft_template = g_string_new(ft_templates[ft->id]);
592 if (FILETYPE_ID(ft) == GEANY_FILETYPES_NONE)
594 replace_static_values(ft_template);
596 else
597 { /* file template only used for new files */
598 file_header = get_template_fileheader(ft);
599 templates_replace_valist(ft_template, "{fileheader}", file_header, NULL);
601 templates_replace_common(ft_template, NULL, ft, NULL);
602 convert_eol_characters(ft_template, NULL);
604 g_free(file_header);
605 return g_string_free(ft_template, FALSE);
609 gchar *templates_get_template_function(GeanyDocument *doc, const gchar *func_name)
611 GString *text;
613 func_name = (func_name != NULL) ? func_name : "";
614 text = g_string_new(templates[GEANY_TEMPLATE_FUNCTION]);
616 templates_replace_valist(text, "{functionname}", func_name, NULL);
617 templates_replace_default_dates(text);
618 templates_replace_command(text, DOC_FILENAME(doc), doc->file_type->name, func_name);
620 make_comment_block(text, doc->file_type->id, 3);
621 convert_eol_characters(text, doc);
623 return g_string_free(text, FALSE);
627 gchar *templates_get_template_changelog(GeanyDocument *doc)
629 GString *result = g_string_new(templates[GEANY_TEMPLATE_CHANGELOG]);
630 const gchar *file_type_name = (doc != NULL) ? doc->file_type->name : "";
632 replace_static_values(result);
633 templates_replace_default_dates(result);
634 templates_replace_command(result, DOC_FILENAME(doc), file_type_name, NULL);
635 convert_eol_characters(result, doc);
637 return g_string_free(result, FALSE);
641 void templates_free_templates(void)
643 gint i;
644 GList *children, *item;
646 /* disconnect the menu from the action widget, so destroying the items below doesn't
647 * trigger rebuilding of the menu on each item destroy */
648 geany_menu_button_action_set_menu(
649 GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL);
651 for (i = 0; i < GEANY_MAX_TEMPLATES; i++)
653 g_free(templates[i]);
655 for (i = 0; i < GEANY_MAX_BUILT_IN_FILETYPES; i++)
657 g_free(ft_templates[i]);
659 /* destroy "New with template" sub menu items (in case we want to reload the templates) */
660 children = gtk_container_get_children(GTK_CONTAINER(new_with_template_menu));
661 foreach_list(item, children)
663 gtk_widget_destroy(GTK_WIDGET(item->data));
665 g_list_free(children);
667 g_object_unref(new_with_template_menu);
668 new_with_template_menu = NULL;
672 static void replace_static_values(GString *text)
674 utils_string_replace_all(text, "{version}", template_prefs.version);
675 utils_string_replace_all(text, "{initial}", template_prefs.initials);
676 utils_string_replace_all(text, "{developer}", template_prefs.developer);
677 utils_string_replace_all(text, "{mail}", template_prefs.mail);
678 utils_string_replace_all(text, "{company}", template_prefs.company);
679 utils_string_replace_all(text, "{untitled}", GEANY_STRING_UNTITLED);
680 utils_string_replace_all(text, "{geanyversion}", "Geany " VERSION);
684 /* Replaces all static template wildcards (version, mail, company, name, ...)
685 * plus those wildcard, value pairs which are passed, e.g.
687 * templates_replace_valist(text, "{some_wildcard}", "some value",
688 * "{another_wildcard}", "another value", NULL);
690 * The argument list must be terminated with NULL. */
691 void templates_replace_valist(GString *text, const gchar *first_wildcard, ...)
693 va_list args;
694 const gchar *key, *value;
696 g_return_if_fail(text != NULL);
698 va_start(args, first_wildcard);
700 key = first_wildcard;
701 value = va_arg(args, gchar*);
703 while (key != NULL)
705 utils_string_replace_all(text, key, value);
707 key = va_arg(args, gchar*);
708 if (key == NULL || text == NULL)
709 break;
710 value = va_arg(args, gchar*);
712 va_end(args);
714 replace_static_values(text);
718 static void templates_replace_default_dates(GString *text)
720 gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
721 gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
722 gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
724 g_return_if_fail(text != NULL);
726 templates_replace_valist(text,
727 "{year}", year,
728 "{date}", date,
729 "{datetime}", datetime,
730 NULL);
732 utils_free_pointers(3, year, date, datetime, NULL);
736 static gchar *run_command(const gchar *command, const gchar *file_name,
737 const gchar *file_type, const gchar *func_name)
739 gchar *result = NULL;
740 gchar **argv;
742 if (g_shell_parse_argv(command, NULL, &argv, NULL))
744 GError *error = NULL;
745 gchar **env;
747 file_name = (file_name != NULL) ? file_name : "";
748 file_type = (file_type != NULL) ? file_type : "";
749 func_name = (func_name != NULL) ? func_name : "";
751 env = utils_copy_environment(NULL,
752 "GEANY_FILENAME", file_name,
753 "GEANY_FILETYPE", file_type,
754 "GEANY_FUNCNAME", func_name,
755 NULL);
756 if (! utils_spawn_sync(NULL, argv, env, G_SPAWN_SEARCH_PATH,
757 NULL, NULL, &result, NULL, NULL, &error))
759 g_warning("templates_replace_command: %s", error->message);
760 g_error_free(error);
761 return NULL;
763 g_strfreev(argv);
764 g_strfreev(env);
766 return result;
770 static void templates_replace_command(GString *text, const gchar *file_name,
771 const gchar *file_type, const gchar *func_name)
773 gchar *match = NULL;
774 gchar *wildcard = NULL;
775 gchar *cmd;
776 gchar *result;
778 g_return_if_fail(text != NULL);
780 while ((match = strstr(text->str, "{command:")) != NULL)
782 cmd = match;
783 while (*match != '}' && *match != '\0')
784 match++;
786 wildcard = g_strndup(cmd, match - cmd + 1);
787 cmd = g_strndup(wildcard + 9, strlen(wildcard) - 10);
789 result = run_command(cmd, file_name, file_type, func_name);
790 if (result != NULL)
792 result = g_strstrip(result);
793 utils_string_replace_first(text, wildcard, result);
794 g_free(result);
796 else
797 utils_string_replace_first(text, wildcard, "");
799 g_free(wildcard);
800 g_free(cmd);