Merge PR#356 from 'b4n/techee/tm'

Huge TagManager improvements
This commit is contained in:
Colomban Wendling 2014-11-08 19:37:20 +01:00
commit 8c77accfd0
35 changed files with 1593 additions and 2513 deletions

View File

@ -778,8 +778,6 @@ INPUT = @top_srcdir@/src/ \
@top_srcdir@/plugins/geanyfunctions.h \
@top_srcdir@/tagmanager/src/tm_source_file.c \
@top_srcdir@/tagmanager/src/tm_source_file.h \
@top_srcdir@/tagmanager/src/tm_work_object.c \
@top_srcdir@/tagmanager/src/tm_work_object.h \
@top_srcdir@/tagmanager/src/tm_workspace.c \
@top_srcdir@/tagmanager/src/tm_workspace.h

View File

@ -98,7 +98,6 @@ doxygen_sources = \
$(top_srcdir)/plugins/geanyplugin.h \
$(top_srcdir)/plugins/geanyfunctions.h \
$(top_srcdir)/tagmanager/src/tm_source_file.[ch] \
$(top_srcdir)/tagmanager/src/tm_work_object.[ch] \
$(top_srcdir)/tagmanager/src/tm_workspace.[ch]
Doxyfile.stamp: Doxyfile $(doxygen_sources)

View File

@ -346,14 +346,16 @@
geany_functions->p_tm->tm_get_real_path
#define tm_source_file_new \
geany_functions->p_tm->tm_source_file_new
#define tm_workspace_add_object \
geany_functions->p_tm->tm_workspace_add_object
#define tm_source_file_update \
geany_functions->p_tm->tm_source_file_update
#define tm_work_object_free \
geany_functions->p_tm->tm_work_object_free
#define tm_workspace_remove_object \
geany_functions->p_tm->tm_workspace_remove_object
#define tm_source_file_free \
geany_functions->p_tm->tm_source_file_free
#define tm_workspace_add_source_file \
geany_functions->p_tm->tm_workspace_add_source_file
#define tm_workspace_remove_source_file \
geany_functions->p_tm->tm_workspace_remove_source_file
#define tm_workspace_add_source_files \
geany_functions->p_tm->tm_workspace_add_source_files
#define tm_workspace_remove_source_files \
geany_functions->p_tm->tm_workspace_remove_source_files
#define search_show_find_in_files_dialog \
geany_functions->p_search->search_show_find_in_files_dialog
#define highlighting_get_style \

View File

@ -501,9 +501,13 @@ static gboolean handle_save_as(const gchar *utf8_filename, gboolean rename_file)
{
document_rename_file(doc, utf8_filename);
}
/* create a new tm_source_file object otherwise tagmanager won't work correctly */
tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
doc->tm_file = NULL;
if (doc->tm_file)
{
/* create a new tm_source_file object otherwise tagmanager won't work correctly */
tm_workspace_remove_source_file(doc->tm_file);
tm_source_file_free(doc->tm_file);
doc->tm_file = NULL;
}
}
success = document_save_file_as(doc, utf8_filename);

View File

@ -140,7 +140,7 @@ static GtkWidget* document_show_message(GeanyDocument *doc, GtkMessageType msgty
* string returned by @c tm_get_real_path().
*
* @return The matching document, or @c NULL.
* @note This is only really useful when passing a @c TMWorkObject::file_name.
* @note This is only really useful when passing a @c TMSourceFile::file_name.
* @see GeanyDocument::real_path.
* @see document_find_by_filename().
*
@ -714,7 +714,11 @@ static gboolean remove_page(guint page_num)
g_free(doc->priv->saved_encoding.encoding);
g_free(doc->file_name);
g_free(doc->real_path);
tm_workspace_remove_object(doc->tm_file, TRUE, !main_status.quitting);
if (doc->tm_file)
{
tm_workspace_remove_source_file(doc->tm_file);
tm_source_file_free(doc->tm_file);
}
if (doc->priv->tag_tree)
gtk_widget_destroy(doc->priv->tag_tree);
@ -2483,17 +2487,14 @@ void document_update_tags(GeanyDocument *doc)
/* lookup the name rather than using filetype name to support custom filetypes */
name = tm_source_file_get_lang_name(doc->file_type->lang);
doc->tm_file = tm_source_file_new(locale_filename, FALSE, name);
doc->tm_file = tm_source_file_new(locale_filename, name);
g_free(locale_filename);
if (doc->tm_file && !tm_workspace_add_object(doc->tm_file))
{
tm_work_object_free(doc->tm_file);
doc->tm_file = NULL;
}
if (doc->tm_file)
tm_workspace_add_source_file_noupdate(doc->tm_file);
}
/* early out if there's no work object and we couldn't create one */
/* early out if there's no tm source file and we couldn't create one */
if (doc->tm_file == NULL)
{
/* We must call sidebar_update_tag_list() before returning,
@ -2503,20 +2504,11 @@ void document_update_tags(GeanyDocument *doc)
return;
}
len = sci_get_length(doc->editor->sci);
/* tm_source_file_buffer_update() below don't support 0-length data,
* so just empty the tags array and leave */
if (len < 1)
{
tm_tags_array_free(doc->tm_file->tags_array, FALSE);
sidebar_update_tag_list(doc, FALSE);
return;
}
/* Parse Scintilla's buffer directly using TagManager
* Note: this buffer *MUST NOT* be modified */
len = sci_get_length(doc->editor->sci);
buffer_ptr = (guchar *) scintilla_send_message(doc->editor->sci, SCI_GETCHARACTERPOINTER, 0, 0);
tm_source_file_buffer_update(doc->tm_file, buffer_ptr, len, TRUE);
tm_workspace_update_source_file_buffer(doc->tm_file, buffer_ptr, len);
sidebar_update_tag_list(doc, TRUE);
document_highlight_tags(doc);
@ -2555,13 +2547,12 @@ void document_highlight_tags(GeanyDocument *doc)
default:
return; /* early out if type keywords are not supported */
}
if (!app->tm_workspace->work_object.tags_array)
if (!app->tm_workspace->tags_array)
return;
/* get any type keywords and tell scintilla about them
* this will cause the type keywords to be colourized in scintilla */
keywords_str = symbols_find_tags_as_string(app->tm_workspace->work_object.tags_array,
TM_GLOBAL_TYPE_MASK, doc->file_type->lang);
keywords_str = symbols_find_typenames_as_string(doc->file_type->lang, FALSE);
if (keywords_str)
{
keywords = g_string_free(keywords_str, FALSE);
@ -2617,7 +2608,8 @@ static void document_load_config(GeanyDocument *doc, GeanyFiletype *type,
/* delete tm file object to force creation of a new one */
if (doc->tm_file != NULL)
{
tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
tm_workspace_remove_source_file(doc->tm_file);
tm_source_file_free(doc->tm_file);
doc->tm_file = NULL;
}
/* load tags files before highlighting (some lexers highlight global typenames) */

View File

@ -93,8 +93,8 @@ typedef struct GeanyDocument
/** The filetype for this document, it's only a reference to one of the elements of the global
* filetypes array. */
GeanyFiletype *file_type;
/** TMWorkObject object for this document, or @c NULL. */
TMWorkObject *tm_file;
/** TMSourceFile object for this document, or @c NULL. */
TMSourceFile *tm_file;
/** Whether this document is read-only. */
gboolean readonly;
/** Whether this document has been changed since it was last saved. */

View File

@ -639,7 +639,7 @@ static void show_tags_list(GeanyEditor *editor, const GPtrArray *tags, gsize roo
g_string_append(words, tag->name);
/* for now, tag types don't all follow C, so just look at arglist */
if (!EMPTY(tag->atts.entry.arglist))
if (!EMPTY(tag->arglist))
g_string_append(words, "?2");
else
g_string_append(words, "?1");
@ -732,10 +732,10 @@ static void autocomplete_scope(GeanyEditor *editor)
return;
tag = g_ptr_array_index(tags, 0);
name = tag->atts.entry.var_type;
name = tag->var_type;
if (name)
{
TMWorkObject *obj = editor->document->tm_file;
TMSourceFile *obj = editor->document->tm_file;
tags = tm_workspace_find_scope_members(obj ? obj->tags_array : NULL,
name, TRUE, FALSE);
@ -1784,43 +1784,43 @@ static gint find_start_bracket(ScintillaObject *sci, gint pos)
static gboolean append_calltip(GString *str, const TMTag *tag, filetype_id ft_id)
{
if (! tag->atts.entry.arglist)
if (! tag->arglist)
return FALSE;
if (ft_id != GEANY_FILETYPES_PASCAL)
{ /* usual calltips: "retval tagname (arglist)" */
if (tag->atts.entry.var_type)
if (tag->var_type)
{
guint i;
g_string_append(str, tag->atts.entry.var_type);
for (i = 0; i < tag->atts.entry.pointerOrder; i++)
g_string_append(str, tag->var_type);
for (i = 0; i < tag->pointerOrder; i++)
{
g_string_append_c(str, '*');
}
g_string_append_c(str, ' ');
}
if (tag->atts.entry.scope)
if (tag->scope)
{
const gchar *cosep = symbols_get_context_separator(ft_id);
g_string_append(str, tag->atts.entry.scope);
g_string_append(str, tag->scope);
g_string_append(str, cosep);
}
g_string_append(str, tag->name);
g_string_append_c(str, ' ');
g_string_append(str, tag->atts.entry.arglist);
g_string_append(str, tag->arglist);
}
else
{ /* special case Pascal calltips: "tagname (arglist) : retval" */
g_string_append(str, tag->name);
g_string_append_c(str, ' ');
g_string_append(str, tag->atts.entry.arglist);
g_string_append(str, tag->arglist);
if (!EMPTY(tag->atts.entry.var_type))
if (!EMPTY(tag->var_type))
{
g_string_append(str, " : ");
g_string_append(str, tag->atts.entry.var_type);
g_string_append(str, tag->var_type);
}
}
@ -1831,7 +1831,7 @@ static gboolean append_calltip(GString *str, const TMTag *tag, filetype_id ft_id
static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
{
const GPtrArray *tags;
const gint arg_types = tm_tag_function_t | tm_tag_prototype_t |
const TMTagType arg_types = tm_tag_function_t | tm_tag_prototype_t |
tm_tag_method_t | tm_tag_macro_with_arg_t;
TMTagAttrType *attrs = NULL;
TMTag *tag;
@ -1862,7 +1862,7 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
{
tag = TM_TAG(tags->pdata[i]);
if (! tag->atts.entry.arglist)
if (! tag->arglist)
tags->pdata[i] = NULL;
}
tm_tags_prune((GPtrArray *) tags);
@ -1873,7 +1873,7 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
TMTagAttrType sort_attr[] = {tm_tag_attr_name_t, tm_tag_attr_scope_t,
tm_tag_attr_arglist_t, 0};
tm_tags_sort((GPtrArray *) tags, sort_attr, TRUE);
tm_tags_sort((GPtrArray *) tags, sort_attr, TRUE, FALSE);
}
/* if the current word has changed since last time, start with the first tag match */

View File

@ -433,23 +433,6 @@ void highlighting_free_styles(void)
}
static GString *get_global_typenames(gint lang)
{
GString *s = NULL;
if (app->tm_workspace)
{
GPtrArray *tags_array = app->tm_workspace->global_tags;
if (tags_array)
{
s = symbols_find_tags_as_string(tags_array, TM_GLOBAL_TYPE_MASK, lang);
}
}
return s;
}
static gchar*
get_keyfile_whitespace_chars(GKeyFile *config, GKeyFile *configh)
{
@ -823,7 +806,7 @@ static void merge_type_keywords(ScintillaObject *sci, guint ft_id, guint keyword
const gchar *user_words = style_sets[ft_id].keywords[keyword_idx];
GString *s;
s = get_global_typenames(filetypes[ft_id]->lang);
s = symbols_find_typenames_as_string(filetypes[ft_id]->lang, TRUE);
if (G_UNLIKELY(s == NULL))
s = g_string_sized_new(200);
else

View File

@ -1289,7 +1289,7 @@ static void do_main_quit(void)
filetypes_free_types();
log_finalize();
tm_workspace_free(TM_WORK_OBJECT(app->tm_workspace));
tm_workspace_free();
g_free(app->configdir);
g_free(app->datadir);
g_free(app->docdir);

View File

@ -58,7 +58,7 @@ G_BEGIN_DECLS
* @warning You should not test for values below 200 as previously
* @c GEANY_API_VERSION was defined as an enum value, not a macro.
*/
#define GEANY_API_VERSION 220
#define GEANY_API_VERSION 221
/* hack to have a different ABI when built with GTK3 because loading GTK2-linked plugins
* with GTK3-linked Geany leads to crash */
@ -72,7 +72,7 @@ G_BEGIN_DECLS
* Changing this forces all plugins to be recompiled before Geany can load them. */
/* This should usually stay the same if fields are only appended, assuming only pointers to
* structs and not structs themselves are declared by plugins. */
#define GEANY_ABI_VERSION (69 << GEANY_ABI_SHIFT)
#define GEANY_ABI_VERSION (70 << GEANY_ABI_SHIFT)
/** Defines a function to check the plugin is safe to load.
@ -599,12 +599,12 @@ SearchFuncs;
typedef struct TagManagerFuncs
{
gchar* (*tm_get_real_path) (const gchar *file_name);
TMWorkObject* (*tm_source_file_new) (const char *file_name, gboolean update, const char *name);
gboolean (*tm_workspace_add_object) (TMWorkObject *work_object);
gboolean (*tm_source_file_update) (TMWorkObject *source_file, gboolean force,
gboolean recurse, gboolean update_parent);
void (*tm_work_object_free) (gpointer work_object);
gboolean (*tm_workspace_remove_object) (TMWorkObject *w, gboolean do_free, gboolean update);
TMSourceFile* (*tm_source_file_new) (const char *file_name, const char *name);
void (*tm_source_file_free) (TMSourceFile *source_file);
void (*tm_workspace_add_source_file) (TMSourceFile *source_file);
void (*tm_workspace_remove_source_file) (TMSourceFile *source_file);
void (*tm_workspace_add_source_files) (GPtrArray *source_files);
void (*tm_workspace_remove_source_files) (GPtrArray *source_files);
}
TagManagerFuncs;

View File

@ -290,10 +290,11 @@ static KeybindingFuncs keybindings_funcs = {
static TagManagerFuncs tagmanager_funcs = {
&tm_get_real_path,
&tm_source_file_new,
&tm_workspace_add_object,
&tm_source_file_update,
&tm_work_object_free,
&tm_workspace_remove_object
&tm_source_file_free,
&tm_workspace_add_source_file,
&tm_workspace_remove_source_file,
&tm_workspace_add_source_files,
&tm_workspace_remove_source_files
};
static SearchFuncs search_funcs = {

View File

@ -904,7 +904,7 @@ static gboolean taglist_go_to_selection(GtkTreeSelection *selection, guint keyva
if (! tag)
return FALSE;
line = tag->atts.entry.line;
line = tag->line;
if (line > 0)
{
GeanyDocument *doc = document_get_current();

View File

@ -64,11 +64,6 @@
#include <stdlib.h>
const guint TM_GLOBAL_TYPE_MASK =
tm_tag_class_t | tm_tag_enum_t | tm_tag_interface_t |
tm_tag_struct_t | tm_tag_typedef_t | tm_tag_union_t | tm_tag_namespace_t;
static gchar **html_entities = NULL;
typedef struct
@ -248,7 +243,7 @@ static void html_tags_loaded(void)
}
GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gint lang)
GString *symbols_find_typenames_as_string(gint lang, gboolean global)
{
guint j;
TMTag *tag;
@ -256,9 +251,10 @@ GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gin
GPtrArray *typedefs;
gint tag_lang;
g_return_val_if_fail(tags_array != NULL, NULL);
typedefs = tm_tags_extract(tags_array, tag_types);
if (global)
typedefs = tm_tags_extract(app->tm_workspace->global_tags, TM_GLOBAL_TYPE_MASK);
else
typedefs = app->tm_workspace->typename_array;
if ((typedefs) && (typedefs->len > 0))
{
@ -266,9 +262,7 @@ GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gin
for (j = 0; j < typedefs->len; ++j)
{
tag = TM_TAG(typedefs->pdata[j]);
/* tag->atts.file.lang contains (for some reason) the line of the tag if
* tag->atts.entry.file is not NULL */
tag_lang = (tag->atts.entry.file) ? tag->atts.entry.file->lang : tag->atts.file.lang;
tag_lang = tag->lang;
/* the check for tag_lang == lang is necessary to avoid wrong type colouring of
* e.g. PHP classes in C++ files
@ -282,7 +276,7 @@ GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gin
}
}
}
if (typedefs)
if (typedefs && global)
g_ptr_array_free(typedefs, TRUE);
return s;
}
@ -333,25 +327,25 @@ GString *symbols_get_macro_list(gint lang)
gint tag_lang;
TMTag *tag;
if (app->tm_workspace->work_objects == NULL)
if (app->tm_workspace->source_files == NULL)
return NULL;
ftags = g_ptr_array_sized_new(50);
words = g_string_sized_new(200);
for (j = 0; j < app->tm_workspace->work_objects->len; j++)
for (j = 0; j < app->tm_workspace->source_files->len; j++)
{
GPtrArray *tags;
tags = tm_tags_extract(TM_WORK_OBJECT(app->tm_workspace->work_objects->pdata[j])->tags_array,
tags = tm_tags_extract(TM_SOURCE_FILE(app->tm_workspace->source_files->pdata[j])->tags_array,
tm_tag_enum_t | tm_tag_variable_t | tm_tag_macro_t | tm_tag_macro_with_arg_t);
if (NULL != tags)
{
for (i = 0; ((i < tags->len) && (i < editor_prefs.autocompletion_max_entries)); ++i)
{
tag = TM_TAG(tags->pdata[i]);
tag_lang = (tag->atts.entry.file) ?
tag->atts.entry.file->lang : tag->atts.file.lang;
tag_lang = (tag->file) ?
tag->file->lang : tag->lang;
if (tag_lang == lang)
g_ptr_array_add(ftags, (gpointer) tags->pdata[i]);
@ -367,7 +361,7 @@ GString *symbols_get_macro_list(gint lang)
return NULL;
}
tm_tags_sort(ftags, NULL, FALSE);
tm_tags_sort(ftags, NULL, FALSE, FALSE);
for (j = 0; j < ftags->len; j++)
{
if (j > 0)
@ -395,24 +389,21 @@ symbols_find_tm_tag(const GPtrArray *tags, const gchar *tag_name)
}
static TMTag *find_work_object_tag(const TMWorkObject *workobj,
static TMTag *find_source_file_tag(GPtrArray *tags_array,
const gchar *tag_name, guint type)
{
GPtrArray *tags;
TMTag *tmtag;
if (G_LIKELY(workobj != NULL))
tags = tm_tags_extract(tags_array, type);
if (tags != NULL)
{
tags = tm_tags_extract(workobj->tags_array, type);
if (tags != NULL)
{
tmtag = symbols_find_tm_tag(tags, tag_name);
tmtag = symbols_find_tm_tag(tags, tag_name);
g_ptr_array_free(tags, TRUE);
g_ptr_array_free(tags, TRUE);
if (tmtag != NULL)
return tmtag;
}
if (tmtag != NULL)
return tmtag;
}
return NULL; /* not found */
}
@ -421,19 +412,19 @@ static TMTag *find_work_object_tag(const TMWorkObject *workobj,
static TMTag *find_workspace_tag(const gchar *tag_name, guint type)
{
guint j;
const GPtrArray *work_objects = NULL;
const GPtrArray *source_files = NULL;
if (app->tm_workspace != NULL)
work_objects = app->tm_workspace->work_objects;
source_files = app->tm_workspace->source_files;
if (work_objects != NULL)
if (source_files != NULL)
{
for (j = 0; j < work_objects->len; j++)
for (j = 0; j < source_files->len; j++)
{
TMWorkObject *workobj = TM_WORK_OBJECT(work_objects->pdata[j]);
TMSourceFile *srcfile = source_files->pdata[j];
TMTag *tmtag;
tmtag = find_work_object_tag(workobj, tag_name, type);
tmtag = find_source_file_tag(srcfile->tags_array, tag_name, type);
if (tmtag != NULL)
return tmtag;
}
@ -468,7 +459,7 @@ static gint compare_symbol(const TMTag *tag_a, const TMTag *tag_b)
ret = strcmp(tag_a->name, tag_b->name);
if (ret == 0)
{
return tag_a->atts.entry.line - tag_b->atts.entry.line;
return tag_a->line - tag_b->line;
}
return ret;
}
@ -484,21 +475,21 @@ static gint compare_symbol_lines(gconstpointer a, gconstpointer b)
if (a == NULL || b == NULL)
return 0;
ret = tag_a->atts.entry.line - tag_b->atts.entry.line;
ret = tag_a->line - tag_b->line;
if (ret == 0)
{
if (tag_a->atts.entry.scope == NULL)
return -(tag_a->atts.entry.scope != tag_b->atts.entry.scope);
if (tag_b->atts.entry.scope == NULL)
return tag_a->atts.entry.scope != tag_b->atts.entry.scope;
if (tag_a->scope == NULL)
return -(tag_a->scope != tag_b->scope);
if (tag_b->scope == NULL)
return tag_a->scope != tag_b->scope;
else
return strcmp(tag_a->atts.entry.scope, tag_b->atts.entry.scope);
return strcmp(tag_a->scope, tag_b->scope);
}
return ret;
}
static GList *get_tag_list(GeanyDocument *doc, guint tag_types)
static GList *get_tag_list(GeanyDocument *doc, TMTagType tag_types)
{
GList *tag_names = NULL;
TMTag *tag;
@ -1037,7 +1028,7 @@ static void hide_empty_rows(GtkTreeStore *store)
static const gchar *get_symbol_name(GeanyDocument *doc, const TMTag *tag, gboolean found_parent)
{
gchar *utf8_name;
const gchar *scope = tag->atts.entry.scope;
const gchar *scope = tag->scope;
static GString *buffer = NULL; /* buffer will be small so we can keep it for reuse */
gboolean doc_is_utf8 = FALSE;
@ -1078,7 +1069,7 @@ static const gchar *get_symbol_name(GeanyDocument *doc, const TMTag *tag, gboole
if (! doc_is_utf8)
g_free(utf8_name);
g_string_append_printf(buffer, " [%lu]", tag->atts.entry.line);
g_string_append_printf(buffer, " [%lu]", tag->line);
return buffer->str;
}
@ -1108,7 +1099,7 @@ static gchar *get_symbol_tooltip(GeanyDocument *doc, const TMTag *tag)
/* find the last word in "foo::bar::blah", e.g. "blah" */
static const gchar *get_parent_name(const TMTag *tag, filetype_id ft_id)
{
const gchar *scope = tag->atts.entry.scope;
const gchar *scope = tag->scope;
const gchar *separator = symbols_get_context_separator(ft_id);
const gchar *str, *ptr;
@ -1226,9 +1217,9 @@ static gboolean tag_equal(gconstpointer v1, gconstpointer v2)
const TMTag *t2 = v2;
return (t1->type == t2->type && strcmp(t1->name, t2->name) == 0 &&
utils_str_equal(t1->atts.entry.scope, t2->atts.entry.scope) &&
utils_str_equal(t1->scope, t2->scope) &&
/* include arglist in match to support e.g. C++ overloading */
utils_str_equal(t1->atts.entry.arglist, t2->atts.entry.arglist));
utils_str_equal(t1->arglist, t2->arglist));
}
@ -1242,15 +1233,15 @@ static guint tag_hash(gconstpointer v)
h = (h << 5) + h + tag->type;
for (p = tag->name; *p != '\0'; p++)
h = (h << 5) + h + *p;
if (tag->atts.entry.scope)
if (tag->scope)
{
for (p = tag->atts.entry.scope; *p != '\0'; p++)
for (p = tag->scope; *p != '\0'; p++)
h = (h << 5) + h + *p;
}
/* for e.g. C++ overloading */
if (tag->atts.entry.arglist)
if (tag->arglist)
{
for (p = tag->atts.entry.arglist; *p != '\0'; p++)
for (p = tag->arglist; *p != '\0'; p++)
h = (h << 5) + h + *p;
}
@ -1348,7 +1339,7 @@ static GList *tags_table_lookup(GHashTable *table, TMTag *tag)
glong delta;
data = node->data;
#define TAG_DELTA(a, b) ABS((glong) TM_TAG(a)->atts.entry.line - (glong) TM_TAG(b)->atts.entry.line)
#define TAG_DELTA(a, b) ABS((glong) TM_TAG(a)->line - (glong) TM_TAG(b)->line)
delta = TAG_DELTA(((GList *) node->data)->data, tag);
for (node = node->next; node; node = node->next)
@ -1542,7 +1533,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags)
gtk_tree_model_get(GTK_TREE_MODEL(store), node->data,
SYMBOLS_COLUMN_TAG, &parent_tag, -1);
d = tag->atts.entry.line - parent_tag->atts.entry.line;
d = tag->line - parent_tag->line;
if (! parent_search || (d >= 0 && d < delta))
{
delta = d;
@ -1616,7 +1607,7 @@ static gboolean tag_has_missing_parent(const TMTag *tag, GtkTreeStore *store,
GtkTreeIter *iter)
{
/* if the tag has a parent tag, it should be at depth >= 2 */
return !EMPTY(tag->atts.entry.scope) &&
return !EMPTY(tag->scope) &&
gtk_tree_store_iter_depth(store, iter) == 1;
}
@ -1666,7 +1657,7 @@ static gint tree_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
if (tag_a && tag_b)
if (!sort_by_name ||
(utils_str_equal(tag_a->name, tag_b->name) &&
utils_str_equal(tag_a->atts.entry.scope, tag_b->atts.entry.scope)))
utils_str_equal(tag_a->scope, tag_b->scope)))
cmp = compare_symbol_lines(tag_a, tag_b);
}
}
@ -1931,8 +1922,8 @@ static void load_user_tags(filetype_id ft_id)
static gboolean goto_tag(const gchar *name, gboolean definition)
{
const gint forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
guint type;
const TMTagType forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
TMTagType type;
TMTag *tmtag = NULL;
GeanyDocument *old_doc = document_get_current();
@ -1941,7 +1932,7 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
/* first look in the current document */
if (old_doc != NULL && old_doc->tm_file)
tmtag = find_work_object_tag(old_doc->tm_file, name, type);
tmtag = find_source_file_tag(old_doc->tm_file->tags_array, name, type);
/* if not found, look in the workspace */
if (tmtag == NULL)
@ -1950,13 +1941,13 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
if (tmtag != NULL)
{
GeanyDocument *new_doc = document_find_by_real_path(
tmtag->atts.entry.file->work_object.file_name);
tmtag->file->file_name);
if (new_doc)
{
/* If we are already on the tag line, swap definition/declaration */
if (new_doc == old_doc &&
tmtag->atts.entry.line == (guint)sci_get_current_line(old_doc->editor->sci) + 1)
tmtag->line == (guint)sci_get_current_line(old_doc->editor->sci) + 1)
{
if (goto_tag(name, !definition))
return TRUE;
@ -1965,10 +1956,10 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
else
{
/* not found in opened document, should open */
new_doc = document_open_file(tmtag->atts.entry.file->work_object.file_name, FALSE, NULL, NULL);
new_doc = document_open_file(tmtag->file->file_name, FALSE, NULL, NULL);
}
if (navqueue_goto_line(old_doc, new_doc, tmtag->atts.entry.line))
if (navqueue_goto_line(old_doc, new_doc, tmtag->line))
return TRUE;
}
return FALSE;
@ -2122,7 +2113,7 @@ static gint get_fold_header_after(ScintillaObject *sci, gint line)
}
static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_types)
static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, TMTagType tag_types)
{
gint line;
gint parent;
@ -2137,7 +2128,7 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_
if (tag)
{
gint tag_line = tag->atts.entry.line - 1;
gint tag_line = tag->line - 1;
gint last_child = line + 1;
/* if it may be a false positive because we're inside a fold level not inside anything
@ -2152,8 +2143,8 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_
if (line <= last_child)
{
if (tag->atts.entry.scope)
*tagname = g_strconcat(tag->atts.entry.scope,
if (tag->scope)
*tagname = g_strconcat(tag->scope,
symbols_get_context_separator(doc->file_type->id), tag->name, NULL);
else
*tagname = g_strdup(tag->name);
@ -2199,7 +2190,7 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_
}
static gint get_current_tag_name_cached(GeanyDocument *doc, const gchar **tagname, guint tag_types)
static gint get_current_tag_name_cached(GeanyDocument *doc, const gchar **tagname, TMTagType tag_types)
{
static gint tag_line = -1;
static gchar *cur_tag = NULL;
@ -2245,7 +2236,7 @@ gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname)
/* same as symbols_get_current_function() but finds class, namespaces and more */
gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname)
{
guint tag_types = (tm_tag_function_t | tm_tag_method_t | tm_tag_class_t |
TMTagType tag_types = (tm_tag_function_t | tm_tag_method_t | tm_tag_class_t |
tm_tag_struct_t | tm_tag_enum_t | tm_tag_union_t);
/* Python parser reports imports as namespaces which confuses the scope detection */

View File

@ -34,8 +34,6 @@ const gchar *symbols_get_context_separator(gint ft_id);
#ifdef GEANY_PRIVATE
extern const guint TM_GLOBAL_TYPE_MASK;
enum
{
SYMBOLS_SORT_BY_NAME,
@ -52,7 +50,7 @@ void symbols_reload_config_files(void);
void symbols_global_tags_loaded(guint file_type_idx);
GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gint lang);
GString *symbols_find_typenames_as_string(gint lang, gboolean global);
const GList *symbols_get_tag_list(GeanyDocument *doc, guint tag_types);

View File

@ -298,7 +298,7 @@ extern boolean fileOpen (const char *const fileName, const langType language)
* This func is NOT THREAD SAFE.
* The user should not tamper with the buffer while this func is executing.
*/
extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
extern boolean bufferOpen (unsigned char *buffer, size_t buffer_size,
const char *const fileName, const langType language )
{
boolean opened = FALSE;

View File

@ -106,7 +106,7 @@ extern void fileUngetc (int c);
extern const unsigned char *fileReadLine (void);
extern char *readLine (vString *const vLine, MIO *const mio);
extern char *readSourceLine (vString *const vLine, MIOPos location, long *const pSeekValue);
extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
extern boolean bufferOpen (unsigned char *buffer, size_t buffer_size,
const char *const fileName, const langType language );
#define bufferClose fileClose

View File

@ -17,20 +17,15 @@ tagmanager_include_HEADERS = \
tm_source_file.h \
tm_tag.h \
tm_tagmanager.h \
tm_work_object.h \
tm_workspace.h
libtagmanager_a_SOURCES =\
tm_tagmanager.h \
tm_parser.h \
tm_file_entry.h \
tm_file_entry.c \
tm_source_file.h \
tm_source_file.c \
tm_tag.h \
tm_tag.c \
tm_work_object.c \
tm_work_object.h \
tm_workspace.h \
tm_workspace.c

View File

@ -44,8 +44,7 @@ all: $(COMPLIB)
clean:
-$(RM) deps.mak *.o $(COMPLIB)
$(COMPLIB): tm_workspace.o tm_work_object.o tm_source_file.o tm_tag.o \
tm_file_entry.o
$(COMPLIB): tm_workspace.o tm_source_file.o tm_tag.o
$(AR) rc $@ $^
$(RANLIB) $@

View File

@ -1,282 +0,0 @@
/*
*
* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
*/
#include "general.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_FNMATCH_H
# include <fnmatch.h>
#endif
#include <glib/gstdio.h>
#include "tm_work_object.h"
#include "tm_file_entry.h"
#define FILE_NEW(T) ((T) = g_slice_new0(TMFileEntry))
#define FILE_FREE(T) g_slice_free(TMFileEntry, (T))
void tm_file_entry_print(TMFileEntry *entry, gpointer UNUSED user_data
, guint level)
{
guint i;
g_return_if_fail(entry);
for (i=0; i < level; ++i)
fputc('\t', stderr);
fprintf(stderr, "%s\n", entry->name);
}
gint tm_file_entry_compare(TMFileEntry *e1, TMFileEntry *e2)
{
g_return_val_if_fail(e1 && e2 && e1->name && e2->name, 0);
#ifdef TM_DEBUG
g_message("Comparing %s and %s", e1->name, e2->name);
#endif
return strcmp(e1->name, e2->name);
}
/* TTimo - modified to handle symlinks */
static TMFileType tm_file_entry_type(const char *path)
{
struct stat s;
#ifndef G_OS_WIN32
if (0 != g_lstat(path, &s))
return tm_file_unknown_t;
#endif
if (S_ISDIR(s.st_mode))
return tm_file_dir_t;
#ifndef G_OS_WIN32
else if (S_ISLNK(s.st_mode))
return tm_file_link_t;
#endif
else if (S_ISREG(s.st_mode))
return tm_file_regular_t;
else
return tm_file_unknown_t;
}
static gboolean apply_filter(const char *name, GList *match, GList *unmatch
, gboolean ignore_hidden)
{
GList *tmp;
gboolean matched = (match == NULL);
g_return_val_if_fail(name, FALSE);
if (ignore_hidden && ('.' == name[0]))
return FALSE;
/* TTimo - ignore .svn directories */
if (!strcmp(name, ".svn"))
return FALSE;
for (tmp = match; tmp; tmp = g_list_next(tmp))
{
if (0 == fnmatch((char *) tmp->data, name, 0))
{
matched = TRUE;
break;
}
}
if (!matched)
return FALSE;
for (tmp = unmatch; tmp; tmp = g_list_next(tmp))
{
if (0 == fnmatch((char *) tmp->data, name, 0))
{
return FALSE;
}
}
return matched;
}
TMFileEntry *tm_file_entry_new(const char *path, TMFileEntry *parent
, gboolean recurse, GList *file_match, GList *file_unmatch
, GList *dir_match, GList *dir_unmatch, gboolean ignore_hidden_files
, gboolean ignore_hidden_dirs)
{
TMFileEntry *entry;
/* GList *tmp; */
char *real_path;
DIR *dir;
struct dirent *dir_entry;
TMFileEntry *new_entry;
char *file_name;
struct stat s;
char *entries = NULL;
g_return_val_if_fail (path != NULL, NULL);
/* TTimo - don't follow symlinks */
if (tm_file_entry_type(path) == tm_file_link_t)
return NULL;
real_path = tm_get_real_path(path);
if (!real_path)
return NULL;
FILE_NEW(entry);
entry->type = tm_file_entry_type(real_path);
entry->parent = parent;
entry->path = real_path;
entry->name = strrchr(entry->path, '/');
if (entry->name)
++ (entry->name);
else
entry->name = entry->path;
switch(entry->type)
{
case tm_file_unknown_t:
g_free(real_path);
FILE_FREE(entry);
return NULL;
case tm_file_link_t:
case tm_file_regular_t:
if (parent && !apply_filter(entry->name, file_match, file_unmatch
, ignore_hidden_files))
{
tm_file_entry_free(entry);
return NULL;
}
break;
case tm_file_dir_t:
if (parent && !(recurse && apply_filter(entry->name, dir_match
, dir_unmatch, ignore_hidden_dirs)))
{
tm_file_entry_free(entry);
return NULL;
}
file_name = g_strdup_printf("%s/CVS/Entries", entry->path);
if (0 == g_stat(file_name, &s))
{
if (S_ISREG(s.st_mode))
{
int fd;
entries = g_new(char, s.st_size + 2);
if (0 > (fd = open(file_name, O_RDONLY)))
{
g_free(entries);
entries = NULL;
}
else
{
off_t n =0;
off_t total_read = 1;
while (0 < (n = read(fd, entries + total_read, s.st_size - total_read)))
total_read += n;
entries[s.st_size] = '\0';
entries[0] = '\n';
close(fd);
entry->version = g_strdup("D");
}
}
}
g_free(file_name);
if (NULL != (dir = opendir(entry->path)))
{
while (NULL != (dir_entry = readdir(dir)))
{
if ((0 == strcmp(dir_entry->d_name, "."))
|| (0 == strcmp(dir_entry->d_name, "..")))
continue;
file_name = g_strdup_printf("%s/%s", entry->path, dir_entry->d_name);
new_entry = tm_file_entry_new(file_name, entry, recurse
, file_match, file_unmatch, dir_match, dir_unmatch
, ignore_hidden_files, ignore_hidden_dirs);
g_free(file_name);
if (new_entry)
{
if (entries)
{
char *str = g_strconcat("\n/", new_entry->name, "/", NULL);
char *name_pos = strstr(entries, str);
if (NULL != name_pos)
{
int len = strlen(str);
char *version_pos = strchr(name_pos + len, '/');
if (NULL != version_pos)
{
*version_pos = '\0';
new_entry->version = g_strdup(name_pos + len);
*version_pos = '/';
}
}
g_free(str);
}
entry->children = g_slist_prepend(entry->children, new_entry);
}
}
}
closedir(dir);
entry->children = g_slist_sort(entry->children, (GCompareFunc) tm_file_entry_compare);
g_free(entries);
break;
}
return entry;
}
void tm_file_entry_free(gpointer entry)
{
if (entry)
{
TMFileEntry *file_entry = TM_FILE_ENTRY(entry);
if (file_entry->children)
{
GSList *tmp;
for (tmp = file_entry->children; tmp; tmp = g_slist_next(tmp))
tm_file_entry_free(tmp->data);
g_slist_free(file_entry->children);
}
g_free(file_entry->version);
g_free(file_entry->path);
FILE_FREE(file_entry);
}
}
void tm_file_entry_foreach(TMFileEntry *entry, TMFileEntryFunc func
, gpointer user_data, guint level, gboolean reverse)
{
g_return_if_fail (entry != NULL);
g_return_if_fail (func != NULL);
if ((reverse) && (entry->children))
{
GSList *tmp;
for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
, user_data, level + 1, TRUE);
}
func(entry, user_data, level);
if ((!reverse) && (entry->children))
{
GSList *tmp;
for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
, user_data, level + 1, FALSE);
}
}
GList *tm_file_entry_list(TMFileEntry *entry, GList *files)
{
GSList *tmp;
files = g_list_prepend(files, g_strdup(entry->path));
for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
{
files = tm_file_entry_list((TMFileEntry *) tmp->data, files);
}
if (!files)
files = g_list_reverse(files);
return files;
}

View File

@ -1,124 +0,0 @@
/*
*
* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
*/
#ifndef TM_FILE_ENTRY_H
#define TM_FILE_ENTRY_H
#include <glib.h>
/* \file
The TMFileEntry structure and associated functions can be used
for file and directory traversal. The following example demonstrates
the use of TMFileEntry.
\include tm_file_tree_dump.c
*/
#ifdef __cplusplus
extern "C"
{
#endif
/* Enum defining file types */
typedef enum
{
tm_file_unknown_t, /* Unknown file type/file does not exist */
tm_file_regular_t, /* Is a regular file */
tm_file_dir_t, /* Is a directory */
tm_file_link_t /* Is a symbolic link */
} TMFileType;
/*
This example demonstrates the use of TMFileEntry and associated functions
for managing file hierarchies in a project.
\example tm_file_tree_dump.c
*/
/* This structure stores the file tree */
typedef struct _TMFileEntry
{
TMFileType type; /* File type */
char *path; /* Full path to the file (incl. dir and name) */
char *name; /* Just the file name (path minus the directory) */
char *version; /* CVS version in case there is a CVS entry for this file */
struct _TMFileEntry *parent; /* The parent directory file entry */
GSList *children; /* List of children (for directory) */
} TMFileEntry;
/* Prototype for the function that gets called for each entry when
tm_file_entry_foreach() is called.
*/
typedef void (*TMFileEntryFunc) (TMFileEntry *entry, gpointer user_data
, guint level);
/* Convinience casting macro */
#define TM_FILE_ENTRY(E) ((TMFileEntry *) (E))
/* Function that compares two file entries on name and returns the
difference
*/
gint tm_file_entry_compare(TMFileEntry *e1, TMFileEntry *e2);
/* Function to create a new file entry structure.
\param path Path to the file for which the entry is to be created.
\param parent Should be NULL for the first call. Since the function calls
itself recursively, this parameter is required to build the hierarchy.
\param recurse Whether the entry is to be recursively scanned (for
directories only)
\param file_match List of file name patterns to match. If set to NULL,
all files match. You can use wildcards like '*.c'. See the example program
for usage.
\param file_unmatch Opposite of file_match. All files matching any of the patterns
supplied are ignored. If set to NULL, no file is ignored.
\param dir_match List of directory name patterns to match. If set to NULL,
all directories match. You can use wildcards like '\.*'.
\param dir_unmatch Opposite of dir_match. All directories matching any of the
patterns supplied are ignored. If set to NULL, no directory is ignored.
\param ignore_hidden_files If set to TRUE, hidden files (starting with '.')
are ignored.
\param ignore_hidden_dirs If set to TRUE, hidden directories (starting with '.')
are ignored.
\return Populated TMFileEntry structure on success, NULL on failure.
*/
TMFileEntry *tm_file_entry_new(const char *path, TMFileEntry *parent
, gboolean recurse, GList *file_match, GList *file_unmatch
, GList *dir_match, GList *dir_unmatch, gboolean ignore_hidden_files
, gboolean ignore_hidden_dirs);
/* Frees a TMFileEntry structure. Freeing is recursive, so all child
entries are freed as well.
\param entry The TMFileEntry structure to be freed.
*/
void tm_file_entry_free(gpointer entry);
/* This will call the function func() for each file entry.
\param entry The root file entry.
\param func The function to be called.
\param user_data Extra information to be passed to the function.
\param level The recursion level. You should set this to 0 initially.
\param reverse If set to TRUE, traversal is in reverse hierarchical order
*/
void tm_file_entry_foreach(TMFileEntry *entry, TMFileEntryFunc func
, gpointer user_data, guint level, gboolean reverse);
/* This is a sample function to show the use of tm_file_entry_foreach().
*/
void tm_file_entry_print(TMFileEntry *entry, gpointer user_data, guint level);
/* Creates a list of path names from a TMFileEntry structure.
\param entry The TMFileEntry structure.
\files Current file list. Should be NULL.
*/
GList *tm_file_entry_list(TMFileEntry *entry, GList *files);
#ifdef __cplusplus
}
#endif
#endif /* TM_FILE_ENTRY_H */

View File

@ -18,37 +18,159 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <glib/gstdio.h>
#ifdef G_OS_WIN32
# define VC_EXTRALEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h> /* for GetFullPathName */
#endif
#include "general.h"
#include "entry.h"
#include "parse.h"
#include "read.h"
#define LIBCTAGS_DEFINED
#include "tm_work_object.h"
#define LIBCTAGS_DEFINED
#include "tm_source_file.h"
#include "tm_tag.h"
guint source_file_class_id = 0;
static TMSourceFile *current_source_file = NULL;
gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name
, gboolean update, const char* name)
static int get_path_max(const char *path)
{
if (0 == source_file_class_id)
source_file_class_id = tm_work_object_register(tm_source_file_free
, tm_source_file_update, NULL);
#ifdef PATH_MAX
return PATH_MAX;
#else
int path_max = pathconf(path, _PC_PATH_MAX);
if (path_max <= 0)
path_max = 4096;
return path_max;
#endif
}
#ifdef G_OS_WIN32
/* realpath implementation for Windows found at http://bugzilla.gnome.org/show_bug.cgi?id=342926
* this one is better than e.g. liberty's lrealpath because this one uses Win32 API and works
* with special chars within the filename */
static char *realpath (const char *pathname, char *resolved_path)
{
int size;
if (resolved_path != NULL)
{
int path_max = get_path_max(pathname);
size = GetFullPathNameA (pathname, path_max, resolved_path, NULL);
if (size > path_max)
return NULL;
else
return resolved_path;
}
else
{
size = GetFullPathNameA (pathname, 0, NULL, NULL);
resolved_path = g_new0 (char, size);
GetFullPathNameA (pathname, size, resolved_path, NULL);
return resolved_path;
}
}
#endif
/**
Given a file name, returns a newly allocated string containing the realpath()
of the file.
@param file_name The original file_name
@return A newly allocated string containing the real path to the file. NULL if none is available.
*/
gchar *tm_get_real_path(const gchar *file_name)
{
if (file_name)
{
gsize len = get_path_max(file_name) + 1;
gchar *path = g_malloc0(len);
if (realpath(file_name, path))
return path;
else
g_free(path);
}
return NULL;
}
/*
This function is registered into the ctags parser when a file is parsed for
the first time. The function is then called by the ctags parser each time
it finds a new tag. You should not have to use this function.
@see tm_source_file_parse()
*/
static int tm_source_file_tags(const tagEntryInfo *tag)
{
if (NULL == current_source_file)
return 0;
g_ptr_array_add(current_source_file->tags_array,
tm_tag_new(current_source_file, tag));
return TRUE;
}
/* Set the argument list of tag identified by its name */
static void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist)
{
guint count;
TMTag **tags, *tag;
if (NULL == arglist ||
NULL == tag_name ||
NULL == current_source_file)
{
return;
}
tags = tm_tags_find(current_source_file->tags_array, tag_name, FALSE, FALSE,
&count);
if (tags != NULL && count == 1)
{
tag = tags[0];
g_free(tag->arglist);
tag->arglist = g_strdup(arglist);
}
}
/* Initializes a TMSourceFile structure from a file name. */
static gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name,
const char* name)
{
struct stat s;
int status;
#ifdef TM_DEBUG
g_message("Source File init: %s", file_name);
#endif
if (FALSE == tm_work_object_init(&(source_file->work_object),
source_file_class_id, file_name, FALSE))
return FALSE;
if (file_name != NULL)
{
status = g_stat(file_name, &s);
if (0 != status)
{
/* g_warning("Unable to stat %s", file_name);*/
return FALSE;
}
if (!S_ISREG(s.st_mode))
{
g_warning("%s: Not a regular file", file_name);
return FALSE;
}
source_file->file_name = tm_get_real_path(file_name);
source_file->short_name = strrchr(source_file->file_name, '/');
if (source_file->short_name)
++ source_file->short_name;
else
source_file->short_name = source_file->file_name;
}
source_file->tags_array = g_ptr_array_new();
source_file->inactive = FALSE;
if (NULL == LanguageTable)
{
initializeParsing();
@ -64,37 +186,46 @@ gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name
else
source_file->lang = getNamedLanguage(name);
if (update)
tm_source_file_update(TM_WORK_OBJECT(source_file), TRUE, FALSE, FALSE);
return TRUE;
}
TMWorkObject *tm_source_file_new(const char *file_name, gboolean update, const char *name)
/** Initializes a TMSourceFile structure and returns a pointer to it. The
* TMSourceFile has to be added to TMWorkspace to start its parsing.
* @param file_name The file name.
* @param name Name of the used programming language, NULL for autodetection.
* @return The created unparsed TMSourceFile object.
* */
TMSourceFile *tm_source_file_new(const char *file_name, const char *name)
{
TMSourceFile *source_file = g_new(TMSourceFile, 1);
if (TRUE != tm_source_file_init(source_file, file_name, update, name))
if (TRUE != tm_source_file_init(source_file, file_name, name))
{
g_free(source_file);
return NULL;
}
return (TMWorkObject *) source_file;
return source_file;
}
void tm_source_file_destroy(TMSourceFile *source_file)
/* Destroys the contents of the source file. Note that the tags are owned by the
source file and are also destroyed when the source file is destroyed. If pointers
to these tags are used elsewhere, then those tag arrays should be rebuilt.
*/
static void tm_source_file_destroy(TMSourceFile *source_file)
{
#ifdef TM_DEBUG
g_message("Destroying source file: %s", source_file->work_object.file_name);
g_message("Destroying source file: %s", source_file->file_name);
#endif
if (NULL != TM_WORK_OBJECT(source_file)->tags_array)
{
tm_tags_array_free(TM_WORK_OBJECT(source_file)->tags_array, TRUE);
TM_WORK_OBJECT(source_file)->tags_array = NULL;
}
tm_work_object_destroy(&(source_file->work_object));
g_free(source_file->file_name);
tm_tags_array_free(source_file->tags_array, TRUE);
source_file->tags_array = NULL;
}
void tm_source_file_free(gpointer source_file)
/** Frees a TMSourceFile structure, including all contents. Before calling this
function the TMSourceFile has to be removed from the TMWorkspace.
@param source_file The source file to free.
*/
void tm_source_file_free(TMSourceFile *source_file)
{
if (NULL != source_file)
{
@ -103,79 +234,63 @@ void tm_source_file_free(gpointer source_file)
}
}
gboolean tm_source_file_parse(TMSourceFile *source_file)
/* Parses the text-buffer or source file and regenarates the tags.
@param source_file The source file to parse
@param text_buf The text buffer to parse
@param buf_size The size of text_buf.
@param use_buffer Set FALSE to ignore the buffer and parse the file directly or
TRUE to parse the buffer and ignore the file content.
@return TRUE on success, FALSE on failure
*/
gboolean tm_source_file_parse(TMSourceFile *source_file, guchar* text_buf, gsize buf_size,
gboolean use_buffer)
{
const char *file_name;
gboolean status = TRUE;
int passCount = 0;
gboolean retry = TRUE;
gboolean parse_file = FALSE;
gboolean free_buf = FALSE;
if ((NULL == source_file) || (NULL == source_file->work_object.file_name))
if ((NULL == source_file) || (NULL == source_file->file_name))
{
g_warning("Attempt to parse NULL file");
return FALSE;
}
file_name = source_file->work_object.file_name;
if (NULL == LanguageTable)
if (source_file->lang == LANG_IGNORE)
{
initializeParsing();
installLanguageMapDefaults();
if (NULL == TagEntryFunction)
TagEntryFunction = tm_source_file_tags;
if (NULL == TagEntrySetArglistFunction)
TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
tm_tags_array_free(source_file->tags_array, FALSE);
return FALSE;
}
current_source_file = source_file;
if (LANG_AUTO == source_file->lang)
source_file->lang = getFileLanguage (file_name);
if (source_file->lang < 0 || ! LanguageTable [source_file->lang]->enabled)
return status;
while ((TRUE == status) && (passCount < 3))
file_name = source_file->file_name;
if (!use_buffer)
{
if (source_file->work_object.tags_array)
tm_tags_array_free(source_file->work_object.tags_array, FALSE);
if (fileOpen (file_name, source_file->lang))
{
if (LanguageTable [source_file->lang]->parser != NULL)
{
LanguageTable [source_file->lang]->parser ();
fileClose ();
break;
}
else if (LanguageTable [source_file->lang]->parser2 != NULL)
status = LanguageTable [source_file->lang]->parser2 (passCount);
fileClose ();
}
struct stat s;
/* load file to memory and parse it from memory unless the file is too big */
if (g_stat(file_name, &s) != 0 || s.st_size > 10*1024*1024)
parse_file = TRUE;
else
{
g_warning("%s: Unable to open %s", G_STRFUNC, file_name);
return FALSE;
if (!g_file_get_contents(file_name, (gchar**)&text_buf, (gsize*)&buf_size, NULL))
{
g_warning("Unable to open %s", file_name);
return FALSE;
}
free_buf = TRUE;
}
++ passCount;
}
return status;
}
gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf, gint buf_size)
{
const char *file_name;
gboolean status = TRUE;
if ((NULL == source_file) || (NULL == source_file->work_object.file_name))
if (!parse_file && (NULL == text_buf || 0 == buf_size))
{
g_warning("Attempt to parse NULL file");
return FALSE;
/* Empty buffer, "parse" by setting empty tag array */
tm_tags_array_free(source_file->tags_array, FALSE);
if (free_buf)
g_free(text_buf);
return TRUE;
}
if ((NULL == text_buf) || (0 == buf_size))
{
g_warning("Attempt to parse a NULL text buffer");
}
file_name = source_file->work_object.file_name;
if (NULL == LanguageTable)
{
initializeParsing();
@ -202,21 +317,34 @@ gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf
}
else
{
int passCount = 0;
while ((TRUE == status) && (passCount < 3))
guint passCount = 0;
while (retry && passCount < 3)
{
if (source_file->work_object.tags_array)
tm_tags_array_free(source_file->work_object.tags_array, FALSE);
if (bufferOpen (text_buf, buf_size, file_name, source_file->lang))
tm_tags_array_free(source_file->tags_array, FALSE);
if (parse_file && fileOpen (file_name, source_file->lang))
{
if (LanguageTable [source_file->lang]->parser != NULL)
{
LanguageTable [source_file->lang]->parser ();
fileClose ();
retry = FALSE;
break;
}
else if (LanguageTable [source_file->lang]->parser2 != NULL)
retry = LanguageTable [source_file->lang]->parser2 (passCount);
fileClose ();
}
else if (!parse_file && bufferOpen (text_buf, buf_size, file_name, source_file->lang))
{
if (LanguageTable [source_file->lang]->parser != NULL)
{
LanguageTable [source_file->lang]->parser ();
bufferClose ();
retry = FALSE;
break;
}
else if (LanguageTable [source_file->lang]->parser2 != NULL)
status = LanguageTable [source_file->lang]->parser2 (passCount);
retry = LanguageTable [source_file->lang]->parser2 (passCount);
bufferClose ();
}
else
@ -226,103 +354,66 @@ gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf
}
++ passCount;
}
return TRUE;
}
return status;
if (free_buf)
g_free(text_buf);
return !retry;
}
void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist)
/* Gets the name associated with the language index.
@param lang The language index.
@return The language name, or NULL.
*/
const gchar *tm_source_file_get_lang_name(gint lang)
{
int count;
TMTag **tags, *tag;
if (NULL == arglist ||
NULL == tag_name ||
NULL == current_source_file ||
NULL == current_source_file->work_object.tags_array)
if (NULL == LanguageTable)
{
return;
}
tags = tm_tags_find(current_source_file->work_object.tags_array, tag_name, FALSE, FALSE,
&count);
if (tags != NULL && count == 1)
{
tag = tags[0];
g_free(tag->atts.entry.arglist);
tag->atts.entry.arglist = g_strdup(arglist);
initializeParsing();
installLanguageMapDefaults();
if (NULL == TagEntryFunction)
TagEntryFunction = tm_source_file_tags;
if (NULL == TagEntrySetArglistFunction)
TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
}
return getLanguageName(lang);
}
int tm_source_file_tags(const tagEntryInfo *tag)
/* Gets the language index for \a name.
@param name The language name.
@return The language index, or -2.
*/
gint tm_source_file_get_named_lang(const gchar *name)
{
if (NULL == current_source_file)
return 0;
if (NULL == current_source_file->work_object.tags_array)
current_source_file->work_object.tags_array = g_ptr_array_new();
g_ptr_array_add(current_source_file->work_object.tags_array,
tm_tag_new(current_source_file, tag));
return TRUE;
}
gboolean tm_source_file_update(TMWorkObject *source_file, gboolean force
, gboolean UNUSED recurse, gboolean update_parent)
{
if (force)
if (NULL == LanguageTable)
{
tm_source_file_parse(TM_SOURCE_FILE(source_file));
tm_tags_sort(source_file->tags_array, NULL, FALSE);
/* source_file->analyze_time = tm_get_file_timestamp(source_file->file_name); */
if ((source_file->parent) && update_parent)
{
tm_work_object_update(source_file->parent, TRUE, FALSE, TRUE);
}
return TRUE;
}
else {
#ifdef TM_DEBUG
g_message ("no parsing of %s has been done", source_file->file_name);
#endif
return FALSE;
initializeParsing();
installLanguageMapDefaults();
if (NULL == TagEntryFunction)
TagEntryFunction = tm_source_file_tags;
if (NULL == TagEntrySetArglistFunction)
TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
}
return getNamedLanguage(name);
}
gboolean tm_source_file_buffer_update(TMWorkObject *source_file, guchar* text_buf,
gint buf_size, gboolean update_parent)
{
#ifdef TM_DEBUG
g_message("Buffer updating based on source file %s", source_file->file_name);
#endif
tm_source_file_buffer_parse (TM_SOURCE_FILE(source_file), text_buf, buf_size);
tm_tags_sort(source_file->tags_array, NULL, FALSE);
/* source_file->analyze_time = time(NULL); */
if ((source_file->parent) && update_parent)
{
#ifdef TM_DEBUG
g_message("Updating parent from buffer..");
#endif
tm_work_object_update(source_file->parent, TRUE, FALSE, TRUE);
}
#ifdef TM_DEBUG
else
g_message("Skipping parent update because parent is %s and update_parent is %s"
, source_file->parent?"NOT NULL":"NULL", update_parent?"TRUE":"FALSE");
#endif
return TRUE;
}
gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs)
#if 0
/*
Writes all tags of a source file (including the file tag itself) to the passed
file pointer.
@param source_file The source file to write.
@param fp The file pointer to write to.
@param attrs The attributes to write.
@return TRUE on success, FALSE on failure.
*/
static gboolean tm_source_file_write(TMSourceFile *source_file, FILE *fp, guint attrs)
{
TMTag *tag;
guint i;
if (NULL != source_file)
{
if (NULL != (tag = tm_tag_new(TM_SOURCE_FILE(source_file), NULL)))
if (NULL != (tag = tm_tag_new(source_file, NULL)))
{
tm_tag_write(tag, fp, tm_tag_attr_max_t);
tm_tag_unref(tag);
@ -339,32 +430,4 @@ gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs)
}
return TRUE;
}
const gchar *tm_source_file_get_lang_name(gint lang)
{
if (NULL == LanguageTable)
{
initializeParsing();
installLanguageMapDefaults();
if (NULL == TagEntryFunction)
TagEntryFunction = tm_source_file_tags;
if (NULL == TagEntrySetArglistFunction)
TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
}
return getLanguageName(lang);
}
gint tm_source_file_get_named_lang(const gchar *name)
{
if (NULL == LanguageTable)
{
initializeParsing();
installLanguageMapDefaults();
if (NULL == TagEntryFunction)
TagEntryFunction = tm_source_file_tags;
if (NULL == TagEntrySetArglistFunction)
TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
}
return getNamedLanguage(name);
}
#endif

View File

@ -10,8 +10,8 @@
#ifndef TM_SOURCE_FILE_H
#define TM_SOURCE_FILE_H
#include "tm_work_object.h"
#include <stdio.h>
#include <glib.h>
#ifndef LIBCTAGS_DEFINED
typedef int langType;
@ -27,138 +27,38 @@ extern "C"
#endif
/* Casts a pointer to a pointer to a TMSourceFile structure */
#define TM_SOURCE_FILE(work_object) ((TMSourceFile *) work_object)
#define TM_SOURCE_FILE(source_file) ((TMSourceFile *) source_file)
/* Checks whether the object is a TMSourceFile */
#define IS_TM_SOURCE_FILE(source_file) (((TMWorkObject *) (source_file))->type \
== source_file_class_id)
/* Evaluates to X is X is defined, else evaluates to Y */
#define FALLBACK(X,Y) (X)?(X):(Y)
/*!
The TMSourceFile structure is derived from TMWorkObject and contains all it's
attributes, plus an integer representing the language of the file.
/**
The TMSourceFile structure represents the source file and its tags in the tag manager.
*/
typedef struct
{
TMWorkObject work_object; /*!< The base work object */
langType lang; /*!< Programming language used */
gboolean inactive; /*!< Whether this file should be scanned for tags */
langType lang; /**< Programming language used */
char *file_name; /**< Full file name (inc. path) */
char *short_name; /**< Just the name of the file (without the path) */
GPtrArray *tags_array; /**< Sorted tag array obtained by parsing the object */
} TMSourceFile;
/*! Initializes a TMSourceFile structure and returns a pointer to it.
* \param file_name The file name.
* \param update Update the tag array of the file.
* \param name Name of the used programming language, NULL for autodetection.
* \return The created TMSourceFile object.
* */
TMWorkObject *tm_source_file_new(const char *file_name, gboolean update, const char *name);
TMSourceFile *tm_source_file_new(const char *file_name, const char *name);
/*! Updates the source file by reparsing if the modification time is greater
than the timestamp in the structure, or if force is TRUE. The tags array and
the tags themselves are destroyed and re-created, hence any other tag arrays
pointing to these tags should be rebuilt as well. All sorting information is
also lost. The language parameter is automatically set the first time the file
is parsed.
\param source_file The source file to update.
\param force Ignored. The source file is always updated.
\param recurse This parameter is ignored for source files and is only there for consistency.
\param update_parent If set to TRUE, sends an update signal to parent if required. You should
always set this to TRUE if you are calling this function directly.
\return TRUE if the file was parsed, FALSE otherwise.
\sa tm_work_object_update(), tm_workspace_update()
*/
gboolean tm_source_file_update(TMWorkObject *source_file, gboolean force
, gboolean recurse, gboolean update_parent);
void tm_source_file_free(TMSourceFile *source_file);
gchar *tm_get_real_path(const gchar *file_name);
#ifdef GEANY_PRIVATE
/* Initializes a TMSourceFile structure from a file name. */
gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name,
gboolean update, const char *name);
/* Destroys the contents of the source file. Note that the tags are owned by the
source file and are also destroyed when the source file is destroyed. If pointers
to these tags are used elsewhere, then those tag arrays should be rebuilt.
*/
void tm_source_file_destroy(TMSourceFile *source_file);
/* Frees a TMSourceFile structure, including all contents */
void tm_source_file_free(gpointer source_file);
/* Updates the source file by reparsing the text-buffer passed as parameter.
Ctags will use a parsing based on buffer instead of on files.
You should call this function when you don't want a previous saving of the file
you're editing. It's useful for a "real-time" updating of the tags.
The tags array and the tags themselves are destroyed and re-created, hence any
other tag arrays pointing to these tags should be rebuilt as well. All sorting
information is also lost. The language parameter is automatically set the first
time the file is parsed.
\param source_file The source file to update with a buffer.
\param text_buf A text buffer. The user should take care of allocate and free it after
the use here.
\param buf_size The size of text_buf.
\param update_parent If set to TRUE, sends an update signal to parent if required. You should
always set this to TRUE if you are calling this function directly.
\return TRUE if the file was parsed, FALSE otherwise.
\sa tm_work_object_update(), tm_workspace_update()
*/
gboolean tm_source_file_buffer_update(TMWorkObject *source_file, guchar* text_buf,
gint buf_size, gboolean update_parent);
/* Parses the source file and regenarates the tags.
\param source_file The source file to parse
\return TRUE on success, FALSE on failure
\sa tm_source_file_update()
*/
gboolean tm_source_file_parse(TMSourceFile *source_file);
/* Parses the text-buffer and regenarates the tags.
\param source_file The source file to parse
\param text_buf The text buffer to parse
\param buf_size The size of text_buf.
\return TRUE on success, FALSE on failure
\sa tm_source_file_update()
*/
gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf, gint buf_size);
/*
This function is registered into the ctags parser when a file is parsed for
the first time. The function is then called by the ctags parser each time
it finds a new tag. You should not have to use this function.
\sa tm_source_file_parse()
*/
int tm_source_file_tags(const tagEntryInfo *tag);
/*
Writes all tags of a source file (including the file tag itself) to the passed
file pointer.
\param source_file The source file to write.
\param fp The file pointer to write to.
\param attrs The attributes to write.
\return TRUE on success, FALSE on failure.
*/
gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs);
/* Contains the id obtained by registering the TMSourceFile class as a child of
TMWorkObject.
\sa tm_work_object_register()
*/
extern guint source_file_class_id;
/* Gets the name associated with the language index.
\param lang The language index.
\return The language name, or NULL.
*/
const gchar *tm_source_file_get_lang_name(gint lang);
/* Gets the language index for \a name.
\param name The language name.
\return The language index, or -2.
*/
gint tm_source_file_get_named_lang(const gchar *name);
/* Set the argument list of tag identified by its name */
void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist);
gboolean tm_source_file_parse(TMSourceFile *source_file, guchar* text_buf, gsize buf_size,
gboolean use_buffer);
#endif /* GEANY_PRIVATE */

File diff suppressed because it is too large Load Diff

View File

@ -10,15 +10,15 @@
#ifndef TM_TAG_H
#define TM_TAG_H
/* \file
/* @file
The TMTag structure and the associated functions are used to manipulate
tags and arrays of tags. Normally, you should not create tags individually
but through an external interface such as tm_source_file_parse(), which generates
an array of tags for the given source file. Once the tag list is generated,
you can do various operations such as:
-# Extract relevant tags using tm_tags_extract()
-# Sort an array of tags using tm_tags_sort() or tm_tags_custom_sort()
-# Deduplicate an array of tags using tm_tags_dedup() or tm_tags_dedup_custom().
-# Sort an array of tags using tm_tags_sort()
-# Deduplicate an array of tags using tm_tags_dedup().
An important thing to remember here is that the tags operations such as extraction,
sorting and deduplication do not change the tag itself in any way, but rather,
@ -37,41 +37,41 @@ extern "C"
{
#endif
/*! Use the TM_TAG() macro to cast a pointer to (TMTag *) */
/** Use the TM_TAG() macro to cast a pointer to (TMTag *) */
#define TM_TAG(tag) ((TMTag *) tag)
/*!
/**
Types of tags. It is a bitmask so that multiple tag types can
be used simultaneously by 'OR'-ing them bitwise.
e.g. tm_tag_class_t | tm_tag_struct_t
*/
typedef enum
{
tm_tag_undef_t = 0, /*!< Unknown type */
tm_tag_class_t = 1, /*!< Class declaration */
tm_tag_enum_t = 2, /*!< Enum declaration */
tm_tag_enumerator_t = 4, /*!< Enumerator value */
tm_tag_field_t = 8, /*!< Field (Java only) */
tm_tag_function_t = 16, /*!< Function definition */
tm_tag_interface_t = 32, /*!< Interface (Java only) */
tm_tag_member_t = 64, /*!< Member variable of class/struct */
tm_tag_method_t = 128, /*!< Class method (Java only) */
tm_tag_namespace_t = 256, /*!< Namespace declaration */
tm_tag_package_t = 512, /*!< Package (Java only) */
tm_tag_prototype_t = 1024, /*!< Function prototype */
tm_tag_struct_t = 2048, /*!< Struct declaration */
tm_tag_typedef_t = 4096, /*!< Typedef */
tm_tag_union_t = 8192, /*!< Union */
tm_tag_variable_t = 16384, /*!< Variable */
tm_tag_externvar_t = 32768, /*!< Extern or forward declaration */
tm_tag_macro_t = 65536, /*!< Macro (without arguments) */
tm_tag_macro_with_arg_t = 131072, /*!< Parameterized macro */
tm_tag_file_t = 262144, /*!< File (Pseudo tag) */
tm_tag_other_t = 524288, /*!< Other (non C/C++/Java tag) */
tm_tag_max_t = 1048575 /*!< Maximum value of TMTagType */
tm_tag_undef_t = 0, /**< Unknown type */
tm_tag_class_t = 1, /**< Class declaration */
tm_tag_enum_t = 2, /**< Enum declaration */
tm_tag_enumerator_t = 4, /**< Enumerator value */
tm_tag_field_t = 8, /**< Field (Java only) */
tm_tag_function_t = 16, /**< Function definition */
tm_tag_interface_t = 32, /**< Interface (Java only) */
tm_tag_member_t = 64, /**< Member variable of class/struct */
tm_tag_method_t = 128, /**< Class method (Java only) */
tm_tag_namespace_t = 256, /**< Namespace declaration */
tm_tag_package_t = 512, /**< Package (Java only) */
tm_tag_prototype_t = 1024, /**< Function prototype */
tm_tag_struct_t = 2048, /**< Struct declaration */
tm_tag_typedef_t = 4096, /**< Typedef */
tm_tag_union_t = 8192, /**< Union */
tm_tag_variable_t = 16384, /**< Variable */
tm_tag_externvar_t = 32768, /**< Extern or forward declaration */
tm_tag_macro_t = 65536, /**< Macro (without arguments) */
tm_tag_macro_with_arg_t = 131072, /**< Parameterized macro */
tm_tag_file_t = 262144, /**< File (Pseudo tag) - obsolete */
tm_tag_other_t = 524288, /**< Other (non C/C++/Java tag) */
tm_tag_max_t = 1048575 /**< Maximum value of TMTagType */
} TMTagType;
/*!
/**
Tag Attributes. Note that some attributes are available to file
pseudotags only. Attributes are useful for specifying as arguments
to the builtin sort and dedup functions, and during printing or writing
@ -81,311 +81,129 @@ typedef enum
*/
typedef enum
{
tm_tag_attr_none_t = 0, /*!< Undefined */
tm_tag_attr_name_t = 1, /*!< Tag Name */
tm_tag_attr_type_t = 2, /*!< Tag Type */
tm_tag_attr_file_t = 4, /*!< File in which tag exists */
tm_tag_attr_line_t = 8, /*!< Line number of tag */
tm_tag_attr_pos_t = 16, /*!< Byte position of tag in the file (Obsolete) */
tm_tag_attr_scope_t = 32, /*!< Scope of the tag */
tm_tag_attr_inheritance_t = 64, /*!< Parent classes */
tm_tag_attr_arglist_t = 128, /*!< Argument list */
tm_tag_attr_local_t = 256, /*!< If it has local scope */
tm_tag_attr_time_t = 512, /*!< Modification time (File tag only) */
tm_tag_attr_vartype_t = 1024, /*!< Variable Type */
tm_tag_attr_access_t = 2048, /*!< Access type (public/protected/private) */
tm_tag_attr_impl_t = 4096, /*!< Implementation (e.g. virtual) */
tm_tag_attr_lang_t = 8192, /*!< Language (File tag only) */
tm_tag_attr_inactive_t = 16384, /*!< Inactive file (File tag only) */
tm_tag_attr_pointer_t = 32768, /*!< Pointer type */
tm_tag_attr_max_t = 65535 /*!< Maximum value */
tm_tag_attr_none_t = 0, /**< Undefined */
tm_tag_attr_name_t = 1, /**< Tag Name */
tm_tag_attr_type_t = 2, /**< Tag Type */
tm_tag_attr_file_t = 4, /**< File in which tag exists */
tm_tag_attr_line_t = 8, /**< Line number of tag */
tm_tag_attr_pos_t = 16, /**< Byte position of tag in the file (Obsolete) */
tm_tag_attr_scope_t = 32, /**< Scope of the tag */
tm_tag_attr_inheritance_t = 64, /**< Parent classes */
tm_tag_attr_arglist_t = 128, /**< Argument list */
tm_tag_attr_local_t = 256, /**< If it has local scope */
tm_tag_attr_time_t = 512, /**< Modification time (File tag only) */
tm_tag_attr_vartype_t = 1024, /**< Variable Type */
tm_tag_attr_access_t = 2048, /**< Access type (public/protected/private) */
tm_tag_attr_impl_t = 4096, /**< Implementation (e.g. virtual) */
tm_tag_attr_lang_t = 8192, /**< Language (File tag only) */
tm_tag_attr_inactive_t = 16384, /**< Inactive file (File tag only, obsolete) */
tm_tag_attr_pointer_t = 32768, /**< Pointer type */
tm_tag_attr_max_t = 65535 /**< Maximum value */
} TMTagAttrType;
/*! Tag access type for C++/Java member functions and variables */
#define TAG_ACCESS_PUBLIC 'p' /*!< Public member */
#define TAG_ACCESS_PROTECTED 'r' /*!< Protected member */
#define TAG_ACCESS_PRIVATE 'v' /*!< Private member */
#define TAG_ACCESS_FRIEND 'f' /*!< Friend members/functions */
#define TAG_ACCESS_DEFAULT 'd' /*!< Default access (Java) */
#define TAG_ACCESS_UNKNOWN 'x' /*!< Unknown access type */
/** Tag access type for C++/Java member functions and variables */
#define TAG_ACCESS_PUBLIC 'p' /**< Public member */
#define TAG_ACCESS_PROTECTED 'r' /**< Protected member */
#define TAG_ACCESS_PRIVATE 'v' /**< Private member */
#define TAG_ACCESS_FRIEND 'f' /**< Friend members/functions */
#define TAG_ACCESS_DEFAULT 'd' /**< Default access (Java) */
#define TAG_ACCESS_UNKNOWN 'x' /**< Unknown access type */
/*! Tag implementation type for functions */
#define TAG_IMPL_VIRTUAL 'v' /*!< Virtual implementation */
#define TAG_IMPL_UNKNOWN 'x' /*!< Unknown implementation */
/** Tag implementation type for functions */
#define TAG_IMPL_VIRTUAL 'v' /**< Virtual implementation */
#define TAG_IMPL_UNKNOWN 'x' /**< Unknown implementation */
/*!
/**
This structure holds all information about a tag, including the file
pseudo tag. It should always be created indirectly with one of the tag
creation functions such as tm_source_file_parse() or tm_tag_new_from_file().
Once created, they can be sorted, deduped, etc. using functions such as
tm_tags_custom_sort(), tm_tags_sort(), tm_tags_dedup() and tm_tags_custom_dedup()
tm_tags_sort() or tm_tags_dedup()
*/
typedef struct _TMTag
{
char *name; /*!< Name of tag */
TMTagType type; /*!< Tag Type */
union
{
/*! These are *real* tag attributes */
struct
{
TMSourceFile *file; /*!< File in which the tag occurs */
gulong line; /*!< Line number of the tag */
gboolean local; /*!< Is the tag of local scope */
guint pointerOrder;
char *arglist; /*!< Argument list (functions/prototypes/macros) */
char *scope; /*!< Scope of tag */
char *inheritance; /*!< Parent classes */
char *var_type; /*!< Variable type (maps to struct for typedefs) */
char access; /*!< Access type (public/protected/private/etc.) */
char impl; /*!< Implementation (e.g. virtual) */
} entry;
/*! These are pseudo tag attributes representing a file */
struct
{
time_t timestamp; /*!< Time of parsing of the file */
langType lang; /*!< Programming language of the file */
gboolean inactive; /*!< Whether this file is to be parsed */
} file;
} atts;
gint refcount; /*!< the reference count of the tag */
char *name; /**< Name of tag */
TMTagType type; /**< Tag Type */
gint refcount; /* the reference count of the tag */
/** These are tag attributes */
TMSourceFile *file; /**< File in which the tag occurs; NULL for global tags */
gulong line; /**< Line number of the tag */
gboolean local; /**< Is the tag of local scope */
guint pointerOrder;
char *arglist; /**< Argument list (functions/prototypes/macros) */
char *scope; /**< Scope of tag */
char *inheritance; /**< Parent classes */
char *var_type; /**< Variable type (maps to struct for typedefs) */
char access; /**< Access type (public/protected/private/etc.) */
char impl; /**< Implementation (e.g. virtual) */
langType lang; /**< Programming language of the file */
} TMTag;
#ifdef GEANY_PRIVATE
extern const TMTagType TM_GLOBAL_TYPE_MASK;
typedef enum {
TM_FILE_FORMAT_TAGMANAGER,
TM_FILE_FORMAT_PIPE,
TM_FILE_FORMAT_CTAGS
} TMFileFormat;
/*
Prototype for user-defined tag comparison function. This is the type
of argument that needs to be passed to tm_tags_sort_custom() and
tm_tags_dedup_custom(). The function should take two void pointers,
cast them to (TMTag **) and return 0, 1 or -1 depending on whether the
first tag is equal to, greater than or less than the second tag.
*/
typedef int (*TMTagCompareFunc) (const void *ptr1, const void *ptr2);
/* The GType for a TMTag */
#define TM_TYPE_TAG (tm_tag_get_type())
/* Gets the GType for a TMTag */
GType tm_tag_get_type(void) G_GNUC_CONST;
/*
Initializes a TMTag structure with information from a tagEntryInfo struct
used by the ctags parsers. Note that the TMTag structure must be malloc()ed
before calling this function. This function is called by tm_tag_new() - you
should not need to call this directly.
\param tag The TMTag structure to initialize
\param file Pointer to a TMSourceFile struct (it is assigned to the file member)
\param tag_entry Tag information gathered by the ctags parser
\return TRUE on success, FALSE on failure
*/
gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry);
/*
Initializes an already malloc()ed TMTag structure by reading a tag entry
line from a file. The structure should be allocated beforehand.
\param tag The TMTag structure to populate
\param file The TMSourceFile struct (assigned to the file member)
\param fp FILE pointer from where the tag line is read
\return TRUE on success, FALSE on FAILURE
*/
gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp);
/*
Same as tm_tag_init_from_file(), but using an alternative parser for PHP and
LaTeX global tags files.
*/
gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp);
/*
Same as tm_tag_init_from_file(), but parsing CTags tag file format
*/
gboolean tm_tag_init_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *fp);
/*
Creates a new tag structure from a tagEntryInfo pointer and a TMSOurceFile pointer
and returns a pointer to it.
\param file - Pointer to the TMSourceFile structure containing the tag
\param tag_entry Contains tag information generated by ctags
\return the new TMTag structure. This should be free()-ed using tm_tag_free()
*/
TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry);
/*
Same as tm_tag_new() except that the tag attributes are read from file.
\param mode langType to use for the tag.
*/
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode, TMFileFormat format);
/*
Writes tag information to the given FILE *.
\param tag The tag information to write.
\param file FILE pointer to which the tag information is written.
\param attrs Attributes to be written (bitmask).
\return TRUE on success, FALSE on failure.
*/
gboolean tm_tag_write(TMTag *tag, FILE *file, guint attrs);
/*
Inbuilt tag comparison function. Do not call directly since it needs some
static variables to be set. Always use tm_tags_sort() and tm_tags_dedup()
instead.
*/
int tm_tag_compare(const void *ptr1, const void *ptr2);
void tm_tags_remove_file_tags(TMSourceFile *source_file, GPtrArray *tags_array);
gboolean tm_tags_merge(GPtrArray *tags_array, gsize orig_len,
TMTagAttrType *sort_attributes, gboolean dedup);
GPtrArray *tm_tags_merge(GPtrArray *big_array, GPtrArray *small_array,
TMTagAttrType *sort_attributes, gboolean unref_duplicates);
/*
Sort an array of tags on the specified attribuites using the inbuilt comparison
function.
\param tags_array The array of tags to be sorted
\param sort_attributes Attributes to be sorted on (int array terminated by 0)
\param dedup Whether to deduplicate the sorted array
\return TRUE on success, FALSE on failure
*/
gboolean tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean dedup);
gboolean tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes,
gboolean dedup, gboolean unref_duplicates);
/*
This function should be used whenever more involved sorting is required. For this,
you need to write a function as per the prototype of TMTagCompareFunc() and pass
the function as a parameter to this function.
\param tags_array Array of tags to be sorted
\param compare_func A function which takes two pointers to (TMTag *)s and returns
0, 1 or -1 depending on whether the first value is equal to, greater than or less that
the second
\param dedup Whether to deduplicate the sorted array. Note that the same comparison
function will be used
\return TRUE on success, FALSE on failure
*/
gboolean tm_tags_custom_sort(GPtrArray *tags_array, TMTagCompareFunc compare_func, gboolean dedup);
/*
This function will extract the tags of the specified types from an array of tags.
The returned value is a GPtrArray which should be free-d with a call to
g_ptr_array_free(array, TRUE). However, do not free the tags themselves since they
are not duplicated.
\param tags_array The original array of tags
\param tag_types - The tag types to extract. Can be a bitmask. For example, passing
(tm_tag_typedef_t | tm_tag_struct_t) will extract all typedefs and structures from
the original array.
\return an array of tags (NULL on failure)
*/
GPtrArray *tm_tags_extract(GPtrArray *tags_array, guint tag_types);
/*
Removes NULL tag entries from an array of tags. Called after tm_tags_dedup() and
tm_tags_custom_dedup() since these functions substitute duplicate entries with NULL
\param tags_array Array of tags to dedup
\return TRUE on success, FALSE on failure
*/
gboolean tm_tags_prune(GPtrArray *tags_array);
/*
Deduplicates an array on tags using the inbuilt comparison function based on
the attributes specified. Called by tm_tags_sort() when dedup is TRUE.
\param tags_array Array of tags to dedup.
\param sort_attributes Attributes the array is sorted on. They will be deduped
on the same criteria.
\return TRUE on success, FALSE on failure
*/
gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes);
gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates);
/*
This is a more powerful form of tm_tags_dedup() since it can accomodate user
defined comparison functions. Called by tm_tags_custom_sort() is dedup is TRUE.
\param tags_array Array of tags to dedup.
\compare_function Comparison function
\return TRUE on success, FALSE on FAILURE
\sa TMTagCompareFunc
*/
gboolean tm_tags_custom_dedup(GPtrArray *tags_array, TMTagCompareFunc compare_func);
/*
Returns a pointer to the position of the first matching tag in a (sorted) tags array.
The passed array of tags should be already sorted by name for optimal performance. If
\c tags_array_sorted is set to FALSE, it may be unsorted but the lookup will be slower.
\param tags_array Tag array (may be sorted on name)
\param name Name of the tag to locate.
\param partial If TRUE, matches the first part of the name instead of doing exact match.
\param tags_array_sorted If TRUE, the passed \c tags_array is sorted by name so it can be
searched with binary search. Otherwise it is searched linear which is obviously slower.
\param tagCount Return location of the matched tags.
*/
TMTag **tm_tags_find(const GPtrArray *tags_array, const char *name,
gboolean partial, gboolean tags_array_sorted, int * tagCount);
gboolean partial, gboolean tags_array_sorted, guint * tagCount);
/*
Completely frees an array of tags.
\param tags_array Array of tags to be freed.
\param free_array Whether the GptrArray is to be freed as well.
*/
void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all);
#if 0
/*
Destroys a TMTag structure, i.e. frees all elements except the tag itself.
\param tag The TMTag structure to destroy
\sa tm_tag_free()
*/
void tm_tag_destroy(TMTag *tag);
const TMTag *tm_get_current_tag(GPtrArray *file_tags, const gulong line, const TMTagType tag_types);
/*
Destroys all data in the tag and frees the tag structure as well.
\param tag Pointer to a TMTag structure
*/
void tm_tag_free(gpointer tag);
#endif
/*
Drops a reference from a TMTag. If the reference count reaches 0, this function
destroys all data in the tag and frees the tag structure as well.
\param tag Pointer to a TMTag structure
*/
void tm_tag_unref(TMTag *tag);
/*
Adds a reference to a TMTag.
\param tag Pointer to a TMTag structure
\return the passed-in TMTag
*/
TMTag *tm_tag_ref(TMTag *tag);
/*
Returns the type of tag as a string
\param tag The tag whose type is required
*/
#ifdef TM_DEBUG /* various debugging functions */
const char *tm_tag_type_name(const TMTag *tag);
/*
Returns the TMTagType given the name of the type. Reverse of tm_tag_type_name.
\param tag_name Name of the tag type
*/
TMTagType tm_tag_name_type(const char* tag_name);
/*
Prints information about a tag to the given file pointer.
\param tag The tag whose info is required.
\fp The file pointer of teh file to print the info to.
*/
void tm_tag_print(TMTag *tag, FILE *fp);
/*
Prints info about all tags in the array to the given file pointer.
*/
void tm_tags_array_print(GPtrArray *tags, FILE *fp);
/*
Returns the depth of tag scope (useful for finding tag hierarchy
*/
gint tm_tag_scope_depth(const TMTag *t);
#endif /* TM_DEBUG */
#endif /* GEANY_PRIVATE */
#ifdef __cplusplus

View File

@ -12,27 +12,25 @@
#include "tm_tag.h"
#include "tm_workspace.h"
#include "tm_work_object.h"
#include "tm_source_file.h"
#ifdef GEANY_PRIVATE
#include "tm_file_entry.h"
#include "tm_parser.h"
#endif /* GEANY_PRIVATE */
/*! \mainpage Introduction
\section Introduction
/** @mainpage Introduction
@section Introduction
TagManager is a library and a set of utility programs which can be integrated into
Integrated Development Environments to provide features such as code completion,
calltips, etc. Tag Manager is based on <a href="http://ctags.sourceforge.net">
Exuberent Ctags</a> with some added features.
\section Licence
@section Licence
TagManager is <a href="http://www.gnu.org/philosophy/free-sw.html">free software</a>,
licenced under the <a href="http://www.gnu.org/licenses/gpl.html">GPL</a>. You can only
use it with free software (GPL compatible) projects. This is chiefly because it uses
code from ctags which is under GPL.
*/
/*! \file
/** @file
Include this file in all programs using the tag manager library. Including this
automatically includes all the necessary files, namely, tm_tag.h, tm_source_file.h
and tm_workspace.h

View File

@ -1,298 +0,0 @@
/*
*
* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
*/
/**
* @file tm_work_object.h
* A TMWorkObject structure is the base class for TMSourceFile.
*/
#include "general.h" /* must always come first */
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <glib/gstdio.h>
#ifdef G_OS_WIN32
# define VC_EXTRALEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h> /* for GetFullPathName */
#endif
#include "tm_tag.h"
#include "tm_work_object.h"
static GPtrArray *s_work_object_subclasses = NULL;
static int get_path_max(const char *path)
{
#ifdef PATH_MAX
return PATH_MAX;
#else
int path_max = pathconf(path, _PC_PATH_MAX);
if (path_max <= 0)
path_max = 4096;
return path_max;
#endif
}
#ifdef G_OS_WIN32
/* realpath implementation for Windows found at http://bugzilla.gnome.org/show_bug.cgi?id=342926
* this one is better than e.g. liberty's lrealpath because this one uses Win32 API and works
* with special chars within the filename */
static char *realpath (const char *pathname, char *resolved_path)
{
int size;
if (resolved_path != NULL)
{
int path_max = get_path_max(pathname);
size = GetFullPathNameA (pathname, path_max, resolved_path, NULL);
if (size > path_max)
return NULL;
else
return resolved_path;
}
else
{
size = GetFullPathNameA (pathname, 0, NULL, NULL);
resolved_path = g_new0 (char, size);
GetFullPathNameA (pathname, size, resolved_path, NULL);
return resolved_path;
}
}
#endif
gchar *tm_get_real_path(const gchar *file_name)
{
if (file_name)
{
gsize len = get_path_max(file_name) + 1;
gchar *path = g_malloc0(len);
if (realpath(file_name, path))
return path;
else
g_free(path);
}
return NULL;
}
guint tm_work_object_register(GFreeFunc free_func, TMUpdateFunc update_func, TMFindFunc find_func)
{
TMWorkObjectClass *object_class;
if (NULL == s_work_object_subclasses)
{
s_work_object_subclasses = g_ptr_array_new();
object_class = g_new(TMWorkObjectClass, 1);
object_class->free_func = tm_work_object_free;
object_class->update_func = NULL;
object_class->find_func = NULL;
g_ptr_array_add(s_work_object_subclasses, object_class);
}
object_class = g_new(TMWorkObjectClass, 1);
object_class->free_func = free_func;
object_class->update_func = update_func;
object_class->find_func = find_func;
g_ptr_array_add(s_work_object_subclasses, object_class);
return (s_work_object_subclasses->len - 1);
}
gboolean tm_work_object_init(TMWorkObject *work_object, guint type, const char *file_name
, gboolean create)
{
struct stat s;
int status;
if (file_name != NULL)
{
if (0 != (status = g_stat(file_name, &s)))
{
if (create)
{
FILE *f;
if (NULL == (f = g_fopen(file_name, "a+")))
{
g_warning("Unable to create file %s", file_name);
return FALSE;
}
fclose(f);
status = g_stat(file_name, &s);
}
}
if (0 != status)
{
/* g_warning("Unable to stat %s", file_name);*/
return FALSE;
}
if (!S_ISREG(s.st_mode))
{
g_warning("%s: Not a regular file", file_name);
return FALSE;
}
work_object->file_name = tm_get_real_path(file_name);
work_object->short_name = strrchr(work_object->file_name, '/');
if (work_object->short_name)
++ work_object->short_name;
else
work_object->short_name = work_object->file_name;
}
else
{
work_object->file_name = NULL;
work_object->short_name = NULL;
}
work_object->type = type;
work_object->parent = NULL;
work_object->analyze_time = 0;
work_object->tags_array = NULL;
return TRUE;
}
/*
time_t tm_get_file_timestamp(const char *file_name)
{
struct stat s;
g_return_val_if_fail(file_name, 0);
if (0 != g_stat(file_name, &s))
{
return (time_t) 0;
}
else
return s.st_mtime;
}
gboolean tm_work_object_is_changed(TMWorkObject *work_object)
{
return (gboolean) (work_object->analyze_time < tm_get_file_timestamp(work_object->file_name));
}
*/
TMWorkObject *tm_work_object_new(guint type, const char *file_name, gboolean create)
{
TMWorkObject *work_object = g_new(TMWorkObject, 1);
if (!tm_work_object_init(work_object, type, file_name, create))
{
g_free(work_object);
return NULL;
}
return work_object;
}
void tm_work_object_destroy(TMWorkObject *work_object)
{
if (work_object)
{
g_free(work_object->file_name);
if (work_object->tags_array)
g_ptr_array_free(work_object->tags_array, TRUE);
}
}
void tm_work_object_free(gpointer work_object)
{
if (NULL != work_object)
{
TMWorkObject *w = (TMWorkObject *) work_object;
if ((w->type > 0) && (w->type < s_work_object_subclasses->len) &&
(s_work_object_subclasses->pdata[w->type] != NULL))
{
GFreeFunc free_func =
((TMWorkObjectClass *)s_work_object_subclasses->pdata[w->type])->free_func;
if (NULL != free_func)
free_func(work_object);
return;
}
tm_work_object_destroy(w);
g_free(work_object);
}
}
void tm_work_object_write_tags(TMWorkObject *work_object, FILE *file, guint attrs)
{
if (NULL != work_object->tags_array)
{
guint i;
for (i=0; i < work_object->tags_array->len; ++i)
tm_tag_write((TMTag *) g_ptr_array_index(work_object->tags_array, i)
, file, (TMTagAttrType) attrs);
}
}
gboolean tm_work_object_update(TMWorkObject *work_object, gboolean force
, gboolean recurse, gboolean update_parent)
{
if ((NULL != work_object) && (work_object->type > 0) &&
(work_object->type < s_work_object_subclasses->len) &&
(s_work_object_subclasses->pdata[work_object->type] != NULL))
{
TMUpdateFunc update_func =
((TMWorkObjectClass *)s_work_object_subclasses->pdata[work_object->type])->update_func;
if (NULL != update_func)
return update_func(work_object, force, recurse, update_parent);
}
return FALSE;
}
TMWorkObject *tm_work_object_find(TMWorkObject *work_object, const char *file_name
, gboolean name_only)
{
if ((NULL != work_object) && (work_object->type > 0) &&
(work_object->type < s_work_object_subclasses->len) &&
(s_work_object_subclasses->pdata[work_object->type] != NULL))
{
TMFindFunc find_func =
((TMWorkObjectClass *)s_work_object_subclasses->pdata[work_object->type])->find_func;
if (NULL == find_func)
{
if (name_only)
{
const char *short_name = strrchr(file_name, '/');
if (short_name)
++ short_name;
else
short_name = file_name;
if (0 == strcmp(work_object->short_name, short_name))
return work_object;
else
return NULL;
}
else
{
char *path = tm_get_real_path(file_name);
int cmp = strcmp(work_object->file_name, file_name);
g_free(path);
if (0 == cmp)
return work_object;
else
return NULL;
}
}
else
return find_func(work_object, file_name, name_only);
}
return NULL;
}
void tm_work_object_dump(const TMWorkObject *w)
{
if (w)
{
fprintf(stderr, "%s", w->file_name);
if (w->parent)
fprintf(stderr, " <- %s\n", w->parent->file_name);
else
fprintf(stderr, " <- NULL\n");
}
}

View File

@ -1,191 +0,0 @@
/*
*
* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
*/
#ifndef TM_WORK_OBJECT_H
#define TM_WORK_OBJECT_H
#include <stdio.h>
#include <time.h>
#include <glib.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Macro to cast a pointer to (TMWorkObject *) */
#define TM_WORK_OBJECT(work_object) ((TMWorkObject *) work_object)
/*!
A TMWorkObject structure is the base class for TMSourceFile.
This struct contains data common to all work objects, namely, a file name,
time when the file was analyzed (for caching) and an array of tags which
should be populated when the object is analyzed.
*/
typedef struct TMWorkObject
{
guint type; /*!< The type of object. Can be a source file or a project */
char *file_name; /*!< Full file name (inc. path) of the work object */
char *short_name; /*!< Just the name of the file (without the path) */
struct TMWorkObject *parent;
time_t analyze_time; /*!< UNUSED Time when the object was last analyzed */
GPtrArray *tags_array; /*!< Tags obtained by parsing the object */
} TMWorkObject;
/*!
Given a file name, returns a newly allocated string containing the realpath()
of the file.
\param file_name The original file_name
\return A newly allocated string containing the real path to the file. NULL if none is available.
*/
gchar *tm_get_real_path(const gchar *file_name);
/*!
Deallocates a work object and it's component structures. The user can call this
function directly since it will automatically call the correct deallocator function
of the derived class if required.
\param work_object Pointer to a work object or an object derived from it.
*/
void tm_work_object_free(gpointer work_object);
#ifdef GEANY_PRIVATE
/* Evaluates to X is X is defined, else evaluates to Y */
#define FALLBACK(X,Y) (X)?(X):(Y)
#define TM_OBJECT_TYPE(work_object) ((TMWorkObject *) work_object)->type /*< Type of the work object */
#define TM_OBJECT_FILE(work_object) ((TMWorkObject *) work_object)->file_name /*< File name of the work object */
#define TM_OBJECT_TAGS(work_object) ((TMWorkObject *) work_object)->tags_array /*< Tag array of the work object */
/* Prototype of the update function required to be written by all classes
derived from TMWorkObject. The function should take a pointer to the
object and a flag indicating whether the cache should be ignored, and
update the object's tag array accordingly.
\sa tm_work_object_update(), tm_workspace_update(),
tm_source_file_update().
*/
typedef gboolean (*TMUpdateFunc) (TMWorkObject *work_object, gboolean force
, gboolean recurse, gboolean update_parent);
/* Prototype of the find function required to be written by all classed
derived from TMWorkObject. The function should take a pointer to the work
object and a file name and return a pointer to the work object corresponding
to the file name if the file is part of the object, and NULL otherwise.
\sa tm_work_object_find()
*/
typedef TMWorkObject *(*TMFindFunc) (TMWorkObject *work_object, const char *file_name
, gboolean name_only);
/*
Contains pointers to functions necessary to handle virtual function calls
correctly. To create a new object derived from TMWorkObject, you
need to write the three functions specified as the members of this class and
register your class before first use using tm_work_object_register()
*/
typedef struct _TMWorkObjectClass
{
GFreeFunc free_func; /* Function to free the derived object */
TMUpdateFunc update_func; /* Function to update the derived object */
TMFindFunc find_func; /* Function to locate contained work objects */
} TMWorkObjectClass;
/*
Initializes the work object structure. This function should be called by the
initialization routine of the derived classes to ensure that the base members
are initialized properly. The library user should not have to call this under
any circumstance.
\param work_object The work object to be initialized.
\param type The type of the work object obtained by registering the derived class.
\param file_name The name of the file corresponding to the work object.
\param create Whether to create the file if it doesn't exist.
\return TRUE on success, FALSE on failure.
\sa tm_work_object_register()
*/
gboolean tm_work_object_init(TMWorkObject *work_object, guint type, const char *file_name
, gboolean create);
/*
Initializes a new TMWorkObject structure and returns a pointer to it. You shouldn't
have to call this function.
\return NULL on failure
\sa tm_source_file_new()
*/
TMWorkObject *tm_work_object_new(guint type, const char *file_name, gboolean create);
/*
Utility function - Given a file name, returns the timestamp of modification.
\param file_name Full path to the file.
\return Timestamp of the file's modification time. 0 on failure.
*/
time_t tm_get_file_timestamp(const char *file_name);
/*
Destroys a work object's data without freeing the structure itself. It should
be called by the deallocator function of classes derived from TMWorkObject. The
user shouldn't have to call this function.
*/
void tm_work_object_destroy(TMWorkObject *work_object);
/*
This function should be called exactly once by all classes derived from TMWorkObject,
since it supplies a unique ID on each call and stores the functions to call for
updation and deallocation of objects of the type allocated. The user should not
have to use this function unless he/she wants to create a new class derived from
TMWorkObject.
\param free_func The function to call to free the derived object.
\param update_func The function to call to update the derived object.
\return A unique ID for the derived class.
\sa TMSourceFile
*/
guint tm_work_object_register(GFreeFunc free_func, TMUpdateFunc update_func, TMFindFunc find_func);
/*
Writes the tags for the work object to the file specified.
\param work_object The work object whose tags need to be written.
\param file The file to which the tags are to be written.
\param attrs The attributes to write (Can be a bitmask).
*/
void tm_work_object_write_tags(TMWorkObject *work_object, FILE *file, guint attrs);
/*
Updates the tags array if necessary. Automatically calls the update function
of the type to which the object belongs.
\param work_object Pointer to a work object or an object derived from it.
\param force Whether the cache is to be ignored.
\param recurse Whether to recurse into child work objects (for workspace).
\param update_parent If set to TRUE, calls the update function of the parent if required.
If you are calling this function, you should set this to TRUE.
\return TRUE on success, FALSE on failure.
\sa tm_source_file_update()
*/
gboolean tm_work_object_update(TMWorkObject *work_object, gboolean force
, gboolean recurse, gboolean update_parent);
/*
Finds the work object corresponding to the file name passed and returns a pointer
to it. If not found, returns NULL. This is a virtual function which automatically
calls the registered find function of teh derived object.
\sa TMFindFunc
*/
TMWorkObject *tm_work_object_find(TMWorkObject *work_object, const char *file_name
, gboolean name_only);
/* Dumps the contents of a work object - useful for debugging */
void tm_work_object_dump(const TMWorkObject *w);
#endif /* GEANY_PRIVATE */
#ifdef __cplusplus
}
#endif
#endif /* TM_WORK_OBJECT_H */

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
#include <glib.h>
#include "tm_work_object.h"
#include "tm_tag.h"
#ifdef __cplusplus
extern "C"
@ -21,166 +21,63 @@ extern "C"
#endif
/*! The Tag Manager Workspace. This is a singleton work object containing a list
of work objects - individual source files. There is also a global tag list
/** The Tag Manager Workspace. This is a singleton object containing a list
of individual source files. There is also a global tag list
which can be loaded or created. This contains global tags gleaned from
/usr/include, etc. and should be used for autocompletion, calltips, etc.
*/
typedef struct
{
TMWorkObject work_object; /*!< The parent work object */
GPtrArray *global_tags; /*!< Global tags loaded at startup */
GPtrArray *work_objects; /*!< An array of TMWorkObject pointers */
GPtrArray *global_tags; /**< Global tags loaded at startup */
GPtrArray *source_files; /**< An array of TMSourceFile pointers */
GPtrArray *tags_array; /**< Sorted tags from all source files
(just pointers to source file tags, the tag objects are owned by the source files) */
GPtrArray *typename_array; /* Typename tags for syntax highlighting (pointers owned by source files) */
} TMWorkspace;
/*! Adds a work object (source file) to the workspace.
\param work_object The work object to add to the workspace.
\return TRUE on success, FALSE on failure (e.g. object already exixts).
*/
gboolean tm_workspace_add_object(TMWorkObject *work_object);
/*! Removes a member object from the workspace if it exists.
\param work_object Pointer to the work object to be removed.
\param do_free Whether the work object is to be freed as well.
\param update Whether to update workspace objects.
\return TRUE on success, FALSE on failure (e.g. the work object does not exist).
*/
gboolean tm_workspace_remove_object(TMWorkObject *work_object, gboolean do_free, gboolean update);
void tm_workspace_add_source_file(TMSourceFile *source_file);
void tm_workspace_remove_source_file(TMSourceFile *source_file);
void tm_workspace_add_source_files(GPtrArray *source_files);
void tm_workspace_remove_source_files(GPtrArray *source_files);
#ifdef GEANY_PRIVATE
/* Since TMWorkspace is a singleton, you should not create multiple
workspaces, but get a pointer to the workspace whenever required. The first
time a pointer is requested, or a work object is added to the workspace,
a workspace is created. Subsequent calls to the function will return the
created workspace.
*/
const TMWorkspace *tm_get_workspace(void);
/* Given a file name, returns a pointer to the object if the object's file
name is same as the passed file name, otherwise retruns NULL. This is an
overloaded version of tm_work_object_find().
\param work_object Pointer to the workspace.
\param file_name The name of the file to search.
\param name_only If you want to match just the name and not the full path.
\return Pointer to the work object matching the file name (NULL if not found).
\sa tm_work_object_find().
*/
TMWorkObject *tm_workspace_find_object(TMWorkObject *work_object, const char *file_name
,gboolean name_only);
/* Loads the global tag list from the specified file. The global tag list should
have been first created using tm_workspace_create_global_tags().
\param tags_file The file containing global tags.
\return TRUE on success, FALSE on failure.
\sa tm_workspace_create_global_tags()
*/
gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode);
/*gboolean tm_workspace_load_global_tags(const char *tags_file);*/
/* Creates a list of global tags. Ideally, this should be created once during
installations so that all users can use the same file. Thsi is because a full
scale global tag list can occupy several megabytes of disk space.
\param pre_process The pre-processing command. This is executed via system(),
so you can pass stuff like 'gcc -E -dD -P `gnome-config --cflags gnome`'.
\param includes Include files to process. Wildcards such as '/usr/include/a*.h'
are allowed.
\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.
*/
gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes,
int includes_count, const char *tags_file, int lang);
int includes_count, const char *tags_file, int lang);
/* 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
this is called automatically by tm_workspace_update().
*/
void tm_workspace_recreate_tags_array(void);
const GPtrArray *tm_workspace_find(const char *name, TMTagType type, TMTagAttrType *attrs,
gboolean partial, langType lang);
/* Calls tm_work_object_update() for all workspace member work objects.
Use if you want to globally refresh the workspace.
\param workspace Pointer to the workspace.
\param force Whether the cache should be ignored.
\param recurse If set to TRUE, updates all children before updating the tag image.
\param update_parent This parameter is ignored for the workspace since it is at the
top of the work object hierarchy.
\sa tm_work_object_update(), tm_source_file_update()
*/
gboolean tm_workspace_update(TMWorkObject *workspace, gboolean force
, gboolean recurse, gboolean update_parent);
/* Dumps the workspace tree - useful for debugging */
void tm_workspace_dump(void);
/* Returns all matching tags found in the workspace.
\param name The name of the tag to find.
\param type The tag types to return (TMTagType). Can be a bitmask.
\param attrs The attributes to sort and dedup on (0 terminated integer array).
\param partial Whether partial match is allowed.
\param lang Specifies the language(see the table in parsers.h) of the tags to be found,
-1 for all
\return Array of matching tags. Do not free() it since it is a static member.
*/
const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs
, gboolean partial, langType lang);
/* Returns all matching tags found in the workspace.
\param name The name of the tag to find.
\param scope The scope name of the tag to find, or NULL.
\param type The tag types to return (TMTagType). Can be a bitmask.
\param attrs The attributes to sort and dedup on (0 terminated integer array).
\param partial Whether partial match is allowed.
\param lang Specifies the language(see the table in parsers.h) of the tags to be found,
-1 for all
\return Array of matching tags. Do not free() it since it is a static member.
*/
const GPtrArray *
tm_workspace_find_scoped (const char *name, const char *scope, gint type,
TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search);
tm_workspace_find_scoped (const char *name, const char *scope, TMTagType type,
TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search);
/* Returns all matching members tags found in given struct/union/class name.
\param name Name of the struct/union/class.
\param file_tags A GPtrArray of edited file TMTag pointers (for search speedup, can be NULL).
\return A GPtrArray of TMTag pointers to struct/union/class members */
const GPtrArray *tm_workspace_find_scope_members(const GPtrArray *file_tags,
const char *scope_name,
gboolean find_global,
gboolean no_definitions);
const GPtrArray *
tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name,
gboolean search_global);
void tm_workspace_add_source_file_noupdate(TMSourceFile *source_file);
/* Returns TMTag which "own" given line
\param line Current line in edited file.
\param file_tags A GPtrArray of edited file TMTag pointers.
\param tag_types the tag types to include in the match
\return TMTag pointers to owner tag. */
const TMTag *tm_get_current_tag(GPtrArray *file_tags, const gulong line, const guint tag_types);
void tm_workspace_update_source_file_buffer(TMSourceFile *source_file, guchar* text_buf,
gsize buf_size);
/* Returns TMTag to function or method which "own" given line
\param line Current line in edited file.
\param file_tags A GPtrArray of edited file TMTag pointers.
\return TMTag pointers to owner function. */
const TMTag *tm_get_current_function(GPtrArray *file_tags, const gulong line);
void tm_workspace_free(void);
/* Returns a list of parent classes for the given class name
\param name Name of the class
\return A GPtrArray of TMTag pointers (includes the TMTag for the class) */
const GPtrArray *tm_workspace_get_parents(const gchar *name);
/* Frees the workspace structure and all child work objects. Use only when
exiting from the main program.
*/
void tm_workspace_free(gpointer workspace);
#ifdef TM_DEBUG
void tm_workspace_dump(void);
#endif /* TM_DEBUG */
/* Contains the id obtained by registering the TMWorkspace class as a child of
TMWorkObject.
\sa tm_work_object_register()
*/
extern guint workspace_class_id;
#endif /* GEANY_PRIVATE */

View File

@ -1,3 +1,3 @@
# format=tagmanager
FOO<EFBFBD>256<EFBFBD>0
FOOÌ128ÎFOOÖ0
FOO<EFBFBD>256<EFBFBD>0

View File

@ -1,6 +1,6 @@
# format=tagmanager
DigitÌ2048Ö0
DigitÌ128Í(byte value)ÎDigitÖ0
DigitÌ2048Ö0
MainÌ128Í()ÎTestÖ0Ïpublic void
TestÌ1Ö0
operator DigitÌ128Í(byte b)ÎDigitÖ0

View File

@ -1,6 +1,6 @@
# format=tagmanager
DigitÌ2048Ö0
DigitÌ128Í(byte value)ÎDigitÖ0
DigitÌ2048Ö0
MainÌ128Í()ÎTestÖ0Ïpublic void
TestÌ1Ö0
operator byteÌ128Í(Digit d)ÎDigitÖ0Ïpublic implicit

View File

@ -2,7 +2,7 @@
DataÌ1ÎProgramÖ0
InterfaceÌ2048Ö0
MyFuncÌ16ÎProgramÖ0
ProgramĚ256Ö0
ProgramÌ32ÎProgramÖ0
ProgramĚ256Ö0
contentsÌ64ÎDataÖ0
iÌ16384ÎProgramÖ0

View File

@ -1,7 +1,7 @@
# format=tagmanager
MainÌ128Í()ÎMainClassÖ0Ïpublic void
MainClassÌ1Ö0
PointĚ2048Ö0
PointÌ128Í(int p1, int p2)ÎPointÖ0
PointĚ2048Ö0
xÌ8ÎPointÖ0Ïint
yÌ8ÎPointÖ0Ïint

View File

@ -118,10 +118,8 @@ ctags_sources = set([
'tagmanager/ctags/vstring.c'])
tagmanager_sources = set([
'tagmanager/src/tm_file_entry.c',
'tagmanager/src/tm_source_file.c',
'tagmanager/src/tm_tag.c',
'tagmanager/src/tm_work_object.c',
'tagmanager/src/tm_workspace.c'])
scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
@ -555,7 +553,7 @@ def build(bld):
bld.install_files('${PREFIX}/include/geany/tagmanager', '''
tagmanager/src/tm_source_file.h
tagmanager/src/tm_tag.h
tagmanager/src/tm_tagmanager.h tagmanager/src/tm_work_object.h
tagmanager/src/tm_tagmanager.h
tagmanager/src/tm_workspace.h ''')
# Docs
base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'