tag:blogger.com,1999:blog-11006675022615796802024-03-13T07:58:08.503+08:00Wholly Unbalanced ParenthesesOccasionally coherent observations.bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.comBlogger63125tag:blogger.com,1999:blog-1100667502261579680.post-2387484979736161462014-08-14T17:27:00.000+08:002014-08-14T17:27:33.567+08:00Learning the Tool of Vim<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<strong>Barry Arthur, 2014-08-14</strong><br />
<br />
<a href="https://www.blogger.com/null" name="preamble"></a>
<br />
<blockquote>
<pre style="font-family: inherit;">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.</pre>
<div align="left">
</div>
</blockquote>
<br />
<h2>
<a href="https://www.blogger.com/null" name="_understanding"></a>Understanding</h2>
<br />
If you already understand Vim, you can skip this section.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_vim_is_a_text_editor"></a>Vim is a Text Editor</h3>
<br />
A text editor is a <em>tool</em> for creating and changing text documents.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_vim_has_a_rich_set_of_text_objects"></a>Vim has a Rich Set of Text Objects</h3>
<br />
Think of a <em>Text Object</em> 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.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_vim_is_configurable"></a>Vim is Configurable</h3>
<br />
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.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_vim_is_extensible"></a>Vim is Extensible</h3>
<br />
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.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_vim_is_scriptable"></a>Vim is Scriptable</h3>
<br />
More complicated edits can be recorded and played back as needed.
These are called macros. I link to three macro articles below.<br />
<br />
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.<br />
<br />
I look forward to meeting you on the
<a href="http://of-vim-and-vigor.blogspot.com/2013/03/the-path-of-master-vimler.html">Path
to VimL Mastery</a>.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_vim_is_modal"></a>Vim is Modal</h3>
<br />
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.<br />
<br />
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".<br />
<br />
<h4>
<a href="https://www.blogger.com/null" name="_chording"></a>Chording</h4>
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.<br />
<b><br /></b>
<b>Two things to know about chording:</b><br />
<ol type="1">
<li>
The number of extra interactions it provides is small.
<br />
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
<strong>all</strong> need to be pressed together for the chord to trigger. Chording
is therefore the mathematically poorer <em>Combination</em> as compared to
the richer <em>Permutation</em> that plucking yields.<br />
</li>
<li>
It <em>hurts</em>.
<br />
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 <em>might</em> be
kinder on your wrists.<br />
</li>
</ol>
<br />
<h4>
<a href="https://www.blogger.com/null" name="_plucking"></a>Plucking</h4>
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).<br />
<b><br /></b>
<b>Plucking is better because:</b><br />
<ol type="1">
<li>
The number of extra interactions is vastly greater. (permutation vs
combination)
<br />
</li>
<li>
It <strong>doesn’t</strong> hurt. (as much)
<br />
</li>
</ol>
<br />
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.<br />
<br />
The <code>d</code> 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.<br />
<br />
The <code>d</code> 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 <code>l</code> now, it will delete a letter (a
synonym for the <code>x</code> command); if I type <code>w</code> it will delete from the
cursor to the end of the word; <code>b</code> will delete back from the cursor to
the start of the word; and another <code>d</code> will delete the entire line.
This is a common idiom in Vim — doubling the operator (here, <code>dd</code>)
will operate on the whole line. So, <code>y</code> is the yank operator (and
unsurprisingly, I hope, pressing it DOES NOTHING because Vim is now
waiting for you to tell it <em>what</em> to yank), and <code>yy</code> yanks the whole
line. “Yank” is Vim’s term for copy (for pasting later).<br />
<br />
One particularly nice set of "motions" are the Text Objects. I will
show one here just quickly, but you need to read <code>:help text-objects</code>
(heck, just grab a cold beer and read <em>all</em> of <code>:help motion.txt</code> — thank me later)<br />
<b><br /></b>
<b>The <em>iw</em> Text Object:</b><br />
<br />
The command <code>diw</code> will delete an entire word, no matter where the
cursor is inside the word. This is better than messing around with
<code>dw</code> which only deletes from the cursor to the end of the word.<br />
<br />
<h4>
<a href="https://www.blogger.com/null" name="_what_does_this_have_to_do_with_vim_being_modal"></a>What Does This Have To Do With Vim Being Modal?</h4>
Whereas some editor might use <code>ctrl-d</code> to delete a word, Vim uses
<code>diw</code> To those unfamiliar with Vim, that might seem like a typo: how
can the <code>d</code> <code>i</code> and <code>w</code> keys be used to delete a word?! What if I want
to <em>type</em> a "d" or "i" or "w"?! This is where modes come in. In
<em>Normal</em> mode, Vim uses <code>diw</code> to delete the word at the cursor. In
<em>Insert</em> mode, it inserts (types) these letters instead.<br />
<br />
By separating semantically different concepts, Vim is able to re-use
keys for different purposes. For example, in <em>Normal</em> and <em>Visual</em>
modes, the "%" key jumps the cursor to the bracket matching the one
under the cursor; in <em>Command-line</em> 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 <em>Insert</em> mode it merely inserts a "%" character.<br />
<strong><br /></strong>
<strong><br /></strong>
<strong>Pop Quiz:</strong> Been paying attention? Let’s see.<br />
<br />
Given the following
text, where the cursor is on the "<code>(</code>" :<br />
<pre><code>
</code></pre>
<pre><code>echo getline(1, '$')</code></pre>
<br />
What do you expect the following <em>Normal</em> mode key sequence to do:<br />
<pre><code>
</code></pre>
<pre><code>d%</code></pre>
<pre><code>
</code></pre>
Check your answer at the end of the article.<br />
<br />
<br />
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:<br />
<ul>
<li>
Normal mode — The editor starts in this mode. Use <code><Escape></code> 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.
<br />
</li>
<li>
Visual mode — Used to extend a highlight region over text.
Non-movement commands in this mode execute the command on the
selected text.
<br />
</li>
<li>
Insert mode — Anything typed in this mode is inserted into the buffer.
<br />
</li>
<li>
Command-line mode — For running one of three types of commands:
<br />
<ul>
<li>
Ex commands — <code>:</code>
<br />
</li>
<li>
Searches — <code>/</code> and <code>?</code>
<br />
</li>
<li>
Filters — <code>!</code> (which you won’t need until you advance somewhat)
<br />
</li>
</ul>
</li>
</ul>
<h2>
</h2>
<h2>
<a href="https://www.blogger.com/null" name="_cognition"></a>Cognition</h2>
<br />
<h3>
<a href="https://www.blogger.com/null" name="_learning_vim_is_learning_a_skill"></a>Learning Vim is learning a skill</h3>
<br />
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 <em>know</em> 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.<br />
<b><br /></b>
<b>A good way to learn a new skill:</b><br />
<ol type="1">
<li>
Normal - Watch an expert do it at normal speed
<br />
</li>
<li>
Slow - Watch an expert do it slowly
<br />
</li>
<li>
With - Do it with an expert, several times, from slow to normal speed
<br />
</li>
<li>
Practice - Practice the new skill several times per day until competent
<br />
</li>
</ol>
<br />
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 <em>Normal</em> and <em>Slow</em> 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.<br />
<br />
<table cellpadding="4" frame="void" style="width: 100%px;">
<tbody>
<tr><td style="border-left: 2px solid silver;"><b style="color: #484848;">A digression:</b><br />
Unfortunately, a lot of video resources for Vim lack in two important ways:<br />
<ol type="1">
<li>
They tend to show too much in one session, confounding higher level
concepts with lower level edit sequences.
<br />
</li>
<li>
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.
<br />
</li>
</ol>
</td></tr>
</tbody></table>
<b><br /></b>
<b>Racing up the Vim Ramp — topics begging for decent videos:</b><br />
<ul>
<li>
motion.txt — All the builtin motions and text objects (or at least
the most useful ones). <a href="https://gist.github.com/dahu/3986511">Seeing
them grouped</a> is useful; perhaps the video could similarly group its
presentation of these powerful commands.
<br />
</li>
<li>
ranges — Something the
<a href="http://of-vim-and-vigor.blogspot.com/2012/02/vim-ranger.html">Vim
Ranger</a> can help you with for now.
<br />
</li>
<li>
<a href="http://of-vim-and-vigor.blogspot.com/2012/01/rap-on-vims-registers.html">registers</a>
<br />
</li>
<li>
Searching & Replacing (Regular Expressions, <code>/</code>, <code>:s///</code>, <code>:g//</code>,
<code>:v//</code>) The Walter Alan Zintz
(<a href="http://dahu.github.io/vim_waz_ere/">waz</a>) tutorial is this in text
form. Other <a href="http://vim.wikia.com/wiki/Power_of_g">useful</a>
<a href="https://github.com/dahu/VimRegexTutor">tutorials</a> exist.
<br />
</li>
<li>
Macros — when to use them, not silly examples where <code>:[range]s///</code>
is preferred.
<a href="http://of-vim-and-vigor.blogspot.com/2012/06/now-you-know-when-to-macro.html">My</a>
<a href="http://of-vim-and-vigor.blogspot.com/2012/04/macronomicron.html">macro</a>
<a href="http://of-vim-and-vigor.blogspot.com/2012/06/advanced-macros-in-vim-commentary.html">articles</a>
are one place to start.
<br />
</li>
<li>
Tags — The
<a href="http://of-vim-and-vigor.blogspot.com/2014/06/tag-like-boss.html">80/20</a>
that makes it worth learning.
<br />
</li>
<li>
Quickfix — <code>:make</code> & <code>:vimgrep</code>
<br />
</li>
<li>
Buffers, Windows and Tabs — Examples of using them wisely. This
<a href="http://of-vim-and-vigor.blogspot.com/2014/05/for-argument-sake.html">buffers
& args</a> article is a place to begin.
<br />
</li>
</ul>
<br />
In addition to all of the resources above, I recommend my
<a href="https://github.com/dahu/LearnVim">LearnVim</a> to rapidly
acquaint yourself with and acquire the skills of Vim.<br />
<br />
<h2>
<a href="https://www.blogger.com/null" name="_practice"></a>Practice</h2>
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.<br />
<br />
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:
<a href="https://github.com/dahu/VimGym">VimGym</a>.<br />
<br />
<a href="http://of-vim-and-vigor.blogspot.com/2014/04/seconds-count-not-keystrokes.html">The
purpose of VimGym</a> is to be a place for you to practice the things
<em>you</em> 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 <em>you</em> where you need it.<br />
<b><br /></b>
<b>But how do I know if I’m practising <em>right</em>?</b><br />
<br />
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.<br />
<br />
In Vim terms, this means practising motions and commands and <em>ways</em>
that are suitable to the task at hand.<br />
<b><br /></b>
<b>Where do I find a coach?</b><br />
<ul>
<li>
Read <code>:help motion.txt</code>
<br />
</li>
<li>
Read the set of learning resources I have linked to in this article
<br />
</li>
<li>
Look at <em>sane</em> solutions to <a href="http://www.vimgolf.com/">vim-golf</a> problems
<br />
<ul>
<li>
A solution is not sane if you don’t understand it.
<br />
</li>
<li>
Ask on #vim for explanations if you think it could be sane given clarity.
<br />
</li>
</ul>
</li>
</ul>
<br />
<h3>
<a href="https://www.blogger.com/null" name="_fast_slow_medium"></a>Fast, Slow, Medium</h3>
Once you know <em>what</em> you should be practising, there is the question
of how: “How do I get my fingers Bernhardt fast?!”<br />
<br />
Steve Yegge proposes the
<a href="http://steve-yegge.blogspot.com/2008/09/programmings-dirtiest-little-secret.html">Fast,
Slow, Medium</a> approach.<br />
<br />
I wonder if Gary used this…?<br />
<br />
<h2>
<a href="https://www.blogger.com/null" name="_affection"></a>Affection</h2>
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.<br />
<strong><br /></strong>
<strong>Advice:</strong> 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.<br />
<br />
<br />
Good luck, and welcome aboard.<br />
<strong><br /></strong>
<strong><br /></strong>
<strong>Quiz Answer:</strong> The cursor is on the "<code>(</code>" character, and in <em>Normal</em>
mode the <code>%</code> key jumps to the matching bracket. The <code>d</code> key is given
<code>%</code> as its motion. The result is that the entire bracketed chunk of
text [ <code>(1, '$')</code> ] is deleted.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-85701936819625964222014-06-09T15:09:00.000+08:002014-06-09T20:41:16.968+08:00Tag Like a Boss<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<em>tagging the way god intended</em><br />
<br />
<br />
This short article aims to get you working with Vim
<a href="http://vimhelp.appspot.com/tagsrch.txt.html#tag-commands">tags</a> quickly and
effectively, using its built-in support. Your heavy plugins can wait
outside.<br />
<br />
Before we can jump in and learn the cool commands and power moves,
we have to take charge of our environment.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_preparing_for_a_tagged_lifestyle"></a>Preparing for a Tagged Lifestyle</h3>
<br />
You will need:<br />
<ul>
<li>
A ctags generated <tt>tags</tt> file (<a href="http://ctags.sourceforge.net/">Exuberant Ctags</a> is the choice for most cases)<br /><br />
Typically this is as easy as:<br /><br />
<pre>ctags -R</pre>
<br />in the root of your project. <br />But if you need anything fancier than that, consult <tt>man ctags</tt> for guidance.</li>
<li>
A correctly set <tt>:help <a href="http://vimhelp.appspot.com/options.txt.html#%27tags%27">'tags'</a></tt> option
<br /><br />
The Vim default of <tt>./tags,tags</tt> is probably sufficient for most
projects but you might want to include library tag files or a
project-common tags file.<br /><br />
</li>
<li>
A correctly set <tt>:help
<a href="http://vimhelp.appspot.com/options.txt.html#%27path%27">'path'</a></tt>
option
<br /><br />
My preferred default is:<br /><br />
<pre>set path=.,**</pre>
<br />
Which searches the directory of the current file and all directories
beneath the current directory. See <tt>:help
<a href="http://vimhelp.appspot.com/editing.txt.html#file-searching">file-searching</a></tt>
for more details.<br />
</li>
</ul>
<br />
These options can be set in your <tt>$MYVIMRC</tt> or, better, within
filetype specific plugins in <tt>~/.vim/ftplugin/<the-filetype>.vim</tt> or
<tt>~/.vim/after/ftplugin/<the-filetype>.vim</tt><br />
<br />
With the right setup, we can now enjoy a happy tagging lifestyle.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_living_with_tag_love"></a>Living with Tag Love</h3>
There are <em>many</em> 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
<a href="http://vimhelp.appspot.com/tagsrch.txt.html#tag-commands">tag</a>
<a href="http://vimhelp.appspot.com/tagsrch.txt.html#include-search">commands</a>
later.<br />
<dl>
<dt><tt><br /></tt></dt>
<dt>
<tt>ctrl-]</tt>
</dt>
<dd>Jump to the keyword under the cursor. Tag jumps are
recorded on a <tt>:help
<a href="http://vimhelp.appspot.com/tagsrch.txt.html#tag-stack">tag stack</a></tt>.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>ctrl-t</tt>
</dt>
<dd>Jump to older tag in the stack.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>:ta</tt>
</dt>
<dd>Jump to newer tag in the stack. <tt>:help </tt>
<a href="http://vimhelp.appspot.com/tagsrch.txt.html#%3Apop">:tag</a>
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>:0ta</tt> or <tt>:0tn</tt>
</dt>
<dd>Jump to previously jumped-to tag. I use this
one often after wandering away from the place I tag-jumped into the
current file.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>:ts /something</tt>
</dt>
<dd>Show a list of tags matching the pattern <tt>something</tt>.
<br />
<br />
TIP: Use <tt><ctrl-d></tt> to show a list of tag candidates. This works with partial matches too.<br />
Read more with <tt>:help <a href="http://vimhelp.appspot.com/cmdline.txt.html#c%5FCTRL%2DD">c_CTRL-D</a></tt></dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>g]</tt>
</dt>
<dd>Show a list of tags matching the keyword under the cursor.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>:tj /something</tt>
</dt>
<dd>Show a list of tags matching the pattern
<tt>something</tt>. If there is only one tag in the list, don’t show the
list but instead jump directly to it.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>g ctrl-]</tt>
</dt>
<dd>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.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>[I</tt>
</dt>
<dd>Ordinarily, this just shows all lines in the file matching the keyword
under the cursor — a shortcut to <tt>:g/<c-r><c-w></tt>
<br />
<br />
This map (taken from the Vim help) lets you jump to one of the matches:<br />
<br />
<pre>:map <F4> [I:let nr = input("Which one: ")<Bar>exe "normal " . nr ."[\t"<CR></pre>
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;"><ul>
<li>
Use <tt>ctrl-c</tt> to cancel the choice if you don’t want to jump to any
of them.
<br />
</li>
<li>
Use <tt>``</tt> to jump back to where you were if you accidentally
pressed <tt><esc></tt> or <tt><enter></tt> instead.
<br />
</li>
</ul>
</td></tr>
</tbody></table>
</dd>
</dl>
<h3>
<a href="https://www.blogger.com/null" name="_courteous_cousins"></a>Courteous Cousins</h3>
While not strictly tagging commands, these little gems are semantically related:<br />
<dl>
<dt><tt><br /></tt></dt>
<dt>
<tt>gd</tt> and <tt>gD</tt>
</dt>
<dd>Jump to the <em>local</em> or <em>global</em> declaration
of the keyword under the cursor, respectively.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>gf</tt>
</dt>
<dd>Jump to the file under the cursor.
</dd>
</dl>
<h3>
<a href="https://www.blogger.com/null" name="_honourable_mentions"></a>Honourable Mentions</h3>
While these are not in my <em>daily</em> tag toolbox, I do call upon them occasionally:<br />
<dl>
<dt>
<tt>:tags</tt>
</dt>
<dd>To see my current tag stack.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>:ptj /something</tt>
</dt>
<dd>To show the tag match in the <tt>:help
<a href="http://vimhelp.appspot.com/windows.txt.html#preview%2Dwindow">preview-window</a></tt>.
</dd>
<dt><tt><br /></tt></dt>
<dt>
<tt>ctrl-w ctrl-i</tt> and <tt>ctrl-w ctrl-d</tt>
</dt>
<dd>To split the window,
showing the associated <em>first line</em> or <em>definition</em>, respectively.
</dd>
</dl>
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_tag_you_8217_re_it"></a>Tag! You’re It!</h2>
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.<br />
<br />
Vanilla, when
done right, is a classy choice.<br />
<br />
Get yourself setup to use tags correctly within your projects and get
on living the tag lifestyle!</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-59904962419627374592014-05-28T19:09:00.000+08:002014-05-28T19:18:30.092+08:00For Argument Sake<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<em>The buffer list is dead! Long live the buffer list!</em><br />
<h3>
<br /></h3>
<h3>
<a href="https://www.blogger.com/null" name="_the_buffer_list"></a>The Buffer List</h3>
I have long been a fan of <tt>:ls</tt> and the accompanying <tt>:b </tt>
partial match on buffer name. That basic functionality is rock solid. I still
recommend it to newcomers to our beloved editor. We’ve built
<a href="https://github.com/Raimondi/vim-buffalo">plugins</a>
<a href="https://github.com/paradigm/SkyBison">around</a> it.<br />
<br />
There is only one problem with the buffer list. Well, okay, two problems:<br />
<ol type="1">
<li>
It isn’t able to be reordered,
<br />
</li>
<li>
It isn’t able to be renumbered.
<br />
</li>
</ol>
<h4>
<br /></h4>
<h4>
<a href="https://www.blogger.com/null" name="_ordering"></a>Ordering</h4>
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.<br />
<h4>
<br /></h4>
<h4>
<a href="https://www.blogger.com/null" name="_numbering"></a>Numbering</h4>
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.<br />
<br />
But not all is lost. We have an alternative in Vim. We have the
<em>argument list</em>!<br />
<br />
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_argument_list"></a>Argument List</h2>
Read more about this little gem with <tt>:help arglist</tt><br />
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:<br />
<b><br /></b>
<b>You can slurp up the <tt>.c</tt> files in the <tt>src/</tt> directory into your current window’s argument list:</b><br />
<pre></pre>
<pre>:args src/*.c</pre>
<b><br /></b>
<b>You can do that recursively within all of the subdirectories:</b><br />
<pre></pre>
<pre>: args src/**/*.c</pre>
<b><br /></b>
<b>You can see your current argument list with:</b><br />
<pre></pre>
<pre>:args</pre>
<b><br /></b>
<b>You can add the <tt>.h</tt> files to the argument list with:</b><br />
<pre></pre>
<pre>:argadd src/**/*.h</pre>
<b><br /></b>
<b>You can jump to an argument by partial buffer (file) name match with:</b><br />
<pre></pre>
<pre>:argedit {partial name}</pre>
<b><br /></b>
<b>You can jump to an argument by (1-based) index with:</b><br />
<pre></pre>
<pre>:argument {index}</pre>
<b><br /></b>
<b>You can perform an operation on all of your arguments in a single command:</b><br />
<pre></pre>
<pre>:argdo %s/Long live \zsthe buffer list\ze!/argument lists/ge | update</pre>
<b><br /></b>
<b>Early Quitters:</b><br />
<br />
If you <tt>:quit</tt> before visiting all of the files in your argument
list, Vim will question your intentions. To prevent that, use <tt>:qa</tt>
instead.<br />
<b><br /></b>
<b>Local vs Global:</b><br />
<br />
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.<br />
<pre></pre>
<pre>:help argglobal
:help arglocal</pre>
<b><br /></b>
<b>Awesome, right?</b><br />
<br />
Could it <em>get</em> 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:<br />
<h3>
<br /></h3>
<h3>
<a href="https://www.blogger.com/null" name="_vimfindsme"></a>VimFindsMe</h3>
The light-weight file finder,
<a href="https://github.com/dahu/VimFindsMe">VimFindsMe</a> (VFM) now supports the
argument list. By default, the <tt><leader>ga</tt> 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 <tt>:setlocal number</tt> option. When you press
<tt><enter></tt>+ in this scratch buffer, VFM will set your argument list
to these files, in this order.<br />
<h4>
<br /></h4>
<h4>
<a href="https://www.blogger.com/null" name="_from_tt_vfmedit_tt"></a>From <tt>:VFMEdit</tt></h4>
The <tt>:VFMEdit</tt> command (mapped to <tt><leader>ge</tt> by default) lets
you filter a <tt>find</tt> result on your <tt>:help <em>path</em></tt> option. If you
press <tt><enter></tt> 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:<br />
<pre></pre>
<pre>:VFMArgs</pre>
<br />
If instead you’d like to <em>add</em> all of the files to your argument list,
type within the VFM scratch window:<br />
<pre></pre>
<pre>:VFMArgadd</pre>
<br />
The cumbersome combination of <tt>:argument</tt> and <tt>:argedit</tt> have been
combined into one convenient function called <tt>VFMArgument(arg)</tt>
where <tt>arg</tt> 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 <tt>:VFMArgs</tt> command or the
builtin <tt>:args</tt> command. The buffer name given must exist in the
current argument list. This function has a corresponding command:<br />
<pre></pre>
<pre>:VFMArgument {arg}</pre>
<br />
Which is triggered by <tt><plug>vfm_argument</tt> (mapped to <tt><leader>gg</tt>
by default). The command supports argument list buffer name completion.<br />
<br />
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_you_can_8217_t_do_this_with_the_buffer_list"></a>You Can’t Do This With The Buffer List</h2>
The list of <tt>:buffers</tt> (aka <tt>:ls</tt> aka <tt>:files</tt>) 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 <tt>:bdelete</tt> and <tt>:bwipe</tt> for a minute. But apart from
that, completely inviolable. Excepting certain <tt>&buftype</tt> settings
that make buffers <tt>unlisted</tt>, of course. Besides all that…
watertight.<br />
<br />
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.<br />
<br />
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.
<a href="https://github.com/dahu/VimFindsMe">VimFindsMe</a> solves these problems
by providing a better interface for setting, modifying and deleting
the argument list (<tt>:VFMArgs</tt>), and a single integrated command
(<tt>:VFMArgument</tt>) for jumping to an argument by index or name.<br />
<br />
Care to argue?</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-49270926975663397082014-04-06T14:46:00.000+08:002014-04-07T16:06:02.510+08:00Seconds Count, Not Keystrokes<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<a href="https://www.blogger.com/null" name="preamble"></a>
<br />
<blockquote>
It’s not how short it is that matters, it’s how quick you are.<br />
<div align="right">
<em>at the keys, not under the sheets</em><br />
— Vimmers
</div>
</blockquote>
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_em_golf_a_good_edit_ruined_em"></a><em>Golf: A good edit ruined.</em></h2>
<strong>The Problems:</strong><br />
<ul>
<li>
Vim Golf optimises on the wrong thing: keystrokes
<br />
</li>
<li>
Vim Golf demands a bare-metal Vim
<br />
</li>
</ul>
<div>
<br /></div>
<h3>
Least Number of Keystrokes</h3>
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 <em>exactly</em> what Vimmers
should be doing? It is Bram’s <em>key</em> point in
<a href="http://www.moolenaar.net/habits_2007.pdf">Seven Habits of Effective Text
Editing</a> suggestions, after all.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_bare_metal_vim"></a>Bare-Metal Vim</h3>
<a href="http://www.youtube.com/watch?v=MrTsuvykUZk"><em>EVERYONE</em></a> 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 <em>should</em> be able to utilise
<em>everything</em> they practised.<br />
<br />
<br />
<table borders="none">
<tbody>
<tr><td>Playa:</td> <td> Aw… but how can I show my l33t skilz? :-(</td></tr>
<tr><td>Vimmer:</td> <td> Play Vim Golf</td></tr>
</tbody></table>
<br />
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_is_there_no_place_for_vim_golf"></a>Is There No Place for Vim Golf?</h2>
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 <em>could</em> 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.<br />
<br />
Learning shorter ways to get stuff done in Vim is fun and enlightening. I know.
I’ve spent <em>many</em> 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.<br />
<ul>
<li>
<strong>The process:</strong> discovery, assessment & assimilation.
<br />
</li>
<li>
<strong>The product:</strong> a new command that you really shouldn’t use when live-typing.</li>
</ul>
<br />
<blockquote>
You want to learn every feature the editor offers and use the most efficient
command all the time.<br />
<em>You will waste a lot of time learning things you will never use.</em></blockquote>
<br />
<blockquote>
<div align="right">
<em>Seven Habits of Effective Text Editing - How not to edit effectively</em><br />
— Bram Moolenaar</div>
</blockquote>
<br />
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_perfect_practice_makes_perfect"></a>Perfect Practice Makes Perfect</h2>
<blockquote>
Practice doesn’t make perfect. <em>Perfect</em> practice makes perfect.<br />
<div align="right">
<em>Charles Birch</em><br />
— Taekwondo Master
</div>
</blockquote>
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.<br />
<br />
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 <em>bad</em> 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.<br />
<br />
<hr />
<h2>
<a href="https://www.blogger.com/null" name="_a_better_way"></a>A Better Way</h2>
<b>Use Your Vim, Luke</b><br />
<br />
Vim Golf requires that you use a crippled Vim. No. Use <em>your</em> Vim. You’ve grown
your <tt>~/.vimrc</tt> 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. <strong>Use them!</strong> Practice them. Cultivate them:
throw away bad ones; repair broken ones; develop new ones.<br />
<b><br /></b>
<b>Compete Against Younger You</b><br />
<br />
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.<br />
<br />
<h3>
<a href="https://www.blogger.com/null" name="_method"></a>Method</h3>
<ol type="1">
<li>
Grab an editing task. These can come from your own experience or you can
just use those on Vim Golf.
<br />
</li>
<li>
Reflect on your prior attempt of this problem (you <em>are</em> repeating your
practice exercises, right?!)
<br />
</li>
<li>
Grab your stopwatch; time your execution; record the results.
<br />
</li>
<li>
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?
<br />
</li>
</ol>
<br />
<table bgcolor="#ffffee" cellpadding="15" frame="border" style="width: 100%px;">
<tbody>
<tr><td><b>Macros, Such Fleeting Pleasures</b><br />
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 <tt>:help 'viminfo</tt> 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.<br />
<a href="https://github.com/dahu/VimLocalMacros">VimLocalMacros</a> 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.</td></tr>
</tbody></table>
<br />
Those four steps sound easy enough, right? It couldn’t get any easier! Er,
well, this is Vim. <em>Of course</em> it could be easier! :-) Get to the
<a href="https://github.com/dahu/VimGym">VimGym</a> and let it handle all that finicky
stuff, like:<br />
<ul>
<li>
keeping an extendible store of practice exercises
<br />
</li>
<li>
timing your attempts and storing the results
<br />
</li>
<li>
analysing your game, suggesting improvements and forcing extra practice in
problem areas
<br />
</li>
</ul>
<br />
<table bgcolor="#ffffee" cellpadding="15" frame="border" style="width: 100%px;">
<tbody>
<tr><td><a href="https://github.com/canadaduane/VimKata">VimKata</a> was <em>one of the very first</em>
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.<br />
VimGym is less than VimKata in some ways and therefore so very much more.</td></tr>
</tbody></table>
<br />
So, in summary, my thoughts on Vim Golf and Deliberate Practice for Vim are:<br />
<ul>
<li>
Vim Golf hobbles Vimmers by limiting them to an unrealistically featureless Vim
<br />
</li>
<li>
Vim Golf measures the wrong thing: time taken to complete the task is more
important than the number of keystrokes
<br />
</li>
<li>
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.
<br />
</li>
<li>
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.
<br />
</li>
</ul>
<br />
Whether you choose to go it alone, stick with just VimGolf, or try VimGym too,
I wish you well on your journey.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-25100404149784726782014-03-22T20:05:00.003+08:002014-03-22T20:39:19.716+08:00Closures in VimL<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<hr />
I’ve talked about
<a href="http://of-vim-and-vigor.blogspot.com/2014/01/anonymous-functions-in-viml.html">Anonymous
Functions in VimL</a> before, but what about closures?<br />
<br />
What is <em>necessary</em> for a language to be able to say that it supports closures?
What is <em>sufficient</em> for someone to be able to fake their way through it?<br />
<br />
Here is the first example from
<a href="http://en.wikipedia.org/wiki/Closure_(computer_programming)">Wikipedia’s
Closure</a> article:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">def</span></b> <b><span style="color: black;">start</span></b><span style="color: #990000;">(</span>x<span style="color: #990000;">):</span>
<b><span style="color: blue;">def</span></b> <b><span style="color: black;">increment</span></b><span style="color: #990000;">(</span>y<span style="color: #990000;">):</span>
<b><span style="color: blue;">return</span></b> x<span style="color: #990000;">+</span>y
<b><span style="color: blue;">return</span></b> increment
first_inc <span style="color: #990000;">=</span> <b><span style="color: black;">start</span></b><span style="color: #990000;">(</span><span style="color: #993399;">0</span><span style="color: #990000;">)</span>
second_inc <span style="color: #990000;">=</span> <b><span style="color: black;">start</span></b><span style="color: #990000;">(</span><span style="color: #993399;">8</span><span style="color: #990000;">)</span>
<b><span style="color: black;">first_inc</span></b><span style="color: #990000;">(</span><span style="color: #993399;">3</span><span style="color: #990000;">)</span> <i><span style="color: #9a1900;"># returns 3</span></i>
<b><span style="color: black;">second_inc</span></b><span style="color: #990000;">(</span><span style="color: #993399;">3</span><span style="color: #990000;">)</span> <i><span style="color: #9a1900;"># returns 11</span></i>
<i><span style="color: #9a1900;"># The x value remains the same for new calls to the function:</span></i>
<b><span style="color: black;">first_inc</span></b><span style="color: #990000;">(</span><span style="color: #993399;">1</span><span style="color: #990000;">)</span> <i><span style="color: #9a1900;"># returns 1</span></i>
<b><span style="color: black;">second_inc</span></b><span style="color: #990000;">(</span><span style="color: #993399;">2</span><span style="color: #990000;">)</span> <i><span style="color: #9a1900;"># returns 10</span></i></tt></pre>
</td></tr>
</tbody></table>
<br />
Here is a faked-up alternative in VimL:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">function</span></b>! Start<span style="color: #990000;">(</span><b><span style="color: blue;">x</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> obj <span style="color: #990000;">=</span> <span style="color: #990000;">{}</span>
<b><span style="color: blue;">let</span></b> obj<span style="color: #990000;">.</span><b><span style="color: blue;">x</span></b> <span style="color: #990000;">=</span> <span style="color: navy;">a:x</span>
<b><span style="color: blue;">func</span></b> obj<span style="color: #990000;">.</span>increment<span style="color: #990000;">(</span><b><span style="color: blue;">y</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">return</span></b> self<span style="color: #990000;">.</span><b><span style="color: blue;">x</span></b> <span style="color: #990000;">+</span> <span style="color: navy;">a:y</span>
<b><span style="color: blue;">endfunc</span></b>
<b><span style="color: blue;">return</span></b> obj
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">let</span></b> first_inc <span style="color: #990000;">=</span> Start<span style="color: #990000;">(</span><span style="color: #993399;">0</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> second_inc <span style="color: #990000;">=</span> Start<span style="color: #990000;">(</span><span style="color: #993399;">8</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> first_inc<span style="color: #990000;">.</span>increment<span style="color: #990000;">(</span><span style="color: #993399;">3</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> second_inc<span style="color: #990000;">.</span>increment<span style="color: #990000;">(</span><span style="color: #993399;">3</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> first_inc<span style="color: #990000;">.</span>increment<span style="color: #990000;">(</span><span style="color: #993399;">1</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> second_inc<span style="color: #990000;">.</span>increment<span style="color: #990000;">(</span><span style="color: #993399;">2</span><span style="color: #990000;">)</span></tt></pre>
</td></tr>
</tbody></table>
<br />
Okay, so not <em>really</em> what you think of as a closure, but it lets you get
similar things done. Wikipedia says:<br />
<blockquote>
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.<br />
<div align="right">
— Wikipedia
</div>
</blockquote>
The manual marshalling in our object-oriented implementation above probably
doesn’t count, but it’s a similar idea… isn’t it?<br />
<br />
Vim certainly has First Class Functions and with
<a href="https://github.com/dahu/VimaholicsAnonymous">VimaholicsAnonymous</a>, it has
Anonymous Functions… Does it have closures? If not… does it matter? Can you
achieve something similar using its prototypal object notation?</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-21061147071526385012014-03-02T18:41:00.000+08:002014-03-02T18:41:08.209+08:00Welcome to the Search Party<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<em>Enhanced searches, highlights and matches for Vim</em><br />
<em><br /></em>
<a href="https://github.com/Raimondi">Raimondi</a> and I wrote a nifty little plugin and,
well, we’d like to invite you to join the
<a href="https://github.com/dahu/SearchParty">SearchParty</a>.<br />
<br />
SearchParty has these awesome features:<br />
<h3>
<a href="https://www.blogger.com/null" name="_visual_searches"></a>Visual Searches</h3>
<ul>
<li>
<tt>*</tt> Searches for the next occurrence of the currently selected visual text.
<br />
</li>
<li>
<tt>#</tt> Searches for the prior occurrence of the currently selected visual text.
<br />
</li>
<li>
<tt>&</tt> Starts a <tt>:substitute</tt> using the currently selected visual text.
<br />
</li>
</ul>
I’ve had a goodly amount of <tt><3</tt> on <tt>#vim</tt> for the visual <tt>&</tt> command.<br />
<h3>
<a href="https://www.blogger.com/null" name="_literal_search"></a>Literal Search</h3>
<tt><leader>/</tt> prompts for a literal string to search for. This does <strong>NOT</strong> use a
regular expression, so the characters you type here will be searched for
literally without any magic interpretation. The <tt><Up></tt> key scrolls through the
prior literal search history.<br />
<br />
This one is a real crowd pleaser. People come for the highlight candy,
but they stay for <em>Literal Search</em>.<br />
<h3>
<a href="https://www.blogger.com/null" name="_ranged_search"></a>Ranged Search</h3>
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><span style="color: #ff6600;"> </span> :<span style="color: #993399;">7</span>,<span style="color: #993399;">12</span> RSearch foo</tt></pre>
</td></tr>
</tbody></table>
Searches for "foo" only within the range from lines 7 through 12, both
inclusive. The default range is <tt>%</tt> (the whole buffer).<br />
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Tip" src="data:image/png;base64,
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" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">The normal <em>next</em> and <em>previous</em> keys (<tt>n</tt> and <tt>N</tt>) cycle within the range.</td></tr>
</tbody></table>
<h3>
<a href="https://www.blogger.com/null" name="_multiple_replacements"></a>Multiple Replacements</h3>
<leader>mp prompts for a Search term and then prompts for space separated
Replacement terms (use <em><tt>\\</tt></em> 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.<br />
<br />
Perhaps an example would far better explain this:<br />
<br />
Given the line:<br />
<br />
<pre> Don't credit it on the sunshine</pre>
<br />
With the cursor on that line, the command:<br />
<pre></pre>
<pre><leader>mp</pre>
<br />
Followed by:<br />
<pre></pre>
<pre>Search:credit
Replace:blame</pre>
<br />
Will produce:<br />
<pre></pre>
<pre> Don't blame it on the sunshine</pre>
<br />
That’s no better than <tt>:s///</tt> I know, but with the cursor still on the same
line, check it:<br />
<pre></pre>
<pre><leader>mp</pre>
<br />
Followed by:<br />
<pre></pre>
<pre>Search:sunshine
Replace:moonlight good\ times</pre>
<br />
Will produce:<br />
<pre></pre>
<pre> Don't blame it on the sunshine
Don't blame it on the moonlight
Don't blame it on the good times</pre>
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">Blaming it on the boogie is left as an exercise for the reader.</td></tr>
</tbody></table>
<h3>
<a href="https://www.blogger.com/null" name="_search_highlighting"></a>Search Highlighting</h3>
IIRC, this is where SearchParty all began — the ability to easily highlight
the word under the cursor without silly machinations like: <tt>*#</tt><br />
<ul>
<li>
<tt><C-L></tt> Temporarily clears search highlight.
<br />
</li>
<li>
<tt><C-BSlash></tt> Toggles search highlighting.
<br />
</li>
<li>
<tt><leader>*</tt> Highlights all occurrences of <tt>word</tt> under the cursor.
<br />
</li>
<li>
<tt><leader>mah</tt> Toggle automatic highlight of all occurrences of <tt>word</tt> under cursor.
<br />
</li>
<li>
<tt><leader>g*</tt> Highlights all occurrences of <tt>WORD</tt> under the cursor.
<br />
</li>
</ul>
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">You might think that <tt><leader>mah</tt> 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 <em>all</em> of the mappings in
SearchParty are <tt><Plug></tt> maps, so you can customise them to your own tastes.
Instructions for doing so are in the plugin docs.</td></tr>
</tbody></table>
<h3>
<a href="https://www.blogger.com/null" name="_highlighting_print_command"></a>Highlighting Print Command</h3>
Modern <tt>grep</tt> commands highlight the search term within the resulting lines (if
you so desire). With SearchParty, Vim’s <tt>:g//</tt> command does too now:<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><span style="color: #ff6600;"> </span> :<b><span style="color: blue;">g</span></b>/something/<b><span style="color: blue;">P</span></b></tt></pre>
</td></tr>
</tbody></table>
Will show the matching lines with all occurrences of "something" on those
lines highlighted.<br />
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Tip" src="data:image/png;base64,
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" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">This command can also be used for an arbitrary range and it will highlight
the most recent search pattern (<tt>@/</tt>) within those lines. E.g.:<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><span style="color: #ff6600;"> </span> :<span style="color: #993399;">10</span>,20P</tt></pre>
</td></tr>
</tbody></table>
</td></tr>
</tbody></table>
<h3>
<a href="https://www.blogger.com/null" name="_set_search"></a>Set Search</h3>
Sometimes you’d like to highlight <em>that word over there</em> without having to go
there, use <tt><leader>*</tt> on it, and come back. <tt><leader>ms</tt> is the answer.<br />
<h3>
<a href="https://www.blogger.com/null" name="_matches"></a>Matches</h3>
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 <tt><leader>mm</tt> command prompts you for a
string (kindly inserting the current <tt>word</tt> 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.<br />
<h3>
<a href="https://www.blogger.com/null" name="_m_a_s_h"></a>M.A.S.H.</h3>
Lastly, we have the Motion Activated Search Highlighter: when you press
<tt>n/N/#/*/g#/g*</tt>, it highlights the match under the cursor differently to
all the other matches on screen (if you have <tt>:set hlsearch</tt> activated). If
you don’t use <tt>hlsearch</tt>, then it will still highlight the current match.<br />
<br />
I <em>really</em> 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.<br />
<h2>
<a href="https://www.blogger.com/null" name="_searchparty_2"></a>SearchParty</h2>
So, welcome to the party. Grab yourself a buffer and get highlighting, make
some matches or MASH out on the lounge. Enjoy your evening.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-90987827835506943032014-02-22T19:04:00.000+08:002014-02-22T19:04:18.044+08:00Y u no, Vim?<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<em>Well, Y you can, it would seem…</em><br />
<em><br /></em>
I was recently reminded (hi, <tt>dhruvasagar</tt>) of the Y combinator while idling on
#vim and I thought to myself… can you Y, Vim? I decided to find out.<br />
<br />
I just recently wrote about
<a href="http://of-vim-and-vigor.blogspot.com/2014/01/anonymous-functions-in-viml.html">Anonymous
Functions</a> in Vim and <a href="https://github.com/dahu/VimaholicsAnonymous">they</a> form
the cornerstone of my attempt at Y-ing here. I used Mike Vanier’s excellent
article: <a href="http://mvanier.livejournal.com/2897.html">The Y Combinator</a> as a guide
(<em>any and all errors are wholly mine)</em>; reading it will fill in the <em>huge</em>
holes I have chosen to skip over here.<br />
<br />
Mr Fibonacci is in the studio with us today, representing la raison d’recurse.<br />
<strong><br /></strong>
<strong>Mr Fibonacci, Zero?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><i><span style="color: #9a1900;">"=> 0</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>Lovely! Er… and 14?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><i><span style="color: #9a1900;">"=> 377</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>Amazing!</strong><br />
<br />
Now to some code… First up is the standard recursive definition of Fibonacci:<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! RecursiveFibonnaci<span style="color: #990000;">(</span><b><span style="color: blue;">n</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">if</span></b> <span style="color: navy;">a:n</span> <span style="color: #990000;">==</span> <span style="color: #993399;">0</span>
<b><span style="color: blue;">return</span></b> <span style="color: #993399;">0</span>
<b><span style="color: blue;">elseif</span></b> <span style="color: navy;">a:n</span> <span style="color: #990000;">==</span> <span style="color: #993399;">1</span>
<b><span style="color: blue;">return</span></b> <span style="color: #993399;">1</span>
<b><span style="color: blue;">else</span></b>
<b><span style="color: blue;">return</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: navy;">a:n</span> <span style="color: #990000;">-</span> <span style="color: #993399;">1</span><span style="color: #990000;">)</span> <span style="color: #990000;">+</span> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: navy;">a:n</span> <span style="color: #990000;">-</span> <span style="color: #993399;">2</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">endif</span></b>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<strong>And asking our studio guest…</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">echo</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: #993399;">10</span><span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> 55</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>Decent.</strong> Now just for fun, here’s the same thing written as an Anonymous
Function:<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">let</span></b> RF <span style="color: #990000;">=</span> Fn<span style="color: #990000;">(</span><span style="color: red;">'(n) => if a:n == 0'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'| return 0'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'|elseif a:n == 1'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'| return 1'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'|else'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'| return call(g:RF, [a:n - 1]) + call(g:RF, [a:n - 2])'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'|endif'</span><span style="color: #990000;">)</span></tt></pre>
</td></tr>
</tbody></table>
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;"><tt>Fn()</tt> is provided by
<a href="https://github.com/dahu/VimaholicsAnonymous">VimaholicsAnonymous</a>.</td></tr>
</tbody></table>
<strong>How does she measure up, Mr Fibonacci?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">echo</span></b> RF<span style="color: #990000;">(</span><span style="color: #993399;">11</span><span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> 89</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>…and does it agree with our recursive stalwart?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">echo</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: #993399;">12</span><span style="color: #990000;">)</span> <span style="color: #990000;">==</span> RF<span style="color: #990000;">(</span><span style="color: #993399;">12</span><span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> 1</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>Standard!</strong> But we haven’t even begun to look at <strong>Y</strong> yet, so here is Mike’s
<tt>AlmostFibonacci</tt> a la Vim:<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! AlmostFibonacci<span style="color: #990000;">(</span><b><span style="color: blue;">f</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">silent</span></b>! <b><span style="color: blue;">unlet</span></b> <span style="color: navy;">b:f</span>
<b><span style="color: blue;">let</span></b> <span style="color: navy;">b:f</span> <span style="color: #990000;">=</span> <span style="color: navy;">a:f</span>
<b><span style="color: blue;">return</span></b> Fn<span style="color: #990000;">(</span><span style="color: red;">'(n) => if a:n == 0'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'| return 0'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'|elseif a:n == 1'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'| return 1'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'|else'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'| return call(b:f, [a:n - 1]) + call(b:f, [a:n - 2])'</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span><span style="color: red;">'|endif'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
You will notice that it contains an almost identical copy of the anonymous
recursive Fibonacci (<tt>RF</tt>) 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 <tt>f</tt> provided to <tt>AlmostFibonacci</tt>. The little <tt>silent! unlet b:f</tt>
dance and the use of a buffer variable in the first place is just some
necessary mechanics to pass <tt>AlmostFibonacci</tt>'s <tt>f</tt> 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.<br />
<br />
<strong>How are we doing, Mr F.?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">echo</span></b> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span>AlmostFibonacci<span style="color: #990000;">(</span><span style="color: red;">'RecursiveFibonnaci'</span><span style="color: #990000;">)</span>, <span style="color: #990000;">[</span><span style="color: #993399;">12</span><span style="color: #990000;">])</span>
<i><span style="color: #9a1900;">"=> 144</span></i>
<b><span style="color: blue;">echo</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: #993399;">12</span><span style="color: #990000;">)</span> <span style="color: #990000;">==</span> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span>AlmostFibonacci<span style="color: #990000;">(</span><span style="color: red;">'RecursiveFibonnaci'</span><span style="color: #990000;">)</span>, <span style="color: #990000;">[</span><span style="color: #993399;">12</span><span style="color: #990000;">])</span>
<i><span style="color: #9a1900;">"=> 1</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>Respect.</strong><br />
<br />
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 <tt>RecursiveFibonnaci</tt> in the call to <tt>AlmostFibonacci</tt> there.
Relax. I know I’m cheating. I just wanted to prove that the code worked. We’ll
get to actual <strong>Y</strong> below. <tt>:-p</tt><br />
<br />
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
<tt>call()</tt> interface. I actually use this <tt>call()</tt> interface in the real <strong>Y</strong>; I
wanted you to know that this difference wasn’t.<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">echo</span></b> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><span style="color: red;">'AlmostFibonacci'</span>, <span style="color: #990000;">[</span><span style="color: red;">'RecursiveFibonnaci'</span><span style="color: #990000;">])</span>, <span style="color: #990000;">[</span><span style="color: #993399;">13</span><span style="color: #990000;">])</span>
<i><span style="color: #9a1900;">"=> 233</span></i>
<b><span style="color: blue;">echo</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: #993399;">13</span><span style="color: #990000;">)</span> <span style="color: #990000;">==</span> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><span style="color: red;">'AlmostFibonacci'</span>, <span style="color: #990000;">[</span><span style="color: red;">'RecursiveFibonnaci'</span><span style="color: #990000;">])</span>, <span style="color: #990000;">[</span><span style="color: #993399;">13</span><span style="color: #990000;">])</span>
<i><span style="color: #9a1900;">"=> 1</span></i></tt></pre>
</td></tr>
</tbody></table>
<br />
And here she is: <strong>Y</strong> in Vim!<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! Y<span style="color: #990000;">(</span><b><span style="color: blue;">f</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> <span style="color: navy;">b:f_</span> <span style="color: #990000;">=</span> <span style="color: navy;">a:f</span>
<b><span style="color: blue;">return</span></b> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><span style="color: navy;">a:f</span>, <span style="color: #990000;">[</span>Fn<span style="color: #990000;">(</span><span style="color: red;">'(x) => call(call("Y", [b:f_]), [a:x])'</span><span style="color: #990000;">)])</span>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
Again, you will notice the same buffer-local dance for marshalling the function
in <tt>a:f</tt> into the inner anonymous function.<br />
<br />
And, hopefully unsurprising by now, here is how we define <tt>Fibonacci</tt> with
<strong>Y</strong>:<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! Fibonacci<span style="color: #990000;">(</span><b><span style="color: blue;">n</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">return</span></b> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><span style="color: red;">'Y'</span>, <span style="color: #990000;">[</span><span style="color: red;">'AlmostFibonacci'</span><span style="color: #990000;">])</span>, <span style="color: #990000;">[</span><span style="color: navy;">a:n</span><span style="color: #990000;">])</span>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<strong><br /></strong>
<strong>Still kosher, Mr F.?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">echo</span></b> Fibonacci<span style="color: #990000;">(</span><span style="color: #993399;">14</span><span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> 377</span></i>
<b><span style="color: blue;">echo</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: #993399;">14</span><span style="color: #990000;">)</span> <span style="color: #990000;">==</span> Fibonacci<span style="color: #990000;">(</span><span style="color: #993399;">14</span><span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> 1</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>Splendid! But… how does the </strong>Y<strong> version compare to the recursive version?</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">let</span></b> <b><span style="color: blue;">start</span></b> <span style="color: #990000;">=</span> <b><span style="color: navy;">reltime</span></b><span style="color: #990000;">()</span>
<b><span style="color: blue;">call</span></b> RecursiveFibonnaci<span style="color: #990000;">(</span><span style="color: #993399;">20</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">reltimestr</span></b><span style="color: #990000;">(</span><b><span style="color: navy;">reltime</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">start</span></b><span style="color: #990000;">))</span>
<i><span style="color: #9a1900;">"=> 0.99 seconds</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>uh huh…</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">let</span></b> <b><span style="color: blue;">start</span></b> <span style="color: #990000;">=</span> <b><span style="color: navy;">reltime</span></b><span style="color: #990000;">()</span>
<b><span style="color: blue;">call</span></b> RF<span style="color: #990000;">(</span><span style="color: #993399;">20</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">reltimestr</span></b><span style="color: #990000;">(</span><b><span style="color: navy;">reltime</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">start</span></b><span style="color: #990000;">))</span>
<i><span style="color: #9a1900;">"=> 1.066 seconds</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>I guess the indirection there causes some overhead, but nothing
disastrous…</strong><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">let</span></b> <b><span style="color: blue;">start</span></b> <span style="color: #990000;">=</span> <b><span style="color: navy;">reltime</span></b><span style="color: #990000;">()</span>
<b><span style="color: blue;">call</span></b> Fibonacci<span style="color: #990000;">(</span><span style="color: #993399;">20</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">reltimestr</span></b><span style="color: #990000;">(</span><b><span style="color: navy;">reltime</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">start</span></b><span style="color: #990000;">))</span>
<i><span style="color: #9a1900;">"=> 14.56 seconds</span></i></tt></pre>
</td></tr>
</tbody></table>
<strong>:-( There is no God!</strong><br />
<br />
It would seem that although "possible", <strong>Y</strong> in Vim is not advised<span style="font-family: monospace;">*</span>. Or, at
least, not the way I approached it. Perhaps there’s a brighter way? I’d love to
see it.<br />
<tt><br /></tt>
<tt>(*)</tt>: Y is not <em>advised</em> anywhere, as far as I can tell, except as a
mind-stretching exercise from the church of functional dys.<br />
<br />
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.<br />
<em><br /></em>
<em>That’s Y!</em></div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-91345907322960607852014-02-11T16:58:00.002+08:002014-02-11T22:44:52.192+08:00What If The Romans Had Vim?<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<hr />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">This is much more about VimL than MDCLXVI strings; <em>if</em> this code
doesn’t rape your cat, you’re welcome.</td></tr>
</tbody></table>
<br />
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, <em>why not?</em><br />
<br />
I prefer to think away from the console, so I grabbed a notepad and pencil and
started doodling a solution based on how I <em>think</em> about parsing Roman Numerals
in wet-ware. Roughly, that looked a bit like:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>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</pre>
</td></tr>
</tbody></table>
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">Yes, I am aware that might expose potentially embarrassing belief systems
I might be operating under regarding life, the universe and everything. Meh.</td></tr>
</tbody></table>
<br />
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.<br />
<br />
Here is what I ended up with:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">function</span></b>! Roman<span style="color: #990000;">()</span>
<b><span style="color: blue;">let</span></b> obj <span style="color: #990000;">=</span> <span style="color: #990000;">{}</span>
<b><span style="color: blue;">let</span></b> obj<span style="color: #990000;">.</span><b><span style="color: navy;">values</span></b> <span style="color: #990000;">=</span> <span style="color: #990000;">{</span><span style="color: red;">'M'</span>:<span style="color: #993399;">1000</span>, <span style="color: red;">'D'</span>:<span style="color: #993399;">500</span>, <span style="color: red;">'C'</span>:<span style="color: #993399;">100</span>, <span style="color: red;">'L'</span>:<span style="color: #993399;">50</span>, <span style="color: red;">'X'</span>:<span style="color: #993399;">10</span>, <span style="color: red;">'V'</span>:<span style="color: #993399;">5</span>, <span style="color: red;">'I'</span>:<span style="color: #993399;">1</span> <span style="color: #990000;">}</span>
<b><span style="color: blue;">func</span></b> obj<span style="color: #990000;">.</span>to_arabic<span style="color: #990000;">(</span>str<span style="color: #990000;">)</span> <span style="color: #009900;">dict</span>
<b><span style="color: blue;">let</span></b> self<span style="color: #990000;">.</span>prior <span style="color: #990000;">=</span> <span style="color: #993399;">0</span>
<b><span style="color: blue;">return</span></b> <b><span style="color: navy;">eval</span></b><span style="color: #ff6600;">(join(map(</span>
<span style="color: #ff6600;"> </span> \ <b><span style="color: navy;">reverse</span></b><span style="color: #ff6600;">(map(split(</span><span style="color: navy;">a:str</span>, <span style="color: red;">'</span><span style="color: #cc33cc;">\z</span><span style="color: red;">s'</span><span style="color: #990000;">)</span>, <span style="color: red;">'self.values[v:val]'</span><span style="color: #990000;">))</span>
<span style="color: #ff6600;"> </span> \, <span style="color: red;">'self.calc(v:val)'</span><span style="color: #990000;">)</span>, <span style="color: red;">'+'</span><span style="color: #990000;">))</span>
<b><span style="color: blue;">endfunc</span></b>
<b><span style="color: blue;">func</span></b> obj<span style="color: #990000;">.</span>calc<span style="color: #990000;">(</span><b><span style="color: blue;">v</span></b><span style="color: #990000;">)</span> <span style="color: #009900;">dict</span>
<b><span style="color: blue;">let</span></b> <span style="color: #990000;">[</span><b><span style="color: blue;">n</span></b>, self<span style="color: #990000;">.</span>prior<span style="color: #990000;">]</span> <span style="color: #990000;">=</span> <span style="color: #990000;">[(</span><span style="color: navy;">a:v</span> <span style="color: #990000;"><</span> self<span style="color: #990000;">.</span>prior ? <span style="color: #990000;">-</span><span style="color: navy;">a:v</span> : <span style="color: navy;">a:v</span><span style="color: #990000;">)</span>, <span style="color: navy;">a:v</span><span style="color: #990000;">]</span>
<b><span style="color: blue;">return</span></b> <b><span style="color: blue;">n</span></b>
<b><span style="color: blue;">endfunc</span></b>
<b><span style="color: blue;">return</span></b> obj
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
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 (<tt>map()</tt>).<br />
<br />
Some explanations of the weirder VimL:<br />
<ul>
<li>
I’m using
<a href="http://of-vim-and-vigor.blogspot.com/2013/08/not-classy-vimlpoo.html">VimL’s
Object Oriented</a> approach which is more like
javascript’s than C++'s. The <tt>Roman()</tt> function is actually an object
generator. Each such object then has a <tt>to_arabic(roman_string)</tt> method.</li>
<li>
I’m also using VimL’s
<a href="http://of-vim-and-vigor.blogspot.com/2012/02/jump-to-longest-line.html">functional-ish</a>
approach to processing data lists. Reading
such constructs is usually better from the inside out, which begins with:
<br />
<ul>
<li>
The <tt>split(a:str, '\zs')</tt> yields a LIST OF individual LETTERS.
Unfortunately, the explanation at <tt>:help /\zs</tt> doesn’t include the idiomatic
use shown here of exploding strings out to a list of their component
characters.
<br />
</li>
<li>
The <tt>map( LIST OF LETTERS , 'self.values[v:val]')</tt> converts individual Roman
Numerals to equivalent Arabic numbers. This, therefore, returns a LIST OF
NUMBERS. VimL’s <tt>map()</tt> function takes the list first and an expression to be
evaluated against each element in turn (the resulting list returned by <tt>map()</tt>
is the modification of each element through this evaluated expression). A
simple example might help; this generates squares:
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt> <b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">map</span></b><span style="color: #990000;">(</span><b><span style="color: navy;">range</span></b><span style="color: #990000;">(</span><span style="color: #993399;">1</span>,<span style="color: #993399;">10</span><span style="color: #990000;">)</span>, <span style="color: red;">'v:val * v:val'</span><span style="color: #990000;">)</span></tt></pre>
</td></tr>
</tbody></table>
<pre>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:</pre>
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt> <span style="color: #990000;">(</span><span style="color: #993399;">1</span><span style="color: #990000;">..</span><span style="color: #993399;">10</span><span style="color: #990000;">).</span>map <span style="color: red;">{</span><span style="color: #990000;">|</span>val<span style="color: #990000;">|</span> val <span style="color: #990000;">*</span> val<span style="color: red;">}</span></tt></pre>
</td></tr>
</tbody></table>
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;"><tt>map()</tt> in VimL is destructive, not that that matters here, though.</td></tr>
</tbody></table>
</li>
<li>
The <tt>map( LIST OF NUMBERS , 'self.calc(v:val)')</tt> inverts numbers in the list
if they precede bigger numbers. <em>Remember the original string order of
letters is reversed in this algorithm.</em>
<br />
</li>
<li>
The <tt>eval(join( LIST OF NUMBERS , '+'))</tt> sums the list.
<br />
</li>
</ul>
</li>
</ul>
All in all… I <em>think</em> this algorithm does what it’s supposed to do, and it
does so with less
<a href="http://www.dreamincode.net/forums/topic/145558-roman-and-arabic-numeral-converter/">aggression</a>
<a href="http://www.cplusplus.com/forum/general/27629/">than</a>
<a href="https://community.oracle.com/thread/2081893?tstart=0">solutions</a> I googled for
afterwards. <tt>o_O</tt><br />
<tt><br /></tt>
At least the first comment in that last one tries to head the complainant in
the right direction early.<br />
<br />
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.<br />
<br />
We all know and love testing, and Vim has
<a href="http://www.vim.org/scripts/script.php?script_id=2565">decent</a> plugins for doing
it <a href="http://www.vim.org/scripts/script.php?script_id=2213">properly</a> when you have
to (i.e. <a href="https://github.com/dahu/Area-41">writing your own plugin</a>.) However,
for quick’n'dirty jobs like this, I usually just drop a small inline test at
the end of the script:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">if</span></b> <b><span style="color: navy;">expand</span></b><span style="color: #990000;">(</span><span style="color: red;">'%:p'</span><span style="color: #990000;">)</span> <span style="color: #990000;">==</span> <b><span style="color: navy;">expand</span></b><span style="color: #990000;">(</span><span style="color: red;">'<sfile>:p'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> fail <span style="color: #990000;">=</span> <span style="color: #993399;">0</span>
<b><span style="color: blue;">for</span></b> <b><span style="color: blue;">t</span></b> <b><span style="color: blue;">in</span></b> <span style="color: #990000;">[</span>
<span style="color: #ff6600;"> </span> \ <span style="color: #990000;">[</span><span style="color: #993399;">1</span>, <span style="color: red;">'I'</span><span style="color: #990000;">]</span>
<span style="color: #ff6600;"> </span> \, <span style="color: #990000;">[</span><span style="color: #993399;">2</span>, <span style="color: red;">'II'</span><span style="color: #990000;">]</span>
<span style="color: #ff6600;"> </span> \, <span style="color: #990000;">[</span><span style="color: #993399;">3</span>, <span style="color: red;">'III'</span><span style="color: #990000;">]</span>
<span style="color: #ff6600;"> </span> \, <span style="color: #990000;">[</span><span style="color: #993399;">1992</span>, <span style="color: red;">'MCMXCII'</span><span style="color: #990000;">]</span>
<span style="color: #ff6600;"> </span> \, <span style="color: #990000;">[</span><span style="color: #993399;">1999</span>, <span style="color: red;">'MCMXCIX'</span><span style="color: #990000;">]</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">]</span>
<b><span style="color: blue;">if</span></b> <b><span style="color: blue;">t</span></b><span style="color: #990000;">[</span><span style="color: #993399;">0</span><span style="color: #990000;">]</span> <span style="color: #990000;">!=</span> Roman<span style="color: #990000;">().</span>to_arabic<span style="color: #990000;">(</span><b><span style="color: blue;">t</span></b><span style="color: #990000;">[</span><span style="color: #993399;">1</span><span style="color: #990000;">])</span>
<b><span style="color: blue;">echo</span></b> <span style="color: red;">'Fail: '</span> <span style="color: #990000;">.</span> <b><span style="color: blue;">t</span></b><span style="color: #990000;">[</span><span style="color: #993399;">0</span><span style="color: #990000;">]</span>
<b><span style="color: blue;">let</span></b> fail <span style="color: #990000;">=</span> <span style="color: #993399;">1</span>
<b><span style="color: blue;">endif</span></b>
<b><span style="color: blue;">endfor</span></b>
<b><span style="color: blue;">if</span></b> ! fail
<b><span style="color: blue;">echo</span></b> <span style="color: red;">"Ok"</span>
<b><span style="color: blue;">endif</span></b>
<b><span style="color: blue;">endif</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAJXElEQVRo3u2ZW4xcZ5HHf1Xf951z
uudqD2PPxRPs2AnGTlg7K0jihDiBJIzA4g5P8IDywOUBgUBaZK3EC/JK2dU+IMFmxQMrJavdDCgo
SOQCwUYBh4ADCIOdYM84YYjHl/Gt7UnPTE+fr/bhnG57nAXHyQSC5E8qzZxudc/3r/pX1b9qxMz4
ez7K3/m5AuAKgL8lgLGxMRsdHbW+vj7r6+uz0dFRGxsb+6tWBXm1VWj79u02/sB9bN92J5XpY+Rn
TnFqdoavT9ZY94nPsGPHDnnDRmBsbMzGH7iPHe96B+nk88wfeI54ZIrlMzN8bVXK+AP38eCDD9ob
NgKjo6N27+oOKrVTzP9+LxocziviFeeF02kn/+zW8OijjxZ/RETeUBHYs2cPPVlG8w/7CNVAqARC
FkiyQMgSBkdWsWfPHmKMAFh5Xg8A/rLCJWIiQqVSIT82SagG1CvqFBcU9UUkdHiYubmn8f5lX28i
gojgnFv0RpIkpGna/kyz2aTRaHDu3DlZSgCcOfZbPvCRezg5fZwVWSguHAoQ6h2udxk1Ejo7K/zs
h99i2bJuujorZFmKqtJmk1wIIBZkEEVEy6jBqmvuxszsL1HwsgB472mc3ccH77qKf/3WTv5tQw++
mqAl9/3QavL+q/nPXXs5WzvLzPEn8fMZ2lUhZgHnpARwEXPFgSaIZoiEAgBGmqbEGF8WrVedA0V4
lffeeT2dt27ky/trTDcDumIQ9w9bOd0xzFfGnmBmfB/RIo2FnBghj5FWCkQTDIdpdt4kgKQgCWgC
LkM0bQNYMgqFEIg41Kd87lPv4pPPHOKepycZ3/U88AtuGuhlW7XJ2r7AU9lKZl5q0N2VEU3Jo+Lw
gBQet/MXE00QDYVJAqKYRNI0Jc9zQghLE4FKpYKqw/uENMv4wqfv4re1Ov+zoYtfvX053xhR1mbC
tl8fZ+uWtbw0mzM3ZzQXhIiC+NICoh1tgwASyggEEI8Q8N4vbQTSNEXF43yC88Z1bxlhx/YP8U/f
eYr9vz6MGTTzyB1b1tFZzZhvROYWjHMvLRDSBKfgvOLEYeSLIgCuBOfKhDacc1yq+l42hdR7RAPq
IiHNeOu1q/jSZ+9m5twMj+zcz4GJ43R1ZQTvUfUYiqljds5QB5koooq7uMS2L1/SDOOV9L/LAuCc
Q8QjmhC8kKQLVCoVurvmUTHu3rqet20Yptk0li3vIkkCgsNrwIeAmbCQQxSo+D/D6FaVski8IPmX
DADicK6gUPCBjmpGnldwKlQrGStXLKfZjIgolWrRnAyl2RScKkkaLuoBgOsBrWDSBTYHoiBckv+X
DSDGCCaAEHxCkgbyPMWsShocC80m0UBR1DmS4HGqpFmGiKLOE6MS1AN5cfFFp1FcHsHQpQdQr9dR
VVQE54TEJ1iaguWkwZPnOSCIFpcIwZMkgTRNgLJbO4cLKaYJSPUCkZGXzM8Q8jaFlj4CIqhz5FEI
icNiwElKjIE8RlQVp44YDVSLvFFH8J7TtTpTR09zw+bNWNFuOXjoMKfOzPCPmzaSuBQRxTDAXhGA
y+oDqopoUS1c8DhN+Pkz40RTfv/cESYm5+jsGaTaPcCv9p3gP/7rp+zd/yLOJxw+epbdeyZ5fNez
HPrjMUQTvv3fP+LFw6fo7e7m2w88gmhx9aLRXbqEXjaA7q4qoh71Kd4HVD0nT9d5+NHf8NK8o3a2
zk9/vo8jx04zfaLGlz//cQ5N1jkyLczMpSRplZtu3MTVa0YwYPrkGW6/7QbWv2UNQwN9mChC0QdM
3dJH4GXa2IwV/T08e/AYd91+A+/euomDE4f55TN/4J03X4+I8OH338zjT+zm+reuYsP6NW1hZnh6
e3r4l3//Xx586Eluu+XGopm9nvPA/3dWruilt7ez/byst4uJF6bYcuOGNsg8Lz1pCzTmZwF45LEn
2fy2tdyw6VqeO/AnFprzQOfrB6Ber7+MkOqrDKwcYmHhF+cB9ffSt7yb7/3gKa65ephnD/yJD7zv
9lLNOmbn5gE4N1NnzeohnHNsWL+aY9PnWi25tLi0AGq1GlddNYBIwLmEPM9R16BvWZUvfnYb6grF
uPXWzYDwzps3cfxEjdtu2UyWJYgoK1f0sXzqFCLKRz94N4//+Gl+s/cQMc+57rprGRocBBUQg+iW
FsDU1BRvWtZTdtGAc44oxTTV1dWJxVnMiioi4kjSDlYN9RdTVtkXsqzCrTdtApQQYNvoLS01V5pg
SKE1yMnz/JJ66BUDGB8fZ2iwvwAgvtTzOeCK0opg0QozKSQBgqpiOEQcqF2geRZ7WPAIWjigGJ6X
VsxNTEzQ399TzKztZlO0fIvFc7RIbtCqfqpSRAAFWiXSl2LNFitR1cIZUipR4y8OMpddRl944Xmu
GhkqQoyAcf53UcyUGB15VPJcCovFa2ZalsjCwyDF4NIyKb+nbJSiBaAkSZYGwM6dO23Xrp9wxx13
Fl43w1pS1ygjUihVMy1N2k62lm4o+W6imMW2FTR0SCkUBSlF4xIl8dTUFB/70B1UKykL9ZOYWJln
0m4+xb4nomrlpQoKiRTvtXS+mIIqqpWLhBaggpiVjim00GsaKVs7mb179/K+94yWnAeLBtEwYtuz
IkXC+lIzAWj52vlktKJEGkQWFlNBBMwRpQBgllOv11/7QGNmdv/99/PVr9xDY/YEZpGjR6fJmw1+
t+8A0ydO87v9E1iMdHV20NPTwdrVg1y3YR0iMDzUX0Shve2JCBGJzcUBUI/aAmbGi0eOsn/fBLVa
bUkAFFOV5Xz34SewPOexH+1maNVaurs66ehezpprljEwMMDs7Cxnz9WYnDYe++b3mTlznGo1o7O7
g5GhAa5dN8L1G69hYKAfs/ND/dSRUxydPsn4xCR/nDzC5ORRjk6f4t57721H81Vtp83MYowMDw/T
bDYREbZs2cLo6CgDAwN0dnYiIsXGrtFAVQkhkOc58/PzqCr1ep3du3fT0dHBwYMHeeihh1BVVq9+
8wWjqmdwcJD169ezbt06Nm7cSH9/P1mWMTIyQqVSkVe9Xm82m9ZsNpmdnWVubo5Go0GMsc3rVqK1
nluc997jnGv/bOWImTE3N7do8WtmNJvN9hDvnCNJEpIkoVKp4L1/7btRVW17uDXge+9pbZtb1gr5
hc8X7za994uoISLEGNvSoWVJkrw2Cl35L+UVAFcAXAFwBcClzv8B3eu58OmgDQoAAAAASUVORK5C
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;"><ul>
<li>
The <tt>if expand('%:p') == expand('<sfile>:p')</tt> 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.
<br />
</li>
<li>
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.
<br />
</li>
<li>
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.
<br />
</li>
</ul>
</td></tr>
</tbody></table>
</div>
<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<b>Update:</b> The testing code has been extracted out into a tiny little plugin called <a href="https://github.com/dahu/vim-u-test" target="_blank">vim-u-test</a> if you're interested in experimenting with it.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-21312294565719579382014-02-08T11:59:00.000+08:002014-02-08T11:59:30.786+08:00VimL List Gymnastics<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<hr />
<em>Some common flexing between lists and dicts in VimL.</em><br />
<em><br /></em>
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">let</span></b> a_list <span style="color: #990000;">=</span> <b><span style="color: navy;">range</span></b><span style="color: #990000;">(</span><span style="color: #993399;">1</span>,<span style="color: #993399;">10</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> a_list
<i><span style="color: #9a1900;">"=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></i>
<i><span style="color: #9a1900;">" from list -> dict</span></i>
<b><span style="color: blue;">let</span></b> a_dict <span style="color: #990000;">=</span> <span style="color: #990000;">{}</span>
<b><span style="color: blue;">call</span></b> <b><span style="color: navy;">map</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">copy</span></b><span style="color: #990000;">(</span>a_list<span style="color: #990000;">)</span>, <span style="color: red;">'extend(a_dict, {v:val : (v:val * v:val)})'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> a_dict
<i><span style="color: #9a1900;">"=> {'1': 1, '2': 4, '3': 9, '4': 16, '5': 25, '6': 36, '7': 49, '8': 64, '9': 81, '10': 100}</span></i>
<i><span style="color: #9a1900;">" from dict -> list</span></i>
<b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">keys</span></b><span style="color: #990000;">(</span>a_dict<span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']</span></i>
<b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">map</span></b><span style="color: #990000;">(</span><b><span style="color: navy;">keys</span></b><span style="color: #990000;">(</span>a_dict<span style="color: #990000;">)</span>, <span style="color: red;">'str2nr(v:val)'</span><span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></i>
<b><span style="color: blue;">echo</span></b> <b><span style="color: navy;">values</span></b><span style="color: #990000;">(</span>a_dict<span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">"=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]</span></i>
<i><span style="color: #9a1900;">" collecting a single dictionary from multiple dictionaries</span></i>
<b><span style="color: blue;">let</span></b> b_text <span style="color: #990000;">=</span> <span style="color: red;">"one thing</span><span style="color: #cc33cc;">\n</span><span style="color: red;">two things</span><span style="color: #cc33cc;">\n</span><span style="color: red;">three more things"</span>
<b><span style="color: blue;">let</span></b> b_dict <span style="color: #990000;">=</span> <span style="color: #990000;">{}</span>
<b><span style="color: blue;">call</span></b> <b><span style="color: navy;">map</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">split</span></b><span style="color: #990000;">(</span>b_text, <span style="color: red;">'</span><span style="color: #cc33cc;">\n</span><span style="color: red;">'</span><span style="color: #990000;">)</span>, <span style="color: red;">'extend(b_dict, {split(v:val)[0] : v:val})'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> b_dict
<i><span style="color: #9a1900;">"=> {'one': 'one thing', 'two': 'two things', 'three': 'three more things'}</span></i></tt></pre>
</td></tr>
</tbody></table>
</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-30894089222889162312014-01-13T17:27:00.003+08:002014-03-02T07:00:16.620+08:00Anonymous Functions in VimL<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<i>Admit it, you’ve wanted this for a long time now.</i><br />
<br />
<b>Update:</b> These two functions are now available in <a href="https://github.com/dahu/VimaholicsAnonymous" target="_blank">VimaholicsAnonymous</a>.<br />
<br />
VimL’s list <tt>sort()</tt> method allows the caller to provide a
custom comparison function with which to sort by.
Unfortunately, VimL doesn’t support anonymous functions
(sometimes called lambdas), so the caller is forced to
pre-write their comparator as a full-fledged function and
provide its <tt>funcref</tt> to <tt>sort()</tt>. Well, that ends
today. Now, VimL <em>has</em> anonymous function love! Check it:<br />
<br />
This humble little snippet of code lets vimmers declare
anonymous functions on the fly:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">let</span></b> fn_idx <span style="color: #990000;">=</span> <span style="color: #993399;">0</span>
<b><span style="color: blue;">function</span></b>! Fn<span style="color: #990000;">(</span>fn_form<span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> <span style="color: #990000;">[</span>fn_args, fn_body<span style="color: #990000;">]</span> <span style="color: #990000;">=</span> <b><span style="color: blue;">split</span></b><span style="color: #990000;">(</span><span style="color: navy;">a:fn_form</span>, <span style="color: red;">'</span><span style="color: #cc33cc;">\s</span><span style="color: red;">*=></span><span style="color: #cc33cc;">\s</span><span style="color: red;">*'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> <span style="color: navy;">g:fn_idx</span> <span style="color: #990000;">=</span> <span style="color: navy;">g:fn_idx</span> <span style="color: #990000;">+</span> <span style="color: #993399;">1</span>
<b><span style="color: blue;">let</span></b> fname <span style="color: #990000;">=</span> <span style="color: red;">'AnonFn_'</span> <span style="color: #990000;">.</span> <span style="color: navy;">g:fn_idx</span>
<b><span style="color: blue;">let</span></b> b_elems <span style="color: #990000;">=</span> <b><span style="color: blue;">split</span></b><span style="color: #990000;">(</span>fn_body, <span style="color: red;">'|'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> b_elems<span style="color: #990000;">[-</span><span style="color: #993399;">1</span><span style="color: #990000;">]</span> <span style="color: #990000;">=</span> <span style="color: red;">'return '</span> <span style="color: #990000;">.</span> b_elems<span style="color: #990000;">[-</span><span style="color: #993399;">1</span><span style="color: #990000;">]</span>
<span style="color: #ff6600;"> exe </span><span style="color: red;">'func! '</span> <span style="color: #990000;">.</span> fname <span style="color: #990000;">.</span> fn_args <span style="color: #990000;">.</span> <span style="color: red;">"</span><span style="color: #cc33cc;">\n</span><span style="color: red;">"</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span> <b><span style="color: blue;">join</span></b><span style="color: #990000;">(</span>b_elems, <span style="color: red;">"</span><span style="color: #cc33cc;">\n</span><span style="color: red;">"</span><span style="color: #990000;">)</span> <span style="color: #990000;">.</span> <span style="color: red;">"</span><span style="color: #cc33cc;">\n</span><span style="color: red;">"</span>
<span style="color: #ff6600;"> </span> \<span style="color: #990000;">.</span> <span style="color: red;">'endfunc'</span>
<b><span style="color: blue;">return</span></b> <b><span style="color: blue;">function</span></b><span style="color: #990000;">(</span>fname<span style="color: #990000;">)</span>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
Like this:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">let</span></b> <b><span style="color: blue;">x</span></b> <span style="color: #990000;">=</span> <span style="color: #990000;">[</span><span style="color: red;">"one"</span>,<span style="color: red;">"two"</span>,<span style="color: red;">"three"</span>,<span style="color: red;">"four"</span>,<span style="color: red;">"five"</span>,<span style="color: red;">"six"</span>,<span style="color: red;">"seven"</span>,<span style="color: red;">"eight"</span>,<span style="color: red;">"nine"</span>,<span style="color: red;">"ten"</span><span style="color: #990000;">]</span>
<b><span style="color: blue;">echo</span></b> <b><span style="color: blue;">sort</span></b><span style="color: #990000;">(</span><b><span style="color: blue;">x</span></b>, Fn<span style="color: #990000;">(</span><span style="color: red;">'(a, b) => len(a:a) > len(a:b)'</span><span style="color: #990000;">))</span></tt></pre>
</td></tr>
</tbody></table>
<br />
The magic is in the <tt>Fn()</tt> call. It takes a string
argument of the form:<br />
<pre>(arguments) => function-body statements separated by | (pipe)</pre>
<br />
The last statement will be implicitly returned by the
anonymous function, so no need to explicitly add a
<tt>return</tt> statement.<br />
<br />
Unicorns, or what?!<br />
<br />
What? You want more. Certainly, sir. Behold:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">function</span></b>! Fx<span style="color: #990000;">(</span>fn, <span style="color: #ff6600;">...</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">return</span></b> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><span style="color: navy;">a:fn</span>, <span style="color: navy;">a:000</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<em><br /></em>
<em>That</em> lets you execute an anonymous function, like:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">echo</span></b> <span style="color: red;">'2 ^ 6 = '</span> <span style="color: #990000;">.</span> <b><span style="color: navy;">string</span></b><span style="color: #ff6600;">(Fx(Fn(</span><span style="color: red;">'(a, b) => pow(a:a, a:b)'</span><span style="color: #990000;">)</span>, <span style="color: #993399;">2</span>, <span style="color: #993399;">6</span><span style="color: #990000;">))</span></tt></pre>
</td></tr>
</tbody></table>
<br />
Any cooler and you’d need your jumper! :-D
Oh, but there’s more… I’m just getting warmed up!<br />
<br />
Just because I like you, here’s a little extra gift:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">let</span></b> Mul <span style="color: #990000;">=</span> Fn<span style="color: #990000;">(</span><span style="color: red;">'(a,b)=>let x = a:a | let y=a:b | x*y'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> <span style="color: red;">'5 * 6 = '</span> <span style="color: #990000;">.</span> Fx<span style="color: #990000;">(</span>Mul, <span style="color: #993399;">5</span>, <span style="color: #993399;">6</span><span style="color: #990000;">)</span></tt></pre>
</td></tr>
</tbody></table>
<em><br /></em>
<em>That</em> lets you call your <tt>funcref</tt>'d anonymous function
by name. Did you see what I did there? Yes, I cheated God! I
<em>named</em> an annonymous function. Cool, eh?<br />
<br />
So, apart from the obvious, is this really that amazing? My
vote is: YES! I have <em>plans</em> for this technology. Here’s a
sneaky hint of where I’m looking to take this:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt>CompileMacros
Mul <span style="color: #990000;">=</span> <span style="color: #990000;">((</span><b><span style="color: blue;">a</span></b>,<b><span style="color: blue;">b</span></b><span style="color: #990000;">)</span> <span style="color: #990000;">=></span> <b><span style="color: blue;">let</span></b> <b><span style="color: blue;">x</span></b> <span style="color: #990000;">=</span> <span style="color: navy;">a:a</span> | <b><span style="color: blue;">let</span></b> <b><span style="color: blue;">y</span></b><span style="color: #990000;">=</span><span style="color: navy;">a:b</span> | <b><span style="color: blue;">x</span></b>*<b><span style="color: blue;">y</span></b><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> <span style="color: red;">'5 * 6 = '</span> <span style="color: #990000;">.</span> #<span style="color: #990000;">(</span>Mul, <span style="color: #993399;">5</span>, <span style="color: #993399;">6</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> <span style="color: red;">'2 * 6 = '</span> <span style="color: #990000;">.</span> #<span style="color: #ff6600;">(((</span><b><span style="color: blue;">a</span></b>, <b><span style="color: blue;">b</span></b><span style="color: #990000;">)</span> <span style="color: #990000;">=></span> <span style="color: navy;">a:a</span> * <span style="color: navy;">a:b</span><span style="color: #990000;">)</span>, <span style="color: #993399;">2</span>, <span style="color: #993399;">6</span><span style="color: #990000;">)</span></tt></pre>
</td></tr>
</tbody></table>
<br />
That’s right. I want hygenic macros in VimL. And that code
<em>works</em> in my current experiments. The notation is stolen
from… clojure I believe, where #(…) executes a lambda.<br />
<br />
The call to <tt>CompileMacros</tt> will process any macros in the
surrounding expressions before sourcing the result. Just for
completeness, defining macros currently looks like this:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">call</span></b> Macro<span style="color: #990000;">(</span><span style="color: red;">'(</span><span style="color: #cc33cc;">\+\(</span><span style="color: red;">(.</span><span style="color: #cc33cc;">\{</span><span style="color: red;">-})</span><span style="color: #cc33cc;">\s</span><span style="color: red;">*=>.</span><span style="color: #cc33cc;">\{</span><span style="color: red;">-}</span><span style="color: #cc33cc;">\)</span><span style="color: red;">)'</span>, <span style="color: red;">"Fn('</span><span style="color: #cc33cc;">\\</span><span style="color: red;">1')"</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">call</span></b> Macro<span style="color: #990000;">(</span><span style="color: red;">'</span><span style="color: #cc33cc;">\%</span><span style="color: red;">(</span><span style="color: #cc33cc;">\n\|</span><span style="color: red;">^</span><span style="color: #cc33cc;">\)\@</span><span style="color: red;"><=</span><span style="color: #cc33cc;">\s</span><span style="color: red;">*</span><span style="color: #cc33cc;">\(\w\+\)\s</span><span style="color: red;">*=</span><span style="color: #cc33cc;">\s</span><span style="color: red;">*</span><span style="color: #cc33cc;">\(</span><span style="color: red;">Fn(.*=>.</span><span style="color: #cc33cc;">\{</span><span style="color: red;">-})</span><span style="color: #cc33cc;">\)\s</span><span style="color: red;">*</span><span style="color: #cc33cc;">\n</span><span style="color: red;">'</span>,
<span style="color: #ff6600;"> </span>\ <span style="color: red;">"let </span><span style="color: #cc33cc;">\\</span><span style="color: red;">1 = </span><span style="color: #cc33cc;">\\</span><span style="color: red;">2</span><span style="color: #cc33cc;">\n</span><span style="color: red;">"</span> <span style="color: #990000;">)</span>
<b><span style="color: blue;">call</span></b> Macro<span style="color: #990000;">(</span><span style="color: red;">'#(</span><span style="color: #cc33cc;">\(</span><span style="color: red;">.*</span><span style="color: #cc33cc;">\)</span><span style="color: red;">)</span><span style="color: #cc33cc;">\n</span><span style="color: red;">'</span>, <span style="color: red;">"Fx(</span><span style="color: #cc33cc;">\\</span><span style="color: red;">1)</span><span style="color: #cc33cc;">\n</span><span style="color: red;">"</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">call</span></b> Macro<span style="color: #990000;">(</span><span style="color: red;">'#Fn(</span><span style="color: #cc33cc;">\(</span><span style="color: red;">.</span><span style="color: #cc33cc;">\{</span><span style="color: red;">-}</span><span style="color: #cc33cc;">\)</span><span style="color: red;">)</span><span style="color: #cc33cc;">\n</span><span style="color: red;">'</span>, <span style="color: red;">"Fx(Fn(</span><span style="color: #cc33cc;">\\</span><span style="color: red;">1)</span><span style="color: #cc33cc;">\n</span><span style="color: red;">"</span><span style="color: #990000;">)</span></tt></pre>
</td></tr>
</tbody></table>
<br />
But that will change in the next version. Using regex to
parse is an abomination; I was merely proof-of-concepting
here. I’ll use <a href="https://github.com/dahu/Vimpeg" target="_blank">VimPEG</a> instead.<br />
<br />
Stay tuned, if bending the spoon is what you’re in to.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-66518367975596509272014-01-12T13:34:00.001+08:002014-01-12T18:53:34.852+08:00Help Us Help You<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
I know: you want to be a good #vim citizen; you want to be a
good vimmer; you want to learn and grow and solve your
problems in a timely manner and do so in a safe and
supportive environment filled with smart, caring and funny
peers.<br />
<br />
I know; we all do. And we all can. Here’s how:<br />
<h3>
<a href="https://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_help_yourself"></a>Help Yourself</h3>
Vim has an awesome built-in manual filled with more answers
than you have questions. Almost every problem you have is
addressed somewhere within its many chapters. Unfortunately,
newcomers often can’t find what they’re looking for in the
manual, or don’t understand the answer because of a lack of
jargon or fundamental Vim-specific knowledge. This feeling
of inaccessibility passes over time as you level up in Vim,
but can be debilitating to the beginner. But despair not!
When you don’t understand something in the manual, then
<strong>that</strong> is the time for asking on <tt>#vim</tt>, but more on that
later. First, here are some tips for helping yourself to
some Vim love:<br />
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">I use the loose term <em>manual</em> here to treat the
reference-manual and user-guide as a whole, just as the
built in tools for navigating them do.</td></tr>
</tbody></table>
<ul>
<li>
<tt>:help <em>topic</em></tt> will jump to <em>topic</em> within the
manual.
<br />
</li>
<li>
<tt>:helpgrep <em>pattern</em></tt> will search for all occurrences
of <em>pattern</em> throughout the manual. Use <tt>:cope</tt> to
open the quickfix window of search results.
<br />
</li>
<li>
There is a decent FAQ: <a href="http://vimhelp.appspot.com/vim_faq.txt.html">http://vimhelp.appspot.com/vim_faq.txt.html</a>
<br />
</li>
<li>
The #vim channel has a fact bot called vimgor filled with
answers to common problems. These facts are often keyed on
weird terms that must be supplied to vimgor precisely to
elicit their associated gems of wisdom, which is
practically useless to the uninitiated. Thankfully, vimgor
supports a <tt>listfacts</tt> interface that will return all
known facts containing the given term, e.g:
<br />
<pre>/msg vimgor listfacts file</pre>
will list all known keys containing <em>file</em>.<br />
</li>
</ul>
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAJXElEQVRo3u2ZW4xcZ5HHf1Xf951z
uudqD2PPxRPs2AnGTlg7K0jihDiBJIzA4g5P8IDywOUBgUBaZK3EC/JK2dU+IMFmxQMrJavdDCgo
SOQCwUYBh4ADCIOdYM84YYjHl/Gt7UnPTE+fr/bhnG57nAXHyQSC5E8qzZxudc/3r/pX1b9qxMz4
ez7K3/m5AuAKgL8lgLGxMRsdHbW+vj7r6+uz0dFRGxsb+6tWBXm1VWj79u02/sB9bN92J5XpY+Rn
TnFqdoavT9ZY94nPsGPHDnnDRmBsbMzGH7iPHe96B+nk88wfeI54ZIrlMzN8bVXK+AP38eCDD9ob
NgKjo6N27+oOKrVTzP9+LxocziviFeeF02kn/+zW8OijjxZ/RETeUBHYs2cPPVlG8w/7CNVAqARC
FkiyQMgSBkdWsWfPHmKMAFh5Xg8A/rLCJWIiQqVSIT82SagG1CvqFBcU9UUkdHiYubmn8f5lX28i
gojgnFv0RpIkpGna/kyz2aTRaHDu3DlZSgCcOfZbPvCRezg5fZwVWSguHAoQ6h2udxk1Ejo7K/zs
h99i2bJuujorZFmKqtJmk1wIIBZkEEVEy6jBqmvuxszsL1HwsgB472mc3ccH77qKf/3WTv5tQw++
mqAl9/3QavL+q/nPXXs5WzvLzPEn8fMZ2lUhZgHnpARwEXPFgSaIZoiEAgBGmqbEGF8WrVedA0V4
lffeeT2dt27ky/trTDcDumIQ9w9bOd0xzFfGnmBmfB/RIo2FnBghj5FWCkQTDIdpdt4kgKQgCWgC
LkM0bQNYMgqFEIg41Kd87lPv4pPPHOKepycZ3/U88AtuGuhlW7XJ2r7AU9lKZl5q0N2VEU3Jo+Lw
gBQet/MXE00QDYVJAqKYRNI0Jc9zQghLE4FKpYKqw/uENMv4wqfv4re1Ov+zoYtfvX053xhR1mbC
tl8fZ+uWtbw0mzM3ZzQXhIiC+NICoh1tgwASyggEEI8Q8N4vbQTSNEXF43yC88Z1bxlhx/YP8U/f
eYr9vz6MGTTzyB1b1tFZzZhvROYWjHMvLRDSBKfgvOLEYeSLIgCuBOfKhDacc1yq+l42hdR7RAPq
IiHNeOu1q/jSZ+9m5twMj+zcz4GJ43R1ZQTvUfUYiqljds5QB5koooq7uMS2L1/SDOOV9L/LAuCc
Q8QjmhC8kKQLVCoVurvmUTHu3rqet20Yptk0li3vIkkCgsNrwIeAmbCQQxSo+D/D6FaVski8IPmX
DADicK6gUPCBjmpGnldwKlQrGStXLKfZjIgolWrRnAyl2RScKkkaLuoBgOsBrWDSBTYHoiBckv+X
DSDGCCaAEHxCkgbyPMWsShocC80m0UBR1DmS4HGqpFmGiKLOE6MS1AN5cfFFp1FcHsHQpQdQr9dR
VVQE54TEJ1iaguWkwZPnOSCIFpcIwZMkgTRNgLJbO4cLKaYJSPUCkZGXzM8Q8jaFlj4CIqhz5FEI
icNiwElKjIE8RlQVp44YDVSLvFFH8J7TtTpTR09zw+bNWNFuOXjoMKfOzPCPmzaSuBQRxTDAXhGA
y+oDqopoUS1c8DhN+Pkz40RTfv/cESYm5+jsGaTaPcCv9p3gP/7rp+zd/yLOJxw+epbdeyZ5fNez
HPrjMUQTvv3fP+LFw6fo7e7m2w88gmhx9aLRXbqEXjaA7q4qoh71Kd4HVD0nT9d5+NHf8NK8o3a2
zk9/vo8jx04zfaLGlz//cQ5N1jkyLczMpSRplZtu3MTVa0YwYPrkGW6/7QbWv2UNQwN9mChC0QdM
3dJH4GXa2IwV/T08e/AYd91+A+/euomDE4f55TN/4J03X4+I8OH338zjT+zm+reuYsP6NW1hZnh6
e3r4l3//Xx586Eluu+XGopm9nvPA/3dWruilt7ez/byst4uJF6bYcuOGNsg8Lz1pCzTmZwF45LEn
2fy2tdyw6VqeO/AnFprzQOfrB6Ber7+MkOqrDKwcYmHhF+cB9ffSt7yb7/3gKa65ephnD/yJD7zv
9lLNOmbn5gE4N1NnzeohnHNsWL+aY9PnWi25tLi0AGq1GlddNYBIwLmEPM9R16BvWZUvfnYb6grF
uPXWzYDwzps3cfxEjdtu2UyWJYgoK1f0sXzqFCLKRz94N4//+Gl+s/cQMc+57rprGRocBBUQg+iW
FsDU1BRvWtZTdtGAc44oxTTV1dWJxVnMiioi4kjSDlYN9RdTVtkXsqzCrTdtApQQYNvoLS01V5pg
SKE1yMnz/JJ66BUDGB8fZ2iwvwAgvtTzOeCK0opg0QozKSQBgqpiOEQcqF2geRZ7WPAIWjigGJ6X
VsxNTEzQ399TzKztZlO0fIvFc7RIbtCqfqpSRAAFWiXSl2LNFitR1cIZUipR4y8OMpddRl944Xmu
GhkqQoyAcf53UcyUGB15VPJcCovFa2ZalsjCwyDF4NIyKb+nbJSiBaAkSZYGwM6dO23Xrp9wxx13
Fl43w1pS1ygjUihVMy1N2k62lm4o+W6imMW2FTR0SCkUBSlF4xIl8dTUFB/70B1UKykL9ZOYWJln
0m4+xb4nomrlpQoKiRTvtXS+mIIqqpWLhBaggpiVjim00GsaKVs7mb179/K+94yWnAeLBtEwYtuz
IkXC+lIzAWj52vlktKJEGkQWFlNBBMwRpQBgllOv11/7QGNmdv/99/PVr9xDY/YEZpGjR6fJmw1+
t+8A0ydO87v9E1iMdHV20NPTwdrVg1y3YR0iMDzUX0Shve2JCBGJzcUBUI/aAmbGi0eOsn/fBLVa
bUkAFFOV5Xz34SewPOexH+1maNVaurs66ehezpprljEwMMDs7Cxnz9WYnDYe++b3mTlznGo1o7O7
g5GhAa5dN8L1G69hYKAfs/ND/dSRUxydPsn4xCR/nDzC5ORRjk6f4t57721H81Vtp83MYowMDw/T
bDYREbZs2cLo6CgDAwN0dnYiIsXGrtFAVQkhkOc58/PzqCr1ep3du3fT0dHBwYMHeeihh1BVVq9+
8wWjqmdwcJD169ezbt06Nm7cSH9/P1mWMTIyQqVSkVe9Xm82m9ZsNpmdnWVubo5Go0GMsc3rVqK1
nluc997jnGv/bOWImTE3N7do8WtmNJvN9hDvnCNJEpIkoVKp4L1/7btRVW17uDXge+9pbZtb1gr5
hc8X7za994uoISLEGNvSoWVJkrw2Cl35L+UVAFcAXAFwBcClzv8B3eu58OmgDQoAAAAASUVORK5C
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">You should explore vimgor using either <tt>/msg</tt> or <tt>/query</tt>
to limit interference on the #vim channel.<br />
Feel free to call upon vimgor directly from within #vim if
you are using it to answer someone else’s question. Here
are some additional tools in that vein:<br />
<ul>
<li>
<tt>;help <em>topic</em></tt> ⇐ will provide a URL to Vim’s manual for
the given topic.
<br />
</li>
<li>
<tt>;man <em>topic</em></tt> ⇐ will provide a URL to the
appropriate unix man page.
<br />
</li>
</ul>
</td></tr>
</tbody></table>
<h3>
<a href="https://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_ask_for_help"></a>Ask For Help</h3>
So you’ve looked in the manual and can’t find an answer, or
don’t understand the answer; you’ve looked at the FAQs and
checked in with vimgor to no avail. <em>Now</em> is the time to
ask for help on #vim. Alternatively, ask <a href="http://www.reddit.com/r/vim" target="_blank">reddit's vim</a> channel. The guidelines for asking on #vim apply equally well for reddit's forum, of course.<br />
<br />
Both for reasons of courtesy to others and self-edification,
it’s important to try to find the answers to your own
questions yourself before asking others on #vim. But just as
important is how you ask:<br />
<br />
For simple, easy and short examples, asking inline is
acceptable and preferred, but if your problem is dense or
requires more than a couple lines of data, using a pastebin
service is preferred. Github’s gist is popular, but any
decent ad-free pastebin will be happily tolerated. The
format of your pastebin is also important. Here is an
excellent example: <a href="https://gist.github.com/2759774">https://gist.github.com/2759774</a><br />
<h4>
<a href="https://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_etiquette"></a>Etiquette</h4>
It’s obvious to most people that asking politely will yield
better responses; some people need to be told explicitly.
The good folk of #vim freely donate their time and energy to
helping others discover the joy of being a vimmer. They
delight in sharing their arcane knowledge with interested
learners and inquisitive minds. In case you’re having
trouble reading between the lines here, don’t approach #vim
with these attitudes:<br />
<ul>
<li>
impatience or unwillingness to learn: You don’t care to
read the :help topic provided, you just want the solution
to your exact problem RIGHT NOW. Nothing upsets a vimmer
more. The <tt>:help</tt> is extremely well written if not a bit
obtuse for newcomers, but we’ll help you understand those
intricacies — very rarely is someone told to rtfm and then
left to drown in their own incomprehension.
<br />
</li>
<li>
rudeness or ungratefulness: diagnosing your problem might
take some time and several steps requiring your
participation. If you get frustrated at this or interact
poorly then your chances of continued support diminish
quickly. Be nice, get nice; say please and thank you.
<br />
</li>
</ul>
One of my greatest teaching mentors gave me this gem once:<br />
<blockquote>
Teach as if your mentor is watching from the corner.<br />
<div align="right">
</div>
</blockquote>
The analogy here is: ask as if you weren’t sitting behind a
terminal; ask as if your mum or boss or teacher or doctor or
someone you respect were listening.<br />
<br />
In fairness, I have rarely seen such bad behaviour on #vim;
it’s generally one of the most polite chat rooms I’ve ever
seen. Let’s keep it that way! :-)</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-42244986639709093272013-08-27T13:32:00.002+08:002013-08-27T13:32:08.244+08:00Not Classy, VimLPOO!<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
Rise, fellow VimLers and cease sobbing onto your consoles about the stink of
VimLPOO (VimL Programming Object Orientedly). Vim keeps an open mind and so
should you.<br />
<br />
tl;dr : VimL OOP can haz class-reopening like Ruby<br />
<br />
Okay, maybe not <strong>exactly</strong> like Ruby, but check it:<br />
<br />
VimL’s OOP is more like javascript’s than Ruby’s. It doesn’t have explicit
classes. It uses dictionaries to store data and methods that operate on it.<br />
<br />
Here is one way in VimL to create an object factory:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! Kid<span style="color: #990000;">(</span>name<span style="color: #990000;">)</span> <span style="color: #ff6600;"><b><1></b></span>
<b><span style="color: blue;">let</span></b> <b><span style="color: blue;">k</span></b> <span style="color: #990000;">=</span> <span style="color: #990000;">{}</span> <span style="color: #ff6600;"><b><2></b></span>
<b><span style="color: blue;">let</span></b> <b><span style="color: blue;">k</span></b><span style="color: #990000;">.</span>name <span style="color: #990000;">=</span> <span style="color: navy;">a:name</span> <span style="color: #ff6600;"><b><3></b></span>
<b><span style="color: blue;">func</span></b> <b><span style="color: blue;">k</span></b><span style="color: #990000;">.</span>say<span style="color: #990000;">(</span>blah<span style="color: #990000;">)</span> <span style="color: #009900;">dict</span> <span style="color: #ff6600;"><b><4></b></span>
<b><span style="color: blue;">echo</span></b> self<span style="color: #990000;">.</span>name <span style="color: #990000;">.</span> <span style="color: red;">': '</span> <span style="color: #990000;">.</span> <span style="color: navy;">a:blah</span>
<b><span style="color: blue;">endfunc</span></b>
<b><span style="color: blue;">return</span></b> <b><span style="color: blue;">k</span></b> <span style="color: #ff6600;"><b><5></b></span>
<b><span style="color: blue;">endfunction</span></b>
<b><span style="color: blue;">let</span></b> boy <span style="color: #990000;">=</span> Kid<span style="color: #990000;">(</span><span style="color: red;">'Jack'</span><span style="color: #990000;">)</span> <span style="color: #ff6600;"><b><6></b></span>
<b><span style="color: blue;">let</span></b> girl <span style="color: #990000;">=</span> Kid<span style="color: #990000;">(</span><span style="color: red;">'Jill'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">call</span></b> boy<span style="color: #990000;">.</span>say<span style="color: #990000;">(</span><span style="color: red;">'wassup?'</span><span style="color: #990000;">)</span> <span style="color: #ff6600;"><b><7></b></span>
<b><span style="color: blue;">call</span></b> girl<span style="color: #990000;">.</span>say<span style="color: #990000;">(</span><span style="color: #ff6600;">'chillin'' at the </span>hill<span style="color: #990000;">.</span> <b><span style="color: blue;">u</span></b>?<span style="color: red;">')</span>
<span style="color: red;">echo boy <b><8></b></span></tt></pre>
</td></tr>
</tbody></table>
<pre>Jack: wassup?
Jill: chillin' at the hill. u?
{'name': 'Jack', 'say': function('69')}</pre>
<ol>
<li>
I like to use the full command form <tt>function</tt> when creating object factories (classes?).
<br />
</li>
<li>
The object container is a dictionary (hash).
<br />
</li>
<li>
You can explicitly set attributes outside of methods if desired.
<br />
</li>
<li>
I like to use the short command form <tt>func</tt> for methods. The <tt>dict</tt> argument tells Vim
that this is an instance method, providing us the <tt>self.</tt> accessor.
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">You don’t need the <tt>!</tt> on method declarations as you do for the outer-level.</td></tr>
</tbody></table>
</li>
<li>
The factory must return the newly created object.
<br />
</li>
<li>
Create an instance using the factory.
<br />
</li>
<li>
Call methods using dot notation.
<br />
</li>
<li>
The object in its native format is just a dictionary (hash).
<br />
</li>
</ol>
Typically, after creating the object factory, the VimLPOO developer can’t
re-open it to augment its behaviour although you can derive a new factory type
from an existing one (inheritance without paternity):<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! RudeKid<span style="color: #990000;">(</span>name<span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> rk <span style="color: #990000;">=</span> Kid<span style="color: #990000;">(</span><span style="color: navy;">a:name</span><span style="color: #990000;">)</span> <span style="color: #ff6600;"><b><1></b></span>
<b><span style="color: blue;">func</span></b>! rk<span style="color: #990000;">.</span>say<span style="color: #990000;">(</span>blah<span style="color: #990000;">)</span> <span style="color: #009900;">dict</span> <span style="color: #ff6600;"><b><2></b></span>
<b><span style="color: blue;">echo</span></b> self<span style="color: #990000;">.</span>name <span style="color: #990000;">.</span> <span style="color: red;">': Yo, biatch! '</span> <span style="color: #990000;">.</span> <span style="color: navy;">a:blah</span>
<b><span style="color: blue;">endfunc</span></b>
<b><span style="color: blue;">return</span></b> rk
<b><span style="color: blue;">endfunction</span></b>
<b><span style="color: blue;">let</span></b> boy <span style="color: #990000;">=</span> RudeKid<span style="color: #990000;">(</span><span style="color: red;">'Jack'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">let</span></b> girl <span style="color: #990000;">=</span> Kid<span style="color: #990000;">(</span><span style="color: red;">'Jill'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">call</span></b> boy<span style="color: #990000;">.</span>say<span style="color: #990000;">(</span><span style="color: red;">'wassup?'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">call</span></b> girl<span style="color: #990000;">.</span>say<span style="color: #990000;">(</span><span style="color: red;">'wtf?'</span><span style="color: #990000;">)</span>
<b><span style="color: blue;">echo</span></b> boy</tt></pre>
</td></tr>
</tbody></table>
<pre>Jack: Yo, biatch! wassup?
Jill: wtf?
{'name': 'Jack', 'say': function('72')}</pre>
<ol>
<li>
Base this object on the parent factory.
<br />
</li>
<li>
Override methods as desired.
<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">The use of <tt>!</tt> is now required because the method already exists in the
base object.</td></tr>
</tbody></table>
</li>
</ol>
But I’m not here today to talk about weak inheritance. I wanna play with class
re-opening, Vim style.<br />
<br />
As a quick recap, a Vim object is a dictionary with data and methods that can
use the <tt>self.</tt> modifier internally to refer to its data and other methods. It
turns out that Vim is not too particular about <em>who</em> gets to claim <tt>dict</tt>
access on your objects. You’re free to create external functions, adorned with
the <tt>dict</tt> modifier, and have them manipulate your objects as if they were
created with the class originally:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">function</span></b>! <span style="color: navy;">s:slapped</span><span style="color: #990000;">()</span> <span style="color: #009900;">dict</span>
<b><span style="color: blue;">echo</span></b> self<span style="color: #990000;">.</span>name <span style="color: #990000;">.</span> <span style="color: red;">" just got slapped!"</span>
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
This happens to be a script-local (<tt>s:</tt>) function; global scope would work too,
but why pollute unnecessarily? Now, if you tried to do a naive direct call of
this, you’d be sorely disappointed:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">call</span></b> boy<span style="color: #990000;">.</span>slapped<span style="color: #990000;">()</span></tt></pre>
</td></tr>
</tbody></table>
<pre>Error detected while processing jack_and_jill.vim:
Line 42:
E716: Key not present in Dictionary: slapped</pre>
<br />
That makes sense… We created <tt>slapped()</tt> as a script-local function, not a
method on the <tt>boy</tt> instance.<br />
<table cellpadding="4" frame="void">
<tbody>
<tr valign="top">
<td><img alt="Note" src="data:image/png;base64,
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
YII=" style="border-image: none 0;" />
</td>
<td style="border-left: 1px solid silver;">Adding the method to the <tt>Kid()</tt> factory <em>after</em> having created the <tt>boy</tt>
instance would be just as useless.</td></tr>
</tbody></table>
<br />
Happiness is just a <tt>call</tt> away:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><b><span style="color: blue;">call</span></b> <b><span style="color: blue;">call</span></b><span style="color: #990000;">(</span><span style="color: red;">'s:slapped'</span>, <span style="color: #990000;">[]</span>, boy<span style="color: #990000;">)</span>
<i><span style="color: #9a1900;">" Jack just got slapped!</span></i></tt></pre>
</td></tr>
</tbody></table>
<br />
:-D How cool is that?!<br />
<br />
I have a little project in the works that uses this to allow clients of the
engine to inject their own solutions to various parts of the workflow. It’s
almost done, so I should be able to show something a bit more real-worldy soon.
For now, what mischief can you concoct with this shiny new toy? I look forward
to finding out. :-)<br />
<br />
Vim on!</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-61435268297541206582013-04-22T06:27:00.004+08:002013-04-23T05:20:01.235+08:00Sort Me A Column<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="preamble"></a>
Need to sort a column within your table without messing with the other
columns?<br />
Vim has your back with blockwise visual selections and a bit
of gymnastics.<br />
<br />
<b>Sample table:</b><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>1 this 1 apple is 1
2 this 4 durian is 2
3 this 3 carrot is 3
4 this 2 banana is 4
5 this 5 eggplant is 5</pre>
</td></tr>
</tbody></table>
<b><br /></b>
<b>Desired result:</b><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>1 this 1 apple is 1
2 this 2 banana is 2
3 this 3 carrot is 3
4 this 4 durian is 4
5 this 5 eggplant is 5</pre>
</td></tr>
</tbody></table>
<b><br /></b>
<b>[wrong] Result of naive <tt>:sort</tt> command:</b><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>1 this 1 apple is 1
2 this 4 durian is 2
3 this 3 carrot is 3
4 this 2 banana is 4
5 this 5 eggplant is 5</pre>
</td></tr>
</tbody></table>
<b><br /></b>
<b>[wrong] Result of <tt>:sort /^. /</tt> command (to skip leading numbers):</b><br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>1 this 1 apple is 1
4 this 2 banana is 4
3 this 3 carrot is 3
2 this 4 durian is 2
5 this 5 eggplant is 5</pre>
</td></tr>
</tbody></table>
<hr />
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_a_solution"></a>A Solution</h2>
<ol type="1">
<li>
Visually select the column of interest with <tt>ctrl-v</tt>
<br />
</li>
<li>
Cut it with <tt>x</tt>
<br />
</li>
<li>
Open a temporary scratch buffer with <tt>:enew</tt>
<br />
</li>
<li>
Paste with <tt>p</tt>
<br />
</li>
<li>
Sort with <tt>:sort</tt>
<br />
</li>
<li>
If you need to, ensure your cursor is line 1, col 1 with <tt>gg0</tt>
<br />
</li>
<li>
Visually select and yank everything, blockwisely with <tt>ctrl-vG$y</tt>
<br />
</li>
<li>
Switch back to where you came from with <tt>ctrl-6</tt> (<tt>ctrl-^</tt>)
<br />
</li>
<li>
Jump to the start of your original cut with <tt>`[</tt>
<br />
</li>
<li>
Paste with <tt>P</tt>
<br />
</li>
</ol>
</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-72336178308528674582013-04-20T20:10:00.001+08:002013-04-20T20:10:22.726+08:00Partial Explosion<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
Vim has a powerful regex spell, <tt> :help /\%[] </tt> . While it might look
like the emoticon of a lunging crocodile, this little piece of regex
lets vimmers match words in either their full form or any partial
reduction thereof. That’s a messy explanation. A showing will help:<br />
<br />
The pattern:<br />
<pre>
</pre>
<pre>/r\%[ead]</pre>
<br />
Will match: <em>r</em>, <em>re</em>, <em>rea</em>, and <em>read</em><br />
<br />
Unicorns, I know!<br />
<br />
This actually gets a lot of love in Vim’s syntax highlighting file for
its own language, VimL. I wish it didn’t to be honest. I actually
deplore the availability of partial keyword forms like <em>fu</em> instead of
the full form <em>function</em>. But that’s not why we’re here today, so
let’s move on.<br />
<br />
Not all regex engines support this awesome atom. In fact… I don’t
know of any other that does.<br />
<br />
I am in the process of creating a vim.lang file for source-highlighter. As you would expect, it has a regex based DSL for specifying syntax items. One such item is for <tt>keyword</tt>s. Easy!, I thought, I’ll just grab the keywords from Vim’s syntax files and… oh, crap… It’s infested with <tt>\%[]</tt>…<br />
<br />
So… Let’s explode them.<br />
<br />
With a quick regex, I got the Vim keywords split out onto separate lines, like this:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>a
arga[dd]
ar[gs]
bar
bn[ext]
breaka[dd]</pre>
</td></tr>
</tbody></table>
<br />
And then we can explode out the partial variations with this little regex:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>:%s/^\(.\{-}\)\[\(.\{-}\)\]/\=join(map(range(len(submatch(2))+1), 'submatch(1).strpart(submatch(2), 0, v:val)'), ' ')/</pre>
</td></tr>
</tbody></table>
<br />
Producing:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>a
arga argad argadd
ar arg args
bar
bn bne bnex bnext
breaka breakad breakadd</pre>
</td></tr>
</tbody></table>
<br />
And just in time for dinner, too.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-11595407542842306832013-04-20T14:40:00.004+08:002013-04-20T14:43:27.762+08:00I'd Tap That<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="preamble"></a>
The Ruby world and many others have a <tt>tap()</tt> method on a class way up
in the hierarchy near <em>God</em> that lets the bug hunting developer peek
inside of objects during execution to see what the gnomes are getting
up to under the covers. I needed just such a tool for my latest
dabblings in Vim, so I built one and thought I’d share it here:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.5
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">function</span></b>! Tap(thing)
<b><span style="color: blue;">echom</span></b> <span style="color: #009900;">string</span>(a:thing)
<b><span style="color: blue;">return</span></b> a:thing
<b><span style="color: blue;">endfunction</span></b></tt></pre>
</td></tr>
</tbody></table>
<br />
It’s not very intimidating, I know, but thats a little gem of a
function. I used it to debug the setting of the <tt>includeexpr</tt> option in
Vim, as shown here:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><!-- Generator: GNU source-highlight 3.1.5
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<br />
<pre><tt><b><span style="color: blue;">set</span></b> <span style="color: #009900;">includeexpr</span>=Tap(<span style="color: #009900;">substitute</span>(Tap(v:fname),<span style="color: red;">'</span><span style="color: #cc33cc;">\\</span><span style="color: red;">${</span><span style="color: #cc33cc;">\\</span><span style="color: red;">?</span><span style="color: #cc33cc;">\\</span><span style="color: red;">(</span><span style="color: #cc33cc;">\\</span><span style="color: red;">w</span><span style="color: #cc33cc;">\\</span><span style="color: red;">+</span><span style="color: #cc33cc;">\\</span><span style="color: red;">)}</span><span style="color: #cc33cc;">\\</span><span style="color: red;">?'</span>,<span style="color: red;">'</span><span style="color: #cc33cc;">\\</span><span style="color: red;">=expand(</span><span style="color: #cc33cc;">\"</span><span style="color: red;">$</span><span style="color: #cc33cc;">\"</span><span style="color: red;">.submatch(1))'</span>,<span style="color: red;">'g'</span>))</tt></pre>
</td></tr>
</tbody></table>
<br />
I was suspicious that the <tt>v:fname</tt> variable was not being set properly
before <tt>includeexpr</tt> was being evaluated by Vim. <tt>Tap()</tt> proved that to be
the case which allowed me to focus my debug efforts on the real cause,
instead of continuing to waste time fretting over the search and
replace patterns in the <tt>substitute</tt> and whether I’d escaped them
correctly or not. I only wish the <tt>Tap()</tt> inspiration had come to me
sooner than it really did. Oh well… with <tt>Tap()</tt> as a permanent
fixture in my <tt>~/.vimrc</tt>, hopefully it won’t take me as long to think of
it the next time I need its services.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-48983226078730799662013-04-06T21:23:00.002+08:002013-04-06T21:23:59.115+08:00Bisectly<span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Verdana, sans-serif;"><b>wtf?!</b></span></span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">We've all been there before; all too often, in fact. There you are in the middle of a serious edit when all of a sudden some vile little gremlin spits at you from deep within Vim. "Argh!" You instantly seethe with indignant rage, vowing to righteously lance that festering pustule...! when the terrifying realisation strikes you - you don't know where this bug is coming from. "Gack." You say as you think to yourself: "It <i>must</i> be one of the plugins... surely? Ok... it <i>could</i> be in my </span><span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Courier New, Courier, monospace;">~/.vimrc</span></span><span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">... But no! I watered it only yesterday and there were hardly any weeds there. So, it's a plugin... But... which one? How am I supposed to find the menacing little urchin among all those other well behaving citizens in my plugin pool?" Historically the Vimmer faced with this situation has had very little option but to manually move plugins aside until the faulty one is found. This is a laborious, boring and very frustrating task. Even if you knew well enough to use binary search to speed up the process, it's still not something anyone <i>wants</i> to do. Thankfully now, you don't have to. Now, you can do it with <a href="https://github.com/dahu/bisectly" target="_blank">Bisectly</a>.</span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; orphans: 2; text-align: -webkit-auto; widows: 2;"></span><br />
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif;"><span style="font-size: 14px; line-height: 17px;"><i>Bisectly is a plugin-manager agnostic fault localisation tool for finding which plugin is causing you nose-bleeds.</i></span></span><br />
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px;">
<br /></div>
<br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">Bisectly uses BSFL (Binary Search Fault Localisation) to quickly whittle down the set of loaded plugins in search of the one causing you pain. It uses a cutesy command interface to identify which sessions the user considers fault-free (</span><span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Courier New, Courier, monospace;">:Unicorns</span></span><span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">) or faulty (</span><span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Courier New, Courier, monospace;">:Zombies</span></span><span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">). This process continues until a single plugin remains, which Bisectly considers to be the guilty party.</span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Verdana, sans-serif;"><b>Plugin Manager Agnostic</b></span></span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">Bisectly interrogates your normal Vim for its final set of </span><span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Courier New, Courier, monospace;">&runtime</span></span><span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"> paths before juggling those in the BSFL algorithm. As such, it should be completely independent of any plugin manager. I have tested it with pathogen only, but I don't foresee any issues with Vam or Vundle. Feedback appreciated on this.</span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Verdana, sans-serif;"><b>Possible Futures</b></span></span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">My original idea for the Zombies Vs Unicorns theme was actually in regard to using BSFL on locating faults within a user's </span><span style="background-color: white; color: #333333; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><span style="font-family: Courier New, Courier, monospace;">~/.vimrc</span></span><span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"> file. I have a plugin that is all-but-finished for this purpose but it has been delayed until a better vimscript parser can be completed. Work on that is currently in progress.</span><br />
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></span>
<span style="background-color: white; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 17px; orphans: 2; text-align: -webkit-auto; widows: 2;">I have dabbled with various solutions to this problem over the last year or so. Most of the other solutions were tied to pathogen or were broader, more generic endeavours (stretching beyond the realm of Vim). All of those solutions, though, utilised an automated testing framework to very rapidly locate the faulty component - in a matter of seconds. I had the idea for this incarnation of Bisectly today and rushed out the simpler manual code while it was fresh in my mind. However, I do intend to revisit this plugin to add support for an automated test framework.</span><br />
<br />bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com2tag:blogger.com,1999:blog-1100667502261579680.post-38455958315939337412013-03-16T20:46:00.001+08:002013-03-17T12:21:14.650+08:00The Path of a Master VimLer<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="preamble"></a>
<br />
<blockquote>
<pre style="font-family: inherit;">An apprentice approached a Master and said,
“Show me your best Vim.”
to which the Master responded,
“Everything in my Vim is best.
You cannot find here any piece of Vim that is not the best.”
At these words, the apprentice became enlightened.</pre>
</blockquote>
<br />
What might the path to VimL mastery look like?<br />
Here's what Raimondi & I think at the moment:<br />
<b><br /></b>
<b>Trainee → Novice → Worker → Professional → Expert</b><br />
<ol type="1">
<li>
<strong>Trainee</strong>
<br />
<ul>
<li>
Read the following parts of <code>:help cmdline.txt</code>
<br />
<ul>
<li>
3. Ex command-lines <code>:help cmdline-lines</code>
<br />
</li>
<li>
4. Ex command-line ranges <code>:help cmdline-ranges</code>
<br />
</li>
<li>
6. Ex special characters <code>:help cmdline-special</code>
<br />
</li>
</ul>
</li>
<li>
Read the following parts of <code>:help options.txt</code>
<br />
<ul>
<li>
1. Setting options <code>:help set-option</code>
<br />
</li>
<li>
The following specific options:
<br />
<ul>
<li>
<code>:help 'debug'</code>
<br />
</li>
<li>
<code>:help 'eventignore'</code>
<br />
</li>
<li>
<code>:help 'ignorecase'</code>
<br />
</li>
<li>
<code>:help 'magic'</code>
<br />
</li>
<li>
<code>:help 'maxfuncdepth'</code>
<br />
</li>
<li>
<code>:help 'runtimepath'</code>
<br />
</li>
<li>
<code>:help 'verbose'</code>
<br />
</li>
</ul>
</li>
</ul>
</li>
<li>
Read all of <code>:help pattern.txt</code>
<br />
</li>
<li>
Read the following parts of <code>:help eval.txt</code>
<br />
<ul>
<li>
1. Variables <code>:help variables</code>
<br />
</li>
<li>
2. Expression syntax (skim) <code>:help expression-syntax</code>
<br />
</li>
<li>
3. Internal variable <code>:help internal-variables</code>
<br />
</li>
<li>
5. Defining functions <code>:help user-functions</code>
<br />
</li>
<li>
7. Commands <code>:help expression-commands</code>
<br />
</li>
<li>
9. Examples <code>:help eval-examples</code>
<br />
</li>
</ul>
</li>
<li>
Read sections 41.1 - 41.8 in <code>:help usr_41.txt</code>
<br />
</li>
<li>
Read <code>:help function-list</code> (Vim’s built-in VimL library)
<br />
</li>
<li>
Read <a href="http://www.ibm.com/developerworks/linux/library/l-vim-script-1/index.html">http://www.ibm.com/developerworks/linux/library/l-vim-script-1/index.html</a>
<br />
</li>
<li>
Read <a href="http://learnvimscriptthehardway.stevelosh.com/">http://learnvimscriptthehardway.stevelosh.com/</a>
<br />
</li>
<li>
Pass the Trainee assessments
<br />
</li>
</ul>
</li>
<li>
<strong>Novice</strong>
<br />
<ul>
<li>
Contribute bug fixes and small enhancements to existing plugins.
<br />
</li>
<li>
Read <code>:help map.txt</code>
<br />
<ul>
<li>
Read <code>:help 'timeout'</code> option
<br />
</li>
<li>
Read <code>:help 'maxmapdepth'</code> option
<br />
</li>
</ul>
</li>
<li>
Read <code>:help usr_40.txt</code>
<br />
</li>
<li>
Read <code>:help autocmd.txt</code>
<br />
</li>
<li>
Read <code>:help filetype.txt</code>
<br />
</li>
<li>
Read <code>:help various.txt</code>
<br />
<ul>
<li>
In regard to <code>:normal</code>, read <code>:help motion.txt</code>
<br />
</li>
</ul>
</li>
<li>
Pass the Novice assessments
<br />
</li>
</ul>
</li>
<li>
<strong>Worker</strong>
<br />
<ul>
<li>
Read <code>:help eval.txt</code>
<br />
</li>
<li>
Read <code>:help usr_41.txt</code>
<br />
</li>
<li>
Create three or more plugins under the supervision of a
Professional or Expert
<br />
</li>
<li>
Assist Novices
<br />
</li>
</ul>
</li>
<li>
<strong>Professional</strong>
<br />
<ul>
<li>
Actively support five or more peer-reviewed, fully usr_41 compliant plugins
<br />
</li>
<li>
Thoroughly document all supported plugins
<br />
</li>
<li>
Supervise Workers
<br />
</li>
<li>
Assist in the development of reference & resource materials
<br />
</li>
<li>
Participate in discussions about best practice for VimL development
<br />
</li>
</ul>
</li>
<li>
<strong>Expert</strong>
<br />
<ul>
<li>
Create new tools and libraries for VimL development
<br />
</li>
<li>
Create new/interesting/engaging/fun reference material or tutorials
for an aspect of Vim/VimL
<br />
</li>
<li>
Mentor, guide and train other VimLers
<br />
</li>
<li>
Maintain a regular presence on Stack Overflow, the vim-dev mailing lists,
#vim or #viml as an authority and guide on advanced Vim and VimL topics
<br />
</li>
</ul>
</li>
</ol>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_a_plan_for_assessing_viml_skills"></a>A Plan for Assessing VimL Skills</h2>
<b>A central registry of available assessments:</b><br />
A master github repo called
<a href="https://github.com/dahu/VimLAssessments.git">https://github.com/dahu/VimLAssessments.git</a> that contains a list of
<code>VimLAss_<level_name>_<assessment_number></code> github repos in the various
skill levels that act as assessments.<br />
E.g.:<br />
<ol type="1">
<li>
Trainee:
<br />
<ul>
<li>
<a href="https://github.com/dahu/VimLAss_Trainee_001.git">https://github.com/dahu/VimLAss_Trainee_001.git</a> — Establish a
working VimL Dev environment
<br />
</li>
</ul>
</li>
</ol>
…<br />
<ol type="1">
<li>
Novice:
<br />
<ul>
<li>
VimLAss_Novice_010 — usr_41 compliance: use <Plug> maps
<br />
</li>
</ul>
</li>
</ol>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_creating_new_vimlass_assessment_repositories"></a>Creating New VimLAss Assessment Repositories</h2>
To create a new VimLAss assessment piece, just copy the
VimLAss_Skeleton repository which has the following layout:<br />
<ul>
<li>
<code>README.md</code> — an overview of the assessment and a detailed set of
tasks to be completed
<br />
</li>
<li>
<code>test/<task>.vim</code> — one or more test files per task as listed in
the <code>README.md</code>
<br />
</li>
<li>
plugin directories with files as necessary. e.g.:
<br />
<ul>
<li>
<code>autoload/</code>
<br />
</li>
<li>
<code>doc/</code>
<br />
</li>
<li>
<code>colors/</code>
<br />
</li>
<li>
<code>compiler/</code>
<br />
</li>
<li>
<code>ftdetect/</code>
<br />
</li>
<li>
<code>ftplugin/</code>
<br />
</li>
<li>
<code>indent/</code>
<br />
</li>
<li>
<code>plugin/</code>
<br />
</li>
<li>
<code>syntax/</code>
<br />
</li>
</ul>
</li>
</ul>
All VimLAss repositories are to use the
<a href="https://github.com/vim-scripts/runVimTests.git">https://github.com/vim-scripts/runVimTests.git</a> unit testing
framework. The repositories should contain tests for expected
behaviour that initially fail. Corresponding tasks in the
<code>READEME.md</code> file detail the necessary fixes and enhancements that
the vimmler is supposed to implement to get the tests to pass.
Successful completion of the assessment begins with having all tests
pass. The vimmler should then apply to a Professional/Expert vimmler
to have his work reviewed, gain feedback and get his assessment signed
off. Actual signoff could involve digital signatures, if that path was
ever deemed necessary, which is unlikely.<br />
<br />
Even though I have provided some links to various pieces mentioned
above, all of this is still very much in thought space at the moment.<br />
<br />
I am sure we haven’t covered all bases yet. Do you have anything to
contribute?</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-85712006247285010062013-02-09T19:08:00.003+08:002013-02-09T19:08:40.101+08:00SinTax Overdue<h2>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Syntax highlighting in Vim sucks.</span></h2>
I know. I haven't done as much of it as you have, but I've heard your cries from my cubicle, your desperate pleas for compassion whispered over and again at your desk to an uncaring Vim, your brave face masking knots of terror while chatting at the water cooler, and your wails of despair in the toilet stall when you thought everyone else had gone. It's been hard watching you go through this and for long now I've wished there was something I could do to ease your burden, to still your trembling hand, wipe the tears from your keyboard and tell you that "It's going to be okay." Of course, I couldn't do that. Nobody could. I'd be lying and you know it. My words would come across as naive, empty platitudes at best or, at worst, taken for cruel taunts to mock your effort, halt your progress and rob you of your due standing among the Nerds of Vim.<br />
<br />
That was how we all lived. That is... before THEY came!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8hX3pnmCkxVRu0gSEg8L6i8oFDHYTfWuG9AL0XbBcJNSBNG_nJF0h1aklQ9ARrXNjdrSFQA6d-B6Al9AIYP5mZp9XiBPVz_jxickYRm6D65NpAgNvzBW1k3BBvP12rP3S5xj4Xu73SvE/s1600/Pulp-O-Mizer_Cover_Image(1).jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8hX3pnmCkxVRu0gSEg8L6i8oFDHYTfWuG9AL0XbBcJNSBNG_nJF0h1aklQ9ARrXNjdrSFQA6d-B6Al9AIYP5mZp9XiBPVz_jxickYRm6D65NpAgNvzBW1k3BBvP12rP3S5xj4Xu73SvE/s1600/Pulp-O-Mizer_Cover_Image(1).jpg" /></a></div>
<br />
<br />
<a href="https://github.com/dahu/SinTax" target="_blank">SinTax</a> is a Vim plugin that provides a DSL for crafting syntax highlighting files.<br />
<br />
It takes this:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">" Vim syntax plugin for filetype name.</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Maintainer:<span class="Apple-tab-span" style="white-space: pre;"> </span>Barry Arthur <barry.arthur@gmail.com></span><br />
<span style="font-family: Courier New, Courier, monospace;">" <span class="Apple-tab-span" style="white-space: pre;"> </span>Israel Chauca F. <israelchauca@gmail.com></span><br />
<span style="font-family: Courier New, Courier, monospace;">" Version:<span class="Apple-tab-span" style="white-space: pre;"> </span>0.1</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Description:<span class="Apple-tab-span" style="white-space: pre;"> </span>Long description.</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Last Change:<span class="Apple-tab-span" style="white-space: pre;"> </span>2013-02-01</span><br />
<span style="font-family: Courier New, Courier, monospace;">" License:<span class="Apple-tab-span" style="white-space: pre;"> </span>Vim License (see :help license)</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Location:<span class="Apple-tab-span" style="white-space: pre;"> </span>syntax/vrs.vim</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Website:<span class="Apple-tab-span" style="white-space: pre;"> </span>https://github.com/Raimondi/vrs</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">name vrs</span><br />
<span style="font-family: Courier New, Courier, monospace;">case ignore</span><br />
<span style="font-family: Courier New, Courier, monospace;">spell default</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">keyword vrsTodo .Todo : TODO FIXME XXX</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">partial token \S\+\s\+</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">partial separator</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%(</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \\} # an_escaped_\}</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \| # or</span><br />
<span style="font-family: Courier New, Courier, monospace;"> [^}] # anything_but_a_}</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsNameErr .Error contained : ^\%{token}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsName .Identifier contained : ^\w\+\s\+</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsFlavorErr .Error contained</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%(</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ^\%{token} # if_the_line_starts_with_a_token</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \)\@<= # before</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%{token} # a_token</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsFlavor .Type contained</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%(</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ^\%{token} # if_the_line_starts_with_a_token</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \)\@<= # before</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%{vrsName} # a_vrsName</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsCompItem .Normal contained</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \w\+ # a_word</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \| # or</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \d\+ # a_number</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \| # or</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ,\@<= # a_separator_if_proceeded_by_a_comma</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%{separator}\+</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">" match a composition atom: \%{pattern-name,count,separator}</span><br />
<span style="font-family: Courier New, Courier, monospace;">match vrsCompose .PreProc contained contains=vrsCompItem</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \\%{ # a_literal_\{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \S\+ # a_word_(pattern-name)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> , # a_comma</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \d\+ # a_number_(count)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> , # a_comma</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%{separator}* # an_optional_separator</span><br />
<span style="font-family: Courier New, Courier, monospace;"> } # and_a_literal_}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsRegExp .String contains=vrsCompose contained</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%(</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ^\%{token,2} # if_the_line_starts_with_two_tokens</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \)\@<= # before</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .* # anything</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsCommand contains=vrsName,vrsFlavor,vrsNameErr,vrsFlavorErr,vrsRegExp,vrsComment</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ^\%{token,2}\S.* # a_line_with_three_'tokens'_minimum</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsContinued .String contains=vrsComment</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ^\s\+\S.* # a_line_with_leading_whitespace_and_a_'token'</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsComment .Comment containedin=ALL contains=vrsTodo</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%( # as_long_as</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \%(</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \\ \\ # (ignoring_any_number_of_double_backslashes_(\\))</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \)*</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \\ # a_backslash</span><br />
<span style="font-family: Courier New, Courier, monospace;"> \)\@<! # doesn't_precede</span><br />
<span style="font-family: Courier New, Courier, monospace;"> #.*$ # a_literal_#_followed_by_anything</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">match vrsError .Error</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ^ # any_line_starting_with</span><br />
<span style="font-family: Courier New, Courier, monospace;"> [^a-zA-Z0-9_#\ ] # anything_that's_not_alphanumeric,_underscore,_hash_or_a_space</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .* # and_anything_afterwards</span><br />
<br />
<br />
<br />
And generates this:<br />
<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">" Vim syntax plugin for filetype name.</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Maintainer:<span class="Apple-tab-span" style="white-space: pre;"> </span>Barry Arthur <barry.arthur@gmail.com></span><br />
<span style="font-family: Courier New, Courier, monospace;">" <span class="Apple-tab-span" style="white-space: pre;"> </span>Israel Chauca F. <israelchauca@gmail.com></span><br />
<span style="font-family: Courier New, Courier, monospace;">" Version:<span class="Apple-tab-span" style="white-space: pre;"> </span>0.1</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Description:<span class="Apple-tab-span" style="white-space: pre;"> </span>Long description.</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Last Change:<span class="Apple-tab-span" style="white-space: pre;"> </span>2013-02-01</span><br />
<span style="font-family: Courier New, Courier, monospace;">" License:<span class="Apple-tab-span" style="white-space: pre;"> </span>Vim License (see :help license)</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Location:<span class="Apple-tab-span" style="white-space: pre;"> </span>syntax/vrs.vim</span><br />
<span style="font-family: Courier New, Courier, monospace;">" Website:<span class="Apple-tab-span" style="white-space: pre;"> </span>https://github.com/Raimondi/vrs</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">" Quit when a (custom) syntax file was already loaded</span><br />
<span style="font-family: Courier New, Courier, monospace;">if exists("b:current_syntax")</span><br />
<span style="font-family: Courier New, Courier, monospace;"> finish</span><br />
<span style="font-family: Courier New, Courier, monospace;">endif</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">" Allow use of line continuation.</span><br />
<span style="font-family: Courier New, Courier, monospace;">let s:save_cpo = &cpo</span><br />
<span style="font-family: Courier New, Courier, monospace;">set cpo&vim</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">syntax case ignore</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax spell default</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax keyword vrsTodo TODO FIXME XXX </span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsNameErr /^\S\+\s\+/ contained </span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsName /^\w\+\s\+/ contained </span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsFlavorErr /\%(^\S\+\s\+\)\@<=\S\+\s\+/ contained</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsFlavor /\%(^\S\+\s\+\)\@<=^\w\+\s\+/ contained</span><br />
<span style="font-family: Courier New, Courier, monospace;">" match a composition atom: \%{pattern-name,count,separator}</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsCompItem /\w\+\|\d\+\|,\@<=\%(\\}\|[^}]\)\+/ contained</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsCompose /\\%{\S\+,\d\+,\%(\\}\|[^}]\)*}/ contained contains=vrsCompItem</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsRegExp /\%(^\S\+\s\+\S\+\s\+\)\@<=.*/ contains=vrsCompose contained</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsCommand /^\S\+\s\+\S\+\s\+\S.*/ contains=vrsName,vrsFlavor,vrsNameErr,vrsFlavorErr,vrsRegExp,vrsComment</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsContinued /^\s\+\S.*/ contains=vrsComment</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsComment /\%(\%(\\\\\)*\\\)\@<!#.*$/ containedin=ALL contains=vrsTodo</span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsError /^[^a-zA-Z0-9_#\ ].*/ </span><br />
<span style="font-family: Courier New, Courier, monospace;">syntax match vrsError /foo/ </span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsTodo Todo</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsNameErr Error</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsName Identifier</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsFlavorErr Error</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsFlavor Type</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsCompItem Normal</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsCompose PreProc</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsRegExp String</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsContinued String</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsComment Comment</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsError Error</span><br />
<span style="font-family: Courier New, Courier, monospace;">hi def link vrsError Error</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">let b:current_syntax = "vrs"</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">let &cpo = s:save_cpo</span><br />
<span style="font-family: Courier New, Courier, monospace;">unlet s:save_cpo</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">" vim: set sw=2 sts=2 et fdm=marker:</span><br />
<div>
<br /></div>
<br />
<br />
Now I feel more equipped to take your hand and say, "there, there."<br />
<br />
<b>Depends On:</b> Raimondi's <a href="https://github.com/Raimondi/VimRegStyle" target="_blank">VimRegStyle</a><br />
<b>Coming Soon! </b>SinTax is still in development but is ready for user testing. Feedback welcome.<br />
<br />bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-32268347059084278022013-02-02T22:43:00.001+08:002015-02-08T19:02:19.946+08:00Evimosaurus Rex<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
E-Rex<br />
<em><br /></em>
<em>because everyone deserves extended regular expressions</em><br />
<br />
A couple posts back I
<a href="http://of-vim-and-vigor.blogspot.com/2013/01/say-it-with-viml.html">compared
some idiomatic Ruby with equivalent Vim forms</a>. One of those was the
multiline, whitespace-insensitive extended regular expression mode
that the <code>/x</code> flag gives the PCRE wielder. I showed how this might
be achieved in Vim as:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>let PHONE_NUMBER_PATTERN = substitute(substitute('
\ ^
\ \%(
\ \(\d\) # prefix_digit
\ [\ \-\.]\? # optional_separator
\ \)\?
\ \%(
\ (\?\(\d\{3}\))\? # area_code
\ [\ \-\.] # separator
\ \)\?
\ \(\d\{3}\) # trunk
\ [\ \-\.] # separator
\ \(\d\{4}\) # line
\ \%(:\ \?x\? # optional_space_or_x
\ \(\d\+\) # extension
\ \)\?
\ $', '# \S\+', '', 'g'), '\\\@<! ', '', 'g')
echo string(PHONE_NUMBER_PATTERN)
let a_phone_number = '1-234-567-0987:1234'
echo matchlist(a_phone_number, PHONE_NUMBER_PATTERN)</code></pre>
</td></tr>
</tbody></table>
<br />
Which is all good and well, but wouldn’t it be nicer if we could just
do this instead:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>let PHONE_NUMBER_PATTERN = ERex.parse('
\ ^
\ \%(
\ \(\d\) # prefix_digit
\ [\ \-\.]\? # optional_separator
\ \)\?
\ \%(
\ (\?\(\d\{3}\))\? # area_code
\ [\ \-\.] # separator
\ \)\?
\ \(\d\{3}\) # trunk
\ [\ \-\.] # separator
\ \(\d\{4}\) # line
\ \%(:\ \?x\? # optional_space_or_x
\ \(\d\+\) # extension
\ \)\?
\ $')
echo string(PHONE_NUMBER_PATTERN)
let a_phone_number = '1-234-567-0987:1234'
echo matchlist(a_phone_number, PHONE_NUMBER_PATTERN)</code></pre>
</td></tr>
</tbody></table>
<br />
Where the <code>ERex</code> object was just magically waiting in the background
for all of our extended regex needs…?<br />
<br />
Install <a href="https://github.com/Raimondi/VimRegStyle">https://github.com/Raimondi/VimRegStyle</a> and you <em>can!</em><br />
<em><br /></em>
<br />
<blockquote>
“There is no charge for awesomeness.”<br />
<div align="right">
— Po</div>
</blockquote>
<br />
This just in! the awesomeness of Extended Regular Expressions has just been added to <a href="https://github.com/dahu/vimple" target="_blank">vimple</a>.<br />
<br /></div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-374686136257365752013-02-02T16:34:00.000+08:002013-02-02T16:34:01.193+08:00RFC on VimRegStyle<div style="font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<hr style="color: #484848;" />
<h2 style="color: #484848;">
<a href="" name="_vimregstyle"></a>VimRegStyle</h2>
<div style="color: #484848;">
<em>more than just a pattern library for sexy regex</em></div>
<div style="color: #484848;">
<em><br /></em></div>
<div style="color: #484848;">
This is a request for feedback on a new plugin:
<a href="https://github.com/Raimondi/VimRegStyle">https://github.com/Raimondi/VimRegStyle</a></div>
<div style="color: #484848;">
<em><br /></em></div>
<div style="color: #484848;">
<em>VimRegStyle</em> is designed to be a repository of PCRE <code>←→</code> Vim
regex equivalences and general pattern library for Vimmers.</div>
<div style="color: #484848;">
<br /></div>
<div style="color: #484848;">
Our goal is to have somewhere for the collection of common regex
patterns expressed in the Vim regex flavour. We frequently get regex
help requests on #vim that are answered with “look that common pattern up
on a regex lib site” only to have them come back and say “it didn’t
work” because they plugged the PCRE into Vim and got spanked for it.</div>
<div style="color: #484848;">
<br /></div>
<div style="color: #484848;">
No more! Now we have a library of our own!</div>
<div style="color: #484848;">
<br /></div>
<div style="color: #484848;">
So… what do I want from you? Feedback on:</div>
<ol style="color: #484848;" type="1">
<li>
Design issues (concerns & improvements)(*)
<br />
</li>
<li>
Ideas for tools, commands, maps and scripts surrounding such a
pattern library.
<br />
</li>
</ol>
<div style="color: #484848;">
(*) This might be the place to mention that we’ve taken several rather
bold steps in the implementation of the pattern repository files:</div>
<ol type="1">
<li style="color: #484848;">
the <code>patterns/</code> directory contains <code>*.vrs</code> files with the
following format:
<br />
<div>
<table cellpadding="4" cellspacing="0" frame="border" rules="all" style="width: 20%px;">
<thead>
<tr>
<th align="left" valign="top" width="33%">name </th>
<th align="left" valign="top" width="33%">flavour </th>
<th align="left" valign="top" width="33%">pattern</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
Where:<br />
<ul>
<li>
<code>name</code> contains no whitespace
<br />
</li>
<li>
<code>flavour</code> can be <code>vim</code> or <code>pcre</code>
<br />
</li>
<li>
<code>pattern</code> is not delimited — use a bare regex
<br />
</li>
</ul>
</li>
<li>
<div style="color: #484848;">
the <code>patterns</code> are further enhanced in the following two ways;
they:
</div>
<ul>
<li style="color: #484848;">
accept PCRE style multiline, whitespace insensitive syntax. All
multiline patterns must commence on the line below the named entry
and must be indented with whitespace.
<br />
</li>
<li>
<div style="color: #484848;">
accept a new regex atom: <code>\%{name,count,separator}</code> providing
pattern composition by inline-expanding the named pattern at the
current point in the regex (optionally <code>count</code> times, each one
separated by <code>separator</code>.)</div>
<div style="color: #484848;">
<strong><br /></strong></div>
<div style="color: #484848;">
<strong>As an example:</strong>, assuming the VRS
library had a pattern called <em>_ip4_segment</em> that represented a
single 0-255 chunk, an <em>ip4</em> regex could then be written using this
composition atom as: <code>\<\%{_ip4_segment,4,.}></code>
</div>
<blockquote>
<span style="color: #666666;">As a side note, the Extended Regex features mentioned here will be
further elaborated on in a separate article. These features can be
freely used in other projects, pulling from arbitrary lookup sources,
including the runtime vars in Vim itself. But more on that later.</span><br />
<div align="right" style="color: #484848;">
</div>
</blockquote>
</li>
</ul>
</li>
</ol>
<div style="color: #484848;">
<strong>When we’re finished with this RFC process we will be looking for
pattern contributions. Thanks to all who contribute their time and
energy into this project! :-)</strong></div>
</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-61737639413663994502013-01-28T09:03:00.000+08:002013-01-28T09:03:53.730+08:00Say it with VimL<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
I like Ruby. She’s a beautiful language. So expressive and elegant
and yummy. VimL is Vim’s scripting language. While she may not win the
sort of aesthetic awards Ruby deserves, she certainly is expressive
and elegant in her own way.<br />
Gregory Brown recently showed
<a href="https://practicingruby.com/articles/shared/zmkztdzucsgv?utm_source=rubyweekly&utm_medium=email">a
handful of idioms for elegantly working with text and files in Ruby</a>.
I thought I’d show their VimL analogues here.<br />
<hr />
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_idioms_for_text_processing"></a>idioms for text processing</h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_1_multiline_matches"></a>1. Multiline Matches</h3>
Vim has its own regular expression flavour. It’s a bit shocking to
<a href="http://www.regular-expressions.info/perl.html">PCRE</a> lovers at
first — it uses an older, more arcane syntax that can reduce the most
ardent Perler to pitiful puling instead. Sulk as they may though,
Vim’s regex flavour got here before PCRE and isn’t going anywhere
fast. The good news is that Vim’s regex flavour is quite strong — equally up to the machinations of PCRE in almost all aspects (and
certainly so in all that count within the context of editing text). I
digress — this is not the place to wage that war.<br />
Gregory showed the PCRE idiom of using the <code>/s</code> flag<*> to enable
<code>DOTALL</code>
mode which allows the <code>.</code> atom to match newlines (as well as
its default match-any-character behaviour.) Vim uses <code>\_.</code> to achieve
this result:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo matchlist("foo\nbar\nbaz\nquux", 'foo\n\(\_.*\)quux')[1]</code></pre>
</td></tr>
</tbody></table>
<h3>
<i style="font-size: medium; font-weight: normal;"><*> The astute reader will have noticed my sleight play there. Ruby’s flavour of PCRE uses the <code>/m</code> flag to mean what the rest of the PCRE speaking world knows <code>/s</code> to do. I must admit, I was scratching my head when I first read Gregory’s article thinking he’d given the wrong example to suit the <code>/m</code> flag. Thanks goes to <em>kotigid</em> on #regex for pointing me at the <a href="http://www.regular-expressions.info/ruby.html">Ruby regex</a> page.</i></h3>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_2_code_matchlist_code"></a>2. <code>matchlist()</code></h3>
While Vim doesn’t have the global match variables (<code>$1</code> et al) that
Gregory is recommending avoidance of, it does have his preferred
method baked right in. The <code>matchlist()</code> function returns a list
containing the whole match as the zeroth element and any submatches
from index 1 onwards.<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo matchlist("---\na\nb\nc\n---\n", '^\(---\s*\n\_.\{-}\n\?\)\(---\s*\n\?\)')</code></pre>
</td></tr>
</tbody></table>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_3_extended_regular_expression_syntax"></a>3. Extended Regular Expression Syntax</h3>
The <code>/x</code> flag in PCRE allows complex regular expressions to be
spread out over multiple lines with embedded comments for easier
readability and clarity. We can approximate that in VimL:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>let PHONE_NUMBER_PATTERN = substitute(substitute('
\ ^
\ \%(
\ \(\d\) # prefix_digit
\ [\ \-\.]\? # optional_separator
\ \)\?
\ \%(
\ (\?\(\d\{3}\))\? # area_code
\ [\ \-\.] # separator
\ \)\?
\ \(\d\{3}\) # trunk
\ [\ \-\.] # separator
\ \(\d\{4}\) # line
\ \%(:\ \?x\? # optional_space_or_x
\ \(\d\+\) # extension
\ \)\?
\ $', '# \S\+', '', 'g'), '\\\@<! ', '', 'g')
echo string(PHONE_NUMBER_PATTERN)
let a_phone_number = '1-234-567-0987:1234'
echo matchlist(a_phone_number, PHONE_NUMBER_PATTERN)</code></pre>
</td></tr>
</tbody></table>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_4_using_code_join_code"></a>4. Using <code>join()</code></h3>
VimL doesn’t have string interpolation like Ruby.<br />
Given a dictionary (a.k.a associative array, or hash) such as:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>let filedata = {'year' : 2013, 'month' : 1, 'day' : 28}</code></pre>
</td></tr>
</tbody></table>
<br />
To include variable values in strings we have to use catenation:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo filedata["year"] . '/' . filedata["month"]. '/' . filedata["day"]</code></pre>
</td></tr>
</tbody></table>
<br />
Of course, the <code>join()</code> trick Gregory showed also works in VimL:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo join([filedata["year"], filedata["month"], filedata["day"] ], "/")</code></pre>
</td></tr>
</tbody></table>
<br />
Another approach in both languages would be to use a printf string:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo printf("%d/%d/%d",filedata["year"], filedata["month"], filedata["day"])</code></pre>
</td></tr>
</tbody></table>
<br />
On the down side, this only works when you know how many fields you
need to print, and you’re forced to insert the <code>/</code> characters
manually. On the up side, you can easily format the values to show,
for example, leading zeros in the <code>day</code> and <code>month</code> fields:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo printf("%d/%02d/%02d",filedata["year"], filedata["month"], filedata["day"])</code></pre>
</td></tr>
</tbody></table>
<hr />
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_idioms_for_working_with_files_and_folders"></a>idioms for working with files and folders</h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_1_filenames"></a>1. Filenames</h3>
Ruby has <code>File.dirname</code>, <code>File.basename</code>, and <code>File.extname</code> for
munging filenames. Vim uses the <code>expand()</code> function to do this.
Ruby’s <code><em>FILE</em></code> (available in Vim as <code>%</code> and VimL as
<code>expand('%')</code>) is expressed in Vim as:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo expand('%:p')</code></pre>
</td></tr>
</tbody></table>
<br />
The <code>:p</code> there is called a <em>Modifier</em> in the <code>:help expand()</code> docs.
The <code>:p</code> modifier means <em>full path</em>.<br />
<br />
To get the dirname only (called the <code>head</code> in vimspeak):<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo expand('%:p:h')</code></pre>
</td></tr>
</tbody></table>
<br />
To get the basename (called <code>tail</code>):<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo expand('%:p:t')</code></pre>
</td></tr>
</tbody></table>
<br />
Which will return the <em>basename.extension</em> form of the filename. To
get just the <em>basename</em> with no extension, use the <code>:r</code> (<code>root</code>)
modifier to strip off one level of extension:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo expand('%:p:t:r')</code></pre>
</td></tr>
</tbody></table>
<br />
To get the extension (mnemonically equivalent in vimspeak):<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre><code>echo expand('%:p:e')</code></pre>
</td></tr>
</tbody></table>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_2_pathname_objects"></a>2. Pathname Objects</h3>
The closest analogue in Vim to <em>Pathname</em> objects is the
<code>fnamemodify()</code> function which provides the same filename
manipulations as the <code>expand()</code> function above. You can find more
functions like this in <code>:help file-functions</code>.<br />
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_3_reading_and_writing_files"></a>3. Reading and Writing Files</h3>
Vim has two builtin functions for reading and writing files:
<code>readfile(fname)</code> (which returns a list of lines) and
<code>writefile(list, fname)</code>. Semantically simple interfaces.<br />
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_4_code_dir_mktmpdir_code"></a>4. <code>Dir.mktmpdir</code></h3>
Vim doesn’t have a <code>mktmpdir()</code> function but more importantly, VimL
doesn’t have the beautiful <em>code blocks</em> of Ruby. As such, we have
to use a more procedural idiom of manually creating a temporary
directory (with <code>:help tempname()</code>), doing what we want in it and
finally remembering to clean up after ourselves. Ruby wins here.<br />
<hr />
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="_reflections"></a>Reflections</h2>
Gregory’s intent behind his article was to lead the misguided Rubiest
away from using needlessly laborious low-level functions for achieving
what can be more beautifully expressed using idiomatic Ruby and
elegant thinking. My intent with this article is twofold: firstly to
show that not only can VimL easily do the sort of text and file
manipulations Gregory showed, but also in most cases just as elegantly
(read: semantically simple). Sure, VimL’s <em>actual</em> syntax in places
might make your skin crawl, but once you overcome that and appreciate
the deeper aesthetics, VimL doesn’t deserve the derision it receives
as being a gnarled and impotent language.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-60495943485134830032012-12-20T16:59:00.001+08:002012-12-20T20:23:10.684+08:00Learn Vimscript the Hard Way, Commentary II<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="preamble"></a>
As I wrote in my first commentary on Steve Losh’s
<a href="http://learnvimscriptthehardway.stevelosh.com/">Learn Vimscript the
Hard Way</a>, I think it is a worthwhile book for people to read to get
more familiar with the mechanics of customising their Vim environment.<br />
<br />
What about those who want to use it to <i>actually</i> learn Vimscript?<br />
<br />
It does an acceptable job of that too.<br />
<br />
The chapters on Vimscript itself (19-27 and 35-40) cover the syntax
and semantics of the language with examples and exercises spread
throughout to give the learner necessary hands on experience.<br />
<br />
I want to stress here that I feel Steve didn’t intend the <i>what</i> of
those examples to be used literally in anyone’s vimrc files or
personal plugins (in fact, I believe that to be true of the whole book
at large) but rather the <i>how</i> of techniques shown. Don’t create your
own little maps in your <tt>~/.vimrc</tt> file for commenting lines in
various filetypes and don’t write your own toy snippets system — very
good plugins exist for these purposes already. <i>Do</i> learn that you
<i>can</i> do these sorts of things so that when the time comes for you to
really write something new, you will know how to.<br />
<br />
Steve also provides two larger exercises starting respectively at
chapters 32 and 41. The first is a new operator to grep for the
motioned text, and the second is a full blown Plugin for a new
programming language. Both serve as good models for the sort of larger
works of the practising VimLer.<br />
<br />
I do recommend this book because it’s freely available to read online.
Another resource I would recommend for learning Vimscript is Damian
Conway’s five part developerWorks article series,
<a href="http://www.ibm.com/developerworks/linux/library/l-vim-script-1/index.html">Scripting
the Vim Editor</a> — that’s how I first got into VimL (VimL is short for
Vim Scripting Language and is another name for Vimscript). Vim’s
built-in <tt>:help usr_41</tt> is the user guide to writing Vim scripts
and <tt>:help eval.txt</tt> is the reference manual on VimL’s expression
evaluation.<br />
<br />
Do you have a favourite resource for learning VimL?<br />
<br />
[update] <br />
Oops... I forgot to add my remarks on some of the technical aspects of Steve's work:<br />
<br />
<ul>
<li>As Steve says, always use <span style="font-family: "Courier New",Courier,monospace;">:help nore</span> maps until you know you need otherwise.</li>
<li>In the same vein, always use <span style="font-family: "Courier New",Courier,monospace;">:normal!</span> (instead of the oft shown <span style="font-family: "Courier New",Courier,monospace;">:normal</span>) to avoid user-defined keymaps on the right hand side.</li>
<li>The <span style="font-family: "Courier New",Courier,monospace;">:echom</span> command (and friends) expects the evaluations of its expressions to be of type string. Use <span style="font-family: "Courier New",Courier,monospace;">:help string(</span> to coerce lists and dictionaries to strings for use in these commands. E.g. <span style="font-family: "Courier New",Courier,monospace;"> :echom string(getline(1, '$'))</span></li>
<li>Vim's help system is context aware based on the format of the help tag. See <span style="font-family: "Courier New",Courier,monospace;">:help help-context</span> for the list of formats.</li>
</ul>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com0tag:blogger.com,1999:blog-1100667502261579680.post-41983095725458506942012-12-20T14:03:00.001+08:002013-02-03T14:05:16.181+08:00Learn Vimscript the Hard Way, Commentary I<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="preamble"></a>
Steve Losh has written a book called <i><a href="http://learnvimscriptthehardway.stevelosh.com/">Learn Vimscript the Hard Way</a></i>.<br />
<br />
It’s badly titled, imho. His definition of the book explains why I say
that: <i>a book for users of the Vim editor who want to learn how to
customize Vim.</i> With that description in mind, I think the book
achieves its goal — a goal that <i>all</i> vimmers would aspire to master.
However with the title of the book, I fear even many proficient
vimmers would assume that the material is out of their reach or too
dense to absorb right now with their busy schedules, relegating it to
a later reading pile, at best.<br />
<br />
For all you up and coming Vimmers looking to read something to take
you beyond all of the beginner tutorials out there, read chapters:
0-18, 28-32, 43-48, 50 & 56.<br />
<br />
For those of you who picked the book up specifically <i>because</i> of its
title, that <a href="http://of-vim-and-vigor.blogspot.com/2012/12/learn-vimscript-hard-way-commentary-ii.html" target="_blank">review is coming soon</a>. :-)bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com2tag:blogger.com,1999:blog-1100667502261579680.post-12958601091685867772012-12-16T21:48:00.004+08:002012-12-17T05:56:35.634+08:00call() for a Good Time<div style="color: #484848; font-family: 'Trebuchet MS', Helvetica, sans-serif;">
<a href="http://www.blogger.com/blogger.g?blogID=1100667502261579680" name="preamble"></a>
Simple functions in Vim are declared like this:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! A(a, b, c)
echo a:a a:b a:c
endfunction
call A(1, 2, 3)</pre>
</td></tr>
</tbody></table>
<br />
There’s probably nothing surprising there except for the <tt>a:a</tt>
syntax, which is how Vim insists on accessing the function’s arguments
(mnemonic: a: for argument).<br />
Just as simple is calling function <tt>A()</tt> from another function, <tt>B()</tt>,
passing its arguments directly along to <tt>A()</tt>:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! B(a, b, c)
return A(a:a, a:b, a:c)
endfunction
call B(1, 2, 3)</pre>
</td></tr>
</tbody></table>
<br />
Nothing surprising there at all. But we’ve just laid the groundwork
for the main attraction tonight. In VimL, you can call a function
using the library function <tt>call(func, arglist)</tt> where <tt>arglist</tt>
is a list. If you’re calling a function that takes multiple arguments,
collect them in an actual list like this:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! C(a, b, c)
return call("A", [a:a, a:b, a:c])
endfunction
call C(1, 2, 3)</pre>
</td></tr>
</tbody></table>
<br />
If you already have the elements in a list, no need to wrap it in an
explicit list:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! D(a)
return call("A", a:a)
endfunction
call D([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
Let’s step it up a notch. What if you want to be able to accept the
args as either separate arguments or as a list? Vim has your back with
variadic functions cloaked in a syntax similar to C’s: <tt>…</tt><br />
<br />
<tt><b><span style="font-size: small;">Variadics in the key of V:</span></b> </tt><br />
<table cellpadding="4" frame="void" style="width: 100%px;">
<tbody>
<tr><td style="border-left: 2px solid silver;"><ul>
<li>
<tt>a:0</tt> is a count of the variadic arguments
<br />
</li>
<li>
<tt>a:000</tt> is all of the variadic arguments in a single list
<br />
</li>
<li>
<tt>a:1</tt> to <tt>a:20</tt> are positional accessors to the variadic
arguments
<br />
</li>
</ul>
</td></tr>
</tbody></table>
<br />
<br />
So now it doesn’t matter how we receive the arguments — standalone or
in a list — we can keep Vim happy and call <tt>A()</tt> appropriately.<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! E(...)
if a:0 == 1
return call("A", a:1)
else
return call("A", a:000)
endif
endfunction
call E(1, 2, 3)
call E([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
Ok. That’s not too bad; it’s perhaps a little awkward. We’re calling
<tt>A()</tt> directly here, but it shouldn’t be a surprise to see that we
can call <tt>C()</tt> in the same way too:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! F(...)
if a:0 == 1
return call("C", a:1)
else
return call("C", a:000)
endif
endfunction
call F(1, 2, 3)
call F([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
Pretty straightforward. What about calling <tt>D()</tt> instead which
expects a single list argument? Hmm… if Vim wants a list, give him
a list:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! G(...)
if a:0 == 1
return call("D", [a:1])
else
return call("D", [a:000])
endif
endfunction
call G(1, 2, 3)
call G([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
It’s worth stopping briefly here to consider what <tt>call()</tt> is doing
to that arglist: It’s <i>splatting</i> it (extracting the arguments and
passing them as separate members to the called function). Nice.
Wouldn’t it be nice if we could splat lists ourselves? Well, be
envious of Ruby coders no more because we <b>can</b> splat lists in VimL!<br />
<br />
Splat!<br />
<table cellpadding="4" frame="void" style="width: 100%px;">
<tbody>
<tr><td style="border-left: 2px solid silver;">To splat a list into separate variables (a, b and c here):<br />
<pre>let [a, b, c] = somelist</pre>
Read <tt>:help :let-unpack</tt> for the juicy extras.</td></tr>
</tbody></table>
<br />
I like the splatting approach because it gives us variable names to
play with inside our function:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! H(...)
if a:0 == 1
let [a, b, c] = a:1
else
let [a, b, c] = a:000
endif
return D([a, b, c])
endfunction
call H(1, 2, 3)
call H([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
Of course, it works just as well for calling functions with explicit
multiple arguments, like <tt>C()</tt>:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! I(...)
if a:0 == 1
let [a, b, c] = a:1
else
let [a, b, c] = a:000
endif
return C(a, b, c)
endfunction
call I(1, 2, 3)
call I([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
You’ll notice that the splat semantics are identical between <tt>H()</tt>
and <tt>I()</tt> and only the call of <tt>D()</tt> and <tt>C()</tt> change,
respectively. This is very neat, I think.<br />
So far we’ve been calling through to functions that call <tt>A()</tt>
directly. Happily, we can call through to one of these dynamic
functions (like <tt>E()</tt>, but any would work as well) and have it Just
Work too:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! J(...)
if a:0 == 1
let [a, b, c] = a:1
else
let [a, b, c] = a:000
endif
return E(a, b, c)
endfunction
call J(1, 2, 3)
call J([1, 2, 3])</pre>
</td></tr>
</tbody></table>
<br />
So, that’s it. Vim has variadic functions and splats. And splats are my
recommended pattern for handling deep call chains between variadic
functions.<br />
There’s one last, cute, little thing about splats: you can collect a
certain number of explicit arguments as you require, and then have any
remaining arguments dumped into a list for you. The <tt>rest</tt> variable
here will be a list containing <tt>[4, 5, 6]</tt> from the subsequent
calls:<br />
<br />
<table bgcolor="#e8e8e8" border="0" cellpadding="10" style="width: 100%px;"><tbody>
<tr><td><pre>function! K(...)
if a:0 == 1
let [a, b, c; rest] = a:1
else
let [a, b, c; rest] = a:000
endif
echo "rest: " . string(rest)
return E(a, b, c)
endfunction
call K([1, 2, 3, 4, 5, 6])
call K(1, 2, 3, 4, 5, 6)</pre>
</td></tr>
</tbody></table>
<br />
And I thought this was going to be a short post when I started. I
almost didn’t bother posting it because of that reason.</div>
bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com3tag:blogger.com,1999:blog-1100667502261579680.post-3202991014673097472012-12-01T11:42:00.000+08:002012-12-01T11:42:11.372+08:00Rapid Programming Language Prototypes with Ruby & Racc, CommentaryI just watched a tolerable ruby conference video by Tom Lee on <a href="http://confreaks.com/videos/1319-rubyconf2012-rapid-programming-language-prototypes-with-ruby-racc" target="_blank">Rapid Programming Language Prototypes with Ruby & Racc</a>.<br />
<br />
What he showed he showed fairly well. His decision to "introduce compiler theory" was, he admitted, last-minute and the hesitation in its delivery bore testimony to that. The demonstration of the compiler pipeline using his intended tools (ruby and racc) was done quite well with a natural progression through the dependent concepts along the way. By the end of the talk he has a functional compiler construction tool chain going from EBNF-ish grammar through to generated (and using gcc, compiled) C code.<br />
<br />
I was surprised that nobody in the audience asked the question I was burning to ask from half way through the live-coding session: Why not use <a href="http://treetop.rubyforge.org/" target="_blank">Treetop</a>? (or the more generic: why not use a peg parser generator or a parser generator that does more of the heavy lifting for you?)<br />
<br />
The whole point of Tom's presentation is: use ruby+racc because it saves you from all the headaches of setting up the equivalent tool chain in C/C++. And it does, he's right. But it feels to me that Treetop does even more of that hard work for you, allowing you to more quickly get to the fun part of actually building your new language. I'm angling for simplicity here.<br />
<br />
I could be wrong, though, so let me ask it here (as Confreaks seems to not allow comments): Why not treetop (or an equally 'simple' parser generator) for something like this? (and answers along the lines of EBNF > PEG are not really what I'm after, but if you have a concrete example of that I'd like to hear it too.)<br />
<br />
On a completely separate note: Tom, you need to add some <a href="http://bairuidahu.deviantart.com/art/Flying-vs-Cycling-261641977" target="_blank">flying</a> love to your Vim habits. :-)<br />
<br />bairuihttp://www.blogger.com/profile/15744674478376238952noreply@blogger.com1