ctags for Mathematica files?

I alway use vi to edit Fortran files. I can use ctags to know which variables and functions I have already defined. Now I use vi to edit Mathematica *.m files. I tried to use ctags for *.m files, but it does not work. I have searched for the solution in Google but no luck. Could you give me some suggestions?

-
Using ctags for Mathematica is rather hard, because a variable/function can be defined in a bazillion ways, unlike C/Fortran which have a fixed syntax for defining them. I use YouCompleteMe to autocomplete existing symbols on-the-fly (regardless of whether they're "definitions" or not) and rely on memory/context to determine whether the suggestion is what I want. –  rm -rf Dec 17 '13 at 20:26

Assuming you mean vim for vi, you could build a searchable index that may be an acceptable compromise.

Suppose that you have a searchable convention that you use for marking each function. The obvious one to me is one where you precede each function with a usage, like

foo::usage = "..." ;
foo[ x_ ] = Module[{}, ... ] ;


That would allow use of grep to build an index that you could use with vim -q (although that's not quite as nice as tags that you could follow). For example:

grep -n ::usage *.m | tee index
vim -q index


or, if you want a more constrained search, say just foo:

grep -n foo::usage *.m | tee index
vim -q index


When using vim -q you can use :cn, :cN to move between file:line pairs (this is probably more normally used for C compilation errors, but can be handy for more ad-hoc stuff like this too).

I'd imagine that it's possible that you could use Mathematica itself to read all your Modules and build a call graph of all the functions and variables defined along with their filename and line numbers. If that was done, it's probably not too much harder to make Mathematica produce a ctags format file that you could use within vi.

[EDIT] The ctags format isn't that complicated. Here's a quick hack of a perl script that can generate it (again provided that you have a ::usage for each symbol of interest)

#!/usr/bin/perl

use warnings ;
use strict ;

my @tags = () ;

open my $fh, "grep ::usage *.m | sed 's/::usage.*//'|" or die ; while (<$fh>)
{
chomp ;
/(.*):(.*)/ or die ;

my ($filename,$symbolname) = ($1,$2) ;

push( @tags, "$symbolname\t$filename\t/${symbolname}::usage/\n" ) ; } close$fh or die ;

print \$_ foreach (sort @tags) ;


This probably works for non-vim vi's too.

-