Kaydet (Commit) f39df400 authored tarafından Nick Treleaven's avatar Nick Treleaven

Add support for generating global tags files for non-C-like

filetypes.


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@1480 ea778897-0a13-0410-b9d1-a72fbfd435f5
üst 3489b63b
2007-04-26 Nick Treleaven <nick.treleaven@btinternet.com>
* tagmanager/tm_source_file.c, tagmanager/include/tm_source_file.h:
Add tm_source_file_get_lang_name() as a wrapper for getLanguageName()
in parse.c.
* src/main.c, src/symbols.c, tagmanager/tm_workspace.c,
tagmanager/include/tm_workspace.h:
Add support for generating global tags files for non-C-like
filetypes.
2007-04-25 Nick Treleaven <nick.treleaven@btinternet.com> 2007-04-25 Nick Treleaven <nick.treleaven@btinternet.com>
* src/filetypes.c, src/filetypes.h, src/main.c: * src/filetypes.c, src/filetypes.h, src/main.c:
......
...@@ -467,6 +467,8 @@ static void parse_command_line_options(gint *argc, gchar ***argv) ...@@ -467,6 +467,8 @@ static void parse_command_line_options(gint *argc, gchar ***argv)
{ {
gboolean ret; gboolean ret;
filetypes_init_types();
configuration_read_filetype_extensions(); // needed for *.lang.tags filetype matching
ret = symbols_generate_global_tags(*argc, *argv); ret = symbols_generate_global_tags(*argc, *argv);
exit(ret); exit(ret);
} }
......
...@@ -704,10 +704,33 @@ gboolean symbols_recreate_tag_list(gint idx) ...@@ -704,10 +704,33 @@ gboolean symbols_recreate_tag_list(gint idx)
} }
/* Detects a global tags filetype from the *.lang.* language extension.
* Returns NULL if there was no matching TM language. */
static filetype *detect_global_tags_filetype(const gchar *utf8_filename)
{
gchar *tags_ext;
gchar *shortname = g_strdup(utf8_filename);
filetype *ft = NULL;
tags_ext = strstr(shortname, ".tags");
if (tags_ext)
{
*tags_ext = '\0'; // remove .tags extension
ft = filetypes_detect_from_filename(shortname);
}
g_free(shortname);
if (filetypes[FILETYPE_ID(ft)]->lang < 0)
return NULL;
return ft;
}
/* Adapted from anjuta-2.0.2/global-tags/tm_global_tags.c, thanks. /* Adapted from anjuta-2.0.2/global-tags/tm_global_tags.c, thanks.
* Needs full path and \" quoting characters around filenames. * Needs full paths for filenames, except for C/C++ tag files, when CFLAGS includes
* the relevant path.
* Example: * Example:
* geany -g tagsfile \"/home/nmt/svn/geany/src/d*.h\" */ * CFLAGS=-I/home/user/libname-1.x geany -g libname.d.tags libname.h */
int symbols_generate_global_tags(int argc, char **argv) int symbols_generate_global_tags(int argc, char **argv)
{ {
/* -E pre-process, -dD output user macros, -p prof info (?), /* -E pre-process, -dD output user macros, -p prof info (?),
...@@ -719,15 +742,34 @@ int symbols_generate_global_tags(int argc, char **argv) ...@@ -719,15 +742,34 @@ int symbols_generate_global_tags(int argc, char **argv)
/* Create global taglist */ /* Create global taglist */
int status; int status;
char *command; char *command;
command = g_strdup_printf("%s %s", pre_process, const char *tags_file = argv[1];
NVL(getenv("CFLAGS"), "")); char *utf8_fname;
//printf(">%s<\n", command); filetype *ft;
utf8_fname = utils_get_utf8_from_locale(tags_file);
ft = detect_global_tags_filetype(utf8_fname);
g_free(utf8_fname);
if (ft == NULL)
{
fprintf(stderr, "Unknown filetype extension for \"%s\".\n", tags_file);
return 1;
}
if (ft->lang == 0 || ft->lang == 1) /* C/C++ */
command = g_strdup_printf("%s %s", pre_process, NVL(getenv("CFLAGS"), ""));
else
command = NULL; // don't preprocess
geany_debug("Generating %s tags file.", ft->name);
status = tm_workspace_create_global_tags(command, status = tm_workspace_create_global_tags(command,
(const char **) (argv + 2), (const char **) (argv + 2),
argc - 2, argv[1]); argc - 2, tags_file, ft->lang);
g_free(command); g_free(command);
if (!status) if (! status)
{
fprintf(stderr, "Failed to create tags file.\n");
return 1; return 1;
}
} }
else else
{ {
...@@ -741,34 +783,6 @@ int symbols_generate_global_tags(int argc, char **argv) ...@@ -741,34 +783,6 @@ int symbols_generate_global_tags(int argc, char **argv)
} }
// fname should be in locale encoding
static gboolean load_tags_filename(const gchar *fname)
{
gchar *tags_ext;
gchar *shortname = g_strdup(fname);
gboolean ret = FALSE;
tags_ext = strstr(shortname, ".tags");
if (tags_ext)
{
gchar *utf8_shortname;
filetype *ft;
*tags_ext = '\0'; // remove .tags extension
utf8_shortname = utils_get_utf8_from_locale(shortname);
ft = filetypes_detect_from_filename(utf8_shortname);
g_free(utf8_shortname);
if (ft)
{
ret = tm_workspace_load_global_tags(fname, ft->lang);
}
}
g_free(shortname);
return ret;
}
void symbols_show_load_tags_dialog() void symbols_show_load_tags_dialog()
{ {
GtkWidget *dialog; GtkWidget *dialog;
...@@ -793,13 +807,16 @@ void symbols_show_load_tags_dialog() ...@@ -793,13 +807,16 @@ void symbols_show_load_tags_dialog()
{ {
gchar *fname = item->data; gchar *fname = item->data;
gchar *utf8_fname; gchar *utf8_fname;
gboolean ok; filetype *ft;
ok = load_tags_filename(fname);
utf8_fname = utils_get_utf8_from_locale(fname); utf8_fname = utils_get_utf8_from_locale(fname);
msgwin_status_add(ok ? _("Loaded tags file '%s'.") : ft = detect_global_tags_filetype(utf8_fname);
_("Could not load tags file '%s'."), utf8_fname);
if (ft != NULL && tm_workspace_load_global_tags(fname, ft->lang))
msgwin_status_add(_("Loaded %s tags file '%s'."), ft->name, utf8_fname);
else
msgwin_status_add(_("Could not load tags file '%s'."), utf8_fname);
g_free(utf8_fname); g_free(utf8_fname);
g_free(fname); g_free(fname);
} }
......
...@@ -100,10 +100,11 @@ gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode); ...@@ -100,10 +100,11 @@ gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode);
\param includes Include files to process. Wildcards such as '/usr/include/a*.h' \param includes Include files to process. Wildcards such as '/usr/include/a*.h'
are allowed. are allowed.
\param tags_file The file where the tags will be stored. \param tags_file The file where the tags will be stored.
\param lang The language to use for the tags file.
\return TRUE on success, FALSE on failure. \return TRUE on success, FALSE on failure.
*/ */
gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes
, int includes_count, const char *tags_file); , int includes_count, const char *tags_file, int lang);
/*! Recreates the tag array of the workspace by collecting the tags of /*! Recreates the tag array of the workspace by collecting the tags of
all member work objects. You shouldn't have to call this directly since all member work objects. You shouldn't have to call this directly since
......
...@@ -187,8 +187,68 @@ static void tm_move_entries_to_g_list(gpointer key, gpointer value, gpointer use ...@@ -187,8 +187,68 @@ static void tm_move_entries_to_g_list(gpointer key, gpointer value, gpointer use
*pp_list = g_list_prepend(*pp_list, value); *pp_list = g_list_prepend(*pp_list, value);
} }
static void write_includes_file(FILE *fp, GList *includes_files)
{
GList *node;
node = includes_files;
while (node)
{
char *str = g_strdup_printf("#include \"%s\"\n", (char*)node->data);
int str_len = strlen(str);
fwrite(str, str_len, 1, fp);
free(str);
node = g_list_next (node);
}
}
static void append_to_temp_file(FILE *fp, GList *file_list)
{
GList *node;
node = file_list;
while (node)
{
const char *fname = node->data;
char *contents;
size_t length;
GError *err = NULL;
if (! g_file_get_contents(fname, &contents, &length, &err))
{
fprintf(stderr, "Unable to read file: %s\n", err->message);
g_error_free(err);
}
else
{
fwrite(contents, length, 1, fp);
fwrite("\n", 1, 1, fp); // in case file doesn't end in newline (e.g. windows).
g_free(contents);
}
node = g_list_next (node);
}
}
static gint get_global_tag_type_mask(gint lang)
{
switch (lang)
{
case 0:
case 1:
// C/C++
return tm_tag_class_t | tm_tag_typedef_t | tm_tag_enum_t | tm_tag_enumerator_t |
tm_tag_prototype_t |
tm_tag_function_t | tm_tag_method_t | // for inline functions
tm_tag_macro_t | tm_tag_macro_with_arg_t;
default:
return tm_tag_max_t;
}
}
gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes
, int includes_count, const char *tags_file) , int includes_count, const char *tags_file, int lang)
{ {
#ifdef HAVE_GLOB_H #ifdef HAVE_GLOB_H
glob_t globbuf; glob_t globbuf;
...@@ -202,7 +262,6 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i ...@@ -202,7 +262,6 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
GPtrArray *tags_array; GPtrArray *tags_array;
GHashTable *includes_files_hash; GHashTable *includes_files_hash;
GList *includes_files = NULL; GList *includes_files = NULL;
GList *node;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
char *temp_file = g_strdup_printf("%s_%d_%ld_1.cpp", P_tmpdir, getpid(), time(NULL)); char *temp_file = g_strdup_printf("%s_%d_%ld_1.cpp", P_tmpdir, getpid(), time(NULL));
char *temp_file2 = g_strdup_printf("%s_%d_%ld_2.cpp", P_tmpdir, getpid(), time(NULL)); char *temp_file2 = g_strdup_printf("%s_%d_%ld_2.cpp", P_tmpdir, getpid(), time(NULL));
...@@ -259,6 +318,7 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i ...@@ -259,6 +318,7 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
} }
else else
#endif #endif
// no glob support or globbing not wanted
for(idx_inc = 0; idx_inc < includes_count; idx_inc++) for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
{ {
if (!g_hash_table_lookup(includes_files_hash, if (!g_hash_table_lookup(includes_files_hash,
...@@ -279,16 +339,10 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i ...@@ -279,16 +339,10 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
#ifdef TM_DEBUG #ifdef TM_DEBUG
g_message ("writing out files to %s\n", temp_file); g_message ("writing out files to %s\n", temp_file);
#endif #endif
node = includes_files; if (pre_process != NULL)
while (node) write_includes_file(fp, includes_files);
{ else
char *str = g_strdup_printf("#include \"%s\"\n", (char*)node->data); append_to_temp_file(fp, includes_files);
int str_len = strlen(str);
fwrite(str, str_len, 1, fp);
free(str);
node = g_list_next (node);
}
g_list_free (includes_files); g_list_free (includes_files);
g_hash_table_destroy(includes_files_hash); g_hash_table_destroy(includes_files_hash);
...@@ -302,18 +356,26 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i ...@@ -302,18 +356,26 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
* following these lines are incorrectly parsed. The real fix should, * following these lines are incorrectly parsed. The real fix should,
* of course be in tagmanager (c) parser. This is just a temporary fix. * of course be in tagmanager (c) parser. This is just a temporary fix.
*/ */
command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s", if (pre_process != NULL)
{
command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s",
pre_process, temp_file, temp_file2); pre_process, temp_file, temp_file2);
#ifdef TM_DEBUG #ifdef TM_DEBUG
g_message("Executing: %s", command); g_message("Executing: %s", command);
#endif #endif
system(command);
system(command); g_free(command);
g_free(command); unlink(temp_file);
unlink(temp_file); g_free(temp_file);
g_free(temp_file); }
source_file = tm_source_file_new(temp_file2, TRUE, NULL); else
{
// no pre-processing needed, so temp_file2 = temp_file
g_free(temp_file2);
temp_file2 = temp_file;
temp_file = NULL;
}
source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang));
if (NULL == source_file) if (NULL == source_file)
{ {
unlink(temp_file2); unlink(temp_file2);
...@@ -326,10 +388,7 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i ...@@ -326,10 +388,7 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
tm_source_file_free(source_file); tm_source_file_free(source_file);
return FALSE; return FALSE;
} }
tags_array = tm_tags_extract(source_file->tags_array, tm_tag_class_t | tags_array = tm_tags_extract(source_file->tags_array, get_global_tag_type_mask(lang));
tm_tag_typedef_t | tm_tag_enum_t | tm_tag_enumerator_t |
tm_tag_prototype_t | tm_tag_function_t | tm_tag_method_t | // for inline functions
tm_tag_macro_t | tm_tag_macro_with_arg_t);
if ((NULL == tags_array) || (0 == tags_array->len)) if ((NULL == tags_array) || (0 == tags_array->len))
{ {
if (tags_array) if (tags_array)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment