I recently decided that putting strategically placed print statements scattered about my python programs to debug was getting to be a little messy.

I had thought to try out other debugging plugins I found online, but thought I would give writing my own simple breakpoint plugin a shot.

I know of python's pdb module, but my goal was to minimize the amount that I had to type to debug my programs.

Only a few keybinds are mapped:

Normal mode:

  • <leader>b — Toggle breakpoint for the current line
  • <leader>B — Run debugger in a new tmux split

Visual Mode:

  • <leader>b — Toggle breakpoint for the selected lines

This has only been tested on Linux. The only requirement is tmux

" Define breakpoint highlight color and mark in number column
hi Breakpoint ctermfg=1 ctermbg=NONE
sign define Breakpoint text=● texthl=Breakpoint

" Map of lines that have breakpoints
let b:breakpoints = {}

function ToggleBreakpoint(lnum)
    let is_breakpoint = get(b:breakpoints, a:lnum, 0)

    if is_breakpoint
        " Remove the line number in breakpoints and unplace the mark
        call remove(b:breakpoints, a:lnum)
        exe ":sign unplace"
        " Add the line number in breakpoints and place the mark
        let b:breakpoints[a:lnum] = 1
        exe ":sign place 2 line=" . a:lnum . " name=Breakpoint file=" . expand("%:p")

function BreakpointIndentation(lnum)
    " Get the line's current indentation level and first character
    let indent_count = indent(a:lnum)
    let curline = getline(a:lnum)
    let firstChar = curline[0]

    " Build the indentation to use for the breakpoint
    if firstChar == "\t"
        " Handle user defined `tabstop` variable
        return repeat(firstChar, indent_count / &tabstop)
    else if firstChar == " "
        return repeat(firstChar, indent_count)
        return ""

function RunPDB()
    let lnum = 1
    let num_lines = line("$")

    " The lines to write to the temporary file
    " Start out by importing pdb
    let lines = ["import pdb"]

    " Iterate over each line in the current buffer
    while lnum <= num_lines
        let is_breakpoint = get(b:breakpoints, lnum, 0)

        " If the line is a breakpoint, add `pdb.set_trace` before that line
        if is_breakpoint
            let indentation = BreakpointIndentation(lnum)
            let breakpoint_line = "pdb.set_trace()"
            if indentation != ""
                let breakpoint_line = indentation . breakpoint_line
            call add(lines, breakpoint_line)

        call add(lines, getline(lnum))
        let lnum += 1

    " Create a new temporary file with the contents of `lines`
    let tmpfile = tempname()
    call writefile(lines, tmpfile)

    " Make a new vertical tmux split and run the temporary file with python
    silent exe "!tmux split-pane -v"
    silent exe "!tmux send-keys 'python " . tmpfile . "' Enter"


nnoremap <leader>b :call ToggleBreakpoint(line("."))<CR>
vnoremap <leader>b :call ToggleBreakpoint(line("."))<CR>
nnoremap <leader>B :call RunPDB()<CR>

This is my first attempt to write anything particularly useful in vimscript.

Are there any sections that can be improved upon?



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.