[m-dev.] for review: enhancements to mtags script
David Matthew Overton
dmo at cs.mu.OZ.AU
Fri Jul 10 15:09:31 AEST 1998
On Mon, Jul 06, 1998 at 06:25:21PM +1000, Fergus Henderson wrote:
>
> This change should get another round of reviewing, so can you please
> send us another diff when you've addressed those comments?
>
Here it is. The suggested change involving substituting `$body' for
`$_' was not made because `$_' is used within the `output_name()'
function.
--
David Overton
MEngSc Student Email: dmo at cs.mu.oz.au
Department of Computer Science Web: http://www.cs.mu.oz.au/~dmo
The University of Melbourne Phone: +61 3 9344 9159
Estimated hours taken: 5
Enhance the mtags script to produce tags for typeclasses and to
support some new features of Vim and Elvis.
scripts/mtags:
Add support for producing tags for typeclass, instance and
method declarations.
Current limitation: assumes each method declaration start on a
new line.
Add new options `--elvis', `--ext' and `--keep-duplicates'
which support the extended tags features of Vim 5.0 and Elvis 2.1.
Add new option `--help'. (Do `mtags --help' for a description
of all options.)
doc/Mmakefile:
Add mtags to the list of manpages.
Index: scripts/mtags
===================================================================
RCS file: /home/staff/zs/imp/mercury/scripts/mtags,v
retrieving revision 1.16
diff -u -r1.16 mtags
--- 1.16 1997/08/27 14:23:23
+++ mtags 1998/07/10 03:36:23
@@ -6,39 +6,131 @@
if $running_under_some_shell;
#---------------------------------------------------------------------------#
-# Copyright (C) 1994-1997 The University of Melbourne.
+# Copyright (C) 1994-1998 The University of Melbourne.
# This file may only be copied under the terms of the GNU General
# Public License - see the file COPYING in the Mercury distribution.
#---------------------------------------------------------------------------#
-# This script creates a vi style `tags' file or (if the `-e' or `--emacs'
-# option is specified) an emacs style `TAGS' file for Mercury programs.
-# It takes its list of filenames from the command line.
-
-# Note that `vim' does not properly support vi-style tags files,
-# at least not as of vim 4.2. If you're using vim rather than real vi,
-# you need to specify the `--vim' option, which causes mtags to generate
-# a dumbed-down tags file that vim can understand.
+$usage = "\
+Usage: mtags [<options>] <source files>
+Use \`mtags --help' for help.";
+
+$help = "\
+Usage:
+ mtags [<options>] <source files>
+
+Description:
+ This script creates tags files for Mercury programs that can be
+ used with Vi, Vim, Elvis or Emacs (depending on the options
+ specified). It takes a list of filenames from the command line
+ and produces a tags file for the Mercury declarations in those
+ files.
+
+Options:
+ With no options specified, mtags defaults to creating a vi-style
+ tags file. If multiple identical tags are found, only the first
+ occurrence of the tag is placed in the tags file.
+
+ -e or --emacs
+ Produce an emacs-style TAGS file.
+
+ --vim
+ Produce a dumbed-down vi-style tags file that will work
+ with versions of vim prior to 5.0, and versions of elvis
+ prior to 2.1.
+
+ --ext
+ Produce a tags file in the extended format supported by
+ vim 5.0+. Duplicate tags are allowed in the tags file.
+ Extra attributes are added to each tag to say whether it
+ is in the implementation or interface of the source file
+ and to describe the kind of tag. Tag kinds used are:
+ `pred': for predicate declarations
+ `func': for function declarations
+ `type': for type definitions
+ `cons': for type constructors
+ `inst': for inst definitions
+ `mode': for mode definitions
+ `tc': for typeclass declarations
+ `tci': for typeclass instance declarations
+ `tcm': for typeclass methods
+ `tcim': for typeclass instance methods
+
+ (Vim assumes that the `kind' attribute has at most 4
+ characters.)
+
+ --elvis
+ Without `--ext', works the same as `--vim' and supports
+ versions of elvis prior to 2.1. When used in
+ conjunction with `--ext', produces an extended tags file
+ in a format that will work with elvis 2.1+.
+
+ --keep-duplicates
+ By default, mtags removes duplicate tags from the tags
+ file. With this option, duplicate tags are not removed.
+ Also, with this option, tags are created for typeclass
+ instances. This option is implied by `--emacs' and by
+ `--ext'.
+
+ -h or --help
+ Dislay this help message and exit.
+
+ --
+ Treat all remaining arguments as source file names. This is
+ useful if you have file names starting with `-'.
+";
$warnings = 0;
$emacs = 0;
$vim = 0;
+$ext = 0;
+$elvis = 0;
+$keep_dups = 0;
OPTION:
while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
if ($ARGV[0] eq "-e" || $ARGV[0] eq "--emacs") {
$emacs = 1;
+ $keep_dups = 1;
shift(ARGV);
next OPTION;
}
if ($ARGV[0] eq "--vim") {
$vim = 1;
+ $elvis = 0;
shift(ARGV);
next OPTION;
}
+ if ($ARGV[0] eq "--ext") {
+ $ext = 1;
+ $keep_dups = 1;
+ shift(ARGV);
+ next OPTION;
+ }
+ if ($ARGV[0] eq "--elvis") {
+ $elvis = 1;
+ $vim = 0;
+ shift(ARGV);
+ next OPTION;
+ }
+ if ($ARGV[0] eq "--keep-duplicates") {
+ $keep_dups = 1;
+ shift(ARGV);
+ next OPTION;
+ }
+ if ($ARGV[0] eq "-h" || $ARGV[0] eq "--help") {
+ print "$help";
+ exit(0);
+ }
+ if ($ARGV[0] eq "--") {
+ shift(ARGV);
+ break;
+ }
+ die "mtags: unrecognized option \`$ARGV[0]'\n" .
+ "Use \`mtags --help' for help.\n";
}
-die "Usage: mtags [--vim] [-e] [--emacs] file1.m ...\n" if $#ARGV < 0;
+die $usage if $#ARGV < 0;
#---------------------------------------------------------------------------#
@@ -56,7 +148,11 @@
$name =~ s/ .*//;
}
- if (!$emacs && $seen{$name}) {
+ $match_line = $_;
+ $match_line =~ s|\\|\\\\|g; # replace `\' with `\\'
+ $match_line =~ s|/|\\/|g; # replace `/' with `\/'
+
+ if (!$emacs && !$keep_dups && $seen{$name}) {
if ($warnings &&
$file ne $prev_file{$name} &&
$. != $prev_line{$name})
@@ -71,12 +167,56 @@
if ($emacs) {
printf out "%s\177%s\001%d,%d\n",
$_, $name, $., $.;
- } elsif ($vim) {
- printf out "%s\t%s\t/^%s\$/\n",
- $name, $file, $_, $name;
+ } elsif ($ext) {
+ # In ``ext'' mode, print the extra attributes used by
+ # vim 5.0+ and elvis 2.1+.
+ if ($context =~ /implementation/) {
+ $static = "\tfile:";
+ $sfile = $file;
+ } else {
+ $static = "";
+ $sfile = "";
+ }
+ if ($elvis) {
+ # Elvis 2.1+
+
+ # Elvis (as of 2.1i) seems to require `[' to be escaped
+ # in tag patterns, even though they are supposed to use
+ # `nomagic' mode.
+ $match_line =~ s/\[/\\\[/g;
+
+ # Elvis allows only a single search pattern or line number
+ # rather than an arbitrary sequence of colon-separated ex
+ # commands.
+ printf out "%s\t%s\t/^%s\$/;\"\tkind:%s%s%s\n",
+ $name, $file, $match_line, $kind, $static, $sfile;
+ } else {
+ # Vim 5.0+
+
+ # Vim 5.0, like vi, allows an arbitrary number of
+ # colon-separated ex commands. However if more than
+ # one command is given, it seems to ignore the extra
+ # tag attributes. For now, we only output a single
+ # search command so that vim will recognise the
+ # extra attributes. If you would prefer the more
+ # complex command used for vi (see below) instead of
+ # the extra attributes, use `mtags --keep-duplicates'
+ # instead of `mtags --ext'.
+ printf out "%s\t%s\t/^%s\$/;\"\tkind:%s%s\n",
+ $name, $file, $match_line, $kind, $static;
+ }
+ } elsif ($vim || $elvis) {
+ # Works with any version of vim, elvis or vi.
+ printf out "%s\t%s\t/^%s\$/\n",
+ $name, $file, $match_line;
} else {
+ # Works with vi or vim 5.0+. The ex command searches
+ # for the matching line and then places the tag in the
+ # search buffer so that if this is a pred/func
+ # declaration you can do `n' to go to the pred/func
+ # body.
printf out "%s\t%s\t/^%s\$/;-;/%s/\n",
- $name, $file, $_, $name;
+ $name, $file, $match_line, $name;
}
$seen{$name} = 1;
$prev_file{$name} = $file;
@@ -88,10 +228,19 @@
if ($emacs) {
open(out, "> TAGS") || die "mtags: error opening TAGS: $!\n";
+} elsif ($keep_dups) {
+ # Vim 5.0+ and elvis 2.1+ allow multiple matches for a tag, so don't
+ # remove duplicate tags.
+ # Vim and elvis expect the tags file to be sorted so they can do
+ # binary search.
+ open(out, "| sort > tags") ||
+ die "mtags: error opening pipe: $!\n";
} else {
+ # Remove duplicate tags for vi.
open(out, "| sort -u +0 -1 > tags") ||
die "mtags: error opening pipe: $!\n";
}
+$context = "implementation";
while ($#ARGV >= 0)
{
$file = shift(ARGV);
@@ -115,21 +264,36 @@
($cmd, $decl, @rest) = split;
$body = join(' ', @rest);
- # skip lines which are not pred, func, type, inst, or mode
- # declarations.
+ # Is this an "interface" or "implementation" declaration?
+ # If so, change context.
+ if ($decl =~ "\binterface\b" || $decl =~ "\bimplementation\b") {
+ $context = $decl;
+ }
+
+ # Skip lines which are not pred, func, type, inst, mode,
+ # typeclass or instance declarations.
+ # Also skip instance declarations if we're producing a normal vi
+ # tags file since vi doesn't allow duplicate tags and the
+ # typeclass tags are probably more important than the instance
+ # tags.
next unless (
$decl eq "pred" ||
$decl eq "func" ||
$decl eq "type" ||
$decl eq "inst" ||
- ($decl eq "mode" && $body =~ /::/)
+ ($decl eq "mode" && $body =~ /::/) ||
+ $decl eq "typeclass" ||
+ ($decl eq "instance" && $keep_dups)
);
# skip declarations which are not definitions
next unless (
- # pred and func declarations are always definitions
+ # pred, func, typeclass and instance declarations are always
+ # definitions
$decl eq "pred" ||
$decl eq "func" ||
+ $decl eq "typeclass" ||
+ $decl eq "instance" ||
# if it doesn't end in a `.' (i.e if it doesn't fit on one line),
# then it's probably a definition
@@ -143,53 +307,114 @@
);
$name = $body;
+ $kind = $decl;
+ # Shorten $kind for typeclass and instance so they display better in
+ # vim which assumes the kind attribute has at most 4 chars.
+ if ($kind eq "typeclass") { $kind = "tc"; }
+ if ($kind eq "instance") { $kind = "tci"; }
do output_name();
- # for everything except type declarations, we're done
- next unless ($decl eq "type");
+ # for everything except type, typeclass and instance declarations,
+ # we're done
+ next unless ($decl eq "type" || $decl eq "typeclass" ||
+ $decl eq "instance");
+
+ if ($decl eq "type") {
+ # make sure we're at the line with the `--->'
+ if ($body !~ /--->/) {
+ next if $_ =~ /\.[ \t]*$/ || $_ =~ /\.[ \t]*%.*$/;
+ $_ = <srcfile>;
+ chop;
+ $body = $_;
+ }
+ next unless ($body =~ /--->/);
+
+ # replace everything up to the `--->' with `;'
+ $body =~ s/.*--->/;/;
- # make sure we're at the line with the `--->'
- if ($body !~ /--->/) {
- next if $_ =~ /\.[ \t]*$/ || $_ =~ /\.[ \t]*%.*$/;
+ for(;;) {
+ # if the body starts with `;', we assume it must be the
+ # start of a constructor definition
+ if ($body =~ /^[ \t]*;/) {
+
+ # delete the leading `;'
+ $body =~ s/[^;]*;[ \t]*//;
+
+ if ($body =~ /^[ \t]*$/) {
+ $_ = <srcfile>;
+ chop;
+ $body = $_;
+ }
+
+ $name = $body;
+ $name =~ s/[;.%].*//;
+ $kind = "cons";
+ do output_name();
+
+ # if there are more constructor definitions on the
+ # same line, process the next one
+ if ($body =~ /;/) {
+ $body =~ s/[^;]*;/;/;
+ next;
+ }
+ }
+
+ last if $_ =~ /\.[ \t]*$/ || $_ =~ /\.[ \t]*%.*$/;
$_ = <srcfile>;
chop;
$body = $_;
- }
- next unless ($body =~ /--->/);
+ }
+ } elsif ($decl eq "typeclass") {
- # replace everything up to the `--->' with `;'
- $body =~ s/.*--->/;/;
+ for(;;) {
- for(;;) {
- # if the body starts with `;', we assume it must be the start of a
- # constructor definition
- if ($body =~ /^[ \t]*;/) {
+ # Assume each method declaration starts on a new line.
+ if ($body =~ /^.*\b(pred|func)[ \t]*/) {
+ $body =~ s/^.*\b(pred|func)[ \t]*//;
+
+ if ($body =~ /^[ \t]*$/) {
+ $_ = <srcfile>;
+ chop;
+ $body = $_;
+ }
+
+ $name = $body;
+ $name =~ s/[(,%].*//;
+ $kind = "tcm"; # tcm == type class method
+ do output_name();
+ }
- # delete the leading `;'
- $body =~ s/[^;]*;[ \t]*//;
+ last if $_ =~ /\]/;
- if ($body =~ /^[ \t]*$/) {
- $_ = <srcfile>;
- chop;
- $body = $_;
- }
+ $_ = <srcfile>;
+ chop;
+ $body = $_;
+ }
+ } else { # instance declaration
+ for(;;) {
- $name = $body;
- $name =~ s/[;.%].*//;
- do output_name();
-
- # if there are more constructor definitions on the same line,
- # process the next one
- if ($body =~ /;/) {
- $body =~ s/[^;]*;/;/;
- next;
+ # Assume each method declaration starts on a new line.
+ if ($body =~ /^.*\b(pred\(|func\()/) {
+ $body =~ s/.*\b(pred\(|func\()//;
+
+ if ($body =~ /^[ \t]*$/) {
+ $_ = <srcfile>;
+ chop;
+ $body = $_;
+ }
+
+ $name = $body;
+ $name =~ s/[\/)].*//;
+ $kind = "tcim"; # tcim == type class instance method
+ do output_name();
}
+
+ last if $_ =~ /\]/;
+
+ $_ = <srcfile>;
+ chop;
+ $body = $_;
}
-
- last if $_ =~ /\.[ \t]*$/ || $_ =~ /\.[ \t]*%.*$/;
- $_ = <srcfile>;
- chop;
- $body = $_;
}
}
close(srcfile) || die "mtags: error closing `$file': $!\n";
Index: doc/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/Mmakefile,v
retrieving revision 1.5.4.1
diff -u -r1.5.4.1 Mmakefile
--- 1.5.4.1 1997/11/28 07:15:49
+++ Mmakefile 1998/07/10 04:59:23
@@ -75,7 +75,8 @@
library_1.html faq_1.html transition_guide_1.html
.PHONY: manpages
-manpages: c2init.1 mmc.1 mgnuc.1 ml.1 mmake.1 msc.1 mprof.1 mprof_merge_runs.1
+manpages: c2init.1 mmc.1 mgnuc.1 ml.1 mmake.1 msc.1 mprof.1 \
+ mprof_merge_runs.1 mtags.1
#-----------------------------------------------------------------------------#
More information about the developers
mailing list