"Coyright (c) 2006-2007 James Dominy "This software may be distibuted under the terms of the Gnu General Public License (GPL) "version 3 (or higher) if ! exists("g:VDBSourced") let g:VDBSourced = 1 let s:ScriptLocation = expand("") python << >> import pty import vim import thread import os import re import sys import time import select df = open("/tmp/vdb-debug.log", "w") def bufvisible(bufnum): for w in vim.windows: if w.buffer.number == bufnum: return True return False def openbuf(bufnum, **kwargs): if bufnum is None: return False i = 0; while i < len(vim.windows): if vim.windows[i].buffer.number == bufnum: vim.command('execute %i . "wincmd w"'%(i+1)) return True i += 1 if "name" in kwargs: if "position" in kwargs and kwargs["position"] == "below": vim.command("set splitbelow") else: vim.command("set nosplitbelow") vim.command("%inew %s"%(kwargs["height"], kwargs["name"])) if "settings" in kwargs: vim.command("setlocal %s"%(kwargs["settings"])) return True else: return False def openwin(winnum): vim.command('execute %s . "wincmd w"'%(winnum)) def removebuf(bufnum): if bufnum is None: return vim.command("bdelete %i"%bufnum.number) def TermInsert(): vim.command("setlocal modifiable") vim.command("normal G") vim.command("startinsert!") if vim.current.buffer.number == VDB.outputbuffer.number: VDB.outputpromptlen = len(VDB.outputbuffer[-1]) def TermBackspace(): if vim.current.buffer.number == VDB.debugbuffer.number: mincol = VDB.debugpromptlen if vim.current.buffer.number == VDB.outputbuffer.number: mincol = VDB.outputpromptlen col = vim.current.window.cursor[1] if col > mincol: vim.current.line = vim.current.line[0:col-1]+vim.current.line[col:] def TermLeftLimit(): if vim.current.buffer.number == VDB.debugbuffer.number: mincol = VDB.debugpromptlen if vim.current.buffer.number == VDB.outputbuffer.number: mincol = VDB.outputpromptlen col = vim.current.window.cursor[1] if col <= mincol: vim.current.window.cursor = (vim.current.window.cursor[0], mincol) def TermUp(): if VDB.debughistorypos > 0: if VDB.debughistorypos == len(VDB.debughistory): VDB.debughistorycurrent = VDB.debugbuffer[-1][VDB.debugpromptlen:] else: VDB.debughistory[VDB.debughistorypos] = VDB.debugbuffer[-1][VDB.debugpromptlen:] VDB.debughistorypos -= 1 VDB.debugbuffer[-1] = VDB.debugbuffer[-1][:VDB.debugpromptlen] + VDB.debughistory[VDB.debughistorypos] vim.current.window.cursor = (vim.current.window.cursor[0], len(VDB.debugbuffer[-1])) def TermDown(): if VDB.debughistorypos < len(VDB.debughistory): VDB.debughistory[VDB.debughistorypos] = VDB.debugbuffer[-1][VDB.debugpromptlen:] VDB.debughistorypos += 1 if VDB.debughistorypos == len(VDB.debughistory): VDB.debugbuffer[-1] = VDB.debugbuffer[-1][:VDB.debugpromptlen] + VDB.debughistorycurrent else: VDB.debugbuffer[-1] = VDB.debugbuffer[-1][:VDB.debugpromptlen] + VDB.debughistory[VDB.debughistorypos] vim.current.window.cursor = (vim.current.window.cursor[0], len(VDB.debugbuffer[-1])) def TermDebugSend(): VDB.debugcommand(VDB.debugbuffer[-1][VDB.debugpromptlen:], False, False) VDBUpdateWatches() openbuf(VDB.debugbuffer.number) vim.command("normal G") vim.command("startinsert!") def TermKeyPress(key): if not VDB.running: print "The program is no longer running." df.write("The program is no longer running.\n"); df.flush() return if key == "CR": VDB.processinput.write("\n") else: VDB.processinput.write(key) VDB.processinput.flush() def setconsolebuf(): for k in ["i", "I", "a", "A", "o", "O", "s", "S", ""]: #make sure insert operatons position the cursor at the end of the buffer, and capture the current length of the last line vim.command("nmap %s :python TermInsert()"%(k)) for k in ["r", "R", "p", "P", "d", "D", "x", "X", "c", "C"]: #prevent changes to the buffer from normal mode vim.command("nmap %s "%(k)) for k in [""]: #ignore the word wipe vim.command("imap %s :python pass"%(k)) vim.command("imap :python TermBackspace()") #catch the backspace and make sure it doesn't go back further then the first insert position for k in ["", "", ""]: #catch left and make sure it doesn't go back too far either vim.command("inoremap %s :python TermLeftLimit()"%(k)) for k in ["", ""]: #send home to the right position vim.command("inoremap %s :python TermLeftLimit()"%(k)) #allow for command history for k in ["", "", "", "", ""]: vim.command("imap %s :python TermUp()"%(k)) for k in ["", "", "", "", ""]: vim.command("imap %s :python TermDown()"%(k)) def setterminalbuf(): for k in ["i", "I", "a", "A", "o", "O", "s", "S", ""]: #make sure insert operatons position the cursor at the end of the buffer, and capture the current length of the last line vim.command("nmap %s :python TermInsert()"%(k)) for k in ["r", "R", "p", "P", "d", "D", "x", "X", "c", "C"]: #prevent changes to the buffer from normal mode vim.command("nmap %s "%(k)) for k in [""]: #ignore the word wipe vim.command("inoremap %s :python pass"%(k)) #pass the standard keys straight through for k in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]{};:,.<>/?": vim.command("silent inoremap %s :python TermKeyPress('%s')"%(k,k)) vim.command("silent inoremap ' :python TermKeyPress('\\'')") vim.command("silent inoremap \" :python TermKeyPress('\\\"')") vim.command("silent inoremap \ :python TermKeyPress('\\'')") vim.command("silent inoremap \\| :python TermKeyPress('\\|')") #and marshall the other significant keys into ansi escape sequences vim.command("silent inoremap :python TermKeyPress(' ')") vim.command("silent inoremap :python TermKeyPress('CR')") #Function keys #Cursor keys #Ins, Del, Home, End, PgUp, Pgdn, Tab, Esc #CTRL-keys #def VDBParseInterface(filename): # interface = {} # f = open(filename, "r") # line = f.readline() # while line != '': # (key, value) = tuple([x.strip() for x in line.split("=")]) # if value = '': # interface[key] = [] # line = f.readline() # while line != '' and line.startswith("\t"): # # interface[key] = class TSession(object): def __init__(self, VDBSourceFile, VDBArguments): vim.command("wincmd o") self.maxheight = vim.current.window.height self.unmodifiablebuffers = [] self.sourcebuffer = vim.current.buffer self.pid = os.getpid() self.executionfile = None vim.command("%inew %i-debug"%(vim.current.window.height/5+1, self.pid)) vim.command("setlocal statusline=Console buftype=nofile noswapfile bufhidden=hide") self.ready = False self.debugbuffer = vim.current.buffer setconsolebuf() vim.command("inoremap :python TermDebugSend()") self.debughistory = [] self.debughistorypos = None vim.command("e %s-output"%(self.pid)) vim.command("setlocal statusline=Output buftype=nofile noswapfile bufhidden=hide") self.outputbuffer = vim.current.buffer setterminalbuf() self.watchbuffer = None #load appropriate interface depending on extension (using gdb interface for testing) self.interface = { "executable": "gdb -fullname", "prompt": "(gdb) ", "autostart": [ "file %(VDBSourceFile)s", "set args %(VDBArguments)s", "set inferior-tty %(VDBTerminal)s", "start" ], "stepinto": "step", "stepover": "next", "continue": "cont", "finish": "finish", "setbreak": "break %(buffer)s:%(lineno)i", "breakpoint": "Breakpoint ([0-9]+) at .*", "clearbreak": "delete %(number)i", "condition": "condition %(number)i %(condition)s", "getsymbolvalue": "print %(symbolname)s", #"executionplacement": "(.+):([0-9]+):[0-9]+:[^:]+:0x[0-9a-f]+", #"ignorechars": ["\032"], "autoresponses": [ #(tuple of form (pattern to match, filtered line to add to console buffer, action) ("^\032\032((.+):([0-9]+):[0-9]+:[^:]+:0x[0-9a-f]+)$", "\\1", self.placeexecution, [("filename", "\\2"), ("lineno", "\\3")]), ("^\$(\d+) = (.*)$", "\\2", None, None), ("^Starting program: (.+)$", None, self.start, None), ("^Program exited normally.$", None, self.stop, None) ], "functions": [] } self.running = False self.executionsignplaced = False self.ptymaster, self.ptyslave = pty.openpty() self.processoutput = os.fdopen(self.ptymaster, "r", 0) self.processinput = os.fdopen(self.ptymaster, "w", 0) self.ptyname = os.ttyname(self.ptyslave) self.command, self.debugoutput = os.popen4(self.interface["executable"], bufsize=0) self.output_tid = thread.start_new_thread(self.outputhandler,()) self.debug_tid = thread.start_new_thread(self.debughandler,()) #run interface autostart commands to start debugging, and set up process output to outputpipe df.write("TSession.__init__: running autostart commands\n"); df.flush() for command in self.interface["autostart"]: self.debugcommand(command%{"VDBSourceFile": VDBSourceFile, "VDBArguments": VDBArguments, "VDBTerminal": self.ptyname}, True) df.write("TSession.__init__: completed autostart commands\n"); df.flush() #set break points in the break point list for b in VDBBreakpoint: reply = self.debugcommand(self.interface["setbreak"]%(b), True) m = re.match(self.interface["breakpoint"], reply[0]) if m is not None: b.number = int(m.group(1)) df.write("finshed TSession.__init__\n"); df.flush() def __del__(self): self.outputbuffer.append('') curbuf = vim.current.buffer.number for buf in self.unmodifiablebuffers: vim.command("buffer %i"%(buf)) vim.command("set modifiable") vim.command("buffer %i"%(curbuf)) removebuf(self.watchbuffer) removebuf(self.debugbuffer) def outputhandler(self): print "output thread starting" df.write("output thread starting\n"); df.flush() oc = self.processoutput.read(1) try: while oc != '': if oc == '\r': pass elif oc == '\n': self.outputbuffer.append('') else: self.outputbuffer[-1] += oc #recognise terminal escapes here ret = select.select([self.processoutput],[],[],0.1) #if self.ready and bufvisible(self.outputbuffer.number): if len(ret[0]) == 0: cw = vim.eval("winnr()") openbuf(self.outputbuffer.number); vim.command("normal G$"); openwin(cw) oc = self.processoutput.read(1) vim.command("echo \"%s\""%oc) except: print "output thread exiting because of exception" df.write("output thread exiting because of exception\n"); df.flush() print "output thread exiting" df.write("output thread exiting\n"); df.flush() def debughandler(self): print "debug thread starting" df.write("debug thread starting\n"); df.flush() try: codematch = re.compile('\\\[\?[0-9]+h') escapecode = '' c = self.debugoutput.read(1) while c != '': if escapecode != '': escapecode += c if codematch.match(escapecode): escapecode = '' else: if ord(c) == 27: escapecode = '\\' else: if c == '\n': #df.write("\n"); df.flush() for response in self.interface["autoresponses"]: #df.write("matching autoresponse: %r\n", response); df.flush() m = re.match(response[0], self.debugbuffer[-1]) if m is not None: df.write("matched autoresponse: %r\n"%(response,)); df.flush() if response[1] is not None: self.debugbuffer[-1] = re.sub("\\\\(\d+)", lambda sm: m.group(int(sm.group(1))), response[1]) args = {} if response[3] is not None: for arg in response[3]: args[arg[0]] = re.sub("\\\\(\d+)", lambda sm: m.group(int(sm.group(1))), arg[1]) if response[2] is not None: if response[3] is not None: response[2](args) else: response[2]() self.debugbuffer.append('') else: self.debugbuffer[-1] += c #df.write(c); df.flush() if self.debugbuffer[-1] == self.interface["prompt"]: self.ready = True self.debugpromptlen = len(self.debugbuffer[-1]) if bufvisible(self.debugbuffer.number): cw = vim.eval("winnr()") openbuf(self.debugbuffer.number) vim.command("normal G$") openwin(cw) c = self.debugoutput.read(1) self.ready = False df.close() except Exception, e: df.write("vdb.vim:%i %s (debug thread exiting)\n"%(10+sys.exc_info()[2].tb_lineno, e)); df.flush() self.ready = True def debugcommand(self, commandstr, sync=False, echo=True): if sync: while not self.ready: time.sleep(0.1) startline = len(self.debugbuffer) if self.ready: if echo: self.debugbuffer[-1] += commandstr self.debugbuffer.append('') self.command.write(commandstr+"\n") df.write(commandstr+"\n"); df.flush() self.debughistory.append(commandstr) if len(self.debughistory) > 50: del self.debughistory[0] self.debughistorypos = len(self.debughistory) self.ready = False if sync: while not self.ready: time.sleep(0.1) return self.debugbuffer[startline:] def placeexecution(self, args): df.write("placeexecution(%r)\n"%(args)) df.flush() cw = vim.eval("winnr()") openbuf(self.sourcebuffer.number, name=self.executionfile, height=(self.maxheight/5)*4, settings="nomodifiable", position="below") if self.executionfile != None: try: if self.executionsignplaced: vim.command("silent sign jump 65535 file=%s"%(self.executionfile)) vim.command("sign unplace 65535 file=%s"%(self.executionfile)) self.executionsignplaced = False idx = VDBBreakpointOnLine(vim.current.window.cursor[0]) if idx is not False: if VDBBreakpoint[idx].condition == "": vim.command("sign place %i line=%i name=BreakPoint file=%s"%(VDBBreakpoint[idx].signnum,vim.current.window.cursor[0],VDBBreakpoint[idx].buffer)) else: vim.command("sign place %i line=%i name=CondBreakPoint file=%s"%(VDBBreakpoint[idx].signnum,vim.current.window.cursor[0],VDBBreakpoint[idx].buffer)) except: pass if vim.current.buffer.name != args["filename"]: vim.command("silent edit %(filename)s"%(args)) self.sourcebuffer = vim.current.buffer vim.command("setlocal nomodifiable") if vim.current.buffer.number not in self.unmodifiablebuffers: self.unmodifiablebuffers.append(vim.current.buffer.number) vim.command("sign place 65535 line=%(lineno)s name=ExecutionLine file=%(filename)s"%(args)) self.executionsignplaced = True self.executionfile = args["filename"] vim.command("silent! sign jump 65535 file=%(filename)s"%(args)) idx = VDBBreakpointOnLine(vim.current.window.cursor[0]) if idx is not False: vim.command("sign unplace %(signnum)i"%(VDBBreakpoint[idx])) vim.command("silent! foldopen") vim.command("redraw") openwin(cw) def getsymbolvalues(self, softupdate = False): i = 0; while i < len(VDBWatch): capture = self.debugcommand(self.interface["getsymbolvalue"]%{"symbolname": VDBWatch[i]}, True) VDBWatchResults[i] = capture[0] i += 1 def start(self): self.running = True def stop(self): self.running = False try: if self.executionsignplaced: vim.command("silent sign jump 65535 file=%s"%(self.executionfile)) vim.command("sign unplace 65535 file=%s"%(self.executionfile)) self.executionsignplaced = False except: pass print "The program has stopped." df.write("The program has stopped."); df.flush() class TBreakpoint(object): def __init__(self, buffer, lineno, signnum, number): self.buffer = buffer.name self.lineno = lineno self.signnum = signnum self.number = number self.condition = "" def __getitem__(self, item): return self.__getattribute__(item) def VDBBreakpointOnLine(lineno, buffer=None): if buffer is None: buffer = vim.current.buffer.name for i in range(len(VDBBreakpoint)): if VDBBreakpoint[i].lineno == lineno and VDBBreakpoint[i].buffer == buffer: return i return False def VDBUpdateWatches(softupdate = False): if VDB is not None and VDB.watchbuffer is not None: if not softupdate: VDB.getsymbolvalues() VDB.watchbuffer[:] = ["%s: %s"%(VDBWatch[i], VDBWatchResults[i]) for i in range(len(VDBWatch))] VDB = None VDBSourceFile = None VDBArguments = None VDBBreakpoint = [] VDBBreakpointIdx = None VDBBreakpointCount = 0 VDBWatch = [] VDBWatchResults = [] VDBBaseDir = os.path.dirname(vim.eval("s:ScriptLocation")) VDBInterface = [] #filelist = [] #for d in os.walk(VDBBaseDir): # filelist += d[2] # #for f in filelist: # if f.endswith(".vdb"): # VDBParseInterface(VDBBaseDir+"/"+f) def VDBStart(): global VDBSourceFile, VDBArguments, VDB if VDB == None: if VDBSourceFile == None: VDBSourceFile = vim.eval("input('Source file to debug: ', '%s', 'file')"%(vim.current.buffer.name)) VDBArguments = vim.eval("input('Command line arguments: ', '', 'file')") VDB = TSession(VDBSourceFile, VDBArguments) return True return False def VDBShowConsole(): VDBStart() openbuf(VDB.debugbuffer.number, name="%i-debug"%(VDB.pid), height=(vim.current.window.height/5)) def VDBSendRawInput(): VDBStart() s = vim.eval("input('Input string: ')") VDB.processinput.write(s+"\n") VDB.processinput.flush() def VDBUntil(): global VDBBreakpointCount VDBStart() b = TBreakpoint(vim.current.window.buffer, vim.current.window.cursor[0], 65534-VDBBreakpointCount, None) VDBBreakpointCount += 1 reply = VDB.debugcommand(VDB.interface["setbreak"]%(b), True) m = re.match(VDB.interface["breakpoint"], reply[0]) if m is not None: b.number = int(m.group(1)) VDB.debugcommand(VDB.interface["continue"]) VDB.debugcommand(VDB.interface["clearbreak"]%(b)) VDBUpdateWatches() def VDBToggleBreak(): global VDBBreakpointIdx, VDBBreakpointCount b = VDBBreakpointOnLine(vim.current.window.cursor[0]) if b is not False: if VDB: VDB.debugcommand(VDB.interface["clearbreak"]%(VDBBreakpoint[b])) vim.command("sign unplace %(signnum)i"%VDBBreakpoint[b]) del VDBBreakpoint[b] else: b = TBreakpoint(vim.current.window.buffer, vim.current.window.cursor[0], 65534-VDBBreakpointCount, None) VDBBreakpointCount += 1 vim.command("sign place %(signnum)i line=%(lineno)i name=BreakPoint file=%(buffer)s"%b) VDBBreakpoint.append(b) if VDB: VDBBreakpointIdx = len(VDBBreakpoint)-1 reply = VDB.debugcommand(VDB.interface["setbreak"]%(b), True) m = re.match(VDB.interface["breakpoint"], reply[0]) if m is not None: b.number = int(m.group(1)) def VDBBreakpointCondition(): global VDBBreakpointIdx, VDBBreakpointCount b = VDBBreakpointOnLine(vim.current.window.cursor[0]) if b is not False: VDBBreakpoint[b].condition = vim.eval("input('Breakpoint condition: ', '%s')"%VDBBreakpoint[b].condition) if VDB: VDB.debugcommand(VDB.interface["condition"]%(VDBBreakpoint[b])) else: b = TBreakpoint(vim.current.window.buffer, vim.current.window.cursor[0], 65534-VDBBreakpointCount, None) VDBBreakpointCount += 1 vim.command("sign place %(signnum)i line=%(lineno)i name=BreakPoint file=%(buffer)s"%b) b.condition = vim.eval("input('Breakpoint condition: ', '%s')"%b.condition) if b.condition == "": vim.command("sign place %(signnum)i line=%(lineno)i name=BreakPoint file=%(buffer)s"%(b)) else: vim.command("sign place %(signnum)i line=%(lineno)i name=CondBreakPoint file=%(buffer)s"%(b)) if VDB: VDBBreakpointIdx = len(VDBBreakpoint)-1 reply = VDB.debugcommand(VDB.interface["setbreak"]%(b), True) m = re.match(VDB.interface["breakpoint"], reply[0]) if m is not None: b.number = int(m.group(1)) VDB.debugcommand(VDB.interface["condition"]%(VDBBreakpoint[b])) def VDBAddWatch(): if VDB is None: print "A debug session must be running before adding watches" return if vim.current.buffer.number == VDB.watchbuffer: symbol = vim.eval("input('New watch symbol: ', '%s')"%(VDBWatch[vim.current.window.cursor[0]-1])) VDBWatch[vim.current.window.cursor[0]-1] = symbol VDBWatchResults[vim.current.window.cursor[0]-1] = "Unknown" else: symbol = vim.eval("input('New watch symbol: ')") if symbol not in VDBWatch: VDBWatch.append(symbol) VDBWatchResults.append("Unknown") if VDB.watchbuffer is not None: openbuf(VDB.watchbuffer.number, name="%i-watches"%VDB.pid, height=5, settings="statusline=Watches buftype=nofile noswapfile buhidden=hide") else: vim.command("5new %i-watches"%VDB.pid) vim.command("setlocal statusline=Watches buftype=nofile noswapfile bufhidden=hide") VDB.watchbuffer = vim.current.buffer VDBUpdateWatches() def VDBMoveWatchUp(): if vim.current.buffer.number != VDB.watchbuffer: return pos = vim.current.window.cursor[0]-1 if pos <= 0: return (VDBWatch[pos-1], VDBWatch[pos]) = (VDBWatch[pos], VDBWatch[pos-1]) (VDBWatchResults[pos-1], VDBWatchResults[pos]) = (VDBWatchResults[pos], VDBWatchResults[pos-1]) VDBUpdateWatches(True) def VDBMoveWatchDown(): if vim.current.buffer.number != VDB.watchbuffer: return pos = vim.current.window.cursor[0]-1 if pos >= len(VDBWatch)-1: return (VDBWatch[pos+1], VDBWatch[pos]) = (VDBWatch[pos], VDBWatch[pos+1]) (VDBWatchResults[pos+1], VDBWatchResults[pos]) = (VDBWatchResults[pos], VDBWatchResults[pos+1]) VDBUpdateWatches(True) def VDBDelWatch(): if vim.current.buffer.number != VDB.watchbuffer: return pos = vim.current.window.cursor[0]-1 del VDBWatch[pos] del vim.current.buffer[pos] def VDBStepInto(): if not VDBStart(): VDB.debugcommand(VDB.interface["stepinto"]) VDBUpdateWatches() def VDBStepOver(): if not VDBStart(): VDB.debugcommand(VDB.interface["stepover"]) VDBUpdateWatches() def VDBFinish(): if not VDBStart(): VDB.debugcommand(VDB.interface["finish"]) def VDBContinue(): VDBStart() VDB.debugcommand(VDB.interface["continue"]) VDBUpdateWatches() def VDBKill(): global VDB if VDB is not None: vim.command("silent sign jump 65535 file=%s"%(VDB.executionfile)) vim.command("sign unplace 65535 file=%s"%(VDB.executionfile)) VDB.__del__() VDB = None def VDBReset(): global VDBSourceFile, VDBArguments, VDB VDBKill() VDBSourceFile = None VDBArguments = None VDBStart() >> highlight ExecutionLine term=bold ctermbg=DarkGreen ctermfg=White highlight ErrorLine term=inverse ctermbg=DarkRed ctermfg=Black highlight StackLine term=inverse ctermbg=DarkBlue ctermfg=Black highlight BreakPoint term=inverse ctermbg=DarkCyan ctermfg=Black sign define ExecutionLine text==> texthl=ExecutionLine linehl=ExecutionLine sign define ErrorLine text==> texthl=ErrorLine linehl=ErrorLine sign define StackLine text=<> texthl=StackLine linehl=StackLine sign define BreakPoint text=! texthl=BreakPoint linehl=BreakPoint sign define CondBreakPoint text=? texthl=BreakPoint linehl=BreakPoint command! VDBShowConsole :python VDBShowConsole() command! VDBSendRawInput :python VDBSendRawInput() command! VDBUntil :python VDBUntil() command! VDBToggleBreak :python VDBToggleBreak() command! VDBBreakpointCondition :python VDBBreakpointCondition() command! VDBAddWatch :python VDBAddWatch() command! VDBMoveWatchUp :python VDBMoveWatchUp() command! VDBMoveWatchDown :python VDBMoveWatchDown() command! VDBDelWatch :python VDBDelWatch() command! VDBStepInto :python VDBStepInto() command! VDBStepOver :python VDBStepOver() command! VDBFinish :python VDBFinish() command! VDBContinue :python VDBContinue() command! VDBKill :python VDBKill() command! VDBReset :python VDBReset() function! VDBMapDefaults() nmap :VDBShowConsole nmap :VDBSendRawInput nmap :VDBUntil nmap :VDBToggleBreak nmap :VDBBreakpointCondition nmap :VDBAddWatch nmap :VDBMoveWatchUp nmap :VDBMoveWatchDown nmap :VDBDelWatch nmap :VDBStepInto nmap :VDBStepOver nmap :VDBContinue nmap :VDBFinish nmap :VDBKill nmap :VDBReset endfunction endif