Lech Lorens wrote:
> Here's an implementation of the 'tagfunc' option together with some
> documentation. Additionally, attached is a script showing how a (very
> unuseful) function used in 'tagfunc' can be implemented.
Ha, awesome, that was quick :-)
I'm glad you weren't working on my script, because I've spent some of that
time
I don't have making a bunch of improvements to it, and added a script to
test
it in a bunch of situations. See attached.
New in this version:
- Renamed it to SmartTag.vim. Just put it in the plugins folder.
- Took the mappings out. User can define their own, as described near the
start of SmartTag.vim.
- Zip file also includes two example files: TestTags.cpp and TestTags.h.
These files also form part of the test. Edit either file in vim and do
":so SmartTagTest.vim". It may take a few minutes. It will report any
errors found, and how many were found (currently zero, but look for TODO
for
a few cases not handled). The files are marked up to enable the testing.
See SmartTagTest.vim for details.
- Fixed some bugs, and handled a bunch of new cases, like nested class
declarations etc.
- Fixed the beeping in a different way: "silent! normal [{"
I'll check out your patch. First thing I notice is in the doc for
'tagfunc'.
It says that the second arg to the function is either 0 or -1, whereas the
doc
for tag-function says it's a string of flags. Looks like the former is
wrong.
Hmm, I haven't compiled vim for some years. Just got 7.2, but couldn't get
the
patches to apply on Windows. Details at the end since it won't be of
interest
to most.
> - left a FIXME in the code stating that duplicate tags should be removed
> from the list returned by the user-defined function. Not quite sure,
> though, whether it wouldn't be better to leave it to the user.
I don't think there's any point keeping them. They can never be of use if
all
details match (name, file, search command). Currently I have a function
called
UniqList() which does it. It's very inefficient (N^2). Would be more
efficiently handled in C. Maybe a uniq() function would be handy in
general,
to remove multiple copies in a list.
Maybe a flag to taglist() requesting that duplicate entries be removed?
> - maybe it would make some sense to let taglist() return a result
> returned by the 'tagfunc' function? taglist() could take an optional
> argument which would state whether recursion is allowed and an upper
> limit on the recursion level could be set. I can at least imagine
> a use case for such a feature (admittedly, awkward a bit).
I don't know that an extra option is required. I think taglist() should
always
make use of 'tagfunc', unless called recursively from within the tag
function
itself. I guess an extra optional arg might be useful to allow the user to
avoid calling tagfunc if they wish.
Hmm, I suppose taglist() won't know whether the 'c' flag should be used when
calling 'tagfunc'. Maybe we need to be able to pass this flag to taglist()
too so it can pass it through?
Hmm, another small difference. My script presumes the tag name is complete,
whereas taglist() just searches, eg taglist("blah") will find tags for
"blabbyblahblab". Is this an issue?
Some other thoughts:
- Another thing I need is a way to do more than one search in the tag
command.
My script searches for tags itself, allowing it to do this. It does this
to
have a better chance of finding the right tag when two tags have the same
search pattern, ie two lines of the file are the same. We can figure out
which one by first searching for the start of the class containing it.
This idea is already mentioned in SmartTag.vim. Eg a tag command like
"/class Blah//int var" could search first for the class, then for the var.
Ideally it shouldn't mind if the first search fails, or there should be a
way
to specify that it's OK if the first search fails (a search flag?).
- Gets a little trickier than above too, because I want to have access to
all
of vim's search capabilities in that tag command. The format of a search
pattern in the tags file has limited regular expression capabilities. Not
many characters are special. Maybe a flag to taglist() telling it to
return
normal regular expressions (so my script doesn't have to figure out what
to
escape first) and a way for tagfunc to say which kind of searches it is
using. My searches for the start of a class aren't as simple as
"/class Blah" :-)
- Vim doesn't load all tags when it does a tag search. It looks at one file
from 'tags' at a time. But taglist() looks at all at once. Could be
inefficient. A tagfunc may also wish to do this one at a time. Not sure
of
the best way to handle that, but we should probably think about it now to
avoid changing the tagfunc spec too much down the track. For a start,
taglist() may need an extra arg so we can request tags from just one entry
from 'tags' at a time. Maybe the index of that entry, or -1 for all (the
default)? Some calls may return zero results if the same tag file has
been
accessed via a different path (eg ./tags vs tags). Vim already skips
those
internally. The tagfunc would also need some way to be able to return
some
tags, but not all, and be called repeatedly until it says it's done.
- By the way, in TagFunc2() you should use "taglist('^' . pattern . '$')"
rather than "taglist('\<' . pattern . '\>')". The latter may miss some
non-alphabetic tags like operators. Not that it matters for a proof of
concept like this, but thought I'd mention it. Oh, I see this example is
in
the docs too, so all the more reason to do it the "proper" way. Not sure
it's the best example though, since not many tags will use line numbers
(for
me none of them do although not sure why).
The script shouldn't be hard to convert for use with 'tagfunc'. Something
like
this:
function! SmartTagFunc(pattern, flags)
if a:flags =~? 'c'
let tags = []
let id = GetNiceTagList(tags, 'nk')
return tags
else
return taglist('^' . pattern . '$')
endif
endfunc
The GetNiceTagList() function takes a "k" flag which tells it to keep tags
that
it thinks are wrong, but appended to the end of the list that's returned.
For
use with 'tagfunc', that flag should be used. Hmm, that flag probably
hasn't
been tested for a while :-)
OK, some details about patch not working for me.
I used "patch -p0 < 7.2.001-100 > log.txt" as suggested, but it crashed.
The
log file only made it to patch 23. Also before every patch it says
something
like:
can't find file to patch at input line 20
Perhaps you used the wrong -p or --strip option?
Then I downloaded a new version of GNU patch, started from scratch, and this
time it didn't get past one patch, then stopped saying:
patch: **** unexpected `***' at line 39: ***
../vim-7.2.000/src/version.c Sat Aug 9 19:37:37 2008
So don't know what that's about. Again, it had this at the start of the log
file:
can't find file to patch at input line 20
Perhaps you used the wrong -p or --strip option?
Has anyone got patching working on Windows? Seems kind of crazy that the
only
way to get the latest version of vim without installing Subversion etc is to
apply over 400 patches. I guess it wouldn't be so bad if it worked :-/