Added global auto completion tags for PHP and LaTeX.

git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@475 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
Enrico Tröger 2006-06-24 14:42:56 +00:00
parent 3a435bf29e
commit 570793a6ef
15 changed files with 4301 additions and 565 deletions

View File

@ -8,7 +8,9 @@ EXTRA_DIST = \
geany.spec \
geany.glade \
geany.gladep \
global.tags \
data/global.tags \
data/global.tags \
data/latex.tags \
data/filetypes.*
uninstall-local:
@ -26,7 +28,9 @@ install-data-local:
done \
fi
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir); \
$(INSTALL_DATA) global.tags $(DESTDIR)$(pkgdatadir); \
$(INSTALL_DATA) data/global.tags $(DESTDIR)$(pkgdatadir); \
$(INSTALL_DATA) data/php.tags $(DESTDIR)$(pkgdatadir); \
$(INSTALL_DATA) data/latex.tags $(DESTDIR)$(pkgdatadir); \
$(INSTALL_DATA) COPYING $(DESTDIR)$(pkgdatadir)/GPL-2; \
for file in $(srcdir)/data/*; do \
if test -f $$file; then \

1327
data/latex.tags Normal file

File diff suppressed because it is too large Load Diff

2738
data/php.tags Normal file

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,8 @@
static style_set *types[GEANY_MAX_FILE_TYPES] = { NULL };
static gboolean global_c_tags_loaded = FALSE;
static gboolean global_php_tags_loaded = FALSE;
static gboolean global_latex_tags_loaded = FALSE;
/* simple wrapper function to print file errors in DEBUG mode */
@ -371,7 +373,8 @@ static void styleset_c_init(void)
// load global tags file for C autocompletion
if (! app->ignore_global_tags && ! global_c_tags_loaded)
{
tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "global.tags");
// 0 is the langType used in TagManager (see the table in tagmanager/parsers.h)
tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "global.tags", 0);
global_c_tags_loaded = TRUE;
}
}
@ -501,7 +504,9 @@ static void styleset_cpp_init(void)
// load global tags file for C autocompletion
if (! app->ignore_global_tags && ! global_c_tags_loaded)
{
tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "global.tags");
// 0 is the langType used in TagManager (see the table in tagmanager/parsers.h)
// C++ is a special case, here we use 0 to have C global tags in C++, too
tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "global.tags", 0);
global_c_tags_loaded = TRUE;
}
}
@ -725,6 +730,14 @@ static void styleset_latex_init(void)
styleset_get_wordchars(config, config_home, GEANY_FILETYPES_LATEX, GEANY_WORDCHARS);
filetypes_get_config(config, config_home, GEANY_FILETYPES_LATEX);
// load global tags file for LaTeX autocompletion
if (! app->ignore_global_tags && ! global_latex_tags_loaded)
{
// 8 is the langType used in TagManager (see the table in tagmanager/parsers.h)
tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "latex.tags", 8);
global_latex_tags_loaded = TRUE;
}
g_key_file_free(config);
g_key_file_free(config_home);
g_free(f);
@ -765,6 +778,14 @@ static void styleset_php_init(void)
styleset_get_wordchars(config, config_home, GEANY_FILETYPES_PHP, GEANY_WORDCHARS"$");
filetypes_get_config(config, config_home, GEANY_FILETYPES_PHP);
// load global tags file for PHP autocompletion
if (! app->ignore_global_tags && ! global_php_tags_loaded)
{
// 6 is the langType used in TagManager (see the table in tagmanager/parsers.h)
tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "php.tags", 6);
global_php_tags_loaded = TRUE;
}
g_key_file_free(config);
g_key_file_free(config_home);
g_free(f);

View File

@ -243,69 +243,7 @@ static long unsigned int updatePseudoTags (FILE *const fp)
* Tag file management
*/
static boolean isValidTagAddress (const char *const excmd)
{
boolean isValid = FALSE;
if (strchr ("/?", excmd [0]) != NULL)
isValid = TRUE;
else
{
char *address = xMalloc (strlen (excmd) + 1, char);
if (sscanf (excmd, "%[^;\n]", address) == 1 &&
strspn (address,"0123456789") == strlen (address))
isValid = TRUE;
eFree (address);
}
return isValid;
}
static boolean isCtagsLine (const char *const line)
{
enum fieldList { TAG, TAB1, SRC_FILE, TAB2, EXCMD, NUM_FIELDS };
boolean ok = FALSE; /* we assume not unless confirmed */
const size_t fieldLength = strlen (line) + 1;
char *const fields = xMalloc (NUM_FIELDS * fieldLength, char);
if (fields == NULL)
error (FATAL, "Cannot analyze tag file");
else
{
#define field(x) (fields + ((size_t) (x) * fieldLength))
const int numFields = sscanf (line, "%[^\t]%[\t]%[^\t]%[\t]%[^\r\n]",
field (TAG), field (TAB1), field (SRC_FILE),
field (TAB2), field (EXCMD));
/* There must be exactly five fields: two tab fields containing
* exactly one tab each, the tag must not begin with "#", and the
* file name should not end with ";", and the excmd must be
* accceptable.
*
* These conditions will reject tag-looking lines like:
* int a; <C-comment>
* #define LABEL <C-comment>
*/
if (numFields == NUM_FIELDS &&
strlen (field (TAB1)) == 1 &&
strlen (field (TAB2)) == 1 &&
field (TAG) [0] != '#' &&
field (SRC_FILE) [strlen (field (SRC_FILE)) - 1] != ';' &&
isValidTagAddress (field (EXCMD)))
ok = TRUE;
eFree (fields);
}
return ok;
}
static boolean isEtagsLine (const char *const line)
{
boolean result = FALSE;
if (line [0] == '\f')
result = (boolean) (line [1] == '\n' || line [1] == '\r');
return result;
}
static boolean isTagFile (const char *const filename)
{
@ -320,8 +258,6 @@ static boolean isTagFile (const char *const filename)
if (line == NULL)
ok = TRUE;
else
ok = (boolean) (isCtagsLine (line) || isEtagsLine (line));
fclose (fp);
}
return ok;
@ -389,32 +325,23 @@ extern void openTagFile (void)
"\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
TagFile.name);
if (Option.etags)
if (Option.append && fileExists)
{
TagFile.fp = fopen (TagFile.name, "r+");
if (TagFile.fp != NULL)
{
if (Option.append && fileExists)
TagFile.fp = fopen (TagFile.name, "a+b");
else
TagFile.fp = fopen (TagFile.name, "w+b");
}
else
{
if (Option.append && fileExists)
{
TagFile.fp = fopen (TagFile.name, "r+");
if (TagFile.fp != NULL)
{
TagFile.numTags.prev = updatePseudoTags (TagFile.fp);
fclose (TagFile.fp);
TagFile.fp = fopen (TagFile.name, "a+");
}
}
else
{
TagFile.fp = fopen (TagFile.name, "w");
if (TagFile.fp != NULL)
addPseudoTags ();
}
TagFile.numTags.prev = updatePseudoTags (TagFile.fp);
fclose (TagFile.fp);
TagFile.fp = fopen (TagFile.name, "a+");
}
}
else
{
TagFile.fp = fopen (TagFile.name, "w");
if (TagFile.fp != NULL)
addPseudoTags ();
}
if (TagFile.fp == NULL)
{
error (FATAL | PERROR, "cannot open tag file");
@ -446,338 +373,11 @@ static int replacementTruncate (const char *const name, const long size)
#endif
static void sortTagFile (void)
{
if (TagFile.numTags.added > 0L)
{
if (Option.sorted)
{
verbose ("sorting tag file\n");
#ifdef EXTERNAL_SORT
externalSortTags (TagsToStdout);
#else
internalSortTags (TagsToStdout);
#endif
}
else if (TagsToStdout)
catFile (tagFileName ());
}
if (TagsToStdout)
remove (tagFileName ()); /* remove temporary file */
}
static void resizeTagFile (const long newSize)
{
int result;
#ifdef USE_REPLACEMENT_TRUNCATE
result = replacementTruncate (TagFile.name, newSize);
#else
# ifdef HAVE_TRUNCATE
result = truncate (TagFile.name, (off_t) newSize);
# else
const int fd = open (TagFile.name, O_RDWR);
if (fd == -1)
result = -1;
else
{
# ifdef HAVE_FTRUNCATE
result = ftruncate (fd, (off_t) newSize);
# else
# ifdef HAVE_CHSIZE
result = chsize (fd, newSize);
# endif
# endif
close (fd);
}
# endif
#endif
if (result == -1)
fprintf (errout, "Cannot shorten tag file: errno = %d\n", errno);
}
static void writeEtagsIncludes (FILE *const fp)
{
if (Option.etagsInclude)
{
unsigned int i;
for (i = 0 ; i < stringListCount (Option.etagsInclude) ; ++i)
{
vString *item = stringListItem (Option.etagsInclude, i);
fprintf (fp, "\f\n%s,include\n", vStringValue (item));
}
}
}
extern void closeTagFile (const boolean resize)
{
long desiredSize, size;
if (Option.etags)
writeEtagsIncludes (TagFile.fp);
desiredSize = ftell (TagFile.fp);
fseek (TagFile.fp, 0L, SEEK_END);
size = ftell (TagFile.fp);
fclose (TagFile.fp);
if (resize && desiredSize < size)
{
DebugStatement (
debugPrintf (DEBUG_STATUS, "shrinking %s from %ld to %ld bytes\n",
TagFile.name, size, desiredSize); )
resizeTagFile (desiredSize);
}
sortTagFile ();
eFree (TagFile.name);
TagFile.name = NULL;
}
extern void beginEtagsFile (void)
{
TagFile.etags.fp = tempFile ("w+b", &TagFile.etags.name);
TagFile.etags.byteCount = 0;
}
extern void endEtagsFile (const char *const name)
{
const char *line;
fprintf (TagFile.fp, "\f\n%s,%ld\n", name, (long) TagFile.etags.byteCount);
if (TagFile.etags.fp != NULL)
{
rewind (TagFile.etags.fp);
while ((line = readLine (TagFile.vLine, TagFile.etags.fp)) != NULL)
fputs (line, TagFile.fp);
fclose (TagFile.etags.fp);
remove (TagFile.etags.name);
eFree (TagFile.etags.name);
TagFile.etags.fp = NULL;
TagFile.etags.name = NULL;
}
}
/*
* Tag entry management
*/
/* This function copies the current line out to a specified file. It has no
* effect on the fileGetc () function. During copying, any '\' characters
* are doubled and a leading '^' or trailing '$' is also quoted. End of line
* characters (line feed or carriage return) are dropped.
*/
static size_t writeSourceLine (FILE *const fp, const char *const line)
{
size_t length = 0;
const char *p;
/* Write everything up to, but not including, a line end character.
*/
for (p = line ; *p != '\0' ; ++p)
{
const int next = *(p + 1);
const int c = *p;
if (c == CRETURN || c == NEWLINE)
break;
/* If character is '\', or a terminal '$', then quote it.
*/
if (c == BACKSLASH || c == (Option.backward ? '?' : '/') ||
(c == '$' && (next == NEWLINE || next == CRETURN)))
{
putc (BACKSLASH, fp);
++length;
}
putc (c, fp);
++length;
}
return length;
}
/* Writes "line", stripping leading and duplicate white space.
*/
static size_t writeCompactSourceLine (FILE *const fp, const char *const line)
{
boolean lineStarted = FALSE;
size_t length = 0;
const char *p;
int c;
/* Write everything up to, but not including, the newline.
*/
for (p = line, c = *p ; c != NEWLINE && c != '\0' ; c = *++p)
{
if (lineStarted || ! isspace (c)) /* ignore leading spaces */
{
lineStarted = TRUE;
if (isspace (c))
{
int next;
/* Consume repeating white space.
*/
while (next = *(p+1) , isspace (next) && next != NEWLINE)
++p;
c = ' '; /* force space character for any white space */
}
if (c != CRETURN || *(p + 1) != NEWLINE)
{
putc (c, fp);
++length;
}
}
}
return length;
}
static int writeXrefEntry (const tagEntryInfo *const tag)
{
const char *const line =
readSourceLine (TagFile.vLine, tag->filePosition, NULL);
int length = fprintf (TagFile.fp, "%-20s %-10s %4lu %-14s ", tag->name,
tag->kindName, tag->lineNumber, tag->sourceFileName);
length += writeCompactSourceLine (TagFile.fp, line);
putc (NEWLINE, TagFile.fp);
++length;
return length;
}
/* Truncates the text line containing the tag at the character following the
* tag, providing a character which designates the end of the tag.
*/
static void truncateTagLine (char *const line, const char *const token,
const boolean discardNewline)
{
char *p = strstr (line, token);
if (p != NULL)
{
p += strlen (token);
if (*p != '\0' && ! (*p == '\n' && discardNewline))
++p; /* skip past character terminating character */
*p = '\0';
}
}
static int writeEtagsEntry (const tagEntryInfo *const tag)
{
int length;
if (tag->isFileEntry)
length = fprintf (TagFile.etags.fp, "\177%s\001%lu,0\n",
tag->name, tag->lineNumber);
else
{
long seekValue;
char *const line =
readSourceLine (TagFile.vLine, tag->filePosition, &seekValue);
if (tag->truncateLine)
truncateTagLine (line, tag->name, TRUE);
else
line [strlen (line) - 1] = '\0';
length = fprintf (TagFile.etags.fp, "%s\177%s\001%lu,%ld\n", line,
tag->name, tag->lineNumber, seekValue);
}
TagFile.etags.byteCount += length;
return length;
}
static int addExtensionFields (const tagEntryInfo *const tag)
{
const char* const kindKey = Option.extensionFields.kindKey ? "kind:" : "";
int length = fprintf (TagFile.fp, ";\"");
if (tag->kindName != NULL && (
Option.extensionFields.kindLong || tag->kind == '\0'))
length += fprintf (TagFile.fp, "\t%s%s", kindKey, tag->kindName);
else if (tag->kind != '\0' && (
! Option.extensionFields.kindLong || tag->kindName == NULL))
length += fprintf (TagFile.fp, "\t%s%c", kindKey, tag->kind);
if (Option.extensionFields.lineNumber)
length += fprintf (TagFile.fp, "\tline:%ld", tag->lineNumber);
if (Option.extensionFields.language && tag->language != NULL)
length += fprintf (TagFile.fp, "\tlanguage:%s", tag->language);
if (Option.extensionFields.scope &&
tag->extensionFields.scope [0] != NULL &&
tag->extensionFields.scope [1] != NULL)
length += fprintf (TagFile.fp, "\t%s:%s",
tag->extensionFields.scope [0],
tag->extensionFields.scope [1]);
if (Option.extensionFields.fileScope && tag->isFileScope)
length += fprintf (TagFile.fp, "\tfile:");
if (Option.extensionFields.inheritance &&
tag->extensionFields.inheritance != NULL)
length += fprintf (TagFile.fp, "\tinherits:%s",
tag->extensionFields.inheritance);
if (Option.extensionFields.access && tag->extensionFields.access != NULL)
length += fprintf (TagFile.fp, "\taccess:%s",
tag->extensionFields.access);
if (Option.extensionFields.implementation &&
tag->extensionFields.implementation != NULL)
length += fprintf (TagFile.fp, "\timplementation:%s",
tag->extensionFields.implementation);
if ((Option.extensionFields.argList) &&
(tag->extensionFields.arglist != NULL))
length += fprintf(TagFile.fp, "\targlist:%s", tag->extensionFields.arglist);
return length;
}
static int writePatternEntry (const tagEntryInfo *const tag)
{
char *const line = readSourceLine (TagFile.vLine, tag->filePosition, NULL);
const int searchChar = Option.backward ? '?' : '/';
boolean newlineTerminated;
int length = 0;
if (tag->truncateLine)
truncateTagLine (line, tag->name, FALSE);
newlineTerminated = (boolean) (line [strlen (line) - 1] == '\n');
length += fprintf (TagFile.fp, "%c^", searchChar);
length += writeSourceLine (TagFile.fp, line);
length += fprintf (TagFile.fp, "%s%c", newlineTerminated ? "$":"",
searchChar);
return length;
}
static int writeLineNumberEntry (const tagEntryInfo *const tag)
{
return fprintf (TagFile.fp, "%lu", tag->lineNumber);
}
static int writeCtagsEntry (const tagEntryInfo *const tag)
{
int length = fprintf (TagFile.fp, "%s\t%s\t",
tag->name, tag->sourceFileName);
if (tag->lineNumberEntry)
length += writeLineNumberEntry (tag);
else
length += writePatternEntry (tag);
if (includeExtensionFlags ())
length += addExtensionFields (tag);
length += fprintf (TagFile.fp, "\n");
return length;
}
extern void makeTagEntry (const tagEntryInfo *const tag)
{
@ -788,18 +388,8 @@ extern void makeTagEntry (const tagEntryInfo *const tag)
{
int length = 0;
DebugStatement ( debugEntry (tag); )
if (NULL != TagEntryFunction)
length = TagEntryFunction(tag);
else if (Option.xref)
{
if (! tag->isFileEntry)
length = writeXrefEntry (tag);
}
else if (Option.etags)
length = writeEtagsEntry (tag);
else
length = writeCtagsEntry (tag);
++TagFile.numTags.added;
rememberMaxLengths (strlen (tag->name), (size_t) length);

View File

@ -60,10 +60,11 @@ typedef struct _TMSourceFile
} TMSourceFile;
/*! Initializes a TMSourceFile structure from a file name. */
gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name, gboolean update);
gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name,
gboolean update, const char *name);
/*! Initializes a TMSourceFile structure and returns a pointer to it. */
TMWorkObject *tm_source_file_new(const char *file_name, gboolean update);
TMWorkObject *tm_source_file_new(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

View File

@ -174,9 +174,11 @@ gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_ent
\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
\param mode langType - if set to greater than 0, the alternative parser is used and mode represents
the langType to use for the tags
\return TRUE on success, FALSE on FAILURE
*/
gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp);
gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp, gint mode);
/*!
Creates a new tag structure from a tagEntryInfo pointer and a TMSOurceFile pointer
@ -190,7 +192,7 @@ TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry);
/*!
Same as tm_tag_new() except that the tag attributes are read from file
*/
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp);
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode);
/*!
Writes tag information to the given FILE *.

View File

@ -21,7 +21,7 @@
workspace, though, to use tag manager, unless you need things like global tags
and a place to store all current open projects and individual files. TMWorkspace
is derived from TMWorkObject.
The following example demonstrates the use of workspace functions to create global tags.
\include tm_global_tags.c
*/
@ -89,7 +89,8 @@ gboolean tm_workspace_remove_object(TMWorkObject *work_object, gboolean free);
\return TRUE on success, FALSE on failure.
\sa tm_workspace_create_global_tags()
*/
gboolean tm_workspace_load_global_tags(const char *tags_file);
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
@ -130,10 +131,12 @@ void tm_workspace_dump(void);
\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);
, gboolean partial, langType lang);
/*! Returns a list of parent classes for the given class name
\param name Name of the class

View File

@ -33,6 +33,26 @@
TclParser, \
ShParser
/*
langType of each parser
0 CParser
1 CppParser
2 JavaParser
3 MakefileParser
4 PascalParser
5 PerlParser
6 PhpParser
7 PythonParser
8 LaTeXParser
9 AsmParser
10 ConfParser
11 SqlParser
12 DocBookParser
13 CssParser
14 RubyParser
15 TclParser
16 ShParser
*/
#endif /* _PARSERS_H */
/* vi:set tabstop=8 shiftwidth=4: */

View File

@ -282,6 +282,6 @@ GList *tm_file_entry_list(TMFileEntry *entry, GList *files)
files = tm_file_entry_list((TMFileEntry *) tmp->data, files);
}
if (!files)
g_list_reverse(files);
files = g_list_reverse(files);
return files;
}

View File

@ -186,7 +186,7 @@ gboolean tm_project_add_file(TMProject *project, const char *file_name
}
if (NULL == source_file)
{
if (NULL == (source_file = tm_source_file_new(file_name, TRUE)))
if (NULL == (source_file = tm_source_file_new(file_name, TRUE, NULL)))
{
g_warning("Unable to create source file for file %s", file_name);
g_free(path);
@ -375,12 +375,12 @@ gboolean tm_project_open(TMProject *project, gboolean force)
tm_project_set_ignorelist(project);
if (NULL == (fp = fopen(project->work_object.file_name, "r")))
return FALSE;
while (NULL != (tag = tm_tag_new_from_file(source_file, fp)))
while (NULL != (tag = tm_tag_new_from_file(source_file, fp, 0)))
{
if (tm_tag_file_t == tag->type)
{
if (!(source_file = TM_SOURCE_FILE(
tm_source_file_new(tag->name, FALSE))))
tm_source_file_new(tag->name, FALSE, NULL))))
{
#ifdef TM_DEBUG
g_warning("Unable to create source file %s", tag->name);

View File

@ -26,7 +26,7 @@ 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)
, gboolean update, const char* name)
{
if (0 == source_file_class_id)
source_file_class_id = tm_work_object_register(tm_source_file_free
@ -39,7 +39,10 @@ gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name
if (FALSE == tm_work_object_init(&(source_file->work_object),
source_file_class_id, file_name, FALSE))
return FALSE;
source_file->lang = LANG_AUTO;
if (name == NULL)
source_file->lang = LANG_AUTO;
else
source_file->lang = getNamedLanguage(name);
source_file->inactive = FALSE;
if (NULL == LanguageTable)
{
@ -54,10 +57,10 @@ gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name
return TRUE;
}
TMWorkObject *tm_source_file_new(const char *file_name, gboolean update)
TMWorkObject *tm_source_file_new(const char *file_name, gboolean update, const char *name)
{
TMSourceFile *source_file = g_new(TMSourceFile, 1);
if (TRUE != tm_source_file_init(source_file, file_name, update))
if (TRUE != tm_source_file_init(source_file, file_name, update, name))
{
g_free(source_file);
return NULL;
@ -92,6 +95,7 @@ gboolean tm_source_file_parse(TMSourceFile *source_file)
{
const char *file_name;
gboolean status = TRUE;
int passCount = 0;
if ((NULL == source_file) || (NULL == source_file->work_object.file_name))
{
@ -99,9 +103,6 @@ gboolean tm_source_file_parse(TMSourceFile *source_file)
return FALSE;
}
#ifdef TM_DEBUG
g_message("Parsing %s", source_file->work_object.file_name);
#endif
file_name = source_file->work_object.file_name;
if (NULL == LanguageTable)
{
@ -111,43 +112,31 @@ gboolean tm_source_file_parse(TMSourceFile *source_file)
TagEntryFunction = tm_source_file_tags;
}
current_source_file = source_file;
if (LANG_AUTO == source_file->lang)
source_file->lang = getFileLanguage (file_name);
if (source_file->lang == LANG_IGNORE)
if (source_file->lang < 0 || ! LanguageTable [source_file->lang]->enabled)
return status;
while ((TRUE == status) && (passCount < 3))
{
#ifdef TM_DEBUG
g_warning("ignoring %s (unknown language)\n", file_name);
#endif
}
else if (! LanguageTable [source_file->lang]->enabled)
{
#ifdef TM_DEBUG
g_warning("ignoring %s (language disabled)\n", file_name);
#endif
}
else
{
int passCount = 0;
while ((TRUE == status) && (passCount < 3))
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 (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 ();
else if (LanguageTable [source_file->lang]->parser2 != NULL)
status = LanguageTable [source_file->lang]->parser2 (passCount);
fileClose ();
}
else
{
g_warning("Unable to open %s", file_name);
return FALSE;
}
++ passCount;
if (LanguageTable [source_file->lang]->parser != NULL)
LanguageTable [source_file->lang]->parser ();
else if (LanguageTable [source_file->lang]->parser2 != NULL)
status = LanguageTable [source_file->lang]->parser2 (passCount);
fileClose ();
}
return TRUE;
else
{
g_warning("Unable to open %s", file_name);
return FALSE;
}
++ passCount;
}
return status;
}

View File

@ -197,10 +197,12 @@ TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry)
TAG_FREE(tag);
return NULL;
}
// if I don't do the following, tag->atts.file.lang has an undefined value, which is quite bad
tag->atts.file.lang = file->lang;
return tag;
}
gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp, gint mode)
{
guchar buf[BUFSIZ];
guchar *start, *end;
@ -209,88 +211,121 @@ gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
return FALSE;
for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
if (mode == 0)
{
while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
++ end;
if (('\0' == *end) || ('\n' == *end))
status = FALSE;
changed_char = *end;
*end = '\0';
if (NULL == tag->name)
for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
{
if (!isprint(*start))
return FALSE;
else
tag->name = g_strdup((gchar*)start);
}
else
{
switch (*start)
while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
++ end;
if (('\0' == *end) || ('\n' == *end))
status = FALSE;
changed_char = *end;
*end = '\0';
if (NULL == tag->name)
{
case TA_LINE:
tag->atts.entry.line = atol((gchar*)start + 1);
break;
case TA_LOCAL:
tag->atts.entry.local = atoi((gchar*)start + 1);
break;
case TA_TYPE:
tag->type = (TMTagType) atoi((gchar*)start + 1);
break;
case TA_ARGLIST:
tag->atts.entry.arglist = g_strdup((gchar*)start + 1);
break;
case TA_SCOPE:
tag->atts.entry.scope = g_strdup((gchar*)start + 1);
break;
case TA_VARTYPE:
tag->atts.entry.var_type = g_strdup((gchar*)start + 1);
break;
case TA_INHERITS:
tag->atts.entry.inheritance = g_strdup((gchar*)start + 1);
break;
case TA_TIME:
if (tm_tag_file_t != tag->type)
{
g_warning("Got time attribute for non-file tag %s", tag->name);
return FALSE;
}
else
tag->atts.file.timestamp = atol((gchar*)start + 1);
break;
case TA_LANG:
if (tm_tag_file_t != tag->type)
{
g_warning("Got lang attribute for non-file tag %s", tag->name);
return FALSE;
}
else
tag->atts.file.lang = atoi((gchar*)start + 1);
break;
case TA_INACTIVE:
if (tm_tag_file_t != tag->type)
{
g_warning("Got inactive attribute for non-file tag %s", tag->name);
return FALSE;
}
else
tag->atts.file.inactive = (gboolean) atoi((gchar*)start + 1);
break;
case TA_ACCESS:
tag->atts.entry.access = *(start + 1);
break;
case TA_IMPL:
tag->atts.entry.impl = *(start + 1);
break;
default:
#ifdef TM_DEBUG
g_warning("Unknown attribute %s", start + 1);
#endif
break;
if (!isprint(*start))
return FALSE;
else
tag->name = g_strdup((gchar*)start);
}
else
{
switch (*start)
{
case TA_LINE:
tag->atts.entry.line = atol((gchar*)start + 1);
break;
case TA_LOCAL:
tag->atts.entry.local = atoi((gchar*)start + 1);
break;
case TA_TYPE:
tag->type = (TMTagType) atoi((gchar*)start + 1);
break;
case TA_ARGLIST:
tag->atts.entry.arglist = g_strdup((gchar*)start + 1);
break;
case TA_SCOPE:
tag->atts.entry.scope = g_strdup((gchar*)start + 1);
break;
case TA_VARTYPE:
tag->atts.entry.var_type = g_strdup((gchar*)start + 1);
break;
case TA_INHERITS:
tag->atts.entry.inheritance = g_strdup((gchar*)start + 1);
break;
case TA_TIME:
if (tm_tag_file_t != tag->type)
{
g_warning("Got time attribute for non-file tag %s", tag->name);
return FALSE;
}
else
tag->atts.file.timestamp = atol((gchar*)start + 1);
break;
case TA_LANG:
if (tm_tag_file_t != tag->type)
{
g_warning("Got lang attribute for non-file tag %s", tag->name);
return FALSE;
}
else
tag->atts.file.lang = atoi((gchar*)start + 1);
break;
case TA_INACTIVE:
if (tm_tag_file_t != tag->type)
{
g_warning("Got inactive attribute for non-file tag %s", tag->name);
return FALSE;
}
else
tag->atts.file.inactive = (gboolean) atoi((gchar*)start + 1);
break;
case TA_ACCESS:
tag->atts.entry.access = *(start + 1);
break;
case TA_IMPL:
tag->atts.entry.impl = *(start + 1);
break;
default:
#ifdef TM_DEBUG
g_warning("Unknown attribute %s", start + 1);
#endif
break;
}
}
*end = changed_char;
}
*end = changed_char;
}
else
{
// alternative parser for PHP and LaTeX global tags files with the following format
// tagname|return value|arglist|description\n
gchar **fields;
guint field_len;
for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
{
while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
++ end;
if (('\0' == *end) || ('\n' == *end))
status = FALSE;
//changed_char = *end;
*end = '\0';
if (NULL == tag->name && !isprint(*start))
return FALSE;
fields = g_strsplit((gchar*)start, "|", -1);
field_len = g_strv_length(fields);
if (field_len >= 1) tag->name = g_strdup(fields[0]);
else tag->name = NULL;
if (field_len >= 2 && fields[1] != NULL) tag->atts.entry.var_type = g_strdup(fields[1]);
if (field_len >= 3 && fields[2] != NULL) tag->atts.entry.arglist = g_strdup(fields[2]);
tag->atts.file.lang = mode;
tag->type = tm_tag_prototype_t;
g_strfreev(fields);
}
}
if (NULL == tag->name)
return FALSE;
if (tm_tag_file_t != tag->type)
@ -298,12 +333,12 @@ gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
return TRUE;
}
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp)
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode)
{
TMTag *tag;
TAG_NEW(tag);
if (FALSE == tm_tag_init_from_file(tag, file, fp))
if (FALSE == tm_tag_init_from_file(tag, file, fp, mode))
{
TAG_FREE(tag);
return NULL;

View File

@ -133,10 +133,11 @@ gboolean tm_workspace_remove_object(TMWorkObject *w, gboolean free)
return FALSE;
}
gboolean tm_workspace_load_global_tags(const char *tags_file)
gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode)
{
FILE *fp;
TMTag *tag;
TMTagAttrType attr[] = { tm_tag_attr_name_t, 0 };
if (NULL == (fp = fopen(tags_file, "r")))
return FALSE;
@ -144,9 +145,14 @@ gboolean tm_workspace_load_global_tags(const char *tags_file)
tm_create_workspace();
if (NULL == theWorkspace->global_tags)
theWorkspace->global_tags = g_ptr_array_new();
while (NULL != (tag = tm_tag_new_from_file(NULL, fp)))
while (NULL != (tag = tm_tag_new_from_file(NULL, fp, mode)))
g_ptr_array_add(theWorkspace->global_tags, tag);
fclose(fp);
// resort the whole array, because tm_tags_find expects a sorted array and it is not sorted
// when global.tags, php.tags and latex.tags are loaded at the same time
tm_tags_sort(theWorkspace->global_tags, attr, TRUE);
return TRUE;
}
@ -278,7 +284,7 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
g_free(command);
unlink(temp_file);
g_free(temp_file);
source_file = tm_source_file_new(temp_file2, TRUE);
source_file = tm_source_file_new(temp_file2, TRUE, NULL);
if (NULL == source_file)
{
unlink(temp_file2);
@ -435,7 +441,7 @@ void tm_workspace_dump(void)
}
const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs
, gboolean partial)
, gboolean partial, langType lang)
{
static GPtrArray *tags = NULL;
TMTag **matches[2], **match;
@ -460,7 +466,7 @@ const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *at
{
for (tagIter=0;tagIter<tagCount[i];++tagIter)
{
if (type & (*match)->type)
if ((type & (*match)->type) && (lang == -1 || (*match)->atts.file.lang == lang))
g_ptr_array_add(tags, *match);
if (partial)
{
@ -498,7 +504,7 @@ const GPtrArray *tm_workspace_get_parents(const gchar *name)
parents = g_ptr_array_new();
else
g_ptr_array_set_size(parents, 0);
matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE);
matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE, -1);
if ((NULL == matches) || (0 == matches->len))
return NULL;
g_ptr_array_add(parents, matches->pdata[0]);
@ -517,7 +523,7 @@ const GPtrArray *tm_workspace_get_parents(const gchar *name)
}
if (parents->len == j)
{
matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE);
matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE, -1);
if ((NULL != matches) && (0 < matches->len))
g_ptr_array_add(parents, matches->pdata[0]);
}