Monday, June 9, 2014

Tag Like a Boss

tagging the way god intended


This short article aims to get you working with Vim tags quickly and effectively, using its built-in support. Your heavy plugins can wait outside.

Before we can jump in and learn the cool commands and power moves, we have to take charge of our environment.

Preparing for a Tagged Lifestyle


You will need:
  • A ctags generated tags file (Exuberant Ctags is the choice for most cases)

    Typically this is as easy as:

    ctags -R

    in the root of your project.
    But if you need anything fancier than that, consult  man ctags  for guidance.
  • A correctly set :help 'tags' option

    The Vim default of ./tags,tags is probably sufficient for most projects but you might want to include library tag files or a project-common tags file.

  • A correctly set :help 'path' option

    My preferred default is:

    set path=.,**

    Which searches the directory of the current file and all directories beneath the current directory. See :help file-searching for more details.

These options can be set in your $MYVIMRC or, better, within filetype specific plugins in ~/.vim/ftplugin/<the-filetype>.vim or ~/.vim/after/ftplugin/<the-filetype>.vim

With the right setup, we can now enjoy a happy tagging lifestyle.

Living with Tag Love

There are many tag commands available in Vim, but I’m going to share with you only a select few — a mere dozen or so. These are the ones I most frequently reach for. You can learn the other tag commands later.

ctrl-]
Jump to the keyword under the cursor. Tag jumps are recorded on a :help tag stack.

ctrl-t
Jump to older tag in the stack.

:ta
Jump to newer tag in the stack. :help :tag

:0ta or :0tn
Jump to previously jumped-to tag. I use this one often after wandering away from the place I tag-jumped into the current file.

:ts /something
Show a list of tags matching the pattern something.

TIP: Use <ctrl-d> to show a list of tag candidates. This works with partial matches too.
Read more with :help c_CTRL-D

g]
Show a list of tags matching the keyword under the cursor.

:tj /something
Show a list of tags matching the pattern something. If there is only one tag in the list, don’t show the list but instead jump directly to it.

g ctrl-]
Show a list of tags matching the keyword under the cursor. If there is only one tag in the list, don’t show the list but instead jump directly to it.

[I
Ordinarily, this just shows all lines in the file matching the keyword under the cursor — a shortcut to :g/<c-r><c-w>

This map (taken from the Vim help) lets you jump to one of the matches:

:map <F4> [I:let nr = input("Which one: ")<Bar>exe "normal " . nr ."[\t"<CR>

Note
  • Use ctrl-c to cancel the choice if you don’t want to jump to any of them.
  • Use `` to jump back to where you were if you accidentally pressed <esc> or <enter> instead.

Courteous Cousins

While not strictly tagging commands, these little gems are semantically related:

gd and gD
Jump to the local or global declaration of the keyword under the cursor, respectively.

gf
Jump to the file under the cursor.

Honourable Mentions

While these are not in my daily tag toolbox, I do call upon them occasionally:
:tags
To see my current tag stack.

:ptj /something
To show the tag match in the :help preview-window.

ctrl-w ctrl-i and ctrl-w ctrl-d
To split the window, showing the associated first line or definition, respectively.

Tag! You’re It!

Using tags within Vim will speed up your editing by making it easy for you to jump around your pile of files. While there are heavy plugins that aim to make this prettier, the seasoned vimmer knows that the extra bling doesn’t add any real value to their edits.

Vanilla, when done right, is a classy choice.

Get yourself setup to use tags correctly within your projects and get on living the tag lifestyle!

Wednesday, May 28, 2014

For Argument Sake

The buffer list is dead! Long live the buffer list!


The Buffer List

I have long been a fan of :ls and the accompanying :b partial match on buffer name. That basic functionality is rock solid. I still recommend it to newcomers to our beloved editor. We’ve built plugins around it.

There is only one problem with the buffer list. Well, okay, two problems:
  1. It isn’t able to be reordered,
  2. It isn’t able to be renumbered.


Ordering

I sometimes wish I could re-order the buffers so that I could group related ones together: all my text files together and all my source files before them, say. The buffer number is fixed at the time the buffer is created and can never be changed throughout the lifetime of the Vim session - it’d be much nicer to be able to re-order these as and when you saw fit. You can’t do this with the buffer list.


Numbering

When buffers are removed from the buffer list, they leave holes in the numbering of listed buffers. Many plugins use temporary buffers (some a LOT) which can leave huge holes in the numbering of your buffers. If you like to jump to buffers by remembering their buffer number, it can be a bit unsettling to know that you need to jump to buffers 1, 2, 6 and 11 - it’d be much nicer to (even if only temporarily) renumber those buffers to: 1, 2, 3, and 4 respectively. You can’t do this with the buffer list.

But not all is lost. We have an alternative in Vim. We have the argument list!


Argument List

Read more about this little gem with :help arglist
Each window can have a separate argument list. You’re free to set and reset the argument list as and when you see fit. Let’s take a short walk down argument lane:

You can slurp up the .c files in the src/ directory into your current window’s argument list:

:args src/*.c

You can do that recursively within all of the subdirectories:

: args src/**/*.c

You can see your current argument list with:

:args

You can add the .h files to the argument list with:

:argadd src/**/*.h

You can jump to an argument by partial buffer (file) name match with:

:argedit {partial name}

You can jump to an argument by (1-based) index with:

:argument {index}

You can perform an operation on all of your arguments in a single command:

:argdo %s/Long live \zsthe buffer list\ze!/argument lists/ge | update

Early Quitters:

If you :quit before visiting all of the files in your argument list, Vim will question your intentions. To prevent that, use :qa instead.

Local vs Global:

If you spawn a new window, it will inherit the parent window’s argument list. There are functions which will attach to the global argument list or create a new local argument list for the current window.

:help argglobal
:help arglocal

Awesome, right?

Could it get any better? Do I ever ask that without candy in my pocket? Make an appointment with your dentist because this is so sweet, it’ll rot your teeth:


VimFindsMe

The light-weight file finder, VimFindsMe (VFM) now supports the argument list. By default, the <leader>ga map will open the current argument list into a scratch buffer. You can add and remove files and reorganise them as you see fit. You can see their positional index by enabling the :setlocal number option. When you press <enter>+ in this scratch buffer, VFM will set your argument list to these files, in this order.


From :VFMEdit

The :VFMEdit command (mapped to <leader>ge by default) lets you filter a find result on your :help path option. If you press <enter> on a file from this window, it will be opened as a new buffer (but not added to your argument list). If you’d like to set your argument list to the files in the VFM scratch window, type:

:VFMArgs

If instead you’d like to add all of the files to your argument list, type within the VFM scratch window:

:VFMArgadd

The cumbersome combination of :argument and :argedit have been combined into one convenient function called VFMArgument(arg) where arg can be either an argument index or partial buffer name. Remember that the argument index is not the buffer number. You can see the list of arguments with either the :VFMArgs command or the builtin :args command. The buffer name given must exist in the current argument list. This function has a corresponding command:

:VFMArgument {arg}

Which is triggered by <plug>vfm_argument (mapped to <leader>gg by default). The command supports argument list buffer name completion.


You Can’t Do This With The Buffer List

The list of :buffers (aka :ls aka :files) is still useful, don’t get me wrong. It is an unwavering record of buffer numbers and names, unassailable throughout the lifetime of your Vim session. Ignoring :bdelete and :bwipe for a minute. But apart from that, completely inviolable. Excepting certain &buftype settings that make buffers unlisted, of course. Besides all that… watertight.

The argument list on the other hand is an ephemeral construct, changeable on a whim and created with ease. It allows you to arbitrarily order and reorder your buffers as often as you need. And you can perform a string of commands against each buffer in your argument list with ease.

The argument list has a few warts, though, like having two commands for switching to an element by index or by name, and a cumbersome method of deleting arguments. VimFindsMe solves these problems by providing a better interface for setting, modifying and deleting the argument list (:VFMArgs), and a single integrated command (:VFMArgument) for jumping to an argument by index or name.

Care to argue?

Wednesday, April 9, 2014

My Choicest Plugins

Some stuff sucks less.

I’ve written a lot of plugins for Vim in the… four years that I’ve been a Vim plugin dev. Sixty five at the time of writing, by my count. Some of them are even useful. Here are twenty of my favourite plugins. Enjoy. :-)

Note
  • Credit where due: Many of my plugins were co-written with the help of the indefatigable Israel Chauca (better know to vimmers as the lovable Raimondi).
  • Plugins are shown here in github stargazer rank, highest to lowest in each category. It’s not much of a metric as far as I’m concerned, but at least it’s more than just my opinion.

The Crowd Pleasers:
Go, you Good Thing!

Useful If Not (Yet?) Popular:
All puppies deserve love.

Learning Resources:
By far the most popular of my contributions:

Fringe:
Scary shit you never knew Vim could do:

There’s something in there for everyone. For questionable values of everyone. But if you’re in the set, \o/

Sunday, April 6, 2014

Seconds Count, Not Keystrokes


It’s not how short it is that matters, it’s how quick you are.
at the keys, not under the sheets
— Vimmers

Golf: A good edit ruined.

The Problems:
  • Vim Golf optimises on the wrong thing: keystrokes
  • Vim Golf demands a bare-metal Vim

Least Number of Keystrokes

Banging out thirty characters in a few seconds to solve a problem is immeasurably better than spending several minutes contemplating the fewest keystrokes possible to achieve the same result. The point here is, time is a better metric to test yourself against. Can you solve this problem any faster than the last time you tried? Perhaps since then, you’ve crafted a new map or text-object or macro to simplify the task. Isn’t that exactly what Vimmers should be doing? It is Bram’s key point in Seven Habits of Effective Text Editing suggestions, after all.

Bare-Metal Vim

EVERYONE uses a more able Vim than what Vim Golf insists upon. Everyone has better features enabled, Useful Plugins, and custom commands, maps and abbreviations to lighten their editing load. I get that competition requires a level playing field, but that in turn is hindering the competitors. Vimmers walk away from their morning on the golf course with less than they should. They should be able to utilise everything they practised.


Playa:  Aw… but how can I show my l33t skilz? :-(
Vimmer:  Play Vim Golf


Is There No Place for Vim Golf?

Of course there is. It has its uses. If you like playing, keep at it. I’ve seen positive effects in some Vimmers. I implied earlier that "spending minutes contemplating a fewer keystroke alternative" was inefficient and that you’d be better served by sticking to a more verbose alternative that you know well. To be clear, what I mean here is that if what you craft on the golf course is arcane, complex and immemorable (albeit awesomely short), you will end up not using it in your daily editing. Sure, you could try to make it a habit, but then you run into problem #2 — don’t remember a cryptic collage of keystrokes when Vim can do it for you, in a map, say.

Learning shorter ways to get stuff done in Vim is fun and enlightening. I know. I’ve spent many hours on this journey too. But it is a journey; the benefit comes from the process, not the product. Learning that there is a keystroke that lets you type Normal Mode commands in Insert Mode is eye-opening and, at first, spawns a desire to play with this shiny new toy. The Learned Vimmer soon realises though that this shiny new bauble is better left in the box and only taken out when maps are being made.
  • The process: discovery, assessment & assimilation.
  • The product: a new command that you really shouldn’t use when live-typing.

You want to learn every feature the editor offers and use the most efficient command all the time.
You will waste a lot of time learning things you will never use.

Seven Habits of Effective Text Editing - How not to edit effectively
— Bram Moolenaar


Perfect Practice Makes Perfect

Practice doesn’t make perfect. Perfect practice makes perfect.
Charles Birch
— Taekwondo Master
I learnt that quote first-hand from the inimitable Mr Birch. I internalised it at the time, reflect on it frequently, and counsel my own students likewise.

The point of the quote is: If you practice the wrong thing, then you’ll learn well to do it wrong. An additional note here is that repairing a bad habit costs more than learning good habits to begin with. The apocryphal metric tossed about on the training floor was: it takes 50 repetitions to learn a new move, and 200 to unlearn a bad one. Regardless of the accuracy of those particular numbers, the phenomenon it describes is nonetheless very real.


A Better Way

Use Your Vim, Luke

Vim Golf requires that you use a crippled Vim. No. Use your Vim. You’ve grown your ~/.vimrc with its suite of maps, abbreviations, commands and functions designed around your Vimming habits, and you’ve installed plugins that further enhance your editing prowess. Use them! Practice them. Cultivate them: throw away bad ones; repair broken ones; develop new ones.

Compete Against Younger You

Instead of comparing your keystroke length to that of others, you’re better off competing against your own Personal Best times for the editing task at hand.

Method

  1. Grab an editing task. These can come from your own experience or you can just use those on Vim Golf.
  2. Reflect on your prior attempt of this problem (you are repeating your practice exercises, right?!)
  3. Grab your stopwatch; time your execution; record the results.
  4. Reflect again. How did you go? Did you improve your Personal Best time? If not, why not? What are the time-sinks? What can you improve? Would a map help? Or a macro? A plugin?

Macros, Such Fleeting Pleasures
Have you ever crafted an awesome macro to refactor code, or munge data into structures, or perform a tedious operation that frequently arises in this particular file, task or programming language, only to lose all that effort when you close Vim? Sure, with :help 'viminfo you can have Vim persist your registers (in which your macros are stored), but their fragile nature means that you or any one of your plugins can overwrite them without warning.
VimLocalMacros was written to solve this problem. It stores the contents of registers inside comments within the current file so that when you come back to the file, you can restore the registers and have your macros at the ready without having to remember and recreate them over and again.

Those four steps sound easy enough, right? It couldn’t get any easier! Er, well, this is Vim. Of course it could be easier! :-) Get to the VimGym and let it handle all that finicky stuff, like:
  • keeping an extendible store of practice exercises
  • timing your attempts and storing the results
  • analysing your game, suggesting improvements and forcing extra practice in problem areas

VimKata was one of the very first Vim plugins I ever worked on, and so it was therefore doomed to failure from the outset. I didn’t have the skills necessary to tackle such a beast. I didn’t know how to build it; I didn’t know what to focus on; I didn’t know what I didn’t know.
VimGym is less than VimKata in some ways and therefore so very much more.

So, in summary, my thoughts on Vim Golf and Deliberate Practice for Vim are:
  • Vim Golf hobbles Vimmers by limiting them to an unrealistically featureless Vim
  • Vim Golf measures the wrong thing: time taken to complete the task is more important than the number of keystrokes
  • Improvement in a skill comes from repeatedly attempting tasks that are at the edge of your abilities and getting feedback on performance. Ideally this would come from an expert, but VimGym uses the task completion time as an acceptable fallback.
  • Vimmers should be adopting a Seven Habits to Effective Text Editing approach to Vimming whereby they identify inefficiencies, craft improvements, and exercise them to make them habitual.

Whether you choose to go it alone, stick with just VimGolf, or try VimGym too, I wish you well on your journey.

Saturday, March 22, 2014

Closures in VimL


I’ve talked about Anonymous Functions in VimL before, but what about closures?

What is necessary for a language to be able to say that it supports closures? What is sufficient for someone to be able to fake their way through it?

Here is the first example from Wikipedia’s Closure article:


def start(x):
    def increment(y):
        return x+y
    return increment

first_inc = start(0)
second_inc = start(8)

first_inc(3)   # returns 3
second_inc(3)  # returns 11

# The x value remains the same for new calls to the function:
first_inc(1)   # returns 1
second_inc(2)  # returns 10

Here is a faked-up alternative in VimL:


function! Start(x)
  let obj = {}
  let obj.x = a:x
  func obj.increment(y)
    return self.x + a:y
  endfunc
  return obj
endfunction

let first_inc = Start(0)
let second_inc = Start(8)

echo first_inc.increment(3)
echo second_inc.increment(3)

echo first_inc.increment(1)
echo second_inc.increment(2)

Okay, so not really what you think of as a closure, but it lets you get similar things done. Wikipedia says:
Closures are typically implemented with a special data structure that contains a pointer to the function code, plus a representation of the function’s lexical environment (i.e., the set of available variables) at the time when the closure was created.
— Wikipedia
The manual marshalling in our object-oriented implementation above probably doesn’t count, but it’s a similar idea… isn’t it?

Vim certainly has First Class Functions and with VimaholicsAnonymous, it has Anonymous Functions… Does it have closures? If not… does it matter? Can you achieve something similar using its prototypal object notation?

Vimmy the Pooh


Vimmy the Pooh
"When you first wake up in the morning, Pooh," said Piglet at last, "what’s the first thing you say to yourself?"
"What to edit?" said Vimmy the Pooh. "What do you say, Piglet?"
"I say, I wonder what’s going to happen exciting today?" said Piglet.
Pooh nodded thoughtfully. "It’s the same thing," he said.
kudos to watabou for the name.

Friday, March 21, 2014

Oh Vim, you so pretty

Oh Vim, you so pretty

— willmarshall on #vim

Aye, the years have been kind to Vim. She started out quite a plain lass from a simple, hard-working folk who didn’t have the means for the finer things in life. She toiled hard throughout her early years, learning and adapting to the changing workplace and ever increasing demands of her clients. Along the way, the awkward young girl blossomed into the stately matron Vim is today; masterly capable at her job and stylishly dressed at it.

When I started coding, on a C64, it was in a simple B&W editor. Then I upgraded to TurboC (<3) where I had the luxury of a couple of colours on that pleasant blue background. At uni, we had a massive line printer that screamed source code line at a time in a consistently jagged font with letters variously on, above or below the intended baseline; reading printouts was a necessary evil back then. When I saw my first printout from TurboC (or was it Turbo Pascal?) with its bold keywords and italics comments, I was in love. These days, with a thousand colour schemes containing millions of colours across dozens of colourable screen sections… we’re spoilt for choice, and waste our time exploring accordingly. Pick a colorscheme that doesn’t make you rage; get on with your real task.

Personally, for Vim I tolerate: jellybeans, eddie and neverland.