Vim 7.2 Scripting

Exclusive offer: get 50% off this eBook here
Hacking Vim 7.2

Hacking Vim 7.2 — Save 50%

Ready-to-use hacks with solutions for common situations encountered by users of the Vim editor

$23.99    $12.00
by Kim Schulz | April 2010 | Linux Servers Open Source

This article by Kim Schulz, author of Hacking Vim 7.2, will contain recipes focusing on the following subjects:

  • Tips for when you develop Vim scripts
  • How to debug a Vim script
  • How to use other scripting languages when writing Vim scripts

Scripting tips

In this section, we will look at a few extra tips that can be handy when you create scripts for Vim. Some are simple code pieces you can add directly in your script, while others are good-to-know tips.

Gvim or Vim?

Some scripts have extra features when used in the GUI version of Vim (Gvim). This could be adding menus, toolbars, or other things that only work if you are using Gvim. So what do you do to check if the user runs the script in a console Vim or in Gvim? Vim has already prepared the information for you. You simply have to check if the feature gui_running is enabled. To do so, you use a function called has(), which returns 1 (true) if a given feature is supported / enabled and 0 (false), otherwise.

An example could be:

if has("gui_running")
"execute gui-only commands here.
endif

This is all you need to do to check if a user has used Gvim or not. Note that it is not enough to check if the feature "gui" exists, because this will return true if your Vim is just compiled with GUI support—even if it is not using it.

Look in :help 'feature-list' for a complete list of other features you can check with the has() function.

Which operating system?

If you have tried to work with multiple operating systems such as Microsoft Windows and Linux, you will surely know that there are many differences.

This can be everything from where programs are placed, to which programs you have available and how access to files is restricted.

Sometimes, this can also have an influence on how you construct your Vim script as you might have to call external programs, or use other functionality, specific for a certain operating system.

Vim lets you check which operation system you are on, such that you can stop executing your script or make decisions about how to configure your script. This is done with the following piece of code:

if has("win16") || has("win32") || has("win64")|| has("win95")
" do windows things here
elseif has("unix")
" do linux/unix things here
endif

This example only shows how to check for Windows (all flavors available) and Linux / Unix. As Vim is available on a wide variety of platforms, you can of course also check for these. All of the operating systems can be found in:


:help 'feature-list'

Which version of Vim?

Throughout the last decade or two, Vim has developed and been extended with a large list of functions. Sometimes, you want to use the newest functions in your script, as these are the best / easiest to use. But what about the users who have a version of Vim that is older than the one you use, and hence don't have access to the functions you use?

You have three options:

  1. Don't care and let it be the user's own problem (not a good option).
  2. Check if the user uses an old version of Vim, and then stop executing the script if this is the case.
  3. Check if the user has too old a version of Vim, and then use alternative code.

The first option is really not one I would recommend anyone to use, so please don't use it.

The second option is acceptable, if you can't work around the problem in the old version of Vim. However, if it is possible to make an alternative solution for the older version of Vim, then this will be the most preferable option.

So let's look at how you can check the version of Vim.

Before we look at how to check the version, we have to take a look at how the version number is built.

The number consists of three parts:

  • Major number (for example, 7 for Vim version 7)
  • Minor number (for example, 3 for Vim version 6.3)
  • Patch number (for example, 123 for Vim 7.0.123)

The first two numbers are the actual version number, but when minor features / patches are applied to a version of Vim, it is mostly only the patch number that is increased. It takes quite a bit of change to get the minor number to increase, and a major part of Vim should change in order to increase the major version number.

Therefore, when you want to check which version of Vim the user is using, you do it for two versions—major and minor versions and patch number. The code for this could look like:


if v:version >= 702 || v:version == 701 && has("patch123")
" code here is only done for version 7.1 with patch 123
" and version 7.2 and above
endif

The first part of the if condition checks if our version of Vim is version 7.2 (notice that the minor version number is padded with 0 if less than 10) or above. If this is not the case, then it checks to see if we have a version 7.1 with patch 123. If patch version 124 or above is included, then you also have patch 123 automatically.

Printing longer lines

Vim was originally created for old text terminals where the length of lines was limited to a certain number of characters. Today, this old limitation shows up once in a while.

One place where you meet this limitation of line length is when printing longer lines to the screen using the "echo" statement. Even though you use Vim in a window where there are more than the traditional 80 characters per line, Vim will still prompt you to press Enter after echoing lines longer than 80 characters. There is, however, a way to get around this, and make it possible to use the entire window width to echo on. Window width means the total number of columns in the Vim window minus a single character. So if your Vim window is wide enough to have 120 characters on each line, then the window width is 120-1 characters.

By adding the following function to your script, you will be able to echo screen-wide long lines in Vim:


" WideMsg() prints [long] message up to (&columns-1) length
function! WideMsg(msg)
let x=&ruler | let y=&showcmd
set noruler noshowcmd
redraw
echo a:msg
let &ruler=x | let &showcmd=y
endfunction

This function was originally proposed by the Vim script developer Yakov Lerner on the Vim online community site at http://www.vim.org.

Now whenever you need to echo a long line of text in your script, instead of using the echo statement you simply use the function Widemsg(). An example could be:

:call WideMsg("This should be a very long line of text")

The length of a single line message is still limited, but now it is limited to the width of the Vim window instead of the traditional 80-1 characters.

Debugging Vim scripts

Sometimes things in your scripts do not work exactly as you expect them to. In these cases, it is always good to know how to debug your script.

In this section, we will look at some of the methods you can use to find your error.

Well-structured code often has fewer bugs and is also easier to debug.

In Vim, there is a special mode to perform script debugging. Depending on what you want to debug, there are some different ways to start this mode. So let's look at some different cases.

If Vim just throws some errors (by printing them at the bottom of the Vim window), but you are not really sure where it is or why it happens, then you might want to try to start Vim directly in debugging mode. This is done on the command line by invoking Vim with the -Dargument.

vim -D somefile.txt

The debugging mode is started when Vim starts to read the first vimrc file it loads (in most cases the global vimrc file where Vim is installed). We will look at what to do when you get into debug mode in a moment.

Another case where you might want to get into debug mode is when you already know which function the error (most likely) is in, and hence, just want to debug that function. In that case you just open Vim as normal (load the script with the particular function if needed) and then use the following command:

:debug call Myfunction()

Here everything after the :debug is the functionality you want to debug. In this case, it is a simple call of the function Myfunction(), but it could just as well be any of the following:

:debug read somefile.txt
:debug nmap ,a :call Myfunction() <CR>
:debug help :debug

So let's look at what to do when we get into the debugging mode.

When reaching the first line that it should debug, Vim breaks the loading and shows something like:

Entering Debug mode. Type "cont" to continue.
cmd: call MyFunction()
>

Now you are in the Vim script debugger and have some choices for what to make Vim do.

If you are not familiar with debugging techniques, it might be a good idea to read up on this subject before starting to debug your scripts.

The following commands are available in the debugger (shortcuts are in parentheses):

  • cont (c): Continue running the scripts / commands as normal (no debugging) until the next breakpoint (more about this later).
  • quit (q): Quit the debugging process without executing the last lines.
  • interrupt (i): Stop the current process like quit, but go back to the debugger.
  • step (s): Execute the next line of code and come back to the debugger when it is finished. If a line calls a function or sources a file, then it will step into the function / file.
  • next (n): Execute the next command and come back to the debugger when it is finished. If used on a line with a function call, it does not go into the function but steps over it.
  • finish (f): Continue executing the script without stopping on breakpoints. Go into debug mode when done.
Hacking Vim 7.2 Ready-to-use hacks with solutions for common situations encountered by users of the Vim editor
Published: April 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

So now you simply execute the different commands to go through the lines of the script / function to see how it jumps through the if conditions, and so on. If you want to execute the same command multiple times, you simply press Enter without feeding a new command.

You can at any point execute another Ex command if needed (see :help 'excommand-index'), but note that you don't have direct access to the variables, among others, in the debugger, unless they are global.

Sometimes, the place you want to get to is many lines into the code, and you really don't want to step all the way through the code until you get to that place.

In that case, you can insert a breakpoint at the exact line where you want to start the real debugging, and then just execute a cont as the first command. A breakpoint is inserted by one of the following commands, depending on how you want it inserted:


breakadd func linenum functionname
breakadd file linenum filename
breakadd here

The first example sets a breakpoint on a particular function. The functionname can be a pattern such as Myfunction* if you, for instance, want to break on any function with a name that begins with Myfunction.

Sometimes, however, it is not in a function that the problem resides, but rather around a specific line in a file. If this is the case, then you should use the second command, where you give it a line number and a filename pattern as arguments to tell it where to break.

The final command is used if you have already stepped to the right place in the file but want to be able to break on it the next time you go through the code in the debugger. This command simply sets a breakpoint on the current line, in the current file, where you currently are in the debugger.

You can at any point of time get a list of breakpoints with the following command:

:breaklist

If a breakpoint is no longer needed, you have to delete it. As when adding breakpoints, there are a few different ways to delete them also.

The simplest way to do it is by simply finding the number of the breakpoint in the list of breakpoints, and then using the following command:


:breakdel number

Alternatively, you can delete the breakpoints the same way as you added them—except that you now use breakdel instead of breakadd:

:breakdel func linenum functionname
:breakdel file linenum file
breakdel here

If you want to remove all breakpoints, you can do it in one step by using this command:


:breakdel *

You can add a breakpoint directly on the command line when going into debug mode. Simply use the -c argument as follows:

vim -D -c 'breakadd file 15 */.vimrc' somefile.txt

Distributing Vim scripts

Now that your script is ready, it is time for you to distribute the script (if you have chosen to do so). The online Vim community has become the de facto place to publish scripts for others to find. Because of this, I urge you to do the same. But before you get to this, there are a couple of things you have to get ready.

First of all, you need to figure out whether your script needs to be packed into a compressed file such as a ZIP file, or if it should just be distributed as a single .vim file. The main reason for choosing the first option is that your script consists of multiple files (such as main script, file type plugin, syntax file, documentation, and so on).

How to create ZIP files (or related file types) is beyond what this article will look at, but here are a couple of pointers on how I make my ZIP files "install ready":

  • Create the ZIP file including the folders where the files are placed relative to your VIMHOME. For example, consider that you have:

    VIMHOME/plugin/myscript.vim

    VIMHOME/syntax/mylang.vim

    VIMHOME/doc/myscript.txt

    Then the ZIP file should contain the three folders: plugin, syntax, and doc with one file in each. This makes the installation easy, as you simply have to go into your VIMHOME and then unpack the ZIP file.

  • Always include a help file for your script. This file should be installed in VIMHOME/doc/ and contain descriptions of what the script does, which settings it has, and how to use it.

Even though you only have one script file, it can still be a good idea to put it in a ZIP file together with a help file. This makes it easier for you to remember to add documentation. We will look more at how to create Vim documentation in the next section.

Making Vimballs

Another, maybe even more interesting, alternative is to make a Vimball. We have previously looked at how to use Vimballs to install scripts, so it could now be interesting to look a bit at how to create one.

The command to create a Vimball is constructed as:


:[range]MkVimball filename.vba

This sure seems simple, right? And it really is. There is, however, a bit of preparation you need to do before calling this function.

The first thing you have to do is to open a new empty buffer in Vim with:

:enew

Now you add the paths to all the files (one on each line) relative to your VIMHOME. Considering the previous ZIP file example, it could look like:


plugin/myscript.vim
doc/myscript.txt
syntax/mylang.vim

When this is done you are actually ready to execute the command across the range of lines. Place the cursor on the first line in the buffer, go into normal mode, and use the keys Shift+v to select all the lines with paths on. Now all you have to do is execute the command:

:MkVimball myscript.vba

Vim will automatically add the range of the lines you have selected in front of the command. The filename myscript.vba can be any name, but if the file already exists, then a warning is given, but no file is written.

If you really want to overwrite an existing file, then just add an ! after the MkVimball command to tell Vim that you mean it. There is no more to it. You now have a Vimball file called myscript.vba, which can be installed as described earlier in this chapter.

Remember that you need to install the Vimball script in order to use the Vimball functions we have described at. The latest version of the Vimball script can always be found here: http://www.vim.org/scripts/script.php?script_id=1502.

Using external interpreters

Even though you can do nearly everything with Vim scripts, there are, however, some things that might be smarter or faster to do in other languages. The developers of Vim have recognized this need, and therefore implemented the possibility to interface with other scripting languages from within Vim. There are in particular three languages that you have access to:

  • Perl
  • Python
  • Ruby

In the following sections, will we take a peek at how to interface with these scripting languages and which variables you have access to.

The support for these language interfaces is not included in Vim by default, and you will have to either compile Vim yourself to get it, or find a precompiled version that supports them.

To check if your version supports one of the languages, you simply run Vim on the command line with -version argument:

vim –version

Then, you look through the list of features to see if it has one of the following in the list:


+perl
+python
+ruby

It needs to say + in front of the language name to show that it is included. If it instead says, for example, -perl, then Perl support is not included.

Alternatively, you can just open up Vim and then test for the features with the has() function.

:echo has("perl")
:echo has("python")
:echo has("ruby")

It should return 1 for the languages you have support for.

Vim scripting in Perl

Perl is a very popular scripting language that has been around for quite some time now. It is very powerful when it comes to parsing text and other similar tasks. This also makes it very useful from within Vim.

The simplest way to use Perl in Vim is with the following command:

:perl command

This executes the Perl command in the argument command. Note that the values you set with the Perl command will persist throughout the entire Vim editing session.

Often you would, however, like to execute more than just a single command and hence you have to use another command.

In that case you can use:

:perl << endpattern
perl code here
endpattern

This executes all the Perl code between the endpattern at the beginning and at the end.

In Perl, Python, or Ruby, you can use anything for your endpattern, but the last one needs to be the only word on that particular line, and should be at the beginning of the line. If you leave out the first endpattern, then Vim defaults to use a single dot as endpattern.

An example that just prints a single line of text to Vim could be:

:perl << EOF
VIM::Msg("this is a text");
EOF

Note how EOF is used as endpattern, and that in the Perl code I used a function called VIM::Msg() to print a message into Vim. This is just one among many functions you can use to interface between Vim and Perl. Other examples of Vim functions you can use from Perl are:

  • VIM::buffers(): Return a list of all buffers open in Vim.
  • VIM::SetOption("option"): Set a Vim option from Perl.
  • $curbuf->Name(): Returns the name of the current buffer.
  • $curbuf->Set(100, "fooo"): Replace line 100 in current buffer
  • with new text.

  • $curwin->SetCursor(15,8): Set cursor at line 15, column 8 in current window.

You can find a full list of the Vim-specific functions you can use from within Perl by looking in the help system with:

:help perl-pverview

If you put Perl code in your script, you should always remember to check if the user has support for Perl in his or her version of Vim.

It is always a good idea to have your Perl code wrapped in Vim functions in your script. This way it is easy to implement your script, and for an inexperienced user, the script will look normal and work as usual. An example of how to wrap Perl in a function could be:


function MoveCursor(row,col)
if has("perl")
perl << EOF
($oldrow,$oldcol) = $curwin->Cursor();
VIM::Msg("Old position was: ($oldrow,$oldcol)");
$curwin->Cursor(row,col);
EOF
else
echo "perl not available. canceling function call"
endif
endfunction

This function gets the old position of the cursor in the current window, prints that position, and then moves the cursor to the position that matches the two arguments for the function (row and column).

If the user does not have Perl support, then a message about this will be written. Note how the EOF is placed entirely to the left, even though the rest of the code is indented. This is strictly needed in order for Vim to be able to recognize it as the endpattern.

Hacking Vim 7.2 Ready-to-use hacks with solutions for common situations encountered by users of the Vim editor
Published: April 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

Vim scripting in Python

Through the recent years, Python has become the favorite scripting language for many programmers. This is mainly for its ease of use and strict rules about indenting (which lead to more readable code).

As with Perl, there is also an interface for Python in Vim, such that you can break out of Vim and use Python in your script. There are three main ways to use Python:

  1. When you only want to execute a single Python statement from Vim: :python statement. An example could be:

    :python print "hello Vim developer"

  2. If you want to execute a larger amount of Python code at the same time, you can use the following from Vim:

    :python << endpattern
    python statements here
    endpattern

    his executes all the Python code between the endpatterns.

  3. The third option for using Python from within Vim is by executing an entire Python script file. This is done with the following command from Vim:

    :pyfile file.py

    Replace file.py with the name of the script you want to execute.

Sometimes your Python script expects to get some command-line arguments. It is, however, not possible to pass these in the pyfile command.

There is, however, a workaround where you set the arguments in sys.argv before executing the Python script file. An example could be:


:python import sys
:python sys.argv = ["argument1", "argument2"]
:pyfile myscript.py

To make it easier to interface between Python and Vim, there is a Python module available called vim. This module gives access to some extra functionality in Vim. Here is an example of usage in a Python script:


import vim
window = vim.current.window
window.height =200
window.width = 10
window.cursor = (1,1)

You can find a complete list of available functions in the help system in:


:help 'python-vim'

It is always a good idea to wrap your Python code into Vim functions if you use it in a Vim script.

Vim scripting in Ruby

For many programmers in the western world, Ruby has been an unknown language until just recently. It has, however, been quite a popular programming language in Asia for some time, and after its introduction as a scripting language for web development it has become quite popular in the rest of the world. A real strength of Ruby is said to be the fact that it is truly object oriented, which makes the language very modular.

Vim has a nice interface for Ruby, such that you can use it from within Vim. This can be done in several different ways. The simplest way to execute single Ruby commands in Vim is with the following: :ruby command.

Replace command with any single-line Ruby command. An example could be:


:ruby print "Hello from Ruby"

You might, however, want to execute several lines of Ruby in a sequence. This can be done with the following Vim command:


:ruby << endpattern
ruby commands here
endpattern

This executes all the Ruby code between the endpatterns. If you set any variables or create any objects in the code, then these will be stored for later use in Vim.

Here is an example of what this could look like:

:ruby << EOF
window = VIM::Window.current
window.height = 250
window.width = 35
window.cursor = (10,10)
EOF

If your Ruby code is in a file, then you can even load this file directly in Vim and execute it. This is done with the following command:

:rubyfile file.rb

This is basically an alternative to using:

:ruby load 'file.rb'

Again all objects, among others, that you create in the script are stored in Vim for later usage, unless you remove them in the script.

Summary

This article has been an article especially for those who wanted to learn how to create complete scripts for Vim.

We learned a couple of tips about how to make your script check for all sorts of things such as the operating system and the version of Vim.

An introduction to using external scripting languages was also covered.


If you have read this article you may be interested to view :

About the Author :


Kim Schulz

Kim Schulz has an M.Sc. in Software Engineering from Aalborg University in Denmark. He has been an active developer in the Linux and Open Source communities since 1997 and has worked with everything from translation and bug fixing to producing full-blown software systems. This entire time, Vim has been Kim's editor of choice and it has been the first thing he installs whenever he sits by a new computer. Today Kim works as a full-time software engineer at CSR Plc. developing software for the next generation wireless technologies. A lot of Kim's spare time has been spent on developing the open-source CMS Fundanemt. This has lead to him now owning the web-hosting company Devteam Denmark that specializes in hosting and development of Fundanemt-based websites.

Books From Packt


Joomla! E-Commerce with VirtueMart
Joomla! E-Commerce with VirtueMart

Magento 1.3 Sales Tactics Cookbook
Magento 1.3 Sales Tactics Cookbook

Expert PHP 5 Tools
Expert PHP 5 Tools

Drupal E-commerce with Ubercart 2.x
Drupal E-commerce with Ubercart 2.x

Hacking Vim: A Cookbook to get the Most out of the Latest Vim Editor
Hacking Vim: A Cookbook to get the Most out of the Latest Vim Editor

Linux Email
Linux Email

ModSecurity 2.5
ModSecurity 2.5

Beginning OpenVPN 2.0.9
Beginning OpenVPN 2.0.9


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
p
K
i
1
Q
U
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software