danielmoch.com

Static site for www.danielmoch.com
git clone git://git.danielmoch.com/danielmoch.com.git
Log | Files | Refs | LICENSE

you-should-be-using-tags-in-vim.md (11924B)


      1 title: You Should Be Using Tags In Vim
      2 author: Daniel Moch
      3 copyright: 2018, Daniel Moch
      4 date: 2018-12-02 17:33:09 UTC-05:00
      5 category: technology
      6 description: You may not know it, but Vim already does what you installed a Jedi plugin to do
      7 
      8 <em>Note: This is a crosspost of an entry I wrote in this year's
      9 <ahref="http://vimways.org">vimways.org</a> advent calendar. If
     10 you'reinterested in Vim, I recommend you pop on over there and read
     11 theother articles too.</em>
     12 
     13 > I love you; you complete me.
     14 >
     15 > - Dr. Evil
     16 
     17 I first came to Vim by recommendation. I was looking for a good Python
     18 IDE (at the time I was new to the language) and one recommendation was
     19 to use Vim with a variety of plugins added on top. That Vim could do a
     20 lot of the things I thought only an IDE could do came as a bit of a
     21 shock. I spent a summer as an intern using Emacs at a Unix terminal, but
     22 didn't have enough curiosity at the time to use it any differently from
     23 `notepad.exe`. I spent that summer wishing I had automatic features for
     24 completion, indentation, and all the things that made me appreciate
     25 the IDE's I used in college. How naive I was!
     26 
     27 So how was I directed to achieve powerful programming completions in
     28 Vim? By the use of a plugin called YouCompleteMe. My experience with it
     29 was okay, at least to start with. It took a while to install and get
     30 working, but that didn't bother me at the time since I was just playing
     31 around with it at home and the stakes were low if it suddenly broke. I
     32 did notice it slowed Vim down. Like a lot. But that was mainly when it
     33 was starting up and I didn't know enough to find it frustrating.
     34 Probably the first thing that really bothered me about the plugin was
     35 that the embedded Jedi language server used more memory than Vim itself.
     36 The other recommended plugins were similarly laggy, and I eventually
     37 went in search of something better.
     38 
     39 What I found was Vim itself.
     40 
     41 Did you know that Vim has built-in facilities for completions? It works
     42 admirably well out of the box too, but with a little bit of additional
     43 setup it can be great. Let's take a look at what Vim has on offer
     44 regarding completion and see what it takes to fully leverage it.
     45 
     46 Completion in Vim
     47 -----------------
     48 
     49 Completion in Vim is powerful, but not necessarily straightforward.
     50 Read [:h
     51 ins-completion](http://vimdoc.sourceforge.net/htmldoc/insert.html#ins-completion)
     52 and you'll see what I mean:
     53 
     54 		Completion can be done for:
     55 
     56 		1. Whole lines                                   |i_CTRL-X_CTRL-L|
     57 		2. keywords in the current file                  |i_CTRL-X_CTRL-N|
     58 		3. keywords in 'dictionary'                      |i_CTRL-X_CTRL-K|
     59 		4. keywords in 'thesaurus', thesaurus-style      |i_CTRL-X_CTRL-T|
     60 		5. keywords in the current and included files    |i_CTRL-X_CTRL-I|
     61 		6. tags                                          |i_CTRL-X_CTRL-]|
     62 		7. file names                                    |i_CTRL-X_CTRL-F|
     63 		8. definitions or macros                         |i_CTRL-X_CTRL-D|
     64 		9. Vim command-line                              |i_CTRL-X_CTRL-V|
     65 		10. User defined completion                      |i_CTRL-X_CTRL-U|
     66 		11. omni completion                              |i_CTRL-X_CTRL-O|
     67 		12. Spelling suggestions                         |i_CTRL-X_s|
     68 		13. keywords in 'complete'                       |i_CTRL-N| |i_CTRL-P|
     69 
     70 Vim is smart enough to pull completion data from a variety of sources,
     71 but in turn expects users to know which source will provide the best
     72 answer and to invoke the correct keymap to draw the desired completions.
     73 It's not a huge hurdle in terms of a learning curve, but it's not as
     74 simple as hitting tab either.
     75 
     76 The first thing one should do when trying to learn Vim's completion
     77 system is to disable any completion plugins and learn these keymaps.
     78 Getting comfortable with them will also help you learn and remember
     79 where Vim can pull completion information from. You should also read
     80 [:h
     81 'completefunc'](http://vimdoc.sourceforge.net/htmldoc/options.html#'completefunc')
     82 and [:h
     83 'complete'](http://vimdoc.sourceforge.net/htmldoc/options.html#'complete')
     84 for more information on user-defined completion and the `complete`
     85 option.
     86 
     87 Now that we have a cursory understanding of completion in Vim, let's
     88 take a deeper look at tags and how they figure into completion.
     89 
     90 Introduction to `tags` in Vim
     91 -----------------------------
     92 
     93 One source of completion in Vim is tag completion, which pulls from a
     94 special file called–appropriately—a tags file. Tags files are collections
     95 of identifiers (e.g., function names) that are compiled into a single
     96 file along with references to their location in a source tree.  Vim is
     97 capable of using a (properly formatted) tags file for a variety of use
     98 cases, among them navigating your source code à la Visual Studio and
     99 completion.
    100 
    101 By default Vim doesn't do anything with a tags file except read it.
    102 See [:h
    103 'tags'](http://vimdoc.sourceforge.net/htmldoc/options.html#'tags') to
    104 learn how to configure where Vim looks for tags files. Vimdoc also
    105 contains a very good
    106 [introduction](http://vimdoc.sourceforge.net/htmldoc/usr_29.html#29.1)
    107 to tags more generally, so I won't spend any more time here
    108 introducing them. Let's move on and take a look at how we generate
    109 tags files.
    110 
    111 Introduction to `ctags`
    112 -----------------------
    113 
    114 Tags files solve the problem of navigating and completing code in a
    115 given project, but they also create a problem: how do we create the
    116 tags file, and how do we keep it up to date? It would be a pain to
    117 manually maintain the tags file even for a small project; it would be
    118 all but impossible to do it for a large project like the Linux kernel.
    119 Luckily no one has to maintain a tags file. There are plenty of
    120 utilities to do that for you, usually bearing the name ctags, or some
    121 variant. One very popular choice is called [Exuberant
    122 Ctags](http://ctags.sourceforge.net/), which has the virtue of being
    123 extendable via regular expressions placed into a `.ctags` file, but
    124 the drawback of not having been updated since 2009. Another
    125 increasingly popular option is [Universal Ctags](https://ctags.io/),
    126 which functions as a drop-in replacement for Exuberant Ctags and is
    127 actively maintained. I've had good luck with both.
    128 
    129 Tags files and the tools that generate them have a long history
    130 alongside advanced text editors. The history-of-computing nerd in me
    131 likes knowing that I'm using the same tool programmers have used since
    132 the early days of BSD Unix. It's also a testament to how strong of a
    133 solution they provide that folks are still using them 40 years later.
    134 
    135 Generating `tags` Files
    136 -----------------------
    137 
    138 ### Manually
    139 
    140 When we speak of manually generating tags files, we're talking about
    141 using any one of the aforementioned tags utilities to generate the tags
    142 file. If you're the type of person who takes pleasure in at least
    143 understanding how to do things from the command line, you should consult
    144 the manual page for your selected tags utility. Take special note of the
    145 flags necessary to recurse through all of the subdirectories if you want
    146 to generate a tags file for an entire project in one shot.
    147 
    148 ### Automatically
    149 
    150 You can always use your ctags utility to generate your tags files from
    151 the command line, but that's a heck of a lot of back and forth between
    152 your text editor and your shell, and I doubt anyone who tries to do that
    153 will enjoy the experience for long. So let's look at ways to generate
    154 them automatically.
    155 
    156 If you only ever see yourself using tags files with Vim, then maybe a
    157 plugin will interest you. I used
    158 [Gutentags](https://bolt80.com/gutentags/) for a long time, and found
    159 it "just works" as advertised. It has sane defaults, but lots of
    160 opportunities to customize its behavior, which you'll see if you visit
    161 the above link.
    162 
    163 In spite of that, I ended up moving in a different direction with
    164 managing my tags files. There were several reasons, but the main one
    165 is that I like to think of tags files as separate from Vim, something
    166 the text editor consumes without having to manage. It's an opinionated
    167 view of things, but I increasingly didn't like to configure my text
    168 editor to manage my tags files. So I went in search of another method,
    169 and what I found was the [Tim
    170 Pope](https://tbaggery.com/2011/08/08/effortless-ctags-with-git.html)
    171 method, which I've since implemented myself. Rather than using Vim
    172 itself to manage tags files, this method uses local [Git
    173 hooks](https://git-scm.com/docs/githooks) to rebuild the tags whenever
    174 any of a handful of common Git operations are performed. The result is
    175 a system that also just works, but does so in a half-a-dozen lines of
    176 shell script rather than a few *hundred* lines of Vimscript. Gotta
    177 keep that Vim config tight.
    178 
    179 As a bonus, if you already use Tim Pope's [Fugitive Git
    180 plugin](https://github.com/tpope/vim-fugitive) (and you should), this
    181 method handily places your tags file where that plugin tells Vim to
    182 look for it—in the `.git` folder. Of course the shell-script
    183 approach is infinitely configurable, so you can ultimately place the
    184 tags file wherever you want. One could also tailor this for other
    185 distributed SCM tools (e.g., Mercurial).
    186 
    187 Generically speaking, there are other options as well. You could set a
    188 filesystem watcher to watch your project tree and run ctags any time a
    189 file changes. A task runner like [Grunt](https://gruntjs.com/) might
    190 be a viable option too, especially for web developers. The goal is to
    191 automate the task of (re)generating your tags file, so there is likely
    192 to be no shortage of options.
    193 
    194 Tying It All Together
    195 ---------------------
    196 
    197 That brings us back to where we started, to the issue of code
    198 completion in Vim. Yes, Vim does offer native code completion
    199 (completing from tags is done with `C-x, C-]` in insert mode). No,
    200 it's probably not as powerful as what you could get with something
    201 like a Jedi plugin à la YouCompleteMe, but I've found it satisfies my
    202 needs more often than not, with `:grep` (or my own
    203 [:GrepJob](https://git.danielmoch.com/vim-makejob.git) filling the gap
    204 nicely in a more native fashion.
    205 
    206 There's more you can do here too. For instance, if you find yourself
    207 instinctively reaching for the tab key in order to complete a word,
    208 there is [VimCompletesMe](https://github.com/ajh17/VimCompletesMe),
    209 which takes advantage of all of Vim's built-in completions through the
    210 clever use of an [omni completion
    211 function](http://vimdoc.sourceforge.net/htmldoc/options.html#'omnifunc').
    212 It works, but users do give up some control over selecting what data
    213 source Vim uses for a particular completion. I used this plugin for a
    214 while after I gave up on YouCompleteMe, but ultimately removed it
    215 because it effectively made the tab key ambiguous in Insert mode.
    216 Sometimes I wanted to insert an actual tab character, but got a
    217 completion instead.
    218 
    219 With all of this in place, it's natural to ask whether a language server
    220 is even necessary with Vim. I don't intend here to suggest an answer to
    221 that question, but I will say that many of the solutions to date for
    222 language server integration in Vim have seemed like more trouble than
    223 they're worth. That said, with the advent of Vim 8 and its asynchronous
    224 capabilities, there is headroom for these solutions to improve, and I
    225 expect the best among them to become more compelling in the near future.
    226 
    227 I do not recommend coming to Vim with a mindset of creating an IDE in
    228 your terminal. That said, Vim is a very powerful tool and if you invest
    229 the time to learn how it works it will take you very far. In other
    230 words, use Vim for all it's worth *before* looking for a plugin to help
    231 you out. Anyone who (like me) jumps right to installing a bunch of
    232 plugins—whether in a spree of grabbing anything that looks interesting
    233 or just to copy someone else's configuration—will likely end up with an
    234 unmaintainable mess of a tool that doesn't work consistently, may not
    235 work at all, or works about as slow as the IDE you wanted to break free
    236 of.