Change the code path of user actions

Most user actions now go through vebugger#userAction, which calls the
user action on the active debugger object. The exceptions are:

 - Starting the debugger - because we don't have an active debugger yet
 - Stopping the debugger - because we'll need to clear the active
   debugger after that
 - Altering breakpoints - because we want to be able to do it even
   without an active debugger(e.g. - setting breakpoints before starting
   the debugger)
This commit is contained in:
IdanArye 2015-02-28 19:16:25 +02:00
parent 3f13848d67
commit 4567ad166b
3 changed files with 410 additions and 436 deletions

View File

@ -1,199 +1,199 @@
"Read and return all new lines from a Vebugger pipe object. "Read and return all new lines from a Vebugger pipe object.
function! s:readNewLinesFromPipe(pipeObject) function! s:readNewLinesFromPipe(pipeObject)
"read "read
let l:text=a:pipeObject.pipe.read(1000,0) let l:text=a:pipeObject.pipe.read(1000,0)
while 0<len(l:text) while 0<len(l:text)
let a:pipeObject.buffer.=l:text let a:pipeObject.buffer.=l:text
let l:text=a:pipeObject.pipe.read(1000,0) let l:text=a:pipeObject.pipe.read(1000,0)
endwhile endwhile
"parse "parse
let l:lastNewline=strridx(a:pipeObject.buffer,"\n") let l:lastNewline=strridx(a:pipeObject.buffer,"\n")
if 0<=l:lastNewline if 0<=l:lastNewline
let l:outLines=split(strpart(a:pipeObject.buffer,0,l:lastNewline),'\r\n\|\n\|\r') let l:outLines=split(strpart(a:pipeObject.buffer,0,l:lastNewline),'\r\n\|\n\|\r')
let a:pipeObject.buffer=strpart(a:pipeObject.buffer,l:lastNewline+1) let a:pipeObject.buffer=strpart(a:pipeObject.buffer,l:lastNewline+1)
return l:outLines return l:outLines
endif endif
return [] return []
endfunction endfunction
let s:f_debugger={} let s:f_debugger={}
"Terminate the debugger "Terminate the debugger
function! s:f_debugger.kill() dict function! s:f_debugger.kill() dict
if self.shell.is_valid if self.shell.is_valid
call self.addLineToTerminal('','== DEBUGGER TERMINATED ==') call self.addLineToTerminal('','== DEBUGGER TERMINATED ==')
endif endif
let &updatetime=self.prevUpdateTime let &updatetime=self.prevUpdateTime
call self.shell.kill(15) call self.shell.kill(15)
if exists('s:debugger') if exists('s:debugger')
for l:closeHandler in s:debugger.closeHandlers for l:closeHandler in s:debugger.closeHandlers
call l:closeHandler.handle(self) call l:closeHandler.handle(self)
endfor endfor
endif endif
endfunction endfunction
"Write a line to the debugger's interactive shell "Write a line to the debugger's interactive shell
function! s:f_debugger.writeLine(line) dict function! s:f_debugger.writeLine(line) dict
call self.shell.stdin.write(a:line."\n") call self.shell.stdin.write(a:line."\n")
endfunction endfunction
"Check for new lines from the debugger's interactive shell and handle them "Check for new lines from the debugger's interactive shell and handle them
function! s:f_debugger.invokeReading() dict function! s:f_debugger.invokeReading() dict
let l:newLines={} let l:newLines={}
for l:k in keys(self.pipes) for l:k in keys(self.pipes)
let l:nl=s:readNewLinesFromPipe(self.pipes[l:k]) let l:nl=s:readNewLinesFromPipe(self.pipes[l:k])
if 0<len(l:nl) if 0<len(l:nl)
let l:newLines[l:k]=l:nl let l:newLines[l:k]=l:nl
endif endif
endfor endfor
for l:k in keys(l:newLines) for l:k in keys(l:newLines)
for l:line in l:newLines[l:k] for l:line in l:newLines[l:k]
call self.handleLine(l:k,l:line) call self.handleLine(l:k,l:line)
endfor endfor
endfor endfor
let l:checkpid=self.shell.checkpid() let l:checkpid=self.shell.checkpid()
if 'exit'==l:checkpid[0] if 'exit'==l:checkpid[0]
\|| 'error'==l:checkpid[0] \|| 'error'==l:checkpid[0]
call self.kill() call self.kill()
endif endif
call feedkeys("f\e") " Make sure the CursorHold event is refired even if the user does nothing call feedkeys("f\e") " Make sure the CursorHold event is refired even if the user does nothing
endfunction endfunction
"Handle a single line from the debugger's interactive shell "Handle a single line from the debugger's interactive shell
function! s:f_debugger.handleLine(pipeName,line) dict function! s:f_debugger.handleLine(pipeName,line) dict
call self.addLineToTerminal(a:pipeName,a:line) call self.addLineToTerminal(a:pipeName,a:line)
let l:readResult=deepcopy(self.readResultTemplate,1) let l:readResult=deepcopy(self.readResultTemplate,1)
for l:readHandler in self.readHandlers for l:readHandler in self.readHandlers
call l:readHandler.handle(a:pipeName,a:line,l:readResult,self) call l:readHandler.handle(a:pipeName,a:line,l:readResult,self)
endfor endfor
for l:thinkHandler in self.thinkHandlers for l:thinkHandler in self.thinkHandlers
call l:thinkHandler.handle(l:readResult,self) call l:thinkHandler.handle(l:readResult,self)
endfor endfor
call self.performWriteActions() call self.performWriteActions()
endfunction endfunction
"Perform all write actions "Perform all write actions
function! s:f_debugger.performWriteActions() dict function! s:f_debugger.performWriteActions() dict
for l:namespace in keys(self.writeActions) for l:namespace in keys(self.writeActions)
let l:handlers=get(self.writeHandlers,l:namespace) let l:handlers=get(self.writeHandlers,l:namespace)
if !empty(l:handlers) if !empty(l:handlers)
for l:writeAction in items(self.writeActions[l:namespace]) for l:writeAction in items(self.writeActions[l:namespace])
if !empty(l:writeAction[1]) if !empty(l:writeAction[1])
if has_key(l:handlers,l:writeAction[0]) if has_key(l:handlers,l:writeAction[0])
call l:handlers[l:writeAction[0]].handle(l:writeAction[1],self) call l:handlers[l:writeAction[0]].handle(l:writeAction[1],self)
endif endif
endif endif
endfor endfor
endif endif
endfor endfor
call self.generateWriteActionsFromTemplate() call self.generateWriteActionsFromTemplate()
endfunction endfunction
"Show the terminal buffer that gets it's content from the debugger's "Show the terminal buffer that gets it's content from the debugger's
"interactive shell "interactive shell
function! s:f_debugger.showTerminalBuffer() dict function! s:f_debugger.showTerminalBuffer() dict
if has_key(self,'terminalBuffer') if has_key(self,'terminalBuffer')
if -1<bufwinnr(self.terminalBuffer) if -1<bufwinnr(self.terminalBuffer)
return return
endif endif
endif endif
new new
setlocal buftype=nofile setlocal buftype=nofile
setlocal bufhidden=wipe setlocal bufhidden=wipe
let self.terminalBuffer=bufnr('') let self.terminalBuffer=bufnr('')
silent file Vebugger:Ternimal silent file Vebugger:Ternimal
wincmd p wincmd p
endfunction endfunction
"Close the terminal buffer "Close the terminal buffer
function! s:f_debugger.closeTerminalBuffer() dict function! s:f_debugger.closeTerminalBuffer() dict
if has_key(self,'terminalBuffer') if has_key(self,'terminalBuffer')
if -1<bufwinnr(self.terminalBuffer) if -1<bufwinnr(self.terminalBuffer)
let l:bufwin=bufwinnr(self.terminalBuffer) let l:bufwin=bufwinnr(self.terminalBuffer)
exe l:bufwin.'wincmd w' exe l:bufwin.'wincmd w'
wincmd c wincmd c
wincmd p wincmd p
endif endif
endif endif
endfunction endfunction
"Check if the terminal buffer associated with this debugger is currently open "Check if the terminal buffer associated with this debugger is currently open
function! s:f_debugger.isTerminalBufferOpen() dict function! s:f_debugger.isTerminalBufferOpen() dict
if has_key(self,'terminalBuffer') if has_key(self,'terminalBuffer')
if -1<bufwinnr(self.terminalBuffer) if -1<bufwinnr(self.terminalBuffer)
return 1 return 1
endif endif
endif endif
return 0 return 0
endfunction endfunction
"Turn on and off the terminal buffer associated with this debugger "Turn on and off the terminal buffer associated with this debugger
function! s:f_debugger.toggleTerminalBuffer() dict function! s:f_debugger.toggleTerminalBuffer() dict
if self.isTerminalBufferOpen() if self.isTerminalBufferOpen()
call self.closeTerminalBuffer() call self.closeTerminalBuffer()
else else
call self.showTerminalBuffer() call self.showTerminalBuffer()
endif endif
endfunction endfunction
"Write a line to the terminal buffer. This function does not process the line "Write a line to the terminal buffer. This function does not process the line
function! s:f_debugger.addLineToTerminal(pipeName,line) dict function! s:f_debugger.addLineToTerminal(pipeName,line) dict
if has_key(self,'terminalBuffer') if has_key(self,'terminalBuffer')
let l:bufwin=bufwinnr(self.terminalBuffer) let l:bufwin=bufwinnr(self.terminalBuffer)
if -1<l:bufwin if -1<l:bufwin
exe l:bufwin.'wincmd w' exe l:bufwin.'wincmd w'
if has_key(self,'pipes') if has_key(self,'pipes')
\&&has_key(self.pipes,a:pipeName) \&&has_key(self.pipes,a:pipeName)
\&&has_key(self.pipes[a:pipeName],'annotation') \&&has_key(self.pipes[a:pipeName],'annotation')
call append (line('$'),(self.pipes[a:pipeName].annotation).(a:line)) call append (line('$'),(self.pipes[a:pipeName].annotation).(a:line))
else else
call append (line('$'),a:line) call append (line('$'),a:line)
endif endif
normal G normal G
wincmd p wincmd p
endif endif
endif endif
endfunction endfunction
"Add an handler to a handler list "Add an handler to a handler list
function! s:addHandler(list,handler) function! s:addHandler(list,handler)
if type(a:handler) == type({}) if type(a:handler) == type({})
call add(a:list,a:handler) call add(a:list,a:handler)
elseif type(a:handler) == type(function('tr')) elseif type(a:handler) == type(function('tr'))
call add(a:list,{'handle':a:handler}) call add(a:list,{'handle':a:handler})
endif endif
endfunction endfunction
"Set a named handler in a handler dictionary "Set a named handler in a handler dictionary
function! s:setHandler(dict,namespace,name,handler) function! s:setHandler(dict,namespace,name,handler)
if !has_key(a:dict,a:namespace) if !has_key(a:dict,a:namespace)
let a:dict[a:namespace]={} let a:dict[a:namespace]={}
endif endif
if type(a:handler) == type({}) if type(a:handler) == type({})
let a:dict[a:namespace][a:name]=a:handler let a:dict[a:namespace][a:name]=a:handler
elseif type(a:handler) == type(function('tr')) elseif type(a:handler) == type(function('tr'))
let a:dict[a:namespace][a:name]={'handle':a:handler} let a:dict[a:namespace][a:name]={'handle':a:handler}
endif endif
endfunction endfunction
"Add a read handler. Read handlers process output from the debugger's "Add a read handler. Read handlers process output from the debugger's
"interactive shell and modify read result objects with structured information "interactive shell and modify read result objects with structured information
"parsed from those lines "parsed from those lines
function! s:f_debugger.addReadHandler(handler) dict function! s:f_debugger.addReadHandler(handler) dict
call s:addHandler(self.readHandlers,a:handler) call s:addHandler(self.readHandlers,a:handler)
endfunction endfunction
"Add a think handler. Think handlers are debugger agnostic - they look at "Add a think handler. Think handlers are debugger agnostic - they look at
"read result objects and decide what to do with them. "read result objects and decide what to do with them.
function! s:f_debugger.addThinkHandler(handler) dict function! s:f_debugger.addThinkHandler(handler) dict
call s:addHandler(self.thinkHandlers,a:handler) call s:addHandler(self.thinkHandlers,a:handler)
endfunction endfunction
"Set a write handler. Write handlers get write action objects and convert them "Set a write handler. Write handlers get write action objects and convert them
@ -201,147 +201,129 @@ endfunction
"of the namespace and name it is registered for, to prevent the same write "of the namespace and name it is registered for, to prevent the same write
"action handled by multiple write handlers. "action handled by multiple write handlers.
function! s:f_debugger.setWriteHandler(namespace,name,handler) dict function! s:f_debugger.setWriteHandler(namespace,name,handler) dict
call s:setHandler(self.writeHandlers,a:namespace,a:name,a:handler) call s:setHandler(self.writeHandlers,a:namespace,a:name,a:handler)
endfunction endfunction
"Add a close handler. Close handlers are called when the debugger is closed to "Add a close handler. Close handlers are called when the debugger is closed to
"tidy things up. "tidy things up.
function! s:f_debugger.addCloseHandler(handler) dict function! s:f_debugger.addCloseHandler(handler) dict
call s:addHandler(self.closeHandlers,a:handler) call s:addHandler(self.closeHandlers,a:handler)
endfunction endfunction
"Create an empty write action that follows the write actions template. That "Create an empty write action that follows the write actions template. That
"action will later be filled by think handlers or from outside. "action will later be filled by think handlers or from outside.
function! s:f_debugger.generateWriteActionsFromTemplate() dict function! s:f_debugger.generateWriteActionsFromTemplate() dict
let self.writeActions=deepcopy(self.writeActionsTemplate) let self.writeActions=deepcopy(self.writeActionsTemplate)
endfunction endfunction
"Set a write action of a specific namespace and name, for write actions that "Set a write action of a specific namespace and name, for write actions that
"do not support a list "do not support a list
function! s:f_debugger.setWriteAction(namespace,name,value) dict function! s:f_debugger.setWriteAction(namespace,name,value) dict
let self.writeActions[a:namespace][a:name]=a:value let self.writeActions[a:namespace][a:name]=a:value
endfunction
"Set a write action and perform it
function! s:f_debugger.setWriteActionAndPerform(namespace, name, value) dict
call self.setWriteAction(a:namespace, a:name, a:value)
call self.performWriteActions()
endfunction endfunction
"Add a write action of a specific namespace and name, for write actions that supports a list "Add a write action of a specific namespace and name, for write actions that supports a list
function! s:f_debugger.addWriteAction(namespace,name,value) dict function! s:f_debugger.addWriteAction(namespace,name,value) dict
call add(self.writeActions[a:namespace][a:name],a:value) call add(self.writeActions[a:namespace][a:name],a:value)
endfunction
"Add a write action and perform it
function! s:f_debugger.addWriteActionAndPerform(namespace, name, value) dict
call self.addWriteAction(a:namespace, a:name, a:value)
call self.performWriteActions()
endfunction endfunction
"Create a bare debugger object from a raw shell line "Create a bare debugger object from a raw shell line
function! vebugger#createDebugger(command) function! vebugger#createDebugger(command)
let l:debugger=deepcopy(s:f_debugger) let l:debugger=deepcopy(s:f_debugger)
let l:debugger.shell=vimproc#ptyopen(a:command,3) let l:debugger.shell=vimproc#ptyopen(a:command,3)
let l:debugger.outBuffer='' let l:debugger.outBuffer=''
let l:debugger.errBuffer='' let l:debugger.errBuffer=''
let l:debugger.pipes={ let l:debugger.pipes={
\'out':{'pipe':(l:debugger.shell.stdout),'buffer':''}, \'out':{'pipe':(l:debugger.shell.stdout),'buffer':''},
\'err':{'pipe':(l:debugger.shell.stderr),'buffer':'','annotation':"err:\t\t"}} \'err':{'pipe':(l:debugger.shell.stderr),'buffer':'','annotation':"err:\t\t"}}
let l:debugger.readResultTemplate={} let l:debugger.readResultTemplate={}
let l:debugger.state={} let l:debugger.state={}
let l:debugger.writeActionsTemplate={} let l:debugger.writeActionsTemplate={}
let l:debugger.readHandlers=[] let l:debugger.readHandlers=[]
let l:debugger.thinkHandlers=[] let l:debugger.thinkHandlers=[]
let l:debugger.writeHandlers={} let l:debugger.writeHandlers={}
let l:debugger.closeHandlers=[] let l:debugger.closeHandlers=[]
let l:debugger.prevUpdateTime=&updatetime let l:debugger.prevUpdateTime=&updatetime
set updatetime=500 set updatetime=500
return l:debugger return l:debugger
endfunction endfunction
"Create a debugger and set it as the currently active debugger "Create a debugger and set it as the currently active debugger
function! vebugger#startDebugger(command) function! vebugger#startDebugger(command)
call vebugger#killDebugger() call vebugger#killDebugger()
let s:debugger=vebugger#createDebugger(a:command) let s:debugger=vebugger#createDebugger(a:command)
augroup vebugger_shell augroup vebugger_shell
autocmd! autocmd!
autocmd CursorHold * call s:debugger.invokeReading() autocmd CursorHold * call s:debugger.invokeReading()
augroup END augroup END
return s:debugger return s:debugger
endfunction endfunction
"Terminate the currently active debugger "Terminate the currently active debugger
function! vebugger#killDebugger() function! vebugger#killDebugger()
augroup vebugger_shell augroup vebugger_shell
autocmd! autocmd!
augroup END augroup END
if exists('s:debugger') if exists('s:debugger')
call s:debugger.closeTerminalBuffer() call s:debugger.closeTerminalBuffer()
call s:debugger.kill() call s:debugger.kill()
unlet s:debugger unlet s:debugger
endif endif
endfunction
function! vebugger#userAction(action, ...)
if exists('s:debugger')
if has_key(s:debugger, a:action)
call call(s:debugger[a:action], a:000, s:debugger)
else
throw 'Current debugger does not support action '.a:action
endif
endif
endfunction endfunction
"Write a line to the currently active debugger "Write a line to the currently active debugger
function! vebugger#writeLine(line) function! vebugger#writeLine(line)
if exists('s:debugger') if exists('s:debugger')
call s:debugger.writeLine(a:line) call s:debugger.writeLine(a:line)
endif endif
endfunction endfunction
"Invoke reading for the currently active debugger "Invoke reading for the currently active debugger
function! vebugger#invokeReading() function! vebugger#invokeReading()
if exists('s:debugger') if exists('s:debugger')
call s:debugger.invokeReading() call s:debugger.invokeReading()
endif endif
endfunction
"Toggle the terminal buffer for the currently active debugger
function! vebugger#toggleTerminalBuffer()
if exists('s:debugger')
call s:debugger.toggleTerminalBuffer()
endif
endfunction endfunction
"Fetch the currently active debugger object "Fetch the currently active debugger object
function! vebugger#getActiveDebugger() function! vebugger#getActiveDebugger()
if exists('s:debugger') if exists('s:debugger')
return s:debugger return s:debugger
else else
return {} return {}
endif endif
endfunction
"Set a write action for the currently active debugger
function! vebugger#setWriteAction(namespace,name,value)
if exists('s:debugger')
call s:debugger.setWriteAction(a:namespace,a:name,a:value)
endif
endfunction
"Add a write action to the currently active debugger
function! vebugger#addWriteAction(namespace,name,value)
if exists('s:debugger')
call s:debugger.addWriteAction(a:namespace,a:name,a:value)
endif
endfunction
"Force performing all the write of the currently active debugger
function! vebugger#performWriteActions()
if exists('s:debugger')
call s:debugger.performWriteActions()
endif
endfunction
"Set a write action for the currently active debugger and perform it
function! vebugger#setWriteActionAndPerform(namespace,name,value)
call vebugger#setWriteAction(a:namespace,a:name,a:value)
call vebugger#performWriteActions()
endfunction
"Add a write action to the currently active debugger and perform it
function! vebugger#addWriteActionAndPerform(namespace,name,value)
call vebugger#addWriteAction(a:namespace,a:name,a:value)
call vebugger#performWriteActions()
endfunction endfunction

View File

@ -2,74 +2,74 @@ let g:vebugger_breakpoints=[]
"Initialize the std part of the debugger's state "Initialize the std part of the debugger's state
function! vebugger#std#setStandardState(debugger) function! vebugger#std#setStandardState(debugger)
let a:debugger.state.std={ let a:debugger.state.std={
\'config':{ \'config':{
\ 'externalFileStop_flowCommand':''}, \ 'externalFileStop_flowCommand':''},
\'location':{}, \'location':{},
\'callstack':[], \'callstack':[],
\'evaluateExpressions':[]} \'evaluateExpressions':[]}
endfunction endfunction
"Initialize the std part of the debugger's read result template "Initialize the std part of the debugger's read result template
function! vebugger#std#setStandardReadResultTemplate(debugger) function! vebugger#std#setStandardReadResultTemplate(debugger)
let a:debugger.readResultTemplate.std={ let a:debugger.readResultTemplate.std={
\'programOutput':{}, \'programOutput':{},
\'location':{}, \'location':{},
\'callstack':{}, \'callstack':{},
\'evaluatedExpression':{}, \'evaluatedExpression':{},
\'programFinish':{}, \'programFinish':{},
\'exception':{}} \'exception':{}}
endfunction endfunction
"Initialize the std part of the debugger's write actions template "Initialize the std part of the debugger's write actions template
function! vebugger#std#setStandardWriteactionsTemplate(debugger) function! vebugger#std#setStandardWriteactionsTemplate(debugger)
let a:debugger.writeActionsTemplate.std={ let a:debugger.writeActionsTemplate.std={
\'flow':'', \'flow':'',
\'breakpoints':[], \'breakpoints':[],
\'evaluateExpressions':[], \'evaluateExpressions':[],
\'executeStatements':[], \'executeStatements':[],
\'removeAfterDisplayed':[], \'removeAfterDisplayed':[],
\'closeDebugger':''} \'closeDebugger':''}
endfunction endfunction
"Adds the std_ functions to the debugger object "Adds the std_ functions to the debugger object
function! vebugger#std#addStandardFunctions(debugger) function! vebugger#std#addStandardFunctions(debugger)
for l:k in keys(s:standardFunctions) for l:k in keys(s:standardFunctions)
let a:debugger['std_'.l:k]=s:standardFunctions[l:k] let a:debugger['std_'.l:k]=s:standardFunctions[l:k]
endfor endfor
endfunction endfunction
"Add the standard think handlers to the debugger "Add the standard think handlers to the debugger
function! vebugger#std#addStandardThinkHandlers(debugger) function! vebugger#std#addStandardThinkHandlers(debugger)
for l:ThinkHandler in values(s:standardThinkHandlers) for l:ThinkHandler in values(s:standardThinkHandlers)
call a:debugger.addThinkHandler(l:ThinkHandler) call a:debugger.addThinkHandler(l:ThinkHandler)
endfor endfor
endfunction endfunction
"Add the standard close handlers to the debugger "Add the standard close handlers to the debugger
function! vebugger#std#addStandardCloseHandlers(debugger) function! vebugger#std#addStandardCloseHandlers(debugger)
for l:CloseHandler in values(s:standardCloseHandlers) for l:CloseHandler in values(s:standardCloseHandlers)
call a:debugger.addCloseHandler(l:CloseHandler) call a:debugger.addCloseHandler(l:CloseHandler)
endfor endfor
endfunction endfunction
"Performs the standard initialization of the debugger object "Performs the standard initialization of the debugger object
function! vebugger#std#standardInit(debugger) function! vebugger#std#standardInit(debugger)
call vebugger#std#setStandardState(a:debugger) call vebugger#std#setStandardState(a:debugger)
call vebugger#std#setStandardReadResultTemplate(a:debugger) call vebugger#std#setStandardReadResultTemplate(a:debugger)
call vebugger#std#setStandardWriteactionsTemplate(a:debugger) call vebugger#std#setStandardWriteactionsTemplate(a:debugger)
call vebugger#std#addStandardFunctions(a:debugger) call vebugger#std#addStandardFunctions(a:debugger)
call vebugger#std#addStandardThinkHandlers(a:debugger) call vebugger#std#addStandardThinkHandlers(a:debugger)
call vebugger#std#addStandardCloseHandlers(a:debugger) call vebugger#std#addStandardCloseHandlers(a:debugger)
endfunction endfunction
"Start a debugger with the std settings "Start a debugger with the std settings
function! vebugger#std#startDebugger(command) function! vebugger#std#startDebugger(command)
let l:debugger=vebugger#startDebugger(a:command) let l:debugger=vebugger#startDebugger(a:command)
call vebugger#std#standardInit(l:debugger) call vebugger#std#standardInit(l:debugger)
return l:debugger return l:debugger
endfunction endfunction
@ -78,69 +78,69 @@ endfunction
"Shell buffers should not be used when attaching a debugger to a running "Shell buffers should not be used when attaching a debugger to a running
"process. "process.
function! vebugger#std#openShellBuffer(debugger) function! vebugger#std#openShellBuffer(debugger)
if has_key(a:debugger,'shellBuffer') if has_key(a:debugger,'shellBuffer')
if -1<bufwinnr(a:debugger.shellBuffer) if -1<bufwinnr(a:debugger.shellBuffer)
return return
endif endif
endif endif
let l:oldBuffer=bufnr('Vebugger:Shell') let l:oldBuffer=bufnr('Vebugger:Shell')
if -1<l:oldBuffer if -1<l:oldBuffer
let a:debugger.shellBuffer=l:oldBuffer let a:debugger.shellBuffer=l:oldBuffer
call a:debugger.std_addLineToShellBuffer('') call a:debugger.std_addLineToShellBuffer('')
call a:debugger.std_addLineToShellBuffer('==================') call a:debugger.std_addLineToShellBuffer('==================')
call a:debugger.std_addLineToShellBuffer('') call a:debugger.std_addLineToShellBuffer('')
return return
endif endif
8 new 8 new
let b:debugger=a:debugger let b:debugger=a:debugger
autocmd BufDelete <buffer> if exists('b:debugger') | call b:debugger.kill() | endif autocmd BufDelete <buffer> if exists('b:debugger') | call b:debugger.kill() | endif
setlocal buftype=nofile setlocal buftype=nofile
setlocal bufhidden=wipe setlocal bufhidden=wipe
let a:debugger.shellBuffer=bufnr('') let a:debugger.shellBuffer=bufnr('')
silent file Vebugger:Shell silent file Vebugger:Shell
wincmd p wincmd p
endfunction endfunction
let s:standardFunctions={} let s:standardFunctions={}
"Write a line to the shell buffer "Write a line to the shell buffer
function! s:standardFunctions.addLineToShellBuffer(line) dict function! s:standardFunctions.addLineToShellBuffer(line) dict
if has_key(self,'shellBuffer') if has_key(self,'shellBuffer')
let l:bufwin=bufwinnr(self.shellBuffer) let l:bufwin=bufwinnr(self.shellBuffer)
if -1<l:bufwin if -1<l:bufwin
exe l:bufwin.'wincmd w' exe l:bufwin.'wincmd w'
call append (line('$'),a:line) call append (line('$'),a:line)
normal G normal G
wincmd p wincmd p
endif endif
endif endif
endfunction endfunction
"Set the write actions to add all breakpoints registered in Vebugger "Set the write actions to add all breakpoints registered in Vebugger
function! s:standardFunctions.addAllBreakpointActions(breakpoints) dict function! s:standardFunctions.addAllBreakpointActions(breakpoints) dict
for l:breakpoint in a:breakpoints for l:breakpoint in a:breakpoints
call self.addWriteAction('std','breakpoints',{ call self.addWriteAction('std','breakpoints',{
\'action':'add', \'action':'add',
\'file':(l:breakpoint.file), \'file':(l:breakpoint.file),
\'line':(l:breakpoint.line)}) \'line':(l:breakpoint.line)})
endfor endfor
endfunction endfunction
"Make the debugger evaluate an expression "Make the debugger evaluate an expression
function! s:standardFunctions.eval(expression) dict function! s:standardFunctions.eval(expression) dict
if -1==index(self.state.std.evaluateExpressions,a:expression) if -1==index(self.state.std.evaluateExpressions,a:expression)
call add(self.state.std.evaluateExpressions,a:expression) call add(self.state.std.evaluateExpressions,a:expression)
endif endif
call self.addWriteAction('std','evaluateExpressions',{ call self.addWriteAction('std','evaluateExpressions',{
\'expression':(a:expression)}) \'expression':(a:expression)})
call self.performWriteActions() call self.performWriteActions()
endfunction endfunction
"Execute a statement in the debugged program "Execute a statement in the debugged program
function! s:standardFunctions.execute(statement) dict function! s:standardFunctions.execute(statement) dict
call self.addWriteAction('std','executeStatements',{ call self.addWriteAction('std','executeStatements',{
\'statement':(a:statement)}) \'statement':(a:statement)})
call self.performWriteActions() call self.performWriteActions()
endfunction endfunction
@ -148,91 +148,91 @@ let s:standardThinkHandlers={}
"Update the shell buffer with program output "Update the shell buffer with program output
function! s:standardThinkHandlers.addProgramOutputToShell(readResult,debugger) dict function! s:standardThinkHandlers.addProgramOutputToShell(readResult,debugger) dict
let l:programOutput=a:readResult.std.programOutput let l:programOutput=a:readResult.std.programOutput
if !empty(l:programOutput) if !empty(l:programOutput)
call a:debugger.std_addLineToShellBuffer(l:programOutput.line) call a:debugger.std_addLineToShellBuffer(l:programOutput.line)
endif endif
endfunction endfunction
"Make Vim jump to the currently executed line "Make Vim jump to the currently executed line
function! s:standardThinkHandlers.moveToCurrentLine(readResult,debugger) dict function! s:standardThinkHandlers.moveToCurrentLine(readResult,debugger) dict
if !empty(a:readResult.std.location) if !empty(a:readResult.std.location)
if !empty(a:debugger.state.std.config.externalFileStop_flowCommand) " Do we need to worry about stopping at external files? if !empty(a:debugger.state.std.config.externalFileStop_flowCommand) " Do we need to worry about stopping at external files?
if 0!=stridx(tolower(fnamemodify(a:readResult.std.location.file,':p')),tolower(getcwd())) if 0!=stridx(tolower(fnamemodify(a:readResult.std.location.file,':p')),tolower(getcwd()))
call a:debugger.setWriteAction('std','flow',a:debugger.state.std.config.externalFileStop_flowCommand) call a:debugger.setWriteAction('std','flow',a:debugger.state.std.config.externalFileStop_flowCommand)
return return
endif endif
endif endif
if a:debugger.state.std.location!=a:readResult.std.location if a:debugger.state.std.location!=a:readResult.std.location
if has_key(a:debugger.state.std.location,'file') if has_key(a:debugger.state.std.location,'file')
exe 'sign unplace 1 file='.fnameescape(fnamemodify(a:debugger.state.std.location.file,':p')) exe 'sign unplace 1 file='.fnameescape(fnamemodify(a:debugger.state.std.location.file,':p'))
endif endif
let a:debugger.state.std.location=deepcopy(a:readResult.std.location) let a:debugger.state.std.location=deepcopy(a:readResult.std.location)
if !bufexists(a:readResult.std.location.file) if !bufexists(a:readResult.std.location.file)
exe get(g:, 'vebugger_view_source_cmd', 'new').' '.(a:readResult.std.location.file) exe get(g:, 'vebugger_view_source_cmd', 'new').' '.(a:readResult.std.location.file)
endif endif
call vebugger#std#updateMarksForFile(a:debugger.state,a:readResult.std.location.file) call vebugger#std#updateMarksForFile(a:debugger.state,a:readResult.std.location.file)
exe 'sign jump 1 file='.fnameescape(fnamemodify(a:readResult.std.location.file,':p')) exe 'sign jump 1 file='.fnameescape(fnamemodify(a:readResult.std.location.file,':p'))
endif endif
endif endif
endfunction endfunction
"Update the call stack "Update the call stack
function! s:standardThinkHandlers.updateCallStack(readResult,debugger) dict function! s:standardThinkHandlers.updateCallStack(readResult,debugger) dict
let l:callstack=a:readResult.std.callstack let l:callstack=a:readResult.std.callstack
if !empty(l:callstack) if !empty(l:callstack)
if get(l:callstack,'clearOld') if get(l:callstack,'clearOld')
let a:debugger.state.std.callstack=[] let a:debugger.state.std.callstack=[]
endif endif
let l:frame={'file':(l:callstack.file),'line':(l:callstack.line)} let l:frame={'file':(l:callstack.file),'line':(l:callstack.line)}
if 'after'==get(l:callstack,'add') if 'after'==get(l:callstack,'add')
call add(a:debugger.state.std.callstack,l:frame) call add(a:debugger.state.std.callstack,l:frame)
elseif 'before'==get(l:callstack,'add') elseif 'before'==get(l:callstack,'add')
call insert(a:debugger.state.std.callstack,l:frame) call insert(a:debugger.state.std.callstack,l:frame)
endif endif
endif endif
endfunction endfunction
"Print an expression that it's evaluation was previously requested "Print an expression that it's evaluation was previously requested
function! s:standardThinkHandlers.printEvaluatedExpression(readResult,debugger) dict function! s:standardThinkHandlers.printEvaluatedExpression(readResult,debugger) dict
let l:evaluatedExpression=a:readResult.std.evaluatedExpression let l:evaluatedExpression=a:readResult.std.evaluatedExpression
if !empty(l:evaluatedExpression) if !empty(l:evaluatedExpression)
if empty(get(l:evaluatedExpression,'expression')) if empty(get(l:evaluatedExpression,'expression'))
echo l:evaluatedExpression.value."\n" echo l:evaluatedExpression.value."\n"
else else
let l:index=index(a:debugger.state.std.evaluateExpressions,l:evaluatedExpression.expression) let l:index=index(a:debugger.state.std.evaluateExpressions,l:evaluatedExpression.expression)
if 0<=l:index if 0<=l:index
call remove(a:debugger.state.std.evaluateExpressions,l:index) call remove(a:debugger.state.std.evaluateExpressions,l:index)
echo l:evaluatedExpression.expression.': '.l:evaluatedExpression.value."\n" echo l:evaluatedExpression.expression.': '.l:evaluatedExpression.value."\n"
let g:echo=l:evaluatedExpression.expression.': '.l:evaluatedExpression.value."\n" let g:echo=l:evaluatedExpression.expression.': '.l:evaluatedExpression.value."\n"
endif endif
endif endif
call a:debugger.addWriteAction('std','removeAfterDisplayed',a:readResult) call a:debugger.addWriteAction('std','removeAfterDisplayed',a:readResult)
endif endif
endfunction endfunction
"Close the debugger when the program is finished but the debugger wasn't "Close the debugger when the program is finished but the debugger wasn't
"closed automatically "closed automatically
function! s:standardThinkHandlers.closeDebuggerWhenProgramFinishes(readResult,debugger) dict function! s:standardThinkHandlers.closeDebuggerWhenProgramFinishes(readResult,debugger) dict
if !empty(a:readResult.std.programFinish) if !empty(a:readResult.std.programFinish)
call a:debugger.setWriteAction('std','closeDebugger','close') call a:debugger.setWriteAction('std','closeDebugger','close')
endif endif
endfunction endfunction
"Print an exception message "Print an exception message
function! s:standardThinkHandlers.printException(readResult,debugger) dict function! s:standardThinkHandlers.printException(readResult,debugger) dict
if !empty(a:readResult.std.exception) if !empty(a:readResult.std.exception)
echohl WarningMsg echohl WarningMsg
echo a:readResult.std.exception.message."\n" echo a:readResult.std.exception.message."\n"
echohl None echohl None
endif endif
endfunction endfunction
let s:standardCloseHandlers={} let s:standardCloseHandlers={}
"Remove the currently executed line when a debugger is closed "Remove the currently executed line when a debugger is closed
function! s:standardCloseHandlers.removeCurrentMarker(debugger) dict function! s:standardCloseHandlers.removeCurrentMarker(debugger) dict
let a:debugger.state.std.location={} let a:debugger.state.std.location={}
sign unplace 1 sign unplace 1
endfunction endfunction
sign define vebugger_current text=-> sign define vebugger_current text=->
@ -240,83 +240,75 @@ sign define vebugger_breakpoint text=** linehl=ColorColumn
"Update all the marks(currently executed line and breakpoints) for a file "Update all the marks(currently executed line and breakpoints) for a file
function! vebugger#std#updateMarksForFile(state,filename) function! vebugger#std#updateMarksForFile(state,filename)
let l:filename=fnamemodify(a:filename,":p") let l:filename=fnamemodify(a:filename,":p")
if bufexists(l:filename) if bufexists(l:filename)
exe 'sign unplace 1 file='.fnameescape(fnamemodify(l:filename,':p')) exe 'sign unplace 1 file='.fnameescape(fnamemodify(l:filename,':p'))
exe 'sign unplace 2 file='.fnameescape(fnamemodify(l:filename,':p')) exe 'sign unplace 2 file='.fnameescape(fnamemodify(l:filename,':p'))
for l:breakpoint in g:vebugger_breakpoints for l:breakpoint in g:vebugger_breakpoints
if fnamemodify(l:breakpoint.file,':p')==fnamemodify(a:filename,':p') if fnamemodify(l:breakpoint.file,':p')==fnamemodify(a:filename,':p')
exe 'sign place 2 name=vebugger_breakpoint line='.l:breakpoint.line.' file='.fnameescape(fnamemodify(l:breakpoint.file,':p')) exe 'sign place 2 name=vebugger_breakpoint line='.l:breakpoint.line.' file='.fnameescape(fnamemodify(l:breakpoint.file,':p'))
endif endif
endfor endfor
if !empty(a:state) if !empty(a:state)
if !empty(a:state.std.location) if !empty(a:state.std.location)
if fnamemodify(a:state.std.location.file,':p')==fnamemodify(a:filename,':p') if fnamemodify(a:state.std.location.file,':p')==fnamemodify(a:filename,':p')
exe 'sign place 1 name=vebugger_current line='.a:state.std.location.line.' file='.fnameescape(fnamemodify(l:filename,':p')) exe 'sign place 1 name=vebugger_current line='.a:state.std.location.line.' file='.fnameescape(fnamemodify(l:filename,':p'))
endif endif
endif endif
endif endif
endif endif
endfunction endfunction
"Toggle a breakpoint on and off "Toggle a breakpoint on and off
function! vebugger#std#toggleBreakpoint(file,line) function! vebugger#std#toggleBreakpoint(file,line)
let l:debugger=vebugger#getActiveDebugger() let l:debugger=vebugger#getActiveDebugger()
let l:debuggerState=empty(l:debugger) let l:debuggerState=empty(l:debugger)
\? {} \? {}
\: l:debugger.state \: l:debugger.state
for l:i in range(len(g:vebugger_breakpoints)) for l:i in range(len(g:vebugger_breakpoints))
let l:breakpoint=g:vebugger_breakpoints[l:i] let l:breakpoint=g:vebugger_breakpoints[l:i]
if l:breakpoint.file==a:file && l:breakpoint.line==a:line if l:breakpoint.file==a:file && l:breakpoint.line==a:line
call remove(g:vebugger_breakpoints,l:i) call remove(g:vebugger_breakpoints,l:i)
call vebugger#addWriteActionAndPerform('std','breakpoints',{ if !empty(l:debugger)
\'action':'remove', call l:debugger.addWriteActionAndPerform('std','breakpoints',{
\'file':(a:file), \'action':'remove',
\'line':(a:line)}) \'file':(a:file),
call vebugger#std#updateMarksForFile(l:debuggerState,a:file) \'line':(a:line)})
return endif
endif call vebugger#std#updateMarksForFile(l:debuggerState,a:file)
endfor return
call add(g:vebugger_breakpoints,{'file':(a:file),'line':(a:line)}) endif
call vebugger#addWriteActionAndPerform('std','breakpoints',{ endfor
\'action':'add', call add(g:vebugger_breakpoints,{'file':(a:file),'line':(a:line)})
\'file':(a:file), if !empty(l:debugger)
\'line':(a:line)}) call l:debugger.addWriteActionAndPerform('std','breakpoints',{
call vebugger#std#updateMarksForFile(l:debuggerState,a:file) \'action':'add',
\'file':(a:file),
\'line':(a:line)})
endif
call vebugger#std#updateMarksForFile(l:debuggerState,a:file)
endfunction endfunction
"Clear all breakpoints "Clear all breakpoints
function! vebugger#std#clearBreakpoints() function! vebugger#std#clearBreakpoints()
let l:debugger=vebugger#getActiveDebugger() let l:debugger=vebugger#getActiveDebugger()
let l:debuggerState=empty(l:debugger) ? {} : l:debugger.state let l:debuggerState=empty(l:debugger) ? {} : l:debugger.state
let l:files=[] let l:files=[]
for l:breakpoint in g:vebugger_breakpoints for l:breakpoint in g:vebugger_breakpoints
if index(l:files,l:breakpoint.file)<0 if index(l:files,l:breakpoint.file)<0
call add(l:files,l:breakpoint.file) call add(l:files,l:breakpoint.file)
endif endif
call vebugger#addWriteAction('std','breakpoints',extend({'action':'remove'},l:breakpoint)) if !empty(l:debugger)
endfor call l:debugger.addWriteAction('std','breakpoints',extend({'action':'remove'},l:breakpoint))
call vebugger#performWriteActions() endif
let g:vebugger_breakpoints=[] endfor
for l:file in l:files if !empty(l:debugger)
call vebugger#std#updateMarksForFile(l:debuggerState,l:file) call l:debugger.performWriteActions()
endfor endif
endfunction let g:vebugger_breakpoints=[]
for l:file in l:files
"Ask the active debugger to evaluate an expression call vebugger#std#updateMarksForFile(l:debuggerState,l:file)
function! vebugger#std#eval(expression) endfor
let l:debugger=vebugger#getActiveDebugger()
if !empty(l:debugger) && !empty(l:debugger.std_eval)
call l:debugger.std_eval(a:expression)
endif
endfunction
"Ask the active debugger to execute a statement
function! vebugger#std#execute(statement)
let l:debugger=vebugger#getActiveDebugger()
if !empty(l:debugger) && !empty(l:debugger.std_eval)
call l:debugger.std_execute(a:statement)
endif
endfunction endfunction

View File

@ -1,25 +1,25 @@
command! -nargs=1 VBGrawWrite call vebugger#writeLine(<q-args>) command! -nargs=1 VBGrawWrite call vebugger#userAction('writeLine', <q-args>)
command! -nargs=0 VBGkill call vebugger#killDebugger() command! -nargs=0 VBGkill call vebugger#killDebugger()
command! -nargs=0 VBGstepIn call vebugger#setWriteActionAndPerform('std','flow','stepin') command! -nargs=0 VBGstepIn call vebugger#userAction('setWriteActionAndPerform', 'std', 'flow', 'stepin')
command! -nargs=0 VBGstepOver call vebugger#setWriteActionAndPerform('std','flow','stepover') command! -nargs=0 VBGstepOver call vebugger#userAction('setWriteActionAndPerform', 'std', 'flow', 'stepover')
command! -nargs=0 VBGstepOut call vebugger#setWriteActionAndPerform('std','flow','stepout') command! -nargs=0 VBGstepOut call vebugger#userAction('setWriteActionAndPerform', 'std', 'flow', 'stepout')
command! -nargs=0 VBGcontinue call vebugger#setWriteActionAndPerform('std','flow','continue') command! -nargs=0 VBGcontinue call vebugger#userAction('setWriteActionAndPerform', 'std', 'flow', 'continue')
command! -nargs=0 VBGtoggleTerminalBuffer call vebugger#toggleTerminalBuffer() command! -nargs=0 VBGtoggleTerminalBuffer call vebugger#userAction('toggleTerminalBuffer')
command! -nargs=+ -complete=file VBGtoggleBreakpoint call vebugger#std#toggleBreakpoint(<f-args>) command! -nargs=+ -complete=file VBGtoggleBreakpoint call vebugger#std#toggleBreakpoint(<f-args>)
command! -nargs=0 VBGtoggleBreakpointThisLine call vebugger#std#toggleBreakpoint(expand('%:~:.'),line('.')) command! -nargs=0 VBGtoggleBreakpointThisLine call vebugger#std#toggleBreakpoint(expand('%:~:.'),line('.'))
command! -nargs=0 VBGclearBreakpints call vebugger#std#clearBreakpoints() command! -nargs=0 VBGclearBreakpints call vebugger#std#clearBreakpoints()
command! -nargs=1 VBGeval call vebugger#std#eval(<q-args>) command! -nargs=1 VBGeval call vebugger#userAction('std_eval', <q-args>)
command! -nargs=0 VBGevalWordUnderCursor call vebugger#std#eval(expand('<cword>')) command! -nargs=0 VBGevalWordUnderCursor call vebugger#userAction('std_eval', expand('<cword>'))
command! -nargs=1 VBGexecute call vebugger#std#execute(<q-args>) command! -nargs=1 VBGexecute call vebugger#userAction('std_execute', <q-args>)
command! -range -nargs=0 VBGevalSelectedText call vebugger#std#eval(vebugger#util#get_visual_selection()) command! -range -nargs=0 VBGevalSelectedText call vebugger#userAction('std_eval', vebugger#util#get_visual_selection())
command! -range -nargs=0 VBGexecuteSelectedText call vebugger#std#execute(vebugger#util#get_visual_selection()) command! -range -nargs=0 VBGexecuteSelectedText call vebugger#userAction('std_execute', vebugger#util#get_visual_selection())
command! -range -nargs=0 VBGrawWriteSelectedText call vebugger#writeLine(vebugger#util#get_visual_selection()) command! -range -nargs=0 VBGrawWriteSelectedText call vebugger#userAction('writeLine', vebugger#util#get_visual_selection())
command! -nargs=+ -complete=file VBGstartGDB call vebugger#gdb#start([<f-args>][0],{'args':[<f-args>][1:]}) command! -nargs=+ -complete=file VBGstartGDB call vebugger#gdb#start([<f-args>][0],{'args':[<f-args>][1:]})
function! s:attachGDB(...) function! s:attachGDB(...)