New script: SmartTag (resolves ambiguous C++ tags etc)

165 views
Skip to first unread message

Robert Webb

unread,
Apr 18, 2010, 4:36:22 AM4/18/10
to Vimdev
Hi guys,

Attached is the SmartTag script, which attempts to improve tagging in a few
ways:

- Try to resolve ambiguous tags
- Tag to overloaded operators
- Tag with cursor on "delete" to jump to destructor
- Tag to local variables (not defined in tags file)

It's handy if you're using C++ and often find methods from different classes
with the same name (eg Get(), Add(), Index(), Next() etc). Searching for
the
right tag can be a pain. This script manages to find the right one most of
the
time.

It also provides a way of tagging to operators.

Sounds simple, but ended up being about 1800 lines, plus a 200 line comment
at
the start explaining things.

The following mappings are provided.
Ctrl-_ Ctrl-_ - Jump to tag under cursor
Ctrl-_ Ctrl-W - Split to tag under cursor
Ctrl-_ Ctrl-T - Create new tab for tag under cursor
Ctrl-_ Ctrl-D - Show debug info about finding tag under cursor
_t - Show type of identifier under cursor (not really
working)

For best results, use Exuberant Ctags with the "--fields=+iS" option.
You may leave out the "S" if you wish as the script can work around it most
of
the time if not used.

Note: you can't use Ctrl-T to jump back to where you tagged from.
Nor can you use :tn etc to try the next tag if it guesses wrong.
I think changes to vim are required in order to fix these, as currently it
provides no way to hook into the tags mechanism (see below).

These things make it a little awkward to use, but I mostly use
Ctrl-_ Ctrl-W, and then close the new window when I'm done, so no need to go
back up the tag stack. And mostly :tn isn't required because it finds the
right tag! There are cases where it will go wrong though. One case that
isn't
handled is virtual functions (there's no way to know as it's decided at
runtime).

The attached ZIP contains the script and a couple of example C++ files and
associated tags file. Read the comment at the start of the script for other
details and more examples.


I've been sitting on this script for over a year, but haven't found the time
to
work on it. But with talk of vim 7.3, I thought I'd better get it out
there.
Ideally some changes will be required to vim in order to really make this
script easy to use. It would be nice if the script could modify the tags
list
and fit in with the normal tag commands (Ctrl-T, :tn etc), thus becoming
transparent. I had ideas about what would be required, but I don't have
time
to get into that myself, so any volunteers? Details of what's required can
be
found in the comment at the start of the script, in the Known Issues
section.
Probably not a huge job.

If anyone tries my script, let me know how it goes! :-)
Rob.

--

Robert Webb <Stel...@gmail.com>,
Software developer
http://www.software3d.com

--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

Subscription settings: http://groups.google.com/group/vim_dev/subscribe?hl=en
TestTags.zip

Lech Lorens

unread,
Apr 20, 2010, 5:14:17 PM4/20/10
to vim...@googlegroups.com
On 18-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
> Hi guys,
[...]
> If anyone tries my script, let me know how it goes! :-)
> Rob.

I tried it. I don't like it. I hate it in fact... because it is such an
awesome tool for C++ development! And I hardly ever write anything but
C code (for which it for some reason doesn't work so well).

I was about to get to implementing the 'tagfunc' option so I will gladly
volunteer for this task. But first, I'll adjust your script to make it
work for C as well.

Some comments regarding your script in random order:
- since it works for C++, I'd call it SmartC++Tags,
- I think that making it an autoload script would be a good idea,
- I'd define an interface for the script: pick some functions made
available to the user, make the other ones local (e.g. change the name
of CursorChar() to s:CursorChar()),
- I don't like how the script beeps on me. I haven't yet figured out why
it does so. If it's intentional, can it be made configurable? If it's
not...,
- I'd leave defining key mappings to the user,
- if the script had Unix-style line endings, it would work without any
adjustments on any system,
- I managed to break it (sorry!): I modified the example C++ code in
such a way that - although I get the right results - I also get lots
of error messages. I attached the two C++ source files and the tags
file. The instruction for getting the errors is at the end of the .cpp
file,
- would you like to pick a license for your script?

Kudos for you for the great work! Really impressive!

--
Cheers,
Lech
test-SmartTags.zip

Lech Lorens

unread,
Apr 20, 2010, 7:29:57 PM4/20/10
to vim...@googlegroups.com
On 20-Apr-2010 Lech Lorens <lech....@gmail.com> wrote:
> On 18-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
> > Hi guys,
> [...]
> > If anyone tries my script, let me know how it goes! :-)
> > Rob.

Hooray!
It works for C. My C code was simply written in a way that revealed an
issue with the script. Here's a patch for this problem and for the
beep.
smart-c-tags.patch

Robert Webb

unread,
Apr 21, 2010, 10:26:33 AM4/21/10
to vim...@googlegroups.com
Lech Lorens wrote:

> I was about to get to implementing the 'tagfunc' option so I will gladly
> volunteer for this task.

You were about to do it anyway? I asked about the possibility a year ago,
did
it make it to a to-do list somewhere?

> - since it works for C++, I'd call it SmartC++Tags,

Hmm, not as catchy :-) It's supposed to work for C as well.
Maybe it can be extended someday if anyone wants to support more languages,
so the name can be considered open for future expansion :-)

> - I think that making it an autoload script would be a good idea,
> - I'd define an interface for the script: pick some functions made
> available to the user, make the other ones local (e.g. change the name
> of CursorChar() to s:CursorChar()),
> - would you like to pick a license for your script?

These are all things I don't know much about. Vim scripts have different
licenses? Man, didn't know anyone worried about that.

> - I'd leave defining key mappings to the user,

Well it was intended as a work-in=progress, with the hope of being fully
integrated into vim's tags system sometime, but that's not possible yet.
Then no mappings will be required. People can still make their own
mappings.

> - if the script had Unix-style line endings, it would work without any
> adjustments on any system,

OK, done.

> - I managed to break it (sorry!): I modified the example C++ code in
> such a way that - although I get the right results - I also get lots
> of error messages. I attached the two C++ source files and the tags
> file. The instruction for getting the errors is at the end of the .cpp
> file,

Don't apologise, it's good that you found a bug and reported it so clearly.

It was because your tags file was created in a different way to mine.
Mine has search patterns for #defined, whereas yours specifies line numbers,
and although my code attempted to handle it, I suppose I never tested it!
(Or possibly broke it after I did). I've fixed it. New script attached.

> Kudos for you for the great work! Really impressive!

Thanks!

> Hooray!
> It works for C. My C code was simply written in a way that revealed an
> issue with the script. Here's a patch for this problem and for the
> beep.

Hmm, not sure about either of those patches. I presume the earlier one is
to
fix the beep? (I have beeps disabled, although I can't figure out how!).
The "normal [{" is different from the search() call you used, by only
jumping
to outer levels of the {...} nesting. The search() would find any "{",
possibly not an outer nesting, and I think that would be more likely to
break.
Better if there's a way to stop "normal [{" from beeping. Is there?

I presume the second patch fixes your C code? You must have structs defined
in
a column that isn't the first. The search deliberately looks only in the
first
column because in a later column it may not be defining a struct/class, but
rather defining the type of a function or other member. In fact, I think I
ran
into that error which is why I added the "^", but looks like I forgot in the
subsequent similar case. Hmm, I did make sure there was no ";" for the rest
of
the line, but I guess there may not be if it's the return type of a
function.
... OK, I've fixed it another way, so test the attached script. Could you
give
me a sample of the code that broke it?

Thanks,
Rob.

--

Robert Webb <Rob...@software3d.com>,
MineSweeper3D - Take Minesweeper to a whole new dimension!
http://www.software3d.com/Mines3D
SmartTags.zip

Lech Lorens

unread,
Apr 21, 2010, 5:41:06 PM4/21/10
to Robert Webb, vim_dev
On 21-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
> Lech Lorens wrote:
>
> > I was about to get to implementing the 'tagfunc' option so I will gladly
> > volunteer for this task.
>
> You were about to do it anyway? I asked about the possibility a year ago,
> did
> it make it to a to-do list somewhere?

From todo.txt:

8 Use a mechanism similar to omni completion to figure out the kind of tab
for CTRL-] and jump to the appropriate matching tag (if there are
several).
Alternative: be able to define a function that takes the tag name and uses
taglist() to find the right location. With indication of using CTRL-] so
that the context can be taken into account. (Robert Webb)

I'd also like some better way to navigate around C code than cscope
currently offers. I was hoping to be able to use the Netbeans interface
and the Clang C compiler to get that. This will, however, have to wait
a moment.

> > - I think that making it an autoload script would be a good idea,
> > - I'd define an interface for the script: pick some functions made
> > available to the user, make the other ones local (e.g. change the name
> > of CursorChar() to s:CursorChar()),
> > - would you like to pick a license for your script?
>
> These are all things I don't know much about. Vim scripts have different
> licenses? Man, didn't know anyone worried about that.

Well... Since you claimed you didn't have much time, I immediately
assumed you would not address any problems with SmartTags. I intended to
fix any problems and then simply to share the results with others.
I wanted to be sure that you didn't have any objections.

> > - I managed to break it (sorry!): I modified the example C++ code in
> > such a way that - although I get the right results - I also get lots
> > of error messages. I attached the two C++ source files and the tags
> > file. The instruction for getting the errors is at the end of the .cpp
> > file,
>
> Don't apologise, it's good that you found a bug and reported it so clearly.
>
> It was because your tags file was created in a different way to mine.
> Mine has search patterns for #defined, whereas yours specifies line numbers,
> and although my code attempted to handle it, I suppose I never tested it!
> (Or possibly broke it after I did). I've fixed it. New script attached.

Should I have run Ctags in any special way? I simply ran
"ctags --fields=+iS filenames..."

> > Hooray!
> > It works for C. My C code was simply written in a way that revealed an
> > issue with the script. Here's a patch for this problem and for the
> > beep.
>
> Hmm, not sure about either of those patches. I presume the earlier one is
> to
> fix the beep? (I have beeps disabled, although I can't figure out how!).
> The "normal [{" is different from the search() call you used, by only
> jumping
> to outer levels of the {...} nesting. The search() would find any "{",
> possibly not an outer nesting, and I think that would be more likely to
> break.
> Better if there's a way to stop "normal [{" from beeping. Is there?

Obviously - search() is wrong. But then there is searchpair() (which
doesn't beep!)...
searchpair('{', '', '}', 'bW')
My experience is that it tends to be slow in large files, however.

":help beep" says:
When no beep or flash is wanted, use ":set vb t_vb=".

So avoiding the beep should be doable without searchpair(). How about
the attached patch?

> I presume the second patch fixes your C code? You must have structs defined
> in
> a column that isn't the first. The search deliberately looks only in the
> first
> column because in a later column it may not be defining a struct/class, but
> rather defining the type of a function or other member. In fact, I think I
> ran
> into that error which is why I added the "^", but looks like I forgot in the
> subsequent similar case. Hmm, I did make sure there was no ";" for the rest
> of
> the line, but I guess there may not be if it's the return type of a
> function.
> ... OK, I've fixed it another way, so test the attached script. Could you
> give
> me a sample of the code that broke it?

It was due to a "typedef":
typedef struct structname {
//
}

Since a few lines below the regexp did not specify "^", I assumed that
it was only a typo and removed it. Didn't analyze your script very
thoroughly...



Do you by any chance have any tests for your script? Today at work
I encountered two cases where SmartTags did not yield the right result
(maybe it was due to one of my two modifications...). I'll try to fix
them but would feel safer if I had some tests.

If there are no tests - I'll prepare some for C myself. I don't feel
that comfortable with C++, though.

--
Cheers,
Lech
_vimSmartTags.vim.patch

Robert Webb

unread,
Apr 22, 2010, 7:00:59 AM4/22/10
to vim...@googlegroups.com
Lech Lorens wrote:

> I'd also like some better way to navigate around C code than cscope

I haven't used cscope. I remember it being either unavailable on
Windows or just too much bother to set up.

> Well... Since you claimed you didn't have much time, I immediately
> assumed you would not address any problems with SmartTags. I
> intended to fix any problems and then simply to share the results
> with others. I wanted to be sure that you didn't have any
> objections.

Go for it, any patches are appreciated, but nice if they're run past
me first (by posting here is fine). One man's bug fix is often
another man's bug, and hopefully I can remember why the code was that
way to begin with.

> > It was because your tags file was created in a different way to
> > mine. Mine has search patterns for #defined, whereas yours
> > specifies line numbers, ...
>
> Should I have run Ctags in any special way? I simply ran
> "ctags --fields=+iS filenames..."

I use "--fields=+iaS", but the "a" shouldn't make a difference.
I use Exuberant Ctags 5.8.

I believe the original ctags used a line number rather than search
patterns for #defines. I had a feeling Exuberant Ctags had a flag to
choose which way, but I can't see it now.

> So avoiding the beep should be doable without searchpair(). How about
> the attached patch?

OK, that'll do it. I attach the newest version of the patch. Sorry,
I made some minor cosmetic changes to the patch, keeping in line with
my variable naming elsewhere.

There's also one other minor bug fix in this version.

I still don't know why mine doesn't beep. I don't set vb or t_vb
anywhere that I can find, or errorbells for that matter.

> It was due to a "typedef":
> typedef struct structname {
> //
> }

Ah of course. Hopefully the new version of the script, fixed in a
different way, works for you?

> I encountered two cases where SmartTags did not yield the right result
> (maybe it was due to one of my two modifications...). I'll try to fix
> them but would feel safer if I had some tests.

Feel free to send me any examples where it fails. If you can find why
and provide a patch so much the better.

> If there are no tests - I'll prepare some for C myself. I don't feel
> that comfortable with C++, though.

You mean automated tests? No I don't have any. Maybe some can be
created based on my sample files? I don't know how vim's tests
scripts work. If you can put some together, that'd be great.

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Want to make polyhedra?
http://www.software3d.com/Stella.php
SmartTags.zip

Lech Lorens

unread,
Apr 27, 2010, 6:53:08 PM4/27/10
to vim...@googlegroups.com
On 20-Apr-2010 Lech Lorens <lech....@gmail.com> wrote:
> On 18-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
> > Hi guys,
> [...]
> > If anyone tries my script, let me know how it goes! :-)
> > Rob.
>
> I was about to get to implementing the 'tagfunc' option so I will gladly
> volunteer for this task. But first, I'll adjust your script to make it
> work for C as well.

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.

Two open questions:
- 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.
- 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).

Any comments welcome.
tagfunc.patch.1
tagfunc-test.vim

Robert Webb

unread,
Apr 28, 2010, 9:36:45 AM4/28/10
to vim...@googlegroups.com
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 :-/

Rob.

--

Robert Webb <Stel...@gmail.com>,
Want to make polyhedra?
http://www.software3d.com/Stella.php

TestTags.zip

Lech Lorens

unread,
Apr 28, 2010, 12:20:48 PM4/28/10
to vim...@googlegroups.com
On 28 April 2010 15:36, Robert Webb <stel...@gmail.com> wrote:
> 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 :-/
>
> Rob.

There is absolutely no need to install Subversion or whatever SCM for
that matter.
You can get up-to-date Vim from repo.or.cz. Either from vim_mainline
or vim_extended.

Go to:
http://repo.or.cz/w/vim_mainline.git

From the description you will notice that you are interested in the
master branch. Scroll down, you will see some information about the
branches available. Click "tree" which coresponds to the master
branch. You will get to:
http://repo.or.cz/w/vim_mainline.git/tree/master

Here at the top you are given the option to download a snapshot of the
branch as a .tar.bz2 or .zip file.

In other words, you get the most recent Vim source code from:
http://repo.or.cz/w/vim_mainline.git/snapshot/master.zip

Note that this is an independent repository (not maintained by Bram Moolenaar).

--
Cheers,
Lech Lorens

Lech Lorens

unread,
Apr 28, 2010, 7:12:46 PM4/28/10
to vim...@googlegroups.com
On 28-Apr-2010 Lech Lorens <lech....@gmail.com> wrote:
> You can get up-to-date Vim from repo.or.cz. Either from vim_mainline
> or vim_extended.

I should have mentioned that both the git repositories are maintained by
Markus Heidelberg who has been doing the wonderful job. Thank you for
your work, Markus!

--
Cheers,
Lech

Lech Lorens

unread,
Apr 28, 2010, 7:24:30 PM4/28/10
to Robert Webb, vim...@googlegroups.com
On 28-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
> 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.

Here is an updated version of the 'tagfunc' patch:
- the outdated documentation you noticed has been brought up to date,
- a problem with tags not working with 'tagfunc' set has been fixed,
- taglist() now uses 'tagfunc' unless is called from 'tagfunc'.

> - 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.

It does find errors for me:
#v+
Error: id "aar", line 335 col 12
Error: id "aal", line 337 col 24
Error: id "ua", line 342 col 3
Error: id "aa", line 342 col 7
Error: id "ab", line 342 col 11
Error: id "bb", line 342 col 15
6 Errors
#v-
I'll try to look into this later.

> - Fixed some bugs, and handled a bunch of new cases, like nested class
> declarations etc.
> - Fixed the beeping in a different way: "silent! normal [{"

The funny thing is that my first thought was to use silent to get rid of
the beep. But I didn't use it with the exclamation point.

I'll have some more comments on your email. I'll try to find time to
answer them tomorrow (huh, it's TODAY already. After getting some sleep,
anyway :-) ).

--
Cheers,
Lech

Lech Lorens

unread,
Apr 28, 2010, 7:27:10 PM4/28/10
to Robert Webb, vim...@googlegroups.com
On 29-Apr-2010 Lech Lorens <lech....@gmail.com> wrote:
> On 28-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
> > 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.
>
> Here is an updated version of the 'tagfunc' patch:

Sorry, I forgot to attach the patch.
By the way, apply patch with -p1 argument.
tagfunc.patch.2

Robert Webb

unread,
Apr 29, 2010, 10:52:08 AM4/29/10
to vim...@googlegroups.com
Lech Lorens replied:

> > ":so SmartTagTest.vim"...will report any
> > errors found, and how many were found (currently zero...
>
> It does find errors for me:
> #v+
> Error: id "aar", line 335 col 12
> Error: id "aal", line 337 col 24
> Error: id "ua", line 342 col 3
> Error: id "aa", line 342 col 7
> Error: id "ab", line 342 col 11
> Error: id "bb", line 342 col 15
> 6 Errors

Did you regenerate the tags file? That's probably it.
Please send me the tags file created at your end.

Thanks re git, that was much easier. However, now I can't
get it to compile with Visual Studio 6 :-/
I think I need to get the Platform SDK first.

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Want to make polyhedra?
http://www.software3d.com/Stella.php

Lech Lorens

unread,
May 1, 2010, 6:51:02 AM5/1/10
to vim_dev
On 28-Apr-2010 Robert Webb <stel...@gmail.com> wrote:
>
> > - 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?

What I meant is: if the user's function used in 'tagfunc' returns a list
of tags, should I verify that there are no duplicates in the list? I'd
say: no - leave it to the user to take care of what is returned.

Another issue is whether taglist() should remove duplicates. It might be
good to handle this but for now I'd rather stick to 'tagfunc' to get it
done well.

> > - 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?

OK, I'll think about this later.

> 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?

I have no problem with that.

> Some other thoughts:
>
> - Another thing I need is a way to do more than one search in the tag command.
[...]
> - 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
[...]
> - Vim doesn't load all tags when it does a tag search. It looks at one file
[...]

It would be great to have all of them, but I consider them improvements
to the basic functionality offered by 'tagfunc'. Once 'tagfunc' is
implemented properly these can be considered.

> - 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).

OK, I changed the example totally so this is a non-issue.

> The script shouldn't be hard to convert for use with 'tagfunc'. Something
> like
> this:

After my small adjustments works for me almost perfectly:

function! SmartTagFunc(pattern, flags)
if a:flags =~? 'c'
let tags = []
let id = GetNiceTagList(tags, 'nk')
return tags
else
return taglist(a:pattern)
endif
endfunc

I am having some problems with the code that I am working on.
Unfortunately, I cannot share it so I will try to tackle the thing
myself.

Some news about 'tagfunc':
I discovered that the 'tagfunc' implementation prevented omni completion
for C from working when 'tagfunc' was set to the SmartTagFunc() function
defined a few lines above. This was due to the fact that - as mentioned
by the documentation - in each of the dictionaries returned by
SmartTagFunc() only the entries 'name', 'filename' and 'cmd' are
considered relevant. Without thinking too much I simply discarded all
the other entries effectively filtering out the data essential to omni
completion. The latest patch fixes the problem. Find it attached.

--
Cheers,
Lech
tagfunc.patch.4

Robert Webb

unread,
May 3, 2010, 8:53:49 AM5/3/10
to vim...@googlegroups.com
Lech Lorens wrote:

> What I meant is: if the user's function used in 'tagfunc' returns a
> list of tags, should I verify that there are no duplicates in the
> list? I'd say: no - leave it to the user to take care of what is
> returned.

Oh, sorry, yes leave that to the user's script.

> Another issue is whether taglist() should remove duplicates. It
> might be good to handle this but for now I'd rather stick to
> 'tagfunc' to get it done well.

OK. Maybe down the road it could be an extra flag for taglist().
We seem to have a few potential flags required now for taglist().
'u' for unique tags? This would not get rid of tags of the same name,
only those that have the same name, cmd & file. It would save my
script having to do it, which it does pretty inefficiently.

> > - Another thing I need is a way to do more than one search in the
> > tag command.
> [...]
> > - 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
> [...]
> > - Vim doesn't load all tags when it does a tag search. It looks
> > at one file
> [...]
>
> It would be great to have all of them, but I consider them
> improvements to the basic functionality offered by 'tagfunc'. Once
> 'tagfunc' is implemented properly these can be considered.

OK. I was hoping the first of those wouldn't be too hard at least.
Currently my test script will fail without it. I find often there's
tags of the same name with the same search commend within a header
file, ie the same line appears twice, within different classes.

Currently my script also makes a second guess if the search fails,
which complicates things further. One solution might be to add
another option, say 'tagcmdfunc', which calls back a user-function to
do the search. It would mean though that I could do multiple searches
as required to find the right line, and if they fail, I can make as
many subsequent guesses as I want (for when the tags file is a little
out of date). It also means that vim's built-in handling of tag
commands doesn't have to be modified. Probably leave it to vim to
open the tag file, then just pass the tag command to the
user-function. What do you think?

> Some news about 'tagfunc': I discovered that the 'tagfunc'
> implementation prevented omni completion for C from working when
> 'tagfunc' was set to the SmartTagFunc() function defined a few lines
> above. This was due to the fact that - as mentioned by the
> documentation - in each of the dictionaries returned by
> SmartTagFunc() only the entries 'name', 'filename' and 'cmd' are
> considered relevant. Without thinking too much I simply discarded
> all the other entries effectively filtering out the data essential
> to omni completion. The latest patch fixes the problem. Find it
> attached.

If it only looks at those entries, why does it matter if other entries
are present? Are you sure it wasn't your other minor change to my
SmartTagFunc() function that fixed it? That would make more sense,
that it expects taglist() to find matches for partial tag patterns.
I'm thinking there might be some use in keeping those fields, eg the
'tagcmdfunc' idea above might have use for them.

> And by the way... 'tagfunc' is now available via vim_extended on
> repo.or.cz:
> http://repo.or.cz/w/vim_extended.git/shortlog/refs/heads/feat/tagfunc

Thanks, and I've compiled it now, at work since it wasn't working at
home.

By the way, I notice that docs/tags hasn't been updated in that
version (doesn't have a tags for 'tagfunc' etc).

- I attach a new version:
- Includes the SmartTagFunc() function. Users need to put
"set tagfunc=SmartTagFunc" in their .vimrc or _vimrc.
- Fixes (hopefully) the errors you got initially
- Fixes errors which occur in my test script when 'tagfunc' is set
(by unsetting it temporarily). Those errors occurred because my
script calls my functions directly rather than via 'tagfunc', so
any calls to taglist() would recursively call back my script a
second time. Maybe taglist() needs a flag telling it not to use
'tagfunc'?
- My new SmartTagFunc() allows the user to do ":tag Class::Member"
to explicitly find a tag from a specific class.

Some other observations re 'tagfunc':

- Can't tag on operator at end of line, eg "b++;". Needs to allow
this when 'tagfunc' set. However if the tagfunc returns an empty
list, how do we know if an id wasn't found, or if no tags for it
were found (so vim knows which error to give)? Maybe return an
empty list for tag-not-found or 0 for id-not-found?

- ^W^] then ^Wq leaves the original window scrolled sometimes. Not
sure when exactly. But try this: extract the attached ZIP file and
open TestTags.cpp. Go to line 332 and use ^E/^Y to put it in the
bottom half of the screen, towards the bottom. Tag to one of the
first 4 taggable items (ie b, mNext, mPrev or mA) using ^W], then
close that window again with ^Wq. The original cursor line is now
at the top of the window. Strangely it doesn't happen for the
remaining tags on the line. I think I also saw it only happen when
the tag was in the top half of the window. Probably the same bug as
here: http://tech.groups.yahoo.com/group/vimdev/message/51805

Actually I just tried minimal tagfunc, and it doesn't seem to do
it, so it could be a fault with my script, although the link above
shows that there's something wrong. Here's the minimal tagfunc I
used:

function! MyTagFunc(pattern, flags)
return taglist(a:pattern)
endfunc
set tagfunc=MyTagFunc

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Software developer
http://www.software3d.com
SmartTagTest.zip

Lech Lorens

unread,
May 6, 2010, 4:02:01 PM5/6/10
to Robert Webb, vim...@googlegroups.com
On 03-May-2010 Robert Webb <stel...@gmail.com> wrote:
> Lech Lorens wrote:
I looked into the things I thought to be problems in the 'tagfunc'
implementation and found out that I misinterpreted the results I was
getting. In other words: 'tagfunc' has been stable for me and I'll try
to find some time during the weekend to look into the other things you'd
like to be done. To be 100% sure: you think that it would be best to get
multiple searches done first (or do you mean removing duplicate tags)?

> > Some news about 'tagfunc': I discovered that the 'tagfunc'
> > implementation prevented omni completion for C from working when
> > 'tagfunc' was set to the SmartTagFunc() function defined a few lines
> > above. This was due to the fact that - as mentioned by the
> > documentation - in each of the dictionaries returned by
> > SmartTagFunc() only the entries 'name', 'filename' and 'cmd' are
> > considered relevant. Without thinking too much I simply discarded
> > all the other entries effectively filtering out the data essential
> > to omni completion. The latest patch fixes the problem. Find it
> > attached.
>
> If it only looks at those entries, why does it matter if other entries
> are present? Are you sure it wasn't your other minor change to my
> SmartTagFunc() function that fixed it? That would make more sense,
> that it expects taglist() to find matches for partial tag patterns.
> I'm thinking there might be some use in keeping those fields, eg the
> 'tagcmdfunc' idea above might have use for them.

Yes, I am sure. I didn't it clear that it's the :tag command that only
looks at those three entries. The completion script uses taglist() to
get tags and expects to get more than just these three.

> > And by the way... 'tagfunc' is now available via vim_extended on
> > repo.or.cz:
> > http://repo.or.cz/w/vim_extended.git/shortlog/refs/heads/feat/tagfunc
>
> Thanks, and I've compiled it now, at work since it wasn't working at
> home.
>
> By the way, I notice that docs/tags hasn't been updated in that
> version (doesn't have a tags for 'tagfunc' etc).

Thanks for noticing. Will fix that. Meanwhile:
:helptags $VIMRUNTIME/doc

> - I attach a new version:
> - Includes the SmartTagFunc() function. Users need to put
> "set tagfunc=SmartTagFunc" in their .vimrc or _vimrc.
> - Fixes (hopefully) the errors you got initially
> - Fixes errors which occur in my test script when 'tagfunc' is set
> (by unsetting it temporarily). Those errors occurred because my
> script calls my functions directly rather than via 'tagfunc', so
> any calls to taglist() would recursively call back my script a
> second time. Maybe taglist() needs a flag telling it not to use
> 'tagfunc'?
> - My new SmartTagFunc() allows the user to do ":tag Class::Member"
> to explicitly find a tag from a specific class.
>
> Some other observations re 'tagfunc':
>
> - Can't tag on operator at end of line, eg "b++;". Needs to allow
> this when 'tagfunc' set.

You can tag an operator. You will want to set 'isk' appropriately.
Probably:
:set isk+=-+

> However if the tagfunc returns an empty list, how do we know if an
> id wasn't found, or if no tags for it were found (so vim knows which
> error to give)? Maybe return an empty list for tag-not-found or
> 0 for id-not-found?

There is "E426: tag not found". Id not found?
If you mean "E349: No identifier under cursor", Vim takes care of this,
no need to do this in the 'tagfunc' function.

> - ^W^] then ^Wq leaves the original window scrolled sometimes. Not
> sure when exactly. But try this: extract the attached ZIP file and
> open TestTags.cpp. Go to line 332 and use ^E/^Y to put it in the
> bottom half of the screen, towards the bottom. Tag to one of the
> first 4 taggable items (ie b, mNext, mPrev or mA) using ^W], then
> close that window again with ^Wq. The original cursor line is now
> at the top of the window. Strangely it doesn't happen for the
> remaining tags on the line. I think I also saw it only happen when
> the tag was in the top half of the window. Probably the same bug as
> here: http://tech.groups.yahoo.com/group/vimdev/message/51805
>
> Actually I just tried minimal tagfunc, and it doesn't seem to do
> it, so it could be a fault with my script, although the link above
> shows that there's something wrong. Here's the minimal tagfunc I
> used:
>
> function! MyTagFunc(pattern, flags)
> return taglist(a:pattern)
> endfunc
> set tagfunc=MyTagFunc

I haven't looked into it yet, but I was thinking whether this could be
related to the fact that you change the position of the cursor while
preparing a tag list.

--
Cheers,
Lech

Robert Webb

unread,
May 7, 2010, 8:20:35 AM5/7/10
to Lech Lorens, vim...@googlegroups.com
Lech Lorens wrote:

> I'll try to find some time during the weekend to look into the other
> things you'd like to be done. To be 100% sure: you think that it
> would be best to get multiple searches done first (or do you mean
> removing duplicate tags)?

That's right. But what do you think of my 'tagcmdfunc' idea?
That would allow my script to handle multiple successive searches, as
well as multiple guesses when a search fails. There'd be no need for
the multiple search feature in vim then. It would be left to the
script. So 'tagfunc' could put whatever it wants in the tag command,
and 'tagcmdfunc' would know what to do with it. Seems the most
flexible solution. Although hmm, if taglist() is called by another
script it may get something unexpected. Maybe taglist() shouldn't use
'tagfunc' by default?

> Thanks for noticing. Will fix that. Meanwhile:
> :helptags $VIMRUNTIME/doc

Ah! For the life of me I couldn't remember or find how to do that.
I kept looking for :doctags! Thanks. Actually I looked at the doc
for "write-plugin" expecting to find it there, but no mention of it.
Would be a good thing to mention for people writing plugins, no?

> > - Can't tag on operator at end of line, eg "b++;". Needs to allow
> > this when 'tagfunc' set.
>
> You can tag an operator. You will want to set 'isk' appropriately.
> Probably:
> :set isk+=-+

Hmm, I guess, but this will have many other ramifications. The point
is that the 'tagfunc' handles things its own way, such as finding
valid C++ operators like mine does. Neither vim not the user need
know how it's done, so they shouldn't need a special isk setting.

I think when 'tagfunc' is set, vim should call it even when it doesn't
think there's an identifier under the cursor. It is up to the script
to find what it wants. Which leads into...

> > However if the tagfunc returns an empty list, how do we know if an
> > id wasn't found, or if no tags for it were found (so vim knows
> > which error to give)? Maybe return an empty list for
> > tag-not-found or 0 for id-not-found?
>
> There is "E426: tag not found". Id not found?
> If you mean "E349: No identifier under cursor", Vim takes care of this,
> no need to do this in the 'tagfunc' function.

If vim called 'tagfunc' regardless of what is found under the cursor,
as I'm suggesting, then it becomes 'tagfunc's responsibility to say
whether it found an identifier under the cursor. So I'm suggesting
that if it returns 0 it means no id was found, and vim then knows to
give the "E349: No identifier under cursor" error. If however it
returns an empty list, then it means an id was found, but no tags.
In this case vim knows to give the "E426: tag not found" error.

> > - ^W^] then ^Wq leaves the original window scrolled sometimes. Not
> > sure when exactly. But try this: extract the attached ZIP file and
> > open TestTags.cpp. Go to line 332 and use ^E/^Y to put it in the
> > bottom half of the screen, towards the bottom. Tag to one of the
> > first 4 taggable items (ie b, mNext, mPrev or mA) using ^W], then
> > close that window again with ^Wq. The original cursor line is now
> > at the top of the window. Strangely it doesn't happen for the
> > remaining tags on the line. I think I also saw it only happen when
> > the tag was in the top half of the window. Probably the same bug as
> > here: http://tech.groups.yahoo.com/group/vimdev/message/51805
> >
> > Actually I just tried minimal tagfunc, and it doesn't seem to do
> > it, so it could be a fault with my script, although the link above
> > shows that there's something wrong. Here's the minimal tagfunc I
> > used:
> >
> > function! MyTagFunc(pattern, flags)
> > return taglist(a:pattern)
> > endfunc
> > set tagfunc=MyTagFunc
>
> I haven't looked into it yet, but I was thinking whether this could be
> related to the fact that you change the position of the cursor while
> preparing a tag list.

Well, I wonder that too, and it's possible. It's just that I reported
that other bug referenced above (a year or so ago) which was very
similar, and... bah, you know what, I just tried it again and now I
can't get it to happen! It happens using my old mappings (before
'tagfunc') but isn't happening when using vim's tag commands. Forget
it for now, I'll keep an eye out for it.

Rob.

--

Robert Webb <Stel...@gmail.com>,
Want to make polyhedra?
http://www.software3d.com/Stella.php

Robert Webb

unread,
May 11, 2010, 6:56:50 AM5/11/10
to Lech Lorens, marco-...@gmx.de, vim...@googlegroups.com
Attached is a new version of my SmartTag script, which attempts to improve
C/C++ tagging in a few ways:

- Try to resolve ambiguous tags
- Tag to operators
- Tag with cursor on "delete" to jump to destructor
- Tag to local variables (not defined in tags file)
- NEW: Tag to labels from goto statements

Can integrate with vim's tag mechanism using Lech Loren's 'tagfunc' patch.

New version has some bug fixes and the new tagging on goto statements.

Test files in attached ZIP have also been updated.

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Software developer
http://www.software3d.com
SmartTagTest.zip

marco-oweber

unread,
May 18, 2010, 9:11:38 PM5/18/10
to Robert Webb, Lech Lorens, vim_dev
I couldn't resist:

I used github because it works best and fastest for me:

http://github.com/MarcWeber/SmartTag

I also moved code and renamed SmartTag to SmartTag#SmartTag

When enabling tagfunc by setting to SmartTag or SmartTag#SmartTag should
tjump show only one match as well? This didn't work for me.

The :call SmartTag#SmartTag('goto')

Does not require that feature, does it?

Robert: Do you have a www.vim.org account?
You can use the SVN mirror and use svn diff to create diffs
which youc an send to me. You can also install git.
I could create a SSH account which you can login into to push
changes yourself.

Lech: Do you have a repository location now?

Marc Weber

Robert Webb

unread,
May 19, 2010, 11:10:47 AM5/19/10
to marco-oweber, Lech Lorens, vim_dev
Marc Weber wrote:

> I couldn't resist:
>
> I used github because it works best and fastest for me:
>
> http://github.com/MarcWeber/SmartTag
>
> I also moved code and renamed SmartTag to SmartTag#SmartTag

What does the # do? Is that like a namespace or something?

> When enabling tagfunc by setting to SmartTag or SmartTag#SmartTag should
> tjump show only one match as well? This didn't work for me.

Hmm, I never use tjump. My script does not try to return just one tag.
Rather it tries to put the tags in a better order. Even if it thinks it knows
which one's best, it could always be wrong, so tags are reordered, but still
kept for use with :tn etc. Something different would be required if we want
:tjump to know when my script is pretty sure there's only one sensible tag.

Actually, if you always want it to throw away tags that it doesn't think are
right, try changing 'nk' to 'n' in the SmartTagFunc() function ('k' means to
"keep" all tags, but put the best ones first). But I don't think that should
be the default behaviour, as it is not as useful with :tn etc.

I noticed some problems myself now when using ^P and ^N in insert mode.
Sometimes if you break completion before it's found all results it seems to
cause problems. These commands don't need to disambiguate tags though, and
should really just use the default tags mechanism, not 'tagfunc'.
Lech, can you fix that?

> Robert: Do you have a www.vim.org account?

Nope.

> You can use the SVN mirror and use svn diff to create diffs
> which youc an send to me. You can also install git.
> I could create a SSH account which you can login into to push
> changes yourself.

I'll have to look into this another time. Is it not possible to submit changes
via a web interface? That is, without installing git?

I'm only making very minor changes occasionally when I encounter problems. For
now I'll just send you any new versions. I'll send you one after this.

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Software developer
http://www.software3d.com

Lech Lorens

unread,
May 19, 2010, 7:09:14 PM5/19/10
to Robert Webb, marco-oweber, vim_dev
On 19-May-2010 Robert Webb <stel...@gmail.com> wrote:
> > I also moved code and renamed SmartTag to SmartTag#SmartTag
>
> What does the # do? Is that like a namespace or something?

Not quite. The part before the # is used to denote the autoload script
in which a given function is defined. Autoload scripts are lazily
sourced - only when a given function is called.
":help autoload" provides some more details.

> I noticed some problems myself now when using ^P and ^N in insert mode.
> Sometimes if you break completion before it's found all results it seems to
> cause problems. These commands don't need to disambiguate tags though, and
> should really just use the default tags mechanism, not 'tagfunc'.
> Lech, can you fix that?

Strange. I'll try to look into it during the weekend. Meanwhile, maybe
you could provide a detailed description of the steps needed to see what
you mean? Your setting of 'cpt', 'tagfunc' (I assume it's the function
you sent last time), etc. Perhaps you can use Vim source code to create
a scenario in which you reproduce the problem?

--
Cheers,
Lech

Robert Webb

unread,
May 20, 2010, 10:12:14 AM5/20/10
to Lech Lorens, marco-oweber, vim_dev
Hey Lech,

> > I noticed some problems myself now when using ^P and ^N in insert mode.
> > Sometimes if you break completion before it's found all results it seems to
> > cause problems. These commands don't need to disambiguate tags though, and
> > should really just use the default tags mechanism, not 'tagfunc'. Lech,
> > can you fix that?
>
> Strange. I'll try to look into it during the weekend. Meanwhile, maybe you
> could provide a detailed description of the steps needed to see what you
> mean? Your setting of 'cpt', 'tagfunc' (I assume it's the function you sent
> last time), etc. Perhaps you can use Vim source code to create a scenario in
> which you reproduce the problem?

I was afraid you'd ask that. Yeah, I didn't look into it when it happened.
I'll try to take more notice next time. It was probably something to do with
me typing stuff while it was still filling in the list of matches.

However, there's no reason to use 'tagfunc' for ^P/^N anyway. All we want
there is tag names, and no need to disambiguate tags of the same name, so
regardless, ^P/^N shouldn't use 'tagfunc'. Using tagfunc will also slow it
down since all tags files are looked at rather than one at a time.

Another thing I noticed. If I tag to something that wasn't originally a tag
(eg a local variable), then it starts off working. Then :tn also works,
finding real tags. But :trew doesn't get back to the local var. That now
seems lost from the list of tags. In fact, shouldn't :tselect show my local
var tag first? I don't see it. I think it loses it when it goes to the next
tags file in 'tags', but it shouldn't be doing that because my script already
looked at all tags, as returned by taglist() which looks at all files in
'tags'.

Rob.

--

Robert Webb <Stel...@gmail.com>,
Software developer
http://www.software3d.com

Lech Lorens

unread,
May 23, 2010, 5:18:47 PM5/23/10
to Robert Webb, vim_dev
On 20-May-2010 Robert Webb <stel...@gmail.com> wrote:
> Hey Lech,
>
> > > I noticed some problems myself now when using ^P and ^N in insert mode.
> > > Sometimes if you break completion before it's found all results it seems to
> > > cause problems. These commands don't need to disambiguate tags though, and
> > > should really just use the default tags mechanism, not 'tagfunc'. Lech,
> > > can you fix that?
> >
> > Strange. I'll try to look into it during the weekend. Meanwhile, maybe you
> > could provide a detailed description of the steps needed to see what you
> > mean? Your setting of 'cpt', 'tagfunc' (I assume it's the function you sent
> > last time), etc. Perhaps you can use Vim source code to create a scenario in
> > which you reproduce the problem?
>
> I was afraid you'd ask that. Yeah, I didn't look into it when it happened.
> I'll try to take more notice next time. It was probably something to do with
> me typing stuff while it was still filling in the list of matches.
>
> However, there's no reason to use 'tagfunc' for ^P/^N anyway. All we want
> there is tag names, and no need to disambiguate tags of the same name, so
> regardless, ^P/^N shouldn't use 'tagfunc'. Using tagfunc will also slow it
> down since all tags files are looked at rather than one at a time.

In another email I have already responded to this claim. I believe that
'tagfunc' could improve the results during the completion and so its
usage should not be disabled when completion is being done.

> Another thing I noticed. If I tag to something that wasn't originally a tag
> (eg a local variable), then it starts off working. Then :tn also works,
> finding real tags. But :trew doesn't get back to the local var. That now
> seems lost from the list of tags. In fact, shouldn't :tselect show my local
> var tag first? I don't see it. I think it loses it when it goes to the next
> tags file in 'tags', but it shouldn't be doing that because my script already
> looked at all tags, as returned by taglist() which looks at all files in
> 'tags'.

I've had a quick look at this one and I think I understand the cause.
Currently the tagging mechanism works in such a way that if e.g. :tnext
is executed, a list of tags is fetched anew and current-index-+1-th tag
is used for a jump. The index of the new tag is remembered. This means
that:
- the list of tags is expected not to change between selecting a tag for
the first time (e.g. with ^]) and executing :tnext, :trew, :tlast etc,
- 'tagfunc' is re-evaluated for each of the commands which are related
to tag management. However, only ^] causes 'tagfunc' to be called with
the 'c' flag specified, so the results returned by 'tagfunc' can
differ.

Fixing this will require the tagging mechanism in Vim to be modified and
your script to return a full list of tags at each call (currently if
a local variable is found, the returned list does not include any more
tags).

I will have a look at the first part of the task (i.e. Vim modification)
ASAP. Unfortunately, ASAP is unlikely to mean soon.

--
Cheers,
Lech

Robert Webb

unread,
May 24, 2010, 7:10:28 AM5/24/10
to Lech Lorens, vim_dev
Lech Lorens wrote:

> > However, there's no reason to use 'tagfunc' for ^P/^N anyway. All
> > we want there is tag names, and no need to disambiguate tags of the
> > same name, so regardless, ^P/^N shouldn't use 'tagfunc'. Using
> > tagfunc will also slow it down since all tags files are looked at
> > rather than one at a time.
>
> In another email I have already responded to this claim. I believe
> that 'tagfunc' could improve the results during the completion and so
> its usage should not be disabled when completion is being done.

Good point. I guess it could act like a kind of intellisense, like only
completing names of valid members of classes etc. A different flag
should be passed to 'tagfunc' then when insert-mode completion is
expected. Scripts not wanting to deal with it can just call taglist().

Actually I didn't check to see whether the 'c' flag (for context) was
passed for ^P/^N. But I presumed it was, which was causing the
problems. We should add the 'i' flag maybe for insert mode. Then my
script will be able to tell the difference.

Currently it will still require searching all files in 'tags' however.

> > Another thing I noticed. If I tag to something that wasn't
> > originally a tag (eg a local variable), then it starts off working.
> > Then :tn also works, finding real tags. But :trew doesn't get back
> > to the local var. That now seems lost from the list of tags. In
> > fact, shouldn't :tselect show my local var tag first? I don't see
> > it. I think it loses it when it goes to the next tags file in
> > 'tags', but it shouldn't be doing that because my script already
> > looked at all tags, as returned by taglist() which looks at all
> > files in 'tags'.
>
> I've had a quick look at this one and I think I understand the cause.
> Currently the tagging mechanism works in such a way that if e.g.
> :tnext is executed, a list of tags is fetched anew and
> current-index-+1-th tag is used for a jump.

Really? But even vim's normal tagging gets tags in a different order
depending on what file you're in. Eg it will find tags in the current
file before others. Wouldn't that be a problem if the tag list was
re-created for every :tn?

> Fixing this will require ... your script to return a full list of
> tags at each call (currently if a local variable is found, the
> returned list does not include any more tags).

Actually, even just changing this in the script would probably fix it.
I suspect it must be keeping the list of tags between :tn etc, but
updates the list when reaching the end and fetching the next entry in
'tags'.

I figured if it was a local variable, then I could save the time spent
getting tags, but meh, maybe it should just do it anyway.

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Want to make polyhedra?
http://www.software3d.com/Stella.php

Robert Webb

unread,
May 24, 2010, 10:41:55 AM5/24/10
to marco-oweber, Lech Lorens, vim_dev
Marc Weber wrote:

> I couldn't resist:
>
> I used github because it works best and fastest for me:
>
> http://github.com/MarcWeber/SmartTag
>
> I also moved code and renamed SmartTag to SmartTag#SmartTag

You forgot to add SmartTag# to the SmartTagFunc() function for use with 'tagfunc', to the test script, and in the docs. I've done that and made a few other changes. I put some of the doc file back in the script as it was more implementation details, and included a brief summary of what the script's for in both places. Also fixed a bug or two and added relevant tests to the test script.

Can you put this into git?

Thanks,
Rob.

--

Robert Webb <Stel...@gmail.com>,
Software developer
http://www.software3d.com
SmartTagTest.zip
Reply all
Reply to author
Forward
0 new messages