4

I have the following configuration setting, blatantly stolen from vim-sensible.

" use magical ; option
if has('path_extra')
    setglobal tags-=./tags tags^=./tags;
endif

I suspect what it does is remove the default ./tags entry for tags files and instead find any tags file that's in ., .., ../.., &c.

Initially I thought that it would pick out only a single tags file, but that is not what it does. Instead it picks out EVERY tags file in ., .., ../.., etc.

I use a script to generate a tags file for the toplevel project and use the same script to generate another one for the area I mainly work in

project
├── myfolder
│   └── tags
└── tags

When I'm "in" the myfolder directory, I would like to pick out just the project/myfolder/tags file ... otherwise I have problems with duplicate entries. It also kind of defeats the purpose of having a tags file for a subfolder, which is to "narrow" the identifiers that the ctags mechanism is aware of.

I guess my question is:

  • Is there a simple, well-supported way to work with "hierarchically organized" tags files?
  • What kind of workflow is the magical semicolon-path feature designed to support?
  • From the way I read :h file-searching all you need to do is set tags=./tags;*/tags. Where ; triggers the upward search from the current file's path, .tags, and stops when it finds */tags which is 1 directory deeper than the current working directory. However this does not work in my test case – Peter Rincker Sep 8 '17 at 17:28
2

I recently addressed this problem by writing a Vimscript function (tested and pasted below) that walks up the directory tree from the current file and sets as the tags file the first file named "tags" that it sees directly under a parent directory (i.e. the function doesn't explore sibling directories). I then make a mapping for the function. (I don't make it a BufNewFile/BufRead autocommand because personally I don't want the tags file changing unexpectedly on me.)

function! UseNearestParentTagsFile()
  let l:path = "%:p"
  while expand(l:path) != "/"
    let l:path = l:path . ":h"
    if filereadable(expand(l:path) . "/tags")
      exe "set tags=" . expand(l:path) . "/tags"
      return
    endif
  endwhile
  echom "No tags file found in path."
endfunction
command! UseNearestParentTagsFile call UseNearestParentTagsFile()
nnoremap <leader>st :UseNearestParentTagsFile<cr>

In fact the above solves a problem slightly different yours because you asked about using the tags file closest to the working directory, not the directory containing the file. For a version of the function above for the working directory, try the following (untested):

function! UseNearestParentTagsFile()
  let l:path = getcwd() . "/"
  while l:path != "/"
    let l:path = fnamemodify(l:path, ":h")
    if filereadable(l:path . "/tags")
      exe "set tags=" . l:path . "/tags"
      return
    endif
  endwhile
  echom "No tags file found in path."
endfunction
command! UseNearestParentTagsFile call UseNearestParentTagsFile()
nnoremap <leader>st :UseNearestParentTagsFile<cr>

As for your criteria:

  • Simple: I would say yes. Just put the above somewhere like your vimrc file.
  • Well-supported: I suppose not, except in the sense that there isn't really much to support.
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.