New command-line options for 'etags'

This adds '--no-fallback-lang' and '--no-empty-file-entries'
options, and their opposites '--fallback-lang' and
'--empty-file-entries'.
* lib-src/etags.c (fallback_lang, empty_files): New toggles.
(main): Initialize them to 'true'.
(longopts) [!CTAGS]: Add the '--(no-)fallback-lang' and
'--(no-)empty-file-entries' options.
(find_entries): If 'fallback_lang' is false, don't attempt Fortran
and C/C++ fallbacks.
(print_help): Add help for new options.
(main): If 'empty_files' is false, don't output file entries for
files that have no tags.  (Bug#73484)

* doc/emacs/maintaining.texi (Create Tags Table):
* etc/NEWS:
* doc/man/etags.1: Document the new options.

* test/manual/etags/Makefile (check): Add test for new options.
* test/manual/etags/ETAGS.good_7: New file.
This commit is contained in:
Eli Zaretskii 2024-10-08 15:39:33 +03:00
parent 9c94363894
commit 339ffd7986
6 changed files with 4833 additions and 16 deletions

View file

@ -3048,6 +3048,10 @@ language not yet supported by @command{etags}, and you want to avoid
having @command{etags} fall back on Fortran and C as the default having @command{etags} fall back on Fortran and C as the default
languages. languages.
You can also prevent @command{etags} from falling back on Fortran and
C if you specify the @samp{--no-fallback-lang} option. The option
@samp{--fallback-lang} countermands that.
The option @samp{--parse-stdin=@var{file}} is mostly useful when The option @samp{--parse-stdin=@var{file}} is mostly useful when
calling @command{etags} from programs. It can be used (only once) in calling @command{etags} from programs. It can be used (only once) in
place of a file name on the command line. @command{etags} will read from place of a file name on the command line. @command{etags} will read from
@ -3068,6 +3072,15 @@ explanation. If followed by one or more @samp{--language=@var{lang}}
options, it outputs detailed information about how tags are generated for options, it outputs detailed information about how tags are generated for
@var{lang}. @var{lang}.
By default, @command{etags} includes in the tags table it produces all
the files it scans, including files where it found no tags at all.
Specify @samp{--no-empty-file-entries} to prevent that; then files with
no tags will not be mentioned in the tags table. However, note that
commands which process files mentioned in the tags table, such as
@code{tags-search} (@pxref{Identifier Search}), will process files which
were thus omitted from the tags table. The option
@samp{--empty-file-entries} countermands that.
@findex etags-regen-mode @findex etags-regen-mode
Instead of creating and updating the tags table by manually invoking Instead of creating and updating the tags table by manually invoking
@command{etags}, you can ask Emacs to do it for you automatically. @command{etags}, you can ask Emacs to do it for you automatically.

View file

@ -1,5 +1,5 @@
.\" See section COPYING for copyright and redistribution information. .\" See section COPYING for copyright and redistribution information.
.TH ETAGS 1 "2022-06-10" "GNU Tools" "GNU" .TH ETAGS 1 "2024-10-06" "GNU Tools" "GNU"
.de BP .de BP
.sp .sp
.ti -.2i .ti -.2i
@ -22,6 +22,8 @@ etags, ctags \- generate tag file for Emacs, vi
[\|\-\-members\|] [\|\-\-no\-members\|] [\|\-\-output=\fItagfile\fP\|] [\|\-\-members\|] [\|\-\-no\-members\|] [\|\-\-output=\fItagfile\fP\|]
[\|\-\-class\-qualify\|] [\|\-\-class\-qualify\|]
[\|\-\-regex=\fIregexp\fP\|] [\|\-\-no\-regex\|] [\|\-\-regex=\fIregexp\fP\|] [\|\-\-no\-regex\|]
[\|\-\-no\-fallback\-lang\|] [\|\-\-fallback\-lang\|]
[\|\-\-no\-empty\-file\-entries\|] [\|\-\-empty\-file\-entries\|]
[\|\-\-help\|] [\|\-\-version\|] [\|\-\-help\|] [\|\-\-version\|]
\fIfile\fP .\|.\|. \fIfile\fP .\|.\|.
@ -256,6 +258,20 @@ reads the regexes contained in the file regex.file.
Don't do any more regexp matching on the following files. May be Don't do any more regexp matching on the following files. May be
freely intermixed with filenames and the \fB\-\-regex\fP option. freely intermixed with filenames and the \fB\-\-regex\fP option.
.TP .TP
\fB\-\-fallback\-lang
If a file's language cannot be determined, attempt to parse it as
Fortran and C/C++. This is the default.
.TP
\fB\-\-no\-fallback\-lang
Do not fall back to Fortran and C/C++ for files whose language is
could not be determined.
.TP
\fB\-\-empty\-file\-entries
Produce file entries for files with no tags. This is the default.
.TP
\fB\-\-no\-empty\-file\-entries
Do not output file entries for files with no tags.
.TP
.B \-u, \-\-update .B \-u, \-\-update
Update tag entries for \fIfiles\fP specified on command line, leaving Update tag entries for \fIfiles\fP specified on command line, leaving
tag entries for other files in place. Currently, this is implemented tag entries for other files in place. Currently, this is implemented

View file

@ -44,6 +44,16 @@ why it the mark trace buffer is enabled by default.
* Changes in Emacs 31.1 * Changes in Emacs 31.1
** Etags
+++
New command-line options for handling unrecognized programming languages.
The new command-line option '--no-fallback-lang' disables attempts to
parse as Fortran or C/C++ files whose programming language 'etags' could
not determine. This allows to avoid false positives and reduce the time
required to scan directories with many such files. Another new option
'--no-empty-file-entries' disables generation of file entries in tags
tables for files in which no tags were found.
--- ---
** find-func.el commands now have history enabled. ** find-func.el commands now have history enabled.
The 'find-function', 'find-library', 'find-face-definition', and The 'find-function', 'find-library', 'find-face-definition', and

View file

@ -480,6 +480,8 @@ static bool ignoreindent; /* -I: ignore indentation in C */
static int packages_only; /* --packages-only: in Ada, only tag packages*/ static int packages_only; /* --packages-only: in Ada, only tag packages*/
static int class_qualify; /* -Q: produce class-qualified tags in C++/Java */ static int class_qualify; /* -Q: produce class-qualified tags in C++/Java */
static int debug; /* --debug */ static int debug; /* --debug */
static int fallback_lang; /* --(no-)fallback-lang: Fortran/C fallbacks */
static int empty_files; /* --(no-)empty-file-entries */
/* STDIN is defined in LynxOS system headers */ /* STDIN is defined in LynxOS system headers */
#ifdef STDIN #ifdef STDIN
@ -530,6 +532,10 @@ static struct option longopts[] =
{ "no-defines", no_argument, NULL, 'D' }, { "no-defines", no_argument, NULL, 'D' },
{ "no-globals", no_argument, &globals, 0 }, { "no-globals", no_argument, &globals, 0 },
{ "include", required_argument, NULL, 'i' }, { "include", required_argument, NULL, 'i' },
{ "no-fallback-lang", no_argument, &fallback_lang, 0 },
{ "fallback-lang", no_argument, &fallback_lang, 1 },
{ "no-empty-file-entries", no_argument, &empty_files, 0 },
{ "empty-file-entries", no_argument, &empty_files, 1 },
#endif #endif
{ NULL } { NULL }
}; };
@ -1039,6 +1045,20 @@ Relative ones are stored relative to the output file's directory.\n");
Do not create tag entries for members of structures\n\ Do not create tag entries for members of structures\n\
in some languages."); in some languages.");
if (!CTAGS)
{
puts ("--fallback-lang\n\
If a file's language could not be determined, try to parse\n\
it as Fortran and C/C++.");
puts ("--no-fallback-lang\n\
Do not fall back to Fortran and C/C++ if a file's language\n\
could not be determined.");
puts ("--empty-file-entries\n\
Produce file entries for files with no tags.");
puts ("--no-empty-file-entries\n\
Do not output file entries for files with no tags.");
}
puts ("-Q, --class-qualify\n\ puts ("-Q, --class-qualify\n\
Qualify tag names with their class name in C++, ObjC, Java, and Perl.\n\ Qualify tag names with their class name in C++, ObjC, Java, and Perl.\n\
This produces tag names of the form \"class::member\" for C++,\n\ This produces tag names of the form \"class::member\" for C++,\n\
@ -1161,6 +1181,15 @@ main (int argc, char **argv)
typedefs = typedefs_or_cplusplus = constantypedefs = true; typedefs = typedefs_or_cplusplus = constantypedefs = true;
globals = members = true; globals = members = true;
/* By default, fall back to Fortran/C/C++ if no language is detected by the
file's name. This could be reversed in a future version, but only for
ETAGS. */
fallback_lang = true;
/* By default, output file entries for files that have no tags. This affects
only ETAGS. */
empty_files = true;
/* When the optstring begins with a '-' getopt_long does not rearrange the /* When the optstring begins with a '-' getopt_long does not rearrange the
non-options arguments to be at the end, but leaves them alone. */ non-options arguments to be at the end, but leaves them alone. */
optstring = concat ("-ac:Cf:Il:o:Qr:RSVhH", optstring = concat ("-ac:Cf:Il:o:Qr:RSVhH",
@ -1388,10 +1417,13 @@ main (int argc, char **argv)
{ {
fdesc *fdp; fdesc *fdp;
/* Output file entries that have no tags. */ /* Output file entries that have no tags, unless disabled. */
for (fdp = fdhead; fdp != NULL; fdp = fdp->next) if (empty_files)
if (!fdp->written) {
fprintf (tagf, "\f\n%s,0\n", fdp->taggedfname); for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
if (!fdp->written)
fprintf (tagf, "\f\n%s,0\n", fdp->taggedfname);
}
while (nincluded_files-- > 0) while (nincluded_files-- > 0)
fprintf (tagf, "\f\n%s,include\n", *included_files++); fprintf (tagf, "\f\n%s,include\n", *included_files++);
@ -1951,22 +1983,30 @@ find_entries (FILE *inf)
} }
} }
/* Else try Fortran or C. */ /* Else try Fortran or C if that fallback is not disabled. */
if (parser == NULL) if (parser == NULL)
{ {
node *old_last_node = last_node; if (fallback_lang)
curfdp->lang = get_language_from_langname ("fortran");
find_entries (inf);
if (old_last_node == last_node)
/* No Fortran entries found. Try C. */
{ {
reset_input (inf); node *old_last_node = last_node;
curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
curfdp->lang = get_language_from_langname ("fortran");
find_entries (inf); find_entries (inf);
if (old_last_node == last_node)
/* No Fortran entries found. Try C. */
{
reset_input (inf);
curfdp->lang = get_language_from_langname (cplusplus
? "c++" : "c");
find_entries (inf);
}
return;
} }
return; /* If fallbacks are disabled, treat files without a language as if
'--language=none' was specified for them. */
curfdp->lang = get_language_from_langname ("none");
parser = curfdp->lang->function;
} }
if (!no_line_directive if (!no_line_directive

File diff suppressed because it is too large Load diff

View file

@ -59,6 +59,7 @@ check:
@$(MAKE) OPTIONS='--regex=@regexfile --no-members' ediff_4 @$(MAKE) OPTIONS='--regex=@regexfile --no-members' ediff_4
@$(MAKE) OPTIONS='nonexistent --members --declarations --regex=@regexfile' ediff_5 @$(MAKE) OPTIONS='nonexistent --members --declarations --regex=@regexfile' ediff_5
@$(MAKE) OPTIONS='--class-qualify --members --declarations --regex=@regexfile' ediff_6 @$(MAKE) OPTIONS='--class-qualify --members --declarations --regex=@regexfile' ediff_6
@$(MAKE) OPTIONS='--no-members --no-fallback --no-empty' ediff_7
@$(MAKE) cdiff @$(MAKE) cdiff
@$(MAKE) ctags_update @$(MAKE) ctags_update