Tuesday, June 5, 2012

Now You Know When To Macro

Use macros to reformat multi-line text
that would be too finicky
with :ex's linewise commands.

What Are Macros?

Macros are just recorded keystrokes of what the user would normally do manually when faced with the given editing task. As such, they do not represent much of a conceptual challenge and therefore the barrier to adoption is quite low. Once users gingerly try their first few macros, they're hooked and look for new and interesting screws to bang with their dull new hammer.

Regular expressions, on the other hand, are a mess of complicated hieroglyphics to the layman. Like nothing they've used or done before, they appear opaque and unfathomable. The meaning of various atoms within a regular expression are overloaded (they take on different meanings within different contextual sections of the expression) which only adds to the surprise and frustration of those who make the effort to learn them. Let's not even mention Vim's silly variable magic-ness.

For a great many editing situations, though, regular expressions are the sharpest tool in a Vimmer's toolbox. It slices and dices text cleanly and, when you master them, efficiently. I urge every Vimmer to vault the regex wall; glory awaits you on the other side.

For the right task, however, macros are the right tool - a better tool than regular expressions (alone).. But... what is the right task? In my opinion, macros should be used for multi-line edits where Vim's :ex commands (the :substitute (regular expression driven search & replace command) among them) prove fragile and stubborn.

A quick duck around the net revealed several good explanations and examples of macros being used correctly. It also produced a few cases of macros being used where the better choice would have been one or several regexes.

I won't bore you with yet another contrived example here, I'll simply point to some good ones:

Actually... As I was readying to publish this, I just noticed a macro that I always use. Moving to the first paragraph, I type:

  qavipJ}jq

I then run it on the second paragraph with @a and the subsequent ones with @@. I don't make it crawl over the whole file automatically because the asciidoc multi-line headings, lists and admonition blocks get messed up with this macro. for the length of my articles and the builtin } command to move to the next paragraph, it's not a big deal.

Recursive Macros

One neat trick about macros is that they can be recursive. This is often used to make the macro auto repeat without having to specify a range or count of lines when executing it. While it is fairly trivial to specify a range of lines for a macro to execute over, I'd suspect that if it _were_ that easy then using a macro in the first place was probably the wrong choice. With a macro that utilises a find up front to set the position of the subsequent edits and then calls itself as the last step, you have a simple and neat solution that finds and changes all occurrences for you.

Here is a simple example of a recursive macro:
http://dailyvim.blogspot.com/2009/06/recursive-macros.html

And I've discussed recursive macros before too.


Cases Where Macros Were The Wrong Tool

Of the many poor examples of macros, I'll highlight why I consider macros to be a poor choice with the following two cases (chosen randomly):

The source data is all on separate, unrelated lines. This is a clear signal that plain :ex (in this case, a regex :substitute) should be employed instead of a macro.

Original source lines:

  First
  Last
  Phone

Desired destination lines:

  <label>First:</label><input type="text" name="First">
  <label>Last:</label><input type="text" name="Last">
  <label>Phone:</label><input type="text" name="Phone">

Simple regex solution:
  :%s/.*/<label>&:<\/label><input type="text" name="&">

Again, the source data is strictly single-line, requiring again, a simple :substitute.

  %s/^\d\+ -- \(.*\)\( (\d\{4})\)$/<li><em>\1<\/em>\2<\/li>/

.Follow up with some normal commands to wrap the list:
  o</ol><esc>
  <c-o>O<ol><esc>


I've tried to show in this article the following things:
  • Vim's macros are cool when used in the right place - where the source involves complex, interdependent multi-line text.
  • Don't use a macro when the source does not consist of multi-line, interdependent text. Use an :ex command, like :substitute then.
  • LEARN regular expressions. They'll save you a LOT of time in the long haul.

The Art of Edits I - Weaponry

When faced with vicious hordes of marauding tweaks, ghastly repeats and soul shaking changes to the landscape that would make a lesser mortal wine and pule under their desks, Vimmers do not wince or cringe or shy away from their keyboards. This is their domain. This is what they've been practising for. The accomplished warrior does not foolhardily rush in to battle without first examining his lot carefully. What is the nature of the beast? What weapon shall I vanquish it with? How many scalps will I collect before my anime starts?

The Armoury

Various weapons adorn the armoury of the Valiant Vimmer:

Edits

A small hand-held weapon, most effective in cramped and dynamic situations. CAUTION: Sole reliance on this weapon will cause fatigue. Remember to sheathe your Insert Edits when you're not using them. These are the normal, insert and visual mode commands that constitute a lot of ordinary editing work. Read the left column of topics in the table of contents of :help quickref for a summary of awesome tips, tricks and techniques this weapon offers.

Abbreviations

Grips and tactics to wield Edits more gracefully.  These are rehearsed and prepared shortenings that automatically expand out to longer forms while we're typing. They're available in both insert and command-line modes. Read :help :abbreviate for the craft and maintenance of this weapon.

Completions

A mystical amulet that bestows upon the wearer the ability to complete an attack automatically. Adept users of this power can call on recent battlefield attacks, those from historic battles, from battlefield manuals or even from an omniscient guiding hand. Read :help ins-completion for access to this gem of valour.

Regexes

The most devastating hand-held weapon in the Vimmer's arsenal. Due to its ungainly size and the need to retreat from battle while preparing an offensive with this weapon, it is not recommended for close quarter or highly dynamic combat. Often best suited for ranged attacks. The adept Vimmer is an effective user of Vim's regular expressions. To sharpen your regex skills, read :help pattern.txt and you can practise with VimRegexTutor.

Ex

One of a warrior's greatest strengths is the ability to command his troops amidst the frenzy of battle. Ex is the powerful tool Vimmers use to coordinate and execute larger strategies on the battlefield. Raining fire down upon your enemies from afar, changing the very landscape beneath their feet, and even travelling in time are but a few of the awesome powers at the command of a Vimmer versed in Ex. These are all of the : (colon) commands in Vim. These commands are inherently linewise and can therefore be ungainly on multiline monsters (macros are the recommended weapon when facing multi-lined monstrosities). Read :help ex-cmd-index for an overview of battlefield orders you can issue.

Maps

The map is a ranged weapon providing a sortie of commands with the flick of a wrist. Skilled Vimmers spend hours in training creating map weapons for special purpose attacks. The builtin Edits occupy a vast majority of the available body (keyboard) space.  Careless novices unwittingly replace valuable original Edits with inferior maps, only to be defeated or fatigued in extreme battle.  The master Vimmer chooses his maps carefully, regularly preferring to place them on the purpose-built shield (:help mapleader) so as not to interfere with his perfected mastery of the native Edits. Read :help map.txt to start crafting your own maps of devastation.

Macros

Macros are pre-rehearsed battle maneuvers that can be performed instantly with precise execution. A powerful weapon but dangerous when employed on the wrong terrain. The macro will blindly repeat the instructions it was established with. Regardless of whether this weapon is fired when facing the wrong enemy or even friendly troops, it will charge headlong in to battle until its target is demolished or it has been overcome (an error occurs).  Here are several good explanations of macros and their uses.

VimL

The arcane language of the truly wizened Vimmer, capable of wreaking havoc on even the most worthy opponent. Once a spell is cast its effects are almost instantaneous, but the incantation process is long and complicated. This discipline is better practised at quieter times of relative peace whereupon its power may be distilled into volatile potions, sacred scrolls, charged wands and ready tomes that can be more freely and immediately used on the battlefield. Such artefacts in the land of Vim are called plugins.  To begin on your path as a Vim Mage, read Damian Conway's excellent introduction to Vimscript. The accomplished Vimlglot might prefer a deeper analysis. The holy arcanum is kept in :help usr_41.txt.

Veteran Vimmers and Alacritous Acolytes alike are well advised to review their personal arsenal frequently, polishing tarnished weapons and sharpening dull and forgotten ones. Develop a regimen of daily practise in each of these tools and skills so that you may face your next editing evil with brave heart, right mind and quick hand.

Being virtuous in preparation and valiant in battle,
the nature of a Vimmer is irrepressible!

Monday, June 4, 2012

Advanced Macros in Vim, Commentary

This is a bloated comment on: http://blog.sanctum.geek.nz/advanced-vim-macros/

Sharks in Shells

Firstly, there are at least two plugins that can tabulate text in vim: Align and Tabular. Using plugins written in pure vimscript is usually better than shelling out to system tools, because it's more OS independent. On that same note, Vim has a builtin :sort command, so no need to shell out for that either.

You warn against reaching for the hammer when holding screws; that it's sometimes better to use a splash of :ex and a sprinkle of VimL. Indeed, that is true in this example (starting with the cursor on the first line of the original data table):

  :Tabularize / \+/
  :sort
  :%s/\d\{4}/\=strftime('%Y')-submatch(0)/

Mentioning Macro Mechanics

Yanking a macro line from your buffer into a register with "ayy captures the trailing ^J which, if you have something bound to <Enter>, will produce unwanted side-effects. Use ^"ay$ instead (or the VimLocalMacros plugin).


When assigning macros in a let expression, the double-quote form does allow for Vim map-style markup:

  let @a = 'must have ^M literal chars'
  let @a = "can have \<cr> escaped markup"

There's no inherent benefit from moving this sort of macro into a function - it's so uniquely dependent on your current text file (and year!) that it simply doesn't make sense in this case. However, this trick might be useful in more generic situations. Using a function to preserve macro contents allows us to reuse the register that macro was occupying. Personally, I use macros on an ad hoc basis, crafting them quickly for the need at hand and discarding them when done. I might overwrite register @a several times over within a single edit session with various macros on an as needed basis. However, I was asked one day how to persist particular macros for a given file. The embedded-in-a-function approach shown in the article is one solution. I also wrote VimLocalMacros for this purpose.

Macros stop executing if an error occurs. You can use this to your benefit. Design your macros so they deliberately fail - easy way to not have to count and just provide a large-enough number of runs: 999@a

Recursive Macros have a use and are not something to be dismissed as the wrong tool instead of reaching for a scripting language.