Thursday, June 14, 2007

New Features in Vim 7

Round up of New features of Vim 7.0


This is my first attempt to write a review of any kind, so please excuse any rookie mistakes. The entire review is written in EMACS...just kidding. The review was written in Vim 7.0
and screen shots were captured using ksnapshot and edited using krita. Normally putting up screen shots of Vim is a ridiculous idea, but many of the new features have visual components (like pop-ups etc), so screen shots seem appropriate here.

If you have to ask what is Vim, then this review is not for you, as I am not going to explain what Vim is, rather this is an attempt to give a brief description of new features of Vim 7.0. So without further a do, let's dive in to Vim 7.0.

New Features at a glance

  • getscript plugin
  • spell check
  • omni completion
  • Tabs
  • Undo branches
  • Internal Grep
  • Highlighting
  • Other notable improvements

getscript plugin

Scripts extend the functionality of Vim in many ways. Vim Official Site is the place where to get them, but until rel 7.0 there was no way of auto upgrading scripts to their latest version. That's where the getscript plugin comes in handy. From within vim do ':GLVS' and the script will download the latest version of the plugins already installed in your '$HOME/.vim' directory. The script is not completely fool-proof and it requires some amount of preparation before it can get to work , but it is certainly step in the right direction.

Spell Check

Vim releases prior to 7.0 did support spell checking through external programs, but was clumsy and slow. Vim 7.0 has built in spell checking. It works out of box for English, all that is required is to issue an command
':setlocal spell spelllang=en_us'.
Al though of little use to programmers, this will come in handy for documentation (You do document your code don't you).
Attached are a few screen shots to demonstrate Vim spell checking in action.

Spell checking in text mode

vim spell checking in text mode

Spell checking in gui mode

Vim spell checking in GUI mode

Sadly spell check did not work correctly while editing this document (how ironic). It would highlight mistakes only between link tags <A> and ignore the rest of the document. I had to rename the file with .txt extension to get spell check working. Also another annoyance is that if you are using a mouse to correct mistakes, you need to first left click on the misspelled word to move the cursor to that word, and then right click to activate the spelling menu, I would expect that right-clicking on a misspelled word should automatically move the cursor to it. Another option I couldn't find in the GUI pop-up for spelling suggestions was the "change/ignore all". I am sure the textmode working is much better.

Omni complete

Perhaps the most touted feature of all, initially called as intellisense, but renamed to omni complete due to trademark issues. This is a sort of smart complete primarily for programming/scripting languages.

The following languages are supported out of box, and the feature is extensible so adding support for other languages is trivial.

  • C
  • (X)HTML with CSS
  • JavaScript
  • PHP
  • Python
  • SQL
  • XML

The help pages on omni complete have detailed instructions on using this new feature. The key sequence to trigger omni complete is ^X^O (Control-X followed by Control-O).

There are already plenty of plugins available at www.vim.org for other languages. VJDE plugin adds IDE like functionality to Vim for editing Java/C/C++ code as well as add omni completion support for Java. cppomnicomplete adds omni complete support for C++. For XML it is possible to convert XML DTDs in to VIM XML data file, so that while editing an XML of that particular DTD, omni complete presents a list of only vaild elements/attributes as per the DTD.

One thing I noticed is that the speed of completion varies, it was quite fast for /Java/HTML but slow for PHP and somewhere in between for C.

Attached are a few screen shots of Omni Complete in action.

Omni Complete for C Omni Complete for html
omni complete for C omni complete for html
Omni Complete for Java Omni Complete for php
omni complete for java omni complete for php

Tabs

Another feature missing in Vim 6.x was tabs for editing multiple files. Although pre 7.0, Vim did support editing multiple files using the concept of buffers and vertical and horizontal splits, addition of tabs is welcome.This will definitely help in integrating Vim with other IDE environments such as Netbeans, Eclipse , Visual Studio etc.

One great feature about Vim tabs is the ease of moving from one tab to another. Simply in normal mode, type '[n]gt' to move to the nth tab. Also all commands that work on windows work on tabs with 'tab' appended to them. e.g. ':tabnew' .

Following is a screen shot for tabs.

tabs in action

Undo Branches

This is an interesting concept, and could become very useful. Traditionally any application has a single Undo/Redo Stack, so after undoing a lot of work if you make new changes, all the redo stack is lost. Vim creates backups of undos at regular interval, so that you can recreate the file as it looked at last branch. The ':undolist' command shows all the undo branches.

How ever there are times when I want to undo a select steps but retain some changes. e.g. I make 10 changes, and undo 5, after that I want changes 9 and 10 redone, it is currently not possible and would require some sort of merge feature found in version control systems.

Internal Grep

Vim 7.0 comes built-in with it's own grep, combined with the solid support for regular expressions, this is a handy feature for windows users who don't have access to external grep command. The internal grep command is invoked by ':vimgrep' and can recurse in to sub directories.

Highlighting

When ever the cursor moves over any of the following characters '<{[(' it's matching '>}])' is highlighted. However this depends on a command getting executed every time the cursor moves and may need to disabled on slow terminals.

Also 2 more options 'cursorline' and 'cursorcolumn' have been added which enable highlighting of the line and column on which the cursor is present. Following is a screen shot with matching [] and cursorline enabled.

cursorline highlight


Other notable improvements

Here is a list of other notable improvements. This list is by no means exhaustive, and a full detailed documentation can be found in Vim help. ':help version7' is your friend.

  • Support for printing multi-byte text
  • MzScheme interpreter support
  • Full 32 bit Unicode support
  • Remote file explorer with netrw plugin
  • Various New commands, vim scripting functions, search patterns
  • Syntax and Indent files for many more file types.
  • Lots and lots of improvements to existing functionality
Conclusion

In conclusion Vim 7.0 continues to build up on top of, what was an already solid 6.x series. I have been running 7.0 (alpha and beta) releases for a long time now and finally with release of 7.0 , it will surely replace all 6.x installation on all my boxes.

The new features of Vim will help to embed it in bigger IDEs such as Netbeans, Eclipse, Sun Studio etc. Thus programmers can have best of both worlds, the power of Vim and convenience of an IDE.

Notes

For this review Vim 7.0 was compiled from source on a Linux box. The reason behind compiling from source was to enable every possible feature , as against using the binary release which has only a limited set of features enabled. Following was the options passed to the 'configure' script.

./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-perlinterp --enable-pythoninterp --enable-tclinterp --enable-rubyinterp --enable-cscope --enable-multibyte --enable-xim --enable-fontset --enable-gui=auto --with-features=hugh

Wednesday, June 13, 2007

Maven best practices: Use dependency management for multi module projects.

Do you struggle to maintain a common configuration for dependencies (version #, type etc.),
between various modules of your multi-module maven 2.x project ?



There is a very easy way to control all your dependency related configurations from the parent 'pom' project.
Instead of specifying the same kind of configuration for dependencies over and over, in various modules, just
specify them once inside the <dependencyManagement> node of the parent pom.xml.



What ever configurations are done in the 'dependencyManagement' section of the parent pom.xml,
are automatically inherited by the child projects.
Typical configurations include a version number of the dependency artifact, a list of transitive dependencies
to exclude, when including this dependency, the default scope of the dependency, etc.
Infact when properly configured, any sub project needs to specify only the group-id and artifact-id of a required
dependency, everything else is inherited from the parent pom.xml.



Just think about it for a second, a clear simple way to have the same version of log4j jars in all your sub modules,
A clear way to have junit.jar scope set to 'test' in all sub projects. And when you need to change the version
of a dependency, you just need to do it in one place, and bam. every child project now referes to the newer version
of your dependency.



Here's a code sniplet of 'dependencyManagement' block in one of my parent pom.xml


<project....>
......
<packaging>pom</packaging>
............
<dependencymanagement>
<dependencies>
<dependency>
<groupid>commons-logging</groupid>
<artifactid>commons-logging</artifactid>
<version>${commons.logging.version}</version>
<exclusions>
<exclusion>
<groupid>log4j</groupid>
<artifactid>log4j</artifactid>
</exclusion>
<exclusion>
<groupid>logkit</groupid>
<artifactid>logkit</artifactid>
</exclusion>
<exclusion>
<groupid>avalon-framework</groupid>
<artifactid>avalon-framework</artifactid>
</exclusion>
<exclusion>
<groupid>javax.servlet</groupid>
<artifactid>servlet-api</artifactid>
</exclusion>
</exclusions>
</dependency>
..........
</dependencies>
</dependencymanagement>
<properties>
<commons.logging.version>1.1</commons.logging.version>
</properties>
</project....>


As you can see, I have 2 things here, I have specified a default version that all subsequent children projects will inherit,
and I have also specified a bunch of transitive dependencies that I want to exclude from this dependency.



Now all a child project needs to do is


<project>
···<packaging>jar</packaging>
···<dependencies>
··· <dependency>
<groupid>commons-logging</groupid>
<artifactid>commons-logging</artifactid>
······</dependency>
···.....
···</dependencies>
</project>

Everything else is inherited from the parent, and when commons-logging is out with a new version, that I need to use
I need to change the version # in just one place.

WARNING Beware that any dependency specified in 'dependencyManagement' section is not an
actual dependency on either the parent project nor the child project, unless it is explicitly specified as one, in the regular
'dependencies' block.
So in short dependencyManagement is a place to configure all possible dependencies that your
sub-projects may have, but not a place to actually state a dependency. e.g. for the above configuration, a child project
will not have a dependency on commons-logging unless it includes it in its pom.xml.



Another thing to keep in mind, is that many IDEs that have the ability to work with maven projects (Eclipse, Netbeans etc),
might not give you this functionality of managing dependencies from 'dependencyManagement' block
, so you may have to do this part by hand.
In my case, where I use Netbean 6.0 IDE, the IDE picks up correct dependency
attributes from the parent pom, only if the files already have the stuff setup before opening the project. If I add a dependency
inside the pom.xml of an open parent project, and then refer to it in a open child project, the maven plugin gets confused, and
refuses to recognize the child project as a valid maven project. The only solution in that case is to restart the IDE :(.


Hope you have found this little piece of information helpful.

Tuesday, June 12, 2007

Prototyping LAMP with WAMP

WAMP is the windows equivalent of the LAMP stack. LAMP stands for Linux (Operating System), Apache (Web Server), Mysql (Database), and PHP (Scripting Language). Under WAMP, instead of using Linux as the Operating System, you use one of the Microsoft Windows OSes such as XP, 2000 or 2k3.

Why use WAMP instead of LAMP


Windows OSes since 2000 i.e. 2k, XP , 2k3 have been extremely stable as opposed to their predecessors. So if you are proficient in Windows, then there is no reason not to use it for web hosting. (barring security, but that's another issue).
Secondly if you want to develop your site off line and then move it to a LAMP Stack, and you are not familiar with Linux, then WAMP serves as an ideal prototyping environment. You can do almost every thing in WAMP that you can do in LAMP.

Installing WAMP


WAMP is hosted at www.en.wampserver.com. Unlike LAMP where you have to install and configure each component seperately, wamp comes bundled in as one single installer, and installs every thing under one directory. WAMP also provides you with a System Tray Menu to start/stop configure various components. For someone new to web development this is a great feature to have.

To install WAMP, download and run the latest WAMP installer 1.6.3 from the site mentioned above. As of WAMP 1.6.3, it contains Apache 2.0.55 , PHP 5.1.4, MySQL 5.0.21 as the main components and also phpmyadmin 2.8.0.3 and sqllitemanager 1.2.0 as add-ons.
By default the installer will place every thing under C:\wamp. The installer also creates 2 services viz. 'wampapache' and 'wampmysql' for starting/stopping Apache and MySQL respectively. The installer creates a handy 'System tray monitor' for managing WAMP.

Once installed, if you open a web browser on your windows box, and type http://localhost/ you should see, something like this.
This confirms that you have successfully installed WAMP.
You can click the phpinfo() link to see details of your PHP environment. Also you can use the pre installed applications phpmyadmin and sqllitemanager to configure MySQL and sqllite respectively.

Next up Configuring and managing WAMP


Configuring and managing WAMP


One neat thing about WAMP is Apache, PHP and MySQL can be configured from one single 'System Tray App'. No need to go digging in explorer to find the relevent files. You can also start/stop apache and MySQL services using the 'System Tray App'.

The default configuration is sufficient to get started, but we are going to perform certain customizations.
  • Create a password for MySQL root account.

    First things first, the default WAMP install, creates a MySQL super-user (root) account with no password. This is OK for prototyping, but if you have an internet facing m/c, you should create a password for that a/c. This is easily done using the pre installed phpmyadmin web application.

    Open the URL http://localhost/phpmyadmin/ in a web browser. This should bring up the phpmyadmin page. This is the starting point of controlling everything related to MySQL.
    Click on the 'Privileges' link, that should bring up the user accounts page. Click on the icon besides the 'Grant' column, to edit root user's properties.
    On the following page, scroll down to 'Change password'. Select the 'Password' check box and supply a password. Click 'GO' button when done. This should setup a password for the root a/c.
    But we are only half done, now that the root a/c has a password, phpmyadmin application will not work unless you edit a config file and put the password in there.
    To get phpmyadmin working again , open the file 'C:\wamp\phpmyadmin\config.inc.php' using wordpad (any text editor). Change the line

    $cfg['Servers'][$i]['password'] = '';
    to
    $cfg['Servers'][$i]['password'] = 'newly-created-password';

    This will make phpmyadmin work correctly again.

Next up Configure Apache

  • Configure Apache

    Configuration files for Apache, PHP and MySQL can be easily accessed using the system tray icon, as shown by the figure in left. Click on 'http.conf' to access apache's configuration file.
    We are not going to change much here. Scroll down till you see a bunch of 'LoadModule xyz' statements. Some of the Apache modules are commented out. Uncomment the following 3 modules by removing the leading '#' 1) mod_status , 2) mod_info and 3) mod_rewrite.
    mod_info and mod_status provide us with vital statistics regarding the apache server, (these shouldn't be enabled on a production server). To be able to access the server info and status , we need to uncomment a few more lines.
    First of change the line ExtendedStatus Off to ExtendedStatus On, next search for and uncomment lines between
    <Location /server-status>...</Location>
    and
    <Location /server-info>...</Location>

    This will enable us to get the server status and info by navigating to URLs http://localhost/server-status and http://localhost/server-info respectively.
    If you install a PHP Content Management System (CMS) such as Drupal then it can use mod_rewrite module to output search engine friendly URLs.
  • Configure PHP and MySQL

    In case you need to configure PHP (add/remove extensions), you can use the 'System Tray Monitor' or directly edit C:\wamp\apache\bin\php.ini file. Similary to configure MySQL edit C:\wamp\mysql\my.ini

Final thoughts

Installing and configuring WAMP is really easy and straight forward. It is an ideal prototyping platform for any one who wishes to develop for the LAMP stack. And if you are feeling adventurous you can use WAMP as your final platform as well. I have also installed Drupal and Gallery on top of WAMP without problems.

Bash Shell Tricks

Things you didn't know bash could do

Are you sure you are squeezing out all, that the bash shell can provide.Presented below are a few obscure things that bash can do, but chances are you may not have heard of them.

Completion

No I am not talking about completing command/file names. I am talking about completing arguments to various commands, completing filenames based on application. This is one of the touted features of
'zsh', but unknown to many is the fact that it is also available in bash.
All you need to do is install bash-completion.

With bash completion installed you can use the TAB key to complete arguments to common commands like rpm, apt, find, grep etc. Also bash-completion will complete host-names
for ssh, scp, by looking up hosts inside your $HOME/.ssh/authorized_keys file. For rpm based distros, bash-completion will even lookup package names already installed.

The feature I find most handy is file-name completion based on the context of the command. e.g. if you type tar -zxvf and then press the TAB key twice, you will get a list of only files ending in .tar.gz or .tgz rather than a list of all files in the directory.

Socket Communication

I bet a lot of you haven't heard of this, but bash can indeed perform basic socket communication via /dev/tcp, /dev/udp. These are pseudo devices that bash uses to communicate with network sockets. In fact if you did ls -l /dev/tcp /dev/udp you will get a 'No such file or directory' error message.

So how to use them, we below I present 2 examples.

One to quickly check headers from a HTTP Server. Here is a simple function you can put in your $HOME/.bashrc that will check for headers of HTTP server.

headers() {
server=$1; port=${2:-80}
exec 5<> /dev/tcp/$server/$port
echo -e "HEAD / HTTP/1.0\nHost: ${server}\n\n" >&5;
cat 0<&5;
exec 5>&-

Simply invoke it by

bash# headers <servername or ip> <port>

The port number defaults to 80 if not provided.

Second example is a quick way to check if a port is open or not. You can always use netcat or telnet, but I find this easier.

testPort() {
server=$1; port=$2; proto=${3:-tcp}
exec 5<>/dev/$proto/$server/$port
(( $? == 0 )) && exec 5<&- }

Again invoke it by

bash# testPort <servername or ip> <port> <protocol>

The protocol can be either tcp or udp and defaults to tcp.


Arithmetic Evaluations


Bash can perform arithmetic evaluations. They are much easier to using expr tool. Below are some examples.Note the absense of $ prefix for variable names.

((count++)) #increment value of variable 'count' by one.
((total+=current)) # set total = total+current.
((current>max?max=current:max=max)) # ternary expression.

Other neat bash tricks


  • ^orig^repl^ replace 'orig' in previous command with 'repl' and execute the new command.
  • cp filename{,.bak} Copy 'filename' as 'filename.bak.
  • mkdir -p dir{1,2,3}/subdir{1,2} Create dir1/subdir1 dir1/subdir2 dir2/subdir1 dir2/subdir2 dir3/subdir1 dir3/subdir2