~ubuntu-branches/ubuntu/natty/geany/natty

« back to all changes in this revision

Viewing changes to src/templates.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2010-08-07 03:23:12 UTC
  • mfrom: (1.4.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20100807032312-ot70ac9d50cn79we
Tags: upstream-0.19
ImportĀ upstreamĀ versionĀ 0.19

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *      along with this program; if not, write to the Free Software
19
19
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 *
21
 
 * $Id: templates.c 4653 2010-02-07 18:24:45Z eht16 $
 
21
 * $Id: templates.c 4917 2010-05-15 13:14:38Z eht16 $
22
22
 */
23
23
 
24
24
/*
39
39
#include "ui_utils.h"
40
40
#include "toolbar.h"
41
41
#include "geanymenubuttonaction.h"
 
42
#include "project.h"
42
43
 
43
44
 
44
45
GeanyTemplatePrefs template_prefs;
45
46
 
46
 
static GtkWidget *new_with_template_menu = NULL;        /* File menu submenu */
47
 
 
 
47
static GtkWidget *new_with_template_menu = NULL;        /* submenu used for both file menu and toolbar */
 
48
 
 
49
 
 
50
/* TODO: implement custom insertion templates, put these into files in data/templates */
48
51
 
49
52
/* default templates, only for initial tempate file creation on first start of Geany */
50
53
static const gchar templates_gpl_notice[] = "\
117
120
\n\
118
121
 * \n\n\n";
119
122
 
120
 
static const gchar templates_filetype_none[] = "";
121
 
 
122
 
static const gchar templates_filetype_c[] = "{fileheader}\n\n\
123
 
#include <stdio.h>\n\
124
 
\n\
125
 
int main(int argc, char** argv)\n\
126
 
{\n\
127
 
        \n\
128
 
        return 0;\n\
129
 
}\n\
130
 
";
131
 
 
132
 
static const gchar templates_filetype_cpp[] = "{fileheader}\n\n\
133
 
#include <iostream>\n\
134
 
\n\
135
 
int main(int argc, char** argv)\n\
136
 
{\n\
137
 
        \n\
138
 
        return 0;\n\
139
 
}\n\
140
 
";
141
 
 
142
 
static const gchar templates_filetype_d[] = "{fileheader}\n\n\
143
 
import std.stdio;\n\
144
 
\n\
145
 
int main(char[][] args)\n\
146
 
{\n\
147
 
        \n\
148
 
        return 0;\n\
149
 
}\n\
150
 
";
151
 
 
152
 
static const gchar templates_filetype_php[] = "\
153
 
<?php\n\
154
 
{fileheader}\
155
 
?>\n\n\
156
 
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
157
 
  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
158
 
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\
159
 
\n\
160
 
<head>\n\
161
 
        <title>{untitled}</title>\n\
162
 
        <meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />\n\
163
 
        <meta name=\"generator\" content=\"{geanyversion}\" />\n\
164
 
</head>\n\
165
 
\n\
166
 
<body>\n\
167
 
        \n\
168
 
</body>\n\
169
 
</html>\n\
170
 
";
171
 
 
172
 
static const gchar templates_filetype_html[] = "{fileheader}\n\
173
 
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
174
 
  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
175
 
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\
176
 
\n\
177
 
<head>\n\
178
 
        <title>{untitled}</title>\n\
179
 
        <meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />\n\
180
 
        <meta name=\"generator\" content=\"{geanyversion}\" />\n\
181
 
</head>\n\
182
 
\n\
183
 
<body>\n\
184
 
        \n\
185
 
</body>\n\
186
 
</html>\n\
187
 
";
188
 
 
189
 
static const gchar templates_filetype_pascal[] = "{fileheader}\n\n\
190
 
program {untitled};\n\
191
 
\n\
192
 
uses crt;\n\
193
 
var i : byte;\n\
194
 
\n\
195
 
BEGIN\n\
196
 
        \n\
197
 
        \n\
198
 
END.\n\
199
 
";
200
 
 
201
 
static const gchar templates_filetype_java[] = "{fileheader}\n\n\
202
 
public class {untitled} {\n\
203
 
\n\
204
 
        public static void main (String args[]) {\
205
 
                \n\
206
 
                \n\
207
 
        }\n\
208
 
}\n\
209
 
";
210
 
 
211
 
static const gchar templates_filetype_ruby[] = "{fileheader}\n\n\
212
 
class StdClass\n\
213
 
        def initialize\n\
214
 
                \n\
215
 
        end\n\
216
 
end\n\
217
 
\n\
218
 
x = StdClass.new\n\
219
 
";
220
 
 
221
 
static const gchar templates_filetype_python[] = "#!/usr/bin/env python\n\
222
 
# -*- coding: utf-8 -*-\n#\n\
223
 
{fileheader}\n\n\
224
 
\n\
225
 
def main():\n\
226
 
        \n\
227
 
        return 0\n\
228
 
\n\
229
 
if __name__ == '__main__':\n\
230
 
        main()\n\
231
 
";
232
 
 
233
 
static const gchar templates_filetype_latex[] = "\
234
 
\\documentclass[a4paper]{article}\n\
235
 
\\usepackage[T1]{fontenc}\n\
236
 
\\usepackage[utf8]{inputenc}\n\
237
 
\\usepackage{lmodern}\n\
238
 
\\usepackage{babel}\n\
239
 
\\begin{document}\n\
240
 
\n\
241
 
\\end{document}\n\
242
 
";
243
 
 
244
123
static gchar *templates[GEANY_MAX_TEMPLATES];
 
124
 
 
125
/* We should probably remove filetype templates support soon - users can use custom
 
126
 * file templates instead. */
245
127
static gchar *ft_templates[GEANY_MAX_BUILT_IN_FILETYPES] = {NULL};
246
128
 
247
129
 
 
130
static void replace_static_values(GString *text);
 
131
static gchar *get_template_fileheader(GeanyFiletype *ft);
 
132
 
 
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);
 
137
 
 
138
 
248
139
/* some simple macros to reduce code size and make the code readable */
249
140
#define TEMPLATES_GET_FILENAME(shortname) \
250
141
        g_strconcat(app->configdir, \
274
165
        }
275
166
}
276
167
 
 
168
 
277
169
/* FIXME the callers should use GStrings instead of char arrays */
278
170
static gchar *replace_all(gchar *text, const gchar *year, const gchar *date, const gchar *datetime)
279
171
{
285
177
        str = g_string_new(text);
286
178
 
287
179
        g_free(text);
288
 
        templates_replace_all(str, year, date, datetime);
 
180
        templates_replace_valist(str,
 
181
                "{year}", year,
 
182
                "{date}", date,
 
183
                "{datetime}", datetime,
 
184
                NULL);
289
185
 
290
186
        return g_string_free(str, FALSE);
291
187
}
341
237
                gchar *shortname = g_strconcat("filetype.", ext, NULL);
342
238
                gchar *fname = TEMPLATES_GET_FILENAME(shortname);
343
239
 
344
 
                switch (ft_id)
345
 
                {
346
 
                        case GEANY_FILETYPES_NONE:
347
 
                                create_template_file_if_necessary(fname, templates_filetype_none);
348
 
                                break;
349
 
                        case GEANY_FILETYPES_C:
350
 
                                create_template_file_if_necessary(fname, templates_filetype_c);
351
 
                                break;
352
 
                        case GEANY_FILETYPES_CPP:
353
 
                                create_template_file_if_necessary(fname, templates_filetype_cpp);
354
 
                                break;
355
 
                        case GEANY_FILETYPES_D:
356
 
                                create_template_file_if_necessary(fname, templates_filetype_d);
357
 
                                break;
358
 
                        case GEANY_FILETYPES_JAVA:
359
 
                                create_template_file_if_necessary(fname, templates_filetype_java);
360
 
                                break;
361
 
                        case GEANY_FILETYPES_PASCAL:
362
 
                                create_template_file_if_necessary(fname, templates_filetype_pascal);
363
 
                                break;
364
 
                        case GEANY_FILETYPES_PHP:
365
 
                                create_template_file_if_necessary(fname, templates_filetype_php);
366
 
                                break;
367
 
                        case GEANY_FILETYPES_HTML:
368
 
                                create_template_file_if_necessary(fname, templates_filetype_html);
369
 
                                break;
370
 
                        case GEANY_FILETYPES_RUBY:
371
 
                                create_template_file_if_necessary(fname, templates_filetype_ruby);
372
 
                                break;
373
 
                        case GEANY_FILETYPES_PYTHON:
374
 
                                create_template_file_if_necessary(fname, templates_filetype_python);
375
 
                                break;
376
 
                        case GEANY_FILETYPES_LATEX:
377
 
                                create_template_file_if_necessary(fname, templates_filetype_latex);
378
 
                                break;
379
 
                        default: break;
380
 
                }
381
240
                TEMPLATES_READ_FILE(fname, &ft_templates[ft_id]);
382
241
                ft_templates[ft_id] = replace_all(ft_templates[ft_id], year, date, datetime);
383
242
 
389
248
 
390
249
 
391
250
static void
392
 
on_new_with_template                   (GtkMenuItem     *menuitem,
393
 
                                        gpointer         user_data)
 
251
on_new_with_filetype_template(GtkMenuItem *menuitem, gpointer user_data)
394
252
{
395
253
        GeanyFiletype *ft = user_data;
396
254
        gchar *template = templates_get_template_new_file(ft);
400
258
}
401
259
 
402
260
 
403
 
/* template items for the new file menu */
404
 
static void create_new_menu_items(GtkWidget *toolbar_new_file_menu)
 
261
/* TODO: remove filetype template support after 0.19 */
 
262
static gboolean create_new_filetype_items(void)
405
263
{
406
264
        GSList *node;
 
265
        gboolean ret = FALSE;
 
266
        GtkWidget *menu = NULL;
407
267
 
408
268
        foreach_slist(node, filetypes_by_title)
409
269
        {
410
270
                GeanyFiletype *ft = node->data;
411
 
                GtkWidget *tmp_menu, *tmp_button;
412
 
                const gchar *label = ft->title;
 
271
                GtkWidget *item;
413
272
 
414
 
                if (ft_templates[ft->id] == NULL)
 
273
                if (ft->id >= GEANY_MAX_BUILT_IN_FILETYPES || ft_templates[ft->id] == NULL)
415
274
                        continue;
416
275
 
417
 
                tmp_menu = gtk_menu_item_new_with_label(label);
418
 
                gtk_widget_show(tmp_menu);
419
 
                gtk_container_add(GTK_CONTAINER(new_with_template_menu), tmp_menu);
420
 
                g_signal_connect(tmp_menu, "activate", G_CALLBACK(on_new_with_template), ft);
421
 
 
422
 
                tmp_button = gtk_menu_item_new_with_label(label);
423
 
                gtk_widget_show(tmp_button);
424
 
                gtk_container_add(GTK_CONTAINER(toolbar_new_file_menu), tmp_button);
425
 
                g_signal_connect(tmp_button, "activate", G_CALLBACK(on_new_with_template), ft);
426
 
        }
 
276
                if (!menu)
 
277
                {
 
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);
 
283
                }
 
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);
 
288
                ret = TRUE;
 
289
        }
 
290
        return ret;
 
291
}
 
292
 
 
293
 
 
294
void templates_replace_common(GString *template, const gchar *fname,
 
295
                                                          GeanyFiletype *ft, const gchar *func_name)
 
296
{
 
297
        gchar *shortname;
 
298
 
 
299
        if (fname == NULL)
 
300
        {
 
301
                if (!ft->extension)
 
302
                        shortname = g_strdup(GEANY_STRING_UNTITLED);
 
303
                else
 
304
                        shortname = g_strconcat(GEANY_STRING_UNTITLED, ".", ft->extension, NULL);
 
305
        }
 
306
        else
 
307
                shortname = g_path_get_basename(fname);
 
308
 
 
309
        templates_replace_valist(template,
 
310
                "{filename}", shortname,
 
311
                "{project}", app->project ? app->project->name : "",
 
312
                "{description}", app->project ? app->project->description : "",
 
313
                NULL);
 
314
        g_free(shortname);
 
315
 
 
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,
 
321
                "{ob}", "{",
 
322
                "{cb}", "}",
 
323
                NULL);
427
324
}
428
325
 
429
326
 
438
335
        if (content != NULL)
439
336
        {
440
337
                gchar *file_header;
441
 
                gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
442
 
                gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
443
 
                gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
444
338
 
445
339
                template = g_string_new(content);
446
340
 
447
 
                file_header = templates_get_template_fileheader(FILETYPE_ID(ft), doc_filename);
448
 
                templates_replace_all(template, year, date, datetime);
449
 
                utils_string_replace_all(template, "{filename}", doc_filename);
450
 
                utils_string_replace_all(template, "{fileheader}", file_header);
 
341
                file_header = get_template_fileheader(ft);
 
342
                templates_replace_valist(template,
 
343
                        "{fileheader}", file_header,
 
344
                        NULL);
 
345
                templates_replace_common(template, doc_filename, ft, NULL);
451
346
 
452
 
                utils_free_pointers(5, year, date, datetime, file_header, content, NULL);
 
347
                utils_free_pointers(2, file_header, content, NULL);
 
348
                return g_string_free(template, FALSE);
453
349
        }
454
 
        return g_string_free(template, FALSE);
 
350
        return NULL;
455
351
}
456
352
 
457
353
 
461
357
        gchar *fname = ui_menu_item_get_text(menuitem);
462
358
        GeanyFiletype *ft;
463
359
        gchar *template;
464
 
        gchar *extension = strrchr(fname, '.'); /* easy way to get the file extension */
 
360
        const gchar *extension = strrchr(fname, '.'); /* easy way to get the file extension */
465
361
        gchar *new_filename = g_strconcat(GEANY_STRING_UNTITLED, extension, NULL);
 
362
        gchar *path;
466
363
 
467
364
        ft = filetypes_detect_from_extension(fname);
468
365
        setptr(fname, utils_get_locale_from_utf8(fname));
 
366
 
469
367
        /* fname is just the basename from the menu item, so prepend the custom files path */
470
 
        setptr(fname, g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_TEMPLATES_SUBDIR,
471
 
                "files", fname, NULL));
472
 
        template = get_template_from_file(fname, new_filename, ft);
 
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);
 
371
        if (!template)
 
372
        {
 
373
                /* try the system path */
 
374
                g_free(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);
 
378
        }
 
379
        if (template)
 
380
                document_new_file(new_filename, ft, template);
 
381
        else
 
382
        {
 
383
                setptr(fname, utils_get_utf8_from_locale(fname));
 
384
                ui_set_statusbar(TRUE, _("Could not find file '%s'."), fname);
 
385
        }
 
386
        g_free(template);
 
387
        g_free(path);
 
388
        g_free(new_filename);
473
389
        g_free(fname);
474
 
 
475
 
        document_new_file(new_filename, ft, template);
476
 
        g_free(template);
477
 
        g_free(new_filename);
478
390
}
479
391
 
480
392
 
481
 
static void add_file_item(gpointer data, gpointer user_data)
 
393
static void add_file_item(const gchar *fname, GtkWidget *menu)
482
394
{
483
 
        GtkWidget *tmp_menu, *tmp_button;
484
 
        GtkWidget *toolbar_new_file_menu = user_data;
 
395
        GtkWidget *tmp_button;
485
396
        gchar *label;
486
397
 
487
 
        g_return_if_fail(data);
488
 
 
489
 
        label = utils_get_utf8_from_locale(data);
490
 
 
491
 
        tmp_menu = gtk_menu_item_new_with_label(label);
492
 
        gtk_widget_show(tmp_menu);
493
 
        gtk_container_add(GTK_CONTAINER(new_with_template_menu), tmp_menu);
494
 
        g_signal_connect(tmp_menu, "activate", G_CALLBACK(on_new_with_file_template), NULL);
 
398
        g_return_if_fail(fname);
 
399
        g_return_if_fail(menu);
 
400
 
 
401
        label = utils_get_utf8_from_locale(fname);
495
402
 
496
403
        tmp_button = gtk_menu_item_new_with_label(label);
497
404
        gtk_widget_show(tmp_button);
498
 
        gtk_container_add(GTK_CONTAINER(toolbar_new_file_menu), tmp_button);
 
405
        gtk_container_add(GTK_CONTAINER(menu), tmp_button);
499
406
        g_signal_connect(tmp_button, "activate", G_CALLBACK(on_new_with_file_template), NULL);
500
407
 
501
408
        g_free(label);
502
409
}
503
410
 
504
411
 
505
 
static gint compare_filenames_by_filetype(gconstpointer a, gconstpointer b)
506
 
{
507
 
        GeanyFiletype *ft_a = filetypes_detect_from_extension(a);
508
 
        GeanyFiletype *ft_b = filetypes_detect_from_extension(b);
509
 
 
510
 
        /* sort by filetype name first */
511
 
        if (G_LIKELY(ft_a != ft_b))
512
 
        {
513
 
                /* None filetypes should come first */
514
 
                if (G_UNLIKELY(ft_a->id == GEANY_FILETYPES_NONE))
515
 
                        return -1;
516
 
                if (G_UNLIKELY(ft_b->id == GEANY_FILETYPES_NONE))
517
 
                        return 1;
518
 
 
519
 
                return utils_str_casecmp(ft_a->name, ft_b->name);
520
 
        }
521
 
        return utils_str_casecmp(a, b);
522
 
}
523
 
 
524
 
 
525
 
static gboolean add_custom_template_items(GtkWidget *toolbar_new_file_menu)
526
 
{
527
 
        gchar *path = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_TEMPLATES_SUBDIR,
528
 
                "files", NULL);
529
 
        GSList *list = utils_get_file_list(path, NULL, NULL);
530
 
 
531
 
        if (list == NULL)
532
 
        {
533
 
                utils_mkdir(path, FALSE);
534
 
                return FALSE;
535
 
        }
536
 
        list = g_slist_sort(list, compare_filenames_by_filetype);
537
 
        g_slist_foreach(list, add_file_item, toolbar_new_file_menu);
538
 
        g_slist_foreach(list, (GFunc) g_free, NULL);
 
412
static gboolean add_custom_template_items(void)
 
413
{
 
414
        GSList *list = utils_get_config_files(GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S "files");
 
415
        GSList *node;
 
416
 
 
417
        foreach_slist(node, list)
 
418
        {
 
419
                gchar *fname = node->data;
 
420
 
 
421
                add_file_item(fname, new_with_template_menu);
 
422
                g_free(fname);
 
423
        }
539
424
        g_slist_free(list);
540
 
        g_free(path);
541
 
        return TRUE;
 
425
        return list != NULL;
542
426
}
543
427
 
544
428
 
545
 
static void create_file_template_menus(void)
 
429
static void create_file_template_menu(void)
546
430
{
547
 
        GtkWidget *sep1, *sep2 = NULL;
548
 
        GtkWidget *toolbar_new_file_menu = NULL;
549
 
 
550
 
        new_with_template_menu = ui_lookup_widget(main_widgets.window, "menu_new_with_template1_menu");
551
 
        toolbar_new_file_menu = gtk_menu_new();
552
 
        /* we hold our own ref on the menu in case it is not used in the toolbar */
553
 
        g_object_ref(toolbar_new_file_menu);
554
 
 
555
 
        create_new_menu_items(toolbar_new_file_menu);
556
 
 
557
 
        sep1 = gtk_separator_menu_item_new();
558
 
        gtk_container_add(GTK_CONTAINER(new_with_template_menu), sep1);
559
 
        sep2 = gtk_separator_menu_item_new();
560
 
        gtk_container_add(GTK_CONTAINER(toolbar_new_file_menu), sep2);
561
 
 
562
 
        if (add_custom_template_items(toolbar_new_file_menu))
563
 
        {
564
 
                gtk_widget_show(sep1);
565
 
                gtk_widget_show(sep2);
566
 
        }
567
 
 
 
431
        GtkWidget *sep = NULL;
 
432
 
 
433
        new_with_template_menu = gtk_menu_new();
 
434
 
 
435
        if (add_custom_template_items())
 
436
        {
 
437
                sep = gtk_separator_menu_item_new();
 
438
                gtk_container_add(GTK_CONTAINER(new_with_template_menu), sep);
 
439
        }
 
440
        if (create_new_filetype_items() && sep)
 
441
        {
 
442
                gtk_widget_show(sep);
 
443
        }
 
444
        /* unless the file menu is showing, menu should be in the toolbar widget */
568
445
        geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(
569
 
                toolbar_get_action_by_name("New")), toolbar_new_file_menu);
570
 
}
571
 
 
572
 
 
 
446
                toolbar_get_action_by_name("New")), new_with_template_menu);
 
447
}
 
448
 
 
449
 
 
450
static void on_file_menu_show(GtkWidget *item)
 
451
{
 
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);
 
456
}
 
457
 
 
458
 
 
459
static void on_file_menu_hide(GtkWidget *item)
 
460
{
 
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);
 
465
}
 
466
 
 
467
 
 
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)
 
470
{
 
471
        const gchar *path = utils_build_path(app->configdir, GEANY_TEMPLATES_SUBDIR, NULL);
 
472
 
 
473
        g_return_if_fail(NZV(doc->real_path));
 
474
 
 
475
        if (strncmp(doc->real_path, path, strlen(path)) == 0)
 
476
        {
 
477
                /* reload templates */
 
478
                templates_free_templates();
 
479
                templates_init();
 
480
        }
 
481
}
 
482
 
 
483
 
 
484
/* warning: also called when reloading template settings */
573
485
void templates_init(void)
574
486
{
575
487
        gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
576
488
        gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
577
489
        gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
 
490
        static gboolean init_done = FALSE;
578
491
 
579
492
        init_general_templates(year, date, datetime);
580
493
        init_ft_templates(year, date, datetime);
583
496
        g_free(datetime);
584
497
        g_free(year);
585
498
 
586
 
        create_file_template_menus();
 
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);
 
502
 
 
503
        /* only connect signals to persistent objects once */
 
504
        if (!init_done)
 
505
        {
 
506
                GtkWidget *item;
 
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);
 
512
 
 
513
                g_signal_connect(geany_object, "document-save", G_CALLBACK(on_document_save), NULL);
 
514
        }
 
515
        init_done = TRUE;
587
516
}
588
517
 
589
518
 
591
520
 * e.g. indent = 8 prints " *     here comes the text of the line"
592
521
 * indent is meant to be the whole amount of characters before the real line content follows, i.e.
593
522
 * 6 characters are filled with whitespace when the comment characters include " *" */
 
523
/* TODO make this function operating on a GString */
594
524
static gchar *make_comment_block(const gchar *comment_text, gint filetype_idx, guint indent)
595
525
{
596
 
        gchar *frame_start;             /* to add before comment_text */
597
 
        gchar *frame_end;               /* to add after comment_text */
598
 
        gchar *line_prefix;             /* to add before every line in comment_text */
 
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 */
599
529
        gchar *result;
600
530
        gchar *tmp;
601
531
        gchar *prefix;
664
594
}
665
595
 
666
596
 
667
 
gchar *templates_get_template_licence(gint filetype_idx, gint licence_type)
668
 
{
669
 
        if (licence_type != GEANY_TEMPLATE_GPL && licence_type != GEANY_TEMPLATE_BSD)
670
 
                return NULL;
671
 
 
672
 
        return make_comment_block(templates[licence_type], filetype_idx, 8);
673
 
}
674
 
 
675
 
 
 
597
gchar *templates_get_template_licence(GeanyDocument *doc, gint licence_type)
 
598
{
 
599
        GString *template;
 
600
        gchar *result = NULL;
 
601
 
 
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);
 
604
 
 
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);
 
609
 
 
610
        result = make_comment_block(template->str, FILETYPE_ID(doc->file_type), 8);
 
611
 
 
612
        g_string_free(template, TRUE);
 
613
 
 
614
        return result;
 
615
}
 
616
 
 
617
 
 
618
static gchar *get_template_fileheader(GeanyFiletype *ft)
 
619
{
 
620
        GString *template = g_string_new(templates[GEANY_TEMPLATE_FILEHEADER]);
 
621
        gchar *result;
 
622
 
 
623
        filetypes_load_config(ft->id, FALSE);   /* load any user extension setting */
 
624
 
 
625
        templates_replace_valist(template,
 
626
                "{gpl}", templates[GEANY_TEMPLATE_GPL],
 
627
                "{bsd}", templates[GEANY_TEMPLATE_BSD],
 
628
                NULL);
 
629
 
 
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);
 
633
        return result;
 
634
}
 
635
 
 
636
 
 
637
/* TODO change the signature to take a GeanyDocument? this would break plugin API/ABI */
676
638
gchar *templates_get_template_fileheader(gint filetype_idx, const gchar *fname)
677
639
{
678
 
        gchar *template = g_strdup(templates[GEANY_TEMPLATE_FILEHEADER]);
679
 
        gchar *shortname;
680
 
        gchar *result;
681
 
        gchar *date = utils_get_date_time(template_prefs.datetime_format, NULL);
682
 
        filetype_id ft_id = filetype_idx;
683
 
        GeanyFiletype *ft = filetypes[ft_id];
684
 
 
685
 
        filetypes_load_config(ft_id, FALSE);    /* load any user extension setting */
686
 
 
687
 
        if (fname == NULL)
688
 
        {
689
 
                if (ft_id == GEANY_FILETYPES_NONE)
690
 
                        shortname = g_strdup(GEANY_STRING_UNTITLED);
691
 
                else
692
 
                        shortname = g_strconcat(GEANY_STRING_UNTITLED, ".", ft->extension, NULL);
693
 
        }
694
 
        else
695
 
                shortname = g_path_get_basename(fname);
696
 
 
697
 
        utils_str_replace_all(&template, "{filename}", shortname);
698
 
        utils_str_replace_all(&template, "{gpl}", templates[GEANY_TEMPLATE_GPL]);
699
 
        utils_str_replace_all(&template, "{bsd}", templates[GEANY_TEMPLATE_BSD]);
700
 
        utils_str_replace_all(&template, "{datetime}", date);
701
 
 
702
 
        result = make_comment_block(template, ft_id, 8);
703
 
 
704
 
        g_free(template);
705
 
        g_free(shortname);
706
 
        g_free(date);
707
 
        return result;
708
 
}
709
 
 
710
 
 
711
 
static gchar *get_file_template(GeanyFiletype *ft)
712
 
{
713
 
        filetype_id ft_id = FILETYPE_ID(ft);
714
 
 
715
 
        return g_strdup(ft_templates[ft_id]);
 
640
        GeanyFiletype *ft = filetypes[filetype_idx];
 
641
        gchar *str = get_template_fileheader(ft);
 
642
        GString *template = g_string_new(str);
 
643
 
 
644
        g_free(str);
 
645
        templates_replace_common(template, fname, ft, NULL);
 
646
        return g_string_free(template, FALSE);
716
647
}
717
648
 
718
649
 
719
650
gchar *templates_get_template_new_file(GeanyFiletype *ft)
720
651
{
721
 
        gchar *ft_template = NULL;
 
652
        GString *ft_template;
722
653
        gchar *file_header = NULL;
723
654
 
 
655
        g_return_val_if_fail(ft != NULL, NULL);
 
656
        g_return_val_if_fail(ft->id < GEANY_MAX_BUILT_IN_FILETYPES, NULL);
 
657
 
 
658
        ft_template = g_string_new(ft_templates[ft->id]);
724
659
        if (FILETYPE_ID(ft) == GEANY_FILETYPES_NONE)
725
 
                return get_file_template(ft);
 
660
        {
 
661
                replace_static_values(ft_template);
 
662
        }
 
663
        else
 
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);
 
667
        }
 
668
        templates_replace_common(ft_template, NULL, ft, NULL);
726
669
 
727
 
        file_header = templates_get_template_fileheader(ft->id, NULL);  /* file template only used for new files */
728
 
        ft_template = get_file_template(ft);
729
 
        utils_str_replace_all(&ft_template, "{fileheader}", file_header);
730
670
        g_free(file_header);
731
 
        return ft_template;
732
 
}
733
 
 
734
 
 
735
 
gchar *templates_get_template_generic(gint template)
736
 
{
737
 
        return g_strdup(templates[template]);
738
 
}
739
 
 
740
 
 
741
 
gchar *templates_get_template_function(gint filetype_idx, const gchar *func_name)
742
 
{
743
 
        gchar *template = g_strdup(templates[GEANY_TEMPLATE_FUNCTION]);
744
 
        gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
745
 
        gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
 
671
        return g_string_free(ft_template, FALSE);
 
672
}
 
673
 
 
674
 
 
675
gchar *templates_get_template_function(GeanyDocument *doc, const gchar *func_name)
 
676
{
746
677
        gchar *result;
747
 
 
748
 
        utils_str_replace_all(&template, "{date}", date);
749
 
        utils_str_replace_all(&template, "{datetime}", datetime);
750
 
        utils_str_replace_all(&template, "{functionname}", (func_name) ? func_name : "");
751
 
 
752
 
        result = make_comment_block(template, filetype_idx, 3);
753
 
 
754
 
        g_free(template);
755
 
        g_free(date);
756
 
        g_free(datetime);
 
678
        GString *text;
 
679
 
 
680
        func_name = (func_name != NULL) ? func_name : "";
 
681
        text = g_string_new(templates[GEANY_TEMPLATE_FUNCTION]);
 
682
 
 
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);
 
686
 
 
687
        result = make_comment_block(text->str, doc->file_type->id, 3);
 
688
 
 
689
        g_string_free(text, TRUE);
757
690
        return result;
758
691
}
759
692
 
760
693
 
761
 
gchar *templates_get_template_changelog(void)
 
694
gchar *templates_get_template_changelog(GeanyDocument *doc)
762
695
{
763
 
        gchar *date = utils_get_date_time(template_prefs.datetime_format, NULL);
764
 
        gchar *result = g_strdup(templates[GEANY_TEMPLATE_CHANGELOG]);
765
 
 
766
 
        utils_str_replace_all(&result, "{date}", date);
767
 
 
768
 
        g_free(date);
769
 
        return result;
 
696
        GString *result = g_string_new(templates[GEANY_TEMPLATE_CHANGELOG]);
 
697
        const gchar *file_type_name = (doc != NULL) ? doc->file_type->name : "";
 
698
 
 
699
        replace_static_values(result);
 
700
        templates_replace_default_dates(result);
 
701
        templates_replace_command(result, DOC_FILENAME(doc), file_type_name, NULL);
 
702
 
 
703
        return g_string_free(result, FALSE);
770
704
}
771
705
 
772
706
 
774
708
{
775
709
        gint i;
776
710
        GList *children, *item;
777
 
        GtkWidget *toolbar_new_file_menu = geany_menu_button_action_get_menu(
778
 
                                        GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")));
 
711
 
 
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);
779
716
 
780
717
        for (i = 0; i < GEANY_MAX_TEMPLATES; i++)
781
718
        {
786
723
                g_free(ft_templates[i]);
787
724
        }
788
725
        /* destroy "New with template" sub menu items (in case we want to reload the templates) */
789
 
        children = gtk_container_get_children(GTK_CONTAINER(toolbar_new_file_menu));
790
 
        foreach_list(item, children)
791
 
        {
792
 
                gtk_widget_destroy(GTK_WIDGET(item->data));
793
 
        }
794
 
        g_object_unref(toolbar_new_file_menu);
795
726
        children = gtk_container_get_children(GTK_CONTAINER(new_with_template_menu));
796
727
        foreach_list(item, children)
797
728
        {
798
729
                gtk_widget_destroy(GTK_WIDGET(item->data));
799
730
        }
 
731
        g_list_free(children);
 
732
 
 
733
        g_object_unref(new_with_template_menu);
 
734
        new_with_template_menu = NULL;
800
735
}
801
736
 
802
737
 
803
 
void templates_replace_all(GString *text, const gchar *year, const gchar *date,
804
 
                                                   const gchar *datetime)
 
738
static void replace_static_values(GString *text)
805
739
{
806
 
        utils_string_replace_all(text, "{year}", year);
807
 
        utils_string_replace_all(text, "{date}", date);
808
 
        utils_string_replace_all(text, "{datetime}", datetime);
809
740
        utils_string_replace_all(text, "{version}", template_prefs.version);
810
741
        utils_string_replace_all(text, "{initial}", template_prefs.initials);
811
742
        utils_string_replace_all(text, "{developer}", template_prefs.developer);
815
746
        utils_string_replace_all(text, "{geanyversion}", "Geany " VERSION);
816
747
}
817
748
 
 
749
 
 
750
/* Replaces all static template wildcards (version, mail, company, name, ...)
 
751
 * plus those wildcard, value pairs which are passed, e.g.
 
752
 *
 
753
 * templates_replace_valist(text, "{some_wildcard}", "some value",
 
754
 *      "{another_wildcard}", "another value", NULL);
 
755
 *
 
756
 * The argument list must be terminated with NULL. */
 
757
void templates_replace_valist(GString *text, const gchar *first_wildcard, ...)
 
758
{
 
759
        va_list args;
 
760
        const gchar *key, *value;
 
761
 
 
762
        g_return_if_fail(text != NULL);
 
763
 
 
764
        va_start(args, first_wildcard);
 
765
 
 
766
        key = first_wildcard;
 
767
        value = va_arg(args, gchar*);
 
768
 
 
769
        while (key != NULL)
 
770
        {
 
771
                utils_string_replace_all(text, key, value);
 
772
 
 
773
                key = va_arg(args, gchar*);
 
774
                if (key == NULL || text == NULL)
 
775
                        break;
 
776
                value = va_arg(args, gchar*);
 
777
        }
 
778
        va_end(args);
 
779
 
 
780
        replace_static_values(text);
 
781
}
 
782
 
 
783
 
 
784
static void templates_replace_default_dates(GString *text)
 
785
{
 
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);
 
789
 
 
790
        g_return_if_fail(text != NULL);
 
791
 
 
792
        templates_replace_valist(text,
 
793
                "{year}", year,
 
794
                "{date}", date,
 
795
                "{datetime}", datetime,
 
796
                NULL);
 
797
 
 
798
        utils_free_pointers(3, year, date, datetime, NULL);
 
799
}
 
800
 
 
801
 
 
802
static gchar *run_command(const gchar *command, const gchar *file_name,
 
803
                                                  const gchar *file_type, const gchar *func_name)
 
804
{
 
805
        gchar *result = NULL;
 
806
        gchar **argv;
 
807
 
 
808
        if (g_shell_parse_argv(command, NULL, &argv, NULL))
 
809
        {
 
810
                GError *error = NULL;
 
811
                gchar **env;
 
812
 
 
813
                file_name = (file_name != NULL) ? file_name : "";
 
814
                file_type = (file_type != NULL) ? file_type : "";
 
815
                func_name = (func_name != NULL) ? func_name : "";
 
816
 
 
817
                env = utils_copy_environment(NULL,
 
818
                        "GEANY_FILENAME", file_name,
 
819
                        "GEANY_FILETYPE", file_type,
 
820
                        "GEANY_FUNCNAME", func_name,
 
821
                        NULL);
 
822
                if (! utils_spawn_sync(NULL, argv, env, G_SPAWN_SEARCH_PATH,
 
823
                                NULL, NULL, &result, NULL, NULL, &error))
 
824
                {
 
825
                        g_warning("templates_replace_command: %s", error->message);
 
826
                        g_error_free(error);
 
827
                        return NULL;
 
828
                }
 
829
                g_strfreev(argv);
 
830
                g_strfreev(env);
 
831
        }
 
832
        return result;
 
833
}
 
834
 
 
835
 
 
836
static void templates_replace_command(GString *text, const gchar *file_name,
 
837
                                                           const gchar *file_type, const gchar *func_name)
 
838
{
 
839
        gchar *match = NULL;
 
840
        gchar *wildcard = NULL;
 
841
        gchar *cmd;
 
842
        gchar *result;
 
843
 
 
844
        g_return_if_fail(text != NULL);
 
845
 
 
846
        while ((match = strstr(text->str, "{command:")) != NULL)
 
847
        {
 
848
                cmd = match;
 
849
                while (*match != '}' && *match != '\0')
 
850
                        match++;
 
851
 
 
852
                wildcard = g_strndup(cmd, match - cmd + 1);
 
853
                cmd = g_strndup(wildcard + 9, strlen(wildcard) - 10);
 
854
 
 
855
                result = run_command(cmd, file_name, file_type, func_name);
 
856
                if (result != NULL)
 
857
                {
 
858
                        utils_string_replace_first(text, wildcard, result);
 
859
                        g_free(result);
 
860
                }
 
861
                else
 
862
                        utils_string_replace_first(text, wildcard, "");
 
863
 
 
864
                g_free(wildcard);
 
865
                g_free(cmd);
 
866
        }
 
867
}