Buggin’ Out with the Vim Debugger: Quirks, Tweaks n Tips

27th April, 2008Insights

This article assumes you have already experimented with using the vim debugger as described in this fine article. Big respect to Sueng Woo Shin for writing the debugger script itself. If you’ve already experimented with it and think you want to use it more then read on…

Using a debugger wins hands down over the good old echo/die approach but if you want to use the aforementioned debugger (which you do because you want to use vim right? right!) then you may need to get used to a few little quirks and maybe even tweak it a little bit so feels a bit….righter.

So with that in mind here’s a few little things that I’ve done and realised that have made it start to feel that little bit righter to me …

How to debug a script which is invoked via the PHP CLI

To debug a page being served up via apache you point your browser to:

http://example.com/index.php?XDEBUG_SESSION_START=1

in order to set a cookie your browser and then the presence of this cookie indicates that you’re keen to debug some stuff.

If the code you want to debug is being run via the PHP CLI then the above won’t work so instead you need to set an environment variable before you run invoke the PHP CLI to run your script. This works for tcsh:

setenv “XDEBUG_CONFIG=vim=1”

Then run your script via the CLI (eg, php -f my_script.php) and as long as you have Vim open and have pressed F5 (like you normally do when you want to debug in vim) then you should be able to debug your script.

What’s going on with regards to the files that get opened when a debugging session starts up?

Well regardless of if you like it or not the debugger always opens the “first” file in the call stack, if you like. So if you are debugging a handler that gets invoked from say http://workingsoftware.com.au/myapp/index.php?h=FindProduct then it always opens index.php. This is quite annoying cos most of the time you don’t really want to debug index.php…in the above example you probably want to debug find_product.class.php, which is the file where the application code actually resides (whereas index.php is part of a framework and you’re usually interested in debugging the application, not the framework). (ed: this is referring to usage of the RocketSled PHP framework but will be similar for any framework where you have one script which dispatches control to a Controller or Handler class or script)

There’s no real way around this that I can see. So this is what I do if say I want to debug a file called find_product.class.php which is a Handler class (or Controller in MVC terminology) invoked by hitting the URL http://workingsoftware.com.au/myapp/index.php?h=FindProduct:

  1. cd myapp/packages/myapp/handlers/
  2. open find_product.class.php at the command line by doing: vim find_product.class.php
  3. hit F5
  4. quickly (within the 5 second limit….see below – I have made this limit longer) go to the URL in your browser (ie, http://workingsoftware.com.au/myapp/index.php?h=FindProduct)
  5. the debugger will open up index.php and in the process close your find_product.class.php leaving you with index.php and the other debugger specific windows. Bit annoying. Since you dont want to debug index.php close this file by doing :q
  6. now you’re left with just the debugger specific windows (actually viewports) in vim. Now open up the file you want to actually debug, find_product.class.php, by doing :sp find_product.class.php
  7. Now go ahead and do your debugging. Once the debugger session finishes you’ll be left with the find_product.class.php file open in vim.

The good news is that if you set any breakpoints in your find_product.class.php file while you were debugging, as long as you don’t close vim itself (doesn’t matter if you close the find_product.class.php file and reopen it, as long as vim stays running) then you can hit F5 again to start another debugging session and repeat the above steps and once you’ve gotten back past the final step you will see that the breakpoints you set in the last debugging session have been remembered in the new one.

What are all these bloody windows?

I have found that using the debugger was made quite hokey due to the fact that the screen space got crowded out with a lot of superflous stuff. I can’t see, at this stage, why you really need the TRACE_WINDOW or HELP_WINDOW to be there in every debugging session. The WATCH_WINDOW and the STACK_WINDOW are the only real useful ones.

So I have edited the debugger.py file to do away with these windows. You can download my edited version here

http://www.workingsoftware.com.au/downloads/debugger.py
NB: All the original code has been more or less left in there, I’ve just commented the various bits out. You can run a diff on the original to see exactly what the changes are.

Now when you start up a debugging session you’ll see the file(s) you’re debugging, the WATCH_WINDOW and the STACK_WINDOW all stacked on top each other like you’d get if you did :sp normally.

The fine peeps who developed this debugger have mapped the F1 key so that it resizes the debugger windows. This is cool but I found you had to press F1 three times to get the window to resize the way I wanted it. So I edited debugger.py again to make it just toggle between the equivalent of Ctrl+W= and Ctrl+W_ . So when you’re debugging if you are in the find_product.class.php file’s window and you press F1 it will blow that window up to take up the majority of the screen. Press it again and it will go back to an even split between find_product.class.php, WATCH_WINDOW and STACK_WINDOW. Go into the WATCH_WINDOW window and press F1 and it will make the WATCH_WINDOW blow up, hit again and back to even split. Same goes for STACK_WINDOW obviously.

Controlling the debugger – keyboard commands

I realise this is probably stating the obvious for a lot of people and that it is also covered in the debugger script documentation but I’ll include it anyway for completeness… Also if you’re using the aforementioned edited version of debugger.py you will no longer have the HELP_WINDOW in your debugging session so you’ll have to remember the commands with your brain… this might help:

Command | What it does

  • F1

    toggle resize

  • F2

    step into

  • F3

    step over

  • F4

    step out

  • F5

    run (to next breakpoint or end of script)

  • F6

    end debugging session

  • F11

    dump context to WATCH_WINDOW. this will dump the values of all the variables in scope into the WATCH_WINDOW

  • F12

    if you have the cursor positioned over a variable in the file that you are debugging then hitting F12 will dump the value of that variable out into the watch window. NB: I have listed 2 caveats associated with F12 below

  • ,e

    If you do ,e and then type in the name of some variable then you will see that variable’s value. If its an array you’ll see the array contents, if its an object you’ll see the object’s contents. if it’s empty or out of scope you’ll see (null).

  • :B

    sets a breakpoint

  • :Bp

    unsets a breakpoint

F12 caveats

  • If you hit F12 and the cursor is positioned on an empty line then it will cause vim to go into INSERT mode. Quite annoying but good to know.
  • If you hit F12 and the cursor is in the WATCH_WINDOW or the STACK_WINDOW then it will print “no commands none” and end yourde bugging session. Again annoying but good to know.

A couple of handy commands for managing breakpoints

So you can use :B and :Bp to toggle a break point on/off. But some other useful stuff that’s not immediately obvious is:

Command | What it does

  • :sign place

    lists all breakpoints, showing which line each one is on

  • :sign unplace *

    clears all breakpoints

  • ???

    go to next breakpoint (haven’t figured this one out yet … anyone?)

Five seconds doesn’t seem like long enough..

The debugger.py script is hard coded to wait 5 seconds for a connection after you’ve pressed F5. This didn’t seem like long enough to me so I changed it to wait 15 seconds.

This change is in the edited debugger.py which you can download here:

http://www.workingsoftware.com.au/downloads/debugger.py

Just search for ‘serv.settimeout(15);’ and change 15 to however many seconds you think is reasonable if you want to change it.

So they’re a few little things I found handy. If you find more let us know 😉

Comment Archive

This post originally appeared on an older version of the Working Software website which implemented it’s own comment mechanism. This new version of our website/blog uses Disqus for comments (see below) however I wanted to preserve the comments made on the previous post here:

hi just to add another usefull thing :Bp would set up a breakpoint with an expression according to context you might wanna check, http://slackdna.blogspot.com/search/label/vim-dbgpclient

Zeft (2009-03-11)

Read More Posts

BYOD and Cybersecurity: An In-Depth Analysis

BYOD and Cybersecurity: An In-Depth Analysis

Bring Your Own Device (BYOD) policies have become increasingly prevalent in Australian businesses, offering flexibility and cost savings. However, they also introduce complex cybersecurity challenges. In this article, we explore the cybersecurity implications of BYOD...

Using a Second Phone Number for Personal Use: Benefits and Risks

Using a Second Phone Number for Personal Use: Benefits and Risks

In today's connected world, balancing personal and professional life is more challenging than ever. One solution gaining popularity is the use of a second phone number for personal use. This approach, especially with solutions like BenkoPhone, offers several benefits...

Want to try BenkoPhone?