Thursday, August 14, 2014

Learning the Tool of Vim

Barry Arthur, 2014-08-14


Learning to use a tool requires:
  Understanding — What is it? 
                  Why do I need it? 
                  How does it fit in with the rest of my world?;
  Cognition — discovering how it works and remembering so;
  Practice — honing the coordination, grace and speed of movements; and finally,
  Affection — the desire to use it, to use it properly, 
              and to identify with the community using it.

Understanding


If you already understand Vim, you can skip this section.

Vim is a Text Editor


A text editor is a tool for creating and changing text documents.

Vim has a Rich Set of Text Objects


Think of a Text Object as a unit of text that can be manipulated (changed, deleted, cut, copied, pasted, selected, etc). Simple editors like Notepad and Nano offer at most two Text Objects — individual characters, and visually selected text. Vim introduces objects for words, sentences, paragraphs, quoted strings, parenthetical collections, entire blocks and functions in programming languages, and a lot more. Text Objects allow the user to manipulate logical portions of text at a higher level of abstraction than mere characters or clumsy explicit selections. This freedom lets the Vimmer think and act faster.

Vim is Configurable


Nearly every facet of operation is controlled by one or more configurable options. Two different Vimmers may have their Vims configured so differently as to appear as different editors to newcomers. Initially daunting, this flexibility and control is appreciated by seasoned Vimmers.

Vim is Extensible


Default functionality can be altered and new functionality added. One such extensible aspect of Vim is its set of Text Objects — existing definitions can be altered and new objects created. Another area of extensibility is through the modification or addition of keys and commands.

Vim is Scriptable


More complicated edits can be recorded and played back as needed. These are called macros. I link to three macro articles below.

For even more scripting power, there is Vimscript (aka VimL), Vim’s built-in scripting language which is used by plugin authors to create weird and wonderful addons, and ordinary Vimmers to automate and control facets of Vim.

I look forward to meeting you on the Path to VimL Mastery.

Vim is Modal


The control interface to Vim is, typically, a keyboard. Keyboards are necessarily limited in the number of keys they hold. This limits the number of unique interactions with Vim that can be made by a User.

One way to solve this problem is by "chording" keystrokes, that is by holding multiple keys down at the same time. While Vim uses a small amount of chording, the more dominant model it uses could instead be referred to as "plucking".

Chording

One definition of such a key-chord includes the common SHIFT, CTRL, and ALT (META/COMMAND) key combinations used in most Operating Systems / Window Managers, like CTRL-W to close a window, or ALT-F4 to close an application (in Windows). Other definitions exclude such simple instances and instead require multiple non-(SHIFT, CTRL, ALT) keys to form a chord.

Two things to know about chording:
  1. The number of extra interactions it provides is small.
    Chording doesn’t scale very well because the hands can only hold down so many characters at the same time, less even, when limited by reach. It also limits the amount of extra interactions that are possible — chording is unaffected by the order in which the keys are pressed — they all need to be pressed together for the chord to trigger. Chording is therefore the mathematically poorer Combination as compared to the richer Permutation that plucking yields.
  2. It hurts.
    Contorting the hand to simultaneously press multiple keys puts a lot of strain on tendons and ligaments, and I believe, significantly contributes to repetitive strain injury (RSI). Anecdotally, I have heard of far more Emacsians complaining of RSI than I have Vimmers. In fact, it is an often cited reason for an ex-Emacsian switching to Vim. For the Emacsian reading this that can’t bare to lose his beloved Emacs, the Evil mode provides a vimmish interface that might be kinder on your wrists.

Plucking

Instead of holding down more than one key simultaneously, Vim prefers a model of striking multiple keys sequentially. This is called a key-sequence and resembles plucking strings on a guitar (as opposed to strumming a chord).

Plucking is better because:
  1. The number of extra interactions is vastly greater. (permutation vs combination)
  2. It doesn’t hurt. (as much)

And it’s actually better than that because the sequence of keys that Vim uses for its commands are not random — they are carefully considered so as to form an actual language designed specifically for the efficient editing of text.

The d key for example is a verb for performing a delete operation. But… deleting what? A character? A word? A line? In other editors, different chords are used to express these alternatives, like ctrl-d deletes a word, ctrl-shift-d deletes a line, ctrl-alt-shift-d breaks your wrist, etc.

The d verb is an unfinished command in Vim. It is an operator (verb) pending a motion (an object to operate on). Vim is waiting for me to tell it what to delete. If I type l now, it will delete a letter (a synonym for the x command); if I type w it will delete from the cursor to the end of the word; b will delete back from the cursor to the start of the word; and another d will delete the entire line. This is a common idiom in Vim — doubling the operator (here, dd) will operate on the whole line. So, y is the yank operator (and unsurprisingly, I hope, pressing it DOES NOTHING because Vim is now waiting for you to tell it what to yank), and yy yanks the whole line. “Yank” is Vim’s term for copy (for pasting later).

One particularly nice set of "motions" are the Text Objects. I will show one here just quickly, but you need to read :help text-objects (heck, just grab a cold beer and read all of :help motion.txt — thank me later)

The iw Text Object:

The command diw will delete an entire word, no matter where the cursor is inside the word. This is better than messing around with dw which only deletes from the cursor to the end of the word.

What Does This Have To Do With Vim Being Modal?

Whereas some editor might use ctrl-d to delete a word, Vim uses diw To those unfamiliar with Vim, that might seem like a typo: how can the d i and w keys be used to delete a word?! What if I want to type a "d" or "i" or "w"?! This is where modes come in. In Normal mode, Vim uses diw to delete the word at the cursor. In Insert mode, it inserts (types) these letters instead.

By separating semantically different concepts, Vim is able to re-use keys for different purposes. For example, in Normal and Visual modes, the "%" key jumps the cursor to the bracket matching the one under the cursor; in Command-line mode, it serves as an alias meaning "the whole buffer" when used as a range, or the name of the current buffer when used as an argument to an ex command; and, of course, in Insert mode it merely inserts a "%" character.


Pop Quiz: Been paying attention? Let’s see.

Given the following text, where the cursor is on the "(" :

echo getline(1, '$')

What do you expect the following Normal mode key sequence to do:

d%

Check your answer at the end of the article.


Vim has 12 modes all up (6 basic modes — the other 6 are variations on the basic ones) but the beginner Vimmer only needs to know 4 of them:
  • Normal mode — The editor starts in this mode. Use <Escape> to return to Normal mode from any other mode. This mode is for movements and operations on Text Objects, like changing, deleting, cutting, yanking (copying), pasting, and entering one of the other modes.
  • Visual mode — Used to extend a highlight region over text. Non-movement commands in this mode execute the command on the selected text.
  • Insert mode — Anything typed in this mode is inserted into the buffer.
  • Command-line mode — For running one of three types of commands:
    • Ex commands — :
    • Searches — / and ?
    • Filters — ! (which you won’t need until you advance somewhat)

Cognition


Learning Vim is learning a skill


Learning a skill is very different to learning knowledge. Skills require that, not just your mind, but also your muscles get involved. We can intellectually know what is required of a task and yet be completely incapable of performing it competently. The gap here is what separates a skill from knowledge: practice. Physical practice. And not just any old practice; it requires Perfect Practice. More on that later.

A good way to learn a new skill:
  1. Normal - Watch an expert do it at normal speed
  2. Slow - Watch an expert do it slowly
  3. With - Do it with an expert, several times, from slow to normal speed
  4. Practice - Practice the new skill several times per day until competent

Use videos if you don’t have access to an expert to watch live. Textual descriptions of steps in tutorials will suffice if no better source is available, but then you lose value by missing the Normal and Slow steps. The value here is in seeing what really is achievable in terms of speed and ease. Seeing a skill being performed properly lowers learning barriers for many who can’t picture themselves being able to do a set of steps explained orally or in written form. Harness the power of Monkey See, Monkey Do.

A digression:
Unfortunately, a lot of video resources for Vim lack in two important ways:
  1. They tend to show too much in one session, confounding higher level concepts with lower level edit sequences.
  2. Some lack OSD overlays showing keystrokes as they’re typed, resulting more in porn than instruction. Watching a Gary Bernhardt session late at night, after the children have gone to bed, is a perfectly acceptable way to unwind after a stressful day.

Racing up the Vim Ramp — topics begging for decent videos:
  • motion.txt — All the builtin motions and text objects (or at least the most useful ones). Seeing them grouped is useful; perhaps the video could similarly group its presentation of these powerful commands.
  • ranges — Something the Vim Ranger can help you with for now.
  • registers
  • Searching & Replacing (Regular Expressions, /, :s///, :g//, :v//) The Walter Alan Zintz (waz) tutorial is this in text form. Other useful tutorials exist.
  • Macros — when to use them, not silly examples where :[range]s/// is preferred. My macro articles are one place to start.
  • Tags — The 80/20 that makes it worth learning.
  • Quickfix — :make & :vimgrep
  • Buffers, Windows and Tabs — Examples of using them wisely. This buffers & args article is a place to begin.

In addition to all of the resources above, I recommend my LearnVim to rapidly acquaint yourself with and acquire the skills of Vim.

Practice

One of the pieces of advice given in LearnVim is the use of a Practice File — a place where you can collect newly learned editing motions and commands requiring frequent practice.

Since LearnVim was first written wherein the Practice File advice was espoused, I have since written a tool to replace the manual maintenance of such a Practice File: VimGym.

The purpose of VimGym is to be a place for you to practice the things you need to work on. As and when you discover new commands or motions or ways to do things, create a practice task in VimGym. Gradually, you will build up a set of exercises targeting your weaknesses, helping you where you need it.

But how do I know if I’m practising right?

Excellent question. This is one of the key requirements for Deliberate Practice — the supervision of a coach — the knowledge that you’re investing energy in the right place, working on the right things.

In Vim terms, this means practising motions and commands and ways that are suitable to the task at hand.

Where do I find a coach?
  • Read :help motion.txt
  • Read the set of learning resources I have linked to in this article
  • Look at sane solutions to vim-golf problems
    • A solution is not sane if you don’t understand it.
    • Ask on #vim for explanations if you think it could be sane given clarity.

Fast, Slow, Medium

Once you know what you should be practising, there is the question of how: “How do I get my fingers Bernhardt fast?!”

Steve Yegge proposes the Fast, Slow, Medium approach.

I wonder if Gary used this…?

Affection

Being a successful Vimmer requires living the Vim Way. Many initially come to Vim with notions carried over from their prior editor pasts and attempt to change Vim accordingly. Many struggle this way until they give up on Vim, decrying it as worthless or inflexible. Those that eventually give up their struggle against Vim discover the opposite; they discover the power and flexibility and extensibility of a tool that, when used right, has continued to be the best “editor of text” for decades and will probably continue to be so for decades more.

Advice: Stop fighting Vim and start using it the way(s) it was intended. When you’re told on #vim that your approach is anathema to the Vim Way: stop, listen and change your approach. Happiness this way lies.


Good luck, and welcome aboard.


Quiz Answer: The cursor is on the "(" character, and in Normal mode the % key jumps to the matching bracket. The d key is given % as its motion. The result is that the entire bracketed chunk of text [ (1, '$') ] is deleted.

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?

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?

Sunday, March 2, 2014

Welcome to the Search Party

Enhanced searches, highlights and matches for Vim

Raimondi and I wrote a nifty little plugin and, well, we’d like to invite you to join the SearchParty.

SearchParty has these awesome features:

Visual Searches

  • * Searches for the next occurrence of the currently selected visual text.
  • # Searches for the prior occurrence of the currently selected visual text.
  • & Starts a :substitute using the currently selected visual text.
I’ve had a goodly amount of <3 on #vim for the visual & command.

Literal Search

<leader>/ prompts for a literal string to search for. This does NOT use a regular expression, so the characters you type here will be searched for literally without any magic interpretation. The <Up> key scrolls through the prior literal search history.

This one is a real crowd pleaser. People come for the highlight candy, but they stay for Literal Search.

Ranged Search


    :7,12 RSearch foo
Searches for "foo" only within the range from lines 7 through 12, both inclusive. The default range is % (the whole buffer).

Tip The normal next and previous keys (n and N) cycle within the range.

Multiple Replacements

<leader>mp prompts for a Search term and then prompts for space separated Replacement terms (use \\ to escape desired spaces). The current line is then duplicated as many times as there are replacements, minus one, and the Search term is then replaced on each line with each successive Replacement.

Perhaps an example would far better explain this:

Given the line:

   Don't credit it on the sunshine

With the cursor on that line, the command:

<leader>mp

Followed by:

Search:credit
Replace:blame

Will produce:

   Don't blame it on the sunshine

That’s no better than :s/// I know, but with the cursor still on the same line, check it:

<leader>mp

Followed by:

Search:sunshine
Replace:moonlight good\ times

Will produce:

   Don't blame it on the sunshine
   Don't blame it on the moonlight
   Don't blame it on the good times

Note Blaming it on the boogie is left as an exercise for the reader.

Search Highlighting

IIRC, this is where SearchParty all began — the ability to easily highlight the word under the cursor without silly machinations like: *#
  • <C-L> Temporarily clears search highlight.
  • <C-BSlash> Toggles search highlighting.
  • <leader>* Highlights all occurrences of word under the cursor.
  • <leader>mah Toggle automatic highlight of all occurrences of word under cursor.
  • <leader>g* Highlights all occurrences of WORD under the cursor.
Note You might think that <leader>mah is a bit verbose but toggling automatic word highlighting is not something I think you’ll need to do very often. If it does bother you, though, this mapping and all of the mappings in SearchParty are <Plug> maps, so you can customise them to your own tastes. Instructions for doing so are in the plugin docs.

Highlighting Print Command

Modern grep commands highlight the search term within the resulting lines (if you so desire). With SearchParty, Vim’s :g// command does too now:

    :g/something/P
Will show the matching lines with all occurrences of "something" on those lines highlighted.

Tip This command can also be used for an arbitrary range and it will highlight the most recent search pattern (@/) within those lines. E.g.:

    :10,20P

Set Search

Sometimes you’d like to highlight that word over there without having to go there, use <leader>* on it, and come back. <leader>ms is the answer.

Matches

This is one of my personal favourites — the ability to have up to six different strings highlighted in big, bold, bright colours all across the screen wherever they appear. The <leader>mm command prompts you for a string (kindly inserting the current word for you) to highlight. If you go past six then the first one is forgotten and replaced with your latest string (cycling like this ad infinitum). I find this useful for ensuring that a few particularly important strings don’t escape my attention throughout a document.

M.A.S.H.

Lastly, we have the Motion Activated Search Highlighter: when you press n/N/#/*/g#/g*, it highlights the match under the cursor differently to all the other matches on screen (if you have :set hlsearch activated). If you don’t use hlsearch, then it will still highlight the current match.

I really like this feature. I used to find it difficult to see where my cursor was when it was within a highlighted search term — the other similarly highlighted blobs would all compete for my attention. M.A.S.H makes this a no-brainer now.

SearchParty

So, welcome to the party. Grab yourself a buffer and get highlighting, make some matches or MASH out on the lounge. Enjoy your evening.

Saturday, February 22, 2014

Y u no, Vim?

Well, Y you can, it would seem…

I was recently reminded (hi, dhruvasagar) of the Y combinator while idling on #vim and I thought to myself… can you Y, Vim? I decided to find out.

I just recently wrote about Anonymous Functions in Vim and they form the cornerstone of my attempt at Y-ing here. I used Mike Vanier’s excellent article: The Y Combinator as a guide (any and all errors are wholly mine); reading it will fill in the huge holes I have chosen to skip over here.

Mr Fibonacci is in the studio with us today, representing la raison d’recurse.

Mr Fibonacci, Zero?
"=> 0
Lovely! Er… and 14?
"=> 377
Amazing!

Now to some code… First up is the standard recursive definition of Fibonacci:
function! RecursiveFibonnaci(n)
  if a:n == 0
    return 0
  elseif a:n == 1
    return 1
  else
    return RecursiveFibonnaci(a:n - 1) + RecursiveFibonnaci(a:n - 2)
  endif
endfunction
And asking our studio guest…
echo RecursiveFibonnaci(10)
"=> 55
Decent. Now just for fun, here’s the same thing written as an Anonymous Function:
let RF = Fn('(n) => if a:n == 0'
        \.'|  return 0'
        \.'|elseif a:n == 1'
        \.'|  return 1'
        \.'|else'
        \.'|  return call(g:RF, [a:n - 1]) + call(g:RF, [a:n - 2])'
        \.'|endif')
Note Fn() is provided by VimaholicsAnonymous.
How does she measure up, Mr Fibonacci?
echo RF(11)
"=> 89
…and does it agree with our recursive stalwart?
echo RecursiveFibonnaci(12) == RF(12)
"=> 1
Standard! But we haven’t even begun to look at Y yet, so here is Mike’s AlmostFibonacci a la Vim:
function! AlmostFibonacci(f)
  silent! unlet b:f
  let b:f = a:f
  return Fn('(n) => if a:n == 0'
        \.'|  return 0'
        \.'|elseif a:n == 1'
        \.'|  return 1'
        \.'|else'
        \.'|  return call(b:f, [a:n - 1]) + call(b:f, [a:n - 2])'
        \.'|endif')
endfunction

You will notice that it contains an almost identical copy of the anonymous recursive Fibonacci (RF) we declared above. It’s not quite the same, of course, because this version is not meant to be self-recursive. It calls the function f provided to AlmostFibonacci. The little silent! unlet b:f dance and the use of a buffer variable in the first place is just some necessary mechanics to pass AlmostFibonacci's f argument into the inner anonymous function. Basically, we cheat through the use of a global. I use a buffer-local here as a baby-global.

How are we doing, Mr F.?
echo call(AlmostFibonacci('RecursiveFibonnaci'), [12])
"=> 144
echo RecursiveFibonnaci(12) == call(AlmostFibonacci('RecursiveFibonnaci'), [12])
"=> 1
Respect.

Heh… The astute among you are half way through a hate comment right now that I have violated one of the laws of thermodynamics, or at least common decency by employing RecursiveFibonnaci in the call to AlmostFibonacci there. Relax. I know I’m cheating. I just wanted to prove that the code worked. We’ll get to actual Y below. :-p

I hesitated whether I would even show this next piece. It’s using the exact same functions as we just used above, but I am using a slightly different call() interface. I actually use this call() interface in the real Y; I wanted you to know that this difference wasn’t.

echo call(call('AlmostFibonacci', ['RecursiveFibonnaci']), [13])
"=> 233
echo RecursiveFibonnaci(13) == call(call('AlmostFibonacci', ['RecursiveFibonnaci']), [13])
"=> 1

And here she is: Y in Vim!
function! Y(f)
  let b:f_ = a:f
  return call(a:f, [Fn('(x) => call(call("Y", [b:f_]), [a:x])')])
endfunction

Again, you will notice the same buffer-local dance for marshalling the function in a:f into the inner anonymous function.

And, hopefully unsurprising by now, here is how we define Fibonacci with Y:
function! Fibonacci(n)
  return call(call('Y', ['AlmostFibonacci']), [a:n])
endfunction

Still kosher, Mr F.?
echo Fibonacci(14)
"=> 377
echo RecursiveFibonnaci(14) == Fibonacci(14)
"=> 1
Splendid! But… how does the Y version compare to the recursive version?
let start = reltime()
call RecursiveFibonnaci(20)
echo reltimestr(reltime(start))
"=> 0.99 seconds
uh huh…
let start = reltime()
call RF(20)
echo reltimestr(reltime(start))
"=> 1.066 seconds
I guess the indirection there causes some overhead, but nothing disastrous…
let start = reltime()
call Fibonacci(20)
echo reltimestr(reltime(start))
"=> 14.56 seconds
:-( There is no God!

It would seem that although "possible", Y in Vim is not advised*. Or, at least, not the way I approached it. Perhaps there’s a brighter way? I’d love to see it.

(*): Y is not advised anywhere, as far as I can tell, except as a mind-stretching exercise from the church of functional dys.

Just to scare little Vimmers late at night, after running this code, the number of anonymous functions in my Vim session was 48098! This code maims unicorns.

That’s Y!

Tuesday, February 11, 2014

What If The Romans Had Vim?


Note This is much more about VimL than MDCLXVI strings; if this code doesn’t rape your cat, you’re welcome.

Call it a kata if you will; I decided over breakfast to have a go at writing a Roman Numeral to Arabic Number converter in VimL. It’d been sufficiently long since I’d written such a converter in any language, and I’d never done one in VimL, so I thought, why not?

I prefer to think away from the console, so I grabbed a notepad and pencil and started doodling a solution based on how I think about parsing Roman Numerals in wet-ware. Roughly, that looked a bit like:

to_arabic(str)
  new stack
  for each roman_letter in str
    val = arabic_value(roman_letter)
    if val < stack.tos()
      stack.push(val - pop())
    elseif val == stack.tos()
      stack.push(val + pop())
    else
      stack.push(val)
    end
  end
  return sum(stack)
end

Note Yes, I am aware that might expose potentially embarrassing belief systems I might be operating under regarding life, the universe and everything. Meh.

I did some mental as well as paper-based run-throughs of the algorithm to convince myself that it would work and then implemented it in VimL. I don’t have the VimL solution to show you because after getting a working version I began refactoring it as I saw opportunities and generalities lurking within the code.

Here is what I ended up with:


function! Roman()
  let obj = {}
  let obj.values = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1 }

  func obj.to_arabic(str) dict
    let self.prior = 0
    return eval(join(map(
          \ reverse(map(split(a:str, '\zs'), 'self.values[v:val]'))
          \, 'self.calc(v:val)'), '+'))
  endfunc

  func obj.calc(v) dict
    let [n, self.prior] = [(a:v < self.prior ? -a:v : a:v), a:v]
    return n
  endfunc

  return obj
endfunction

So while my pseudo-code used a stack and processed the string in original order, the final algorithm reversed the string and just tracked the prior value each time through the loop (map()).

Some explanations of the weirder VimL:
  • I’m using VimL’s Object Oriented approach which is more like javascript’s than C++'s. The Roman() function is actually an object generator. Each such object then has a to_arabic(roman_string) method.
  • I’m also using VimL’s functional-ish approach to processing data lists. Reading such constructs is usually better from the inside out, which begins with:
    • The split(a:str, '\zs') yields a LIST OF individual LETTERS. Unfortunately, the explanation at :help /\zs doesn’t include the idiomatic use shown here of exploding strings out to a list of their component characters.
    • The map( LIST OF LETTERS , 'self.values[v:val]') converts individual Roman Numerals to equivalent Arabic numbers. This, therefore, returns a LIST OF NUMBERS. VimL’s map() function takes the list first and an expression to be evaluated against each element in turn (the resulting list returned by map() is the modification of each element through this evaluated expression). A simple example might help; this generates squares:

        echo map(range(1,10), 'v:val * v:val')
      The archaic looking `v:val` is VimL's Way of exposing access to the value of
      the element. If it helps, this would be equivalent to the Ruby code:

        (1..10).map {|val| val * val}
      Note map() in VimL is destructive, not that that matters here, though.
    • The map( LIST OF NUMBERS , 'self.calc(v:val)') inverts numbers in the list if they precede bigger numbers. Remember the original string order of letters is reversed in this algorithm.
    • The eval(join( LIST OF NUMBERS , '+')) sums the list.
All in all… I think this algorithm does what it’s supposed to do, and it does so with less aggression than solutions I googled for afterwards. o_O

At least the first comment in that last one tries to head the complainant in the right direction early.

The other thing I wanted to show today is micro-tests. Of course, being able to refactor sloppy code into a better solution is made practical with tests.

We all know and love testing, and Vim has decent plugins for doing it properly when you have to (i.e. writing your own plugin.) However, for quick’n'dirty jobs like this, I usually just drop a small inline test at the end of the script:


if expand('%:p') == expand('<sfile>:p')
  let fail = 0
  for t in [
        \  [1, 'I']
        \, [2, 'II']
        \, [3, 'III']
        \, [1992, 'MCMXCII']
        \, [1999, 'MCMXCIX']
        \]
    if t[0] != Roman().to_arabic(t[1])
      echo 'Fail: ' . t[0]
      let fail = 1
    endif
  endfor
  if ! fail
    echo "Ok"
  endif
endif

Note
  • The if expand('%:p') == expand('<sfile>:p') trick is to allow this script to be `:source`d from another script without triggering the unit-tests. I didn’t need this here because roman numeracy has been out of fashion for a while now, but I thought I would show this here as an added bonus.
  • I’ve shown few tests here to keep the post brief. My real tests for this little algorithm number in the fifties. I bet even then I’ve overlooked some poignant design aspect of Roman Numerals. This was meant to be an exercise in the general approach rather than aiming to provide an exhaustively accurate turn-key solution. One notable absence in that vein is the lack of data validation to ensure the roman numeral string is not of Celtic descent.
  • For those with the inability to read between the lines (osse), that last paragraph means: if I have flubbed some VimL, I’d love to hear from you; if I’ve merely upset dead Romans and their counting system, I don’t so much care.
Update: The testing code has been extracted out into a tiny little plugin called vim-u-test if you're interested in experimenting with it.