Skip to content

Commit

Permalink
modeline: choose a parser by emacs mode specification at the first line
Browse files Browse the repository at this point in the history
If a parser for a given file cannot be determined by file extension,
a editor mode line can be used as a good hint for the choice.

emacs detects following two formats at the first line of a file as a
mode specification:

     -*- MODE -*-[1]

     -*- mode: MODE; ... -*-[2]

[1] https://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes
[2] https://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html
This patch makes ctags determines a parser by this mode specification.

TODO: getPatternLanguage is not considered yet.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
  • Loading branch information
masatake committed Jul 7, 2014
1 parent 8a5e949 commit 2c15f1d
Showing 1 changed file with 63 additions and 0 deletions.
63 changes: 63 additions & 0 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,67 @@ static langType getInterpreterLanguage (const char *const fileName)

#endif

static vString* determineEmacsModeAtFirstLine (const char* const line)
{
vString* mode = vStringNew ();

const char* p = strstr(line, "-*-");
if (p == NULL)
return mode;
p += strlen("-*-");

for ( ; isspace ((int) *p) ; ++p)
; /* no-op */

if (strncmp(p, "mode:", strlen("mode:")) == 0)
{
/* -*- mode: MODE; -*- */
p += strlen("mode:");
for ( ; isspace ((int) *p) ; ++p)
; /* no-op */
for ( ; *p != '\0' && isalnum ((int) *p) ; ++p)
vStringPut (mode, (int) *p);
vStringTerminate (mode);
}
else
{
/* -*- MODE -*- */
for ( ; *p != '\0' && isalnum ((int) *p) ; ++p)
vStringPut (mode, (int) *p);
vStringTerminate (mode);

for ( ; isspace ((int) *p) ; ++p)
; /* no-op */
if (strncmp(p, "-*-", strlen("-*-")) != 0)
vStringClear (mode);
}

return mode;

}

static langType getEmacsModeLanguageAtFirstLine (const char *const fileName)
{
langType result = LANG_IGNORE;
FILE* const fp = fopen (fileName, "r");
if (fp != NULL)
{
vString* const vLine = vStringNew ();
const char* const line = readLine (vLine, fp);
if (line != NULL)
{
vString* const mode = determineEmacsModeAtFirstLine (line);
result = getExtensionLanguage (vStringValue (mode));
if (result == LANG_IGNORE)
result = getNamedLanguage (vStringValue (mode));
vStringDelete (mode);
}
vStringDelete (vLine);
fclose (fp);
}
return result;
}

extern langType getFileLanguage (const char *const fileName)
{
langType language = Option.language;
Expand All @@ -182,6 +243,8 @@ extern langType getFileLanguage (const char *const fileName)
language = getInterpreterLanguage (fileName);
}
#endif
if (language == LANG_IGNORE)
language = getEmacsModeLanguageAtFirstLine (fileName);
}
return language;
}
Expand Down

0 comments on commit 2c15f1d

Please sign in to comment.