Fix #25 - pre-process GDB's MI output
This commit is contained in:
parent
fa84d5c0a5
commit
3ef3f45016
@ -1,21 +1,13 @@
|
|||||||
"Read and return all new lines from a Vebugger pipe object.
|
"Read bytes from pipe to buffer
|
||||||
function! s:readNewLinesFromPipe(pipeObject)
|
function! s:fillBufferFromPipe(pipeObject)
|
||||||
"read
|
let l:text = a:pipeObject.pipe.read(1024, 0)
|
||||||
let l:text=a:pipeObject.pipe.read(1000,0)
|
let l:totalBytesRead = 0
|
||||||
while 0 < len(l:text)
|
while 0 < len(l:text)
|
||||||
|
let l:totalBytesRead += 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(1024, 0)
|
||||||
endwhile
|
endwhile
|
||||||
|
return l:totalBytesRead
|
||||||
"parse
|
|
||||||
let l:lastNewline=strridx(a:pipeObject.buffer,"\n")
|
|
||||||
if 0<=l:lastNewline
|
|
||||||
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)
|
|
||||||
return l:outLines
|
|
||||||
endif
|
|
||||||
|
|
||||||
return []
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let s:f_debugger={}
|
let s:f_debugger={}
|
||||||
@ -43,10 +35,13 @@ endfunction
|
|||||||
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:pipe = self.pipes[l:k]
|
||||||
|
if 0 < s:fillBufferFromPipe(l:pipe)
|
||||||
|
let l:nl = l:pipe.bufferer()
|
||||||
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
|
||||||
|
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]
|
||||||
@ -252,6 +247,11 @@ function! vebugger#createDebugger(command)
|
|||||||
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"}}
|
||||||
|
for l:pipe in values(l:debugger.pipes)
|
||||||
|
"let l:pipe.buffer = ''
|
||||||
|
"let l:pipe.readIntoBuffer = function('vebugger#readIntoBuffer')
|
||||||
|
"let l:pipe.bufferer = function('vebugger#readNewLinesFromPipe')
|
||||||
|
endfor
|
||||||
|
|
||||||
let l:debugger.readResultTemplate={}
|
let l:debugger.readResultTemplate={}
|
||||||
let l:debugger.state={}
|
let l:debugger.state={}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
function! vebugger#gdb#start(binaryFile,args)
|
function! vebugger#gdb#start(binaryFile,args)
|
||||||
let l:debugger=vebugger#std#startDebugger(shellescape(vebugger#util#getToolFullPath('gdb',get(a:args,'version'),'gdb'))
|
let l:debugger=vebugger#std#startDebugger(shellescape(vebugger#util#getToolFullPath('gdb',get(a:args,'version'),'gdb'))
|
||||||
\.' -i mi --silent '.fnameescape(a:binaryFile))
|
\.' -i mi --silent '.fnameescape(a:binaryFile))
|
||||||
|
let l:debugger.pipes.out.bufferer = function('vebugger#gdb#readMILinesFromPipe')
|
||||||
let l:debugger.state.gdb={}
|
let l:debugger.state.gdb={}
|
||||||
|
|
||||||
|
|
||||||
@ -57,6 +58,61 @@ function! s:findFolderFromStackTrace(src,nameFromStackTrace)
|
|||||||
return l:path
|
return l:path
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#gdb#readMILinesFromPipe() dict
|
||||||
|
if !has_key(self, 'tildeBuffer')
|
||||||
|
let self.tildeBuffer = ''
|
||||||
|
endif
|
||||||
|
let l:result = []
|
||||||
|
|
||||||
|
while 1
|
||||||
|
let l:newLinePos = stridx(self.buffer, "\n")
|
||||||
|
if l:newLinePos < 0
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
let l:firstChar = self.buffer[0]
|
||||||
|
if l:firstChar == '~'
|
||||||
|
while self.buffer[0] == '~'
|
||||||
|
let l:newLinePos = stridx(self.buffer, "\n")
|
||||||
|
let l:line = self.buffer[0 : l:newLinePos]
|
||||||
|
let l:line = l:line[2 : strridx(l:line, '"') - 1]
|
||||||
|
let self.buffer = strpart(self.buffer, l:newLinePos + 1)
|
||||||
|
"let self.tildeBuffer .= l:line
|
||||||
|
let l:line = substitute(l:line, '\\n', "\n", "g")
|
||||||
|
let l:line = substitute(l:line, '\\t', "\t", "g")
|
||||||
|
let l:line = substitute(l:line, '\\"', '"', "g")
|
||||||
|
let self.tildeBuffer .= l:line
|
||||||
|
endwhile
|
||||||
|
let l:lastTildeNewLine = strridx(self.tildeBuffer, "\n")
|
||||||
|
if 0 <= l:lastTildeNewLine
|
||||||
|
let l:newTildeLines = split(self.tildeBuffer[: l:lastTildeNewLine - 1], '\n')
|
||||||
|
call map(l:newTildeLines, '"~".v:val')
|
||||||
|
let self.tildeBuffer = strpart(self.tildeBuffer, l:lastTildeNewLine + 1)
|
||||||
|
call extend(l:result, l:newTildeLines)
|
||||||
|
endif
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
if !empty(self.tildeBuffer)
|
||||||
|
call extend(l:result, split(self.tildeBuffer, '\n'))
|
||||||
|
let self.tildeBuffer = ''
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let l:line = self.buffer[0 : l:newLinePos]
|
||||||
|
if l:firstChar == '&'
|
||||||
|
let l:line = l:line[2 : strridx(l:line, '"') - 1]
|
||||||
|
let l:line = substitute(l:line, '\\n', "\n", "g")
|
||||||
|
let l:line = substitute(l:line, '\\t', "\t", "g")
|
||||||
|
let l:line = substitute(l:line, '\\"', '"', "g")
|
||||||
|
let l:line = '&'.l:line
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:line = substitute(l:line, '\v[\n\r]+$', '', "")
|
||||||
|
call add(l:result, l:line)
|
||||||
|
let self.buffer = strpart(self.buffer, l:newLinePos + 1)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return l:result
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! vebugger#gdb#_readProgramOutput(pipeName,line,readResult,debugger)
|
function! vebugger#gdb#_readProgramOutput(pipeName,line,readResult,debugger)
|
||||||
if 'err'==a:pipeName
|
if 'err'==a:pipeName
|
||||||
\&&a:line!~'\v^[=~*&^]'
|
\&&a:line!~'\v^[=~*&^]'
|
||||||
@ -67,7 +123,6 @@ endfunction
|
|||||||
|
|
||||||
function! vebugger#gdb#_readWhere(pipeName,line,readResult,debugger)
|
function! vebugger#gdb#_readWhere(pipeName,line,readResult,debugger)
|
||||||
if 'out'==a:pipeName
|
if 'out'==a:pipeName
|
||||||
"let l:matches=matchlist(a:line,'\v^\~"#(\d+)\s+(.+)\s+\(.*\)\s+at\s+([^:]+):(\d+)')
|
|
||||||
let l:matches=matchlist(a:line,'\v^\*stopped.*fullname\=\"([^"]+)\",line\=\"(\d+)"')
|
let l:matches=matchlist(a:line,'\v^\*stopped.*fullname\=\"([^"]+)\",line\=\"(\d+)"')
|
||||||
if 2<len(l:matches)
|
if 2<len(l:matches)
|
||||||
let l:file=l:matches[1]
|
let l:file=l:matches[1]
|
||||||
@ -80,7 +135,7 @@ function! vebugger#gdb#_readWhere(pipeName,line,readResult,debugger)
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vebugger#gdb#_readFinish(pipeName,line,readResult,debugger)
|
function! vebugger#gdb#_readFinish(pipeName,line,readResult,debugger)
|
||||||
if a:line=~'\c\V\^~"[Inferior \.\*exited normally]'
|
if a:line=~'\c\V*stopped\.\*exited\[ -]normally'
|
||||||
let a:readResult.std.programFinish={'finish':1}
|
let a:readResult.std.programFinish={'finish':1}
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
@ -129,7 +184,7 @@ endfunction
|
|||||||
function! vebugger#gdb#_readEvaluatedExpressions(pipeName,line,readResult,debugger) dict
|
function! vebugger#gdb#_readEvaluatedExpressions(pipeName,line,readResult,debugger) dict
|
||||||
if 'out' == a:pipeName
|
if 'out' == a:pipeName
|
||||||
if has_key(self, 'nextExpressionToBePrinted')
|
if has_key(self, 'nextExpressionToBePrinted')
|
||||||
let l:matches=matchlist(a:line,'\v^\~"\$(\d+) \= (.*)"$')
|
let l:matches=matchlist(a:line,'\v^\~\$(\d+) \= (.*)$')
|
||||||
if 2<len(l:matches)
|
if 2<len(l:matches)
|
||||||
let l:expression=l:matches[1]
|
let l:expression=l:matches[1]
|
||||||
let l:value=l:matches[2]
|
let l:value=l:matches[2]
|
||||||
@ -139,7 +194,7 @@ function! vebugger#gdb#_readEvaluatedExpressions(pipeName,line,readResult,debugg
|
|||||||
endif
|
endif
|
||||||
call remove(self,'nextExpressionToBePrinted')
|
call remove(self,'nextExpressionToBePrinted')
|
||||||
else
|
else
|
||||||
let l:matches=matchlist(a:line,'\v^\&"print (.{-})(\\r)?(\\n)?"$')
|
let l:matches=matchlist(a:line,'\v^\&print (.+)$')
|
||||||
if 1<len(l:matches)
|
if 1<len(l:matches)
|
||||||
let self.nextExpressionToBePrinted=s:unescapeString(l:matches[1])
|
let self.nextExpressionToBePrinted=s:unescapeString(l:matches[1])
|
||||||
endif
|
endif
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
let g:vebugger_breakpoints=[]
|
let g:vebugger_breakpoints=[]
|
||||||
|
|
||||||
|
"Initialize the default pipe bufferers
|
||||||
|
function! vebugger#std#setStandardBufferers(debugger)
|
||||||
|
for l:pipe in values(a:debugger.pipes)
|
||||||
|
let l:pipe.bufferer = function('vebugger#std#readNewLinesFromPipe')
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
"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={
|
||||||
@ -55,6 +62,7 @@ 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#setStandardBufferers(a: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)
|
||||||
@ -73,6 +81,19 @@ function! vebugger#std#startDebugger(command)
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
"Read and return all new lines from a Vebugger pipe object.
|
||||||
|
function! vebugger#std#readNewLinesFromPipe() dict
|
||||||
|
let l:lastNewline = strridx(self.buffer, "\n")
|
||||||
|
if 0 <= l:lastNewline
|
||||||
|
let l:outLines = split(strpart(self.buffer, 0, l:lastNewline), '\r\n\|\n\|\r')
|
||||||
|
let self.buffer = strpart(self.buffer, l:lastNewline + 1)
|
||||||
|
return l:outLines
|
||||||
|
endif
|
||||||
|
|
||||||
|
return []
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
"Opens the shell buffer for a debugger. The shell buffer displays the output
|
"Opens the shell buffer for a debugger. The shell buffer displays the output
|
||||||
"of the debugged program, and when it's closed the debugger gets terminated.
|
"of the debugged program, and when it's closed the debugger gets terminated.
|
||||||
"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
|
||||||
|
@ -493,3 +493,26 @@ defines the "std" namespace, and plugins built on top of Vebugger can define a
|
|||||||
namespaced named after the plugin to contain their own read results. A
|
namespaced named after the plugin to contain their own read results. A
|
||||||
debugger frontend implementation can also define it's own namespace for
|
debugger frontend implementation can also define it's own namespace for
|
||||||
storing debugger-specific data and configuration.
|
storing debugger-specific data and configuration.
|
||||||
|
|
||||||
|
COMPILER OUTPUT BUFFERERS *vebugger-architecture-bufferers*
|
||||||
|
|
||||||
|
Read handlers receive lines created by the debugger output bufferer. There is
|
||||||
|
only one for each debugger, and if you just want to get the debugger output
|
||||||
|
line-by-line "as is" you can just use the default one and ignore this section.
|
||||||
|
|
||||||
|
The debugger bufferer is a dict function(|:func-dict|) that operates on pipe
|
||||||
|
objects. It will be called when the pipe object's "self.buffer", which
|
||||||
|
represents everything read from a debugger's output stream, has new data.
|
||||||
|
|
||||||
|
The bufferer function should:
|
||||||
|
* return a list of new lines that will be send to the read handlers, or an
|
||||||
|
empty list if there are no new lines.
|
||||||
|
* "advance" the buffer - delete from it's head everything that was handled.
|
||||||
|
This can easily be done with |strpart()|.
|
||||||
|
|
||||||
|
Bufferers should be set individually for each pipe, usually in the debugger
|
||||||
|
creation function:
|
||||||
|
|
||||||
|
Example: >
|
||||||
|
let l:debugger.pipes.out.bufferer = function('g:myCustomBufferer')
|
||||||
|
<
|
||||||
|
Loading…
x
Reference in New Issue
Block a user