/* * templates.c - this file is part of Geany, a fast and lightweight IDE * * Copyright 2005-2007 Enrico Troeger * Copyright 2006-2007 Nick Treleaven * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ #include #include #include "geany.h" #include "templates.h" #include "support.h" #include "utils.h" #include "document.h" // default templates, only for initial tempate file creation on first start of Geany static const gchar templates_gpl_notice[] = "\ This program is free software; you can redistribute it and/or modify\n\ it under the terms of the GNU General Public License as published by\n\ the Free Software Foundation; either version 2 of the License, or\n\ (at your option) any later version.\n\ \n\ This program is distributed in the hope that it will be useful,\n\ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ GNU General Public License for more details.\n\ \n\ You should have received a copy of the GNU General Public License\n\ along with this program; if not, write to the Free Software\n\ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\ "; static const gchar templates_function_description[] = "\ \n\ name: {functionname}\n\ @param\n\ @return\n\ "; static const gchar templates_multiline[] = "\ \n\ \n\ "; static const gchar templates_fileheader[] = "\ {filename}\n\ \n\ Copyright {year} {developer} <{mail}>\n\ \n\ {gpl}\ "; static const gchar templates_changelog[] = "\ {date} {developer} <{mail}>\n\ \n\ * \n\n\n"; static const gchar templates_filetype_none[] = ""; static const gchar templates_filetype_c[] = "\n\ #include \n\ \n\ int main(int argc, char** argv)\n\ {\n\ \n\ return 0;\n\ }\n\ "; static const gchar templates_filetype_cpp[] = "\n\ #include \n\ \n\ int main(int argc, char** argv)\n\ {\n\ \n\ return 0;\n\ }\n\ "; static const gchar templates_filetype_d[] = "\n\ import std.stdio;\n\ \n\ int main(char[][] args)\n\ {\n\ \n\ return 0;\n\ }\n\ "; static const gchar templates_filetype_php[] = "\n\ \n\ \n\ \n\ {untitled}\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ "; static const gchar templates_filetype_html[] = "\n\ \n\ \n\ \n\ {untitled}\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ "; static const gchar templates_filetype_pascal[] = "\n\ program {untitled};\n\ \n\ uses crt;\n\ var i : byte;\n\ \n\ BEGIN\n\ \n\ \n\ END.\n\ "; static const gchar templates_filetype_java[] = "\n\ public class {untitled} {\n\ \n\ public static void main (String args[]) {\ \n\ \n\ }\n\ }\n\ "; static const gchar templates_filetype_ruby[] = "\n\ \n\ class StdClass\n\ def initialize\n\ \n\ end\n\ end\n\ \n\ x = StdClass.new\n\ "; static gchar *templates[GEANY_MAX_TEMPLATES]; // some simple macros to reduce code size and make the code readable #define TEMPLATES_GET_FILENAME(x) g_strconcat(app->configdir, G_DIR_SEPARATOR_S, x, NULL) #define TEMPLATES_CREATE_FILE(x, y) if (! g_file_test(x, G_FILE_TEST_EXISTS)) utils_write_file(x, y) #define TEMPLATES_READ_FILE(x, y) g_file_get_contents(x, y, NULL, NULL); // prototype, because this function should never be used outside of templates.c static gchar *templates_replace_all(gchar *source, gchar *year, gchar *date); void templates_init(void) { gchar *template_filename_fileheader = TEMPLATES_GET_FILENAME("template.fileheader"); gchar *template_filename_gpl = TEMPLATES_GET_FILENAME("template.gpl"); gchar *template_filename_function = TEMPLATES_GET_FILENAME("template.function"); gchar *template_filename_changelog = TEMPLATES_GET_FILENAME("template.changelog"); gchar *template_filename_filetype_none = TEMPLATES_GET_FILENAME("template.filetype.none"); gchar *template_filename_filetype_c = TEMPLATES_GET_FILENAME("template.filetype.c"); gchar *template_filename_filetype_cpp = TEMPLATES_GET_FILENAME("template.filetype.cpp"); gchar *template_filename_filetype_d = TEMPLATES_GET_FILENAME("template.filetype.d"); gchar *template_filename_filetype_java = TEMPLATES_GET_FILENAME("template.filetype.java"); gchar *template_filename_filetype_pascal = TEMPLATES_GET_FILENAME("template.filetype.pascal"); gchar *template_filename_filetype_php = TEMPLATES_GET_FILENAME("template.filetype.php"); gchar *template_filename_filetype_html = TEMPLATES_GET_FILENAME("template.filetype.html"); gchar *template_filename_filetype_ruby = TEMPLATES_GET_FILENAME("template.filetype.ruby"); time_t tp = time(NULL); const struct tm *tm = localtime(&tp); gchar *year = g_malloc0(5); gchar *date = utils_get_date(); strftime(year, 5, "%Y", tm); // create the template files in the configuration directory, if they don't exist TEMPLATES_CREATE_FILE(template_filename_fileheader, templates_fileheader); TEMPLATES_CREATE_FILE(template_filename_gpl, templates_gpl_notice); TEMPLATES_CREATE_FILE(template_filename_function, templates_function_description); TEMPLATES_CREATE_FILE(template_filename_changelog, templates_changelog); TEMPLATES_CREATE_FILE(template_filename_filetype_none, templates_filetype_none); TEMPLATES_CREATE_FILE(template_filename_filetype_c, templates_filetype_c); TEMPLATES_CREATE_FILE(template_filename_filetype_cpp, templates_filetype_cpp); TEMPLATES_CREATE_FILE(template_filename_filetype_d, templates_filetype_d); TEMPLATES_CREATE_FILE(template_filename_filetype_java, templates_filetype_java); TEMPLATES_CREATE_FILE(template_filename_filetype_pascal, templates_filetype_pascal); TEMPLATES_CREATE_FILE(template_filename_filetype_php, templates_filetype_php); TEMPLATES_CREATE_FILE(template_filename_filetype_html, templates_filetype_html); TEMPLATES_CREATE_FILE(template_filename_filetype_ruby, templates_filetype_ruby); // read the contents TEMPLATES_READ_FILE(template_filename_fileheader, &templates[GEANY_TEMPLATE_FILEHEADER]); templates[GEANY_TEMPLATE_FILEHEADER] = templates_replace_all(templates[GEANY_TEMPLATE_FILEHEADER], year, date); TEMPLATES_READ_FILE(template_filename_gpl, &templates[GEANY_TEMPLATE_GPL]); //templates[GEANY_TEMPLATE_GPL] = templates_replace_all(templates[GEANY_TEMPLATE_GPL], year, date); TEMPLATES_READ_FILE(template_filename_function, &templates[GEANY_TEMPLATE_FUNCTION]); templates[GEANY_TEMPLATE_FUNCTION] = templates_replace_all(templates[GEANY_TEMPLATE_FUNCTION], year, date); TEMPLATES_READ_FILE(template_filename_changelog, &templates[GEANY_TEMPLATE_CHANGELOG]); templates[GEANY_TEMPLATE_CHANGELOG] = templates_replace_all(templates[GEANY_TEMPLATE_CHANGELOG], year, date); TEMPLATES_READ_FILE(template_filename_filetype_none, &templates[GEANY_TEMPLATE_FILETYPE_NONE]); templates[GEANY_TEMPLATE_FILETYPE_NONE] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_NONE], year, date); TEMPLATES_READ_FILE(template_filename_filetype_c, &templates[GEANY_TEMPLATE_FILETYPE_C]); templates[GEANY_TEMPLATE_FILETYPE_C] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_C], year, date); TEMPLATES_READ_FILE(template_filename_filetype_d, &templates[GEANY_TEMPLATE_FILETYPE_D]); templates[GEANY_TEMPLATE_FILETYPE_D] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_D], year, date); TEMPLATES_READ_FILE(template_filename_filetype_cpp, &templates[GEANY_TEMPLATE_FILETYPE_CPP]); templates[GEANY_TEMPLATE_FILETYPE_CPP] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_CPP], year, date); TEMPLATES_READ_FILE(template_filename_filetype_java, &templates[GEANY_TEMPLATE_FILETYPE_JAVA]); templates[GEANY_TEMPLATE_FILETYPE_JAVA] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_JAVA], year, date); TEMPLATES_READ_FILE(template_filename_filetype_pascal, &templates[GEANY_TEMPLATE_FILETYPE_PASCAL]); templates[GEANY_TEMPLATE_FILETYPE_PASCAL] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_PASCAL], year, date); TEMPLATES_READ_FILE(template_filename_filetype_php, &templates[GEANY_TEMPLATE_FILETYPE_PHP]); templates[GEANY_TEMPLATE_FILETYPE_PHP] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_PHP], year, date); TEMPLATES_READ_FILE(template_filename_filetype_html, &templates[GEANY_TEMPLATE_FILETYPE_HTML]); templates[GEANY_TEMPLATE_FILETYPE_HTML] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_HTML], year, date); TEMPLATES_READ_FILE(template_filename_filetype_ruby, &templates[GEANY_TEMPLATE_FILETYPE_RUBY]); templates[GEANY_TEMPLATE_FILETYPE_RUBY] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_RUBY], year, date); // free the whole stuff g_free(date); g_free(year); g_free(template_filename_fileheader); g_free(template_filename_gpl); g_free(template_filename_function); g_free(template_filename_changelog); g_free(template_filename_filetype_none); g_free(template_filename_filetype_c); g_free(template_filename_filetype_cpp); g_free(template_filename_filetype_d); g_free(template_filename_filetype_java); g_free(template_filename_filetype_php); g_free(template_filename_filetype_html); g_free(template_filename_filetype_pascal); g_free(template_filename_filetype_ruby); } /* indent is used to make some whitespace between comment char and real start of the line * e.g. indent = 8 prints " * here comes the text of the line" * indent is meant to be the whole amount of characters before the real line content follows, i.e. * 6 characters are filled with whitespace when the comment characters include " *" */ static gchar *make_comment_block(const gchar *comment_text, gint filetype_idx, gint indent) { gchar *frame_start = ""; // to add before comment_text gchar *frame_end = ""; // to add after comment_text gchar *line_prefix; // to add before every line in comment_text gchar *result; gchar *tmp; gchar *prefix; gchar **lines; gint i; /// TODO the following switch could be replaced by some intelligent code which reads /// frame_start, frame_end and line_prefix from the filetype definition files switch (filetype_idx) { case GEANY_FILETYPES_HTML: case GEANY_FILETYPES_XML: case GEANY_FILETYPES_DOCBOOK: { frame_start = "\n"; line_prefix = ""; break; } case GEANY_FILETYPES_PYTHON: case GEANY_FILETYPES_RUBY: case GEANY_FILETYPES_SH: case GEANY_FILETYPES_MAKE: case GEANY_FILETYPES_PERL: case GEANY_FILETYPES_DIFF: case GEANY_FILETYPES_TCL: case GEANY_FILETYPES_OMS: case GEANY_FILETYPES_CONF: { line_prefix = "#"; break; } case GEANY_FILETYPES_LATEX: { line_prefix = "%"; break; } case GEANY_FILETYPES_VHDL: { line_prefix = "--"; break; } case GEANY_FILETYPES_FORTRAN: { line_prefix = "c"; break; } case GEANY_FILETYPES_ASM: { line_prefix = ";"; break; } case GEANY_FILETYPES_PASCAL: { frame_start = "{\n"; frame_end = "}\n"; line_prefix = ""; break; } case GEANY_FILETYPES_PHP: { frame_start = "\n"; line_prefix = " *"; break; } case GEANY_FILETYPES_CAML: { frame_start = "(*\n"; frame_end = " *)\n"; line_prefix = " *"; break; } case GEANY_FILETYPES_ALL: { line_prefix = ""; break; } default: // guess /* */ is appropriate { frame_start = "/*\n"; frame_end = " */\n"; line_prefix = " *"; } } // construct the real prefix with given amount of whitespace i = (indent > strlen(line_prefix)) ? (indent - strlen(line_prefix)) : strlen(line_prefix); tmp = g_strnfill(i, ' '); prefix = g_strconcat(line_prefix, tmp, NULL); g_free(tmp); // add line_prefix to every line of comment_text lines = g_strsplit(comment_text, "\n", -1); for (i = 0; i < (g_strv_length(lines) - 1); i++) { tmp = lines[i]; lines[i] = g_strconcat(prefix, tmp, NULL); g_free(tmp); } tmp = g_strjoinv("\n", lines); // add frame_start and frame_end result = g_strconcat(frame_start, tmp, frame_end, NULL); g_free(prefix); g_free(tmp); g_strfreev(lines); return result; } gchar *templates_get_template_licence(gint filetype_idx) { //if (licence_type != GEANY_TEMPLATE_GPL) //return NULL; return make_comment_block(templates[GEANY_TEMPLATE_GPL], filetype_idx, 8); } static gchar *get_file_header(filetype *ft, const gchar *fname) { gchar *template = g_strdup(templates[GEANY_TEMPLATE_FILEHEADER]); gchar *shortname; gchar *result; gchar *date = utils_get_date_time(); if (fname == NULL) { if (FILETYPE_ID(ft) == GEANY_FILETYPES_ALL) shortname = g_strdup(GEANY_STRING_UNTITLED); else shortname = g_strconcat(GEANY_STRING_UNTITLED, ".", ft->extension, NULL); } else shortname = g_path_get_basename(fname); template = utils_str_replace(template, "{filename}", shortname); template = utils_str_replace(template, "{gpl}", templates[GEANY_TEMPLATE_GPL]); template = utils_str_replace(template, "{datetime}", date); result = make_comment_block(template, FILETYPE_ID(ft), 8); g_free(template); g_free(shortname); g_free(date); return result; } gchar *templates_get_template_fileheader(gint idx) { gchar *fname; filetype *ft; g_return_val_if_fail(DOC_IDX_VALID(idx), NULL); ft = doc_list[idx].file_type; fname = doc_list[idx].file_name; return get_file_header(ft, fname); } static gchar *get_file_template(filetype *ft) { switch (FILETYPE_ID(ft)) { case GEANY_FILETYPES_ALL: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_NONE); break; case GEANY_FILETYPES_C: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_C); break; case GEANY_FILETYPES_CPP: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_CPP); break; case GEANY_FILETYPES_PHP: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_PHP); break; case GEANY_FILETYPES_JAVA: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_JAVA); break; case GEANY_FILETYPES_PASCAL: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_PASCAL); break; case GEANY_FILETYPES_RUBY: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_RUBY); break; case GEANY_FILETYPES_D: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_D); break; case GEANY_FILETYPES_HTML: return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_HTML); break; default: return NULL; } } gchar *templates_get_template_new_file(filetype *ft) { gchar *template = NULL; gchar *ft_template = NULL; gchar *file_header = NULL; if (FILETYPE_ID(ft) == GEANY_FILETYPES_ALL) return get_file_template(ft); file_header = get_file_header(ft, NULL); // file template only used for new files ft_template = get_file_template(ft); template = g_strconcat(file_header, "\n", ft_template, NULL); g_free(ft_template); g_free(file_header); return template; } gchar *templates_get_template_generic(gint template) { return g_strdup(templates[template]); } gchar *templates_get_template_function(gint filetype_idx, const gchar *func_name) { gchar *template = g_strdup(templates[GEANY_TEMPLATE_FUNCTION]); gchar *date = utils_get_date(); gchar *datetime = utils_get_date_time(); gchar *result; template = utils_str_replace(template, "{date}", date); template = utils_str_replace(template, "{datetime}", datetime); template = utils_str_replace(template, "{functionname}", (func_name) ? func_name : ""); result = make_comment_block(template, filetype_idx, 3); g_free(template); g_free(date); g_free(datetime); return result; } gchar *templates_get_template_changelog(void) { gchar *date = utils_get_date_time(); gchar *result = g_strdup(templates[GEANY_TEMPLATE_CHANGELOG]); result = utils_str_replace(result, "{date}", date); g_free(date); return result; } void templates_free_templates(void) { gint i; for (i = 0; i < GEANY_MAX_TEMPLATES; i++) { g_free(templates[i]); } } static gchar *templates_replace_all(gchar *text, gchar *year, gchar *date) { text = utils_str_replace(text, "{year}", year); text = utils_str_replace(text, "{date}", date); text = utils_str_replace(text, "{version}", app->pref_template_version); text = utils_str_replace(text, "{initial}", app->pref_template_initial); text = utils_str_replace(text, "{developer}", app->pref_template_developer); text = utils_str_replace(text, "{mail}", app->pref_template_mail); text = utils_str_replace(text, "{company}", app->pref_template_company); text = utils_str_replace(text, "{untitled}", GEANY_STRING_UNTITLED); text = utils_str_replace(text, "{geanyversion}", "Geany " VERSION); return text; }